Unified · Split
| @@ -4357,6 +4357,42 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 4356 unmodified lines | |||
| 4357 | }).pipe(Effect.provide(NodeHttpServer.layerTest)), | 4357 | }).pipe(Effect.provide(NodeHttpServer.layerTest)), |
| 4358 | ); | 4358 | ); |
| 4359 | 4359 | ||
| 4360 | it.effect("routes websocket rpc projects.listEntries and projects.readFile", () => | ||
| 4361 | Effect.gen(function* () { | ||
| 4362 | const fs = yield* FileSystem.FileSystem; | ||
| 4363 | const path = yield* Path.Path; | ||
| 4364 | const workspaceDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-ws-project-files-" }); | ||
| 4365 | yield* fs.makeDirectory(path.join(workspaceDir, "src"), { recursive: true }); | ||
| 4366 | yield* fs.writeFileString( | ||
| 4367 | path.join(workspaceDir, "src", "index.ts"), | ||
| 4368 | "export const answer = 42;\n", | ||
| 4369 | ); | ||
| 4370 | |||
| 4371 | yield* buildAppUnderTest(); | ||
| 4372 | |||
| 4373 | const wsUrl = yield* getWsServerUrl("/ws"); | ||
| 4374 | const response = yield* Effect.scoped( | ||
| 4375 | withWsRpcClient(wsUrl, (client) => | ||
| 4376 | Effect.all({ | ||
| 4377 | listing: client[WS_METHODS.projectsListEntries]({ cwd: workspaceDir }), | ||
| 4378 | file: client[WS_METHODS.projectsReadFile]({ | ||
| 4379 | cwd: workspaceDir, | ||
| 4380 | relativePath: "src/index.ts", | ||
| 4381 | }), | ||
| 4382 | }), | ||
| 4383 | ), | ||
| 4384 | ); | ||
| 4385 | |||
| 4386 | assert.isTrue(response.listing.entries.some((entry) => entry.path === "src/index.ts")); | ||
| 4387 | assert.deepEqual(response.file, { | ||
| 4388 | relativePath: "src/index.ts", | ||
| 4389 | contents: "export const answer = 42;\n", | ||
| 4390 | byteLength: 26, | ||
| 4391 | truncated: false, | ||
| 4392 | }); | ||
| 4393 | }).pipe(Effect.provide(NodeHttpServer.layerTest)), | ||
| 4394 | ); | ||
| 4395 | |||
| 4360 | it.effect("routes websocket rpc projects.searchEntries excludes gitignored files", () => | 4396 | it.effect("routes websocket rpc projects.searchEntries excludes gitignored files", () => |
| 4361 | Effect.gen(function* () { | 4397 | Effect.gen(function* () { |
| 4362 | const fs = yield* FileSystem.FileSystem; | 4398 | const fs = yield* FileSystem.FileSystem; |
| @@ -87,6 +87,35 @@ it.layer(TestLayer)("WorkspaceEntriesLive", (it) => { · 86 unmodified lines | |||
| 87 | vi.restoreAllMocks(); | 87 | vi.restoreAllMocks(); |
| 88 | }); | 88 | }); |
| 89 | 89 | ||
| 90 | describe("list", () => { | ||
| 91 | it.effect("returns the complete cached workspace index", () => | ||
| 92 | Effect.gen(function* () { | ||
| 93 | const cwd = yield* makeTempDir(); | ||
| 94 | yield* writeTextFile(cwd, "src/components/Composer.tsx"); | ||
| 95 | yield* writeTextFile(cwd, "README.md"); | ||
| 96 | yield* writeTextFile(cwd, "node_modules/pkg/index.js"); | ||
| 97 | |||
| 98 | const workspaceEntries = yield* WorkspaceEntries; | ||
| 99 | const result = yield* workspaceEntries.list({ cwd }); | ||
| 100 | |||
| 101 | expect(result.entries).toEqual( | ||
| 102 | expect.arrayContaining([ | ||
| 103 | { path: "src", kind: "directory" }, | ||
| 104 | { path: "src/components", kind: "directory", parentPath: "src" }, | ||
| 105 | { | ||
| 106 | path: "src/components/Composer.tsx", | ||
| 107 | kind: "file", | ||
| 108 | parentPath: "src/components", | ||
| 109 | }, | ||
| 110 | { path: "README.md", kind: "file" }, | ||
| 111 | ]), | ||
| 112 | ); | ||
| 113 | expect(result.entries.some((entry) => entry.path.startsWith("node_modules"))).toBe(false); | ||
| 114 | expect(result.truncated).toBe(false); | ||
| 115 | }), | ||
| 116 | ); | ||
| 117 | }); | ||
| 118 | |||
| 90 | describe("search", () => { | 119 | describe("search", () => { |
| 91 | it.effect("returns files and directories relative to cwd", () => | 120 | it.effect("returns files and directories relative to cwd", () => |
| 92 | Effect.gen(function* () { | 121 | Effect.gen(function* () { |
| @@ -530,9 +530,24 @@ export const makeWorkspaceEntries = Effect.gen(function* () { · 529 unmodified lines | |||
| 530 | }, | 530 | }, |
| 531 | ); | 531 | ); |
| 532 | 532 | ||
| 533 | const list: WorkspaceEntriesShape["list"] = Effect.fn("WorkspaceEntries.list")(function* (input) { | ||
| 534 | const normalizedCwd = yield* normalizeWorkspaceRoot(input.cwd); | ||
| 535 | return yield* Cache.get(workspaceIndexCache, normalizedCwd).pipe( | ||
| 536 | Effect.map((index) => ({ | ||
| 537 | entries: index.entries.map(({ path: entryPath, kind, parentPath }) => ({ | ||
| 538 | path: entryPath, | ||
| 539 | kind, | ||
| 540 | ...(parentPath ? { parentPath } : {}), | ||
| 541 | })), | ||
| 542 | truncated: index.truncated, | ||
| 543 | })), | ||
| 544 | ); | ||
| 545 | }); | ||
| 546 | |||
| 533 | return { | 547 | return { |
| 534 | browse, | 548 | browse, |
| 535 | invalidate, | 549 | invalidate, |
| 550 | list, | ||
| 536 | search, | 551 | search, |
| 537 | } satisfies WorkspaceEntriesShape; | 552 | } satisfies WorkspaceEntriesShape; |
| 538 | }); | 553 | }); |
| @@ -54,6 +54,64 @@ const writeTextFile = Effect.fn("writeTextFile")(function* ( · 53 unmodified lines | |||
| 54 | }); | 54 | }); |
| 55 | 55 | ||
| 56 | it.layer(TestLayer)("WorkspaceFileSystemLive", (it) => { | 56 | it.layer(TestLayer)("WorkspaceFileSystemLive", (it) => { |
| 57 | describe("readFile", () => { | ||
| 58 | it.effect("reads UTF-8 files relative to the workspace root", () => | ||
| 59 | Effect.gen(function* () { | ||
| 60 | const workspaceFileSystem = yield* WorkspaceFileSystem; | ||
| 61 | const cwd = yield* makeTempDir; | ||
| 62 | yield* writeTextFile(cwd, "src/index.ts", "export const answer = 42;\n"); | ||
| 63 | |||
| 64 | const result = yield* workspaceFileSystem.readFile({ | ||
| 65 | cwd, | ||
| 66 | relativePath: "src/index.ts", | ||
| 67 | }); | ||
| 68 | |||
| 69 | expect(result).toEqual({ | ||
| 70 | relativePath: "src/index.ts", | ||
| 71 | contents: "export const answer = 42;\n", | ||
| 72 | byteLength: 26, | ||
| 73 | truncated: false, | ||
| 74 | }); | ||
| 75 | }), | ||
| 76 | ); | ||
| 77 | |||
| 78 | it.effect("rejects reads outside the workspace root", () => | ||
| 79 | Effect.gen(function* () { | ||
| 80 | const workspaceFileSystem = yield* WorkspaceFileSystem; | ||
| 81 | const cwd = yield* makeTempDir; | ||
| 82 | |||
| 83 | const error = yield* workspaceFileSystem | ||
| 84 | .readFile({ cwd, relativePath: "../escape.md" }) | ||
| 85 | .pipe(Effect.flip); | ||
| 86 | |||
| 87 | expect(error.message).toContain( | ||
| 88 | "Workspace file path must be relative to the project root: ../escape.md", | ||
| 89 | ); | ||
| 90 | }), | ||
| 91 | ); | ||
| 92 | |||
| 93 | it.effect("rejects symlinks that resolve outside the workspace root", () => | ||
| 94 | Effect.gen(function* () { | ||
| 95 | const workspaceFileSystem = yield* WorkspaceFileSystem; | ||
| 96 | const fileSystem = yield* FileSystem.FileSystem; | ||
| 97 | const path = yield* Path.Path; | ||
| 98 | const cwd = yield* makeTempDir; | ||
| 99 | const outsideDir = yield* makeTempDir; | ||
| 100 | yield* writeTextFile(outsideDir, "secret.txt", "outside\n"); | ||
| 101 | yield* fileSystem.symlink( | ||
| 102 | path.join(outsideDir, "secret.txt"), | ||
| 103 | path.join(cwd, "linked-secret.txt"), | ||
| 104 | ); | ||
| 105 | |||
| 106 | const error = yield* workspaceFileSystem | ||
| 107 | .readFile({ cwd, relativePath: "linked-secret.txt" }) | ||
| 108 | .pipe(Effect.flip); | ||
| 109 | |||
| 110 | expect(error.message).toContain("resolves outside the project root"); | ||
| 111 | }), | ||
| 112 | ); | ||
| 113 | }); | ||
| 114 | |||
| 57 | describe("writeFile", () => { | 115 | describe("writeFile", () => { |
| 58 | it.effect("writes files relative to the workspace root", () => | 116 | it.effect("writes files relative to the workspace root", () => |
| 59 | Effect.gen(function* () { | 117 | Effect.gen(function* () { |
| @@ -1,3 +1,6 @@ | |||
| 1 | // @effect-diagnostics nodeBuiltinImport:off | ||
| 2 | import fsPromises from "node:fs/promises"; | ||
| 3 | |||
| 1 | import * as Effect from "effect/Effect"; | 4 | import * as Effect from "effect/Effect"; |
| 2 | import * as FileSystem from "effect/FileSystem"; | 5 | import * as FileSystem from "effect/FileSystem"; |
| 3 | import * as Layer from "effect/Layer"; | 6 | import * as Layer from "effect/Layer"; |
| @@ -11,12 +14,74 @@ import { · 7 unmodified lines | |||
| 11 | import { WorkspaceEntries } from "../Services/WorkspaceEntries.ts"; | 14 | import { WorkspaceEntries } from "../Services/WorkspaceEntries.ts"; |
| 12 | import { WorkspacePaths } from "../Services/WorkspacePaths.ts"; | 15 | import { WorkspacePaths } from "../Services/WorkspacePaths.ts"; |
| 13 | 16 | ||
| 17 | const PROJECT_READ_FILE_MAX_BYTES = 1024 * 1024; | ||
| 18 | |||
| 14 | export const makeWorkspaceFileSystem = Effect.gen(function* () { | 19 | export const makeWorkspaceFileSystem = Effect.gen(function* () { |
| 15 | const fileSystem = yield* FileSystem.FileSystem; | 20 | const fileSystem = yield* FileSystem.FileSystem; |
| 16 | const path = yield* Path.Path; | 21 | const path = yield* Path.Path; |
| 17 | const workspacePaths = yield* WorkspacePaths; | 22 | const workspacePaths = yield* WorkspacePaths; |
| 18 | const workspaceEntries = yield* WorkspaceEntries; | 23 | const workspaceEntries = yield* WorkspaceEntries; |
| 19 | 24 | ||
| 25 | const readFile: WorkspaceFileSystemShape["readFile"] = Effect.fn("WorkspaceFileSystem.readFile")( | ||
| 26 | function* (input) { | ||
| 27 | const target = yield* workspacePaths.resolveRelativePathWithinRoot({ | ||
| 28 | workspaceRoot: input.cwd, | ||
| 29 | relativePath: input.relativePath, | ||
| 30 | }); | ||
| 31 | |||
| 32 | const result = yield* Effect.tryPromise({ | ||
| 33 | try: async () => { | ||
| 34 | const [realWorkspaceRoot, realTargetPath] = await Promise.all([ | ||
| 35 | fsPromises.realpath(input.cwd), | ||
| 36 | fsPromises.realpath(target.absolutePath), | ||
| 37 | ]); | ||
| 38 | const relativeRealPath = path.relative(realWorkspaceRoot, realTargetPath); | ||
| 39 | if ( | ||
| 40 | relativeRealPath.startsWith(`..${path.sep}`) || | ||
| 41 | relativeRealPath === ".." || | ||
| 42 | path.isAbsolute(relativeRealPath) | ||
| 43 | ) { | ||
| 44 | throw new Error("Workspace file path resolves outside the project root."); | ||
| 45 | } | ||
| 46 | |||
| 47 | const handle = await fsPromises.open(realTargetPath, "r"); | ||
| 48 | try { | ||
| 49 | const stat = await handle.stat(); | ||
| 50 | if (!stat.isFile()) { | ||
| 51 | throw new Error("Workspace path is not a file."); | ||
| 52 | } | ||
| 53 | const bytesToRead = Math.min(stat.size, PROJECT_READ_FILE_MAX_BYTES); | ||
| 54 | const buffer = Buffer.alloc(bytesToRead); | ||
| 55 | const { bytesRead } = await handle.read(buffer, 0, bytesToRead, 0); | ||
| 56 | const fileBytes = buffer.subarray(0, bytesRead); | ||
| 57 | if (fileBytes.includes(0)) { | ||
| 58 | throw new Error("Binary files cannot be previewed as text."); | ||
| 59 | } | ||
| 60 | const contents = new TextDecoder("utf-8").decode(fileBytes); | ||
| 61 | return { | ||
| 62 | relativePath: target.relativePath, | ||
| 63 | contents, | ||
| 64 | byteLength: stat.size, | ||
| 65 | truncated: stat.size > PROJECT_READ_FILE_MAX_BYTES, | ||
| 66 | }; | ||
| 67 | } finally { | ||
| 68 | await handle.close(); | ||
| 69 | } | ||
| 70 | }, | ||
| 71 | catch: (cause) => | ||
| 72 | new WorkspaceFileSystemError({ | ||
| 73 | cwd: input.cwd, | ||
| 74 | relativePath: input.relativePath, | ||
| 75 | operation: "workspaceFileSystem.readFile", | ||
| 76 | detail: cause instanceof Error ? cause.message : String(cause), | ||
| 77 | cause, | ||
| 78 | }), | ||
| 79 | }); | ||
| 80 | |||
| 81 | return result; | ||
| 82 | }, | ||
| 83 | ); | ||
| 84 | |||
| 20 | const writeFile: WorkspaceFileSystemShape["writeFile"] = Effect.fn( | 85 | const writeFile: WorkspaceFileSystemShape["writeFile"] = Effect.fn( |
| 21 | "WorkspaceFileSystem.writeFile", | 86 | "WorkspaceFileSystem.writeFile", |
| 22 | )(function* (input) { | 87 | )(function* (input) { |
| @@ -52,7 +117,7 @@ export const makeWorkspaceFileSystem = Effect.gen(function* () { · 29 unmodified lines | |||
| 52 | yield* workspaceEntries.invalidate(input.cwd); | 117 | yield* workspaceEntries.invalidate(input.cwd); |
| 53 | return { relativePath: target.relativePath }; | 118 | return { relativePath: target.relativePath }; |
| 54 | }); | 119 | }); |
| 55 | return { writeFile } satisfies WorkspaceFileSystemShape; | 120 | return { readFile, writeFile } satisfies WorkspaceFileSystemShape; |
| 56 | }); | 121 | }); |
| 57 | 122 | ||
| 58 | export const WorkspaceFileSystemLive = Layer.effect(WorkspaceFileSystem, makeWorkspaceFileSystem); | 123 | export const WorkspaceFileSystemLive = Layer.effect(WorkspaceFileSystem, makeWorkspaceFileSystem); |
| @@ -13,6 +13,8 @@ import type * as Effect from "effect/Effect"; · 12 unmodified lines | |||
| 13 | import type { | 13 | import type { |
| 14 | FilesystemBrowseInput, | 14 | FilesystemBrowseInput, |
| 15 | FilesystemBrowseResult, | 15 | FilesystemBrowseResult, |
| 16 | ProjectListEntriesInput, | ||
| 17 | ProjectListEntriesResult, | ||
| 16 | ProjectSearchEntriesInput, | 18 | ProjectSearchEntriesInput, |
| 17 | ProjectSearchEntriesResult, | 19 | ProjectSearchEntriesResult, |
| 18 | } from "@t3tools/contracts"; | 20 | } from "@t3tools/contracts"; |
| @@ -50,6 +52,13 @@ export interface WorkspaceEntriesShape { · 31 unmodified lines | |||
| 50 | input: FilesystemBrowseInput, | 52 | input: FilesystemBrowseInput, |
| 51 | ) => Effect.Effect<FilesystemBrowseResult, WorkspaceEntriesBrowseError>; | 53 | ) => Effect.Effect<FilesystemBrowseResult, WorkspaceEntriesBrowseError>; |
| 52 | 54 | ||
| 55 | /** | ||
| 56 | * List the cached workspace index for a project root. | ||
| 57 | */ | ||
| 58 | readonly list: ( | ||
| 59 | input: ProjectListEntriesInput, | ||
| 60 | ) => Effect.Effect<ProjectListEntriesResult, WorkspaceEntriesError>; | ||
| 61 | |||
| 53 | /** | 62 | /** |
| 54 | * Search indexed workspace entries for files and directories matching the | 63 | * Search indexed workspace entries for files and directories matching the |
| 55 | * provided query. | 64 | * provided query. |
| @@ -10,7 +10,12 @@ import * as Schema from "effect/Schema"; · 9 unmodified lines | |||
| 10 | import * as Context from "effect/Context"; | 10 | import * as Context from "effect/Context"; |
| 11 | import type * as Effect from "effect/Effect"; | 11 | import type * as Effect from "effect/Effect"; |
| 12 | 12 | ||
| 13 | import type { ProjectWriteFileInput, ProjectWriteFileResult } from "@t3tools/contracts"; | 13 | import type { |
| 14 | ProjectReadFileInput, | ||
| 15 | ProjectReadFileResult, | ||
| 16 | ProjectWriteFileInput, | ||
| 17 | ProjectWriteFileResult, | ||
| 18 | } from "@t3tools/contracts"; | ||
| 14 | import { WorkspacePathOutsideRootError } from "./WorkspacePaths.ts"; | 19 | import { WorkspacePathOutsideRootError } from "./WorkspacePaths.ts"; |
| 15 | 20 | ||
| 16 | export class WorkspaceFileSystemError extends Schema.TaggedErrorClass<WorkspaceFileSystemError>()( | 21 | export class WorkspaceFileSystemError extends Schema.TaggedErrorClass<WorkspaceFileSystemError>()( |
| @@ -22,12 +27,26 @@ export class WorkspaceFileSystemError extends Schema.TaggedErrorClass<WorkspaceF · 5 unmodified lines | |||
| 22 | detail: Schema.String, | 27 | detail: Schema.String, |
| 23 | cause: Schema.optional(Schema.Defect()), | 28 | cause: Schema.optional(Schema.Defect()), |
| 24 | }, | 29 | }, |
| 25 | ) {} | 30 | ) { |
| 31 | override get message(): string { | ||
| 32 | return this.detail; | ||
| 33 | } | ||
| 34 | } | ||
| 26 | 35 | ||
| 27 | /** | 36 | /** |
| 28 | * WorkspaceFileSystemShape - Service API for workspace-relative file operations. | 37 | * WorkspaceFileSystemShape - Service API for workspace-relative file operations. |
| 29 | */ | 38 | */ |
| 30 | export interface WorkspaceFileSystemShape { | 39 | export interface WorkspaceFileSystemShape { |
| 40 | /** | ||
| 41 | * Read a UTF-8 text file relative to the workspace root. | ||
| 42 | */ | ||
| 43 | readonly readFile: ( | ||
| 44 | input: ProjectReadFileInput, | ||
| 45 | ) => Effect.Effect< | ||
| 46 | ProjectReadFileResult, | ||
| 47 | WorkspaceFileSystemError | WorkspacePathOutsideRootError | ||
| 48 | >; | ||
| 49 | |||
| 31 | /** | 50 | /** |
| 32 | * Write a file relative to the workspace root. | 51 | * Write a file relative to the workspace root. |
| 33 | * | 52 | * |
| @@ -34,6 +34,8 @@ import { · 33 unmodified lines | |||
| 34 | OrchestrationGetSnapshotError, | 34 | OrchestrationGetSnapshotError, |
| 35 | OrchestrationGetTurnDiffError, | 35 | OrchestrationGetTurnDiffError, |
| 36 | ORCHESTRATION_WS_METHODS, | 36 | ORCHESTRATION_WS_METHODS, |
| 37 | ProjectListEntriesError, | ||
| 38 | ProjectReadFileError, | ||
| 37 | ProjectSearchEntriesError, | 39 | ProjectSearchEntriesError, |
| 38 | ProjectWriteFileError, | 40 | ProjectWriteFileError, |
| 39 | RelayClientInstallFailedError, | 41 | RelayClientInstallFailedError, |
| @@ -160,6 +162,8 @@ const RPC_REQUIRED_SCOPE = new Map<string, AuthEnvironmentScope>([ · 120 unmodified lines | |||
| 160 | [WS_METHODS.sourceControlLookupRepository, AuthOrchestrationReadScope], | 162 | [WS_METHODS.sourceControlLookupRepository, AuthOrchestrationReadScope], |
| 161 | [WS_METHODS.sourceControlCloneRepository, AuthOrchestrationOperateScope], | 163 | [WS_METHODS.sourceControlCloneRepository, AuthOrchestrationOperateScope], |
| 162 | [WS_METHODS.sourceControlPublishRepository, AuthOrchestrationOperateScope], | 164 | [WS_METHODS.sourceControlPublishRepository, AuthOrchestrationOperateScope], |
| 165 | [WS_METHODS.projectsListEntries, AuthOrchestrationReadScope], | ||
| 166 | [WS_METHODS.projectsReadFile, AuthOrchestrationReadScope], | ||
| 163 | [WS_METHODS.projectsSearchEntries, AuthOrchestrationReadScope], | 167 | [WS_METHODS.projectsSearchEntries, AuthOrchestrationReadScope], |
| 164 | [WS_METHODS.projectsWriteFile, AuthOrchestrationOperateScope], | 168 | [WS_METHODS.projectsWriteFile, AuthOrchestrationOperateScope], |
| 165 | [WS_METHODS.shellOpenInEditor, AuthOrchestrationOperateScope], | 169 | [WS_METHODS.shellOpenInEditor, AuthOrchestrationOperateScope], |
| @@ -1172,6 +1176,33 @@ const makeWsRpcLayer = (currentSession: AuthenticatedSession) => · 1006 unmodified lines | |||
| 1172 | ), | 1176 | ), |
| 1173 | { "rpc.aggregate": "workspace" }, | 1177 | { "rpc.aggregate": "workspace" }, |
| 1174 | ), | 1178 | ), |
| 1179 | [WS_METHODS.projectsListEntries]: (input) => | ||
| 1180 | observeRpcEffect( | ||
| 1181 | WS_METHODS.projectsListEntries, | ||
| 1182 | workspaceEntries.list(input).pipe( | ||
| 1183 | Effect.mapError( | ||
| 1184 | (cause) => | ||
| 1185 | new ProjectListEntriesError({ | ||
| 1186 | message: `Failed to list workspace entries: ${cause.detail}`, | ||
| 1187 | cause, | ||
| 1188 | }), | ||
| 1189 | ), | ||
| 1190 | ), | ||
| 1191 | { "rpc.aggregate": "workspace" }, | ||
| 1192 | ), | ||
| 1193 | [WS_METHODS.projectsReadFile]: (input) => | ||
| 1194 | observeRpcEffect( | ||
| 1195 | WS_METHODS.projectsReadFile, | ||
| 1196 | workspaceFileSystem.readFile(input).pipe( | ||
| 1197 | Effect.mapError((cause) => { | ||
| 1198 | const message = isWorkspacePathOutsideRootError(cause) | ||
| 1199 | ? "Workspace file path must stay within the project root." | ||
| 1200 | : `Failed to read workspace file: ${cause.detail}`; | ||
| 1201 | return new ProjectReadFileError({ message, cause }); | ||
| 1202 | }), | ||
| 1203 | ), | ||
| 1204 | { "rpc.aggregate": "workspace" }, | ||
| 1205 | ), | ||
| 1175 | [WS_METHODS.projectsWriteFile]: (input) => | 1206 | [WS_METHODS.projectsWriteFile]: (input) => |
| 1176 | observeRpcEffect( | 1207 | observeRpcEffect( |
| 1177 | WS_METHODS.projectsWriteFile, | 1208 | WS_METHODS.projectsWriteFile, |
| @@ -0,0 +1,11 @@ | |||
| 1 | # Third-Party Notices | ||
| 2 | |||
| 3 | ## vscode-icons | ||
| 4 | |||
| 5 | The custom file icon symbols in `src/pierre-icons.ts` are adapted from the | ||
| 6 | [`vscode-icons`](https://github.com/vscode-icons/vscode-icons) project. | ||
| 7 | |||
| 8 | Copyright (c) 2016 Roberto Huertas | ||
| 9 | |||
| 10 | Licensed under the MIT License. The full license text is available in the | ||
| 11 | upstream repository: <https://github.com/vscode-icons/vscode-icons/blob/master/LICENSE>. | ||
| @@ -27,6 +27,7 @@ · 26 unmodified lines | |||
| 27 | "@legendapp/list": "3.0.0-beta.44", | 27 | "@legendapp/list": "3.0.0-beta.44", |
| 28 | "@lexical/react": "^0.41.0", | 28 | "@lexical/react": "^0.41.0", |
| 29 | "@pierre/diffs": "catalog:", | 29 | "@pierre/diffs": "catalog:", |
| 30 | "@pierre/trees": "1.0.0-beta.4", | ||
| 30 | "@t3tools/client-runtime": "workspace:*", | 31 | "@t3tools/client-runtime": "workspace:*", |
| 31 | "@t3tools/contracts": "workspace:*", | 32 | "@t3tools/contracts": "workspace:*", |
| 32 | "@t3tools/shared": "workspace:*", | 33 | "@t3tools/shared": "workspace:*", |
| @@ -50,6 +50,7 @@ vi.mock("../browser/openFileInPreview", async (importOriginal) => ({ · 49 unmodified lines | |||
| 50 | import ChatMarkdown from "./ChatMarkdown"; | 50 | import ChatMarkdown from "./ChatMarkdown"; |
| 51 | import { serializeTableElementToCsv, serializeTableElementToMarkdown } from "../markdown-clipboard"; | 51 | import { serializeTableElementToCsv, serializeTableElementToMarkdown } from "../markdown-clipboard"; |
| 52 | import { EnvironmentId, ThreadId } from "@t3tools/contracts"; | 52 | import { EnvironmentId, ThreadId } from "@t3tools/contracts"; |
| 53 | import { selectThreadRightPanelState, useRightPanelStore } from "../rightPanelStore"; | ||
| 53 | 54 | ||
| 54 | const threadRef = { | 55 | const threadRef = { |
| 55 | environmentId: EnvironmentId.make("environment-test"), | 56 | environmentId: EnvironmentId.make("environment-test"), |
| @@ -63,6 +64,7 @@ describe("ChatMarkdown", () => { · 7 unmodified lines | |||
| 63 | openUrlInPreviewMock.mockClear(); | 64 | openUrlInPreviewMock.mockClear(); |
| 64 | contextMenuShowMock.mockReset(); | 65 | contextMenuShowMock.mockReset(); |
| 65 | readLocalApiMock.mockClear(); | 66 | readLocalApiMock.mockClear(); |
| 67 | useRightPanelStore.setState({ byThreadKey: {} }); | ||
| 66 | localStorage.clear(); | 68 | localStorage.clear(); |
| 67 | document.body.innerHTML = ""; | 69 | document.body.innerHTML = ""; |
| 68 | }); | 70 | }); |
| @@ -248,6 +250,92 @@ describe("ChatMarkdown", () => { · 179 unmodified lines | |||
| 248 | } | 250 | } |
| 249 | }); | 251 | }); |
| 250 | 252 | ||
| 253 | it("opens code file links in the right-panel file preview", async () => { | ||
| 254 | const screen = await render( | ||
| 255 | <ChatMarkdown | ||
| 256 | text="[ChatMarkdown.tsx](apps/web/src/components/ChatMarkdown.tsx#L978)" | ||
| 257 | cwd="/repo/project" | ||
| 258 | threadRef={threadRef} | ||
| 259 | />, | ||
| 260 | ); | ||
| 261 | |||
| 262 | try { | ||
| 263 | await page.getByRole("link", { name: "ChatMarkdown.tsx · L978" }).click(); | ||
| 264 | |||
| 265 | await vi.waitFor(() => { | ||
| 266 | expect( | ||
| 267 | selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, threadRef), | ||
| 268 | ).toMatchObject({ | ||
| 269 | isOpen: true, | ||
| 270 | activeSurfaceId: "file:apps/web/src/components/ChatMarkdown.tsx", | ||
| 271 | }); | ||
| 272 | expect(openInPreferredEditorMock).not.toHaveBeenCalled(); | ||
| 273 | expect(openFileInPreviewMock).not.toHaveBeenCalled(); | ||
| 274 | }); | ||
| 275 | } finally { | ||
| 276 | await screen.unmount(); | ||
| 277 | } | ||
| 278 | }); | ||
| 279 | |||
| 280 | it("opens HTML and PDF file links in the integrated browser preview", async () => { | ||
| 281 | const screen = await render( | ||
| 282 | <ChatMarkdown | ||
| 283 | text="[report.html](report.html) [report.pdf](report.pdf)" | ||
| 284 | cwd="/repo/project" | ||
| 285 | threadRef={threadRef} | ||
| 286 | />, | ||
| 287 | ); | ||
| 288 | |||
| 289 | try { | ||
| 290 | await page.getByRole("link", { name: "report.html" }).click(); | ||
| 291 | await page.getByRole("link", { name: "report.pdf" }).click(); | ||
| 292 | |||
| 293 | await vi.waitFor(() => { | ||
| 294 | expect(openFileInPreviewMock).toHaveBeenNthCalledWith( | ||
| 295 | 1, | ||
| 296 | threadRef, | ||
| 297 | "/repo/project/report.html", | ||
| 298 | ); | ||
| 299 | expect(openFileInPreviewMock).toHaveBeenNthCalledWith( | ||
| 300 | 2, | ||
| 301 | threadRef, | ||
| 302 | "/repo/project/report.pdf", | ||
| 303 | ); | ||
| 304 | expect(openInPreferredEditorMock).not.toHaveBeenCalled(); | ||
| 305 | }); | ||
| 306 | } finally { | ||
| 307 | await screen.unmount(); | ||
| 308 | } | ||
| 309 | }); | ||
| 310 | |||
| 311 | it("keeps opening file links in the editor from the context menu", async () => { | ||
| 312 | contextMenuShowMock.mockResolvedValue("open"); | ||
| 313 | const filePath = "/repo/project/src/index.ts"; | ||
| 314 | const screen = await render( | ||
| 315 | <ChatMarkdown text="[index.ts](src/index.ts)" cwd="/repo/project" threadRef={threadRef} />, | ||
| 316 | ); | ||
| 317 | |||
| 318 | try { | ||
| 319 | page | ||
| 320 | .getByRole("link", { name: "index.ts" }) | ||
| 321 | .element() | ||
| 322 | .dispatchEvent( | ||
| 323 | new MouseEvent("contextmenu", { | ||
| 324 | bubbles: true, | ||
| 325 | cancelable: true, | ||
| 326 | clientX: 4, | ||
| 327 | clientY: 8, | ||
| 328 | }), | ||
| 329 | ); | ||
| 330 | |||
| 331 | await vi.waitFor(() => { | ||
| 332 | expect(openInPreferredEditorMock).toHaveBeenCalledWith(expect.anything(), filePath); | ||
| 333 | }); | ||
| 334 | } finally { | ||
| 335 | await screen.unmount(); | ||
| 336 | } | ||
| 337 | }); | ||
| 338 | |||
| 251 | it("keeps a favicon with the leading segment of a wrapping URL", async () => { | 339 | it("keeps a favicon with the leading segment of a wrapping URL", async () => { |
| 252 | const url = "https://github.com/pingdotgg/t3code/pull/3017/changes"; | 340 | const url = "https://github.com/pingdotgg/t3code/pull/3017/changes"; |
| 253 | const screen = await render( | 341 | const screen = await render( |
| @@ -429,7 +517,7 @@ describe("ChatMarkdown", () => { · 175 unmodified lines | |||
| 429 | 517 | ||
| 430 | // Language with a known icon: icon XOR text — never the redundant pair. | 518 | // Language with a known icon: icon XOR text — never the redundant pair. |
| 431 | const languageOnly = titles[0]!; | 519 | const languageOnly = titles[0]!; |
| 432 | const hasIcon = languageOnly.querySelector("img") != null; | 520 | const hasIcon = languageOnly.querySelector("svg[data-pierre-icon]") != null; |
| 433 | const hasText = (languageOnly.textContent ?? "").includes("ts"); | 521 | const hasText = (languageOnly.textContent ?? "").includes("ts"); |
| 434 | expect(hasIcon || hasText).toBe(true); | 522 | expect(hasIcon || hasText).toBe(true); |
| 435 | expect(hasIcon && hasText).toBe(false); | 523 | expect(hasIcon && hasText).toBe(false); |
| @@ -446,7 +534,7 @@ describe("ChatMarkdown", () => { · 10 unmodified lines | |||
| 446 | expect(titles[1]!.textContent).toBe("src/main.ts"); | 534 | expect(titles[1]!.textContent).toBe("src/main.ts"); |
| 447 | 535 | ||
| 448 | // Unknown language: no icon attempt, text label. | 536 | // Unknown language: no icon attempt, text label. |
| 449 | expect(titles[2]!.querySelector("img")).toBeNull(); | 537 | expect(titles[2]!.querySelector("svg[data-pierre-icon]")).toBeNull(); |
| 450 | expect(titles[2]!.textContent).toBe("text"); | 538 | expect(titles[2]!.textContent).toBe("text"); |
| 451 | } finally { | 539 | } finally { |
| 452 | await screen.unmount(); | 540 | await screen.unmount(); |
| @@ -33,12 +33,8 @@ import remarkBreaks from "remark-breaks"; · 32 unmodified lines | |||
| 33 | import remarkGfm from "remark-gfm"; | 33 | import remarkGfm from "remark-gfm"; |
| 34 | import { renderSkillInlineMarkdownChildren } from "./chat/SkillInlineText"; | 34 | import { renderSkillInlineMarkdownChildren } from "./chat/SkillInlineText"; |
| 35 | import { CHAT_FILE_TAG_CHIP_CLASS_NAME, FileTagChipContent } from "./chat/FileTagChip"; | 35 | import { CHAT_FILE_TAG_CHIP_CLASS_NAME, FileTagChipContent } from "./chat/FileTagChip"; |
| 36 | import { VscodeEntryIcon } from "./chat/VscodeEntryIcon"; | 36 | import { PierreEntryIcon } from "./chat/PierreEntryIcon"; |
| 37 | import { | 37 | import { hasSpecificPierreIconForFileName, syntheticFileNameForLanguageId } from "../pierre-icons"; |
| 38 | getVscodeIconUrlForEntry, | ||
| 39 | hasSpecificVscodeIconForFileName, | ||
| 40 | syntheticFileNameForLanguageId, | ||
| 41 | } from "../vscode-icons"; | ||
| 42 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | 38 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; |
| 43 | import { Button } from "./ui/button"; | 39 | import { Button } from "./ui/button"; |
| 44 | import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "./ui/collapsible"; | 40 | import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "./ui/collapsible"; |
| @@ -62,6 +58,7 @@ import { · 17 unmodified lines | |||
| 62 | } from "../markdown-links"; | 58 | } from "../markdown-links"; |
| 63 | import { readLocalApi } from "../localApi"; | 59 | import { readLocalApi } from "../localApi"; |
| 64 | import { cn } from "../lib/utils"; | 60 | import { cn } from "../lib/utils"; |
| 61 | import { useRightPanelStore } from "../rightPanelStore"; | ||
| 65 | import { isPreviewSupportedInRuntime } from "../previewStateStore"; | 62 | import { isPreviewSupportedInRuntime } from "../previewStateStore"; |
| 66 | import { | 63 | import { |
| 67 | isBrowserPreviewFile, | 64 | isBrowserPreviewFile, |
| @@ -443,22 +440,17 @@ function MarkdownCodeBlockTitleContent({ · 375 unmodified lines | |||
| 443 | language: string; | 440 | language: string; |
| 444 | theme: "light" | "dark"; | 441 | theme: "light" | "dark"; |
| 445 | }) { | 442 | }) { |
| 446 | const [failedIconUrl, setFailedIconUrl] = useState<string | null>(null); | ||
| 447 | |||
| 448 | if (fenceTitle) { | 443 | if (fenceTitle) { |
| 449 | return ( | 444 | return ( |
| 450 | <> | 445 | <> |
| 451 | <VscodeEntryIcon pathValue={fenceTitle} kind="file" theme={theme} className="size-3.5" /> | 446 | <PierreEntryIcon pathValue={fenceTitle} kind="file" theme={theme} className="size-3.5" /> |
| 452 | <span className="truncate">{fenceTitle}</span> | 447 | <span className="truncate">{fenceTitle}</span> |
| 453 | </> | 448 | </> |
| 454 | ); | 449 | ); |
| 455 | } | 450 | } |
| 456 | 451 | ||
| 457 | const fileName = syntheticFileNameForLanguageId(language); | 452 | const fileName = syntheticFileNameForLanguageId(language); |
| 458 | const iconUrl = hasSpecificVscodeIconForFileName(fileName, theme) | 453 | if (!hasSpecificPierreIconForFileName(fileName)) { |
| 459 | ? getVscodeIconUrlForEntry(fileName, "file", theme) | ||
| 460 | : null; | ||
| 461 | if (!iconUrl || failedIconUrl === iconUrl) { | ||
| 462 | return <span className="truncate">{language}</span>; | 454 | return <span className="truncate">{language}</span>; |
| 463 | } | 455 | } |
| 464 | return ( | 456 | return ( |
| @@ -468,15 +460,7 @@ function MarkdownCodeBlockTitleContent({ · 3 unmodified lines | |||
| 468 | <span className="inline-flex shrink-0 rounded-sm" aria-label={`Language: ${language}`} /> | 460 | <span className="inline-flex shrink-0 rounded-sm" aria-label={`Language: ${language}`} /> |
| 469 | } | 461 | } |
| 470 | > | 462 | > |
| 471 | <img | 463 | <PierreEntryIcon pathValue={fileName} kind="file" theme={theme} className="size-3.5" /> |
| 472 | src={iconUrl} | ||
| 473 | alt="" | ||
| 474 | aria-hidden | ||
| 475 | className="size-3.5 shrink-0" | ||
| 476 | loading="lazy" | ||
| 477 | draggable={false} | ||
| 478 | onError={() => setFailedIconUrl(iconUrl)} | ||
| 479 | /> | ||
| 480 | </TooltipTrigger> | 464 | </TooltipTrigger> |
| 481 | <TooltipPopup side="top">{language}</TooltipPopup> | 465 | <TooltipPopup side="top">{language}</TooltipPopup> |
| 482 | </Tooltip> | 466 | </Tooltip> |
| @@ -674,6 +658,7 @@ interface MarkdownFileLinkProps { · 191 unmodified lines | |||
| 674 | targetPath: string; | 658 | targetPath: string; |
| 675 | iconPath: string; | 659 | iconPath: string; |
| 676 | displayPath: string; | 660 | displayPath: string; |
| 661 | workspaceRelativePath: string | null; | ||
| 677 | label: string; | 662 | label: string; |
| 678 | copyMarkdown: string; | 663 | copyMarkdown: string; |
| 679 | theme: "light" | "dark"; | 664 | theme: "light" | "dark"; |
| @@ -997,13 +982,14 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ · 317 unmodified lines | |||
| 997 | targetPath, | 982 | targetPath, |
| 998 | iconPath, | 983 | iconPath, |
| 999 | displayPath, | 984 | displayPath, |
| 985 | workspaceRelativePath, | ||
| 1000 | label, | 986 | label, |
| 1001 | copyMarkdown, | 987 | copyMarkdown, |
| 1002 | theme, | 988 | theme, |
| 1003 | threadRef, | 989 | threadRef, |
| 1004 | className, | 990 | className, |
| 1005 | }: MarkdownFileLinkProps) { | 991 | }: MarkdownFileLinkProps) { |
| 1006 | const handleOpen = useCallback(() => { | 992 | const handleOpenInEditor = useCallback(() => { |
| 1007 | const api = readLocalApi(); | 993 | const api = readLocalApi(); |
| 1008 | if (!api) { | 994 | if (!api) { |
| 1009 | toastManager.add({ | 995 | toastManager.add({ |
| @@ -1024,6 +1010,14 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ · 14 unmodified lines | |||
| 1024 | }); | 1010 | }); |
| 1025 | }, [targetPath]); | 1011 | }, [targetPath]); |
| 1026 | 1012 | ||
| 1013 | const handleOpenInFilePreview = useCallback(() => { | ||
| 1014 | if (!threadRef || !workspaceRelativePath) { | ||
| 1015 | handleOpenInEditor(); | ||
| 1016 | return; | ||
| 1017 | } | ||
| 1018 | useRightPanelStore.getState().openFile(threadRef, workspaceRelativePath); | ||
| 1019 | }, [handleOpenInEditor, threadRef, workspaceRelativePath]); | ||
| 1020 | |||
| 1027 | const handleOpenInBrowser = useCallback(() => { | 1021 | const handleOpenInBrowser = useCallback(() => { |
| 1028 | if (!threadRef) return; | 1022 | if (!threadRef) return; |
| 1029 | void openFileInPreview(threadRef, iconPath).catch((error) => { | 1023 | void openFileInPreview(threadRef, iconPath).catch((error) => { |
| @@ -1092,7 +1086,7 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ · 62 unmodified lines | |||
| 1092 | ); | 1086 | ); |
| 1093 | 1087 | ||
| 1094 | if (clicked === "open") { | 1088 | if (clicked === "open") { |
| 1095 | handleOpen(); | 1089 | handleOpenInEditor(); |
| 1096 | return; | 1090 | return; |
| 1097 | } | 1091 | } |
| 1098 | if (clicked === "open-in-browser") { | 1092 | if (clicked === "open-in-browser") { |
| @@ -1107,7 +1101,15 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ · 8 unmodified lines | |||
| 1107 | handleCopy(targetPath, "Full path"); | 1101 | handleCopy(targetPath, "Full path"); |
| 1108 | } | 1102 | } |
| 1109 | }, | 1103 | }, |
| 1110 | [displayPath, handleCopy, handleOpen, handleOpenInBrowser, iconPath, targetPath, threadRef], | 1104 | [ |
| 1105 | displayPath, | ||
| 1106 | handleCopy, | ||
| 1107 | handleOpenInBrowser, | ||
| 1108 | handleOpenInEditor, | ||
| 1109 | iconPath, | ||
| 1110 | targetPath, | ||
| 1111 | threadRef, | ||
| 1112 | ], | ||
| 1111 | ); | 1113 | ); |
| 1112 | 1114 | ||
| 1113 | return ( | 1115 | return ( |
| @@ -1121,7 +1123,11 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ · 7 unmodified lines | |||
| 1121 | onClick={(event) => { | 1123 | onClick={(event) => { |
| 1122 | event.preventDefault(); | 1124 | event.preventDefault(); |
| 1123 | event.stopPropagation(); | 1125 | event.stopPropagation(); |
| 1124 | handleOpen(); | 1126 | if (threadRef && isPreviewSupportedInRuntime() && isBrowserPreviewFile(iconPath)) { |
| 1127 | handleOpenInBrowser(); | ||
| 1128 | return; | ||
| 1129 | } | ||
| 1130 | handleOpenInFilePreview(); | ||
| 1125 | }} | 1131 | }} |
| 1126 | onContextMenu={handleContextMenu} | 1132 | onContextMenu={handleContextMenu} |
| 1127 | > | 1133 | > |
| @@ -1150,6 +1156,7 @@ function areMarkdownFileLinkPropsEqual( · 22 unmodified lines | |||
| 1150 | previous.targetPath === next.targetPath && | 1156 | previous.targetPath === next.targetPath && |
| 1151 | previous.iconPath === next.iconPath && | 1157 | previous.iconPath === next.iconPath && |
| 1152 | previous.displayPath === next.displayPath && | 1158 | previous.displayPath === next.displayPath && |
| 1159 | previous.workspaceRelativePath === next.workspaceRelativePath && | ||
| 1153 | previous.label === next.label && | 1160 | previous.label === next.label && |
| 1154 | previous.copyMarkdown === next.copyMarkdown && | 1161 | previous.copyMarkdown === next.copyMarkdown && |
| 1155 | previous.theme === next.theme && | 1162 | previous.theme === next.theme && |
| @@ -1274,6 +1281,7 @@ function ChatMarkdown({ · 118 unmodified lines | |||
| 1274 | targetPath={fileLinkMeta.targetPath} | 1281 | targetPath={fileLinkMeta.targetPath} |
| 1275 | iconPath={fileLinkMeta.filePath} | 1282 | iconPath={fileLinkMeta.filePath} |
| 1276 | displayPath={fileLinkMeta.displayPath} | 1283 | displayPath={fileLinkMeta.displayPath} |
| 1284 | workspaceRelativePath={fileLinkMeta.workspaceRelativePath} | ||
| 1277 | label={labelParts.join(" · ")} | 1285 | label={labelParts.join(" · ")} |
| 1278 | copyMarkdown={`[${fileLinkMeta.basename}](${normalizedHref})`} | 1286 | copyMarkdown={`[${fileLinkMeta.basename}](${normalizedHref})`} |
| 1279 | theme={resolvedTheme} | 1287 | theme={resolvedTheme} |
| @@ -53,7 +53,7 @@ import { · 52 unmodified lines | |||
| 53 | resetSavedEnvironmentRuntimeStoreForTests, | 53 | resetSavedEnvironmentRuntimeStoreForTests, |
| 54 | useSavedEnvironmentRegistryStore, | 54 | useSavedEnvironmentRegistryStore, |
| 55 | useSavedEnvironmentRuntimeStore, | 55 | useSavedEnvironmentRuntimeStore, |
| 56 | } from "../environments/runtime"; | 56 | } from "../environments/runtime/catalog"; |
| 57 | import { | 57 | import { |
| 58 | INLINE_TERMINAL_CONTEXT_PLACEHOLDER, | 58 | INLINE_TERMINAL_CONTEXT_PLACEHOLDER, |
| 59 | removeInlineTerminalContextPlaceholder, | 59 | removeInlineTerminalContextPlaceholder, |
| @@ -2110,6 +2110,360 @@ describe("ChatView timeline estimator parity (full app)", () => { · 2050 unmodified lines | |||
| 2110 | } | 2110 | } |
| 2111 | }); | 2111 | }); |
| 2112 | 2112 | ||
| 2113 | it("keeps panel toggles fixed and can maximize the right panel", async () => { | ||
| 2114 | const mounted = await mountChatView({ | ||
| 2115 | viewport: WIDE_FOOTER_VIEWPORT, | ||
| 2116 | snapshot: createSnapshotForTargetUser({ | ||
| 2117 | targetMessageId: "msg-user-maximize-right-panel" as MessageId, | ||
| 2118 | targetText: "maximize right panel", | ||
| 2119 | }), | ||
| 2120 | }); | ||
| 2121 | |||
| 2122 | try { | ||
| 2123 | const terminalToggle = await waitForElement( | ||
| 2124 | () => | ||
| 2125 | document.querySelector<HTMLButtonElement>('button[aria-label="Toggle terminal drawer"]'), | ||
| 2126 | "Unable to find terminal drawer toggle.", | ||
| 2127 | ); | ||
| 2128 | const rightPanelToggle = await waitForElement( | ||
| 2129 | () => document.querySelector<HTMLButtonElement>('button[aria-label="Toggle right panel"]'), | ||
| 2130 | "Unable to find right panel toggle.", | ||
| 2131 | ); | ||
| 2132 | const headerActions = await waitForElement( | ||
| 2133 | () => document.querySelector<HTMLElement>("[data-chat-header-actions]"), | ||
| 2134 | "Unable to find chat header actions.", | ||
| 2135 | ); | ||
| 2136 | const chatHeader = await waitForElement( | ||
| 2137 | () => document.querySelector<HTMLElement>("[data-chat-header]"), | ||
| 2138 | "Unable to find chat header.", | ||
| 2139 | ); | ||
| 2140 | const panelLayoutControls = await waitForElement( | ||
| 2141 | () => document.querySelector<HTMLElement>("[data-panel-layout-controls]"), | ||
| 2142 | "Unable to find panel layout controls.", | ||
| 2143 | ); | ||
| 2144 | expect(chatHeader.getBoundingClientRect().height).toBe(52); | ||
| 2145 | expect(panelLayoutControls.getBoundingClientRect().height).toBe(52); | ||
| 2146 | expect(panelLayoutControls.getBoundingClientRect().top).toBe( | ||
| 2147 | chatHeader.getBoundingClientRect().top, | ||
| 2148 | ); | ||
| 2149 | const initialTerminalRect = terminalToggle.getBoundingClientRect(); | ||
| 2150 | const initialRightPanelRect = rightPanelToggle.getBoundingClientRect(); | ||
| 2151 | const initialControlRects = [initialTerminalRect, initialRightPanelRect]; | ||
| 2152 | expect(document.querySelector('button[aria-label="Maximize panel"]')).toBeNull(); | ||
| 2153 | expect(initialControlRects.every((rect) => rect.width === 28 && rect.height === 28)).toBe( | ||
| 2154 | true, | ||
| 2155 | ); | ||
| 2156 | expect(initialControlRects.every((rect) => rect.top === initialControlRects[0]?.top)).toBe( | ||
| 2157 | true, | ||
| 2158 | ); | ||
| 2159 | expect(initialRightPanelRect.left - initialTerminalRect.right).toBe(4); | ||
| 2160 | expect( | ||
| 2161 | initialTerminalRect.left - | ||
| 2162 | (headerActions.lastElementChild?.getBoundingClientRect().right ?? Number.NaN), | ||
| 2163 | ).toBe(4); | ||
| 2164 | |||
| 2165 | document.documentElement.classList.add("wco"); | ||
| 2166 | expect(panelLayoutControls.getBoundingClientRect().height).toBe(52); | ||
| 2167 | expect(panelLayoutControls.getBoundingClientRect().top).toBe( | ||
| 2168 | chatHeader.getBoundingClientRect().top, | ||
| 2169 | ); | ||
| 2170 | document.documentElement.classList.remove("wco"); | ||
| 2171 | |||
| 2172 | rightPanelToggle.click(); | ||
| 2173 | |||
| 2174 | const maximizeButton = await waitForElement( | ||
| 2175 | () => document.querySelector<HTMLButtonElement>('button[aria-label="Maximize panel"]'), | ||
| 2176 | "Unable to find maximize panel button.", | ||
| 2177 | ); | ||
| 2178 | const rightPanelTabbar = await waitForElement( | ||
| 2179 | () => document.querySelector<HTMLElement>("[data-right-panel-tabbar]"), | ||
| 2180 | "Unable to find right panel tab bar.", | ||
| 2181 | ); | ||
| 2182 | const maximizeRect = maximizeButton.getBoundingClientRect(); | ||
| 2183 | const rightPanelTabbarRect = rightPanelTabbar.getBoundingClientRect(); | ||
| 2184 | expect(document.querySelector('button[aria-label="Add panel surface"]')).toBeNull(); | ||
| 2185 | expect(rightPanelTabbarRect.height).toBe(52); | ||
| 2186 | expect(rightPanelTabbarRect.top).toBe(chatHeader.getBoundingClientRect().top); | ||
| 2187 | expect(maximizeRect.width).toBe(28); | ||
| 2188 | expect(maximizeRect.height).toBe(28); | ||
| 2189 | expect(maximizeRect.top).toBe(initialTerminalRect.top); | ||
| 2190 | expect(initialTerminalRect.left - maximizeRect.right).toBe(4); | ||
| 2191 | expect(terminalToggle.getBoundingClientRect().left).toBeCloseTo(initialTerminalRect.left, 1); | ||
| 2192 | expect(rightPanelToggle.getBoundingClientRect().left).toBeCloseTo( | ||
| 2193 | initialRightPanelRect.left, | ||
| 2194 | 1, | ||
| 2195 | ); | ||
| 2196 | |||
| 2197 | useRightPanelStore.getState().openFile(THREAD_REF, "components.json"); | ||
| 2198 | const fileTabIcon = await waitForElement( | ||
| 2199 | () => | ||
| 2200 | document.querySelector<SVGElement>( | ||
| 2201 | '[data-right-panel-tabbar] [data-pierre-icon][data-icon-token="json"]', | ||
| 2202 | ), | ||
| 2203 | "Unable to find the Pierre file icon in the file tab.", | ||
| 2204 | ); | ||
| 2205 | expect(fileTabIcon.closest("button")?.textContent).toContain("components.json"); | ||
| 2206 | |||
| 2207 | document.documentElement.classList.add("wco"); | ||
| 2208 | expect(rightPanelTabbar.getBoundingClientRect().height).toBe( | ||
| 2209 | panelLayoutControls.getBoundingClientRect().height, | ||
| 2210 | ); | ||
| 2211 | expect(rightPanelTabbar.getBoundingClientRect().top).toBe( | ||
| 2212 | panelLayoutControls.getBoundingClientRect().top, | ||
| 2213 | ); | ||
| 2214 | document.documentElement.classList.remove("wco"); | ||
| 2215 | |||
| 2216 | maximizeButton.click(); | ||
| 2217 | |||
| 2218 | await vi.waitFor(() => { | ||
| 2219 | const chatColumn = document.querySelector<HTMLElement>( | ||
| 2220 | '[data-chat-column-maximized-away="true"]', | ||
| 2221 | ); | ||
| 2222 | const panel = document.querySelector<HTMLElement>( | ||
| 2223 | '[data-preview-panel-mode="inline"][data-preview-panel-maximized="true"]', | ||
| 2224 | ); | ||
| 2225 | expect(chatColumn?.getBoundingClientRect().width).toBe(0); | ||
| 2226 | expect(panel?.getBoundingClientRect().width).toBeGreaterThan(1_000); | ||
| 2227 | expect( | ||
| 2228 | document.querySelector<HTMLButtonElement>('button[aria-label="Restore panel size"]'), | ||
| 2229 | ).not.toBeNull(); | ||
| 2230 | expect(terminalToggle.getBoundingClientRect().left).toBeCloseTo( | ||
| 2231 | initialTerminalRect.left, | ||
| 2232 | 1, | ||
| 2233 | ); | ||
| 2234 | expect(rightPanelToggle.getBoundingClientRect().left).toBeCloseTo( | ||
| 2235 | initialRightPanelRect.left, | ||
| 2236 | 1, | ||
| 2237 | ); | ||
| 2238 | }); | ||
| 2239 | } finally { | ||
| 2240 | await mounted.cleanup(); | ||
| 2241 | } | ||
| 2242 | }); | ||
| 2243 | |||
| 2244 | it("scrolls file tabs and preserves the workspace explorer across file previews", async () => { | ||
| 2245 | const workspaceEntries = [ | ||
| 2246 | { path: "src", kind: "directory" as const }, | ||
| 2247 | { path: "src/index.ts", kind: "file" as const }, | ||
| 2248 | { path: "src/router.ts", kind: "file" as const }, | ||
| 2249 | { path: "src/store.ts", kind: "file" as const }, | ||
| 2250 | { path: "src/styles.css", kind: "file" as const }, | ||
| 2251 | { path: "src/large.ts", kind: "file" as const }, | ||
| 2252 | { path: "e2e", kind: "directory" as const }, | ||
| 2253 | { path: "e2e/test-results", kind: "directory" as const }, | ||
| 2254 | { | ||
| 2255 | path: "e2e/test-results/playwright-integration-results", | ||
| 2256 | kind: "directory" as const, | ||
| 2257 | }, | ||
| 2258 | { | ||
| 2259 | path: "e2e/test-results/playwright-integration-results/chromium-desktop-project", | ||
| 2260 | kind: "directory" as const, | ||
| 2261 | }, | ||
| 2262 | { | ||
| 2263 | path: "e2e/test-results/playwright-integration-results/chromium-desktop-project/.last-run.json", | ||
| 2264 | kind: "file" as const, | ||
| 2265 | }, | ||
| 2266 | { path: "README.md", kind: "file" as const }, | ||
| 2267 | { path: "AGENTS.md", kind: "file" as const }, | ||
| 2268 | { path: "package.json", kind: "file" as const }, | ||
| 2269 | { path: "tsconfig.json", kind: "file" as const }, | ||
| 2270 | ]; | ||
| 2271 | const mounted = await mountChatView({ | ||
| 2272 | viewport: WIDE_FOOTER_VIEWPORT, | ||
| 2273 | snapshot: createSnapshotForTargetUser({ | ||
| 2274 | targetMessageId: "msg-user-file-tabs-and-tree-state" as MessageId, | ||
| 2275 | targetText: "keep file tabs readable and preserve tree state", | ||
| 2276 | }), | ||
| 2277 | resolveRpc: (body) => { | ||
| 2278 | if (body._tag === WS_METHODS.projectsListEntries) { | ||
| 2279 | return { entries: workspaceEntries, truncated: false }; | ||
| 2280 | } | ||
| 2281 | if (body._tag === WS_METHODS.projectsReadFile) { | ||
| 2282 | const relativePath = | ||
| 2283 | typeof body.relativePath === "string" ? body.relativePath : "file.ts"; | ||
| 2284 | const contents = | ||
| 2285 | relativePath === "src/large.ts" | ||
| 2286 | ? Array.from( | ||
| 2287 | { length: 5_000 }, | ||
| 2288 | (_, index) => `export const line${index + 1} = ${index + 1};`, | ||
| 2289 | ).join("\n") | ||
| 2290 | : `// ${relativePath}\n`; | ||
| 2291 | return { | ||
| 2292 | relativePath, | ||
| 2293 | contents, | ||
| 2294 | byteLength: new TextEncoder().encode(contents).byteLength, | ||
| 2295 | truncated: false, | ||
| 2296 | }; | ||
| 2297 | } | ||
| 2298 | return undefined; | ||
| 2299 | }, | ||
| 2300 | }); | ||
| 2301 | |||
| 2302 | try { | ||
| 2303 | useRightPanelStore.getState().open(THREAD_REF, "files"); | ||
| 2304 | |||
| 2305 | const explorer = await waitForElement( | ||
| 2306 | () => document.querySelector<HTMLElement>("[data-file-browser-panel]"), | ||
| 2307 | "Unable to find the workspace file explorer.", | ||
| 2308 | ); | ||
| 2309 | |||
| 2310 | for (const entry of workspaceEntries) { | ||
| 2311 | if (entry.kind === "file") { | ||
| 2312 | useRightPanelStore.getState().openFile(THREAD_REF, entry.path); | ||
| 2313 | } | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | const tabList = await waitForElement( | ||
| 2317 | () => document.querySelector<HTMLElement>("[data-right-panel-tab-list]"), | ||
| 2318 | "Unable to find the right panel tab list.", | ||
| 2319 | ); | ||
| 2320 | const tabViewport = await waitForElement( | ||
| 2321 | () => tabList.querySelector<HTMLElement>('[data-slot="scroll-area-viewport"]'), | ||
| 2322 | "Unable to find the right panel tab viewport.", | ||
| 2323 | ); | ||
| 2324 | |||
| 2325 | await vi.waitFor(() => { | ||
| 2326 | const fileTabs = Array.from(tabList.querySelectorAll<HTMLElement>("[data-active-tab]")); | ||
| 2327 | expect(fileTabs.length).toBe( | ||
| 2328 | workspaceEntries.filter((entry) => entry.kind === "file").length, | ||
| 2329 | ); | ||
| 2330 | expect(tabViewport.scrollWidth).toBeGreaterThan(tabViewport.clientWidth); | ||
| 2331 | expect(tabViewport.scrollLeft).toBeGreaterThan(0); | ||
| 2332 | expect(tabList.querySelector('[data-slot="scroll-area-scrollbar"]')).toBeNull(); | ||
| 2333 | expect( | ||
| 2334 | fileTabs.every((tab) => { | ||
| 2335 | const width = tab.getBoundingClientRect().width; | ||
| 2336 | return width >= 100 && width <= 176; | ||
| 2337 | }), | ||
| 2338 | ).toBe(true); | ||
| 2339 | expect(document.querySelector<HTMLElement>("[data-file-browser-panel]")).toBe(explorer); | ||
| 2340 | }); | ||
| 2341 | |||
| 2342 | useRightPanelStore.getState().openFile(THREAD_REF, "src/index.ts"); | ||
| 2343 | await vi.waitFor(() => { | ||
| 2344 | expect(document.querySelector<HTMLElement>("[data-file-browser-panel]")).toBe(explorer); | ||
| 2345 | }); | ||
| 2346 | |||
| 2347 | useRightPanelStore | ||
| 2348 | .getState() | ||
| 2349 | .openFile( | ||
| 2350 | THREAD_REF, | ||
| 2351 | "e2e/test-results/playwright-integration-results/chromium-desktop-project/.last-run.json", | ||
| 2352 | ); | ||
| 2353 | await mounted.setContainerSize({ width: 800, height: WIDE_FOOTER_VIEWPORT.height }); | ||
| 2354 | const breadcrumbs = await waitForElement( | ||
| 2355 | () => document.querySelector<HTMLElement>("[data-file-breadcrumbs]"), | ||
| 2356 | "Unable to find the responsive file breadcrumbs.", | ||
| 2357 | ); | ||
| 2358 | const breadcrumbViewport = await waitForElement( | ||
| 2359 | () => breadcrumbs.querySelector<HTMLElement>('[data-slot="scroll-area-viewport"]'), | ||
| 2360 | "Unable to find the file breadcrumb viewport.", | ||
| 2361 | ); | ||
| 2362 | const currentCrumb = await waitForElement( | ||
| 2363 | () => | ||
| 2364 | Array.from( | ||
| 2365 | breadcrumbs.querySelectorAll<HTMLElement>("[data-current-file-crumb='true']"), | ||
| 2366 | ).find((crumb) => crumb.textContent === ".last-run.json") ?? null, | ||
| 2367 | "Unable to find the current file breadcrumb.", | ||
| 2368 | ); | ||
| 2369 | const explorerToggle = await waitForElement( | ||
| 2370 | () => document.querySelector<HTMLButtonElement>('button[aria-label="Hide file explorer"]'), | ||
| 2371 | "Unable to find the file explorer toggle.", | ||
| 2372 | ); | ||
| 2373 | |||
| 2374 | await vi.waitFor(() => { | ||
| 2375 | const viewportRect = breadcrumbViewport.getBoundingClientRect(); | ||
| 2376 | const currentCrumbRect = currentCrumb.getBoundingClientRect(); | ||
| 2377 | expect(breadcrumbViewport.scrollWidth).toBeGreaterThan(breadcrumbViewport.clientWidth); | ||
| 2378 | expect(breadcrumbViewport.scrollLeft).toBeGreaterThan(0); | ||
| 2379 | expect(breadcrumbs.querySelector('[data-slot="scroll-area-scrollbar"]')).toBeNull(); | ||
| 2380 | expect(currentCrumbRect.right).toBeLessThanOrEqual(viewportRect.right + 1); | ||
| 2381 | expect(viewportRect.right).toBeLessThan(explorerToggle.getBoundingClientRect().left); | ||
| 2382 | expect(explorerToggle.getAttribute("aria-pressed")).toBe("true"); | ||
| 2383 | expect(explorerToggle.getBoundingClientRect().width).toBe(28); | ||
| 2384 | expect(explorerToggle.getBoundingClientRect().height).toBe(28); | ||
| 2385 | }); | ||
| 2386 | |||
| 2387 | const fileSearchButton = await waitForElement( | ||
| 2388 | () => | ||
| 2389 | document.querySelector<HTMLButtonElement>('button[aria-label="Search workspace files"]'), | ||
| 2390 | "Unable to find the workspace file search button.", | ||
| 2391 | ); | ||
| 2392 | fileSearchButton.click(); | ||
| 2393 | const fileTree = await waitForElement( | ||
| 2394 | () => document.querySelector<HTMLElement>("file-tree-container"), | ||
| 2395 | "Unable to find the file tree host.", | ||
| 2396 | ); | ||
| 2397 | const fileSearchInput = await waitForElement( | ||
| 2398 | () => | ||
| 2399 | fileTree.shadowRoot?.querySelector<HTMLInputElement>("[data-file-tree-search-input]") ?? | ||
| 2400 | null, | ||
| 2401 | "Unable to find the file tree search input.", | ||
| 2402 | ); | ||
| 2403 | fileSearchInput.focus(); | ||
| 2404 | const searchKeyEvent = new KeyboardEvent("keydown", { | ||
| 2405 | key: "r", | ||
| 2406 | bubbles: true, | ||
| 2407 | cancelable: true, | ||
| 2408 | composed: true, | ||
| 2409 | }); | ||
| 2410 | fileSearchInput.dispatchEvent(searchKeyEvent); | ||
| 2411 | await waitForLayout(); | ||
| 2412 | expect(searchKeyEvent.defaultPrevented).toBe(false); | ||
| 2413 | expect(fileTree.shadowRoot?.activeElement).toBe(fileSearchInput); | ||
| 2414 | expect(useComposerDraftStore.getState().draftsByThreadKey[THREAD_KEY]?.prompt ?? "").toBe(""); | ||
| 2415 | |||
| 2416 | useRightPanelStore.getState().openFile(THREAD_REF, "src/large.ts"); | ||
| 2417 | const codeVirtualizer = await waitForElement( | ||
| 2418 | () => document.querySelector<HTMLElement>(".file-preview-virtualizer"), | ||
| 2419 | "Unable to find the virtualized file preview.", | ||
| 2420 | ); | ||
| 2421 | expect(codeVirtualizer.querySelector("diffs-container")).not.toBeNull(); | ||
| 2422 | expect(codeVirtualizer.classList.contains("overflow-auto")).toBe(true); | ||
| 2423 | } finally { | ||
| 2424 | await mounted.cleanup(); | ||
| 2425 | } | ||
| 2426 | }); | ||
| 2427 | |||
| 2428 | it("removes persisted file tabs when a draft workspace no longer exists", async () => { | ||
| 2429 | const orphanedDraftId = DraftId.make("draft-orphaned-file-panel"); | ||
| 2430 | const orphanedThreadId = "thread-orphaned-file-panel" as ThreadId; | ||
| 2431 | const orphanedThreadRef = scopeThreadRef(LOCAL_ENVIRONMENT_ID, orphanedThreadId); | ||
| 2432 | useComposerDraftStore.getState().setProjectDraftThreadId( | ||
| 2433 | { | ||
| 2434 | environmentId: LOCAL_ENVIRONMENT_ID, | ||
| 2435 | projectId: "project-deleted" as ProjectId, | ||
| 2436 | }, | ||
| 2437 | orphanedDraftId, | ||
| 2438 | { threadId: orphanedThreadId }, | ||
| 2439 | ); | ||
| 2440 | useRightPanelStore.getState().openFile(orphanedThreadRef, "conductor.json"); | ||
| 2441 | |||
| 2442 | const mounted = await mountChatView({ | ||
| 2443 | viewport: WIDE_FOOTER_VIEWPORT, | ||
| 2444 | snapshot: createSnapshotForTargetUser({ | ||
| 2445 | targetMessageId: "msg-user-orphaned-file-panel" as MessageId, | ||
| 2446 | targetText: "orphaned persisted file panel", | ||
| 2447 | }), | ||
| 2448 | initialPath: `/draft/${orphanedDraftId}`, | ||
| 2449 | }); | ||
| 2450 | |||
| 2451 | try { | ||
| 2452 | await vi.waitFor(() => { | ||
| 2453 | expect( | ||
| 2454 | selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, orphanedThreadRef), | ||
| 2455 | ).toEqual({ | ||
| 2456 | isOpen: false, | ||
| 2457 | activeSurfaceId: null, | ||
| 2458 | surfaces: [], | ||
| 2459 | }); | ||
| 2460 | expect(document.querySelector("[data-right-panel-tabbar]")).toBeNull(); | ||
| 2461 | }); | ||
| 2462 | } finally { | ||
| 2463 | await mounted.cleanup(); | ||
| 2464 | } | ||
| 2465 | }); | ||
| 2466 | |||
| 2113 | it("keeps multiple terminal panel surfaces separate from the bottom drawer", async () => { | 2467 | it("keeps multiple terminal panel surfaces separate from the bottom drawer", async () => { |
| 2114 | const mounted = await mountChatView({ | 2468 | const mounted = await mountChatView({ |
| 2115 | viewport: WIDE_FOOTER_VIEWPORT, | 2469 | viewport: WIDE_FOOTER_VIEWPORT, |
| @@ -2126,11 +2480,10 @@ describe("ChatView timeline estimator parity (full app)", () => { · 10 unmodified lines | |||
| 2126 | ); | 2480 | ); |
| 2127 | rightPanelToggle.click(); | 2481 | rightPanelToggle.click(); |
| 2128 | 2482 | ||
| 2129 | const addSurface = await waitForElement( | 2483 | await vi.waitFor(() => { |
| 2130 | () => document.querySelector<HTMLButtonElement>('button[aria-label="Add panel surface"]'), | 2484 | expect(document.body.textContent).toContain("Open a surface"); |
| 2131 | "Unable to find add panel surface button.", | 2485 | }); |
| 2132 | ); | 2486 | expect(document.querySelector('button[aria-label="Add panel surface"]')).toBeNull(); |
| 2133 | expect(document.body.textContent).toContain("Open a surface"); | ||
| 2134 | expect( | 2487 | expect( |
| 2135 | selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, THREAD_REF), | 2488 | selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, THREAD_REF), |
| 2136 | ).toEqual({ | 2489 | ).toEqual({ |
| @@ -2140,16 +2493,14 @@ describe("ChatView timeline estimator parity (full app)", () => { · 3 unmodified lines | |||
| 2140 | }); | 2493 | }); |
| 2141 | expect(wsRequests.some((request) => request._tag === WS_METHODS.terminalOpen)).toBe(false); | 2494 | expect(wsRequests.some((request) => request._tag === WS_METHODS.terminalOpen)).toBe(false); |
| 2142 | 2495 | ||
| 2143 | addSurface.click(); | 2496 | const emptyStateTerminalButton = await waitForElement( |
| 2144 | |||
| 2145 | const terminalItem = await waitForElement( | ||
| 2146 | () => | 2497 | () => |
| 2147 | Array.from(document.querySelectorAll<HTMLElement>('[role="menuitem"]')).find( | 2498 | Array.from(document.querySelectorAll<HTMLButtonElement>("button")).find((button) => |
| 2148 | (item) => item.textContent?.trim() === "Terminal", | 2499 | button.textContent?.includes("Start a shell in this workspace."), |
| 2149 | ) ?? null, | 2500 | ) ?? null, |
| 2150 | "Unable to find Terminal panel menu item.", | 2501 | "Unable to find the empty-state Terminal button.", |
| 2151 | ); | 2502 | ); |
| 2152 | terminalItem.click(); | 2503 | emptyStateTerminalButton.click(); |
| 2153 | 2504 | ||
| 2154 | await vi.waitFor(() => { | 2505 | await vi.waitFor(() => { |
| 2155 | expect( | 2506 | expect( |
| @@ -2159,6 +2510,10 @@ describe("ChatView timeline estimator parity (full app)", () => { · 3 unmodified lines | |||
| 2159 | ).toEqual(["term-1"]); | 2510 | ).toEqual(["term-1"]); |
| 2160 | }); | 2511 | }); |
| 2161 | 2512 | ||
| 2513 | const addSurface = await waitForElement( | ||
| 2514 | () => document.querySelector<HTMLButtonElement>('button[aria-label="Add panel surface"]'), | ||
| 2515 | "Unable to find add panel surface button beside the tabs.", | ||
| 2516 | ); | ||
| 2162 | addSurface.click(); | 2517 | addSurface.click(); |
| 2163 | const secondTerminalItem = await waitForElement( | 2518 | const secondTerminalItem = await waitForElement( |
| 2164 | () => | 2519 | () => |
| @@ -35,7 +35,7 @@ import { lazy, memo, Suspense, useCallback, useEffect, useMemo, useRef, useState · 34 unmodified lines | |||
| 35 | import { useNavigate, useSearch } from "@tanstack/react-router"; | 35 | import { useNavigate, useSearch } from "@tanstack/react-router"; |
| 36 | import { useShallow } from "zustand/react/shallow"; | 36 | import { useShallow } from "zustand/react/shallow"; |
| 37 | import { useVcsStatus } from "~/lib/vcsStatusState"; | 37 | import { useVcsStatus } from "~/lib/vcsStatusState"; |
| 38 | import { usePrimaryEnvironmentId } from "../environments/primary"; | 38 | import { usePrimaryEnvironmentId } from "../environments/primary/context"; |
| 39 | import { readEnvironmentApi } from "../environmentApi"; | 39 | import { readEnvironmentApi } from "../environmentApi"; |
| 40 | import { resolveAssetUrl } from "../assets/assetUrls"; | 40 | import { resolveAssetUrl } from "../assets/assetUrls"; |
| 41 | import { isElectron } from "../env"; | 41 | import { isElectron } from "../env"; |
| @@ -67,7 +67,7 @@ import { · 25 unmodified lines | |||
| 67 | togglePendingUserInputOptionSelection, | 67 | togglePendingUserInputOptionSelection, |
| 68 | type PendingUserInputDraftAnswer, | 68 | type PendingUserInputDraftAnswer, |
| 69 | } from "../pendingUserInput"; | 69 | } from "../pendingUserInput"; |
| 70 | import { selectProjectsAcrossEnvironments, useStore } from "../store"; | 70 | import { selectEnvironmentState, selectProjectsAcrossEnvironments, useStore } from "../store"; |
| 71 | import { createProjectSelectorByRef, createThreadSelectorByRef } from "../storeSelectors"; | 71 | import { createProjectSelectorByRef, createThreadSelectorByRef } from "../storeSelectors"; |
| 72 | import { useUiStateStore } from "../uiStateStore"; | 72 | import { useUiStateStore } from "../uiStateStore"; |
| 73 | import { | 73 | import { |
| @@ -111,6 +111,8 @@ const PreviewPanel = lazy(() => · 37 unmodified lines | |||
| 111 | import("./preview/PreviewPanel").then((mod) => ({ default: mod.PreviewPanel })), | 111 | import("./preview/PreviewPanel").then((mod) => ({ default: mod.PreviewPanel })), |
| 112 | ); | 112 | ); |
| 113 | const DiffPanel = lazy(() => import("./DiffPanel")); | 113 | const DiffPanel = lazy(() => import("./DiffPanel")); |
| 114 | const FilePreviewPanel = lazy(() => import("./files/FilePreviewPanel")); | ||
| 115 | const EMPTY_PENDING_FILE_SURFACE_IDS: ReadonlySet<string> = new Set(); | ||
| 114 | import { BranchToolbar } from "./BranchToolbar"; | 116 | import { BranchToolbar } from "./BranchToolbar"; |
| 115 | import { resolveShortcutCommand, shortcutLabelForCommand } from "../keybindings"; | 117 | import { resolveShortcutCommand, shortcutLabelForCommand } from "../keybindings"; |
| 116 | import PlanSidebar from "./PlanSidebar"; | 118 | import PlanSidebar from "./PlanSidebar"; |
| @@ -137,10 +139,10 @@ import { · 20 unmodified lines | |||
| 137 | selectProjectGroupingSettings, | 139 | selectProjectGroupingSettings, |
| 138 | } from "../logicalProject"; | 140 | } from "../logicalProject"; |
| 139 | import { | 141 | import { |
| 140 | reconnectSavedEnvironment, | ||
| 141 | useSavedEnvironmentRegistryStore, | 142 | useSavedEnvironmentRegistryStore, |
| 142 | useSavedEnvironmentRuntimeStore, | 143 | useSavedEnvironmentRuntimeStore, |
| 143 | } from "../environments/runtime"; | 144 | } from "../environments/runtime/catalog"; |
| 145 | import { reconnectSavedEnvironment } from "../environments/runtime/service"; | ||
| 144 | import { buildDraftThreadRouteParams } from "../threadRoutes"; | 146 | import { buildDraftThreadRouteParams } from "../threadRoutes"; |
| 145 | import { | 147 | import { |
| 146 | type ComposerImageAttachment, | 148 | type ComposerImageAttachment, |
| @@ -167,6 +169,7 @@ import { ExpandedImageDialog } from "./chat/ExpandedImageDialog"; · 20 unmodified lines | |||
| 167 | import { PullRequestThreadDialog } from "./PullRequestThreadDialog"; | 169 | import { PullRequestThreadDialog } from "./PullRequestThreadDialog"; |
| 168 | import { MessagesTimeline } from "./chat/MessagesTimeline"; | 170 | import { MessagesTimeline } from "./chat/MessagesTimeline"; |
| 169 | import { ChatHeader } from "./chat/ChatHeader"; | 171 | import { ChatHeader } from "./chat/ChatHeader"; |
| 172 | import { PanelLayoutControls } from "./chat/PanelLayoutControls"; | ||
| 170 | import { type ExpandedImagePreview } from "./chat/ExpandedImagePreview"; | 173 | import { type ExpandedImagePreview } from "./chat/ExpandedImagePreview"; |
| 171 | import { NoActiveThreadState } from "./NoActiveThreadState"; | 174 | import { NoActiveThreadState } from "./NoActiveThreadState"; |
| 172 | import { resolveEffectiveEnvMode, resolveEnvironmentOptionLabel } from "./BranchToolbar.logic"; | 175 | import { resolveEffectiveEnvMode, resolveEnvironmentOptionLabel } from "./BranchToolbar.logic"; |
| @@ -256,10 +259,12 @@ type EnvironmentUnavailableState = { · 83 unmodified lines | |||
| 256 | 259 | ||
| 257 | type ThreadPlanCatalogEntry = Pick<Thread, "id" | "proposedPlans">; | 260 | type ThreadPlanCatalogEntry = Pick<Thread, "id" | "proposedPlans">; |
| 258 | 261 | ||
| 259 | function eventTargetElement(target: EventTarget | null): Element | null { | 262 | function eventPathContainsSelector(event: Event, selector: string): boolean { |
| 260 | if (target instanceof Element) return target; | 263 | const path = event.composedPath(); |
| 261 | if (target instanceof Node) return target.parentElement; | 264 | if (path.length === 0 && event.target) { |
| 262 | return null; | 265 | path.push(event.target); |
| 266 | } | ||
| 267 | return path.some((target) => target instanceof Element && target.closest(selector)); | ||
| 263 | } | 268 | } |
| 264 | 269 | ||
| 265 | function shouldTypeToFocusComposer(event: KeyboardEvent): boolean { | 270 | function shouldTypeToFocusComposer(event: KeyboardEvent): boolean { |
| @@ -267,9 +272,8 @@ function shouldTypeToFocusComposer(event: KeyboardEvent): boolean { · 1 unmodified line | |||
| 267 | if (event.metaKey || event.ctrlKey || event.altKey) return false; | 272 | if (event.metaKey || event.ctrlKey || event.altKey) return false; |
| 268 | if (event.key.length !== 1) return false; | 273 | if (event.key.length !== 1) return false; |
| 269 | 274 | ||
| 270 | const target = eventTargetElement(event.target); | 275 | if (eventPathContainsSelector(event, TYPE_TO_FOCUS_EDITABLE_SELECTOR)) return false; |
| 271 | if (target?.closest(TYPE_TO_FOCUS_EDITABLE_SELECTOR)) return false; | 276 | if (eventPathContainsSelector(event, TYPE_TO_FOCUS_INTERACTIVE_SELECTOR)) return false; |
| 272 | if (target?.closest(TYPE_TO_FOCUS_INTERACTIVE_SELECTOR)) return false; | ||
| 273 | if (document.querySelector(TYPE_TO_FOCUS_FLOATING_LAYER_SELECTOR)) return false; | 277 | if (document.querySelector(TYPE_TO_FOCUS_FLOATING_LAYER_SELECTOR)) return false; |
| 274 | 278 | ||
| 275 | return true; | 279 | return true; |
| @@ -1055,7 +1059,7 @@ const PersistentThreadTerminalPanel = memo(function PersistentThreadTerminalPane · 779 unmodified lines | |||
| 1055 | ); | 1059 | ); |
| 1056 | }); | 1060 | }); |
| 1057 | 1061 | ||
| 1058 | export default function ChatView(props: ChatViewProps) { | 1062 | function ChatViewContent(props: ChatViewProps) { |
| 1059 | const { | 1063 | const { |
| 1060 | environmentId, | 1064 | environmentId, |
| 1061 | threadId, | 1065 | threadId, |
| @@ -1152,6 +1156,9 @@ export default function ChatView(props: ChatViewProps) { · 90 unmodified lines | |||
| 1152 | >({}); | 1156 | >({}); |
| 1153 | const [isConnecting, _setIsConnecting] = useState(false); | 1157 | const [isConnecting, _setIsConnecting] = useState(false); |
| 1154 | const [isRevertingCheckpoint, setIsRevertingCheckpoint] = useState(false); | 1158 | const [isRevertingCheckpoint, setIsRevertingCheckpoint] = useState(false); |
| 1159 | const [maximizedRightPanelThreadKey, setMaximizedRightPanelThreadKey] = useState<string | null>( | ||
| 1160 | null, | ||
| 1161 | ); | ||
| 1155 | const [respondingRequestIds, setRespondingRequestIds] = useState<ApprovalRequestId[]>([]); | 1162 | const [respondingRequestIds, setRespondingRequestIds] = useState<ApprovalRequestId[]>([]); |
| 1156 | const [respondingUserInputRequestIds, setRespondingUserInputRequestIds] = useState< | 1163 | const [respondingUserInputRequestIds, setRespondingUserInputRequestIds] = useState< |
| 1157 | ApprovalRequestId[] | 1164 | ApprovalRequestId[] |
| @@ -1324,6 +1331,9 @@ export default function ChatView(props: ChatViewProps) { · 166 unmodified lines | |||
| 1324 | const planSidebarOpen = activeRightPanelKind === "plan"; | 1331 | const planSidebarOpen = activeRightPanelKind === "plan"; |
| 1325 | const previewPanelOpen = activeRightPanelKind === "preview" && isPreviewSupportedInRuntime(); | 1332 | const previewPanelOpen = activeRightPanelKind === "preview" && isPreviewSupportedInRuntime(); |
| 1326 | const rightPanelOpen = rightPanelState.isOpen; | 1333 | const rightPanelOpen = rightPanelState.isOpen; |
| 1334 | const canMaximizeRightPanel = rightPanelOpen && !shouldUsePlanSidebarSheet; | ||
| 1335 | const rightPanelMaximized = | ||
| 1336 | canMaximizeRightPanel && maximizedRightPanelThreadKey === routeThreadKey; | ||
| 1327 | const inlineRightPanelOwnsTitleBar = rightPanelOpen && !shouldUsePlanSidebarSheet; | 1337 | const inlineRightPanelOwnsTitleBar = rightPanelOpen && !shouldUsePlanSidebarSheet; |
| 1328 | 1338 | ||
| 1329 | useEffect(() => { | 1339 | useEffect(() => { |
| @@ -1358,11 +1368,58 @@ export default function ChatView(props: ChatViewProps) { · 28 unmodified lines | |||
| 1358 | const activeProject = useStore( | 1368 | const activeProject = useStore( |
| 1359 | useMemo(() => createProjectSelectorByRef(activeProjectRef), [activeProjectRef]), | 1369 | useMemo(() => createProjectSelectorByRef(activeProjectRef), [activeProjectRef]), |
| 1360 | ); | 1370 | ); |
| 1371 | const activeProjectKey = activeProject | ||
| 1372 | ? `${activeProject.environmentId}:${activeProject.cwd}` | ||
| 1373 | : null; | ||
| 1374 | const [pendingFileSurfaceIdsByProject, setPendingFileSurfaceIdsByProject] = useState< | ||
| 1375 | ReadonlyMap<string, ReadonlySet<string>> | ||
| 1376 | >(() => new Map()); | ||
| 1377 | const pendingFileSurfaceIds = activeProjectKey | ||
| 1378 | ? (pendingFileSurfaceIdsByProject.get(activeProjectKey) ?? EMPTY_PENDING_FILE_SURFACE_IDS) | ||
| 1379 | : EMPTY_PENDING_FILE_SURFACE_IDS; | ||
| 1380 | const handleFilePendingChange = useCallback( | ||
| 1381 | (relativePath: string, pending: boolean) => { | ||
| 1382 | if (!activeProjectKey) return; | ||
| 1383 | setPendingFileSurfaceIdsByProject((currentByProject) => { | ||
| 1384 | const current = currentByProject.get(activeProjectKey) ?? EMPTY_PENDING_FILE_SURFACE_IDS; | ||
| 1385 | const surfaceId = `file:${relativePath}`; | ||
| 1386 | if (current.has(surfaceId) === pending) return currentByProject; | ||
| 1387 | |||
| 1388 | const next = new Set(current); | ||
| 1389 | if (pending) { | ||
| 1390 | next.add(surfaceId); | ||
| 1391 | } else { | ||
| 1392 | next.delete(surfaceId); | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | const nextByProject = new Map(currentByProject); | ||
| 1396 | if (next.size === 0) { | ||
| 1397 | nextByProject.delete(activeProjectKey); | ||
| 1398 | } else { | ||
| 1399 | nextByProject.set(activeProjectKey, next); | ||
| 1400 | } | ||
| 1401 | return nextByProject; | ||
| 1402 | }); | ||
| 1403 | }, | ||
| 1404 | [activeProjectKey], | ||
| 1405 | ); | ||
| 1406 | const activeEnvironmentBootstrapComplete = useStore((state) => | ||
| 1407 | activeThread | ||
| 1408 | ? selectEnvironmentState(state, activeThread.environmentId).bootstrapComplete | ||
| 1409 | : false, | ||
| 1410 | ); | ||
| 1361 | const configuredPreviewUrls = useMemo( | 1411 | const configuredPreviewUrls = useMemo( |
| 1362 | () => getConfiguredPreviewUrls(activeProject?.scripts), | 1412 | () => getConfiguredPreviewUrls(activeProject?.scripts), |
| 1363 | [activeProject?.scripts], | 1413 | [activeProject?.scripts], |
| 1364 | ); | 1414 | ); |
| 1365 | 1415 | ||
| 1416 | useEffect(() => { | ||
| 1417 | if (!activeThreadRef || !activeEnvironmentBootstrapComplete) return; | ||
| 1418 | useRightPanelStore | ||
| 1419 | .getState() | ||
| 1420 | .reconcileFileSurfaces(activeThreadRef, activeProject !== undefined); | ||
| 1421 | }, [activeEnvironmentBootstrapComplete, activeProject, activeThreadRef]); | ||
| 1422 | |||
| 1366 | useEffect(() => { | 1423 | useEffect(() => { |
| 1367 | if (routeKind !== "server") { | 1424 | if (routeKind !== "server") { |
| 1368 | return; | 1425 | return; |
| @@ -2209,6 +2266,8 @@ export default function ChatView(props: ChatViewProps) { · 840 unmodified lines | |||
| 2209 | }), | 2266 | }), |
| 2210 | [terminalUiState.terminalOpen], | 2267 | [terminalUiState.terminalOpen], |
| 2211 | ); | 2268 | ); |
| 2269 | const terminalToggleShortcutLabel = shortcutLabelForCommand(keybindings, "terminal.toggle"); | ||
| 2270 | const rightPanelToggleShortcutLabel = shortcutLabelForCommand(keybindings, "rightPanel.toggle"); | ||
| 2212 | const splitTerminalShortcutLabel = useMemo( | 2271 | const splitTerminalShortcutLabel = useMemo( |
| 2213 | () => shortcutLabelForCommand(keybindings, "terminal.split", terminalShortcutLabelOptions), | 2272 | () => shortcutLabelForCommand(keybindings, "terminal.split", terminalShortcutLabelOptions), |
| 2214 | [keybindings, terminalShortcutLabelOptions], | 2273 | [keybindings, terminalShortcutLabelOptions], |
| @@ -2257,6 +2316,14 @@ export default function ChatView(props: ChatViewProps) { · 42 unmodified lines | |||
| 2257 | onDiffPanelOpen, | 2316 | onDiffPanelOpen, |
| 2258 | threadId, | 2317 | threadId, |
| 2259 | ]); | 2318 | ]); |
| 2319 | const addFilesSurface = () => { | ||
| 2320 | if (!activeThreadRef || !activeProject) return; | ||
| 2321 | useRightPanelStore.getState().open(activeThreadRef, "files"); | ||
| 2322 | }; | ||
| 2323 | const openFileSurface = (relativePath: string) => { | ||
| 2324 | if (!activeThreadRef || !activeProject) return; | ||
| 2325 | useRightPanelStore.getState().openFile(activeThreadRef, relativePath); | ||
| 2326 | }; | ||
| 2260 | // Right-panel arbitration: | 2327 | // Right-panel arbitration: |
| 2261 | // - The diff panel's openness is mirrored by the `?diff=1` URL search | 2328 | // - The diff panel's openness is mirrored by the `?diff=1` URL search |
| 2262 | // param so it deep-links cleanly. The store still records preview/plan | 2329 | // param so it deep-links cleanly. The store still records preview/plan |
| @@ -2979,12 +3046,14 @@ export default function ChatView(props: ChatViewProps) { · 716 unmodified lines | |||
| 2979 | }, [activePlan?.turnId, activeThreadRef, planSidebarOpen, sidebarProposedPlan?.turnId]); | 3046 | }, [activePlan?.turnId, activeThreadRef, planSidebarOpen, sidebarProposedPlan?.turnId]); |
| 2980 | const closePlanSidebar = useCallback(() => { | 3047 | const closePlanSidebar = useCallback(() => { |
| 2981 | if (!activeThreadRef) return; | 3048 | if (!activeThreadRef) return; |
| 3049 | setMaximizedRightPanelThreadKey(null); | ||
| 2982 | useRightPanelStore.getState().close(activeThreadRef); | 3050 | useRightPanelStore.getState().close(activeThreadRef); |
| 2983 | planSidebarDismissedForTurnRef.current = | 3051 | planSidebarDismissedForTurnRef.current = |
| 2984 | activePlan?.turnId ?? sidebarProposedPlan?.turnId ?? "__dismissed__"; | 3052 | activePlan?.turnId ?? sidebarProposedPlan?.turnId ?? "__dismissed__"; |
| 2985 | }, [activePlan?.turnId, activeThreadRef, sidebarProposedPlan?.turnId]); | 3053 | }, [activePlan?.turnId, activeThreadRef, sidebarProposedPlan?.turnId]); |
| 2986 | const closePreviewPanel = useCallback(() => { | 3054 | const closePreviewPanel = useCallback(() => { |
| 2987 | if (!activeThreadRef) return; | 3055 | if (!activeThreadRef) return; |
| 3056 | setMaximizedRightPanelThreadKey(null); | ||
| 2988 | useRightPanelStore.getState().close(activeThreadRef); | 3057 | useRightPanelStore.getState().close(activeThreadRef); |
| 2989 | }, [activeThreadRef]); | 3058 | }, [activeThreadRef]); |
| 2990 | const activateRightPanelSurface = useCallback( | 3059 | const activateRightPanelSurface = useCallback( |
| @@ -3018,8 +3087,17 @@ export default function ChatView(props: ChatViewProps) { · 27 unmodified lines | |||
| 3018 | ); | 3087 | ); |
| 3019 | const toggleRightPanel = useCallback(() => { | 3088 | const toggleRightPanel = useCallback(() => { |
| 3020 | if (!activeThreadRef) return; | 3089 | if (!activeThreadRef) return; |
| 3090 | if (rightPanelOpen) { | ||
| 3091 | setMaximizedRightPanelThreadKey(null); | ||
| 3092 | } | ||
| 3021 | useRightPanelStore.getState().toggleVisibility(activeThreadRef); | 3093 | useRightPanelStore.getState().toggleVisibility(activeThreadRef); |
| 3022 | }, [activeThreadRef]); | 3094 | }, [activeThreadRef, rightPanelOpen]); |
| 3095 | const toggleRightPanelMaximized = () => { | ||
| 3096 | if (!canMaximizeRightPanel) return; | ||
| 3097 | setMaximizedRightPanelThreadKey((threadKey) => | ||
| 3098 | threadKey === routeThreadKey ? null : routeThreadKey, | ||
| 3099 | ); | ||
| 3100 | }; | ||
| 3023 | const closeRightPanelSurface = useCallback( | 3101 | const closeRightPanelSurface = useCallback( |
| 3024 | (surface: RightPanelSurface) => { | 3102 | (surface: RightPanelSurface) => { |
| 3025 | if (!activeThreadRef) return; | 3103 | if (!activeThreadRef) return; |
| @@ -4481,23 +4559,43 @@ export default function ChatView(props: ChatViewProps) { · 1455 unmodified lines | |||
| 4481 | } | 4559 | } |
| 4482 | 4560 | ||
| 4483 | return ( | 4561 | return ( |
| 4484 | <div className="flex min-h-0 min-w-0 flex-1 overflow-hidden bg-background"> | 4562 | <div className="relative flex min-h-0 min-w-0 flex-1 overflow-hidden bg-background"> |
| 4485 | {isElectron && activeThreadRef ? ( | 4563 | {isElectron && activeThreadRef ? ( |
| 4486 | <PreviewAutomationOwner threadRef={activeThreadRef} visible={previewPanelOpen} /> | 4564 | <PreviewAutomationOwner threadRef={activeThreadRef} visible={previewPanelOpen} /> |
| 4487 | ) : null} | 4565 | ) : null} |
| 4488 | <div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden"> | 4566 | <PanelLayoutControls |
| 4567 | terminalAvailable={Boolean(activeProject)} | ||
| 4568 | terminalOpen={Boolean(terminalUiState.terminalOpen)} | ||
| 4569 | terminalShortcutLabel={terminalToggleShortcutLabel} | ||
| 4570 | rightPanelAvailable={Boolean(activeProject)} | ||
| 4571 | rightPanelOpen={rightPanelOpen} | ||
| 4572 | rightPanelShortcutLabel={rightPanelToggleShortcutLabel} | ||
| 4573 | rightPanelMaximized={rightPanelMaximized} | ||
| 4574 | canMaximizeRightPanel={canMaximizeRightPanel} | ||
| 4575 | onToggleTerminal={toggleTerminalVisibility} | ||
| 4576 | onToggleRightPanel={toggleRightPanel} | ||
| 4577 | onToggleRightPanelMaximized={toggleRightPanelMaximized} | ||
| 4578 | /> | ||
| 4579 | <div | ||
| 4580 | className={cn( | ||
| 4581 | "flex min-h-0 min-w-0 flex-col overflow-hidden", | ||
| 4582 | rightPanelMaximized ? "w-0 flex-none" : "flex-1", | ||
| 4583 | )} | ||
| 4584 | data-chat-column-maximized-away={rightPanelMaximized ? "true" : "false"} | ||
| 4585 | > | ||
| 4489 | {/* Top bar */} | 4586 | {/* Top bar */} |
| 4490 | <header | 4587 | <header |
| 4588 | data-chat-header | ||
| 4491 | className={cn( | 4589 | className={cn( |
| 4492 | "border-b border-border", | 4590 | "border-b border-border", |
| 4493 | isElectron | 4591 | isElectron |
| 4494 | ? cn( | 4592 | ? cn( |
| 4495 | "drag-region flex h-[52px] items-center px-3 sm:px-5 wco:h-[env(titlebar-area-height)]", | 4593 | "workspace-topbar drag-region px-3 sm:px-5", |
| 4496 | reserveTitleBarControlInset && | 4594 | reserveTitleBarControlInset && |
| 4497 | !inlineRightPanelOwnsTitleBar && | 4595 | !inlineRightPanelOwnsTitleBar && |
| 4498 | "wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]", | 4596 | "wco:pr-[var(--workspace-native-controls-inset)]", |
| 4499 | ) | 4597 | ) |
| 4500 | : "pb-2 pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] pt-2 sm:pb-3 sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)] sm:pt-3", | 4598 | : "workspace-topbar pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)]", |
| 4501 | )} | 4599 | )} |
| 4502 | > | 4600 | > |
| 4503 | <ChatHeader | 4601 | <ChatHeader |
| @@ -4513,17 +4611,12 @@ export default function ChatView(props: ChatViewProps) { · 9 unmodified lines | |||
| 4513 | } | 4611 | } |
| 4514 | keybindings={keybindings} | 4612 | keybindings={keybindings} |
| 4515 | availableEditors={availableEditors} | 4613 | availableEditors={availableEditors} |
| 4516 | terminalAvailable={Boolean(activeProject)} | ||
| 4517 | terminalOpen={Boolean(terminalUiState.terminalOpen)} | ||
| 4518 | rightPanelAvailable={Boolean(activeProject)} | ||
| 4519 | rightPanelOpen={rightPanelOpen} | ||
| 4520 | gitCwd={gitCwd} | 4614 | gitCwd={gitCwd} |
| 4521 | onRunProjectScript={runProjectScript} | 4615 | onRunProjectScript={runProjectScript} |
| 4522 | onAddProjectScript={saveProjectScript} | 4616 | onAddProjectScript={saveProjectScript} |
| 4523 | onUpdateProjectScript={updateProjectScript} | 4617 | onUpdateProjectScript={updateProjectScript} |
| 4524 | onDeleteProjectScript={deleteProjectScript} | 4618 | onDeleteProjectScript={deleteProjectScript} |
| 4525 | onToggleTerminal={toggleTerminalVisibility} | 4619 | rightPanelOpen={rightPanelOpen} |
| 4526 | onToggleRightPanel={toggleRightPanel} | ||
| 4527 | /> | 4620 | /> |
| 4528 | </header> | 4621 | </header> |
| 4529 | 4622 | ||
| @@ -4730,8 +4823,10 @@ export default function ChatView(props: ChatViewProps) { · 200 unmodified lines | |||
| 4730 | {!shouldUsePlanSidebarSheet && rightPanelOpen && activeThreadRef ? ( | 4823 | {!shouldUsePlanSidebarSheet && rightPanelOpen && activeThreadRef ? ( |
| 4731 | <RightPanelTabs | 4824 | <RightPanelTabs |
| 4732 | mode="inline" | 4825 | mode="inline" |
| 4826 | maximized={rightPanelMaximized} | ||
| 4733 | surfaces={rightPanelState.surfaces} | 4827 | surfaces={rightPanelState.surfaces} |
| 4734 | activeSurfaceId={activeRightPanelSurface?.id ?? null} | 4828 | activeSurfaceId={activeRightPanelSurface?.id ?? null} |
| 4829 | pendingSurfaceIds={pendingFileSurfaceIds} | ||
| 4735 | previewSessions={activePreviewState.sessions} | 4830 | previewSessions={activePreviewState.sessions} |
| 4736 | terminalLabelsById={activeTerminalLabelsById} | 4831 | terminalLabelsById={activeTerminalLabelsById} |
| 4737 | onActivate={activateRightPanelSurface} | 4832 | onActivate={activateRightPanelSurface} |
| @@ -4739,8 +4834,10 @@ export default function ChatView(props: ChatViewProps) { · 1 unmodified line | |||
| 4739 | onAddBrowser={createBrowserSurface} | 4834 | onAddBrowser={createBrowserSurface} |
| 4740 | onAddTerminal={addTerminalSurface} | 4835 | onAddTerminal={addTerminalSurface} |
| 4741 | onAddDiff={addDiffSurface} | 4836 | onAddDiff={addDiffSurface} |
| 4837 | onAddFiles={addFilesSurface} | ||
| 4742 | browserAvailable={isPreviewSupportedInRuntime()} | 4838 | browserAvailable={isPreviewSupportedInRuntime()} |
| 4743 | diffAvailable={isServerThread && isGitRepo} | 4839 | diffAvailable={isServerThread && isGitRepo} |
| 4840 | filesAvailable={Boolean(activeProject)} | ||
| 4744 | > | 4841 | > |
| 4745 | {activeRightPanelSurface?.kind === "preview" ? ( | 4842 | {activeRightPanelSurface?.kind === "preview" ? ( |
| 4746 | <Suspense fallback={null}> | 4843 | <Suspense fallback={null}> |
| @@ -4771,11 +4868,27 @@ export default function ChatView(props: ChatViewProps) { · 24 unmodified lines | |||
| 4771 | closeShortcutLabel={closeTerminalShortcutLabel ?? undefined} | 4868 | closeShortcutLabel={closeTerminalShortcutLabel ?? undefined} |
| 4772 | /> | 4869 | /> |
| 4773 | ) : activeRightPanelSurface?.kind === "diff" ? ( | 4870 | ) : activeRightPanelSurface?.kind === "diff" ? ( |
| 4774 | <DiffWorkerPoolProvider> | 4871 | <Suspense fallback={null}> |
| 4775 | <Suspense fallback={null}> | 4872 | <DiffPanel mode="embedded" /> |
| 4776 | <DiffPanel mode="embedded" /> | 4873 | </Suspense> |
| 4777 | </Suspense> | 4874 | ) : (activeRightPanelSurface?.kind === "files" || |
| 4778 | </DiffWorkerPoolProvider> | 4875 | activeRightPanelSurface?.kind === "file") && |
| 4876 | activeProject ? ( | ||
| 4877 | <Suspense fallback={null}> | ||
| 4878 | <FilePreviewPanel | ||
| 4879 | key={`${activeProject.environmentId}:${activeProject.cwd}`} | ||
| 4880 | environmentId={activeProject.environmentId} | ||
| 4881 | cwd={activeProject.cwd} | ||
| 4882 | projectName={activeProject.name} | ||
| 4883 | relativePath={ | ||
| 4884 | activeRightPanelSurface.kind === "file" | ||
| 4885 | ? activeRightPanelSurface.relativePath | ||
| 4886 | : null | ||
| 4887 | } | ||
| 4888 | onOpenFile={openFileSurface} | ||
| 4889 | onPendingChange={handleFilePendingChange} | ||
| 4890 | /> | ||
| 4891 | </Suspense> | ||
| 4779 | ) : null} | 4892 | ) : null} |
| 4780 | </RightPanelTabs> | 4893 | </RightPanelTabs> |
| 4781 | ) : null} | 4894 | ) : null} |
| @@ -4786,6 +4899,7 @@ export default function ChatView(props: ChatViewProps) { · 4 unmodified lines | |||
| 4786 | mode="sheet" | 4899 | mode="sheet" |
| 4787 | surfaces={rightPanelState.surfaces} | 4900 | surfaces={rightPanelState.surfaces} |
| 4788 | activeSurfaceId={activeRightPanelSurface?.id ?? null} | 4901 | activeSurfaceId={activeRightPanelSurface?.id ?? null} |
| 4902 | pendingSurfaceIds={pendingFileSurfaceIds} | ||
| 4789 | previewSessions={activePreviewState.sessions} | 4903 | previewSessions={activePreviewState.sessions} |
| 4790 | terminalLabelsById={activeTerminalLabelsById} | 4904 | terminalLabelsById={activeTerminalLabelsById} |
| 4791 | onActivate={activateRightPanelSurface} | 4905 | onActivate={activateRightPanelSurface} |
| @@ -4793,8 +4907,10 @@ export default function ChatView(props: ChatViewProps) { · 1 unmodified line | |||
| 4793 | onAddBrowser={createBrowserSurface} | 4907 | onAddBrowser={createBrowserSurface} |
| 4794 | onAddTerminal={addTerminalSurface} | 4908 | onAddTerminal={addTerminalSurface} |
| 4795 | onAddDiff={addDiffSurface} | 4909 | onAddDiff={addDiffSurface} |
| 4910 | onAddFiles={addFilesSurface} | ||
| 4796 | browserAvailable={isPreviewSupportedInRuntime()} | 4911 | browserAvailable={isPreviewSupportedInRuntime()} |
| 4797 | diffAvailable={isServerThread && isGitRepo} | 4912 | diffAvailable={isServerThread && isGitRepo} |
| 4913 | filesAvailable={Boolean(activeProject)} | ||
| 4798 | > | 4914 | > |
| 4799 | {activeRightPanelSurface?.kind === "preview" ? ( | 4915 | {activeRightPanelSurface?.kind === "preview" ? ( |
| 4800 | <Suspense fallback={null}> | 4916 | <Suspense fallback={null}> |
| @@ -4825,11 +4941,9 @@ export default function ChatView(props: ChatViewProps) { · 24 unmodified lines | |||
| 4825 | closeShortcutLabel={closeTerminalShortcutLabel ?? undefined} | 4941 | closeShortcutLabel={closeTerminalShortcutLabel ?? undefined} |
| 4826 | /> | 4942 | /> |
| 4827 | ) : activeRightPanelSurface?.kind === "diff" ? ( | 4943 | ) : activeRightPanelSurface?.kind === "diff" ? ( |
| 4828 | <DiffWorkerPoolProvider> | 4944 | <Suspense fallback={null}> |
| 4829 | <Suspense fallback={null}> | 4945 | <DiffPanel mode="embedded" /> |
| 4830 | <DiffPanel mode="embedded" /> | 4946 | </Suspense> |
| 4831 | </Suspense> | ||
| 4832 | </DiffWorkerPoolProvider> | ||
| 4833 | ) : activeRightPanelSurface?.kind === "plan" ? ( | 4947 | ) : activeRightPanelSurface?.kind === "plan" ? ( |
| 4834 | <PlanSidebar | 4948 | <PlanSidebar |
| 4835 | activePlan={activePlan} | 4949 | activePlan={activePlan} |
| @@ -4843,6 +4957,24 @@ export default function ChatView(props: ChatViewProps) { · 7 unmodified lines | |||
| 4843 | mode="embedded" | 4957 | mode="embedded" |
| 4844 | onClose={closePlanSidebar} | 4958 | onClose={closePlanSidebar} |
| 4845 | /> | 4959 | /> |
| 4960 | ) : (activeRightPanelSurface?.kind === "files" || | ||
| 4961 | activeRightPanelSurface?.kind === "file") && | ||
| 4962 | activeProject ? ( | ||
| 4963 | <Suspense fallback={null}> | ||
| 4964 | <FilePreviewPanel | ||
| 4965 | key={`${activeProject.environmentId}:${activeProject.cwd}`} | ||
| 4966 | environmentId={activeProject.environmentId} | ||
| 4967 | cwd={activeProject.cwd} | ||
| 4968 | projectName={activeProject.name} | ||
| 4969 | relativePath={ | ||
| 4970 | activeRightPanelSurface.kind === "file" | ||
| 4971 | ? activeRightPanelSurface.relativePath | ||
| 4972 | : null | ||
| 4973 | } | ||
| 4974 | onOpenFile={openFileSurface} | ||
| 4975 | onPendingChange={handleFilePendingChange} | ||
| 4976 | /> | ||
| 4977 | </Suspense> | ||
| 4846 | ) : null} | 4978 | ) : null} |
| 4847 | </RightPanelTabs> | 4979 | </RightPanelTabs> |
| 4848 | </RightPanelSheet> | 4980 | </RightPanelSheet> |
| @@ -4854,3 +4986,11 @@ export default function ChatView(props: ChatViewProps) { · 5 unmodified lines | |||
| 4854 | </div> | 4986 | </div> |
| 4855 | ); | 4987 | ); |
| 4856 | } | 4988 | } |
| 4989 | |||
| 4990 | export default function ChatView(props: ChatViewProps) { | ||
| 4991 | return ( | ||
| 4992 | <DiffWorkerPoolProvider> | ||
| 4993 | <ChatViewContent {...props} /> | ||
| 4994 | </DiffWorkerPoolProvider> | ||
| 4995 | ); | ||
| 4996 | } | ||
| @@ -64,7 +64,7 @@ import { · 63 unmodified lines | |||
| 64 | type TerminalContextDraft, | 64 | type TerminalContextDraft, |
| 65 | } from "~/lib/terminalContext"; | 65 | } from "~/lib/terminalContext"; |
| 66 | import { cn } from "~/lib/utils"; | 66 | import { cn } from "~/lib/utils"; |
| 67 | import { basenameOfPath } from "~/vscode-icons"; | 67 | import { basenameOfPath } from "~/pierre-icons"; |
| 68 | import { | 68 | import { |
| 69 | COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, | 69 | COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, |
| 70 | COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, | 70 | COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, |
| @@ -47,6 +47,7 @@ export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { · 46 unmodified lines | |||
| 47 | highlighterOptions={{ | 47 | highlighterOptions={{ |
| 48 | theme: diffThemeName, | 48 | theme: diffThemeName, |
| 49 | tokenizeMaxLineLength: 1_000, | 49 | tokenizeMaxLineLength: 1_000, |
| 50 | useTokenTransformer: true, | ||
| 50 | }} | 51 | }} |
| 51 | > | 52 | > |
| 52 | <DiffWorkerThemeSync themeName={diffThemeName} /> | 53 | <DiffWorkerThemeSync themeName={diffThemeName} /> |
| @@ -10,13 +10,11 @@ export function NoActiveThreadState() { · 9 unmodified lines | |||
| 10 | <header | 10 | <header |
| 11 | className={cn( | 11 | className={cn( |
| 12 | "border-b border-border px-3 sm:px-5", | 12 | "border-b border-border px-3 sm:px-5", |
| 13 | isElectron | 13 | isElectron ? "workspace-topbar drag-region" : "workspace-topbar", |
| 14 | ? "drag-region flex h-[52px] items-center wco:h-[env(titlebar-area-height)]" | ||
| 15 | : "py-2 sm:py-3", | ||
| 16 | )} | 14 | )} |
| 17 | > | 15 | > |
| 18 | {isElectron ? ( | 16 | {isElectron ? ( |
| 19 | <span className="text-xs text-muted-foreground/50 wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]"> | 17 | <span className="text-xs text-muted-foreground/50 wco:pr-[var(--workspace-native-controls-inset)]"> |
| 20 | No active thread | 18 | No active thread |
| 21 | </span> | 19 | </span> |
| 22 | ) : ( | 20 | ) : ( |
| @@ -1,21 +1,26 @@ | |||
| 1 | import type { PreviewSessionSnapshot } from "@t3tools/contracts"; | 1 | import type { PreviewSessionSnapshot } from "@t3tools/contracts"; |
| 2 | import { getTerminalLabel } from "@t3tools/shared/terminalLabels"; | 2 | import { getTerminalLabel } from "@t3tools/shared/terminalLabels"; |
| 3 | import { ClipboardList, FileDiff, Globe2, Plus, TerminalSquare, X } from "lucide-react"; | 3 | import { ClipboardList, FileDiff, Files, Globe2, Plus, TerminalSquare, X } from "lucide-react"; |
| 4 | import { type ReactNode, useState } from "react"; | 4 | import { type ReactNode, useEffect, useRef, useState } from "react"; |
| 5 | 5 | ||
| 6 | import { isElectron } from "~/env"; | 6 | import { isElectron } from "~/env"; |
| 7 | import type { RightPanelSurface } from "~/rightPanelStore"; | 7 | import type { RightPanelSurface } from "~/rightPanelStore"; |
| 8 | import { cn } from "~/lib/utils"; | 8 | import { cn } from "~/lib/utils"; |
| 9 | import { Menu, MenuItem, MenuPopup, MenuTrigger } from "~/components/ui/menu"; | ||
| 10 | import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip"; | 9 | import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip"; |
| 10 | import { Menu, MenuItem, MenuPopup, MenuTrigger } from "~/components/ui/menu"; | ||
| 11 | import { ScrollArea } from "~/components/ui/scroll-area"; | ||
| 11 | import { faviconUrlForOrigin } from "~/lib/favicon"; | 12 | import { faviconUrlForOrigin } from "~/lib/favicon"; |
| 13 | import { useTheme } from "~/hooks/useTheme"; | ||
| 12 | 14 | ||
| 13 | import { PreviewPanelShell, type PreviewPanelMode } from "./preview/PreviewPanelShell"; | 15 | import { PreviewPanelShell, type PreviewPanelMode } from "./preview/PreviewPanelShell"; |
| 16 | import { PierreEntryIcon } from "./chat/PierreEntryIcon"; | ||
| 14 | 17 | ||
| 15 | interface RightPanelTabsProps { | 18 | interface RightPanelTabsProps { |
| 16 | mode: PreviewPanelMode; | 19 | mode: PreviewPanelMode; |
| 20 | maximized?: boolean; | ||
| 17 | surfaces: readonly RightPanelSurface[]; | 21 | surfaces: readonly RightPanelSurface[]; |
| 18 | activeSurfaceId: string | null; | 22 | activeSurfaceId: string | null; |
| 23 | pendingSurfaceIds: ReadonlySet<string>; | ||
| 19 | previewSessions: Readonly<Record<string, PreviewSessionSnapshot>>; | 24 | previewSessions: Readonly<Record<string, PreviewSessionSnapshot>>; |
| 20 | terminalLabelsById: ReadonlyMap<string, string>; | 25 | terminalLabelsById: ReadonlyMap<string, string>; |
| 21 | onActivate: (surface: RightPanelSurface) => void; | 26 | onActivate: (surface: RightPanelSurface) => void; |
| @@ -23,8 +28,10 @@ interface RightPanelTabsProps { · 1 unmodified line | |||
| 23 | onAddBrowser: () => void; | 28 | onAddBrowser: () => void; |
| 24 | onAddTerminal: () => void; | 29 | onAddTerminal: () => void; |
| 25 | onAddDiff: () => void; | 30 | onAddDiff: () => void; |
| 31 | onAddFiles: () => void; | ||
| 26 | browserAvailable: boolean; | 32 | browserAvailable: boolean; |
| 27 | diffAvailable: boolean; | 33 | diffAvailable: boolean; |
| 34 | filesAvailable: boolean; | ||
| 28 | children: ReactNode; | 35 | children: ReactNode; |
| 29 | } | 36 | } |
| 30 | 37 | ||
| @@ -32,8 +39,10 @@ function RightPanelEmptyState(props: { · 1 unmodified line | |||
| 32 | onAddBrowser: () => void; | 39 | onAddBrowser: () => void; |
| 33 | onAddTerminal: () => void; | 40 | onAddTerminal: () => void; |
| 34 | onAddDiff: () => void; | 41 | onAddDiff: () => void; |
| 42 | onAddFiles: () => void; | ||
| 35 | browserAvailable: boolean; | 43 | browserAvailable: boolean; |
| 36 | diffAvailable: boolean; | 44 | diffAvailable: boolean; |
| 45 | filesAvailable: boolean; | ||
| 37 | }) { | 46 | }) { |
| 38 | const actions = [ | 47 | const actions = [ |
| 39 | { | 48 | { |
| @@ -50,6 +59,13 @@ function RightPanelEmptyState(props: { · 10 unmodified lines | |||
| 50 | available: true, | 59 | available: true, |
| 51 | onClick: props.onAddTerminal, | 60 | onClick: props.onAddTerminal, |
| 52 | }, | 61 | }, |
| 62 | { | ||
| 63 | label: "Files", | ||
| 64 | description: "Browse and read workspace files.", | ||
| 65 | icon: Files, | ||
| 66 | available: props.filesAvailable, | ||
| 67 | onClick: props.onAddFiles, | ||
| 68 | }, | ||
| 53 | { | 69 | { |
| 54 | label: "Diff", | 70 | label: "Diff", |
| 55 | description: "Review changes in this thread.", | 71 | description: "Review changes in this thread.", |
| @@ -68,7 +84,7 @@ function RightPanelEmptyState(props: { · 12 unmodified lines | |||
| 68 | Choose what to show in the right panel. | 84 | Choose what to show in the right panel. |
| 69 | </p> | 85 | </p> |
| 70 | </div> | 86 | </div> |
| 71 | <div className="grid gap-2 sm:grid-cols-3"> | 87 | <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-4"> |
| 72 | {actions.map((action) => { | 88 | {actions.map((action) => { |
| 73 | const Icon = action.icon; | 89 | const Icon = action.icon; |
| 74 | return ( | 90 | return ( |
| @@ -101,6 +117,10 @@ function surfaceTitle( · 26 unmodified lines | |||
| 101 | switch (surface.kind) { | 117 | switch (surface.kind) { |
| 102 | case "diff": | 118 | case "diff": |
| 103 | return "Diff"; | 119 | return "Diff"; |
| 120 | case "files": | ||
| 121 | return "Files"; | ||
| 122 | case "file": | ||
| 123 | return surface.relativePath.slice(surface.relativePath.lastIndexOf("/") + 1); | ||
| 104 | case "terminal": | 124 | case "terminal": |
| 105 | return ( | 125 | return ( |
| 106 | terminalLabelsById.get(surface.activeTerminalId) ?? | 126 | terminalLabelsById.get(surface.activeTerminalId) ?? |
| @@ -140,9 +160,11 @@ function PreviewFavicon({ url }: { url: string | null }) { · 33 unmodified lines | |||
| 140 | function SurfaceIcon({ | 160 | function SurfaceIcon({ |
| 141 | surface, | 161 | surface, |
| 142 | sessions, | 162 | sessions, |
| 163 | theme, | ||
| 143 | }: { | 164 | }: { |
| 144 | surface: RightPanelSurface; | 165 | surface: RightPanelSurface; |
| 145 | sessions: Readonly<Record<string, PreviewSessionSnapshot>>; | 166 | sessions: Readonly<Record<string, PreviewSessionSnapshot>>; |
| 167 | theme: "light" | "dark"; | ||
| 146 | }) { | 168 | }) { |
| 147 | switch (surface.kind) { | 169 | switch (surface.kind) { |
| 148 | case "preview": { | 170 | case "preview": { |
| @@ -152,6 +174,17 @@ function SurfaceIcon({ · 3 unmodified lines | |||
| 152 | } | 174 | } |
| 153 | case "diff": | 175 | case "diff": |
| 154 | return <FileDiff className="size-3.5 shrink-0" />; | 176 | return <FileDiff className="size-3.5 shrink-0" />; |
| 177 | case "files": | ||
| 178 | return <Files className="size-3.5 shrink-0" />; | ||
| 179 | case "file": | ||
| 180 | return ( | ||
| 181 | <PierreEntryIcon | ||
| 182 | pathValue={surface.relativePath} | ||
| 183 | kind="file" | ||
| 184 | theme={theme} | ||
| 185 | className="size-3.5" | ||
| 186 | /> | ||
| 187 | ); | ||
| 155 | case "terminal": | 188 | case "terminal": |
| 156 | return <TerminalSquare className="size-3.5 shrink-0" />; | 189 | return <TerminalSquare className="size-3.5 shrink-0" />; |
| 157 | case "plan": | 190 | case "plan": |
| @@ -161,80 +194,124 @@ function SurfaceIcon({ · 3 unmodified lines | |||
| 161 | 194 | ||
| 162 | export function RightPanelTabs(props: RightPanelTabsProps) { | 195 | export function RightPanelTabs(props: RightPanelTabsProps) { |
| 163 | const ownsDesktopTitleBar = isElectron && props.mode === "inline"; | 196 | const ownsDesktopTitleBar = isElectron && props.mode === "inline"; |
| 197 | const { resolvedTheme } = useTheme(); | ||
| 198 | const tabListRef = useRef<HTMLDivElement>(null); | ||
| 199 | |||
| 200 | useEffect(() => { | ||
| 201 | const activeTab = tabListRef.current?.querySelector<HTMLElement>("[data-active-tab='true']"); | ||
| 202 | activeTab?.scrollIntoView({ block: "nearest", inline: "nearest" }); | ||
| 203 | }, [props.activeSurfaceId]); | ||
| 164 | 204 | ||
| 165 | return ( | 205 | return ( |
| 166 | <PreviewPanelShell mode={props.mode}> | 206 | <PreviewPanelShell |
| 207 | mode={props.mode} | ||
| 208 | {...(props.maximized !== undefined ? { maximized: props.maximized } : {})} | ||
| 209 | > | ||
| 167 | <div | 210 | <div |
| 168 | className={cn( | 211 | className={cn( |
| 169 | "flex shrink-0 items-center px-2", | 212 | "px-2 pr-28", |
| 170 | ownsDesktopTitleBar | 213 | props.mode === "inline" ? "workspace-topbar" : "flex h-10 shrink-0 items-center", |
| 171 | ? "drag-region h-[52px] wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]" | 214 | ownsDesktopTitleBar && |
| 172 | : "h-10", | 215 | "drag-region wco:pr-[calc(var(--workspace-native-controls-inset)+6rem)]", |
| 173 | )} | 216 | )} |
| 217 | data-right-panel-tabbar | ||
| 174 | > | 218 | > |
| 175 | <div className="flex min-w-0 flex-1 items-center gap-1 overflow-x-auto"> | 219 | <ScrollArea |
| 176 | {props.surfaces.map((surface) => { | 220 | ref={tabListRef} |
| 177 | const active = surface.id === props.activeSurfaceId; | 221 | hideScrollbars |
| 178 | const title = surfaceTitle(surface, props.previewSessions, props.terminalLabelsById); | 222 | scrollFade |
| 179 | return ( | 223 | className="min-w-0 flex-1 rounded-none" |
| 180 | <div | 224 | data-right-panel-tab-list |
| 181 | key={surface.id} | 225 | > |
| 182 | className={cn( | 226 | <div className="flex h-full w-max min-w-full items-center gap-1"> |
| 183 | "group flex h-7 min-w-0 max-w-52 items-center gap-1.5 rounded-md px-2 text-sm", | 227 | {props.surfaces.map((surface) => { |
| 184 | active | 228 | const active = surface.id === props.activeSurfaceId; |
| 185 | ? "bg-accent text-foreground" | 229 | const pending = props.pendingSurfaceIds.has(surface.id); |
| 186 | : "text-muted-foreground hover:bg-accent/60 hover:text-foreground", | 230 | const title = surfaceTitle(surface, props.previewSessions, props.terminalLabelsById); |
| 187 | )} | 231 | return ( |
| 188 | > | 232 | <div |
| 189 | <Tooltip> | 233 | key={surface.id} |
| 190 | <TooltipTrigger | 234 | data-active-tab={active} |
| 191 | render={ | 235 | className={cn( |
| 192 | <button | 236 | "group flex h-7 min-w-25 max-w-44 shrink-0 items-center gap-1.5 rounded-md px-2 text-sm", |
| 193 | type="button" | 237 | active |
| 194 | className="flex min-w-0 flex-1 items-center gap-1.5" | 238 | ? "bg-accent text-foreground" |
| 195 | onClick={() => props.onActivate(surface)} | 239 | : "text-muted-foreground hover:bg-accent/60 hover:text-foreground", |
| 196 | > | 240 | )} |
| 197 | <SurfaceIcon surface={surface} sessions={props.previewSessions} /> | ||
| 198 | <span className="truncate">{title}</span> | ||
| 199 | </button> | ||
| 200 | } | ||
| 201 | /> | ||
| 202 | <TooltipPopup>{title}</TooltipPopup> | ||
| 203 | </Tooltip> | ||
| 204 | <button | ||
| 205 | type="button" | ||
| 206 | className="rounded p-0.5 opacity-0 hover:bg-muted group-hover:opacity-100 focus:opacity-100" | ||
| 207 | aria-label={`Close ${title}`} | ||
| 208 | onClick={() => props.onCloseSurface(surface)} | ||
| 209 | > | 241 | > |
| 210 | <X className="size-3" /> | 242 | <Tooltip> |
| 211 | </button> | 243 | <TooltipTrigger |
| 212 | </div> | 244 | render={ |
| 213 | ); | 245 | <button |
| 214 | })} | 246 | type="button" |
| 215 | </div> | 247 | className="flex min-w-0 flex-1 items-center gap-1.5" |
| 216 | <Menu> | 248 | onClick={() => props.onActivate(surface)} |
| 217 | <MenuTrigger | 249 | > |
| 218 | className="relative ml-1 inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground" | 250 | <SurfaceIcon |
| 219 | aria-label="Add panel surface" | 251 | surface={surface} |
| 220 | > | 252 | sessions={props.previewSessions} |
| 221 | <Plus className="size-4" /> | 253 | theme={resolvedTheme} |
| 222 | </MenuTrigger> | 254 | /> |
| 223 | <MenuPopup align="start" side="bottom" sideOffset={6} className="min-w-44"> | 255 | <span className="truncate">{title}</span> |
| 224 | <MenuItem onClick={props.onAddBrowser} disabled={!props.browserAvailable}> | 256 | </button> |
| 225 | <Globe2 /> | 257 | } |
| 226 | Browser | 258 | /> |
| 227 | </MenuItem> | 259 | <TooltipPopup>{title}</TooltipPopup> |
| 228 | <MenuItem onClick={props.onAddTerminal}> | 260 | </Tooltip> |
| 229 | <TerminalSquare /> | 261 | <button |
| 230 | Terminal | 262 | type="button" |
| 231 | </MenuItem> | 263 | className={cn( |
| 232 | <MenuItem onClick={props.onAddDiff} disabled={!props.diffAvailable}> | 264 | "relative flex size-4 shrink-0 items-center justify-center rounded hover:bg-muted focus:opacity-100", |
| 233 | <FileDiff /> | 265 | pending ? "opacity-100" : "opacity-0 group-hover:opacity-100", |
| 234 | Diff | 266 | )} |
| 235 | </MenuItem> | 267 | aria-label={`Close ${title}`} |
| 236 | </MenuPopup> | 268 | onClick={() => props.onCloseSurface(surface)} |
| 237 | </Menu> | 269 | > |
| 270 | {pending ? ( | ||
| 271 | <> | ||
| 272 | <span | ||
| 273 | className="size-2 rounded-full bg-current group-hover:hidden" | ||
| 274 | aria-hidden | ||
| 275 | /> | ||
| 276 | <X className="hidden size-3 group-hover:block" /> | ||
| 277 | </> | ||
| 278 | ) : ( | ||
| 279 | <X className="size-3" /> | ||
| 280 | )} | ||
| 281 | </button> | ||
| 282 | </div> | ||
| 283 | ); | ||
| 284 | })} | ||
| 285 | {props.surfaces.length > 0 ? ( | ||
| 286 | <Menu> | ||
| 287 | <MenuTrigger | ||
| 288 | className="relative inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground" | ||
| 289 | aria-label="Add panel surface" | ||
| 290 | > | ||
| 291 | <Plus className="size-4" /> | ||
| 292 | </MenuTrigger> | ||
| 293 | <MenuPopup align="start" side="bottom" sideOffset={6} className="min-w-44"> | ||
| 294 | <MenuItem onClick={props.onAddBrowser} disabled={!props.browserAvailable}> | ||
| 295 | <Globe2 /> | ||
| 296 | Browser | ||
| 297 | </MenuItem> | ||
| 298 | <MenuItem onClick={props.onAddTerminal}> | ||
| 299 | <TerminalSquare /> | ||
| 300 | Terminal | ||
| 301 | </MenuItem> | ||
| 302 | <MenuItem onClick={props.onAddFiles} disabled={!props.filesAvailable}> | ||
| 303 | <Files /> | ||
| 304 | Files | ||
| 305 | </MenuItem> | ||
| 306 | <MenuItem onClick={props.onAddDiff} disabled={!props.diffAvailable}> | ||
| 307 | <FileDiff /> | ||
| 308 | Diff | ||
| 309 | </MenuItem> | ||
| 310 | </MenuPopup> | ||
| 311 | </Menu> | ||
| 312 | ) : null} | ||
| 313 | </div> | ||
| 314 | </ScrollArea> | ||
| 238 | </div> | 315 | </div> |
| 239 | <div className="flex min-h-0 flex-1 flex-col"> | 316 | <div className="flex min-h-0 flex-1 flex-col"> |
| 240 | {props.activeSurfaceId === null ? ( | 317 | {props.activeSurfaceId === null ? ( |
| @@ -242,8 +319,10 @@ export function RightPanelTabs(props: RightPanelTabsProps) { · 1 unmodified line | |||
| 242 | onAddBrowser={props.onAddBrowser} | 319 | onAddBrowser={props.onAddBrowser} |
| 243 | onAddTerminal={props.onAddTerminal} | 320 | onAddTerminal={props.onAddTerminal} |
| 244 | onAddDiff={props.onAddDiff} | 321 | onAddDiff={props.onAddDiff} |
| 322 | onAddFiles={props.onAddFiles} | ||
| 245 | browserAvailable={props.browserAvailable} | 323 | browserAvailable={props.browserAvailable} |
| 246 | diffAvailable={props.diffAvailable} | 324 | diffAvailable={props.diffAvailable} |
| 325 | filesAvailable={props.filesAvailable} | ||
| 247 | /> | 326 | /> |
| 248 | ) : ( | 327 | ) : ( |
| 249 | props.children | 328 | props.children |
| @@ -9,7 +9,7 @@ import { · 8 unmodified lines | |||
| 9 | import { ChevronRightIcon, FolderIcon, FolderClosedIcon } from "lucide-react"; | 9 | import { ChevronRightIcon, FolderIcon, FolderClosedIcon } from "lucide-react"; |
| 10 | import { cn } from "~/lib/utils"; | 10 | import { cn } from "~/lib/utils"; |
| 11 | import { DiffStatLabel, hasNonZeroStat } from "./DiffStatLabel"; | 11 | import { DiffStatLabel, hasNonZeroStat } from "./DiffStatLabel"; |
| 12 | import { VscodeEntryIcon } from "./VscodeEntryIcon"; | 12 | import { PierreEntryIcon } from "./PierreEntryIcon"; |
| 13 | import { Button } from "../ui/button"; | 13 | import { Button } from "../ui/button"; |
| 14 | 14 | ||
| 15 | const EMPTY_DIRECTORY_OVERRIDES: Record<string, boolean> = {}; | 15 | const EMPTY_DIRECTORY_OVERRIDES: Record<string, boolean> = {}; |
| @@ -177,7 +177,7 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: { · 161 unmodified lines | |||
| 177 | {hasDirectoryNodes || depth > 0 ? ( | 177 | {hasDirectoryNodes || depth > 0 ? ( |
| 178 | <span aria-hidden="true" className="size-3.5 shrink-0" /> | 178 | <span aria-hidden="true" className="size-3.5 shrink-0" /> |
| 179 | ) : null} | 179 | ) : null} |
| 180 | <VscodeEntryIcon | 180 | <PierreEntryIcon |
| 181 | pathValue={node.path} | 181 | pathValue={node.path} |
| 182 | kind="file" | 182 | kind="file" |
| 183 | theme={resolvedTheme} | 183 | theme={resolvedTheme} |
| @@ -79,7 +79,7 @@ import { · 78 unmodified lines | |||
| 79 | } from "./composerProviderState"; | 79 | } from "./composerProviderState"; |
| 80 | import { ContextWindowMeter } from "./ContextWindowMeter"; | 80 | import { ContextWindowMeter } from "./ContextWindowMeter"; |
| 81 | import { buildExpandedImagePreview, type ExpandedImagePreview } from "./ExpandedImagePreview"; | 81 | import { buildExpandedImagePreview, type ExpandedImagePreview } from "./ExpandedImagePreview"; |
| 82 | import { basenameOfPath } from "../../vscode-icons"; | 82 | import { basenameOfPath } from "../../pierre-icons"; |
| 83 | import { cn, randomUUID } from "~/lib/utils"; | 83 | import { cn, randomUUID } from "~/lib/utils"; |
| 84 | import { Separator } from "../ui/separator"; | 84 | import { Separator } from "../ui/separator"; |
| 85 | import { Button } from "../ui/button"; | 85 | import { Button } from "../ui/button"; |
| @@ -9,14 +9,12 @@ import { scopeThreadRef } from "@t3tools/client-runtime"; · 8 unmodified lines | |||
| 9 | import { memo } from "react"; | 9 | import { memo } from "react"; |
| 10 | import GitActionsControl from "../GitActionsControl"; | 10 | import GitActionsControl from "../GitActionsControl"; |
| 11 | import { type DraftId } from "~/composerDraftStore"; | 11 | import { type DraftId } from "~/composerDraftStore"; |
| 12 | import { PanelBottomIcon, PanelRightIcon } from "lucide-react"; | ||
| 13 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; | 12 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 14 | import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl"; | 13 | import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl"; |
| 15 | import { Toggle } from "../ui/toggle"; | ||
| 16 | import { SidebarTrigger } from "../ui/sidebar"; | 14 | import { SidebarTrigger } from "../ui/sidebar"; |
| 17 | import { OpenInPicker } from "./OpenInPicker"; | 15 | import { OpenInPicker } from "./OpenInPicker"; |
| 18 | import { usePrimaryEnvironmentId } from "../../environments/primary"; | 16 | import { usePrimaryEnvironmentId } from "../../environments/primary/context"; |
| 19 | import { shortcutLabelForCommand } from "../../keybindings"; | 17 | import { cn } from "~/lib/utils"; |
| 20 | 18 | ||
| 21 | interface ChatHeaderProps { | 19 | interface ChatHeaderProps { |
| 22 | activeThreadEnvironmentId: EnvironmentId; | 20 | activeThreadEnvironmentId: EnvironmentId; |
| @@ -29,17 +27,12 @@ interface ChatHeaderProps { · 6 unmodified lines | |||
| 29 | preferredScriptId: string | null; | 27 | preferredScriptId: string | null; |
| 30 | keybindings: ResolvedKeybindingsConfig; | 28 | keybindings: ResolvedKeybindingsConfig; |
| 31 | availableEditors: ReadonlyArray<EditorId>; | 29 | availableEditors: ReadonlyArray<EditorId>; |
| 32 | terminalAvailable: boolean; | ||
| 33 | terminalOpen: boolean; | ||
| 34 | rightPanelAvailable: boolean; | ||
| 35 | rightPanelOpen: boolean; | ||
| 36 | gitCwd: string | null; | 30 | gitCwd: string | null; |
| 37 | onRunProjectScript: (script: ProjectScript) => void; | 31 | onRunProjectScript: (script: ProjectScript) => void; |
| 38 | onAddProjectScript: (input: NewProjectScriptInput) => Promise<void>; | 32 | onAddProjectScript: (input: NewProjectScriptInput) => Promise<void>; |
| 39 | onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise<void>; | 33 | onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise<void>; |
| 40 | onDeleteProjectScript: (scriptId: string) => Promise<void>; | 34 | onDeleteProjectScript: (scriptId: string) => Promise<void>; |
| 41 | onToggleTerminal: () => void; | 35 | rightPanelOpen: boolean; |
| 42 | onToggleRightPanel: () => void; | ||
| 43 | } | 36 | } |
| 44 | 37 | ||
| 45 | export function shouldShowOpenInPicker(input: { | 38 | export function shouldShowOpenInPicker(input: { |
| @@ -65,17 +58,12 @@ export const ChatHeader = memo(function ChatHeader({ · 19 unmodified lines | |||
| 65 | preferredScriptId, | 58 | preferredScriptId, |
| 66 | keybindings, | 59 | keybindings, |
| 67 | availableEditors, | 60 | availableEditors, |
| 68 | terminalAvailable, | ||
| 69 | terminalOpen, | ||
| 70 | rightPanelAvailable, | ||
| 71 | rightPanelOpen, | ||
| 72 | gitCwd, | 61 | gitCwd, |
| 73 | onRunProjectScript, | 62 | onRunProjectScript, |
| 74 | onAddProjectScript, | 63 | onAddProjectScript, |
| 75 | onUpdateProjectScript, | 64 | onUpdateProjectScript, |
| 76 | onDeleteProjectScript, | 65 | onDeleteProjectScript, |
| 77 | onToggleTerminal, | 66 | rightPanelOpen, |
| 78 | onToggleRightPanel, | ||
| 79 | }: ChatHeaderProps) { | 67 | }: ChatHeaderProps) { |
| 80 | const primaryEnvironmentId = usePrimaryEnvironmentId(); | 68 | const primaryEnvironmentId = usePrimaryEnvironmentId(); |
| 81 | const showOpenInPicker = shouldShowOpenInPicker({ | 69 | const showOpenInPicker = shouldShowOpenInPicker({ |
| @@ -83,9 +71,6 @@ export const ChatHeader = memo(function ChatHeader({ · 1 unmodified line | |||
| 83 | activeThreadEnvironmentId, | 71 | activeThreadEnvironmentId, |
| 84 | primaryEnvironmentId, | 72 | primaryEnvironmentId, |
| 85 | }); | 73 | }); |
| 86 | const terminalShortcutLabel = shortcutLabelForCommand(keybindings, "terminal.toggle"); | ||
| 87 | const rightPanelShortcutLabel = shortcutLabelForCommand(keybindings, "rightPanel.toggle"); | ||
| 88 | |||
| 89 | return ( | 74 | return ( |
| 90 | <div className="@container/header-actions flex min-w-0 flex-1 flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> | 75 | <div className="@container/header-actions flex min-w-0 flex-1 flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> |
| 91 | <div className="flex min-w-0 flex-wrap items-center gap-2 overflow-hidden sm:flex-1 sm:flex-nowrap sm:gap-3"> | 76 | <div className="flex min-w-0 flex-wrap items-center gap-2 overflow-hidden sm:flex-1 sm:flex-nowrap sm:gap-3"> |
| @@ -104,7 +89,13 @@ export const ChatHeader = memo(function ChatHeader({ · 12 unmodified lines | |||
| 104 | <TooltipPopup side="top">{activeThreadTitle}</TooltipPopup> | 89 | <TooltipPopup side="top">{activeThreadTitle}</TooltipPopup> |
| 105 | </Tooltip> | 90 | </Tooltip> |
| 106 | </div> | 91 | </div> |
| 107 | <div className="flex min-w-0 flex-wrap items-center justify-start gap-2 sm:shrink-0 sm:justify-end @3xl/header-actions:gap-3"> | 92 | <div |
| 93 | data-chat-header-actions | ||
| 94 | className={cn( | ||
| 95 | "flex min-w-0 flex-wrap items-center justify-start gap-2 sm:shrink-0 sm:justify-end @3xl/header-actions:gap-3", | ||
| 96 | rightPanelOpen ? "pr-0" : "pr-16", | ||
| 97 | )} | ||
| 98 | > | ||
| 108 | {activeProjectScripts && ( | 99 | {activeProjectScripts && ( |
| 109 | <ProjectScriptsControl | 100 | <ProjectScriptsControl |
| 110 | scripts={activeProjectScripts} | 101 | scripts={activeProjectScripts} |
| @@ -130,50 +121,6 @@ export const ChatHeader = memo(function ChatHeader({ · 19 unmodified lines | |||
| 130 | {...(draftId ? { draftId } : {})} | 121 | {...(draftId ? { draftId } : {})} |
| 131 | /> | 122 | /> |
| 132 | )} | 123 | )} |
| 133 | <Tooltip> | ||
| 134 | <TooltipTrigger | ||
| 135 | render={ | ||
| 136 | <Toggle | ||
| 137 | className="shrink-0" | ||
| 138 | pressed={terminalOpen} | ||
| 139 | onPressedChange={onToggleTerminal} | ||
| 140 | aria-label="Toggle terminal drawer" | ||
| 141 | variant="ghost" | ||
| 142 | size="xs" | ||
| 143 | disabled={!terminalAvailable} | ||
| 144 | > | ||
| 145 | <PanelBottomIcon className="size-3.5" /> | ||
| 146 | </Toggle> | ||
| 147 | } | ||
| 148 | /> | ||
| 149 | <TooltipPopup side="bottom"> | ||
| 150 | {terminalAvailable | ||
| 151 | ? `Toggle terminal drawer${terminalShortcutLabel ? ` (${terminalShortcutLabel})` : ""}` | ||
| 152 | : "Terminal drawer is unavailable"} | ||
| 153 | </TooltipPopup> | ||
| 154 | </Tooltip> | ||
| 155 | <Tooltip> | ||
| 156 | <TooltipTrigger | ||
| 157 | render={ | ||
| 158 | <Toggle | ||
| 159 | className="shrink-0" | ||
| 160 | pressed={rightPanelOpen} | ||
| 161 | onPressedChange={onToggleRightPanel} | ||
| 162 | aria-label="Toggle right panel" | ||
| 163 | variant="ghost" | ||
| 164 | size="xs" | ||
| 165 | disabled={!rightPanelAvailable} | ||
| 166 | > | ||
| 167 | <PanelRightIcon className="size-3.5" /> | ||
| 168 | </Toggle> | ||
| 169 | } | ||
| 170 | /> | ||
| 171 | <TooltipPopup side="bottom"> | ||
| 172 | {rightPanelAvailable | ||
| 173 | ? `Toggle right panel${rightPanelShortcutLabel ? ` (${rightPanelShortcutLabel})` : ""}` | ||
| 174 | : "Right panel is unavailable"} | ||
| 175 | </TooltipPopup> | ||
| 176 | </Tooltip> | ||
| 177 | </div> | 124 | </div> |
| 178 | </div> | 125 | </div> |
| 179 | ); | 126 | ); |
| @@ -18,7 +18,7 @@ import { · 17 unmodified lines | |||
| 18 | CommandList, | 18 | CommandList, |
| 19 | CommandSeparator, | 19 | CommandSeparator, |
| 20 | } from "../ui/command"; | 20 | } from "../ui/command"; |
| 21 | import { VscodeEntryIcon } from "./VscodeEntryIcon"; | 21 | import { PierreEntryIcon } from "./PierreEntryIcon"; |
| 22 | 22 | ||
| 23 | export type ComposerCommandItem = | 23 | export type ComposerCommandItem = |
| 24 | | { | 24 | | { |
| @@ -228,7 +228,7 @@ const ComposerCommandMenuItem = memo(function ComposerCommandMenuItem(props: { · 203 unmodified lines | |||
| 228 | }} | 228 | }} |
| 229 | > | 229 | > |
| 230 | {props.item.type === "path" ? ( | 230 | {props.item.type === "path" ? ( |
| 231 | <VscodeEntryIcon | 231 | <PierreEntryIcon |
| 232 | pathValue={props.item.path} | 232 | pathValue={props.item.path} |
| 233 | kind={props.item.pathKind} | 233 | kind={props.item.pathKind} |
| 234 | theme={props.resolvedTheme} | 234 | theme={props.resolvedTheme} |
| @@ -1,4 +1,4 @@ | |||
| 1 | import { inferEntryKindFromPath } from "../../vscode-icons"; | 1 | import { inferEntryKindFromPath } from "../../pierre-icons"; |
| 2 | import { | 2 | import { |
| 3 | CHAT_INLINE_CHIP_CLASS_NAME, | 3 | CHAT_INLINE_CHIP_CLASS_NAME, |
| 4 | CHAT_INLINE_CHIP_LABEL_CLASS_NAME, | 4 | CHAT_INLINE_CHIP_LABEL_CLASS_NAME, |
| @@ -6,7 +6,7 @@ import { · 1 unmodified line | |||
| 6 | COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, | 6 | COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, |
| 7 | COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, | 7 | COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, |
| 8 | } from "../composerInlineChip"; | 8 | } from "../composerInlineChip"; |
| 9 | import { VscodeEntryIcon } from "./VscodeEntryIcon"; | 9 | import { PierreEntryIcon } from "./PierreEntryIcon"; |
| 10 | 10 | ||
| 11 | export const FILE_TAG_CHIP_CLASS_NAME = COMPOSER_INLINE_CHIP_CLASS_NAME; | 11 | export const FILE_TAG_CHIP_CLASS_NAME = COMPOSER_INLINE_CHIP_CLASS_NAME; |
| 12 | export const CHAT_FILE_TAG_CHIP_CLASS_NAME = CHAT_INLINE_CHIP_CLASS_NAME; | 12 | export const CHAT_FILE_TAG_CHIP_CLASS_NAME = CHAT_INLINE_CHIP_CLASS_NAME; |
| @@ -19,7 +19,7 @@ export function FileTagChipContent(props: { · 6 unmodified lines | |||
| 19 | }) { | 19 | }) { |
| 20 | return ( | 20 | return ( |
| 21 | <> | 21 | <> |
| 22 | <VscodeEntryIcon | 22 | <PierreEntryIcon |
| 23 | pathValue={props.path} | 23 | pathValue={props.path} |
| 24 | kind={inferEntryKindFromPath(props.path)} | 24 | kind={inferEntryKindFromPath(props.path)} |
| 25 | theme={props.theme} | 25 | theme={props.theme} |
| @@ -7,8 +7,6 @@ import { page } from "vite-plus/test/browser"; · 6 unmodified lines | |||
| 7 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; | 7 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; |
| 8 | import { render } from "vitest-browser-react"; | 8 | import { render } from "vitest-browser-react"; |
| 9 | 9 | ||
| 10 | import { getVscodeIconUrlForEntry } from "../../vscode-icons"; | ||
| 11 | |||
| 12 | const scrollToEndSpy = vi.fn(); | 10 | const scrollToEndSpy = vi.fn(); |
| 13 | const getStateSpy = vi.fn(() => ({ isAtEnd: true })); | 11 | const getStateSpy = vi.fn(() => ({ isAtEnd: true })); |
| 14 | 12 | ||
| @@ -392,14 +390,12 @@ describe("MessagesTimeline", () => { · 377 unmodified lines | |||
| 392 | const assistantFileLink = document.querySelector( | 390 | const assistantFileLink = document.querySelector( |
| 393 | '[data-message-role="assistant"] .chat-markdown-file-link', | 391 | '[data-message-role="assistant"] .chat-markdown-file-link', |
| 394 | ); | 392 | ); |
| 395 | const icon = assistantFileLink?.querySelector("img"); | 393 | const icon = assistantFileLink?.querySelector("svg[data-pierre-icon]"); |
| 396 | 394 | ||
| 397 | expect(assistantFileLink?.textContent).toContain("package.json"); | 395 | expect(assistantFileLink?.textContent).toContain("package.json"); |
| 398 | expect(assistantFileLink?.textContent).toContain("L25"); | 396 | expect(assistantFileLink?.textContent).toContain("L25"); |
| 399 | expect(assistantFileLink?.getAttribute("href")).toBe("/repo/project/path/to/package.json:25"); | 397 | expect(assistantFileLink?.getAttribute("href")).toBe("/repo/project/path/to/package.json:25"); |
| 400 | expect(icon?.getAttribute("src")).toBe( | 398 | expect(icon?.getAttribute("data-pierre-icon")).toBe("t3-file-icon-package-json"); |
| 401 | getVscodeIconUrlForEntry("/repo/project/path/to/package.json", "file", "dark"), | ||
| 402 | ); | ||
| 403 | } finally { | 399 | } finally { |
| 404 | await screen.unmount(); | 400 | await screen.unmount(); |
| 405 | } | 401 | } |
| @@ -0,0 +1,114 @@ | |||
| 1 | import { Maximize2Icon, Minimize2Icon, PanelBottomIcon, PanelRightIcon } from "lucide-react"; | ||
| 2 | import { memo } from "react"; | ||
| 3 | |||
| 4 | import { cn } from "~/lib/utils"; | ||
| 5 | |||
| 6 | import { Toggle } from "../ui/toggle"; | ||
| 7 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; | ||
| 8 | |||
| 9 | interface PanelLayoutControlsProps { | ||
| 10 | terminalAvailable: boolean; | ||
| 11 | terminalOpen: boolean; | ||
| 12 | terminalShortcutLabel: string | null; | ||
| 13 | rightPanelAvailable: boolean; | ||
| 14 | rightPanelOpen: boolean; | ||
| 15 | rightPanelShortcutLabel: string | null; | ||
| 16 | rightPanelMaximized: boolean; | ||
| 17 | canMaximizeRightPanel: boolean; | ||
| 18 | onToggleTerminal: () => void; | ||
| 19 | onToggleRightPanel: () => void; | ||
| 20 | onToggleRightPanelMaximized: () => void; | ||
| 21 | } | ||
| 22 | |||
| 23 | export const PanelLayoutControls = memo(function PanelLayoutControls({ | ||
| 24 | terminalAvailable, | ||
| 25 | terminalOpen, | ||
| 26 | terminalShortcutLabel, | ||
| 27 | rightPanelAvailable, | ||
| 28 | rightPanelOpen, | ||
| 29 | rightPanelShortcutLabel, | ||
| 30 | rightPanelMaximized, | ||
| 31 | canMaximizeRightPanel, | ||
| 32 | onToggleTerminal, | ||
| 33 | onToggleRightPanel, | ||
| 34 | onToggleRightPanelMaximized, | ||
| 35 | }: PanelLayoutControlsProps) { | ||
| 36 | return ( | ||
| 37 | <div className={cn("workspace-titlebar-controls z-50 gap-1")} data-panel-layout-controls> | ||
| 38 | {rightPanelOpen ? ( | ||
| 39 | <Tooltip> | ||
| 40 | <TooltipTrigger | ||
| 41 | render={ | ||
| 42 | <Toggle | ||
| 43 | className="shrink-0" | ||
| 44 | pressed={rightPanelMaximized} | ||
| 45 | onPressedChange={onToggleRightPanelMaximized} | ||
| 46 | aria-label={rightPanelMaximized ? "Restore panel size" : "Maximize panel"} | ||
| 47 | variant="ghost" | ||
| 48 | size="sm" | ||
| 49 | disabled={!canMaximizeRightPanel} | ||
| 50 | > | ||
| 51 | {rightPanelMaximized ? ( | ||
| 52 | <Minimize2Icon className="size-3.5" /> | ||
| 53 | ) : ( | ||
| 54 | <Maximize2Icon className="size-3.5" /> | ||
| 55 | )} | ||
| 56 | </Toggle> | ||
| 57 | } | ||
| 58 | /> | ||
| 59 | <TooltipPopup side="bottom"> | ||
| 60 | {canMaximizeRightPanel | ||
| 61 | ? rightPanelMaximized | ||
| 62 | ? "Restore panel size" | ||
| 63 | : "Maximize panel" | ||
| 64 | : "Panel maximization is unavailable at this width"} | ||
| 65 | </TooltipPopup> | ||
| 66 | </Tooltip> | ||
| 67 | ) : null} | ||
| 68 | <Tooltip> | ||
| 69 | <TooltipTrigger | ||
| 70 | render={ | ||
| 71 | <Toggle | ||
| 72 | className="shrink-0" | ||
| 73 | pressed={terminalOpen} | ||
| 74 | onPressedChange={onToggleTerminal} | ||
| 75 | aria-label="Toggle terminal drawer" | ||
| 76 | variant="ghost" | ||
| 77 | size="sm" | ||
| 78 | disabled={!terminalAvailable} | ||
| 79 | > | ||
| 80 | <PanelBottomIcon className="size-3.5" /> | ||
| 81 | </Toggle> | ||
| 82 | } | ||
| 83 | /> | ||
| 84 | <TooltipPopup side="bottom"> | ||
| 85 | {terminalAvailable | ||
| 86 | ? `Toggle terminal drawer${terminalShortcutLabel ? ` (${terminalShortcutLabel})` : ""}` | ||
| 87 | : "Terminal drawer is unavailable"} | ||
| 88 | </TooltipPopup> | ||
| 89 | </Tooltip> | ||
| 90 | <Tooltip> | ||
| 91 | <TooltipTrigger | ||
| 92 | render={ | ||
| 93 | <Toggle | ||
| 94 | className="shrink-0" | ||
| 95 | pressed={rightPanelOpen} | ||
| 96 | onPressedChange={onToggleRightPanel} | ||
| 97 | aria-label="Toggle right panel" | ||
| 98 | variant="ghost" | ||
| 99 | size="sm" | ||
| 100 | disabled={!rightPanelAvailable} | ||
| 101 | > | ||
| 102 | <PanelRightIcon className="size-3.5" /> | ||
| 103 | </Toggle> | ||
| 104 | } | ||
| 105 | /> | ||
| 106 | <TooltipPopup side="bottom"> | ||
| 107 | {rightPanelAvailable | ||
| 108 | ? `Toggle right panel${rightPanelShortcutLabel ? ` (${rightPanelShortcutLabel})` : ""}` | ||
| 109 | : "Right panel is unavailable"} | ||
| 110 | </TooltipPopup> | ||
| 111 | </Tooltip> | ||
| 112 | </div> | ||
| 113 | ); | ||
| 114 | }); | ||
| @@ -0,0 +1,95 @@ | |||
| 1 | import { FileIcon, FolderIcon } from "lucide-react"; | ||
| 2 | import { memo, useInsertionEffect, useMemo } from "react"; | ||
| 3 | |||
| 4 | import { ensurePierreIconSprite, resolvePierreIconForEntry } from "../../pierre-icons"; | ||
| 5 | import { cn } from "~/lib/utils"; | ||
| 6 | |||
| 7 | const ICON_COLORS: Record<string, readonly [light: string, dark: string]> = { | ||
| 8 | astro: ["#a631be", "#d568ea"], | ||
| 9 | babel: ["#d5a910", "#ffd452"], | ||
| 10 | bash: ["#199f43", "#5ecc71"], | ||
| 11 | biome: ["#1a85d4", "#69b1ff"], | ||
| 12 | bootstrap: ["#693acf", "#9d6afb"], | ||
| 13 | browserslist: ["#d5a910", "#ffd452"], | ||
| 14 | bun: ["#594c5b", "#79697b"], | ||
| 15 | c: ["#1a85d4", "#69b1ff"], | ||
| 16 | claude: ["#d47628", "#ffa359"], | ||
| 17 | cpp: ["#1a85d4", "#69b1ff"], | ||
| 18 | css: ["#693acf", "#9d6afb"], | ||
| 19 | database: ["#a631be", "#d568ea"], | ||
| 20 | default: ["#84848a", "#adadb1"], | ||
| 21 | docker: ["#1a85d4", "#69b1ff"], | ||
| 22 | eslint: ["#693acf", "#9d6afb"], | ||
| 23 | git: ["#ff8c5b", "#d5512f"], | ||
| 24 | go: ["#1ca1c7", "#68cdf2"], | ||
| 25 | graphql: ["#d32a61", "#ff678d"], | ||
| 26 | html: ["#d47628", "#ffa359"], | ||
| 27 | image: ["#d32a61", "#ff678d"], | ||
| 28 | javascript: ["#d5a910", "#ffd452"], | ||
| 29 | json: ["#d47628", "#ffa359"], | ||
| 30 | markdown: ["#199f43", "#5ecc71"], | ||
| 31 | mcp: ["#17a5af", "#64d1db"], | ||
| 32 | nextjs: ["#84848a", "#adadb1"], | ||
| 33 | npm: ["#d52c36", "#ff6762"], | ||
| 34 | oxc: ["#1ca1c7", "#68cdf2"], | ||
| 35 | postcss: ["#d52c36", "#ff6762"], | ||
| 36 | prettier: ["#17a5af", "#64d1db"], | ||
| 37 | python: ["#1a85d4", "#69b1ff"], | ||
| 38 | react: ["#1ca1c7", "#68cdf2"], | ||
| 39 | ruby: ["#d52c36", "#ff6762"], | ||
| 40 | rust: ["#d47628", "#ffa359"], | ||
| 41 | sass: ["#d32a61", "#ff678d"], | ||
| 42 | stylelint: ["#84848a", "#adadb1"], | ||
| 43 | svelte: ["#d52c36", "#ff6762"], | ||
| 44 | svg: ["#d47628", "#ffa359"], | ||
| 45 | svgo: ["#199f43", "#5ecc71"], | ||
| 46 | swift: ["#d47628", "#ffa359"], | ||
| 47 | table: ["#17a5af", "#64d1db"], | ||
| 48 | tailwind: ["#1ca1c7", "#68cdf2"], | ||
| 49 | terraform: ["#693acf", "#9d6afb"], | ||
| 50 | text: ["#84848a", "#adadb1"], | ||
| 51 | typescript: ["#1a85d4", "#69b1ff"], | ||
| 52 | vite: ["#a631be", "#d568ea"], | ||
| 53 | vscode: ["#1a85d4", "#69b1ff"], | ||
| 54 | vue: ["#199f43", "#5ecc71"], | ||
| 55 | wasm: ["#693acf", "#9d6afb"], | ||
| 56 | webpack: ["#1a85d4", "#69b1ff"], | ||
| 57 | yml: ["#d52c36", "#ff6762"], | ||
| 58 | zig: ["#d47628", "#ffa359"], | ||
| 59 | zip: ["#d47628", "#ffa359"], | ||
| 60 | }; | ||
| 61 | |||
| 62 | export const PierreEntryIcon = memo(function PierreEntryIcon(props: { | ||
| 63 | pathValue: string; | ||
| 64 | kind: "file" | "directory"; | ||
| 65 | theme: "light" | "dark"; | ||
| 66 | className?: string; | ||
| 67 | }) { | ||
| 68 | useInsertionEffect(ensurePierreIconSprite, []); | ||
| 69 | const icon = useMemo( | ||
| 70 | () => resolvePierreIconForEntry(props.pathValue, props.kind), | ||
| 71 | [props.kind, props.pathValue], | ||
| 72 | ); | ||
| 73 | |||
| 74 | if (!icon) { | ||
| 75 | return props.kind === "directory" ? ( | ||
| 76 | <FolderIcon className={cn("size-4 text-muted-foreground/80", props.className)} /> | ||
| 77 | ) : ( | ||
| 78 | <FileIcon className={cn("size-4 text-muted-foreground/80", props.className)} /> | ||
| 79 | ); | ||
| 80 | } | ||
| 81 | |||
| 82 | const colors = ICON_COLORS[icon.token ?? "default"] ?? ICON_COLORS.default; | ||
| 83 | return ( | ||
| 84 | <svg | ||
| 85 | aria-hidden="true" | ||
| 86 | data-pierre-icon={icon.name} | ||
| 87 | data-icon-token={icon.token} | ||
| 88 | className={cn("size-4 shrink-0", props.className)} | ||
| 89 | style={{ color: colors?.[props.theme === "light" ? 0 : 1] }} | ||
| 90 | viewBox="0 0 16 16" | ||
| 91 | > | ||
| 92 | <use href={`#${icon.name}`} /> | ||
| 93 | </svg> | ||
| 94 | ); | ||
| 95 | }); | ||
| @@ -1,37 +0,0 @@ | |||
| 1 | import { memo, useMemo, useState } from "react"; | ||
| 2 | import { getVscodeIconUrlForEntry } from "../../vscode-icons"; | ||
| 3 | import { FileIcon, FolderIcon } from "lucide-react"; | ||
| 4 | import { cn } from "~/lib/utils"; | ||
| 5 | |||
| 6 | export const VscodeEntryIcon = memo(function VscodeEntryIcon(props: { | ||
| 7 | pathValue: string; | ||
| 8 | kind: "file" | "directory"; | ||
| 9 | theme: "light" | "dark"; | ||
| 10 | className?: string; | ||
| 11 | }) { | ||
| 12 | const [failedIconUrl, setFailedIconUrl] = useState<string | null>(null); | ||
| 13 | const iconUrl = useMemo( | ||
| 14 | () => getVscodeIconUrlForEntry(props.pathValue, props.kind, props.theme), | ||
| 15 | [props.kind, props.pathValue, props.theme], | ||
| 16 | ); | ||
| 17 | const failed = failedIconUrl === iconUrl; | ||
| 18 | |||
| 19 | if (failed) { | ||
| 20 | return props.kind === "directory" ? ( | ||
| 21 | <FolderIcon className={cn("size-4 text-muted-foreground/80", props.className)} /> | ||
| 22 | ) : ( | ||
| 23 | <FileIcon className={cn("size-4 text-muted-foreground/80", props.className)} /> | ||
| 24 | ); | ||
| 25 | } | ||
| 26 | |||
| 27 | return ( | ||
| 28 | <img | ||
| 29 | src={iconUrl} | ||
| 30 | alt="" | ||
| 31 | aria-hidden="true" | ||
| 32 | className={cn("size-4 shrink-0", props.className)} | ||
| 33 | loading="lazy" | ||
| 34 | onError={() => setFailedIconUrl(iconUrl)} | ||
| 35 | /> | ||
| 36 | ); | ||
| 37 | }); | ||
| @@ -0,0 +1,128 @@ | |||
| 1 | import type { EnvironmentId, ProjectEntry } from "@t3tools/contracts"; | ||
| 2 | import { FileTree, useFileTree } from "@pierre/trees/react"; | ||
| 3 | import { RefreshCw, Search } from "lucide-react"; | ||
| 4 | import { useEffect, useMemo, useRef } from "react"; | ||
| 5 | |||
| 6 | import { useTheme } from "~/hooks/useTheme"; | ||
| 7 | import { cn } from "~/lib/utils"; | ||
| 8 | import { T3_PIERRE_ICONS } from "~/pierre-icons"; | ||
| 9 | |||
| 10 | import { useProjectEntriesQuery } from "./projectFilesQueryState"; | ||
| 11 | |||
| 12 | interface FileBrowserPanelProps { | ||
| 13 | environmentId: EnvironmentId; | ||
| 14 | cwd: string; | ||
| 15 | projectName: string; | ||
| 16 | onOpenFile: (relativePath: string) => void; | ||
| 17 | } | ||
| 18 | |||
| 19 | const TREE_UNSAFE_CSS = ` | ||
| 20 | :host { | ||
| 21 | --trees-bg-override: transparent; | ||
| 22 | --trees-selected-bg-override: color-mix(in srgb, currentColor 12%, transparent); | ||
| 23 | --trees-hover-bg-override: color-mix(in srgb, currentColor 7%, transparent); | ||
| 24 | --trees-border-color-override: color-mix(in srgb, currentColor 14%, transparent); | ||
| 25 | --trees-font-family-override: var(--font-sans); | ||
| 26 | --trees-font-size-override: 12px; | ||
| 27 | } | ||
| 28 | button[data-type='item'] { border-radius: 5px; } | ||
| 29 | `; | ||
| 30 | |||
| 31 | function treePath(entry: ProjectEntry): string { | ||
| 32 | return entry.kind === "directory" ? `${entry.path}/` : entry.path; | ||
| 33 | } | ||
| 34 | |||
| 35 | export default function FileBrowserPanel({ | ||
| 36 | environmentId, | ||
| 37 | cwd, | ||
| 38 | projectName, | ||
| 39 | onOpenFile, | ||
| 40 | }: FileBrowserPanelProps) { | ||
| 41 | const { resolvedTheme } = useTheme(); | ||
| 42 | const entriesQuery = useProjectEntriesQuery(environmentId, cwd); | ||
| 43 | const entries = entriesQuery.data?.entries ?? []; | ||
| 44 | const entryKinds = useMemo( | ||
| 45 | () => new Map(entries.map((entry) => [entry.path, entry.kind] as const)), | ||
| 46 | [entries], | ||
| 47 | ); | ||
| 48 | const entryKindsRef = useRef<ReadonlyMap<string, ProjectEntry["kind"]>>(entryKinds); | ||
| 49 | const treePaths = useMemo(() => entries.map(treePath), [entries]); | ||
| 50 | const previousTreePathsRef = useRef<readonly string[]>([]); | ||
| 51 | |||
| 52 | const { model } = useFileTree({ | ||
| 53 | density: "compact", | ||
| 54 | fileTreeSearchMode: "hide-non-matches", | ||
| 55 | flattenEmptyDirectories: true, | ||
| 56 | initialExpansion: 1, | ||
| 57 | icons: T3_PIERRE_ICONS, | ||
| 58 | onSelectionChange: (selectedPaths) => { | ||
| 59 | const selectedPath = selectedPaths.at(-1)?.replace(/\/$/, ""); | ||
| 60 | if (selectedPath && entryKindsRef.current.get(selectedPath) === "file") { | ||
| 61 | onOpenFile(selectedPath); | ||
| 62 | } | ||
| 63 | }, | ||
| 64 | paths: [], | ||
| 65 | search: true, | ||
| 66 | unsafeCSS: TREE_UNSAFE_CSS, | ||
| 67 | }); | ||
| 68 | |||
| 69 | useEffect(() => { | ||
| 70 | if (previousTreePathsRef.current === treePaths) return; | ||
| 71 | entryKindsRef.current = entryKinds; | ||
| 72 | previousTreePathsRef.current = treePaths; | ||
| 73 | model.resetPaths(treePaths); | ||
| 74 | }, [entryKinds, model, treePaths]); | ||
| 75 | |||
| 76 | const fileCount = useMemo( | ||
| 77 | () => entries.reduce((count, entry) => count + (entry.kind === "file" ? 1 : 0), 0), | ||
| 78 | [entries], | ||
| 79 | ); | ||
| 80 | |||
| 81 | return ( | ||
| 82 | <div | ||
| 83 | className="flex min-h-0 flex-1 flex-col bg-background" | ||
| 84 | data-file-browser-panel={`${environmentId}:${cwd}`} | ||
| 85 | > | ||
| 86 | <div className="flex h-9 shrink-0 items-center gap-2 border-b border-border/60 px-3"> | ||
| 87 | <div className="min-w-0 flex-1"> | ||
| 88 | <div className="truncate text-xs font-medium text-foreground">{projectName}</div> | ||
| 89 | <div className="truncate text-[10px] leading-none text-muted-foreground"> | ||
| 90 | {entriesQuery.isPending && entriesQuery.data === null | ||
| 91 | ? "Indexing…" | ||
| 92 | : `${fileCount.toLocaleString()} files`} | ||
| 93 | {entriesQuery.data?.truncated ? " · partial" : ""} | ||
| 94 | </div> | ||
| 95 | </div> | ||
| 96 | <button | ||
| 97 | type="button" | ||
| 98 | className="rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground" | ||
| 99 | aria-label="Search workspace files" | ||
| 100 | onClick={() => model.openSearch()} | ||
| 101 | > | ||
| 102 | <Search className="size-3.5" /> | ||
| 103 | </button> | ||
| 104 | <button | ||
| 105 | type="button" | ||
| 106 | className="rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground" | ||
| 107 | aria-label="Refresh workspace files" | ||
| 108 | onClick={entriesQuery.refresh} | ||
| 109 | > | ||
| 110 | <RefreshCw className={cn("size-3.5", entriesQuery.isPending && "animate-spin")} /> | ||
| 111 | </button> | ||
| 112 | </div> | ||
| 113 | {entriesQuery.error && entriesQuery.data === null ? ( | ||
| 114 | <div className="p-4 text-xs leading-relaxed text-destructive">{entriesQuery.error}</div> | ||
| 115 | ) : ( | ||
| 116 | <FileTree | ||
| 117 | model={model} | ||
| 118 | aria-label={`${projectName} files`} | ||
| 119 | className="min-h-0 flex-1 overflow-hidden" | ||
| 120 | style={{ | ||
| 121 | colorScheme: resolvedTheme, | ||
| 122 | ["--trees-fg-override" as string]: "var(--foreground)", | ||
| 123 | }} | ||
| 124 | /> | ||
| 125 | )} | ||
| 126 | </div> | ||
| 127 | ); | ||
| 128 | } | ||
| @@ -0,0 +1,298 @@ | |||
| 1 | import type { EnvironmentId } from "@t3tools/contracts"; | ||
| 2 | import { Editor } from "@pierre/diffs/editor"; | ||
| 3 | import { EditorProvider, File, Virtualizer } from "@pierre/diffs/react"; | ||
| 4 | import { ChevronRight, FolderTree, LoaderCircle } from "lucide-react"; | ||
| 5 | import { useEffect, useMemo, useRef, useState } from "react"; | ||
| 6 | |||
| 7 | import { ensureEnvironmentApi } from "~/environmentApi"; | ||
| 8 | import { useTheme } from "~/hooks/useTheme"; | ||
| 9 | import { resolveDiffThemeName } from "~/lib/diffRendering"; | ||
| 10 | import { cn } from "~/lib/utils"; | ||
| 11 | import { ScrollArea } from "~/components/ui/scroll-area"; | ||
| 12 | import { Toggle } from "~/components/ui/toggle"; | ||
| 13 | import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip"; | ||
| 14 | |||
| 15 | import FileBrowserPanel from "./FileBrowserPanel"; | ||
| 16 | import { projectFileCacheKey } from "./fileContentRevision"; | ||
| 17 | import { fileBreadcrumbs } from "./filePath"; | ||
| 18 | import { FileSaveCoordinator } from "./fileSaveCoordinator"; | ||
| 19 | import { | ||
| 20 | confirmProjectFileQueryData, | ||
| 21 | setProjectFileQueryData, | ||
| 22 | useProjectFileQuery, | ||
| 23 | } from "./projectFilesQueryState"; | ||
| 24 | |||
| 25 | interface FilePreviewPanelProps { | ||
| 26 | environmentId: EnvironmentId; | ||
| 27 | cwd: string; | ||
| 28 | projectName: string; | ||
| 29 | relativePath: string | null; | ||
| 30 | onOpenFile: (relativePath: string) => void; | ||
| 31 | onPendingChange: (relativePath: string, pending: boolean) => void; | ||
| 32 | } | ||
| 33 | |||
| 34 | const FILE_EXPLORER_STORAGE_KEY = "t3code.fileExplorerOpen"; | ||
| 35 | const FILE_SAVE_DEBOUNCE_MS = 500; | ||
| 36 | |||
| 37 | interface EditableFileSurfaceProps { | ||
| 38 | environmentId: EnvironmentId; | ||
| 39 | cwd: string; | ||
| 40 | relativePath: string; | ||
| 41 | contents: string; | ||
| 42 | resolvedTheme: "light" | "dark"; | ||
| 43 | onPendingChange: (relativePath: string, pending: boolean) => void; | ||
| 44 | } | ||
| 45 | |||
| 46 | function EditableFileSurface({ | ||
| 47 | environmentId, | ||
| 48 | cwd, | ||
| 49 | relativePath, | ||
| 50 | contents, | ||
| 51 | resolvedTheme, | ||
| 52 | onPendingChange, | ||
| 53 | }: EditableFileSurfaceProps) { | ||
| 54 | const saveCoordinator = useMemo( | ||
| 55 | () => | ||
| 56 | new FileSaveCoordinator({ | ||
| 57 | debounceMs: FILE_SAVE_DEBOUNCE_MS, | ||
| 58 | onPendingChange: (pending) => onPendingChange(relativePath, pending), | ||
| 59 | persist: async (nextContents) => { | ||
| 60 | await ensureEnvironmentApi(environmentId).projects.writeFile({ | ||
| 61 | cwd, | ||
| 62 | relativePath, | ||
| 63 | contents: nextContents, | ||
| 64 | }); | ||
| 65 | }, | ||
| 66 | onConfirmed: (confirmedContents) => { | ||
| 67 | confirmProjectFileQueryData(environmentId, cwd, relativePath, confirmedContents); | ||
| 68 | }, | ||
| 69 | }), | ||
| 70 | [cwd, environmentId, onPendingChange, relativePath], | ||
| 71 | ); | ||
| 72 | const editor = useMemo( | ||
| 73 | () => | ||
| 74 | new Editor({ | ||
| 75 | onChange: (file) => { | ||
| 76 | setProjectFileQueryData(environmentId, cwd, relativePath, file.contents); | ||
| 77 | saveCoordinator.change(file.contents); | ||
| 78 | }, | ||
| 79 | }), | ||
| 80 | [cwd, environmentId, relativePath, saveCoordinator], | ||
| 81 | ); | ||
| 82 | |||
| 83 | useEffect( | ||
| 84 | () => () => { | ||
| 85 | editor.cleanUp(); | ||
| 86 | saveCoordinator.dispose(); | ||
| 87 | }, | ||
| 88 | [editor, saveCoordinator], | ||
| 89 | ); | ||
| 90 | |||
| 91 | return ( | ||
| 92 | <EditorProvider editor={editor}> | ||
| 93 | <Virtualizer | ||
| 94 | className="file-preview-virtualizer min-h-0 flex-1 overflow-auto" | ||
| 95 | config={{ | ||
| 96 | overscrollSize: 600, | ||
| 97 | intersectionObserverMargin: 1200, | ||
| 98 | }} | ||
| 99 | > | ||
| 100 | <File | ||
| 101 | file={{ | ||
| 102 | name: relativePath, | ||
| 103 | contents, | ||
| 104 | cacheKey: projectFileCacheKey(cwd, relativePath, contents), | ||
| 105 | }} | ||
| 106 | options={{ | ||
| 107 | disableFileHeader: true, | ||
| 108 | overflow: "scroll", | ||
| 109 | theme: resolveDiffThemeName(resolvedTheme), | ||
| 110 | themeType: resolvedTheme, | ||
| 111 | }} | ||
| 112 | className="min-h-full" | ||
| 113 | contentEditable | ||
| 114 | /> | ||
| 115 | </Virtualizer> | ||
| 116 | </EditorProvider> | ||
| 117 | ); | ||
| 118 | } | ||
| 119 | |||
| 120 | function initialExplorerOpen(): boolean { | ||
| 121 | try { | ||
| 122 | return window.localStorage.getItem(FILE_EXPLORER_STORAGE_KEY) !== "false"; | ||
| 123 | } catch { | ||
| 124 | return true; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | export default function FilePreviewPanel({ | ||
| 129 | environmentId, | ||
| 130 | cwd, | ||
| 131 | projectName, | ||
| 132 | relativePath, | ||
| 133 | onOpenFile, | ||
| 134 | onPendingChange, | ||
| 135 | }: FilePreviewPanelProps) { | ||
| 136 | const { resolvedTheme } = useTheme(); | ||
| 137 | const file = useProjectFileQuery(environmentId, cwd, relativePath); | ||
| 138 | const [explorerOpen, setExplorerOpen] = useState(initialExplorerOpen); | ||
| 139 | const breadcrumbRef = useRef<HTMLDivElement>(null); | ||
| 140 | const breadcrumbs = useMemo( | ||
| 141 | () => (relativePath ? fileBreadcrumbs(projectName, relativePath) : []), | ||
| 142 | [projectName, relativePath], | ||
| 143 | ); | ||
| 144 | |||
| 145 | useEffect(() => { | ||
| 146 | const currentCrumb = breadcrumbRef.current?.querySelector<HTMLElement>( | ||
| 147 | "[data-current-file-crumb='true']", | ||
| 148 | ); | ||
| 149 | currentCrumb?.scrollIntoView({ block: "nearest", inline: "end" }); | ||
| 150 | }, [relativePath]); | ||
| 151 | |||
| 152 | const toggleExplorer = () => { | ||
| 153 | setExplorerOpen((current) => { | ||
| 154 | const next = !current; | ||
| 155 | try { | ||
| 156 | window.localStorage.setItem(FILE_EXPLORER_STORAGE_KEY, String(next)); | ||
| 157 | } catch {} | ||
| 158 | return next; | ||
| 159 | }); | ||
| 160 | }; | ||
| 161 | |||
| 162 | return ( | ||
| 163 | <div className="flex min-h-0 flex-1 flex-col overflow-hidden bg-background"> | ||
| 164 | {relativePath ? ( | ||
| 165 | <div className="flex h-11 shrink-0 items-center gap-2 border-y border-border/60 px-3"> | ||
| 166 | <ScrollArea | ||
| 167 | ref={breadcrumbRef} | ||
| 168 | hideScrollbars | ||
| 169 | scrollFade | ||
| 170 | className="min-w-0 flex-1 rounded-none" | ||
| 171 | data-file-breadcrumbs | ||
| 172 | > | ||
| 173 | <div className="flex h-full w-max min-w-full items-center text-xs"> | ||
| 174 | {breadcrumbs.map((crumb, index) => ( | ||
| 175 | <div | ||
| 176 | key={crumb.path || "project"} | ||
| 177 | className="flex min-w-0 shrink-0 items-center" | ||
| 178 | data-current-file-crumb={crumb.kind === "file"} | ||
| 179 | > | ||
| 180 | {index > 0 ? ( | ||
| 181 | <ChevronRight className="mx-1 size-3.5 shrink-0 text-muted-foreground/60" /> | ||
| 182 | ) : null} | ||
| 183 | <span | ||
| 184 | className={cn( | ||
| 185 | "max-w-40 truncate", | ||
| 186 | crumb.kind === "file" | ||
| 187 | ? "font-medium text-foreground" | ||
| 188 | : "text-muted-foreground", | ||
| 189 | )} | ||
| 190 | title={crumb.path || projectName} | ||
| 191 | > | ||
| 192 | {crumb.label} | ||
| 193 | </span> | ||
| 194 | </div> | ||
| 195 | ))} | ||
| 196 | </div> | ||
| 197 | </ScrollArea> | ||
| 198 | <Tooltip> | ||
| 199 | <TooltipTrigger | ||
| 200 | render={ | ||
| 201 | <Toggle | ||
| 202 | className="shrink-0" | ||
| 203 | pressed={explorerOpen} | ||
| 204 | onPressedChange={toggleExplorer} | ||
| 205 | aria-label={explorerOpen ? "Hide file explorer" : "Show file explorer"} | ||
| 206 | variant="ghost" | ||
| 207 | size="sm" | ||
| 208 | > | ||
| 209 | <FolderTree className="size-3.5" /> | ||
| 210 | </Toggle> | ||
| 211 | } | ||
| 212 | /> | ||
| 213 | <TooltipPopup> | ||
| 214 | {explorerOpen ? "Hide file explorer" : "Show file explorer"} | ||
| 215 | </TooltipPopup> | ||
| 216 | </Tooltip> | ||
| 217 | </div> | ||
| 218 | ) : null} | ||
| 219 | {relativePath && file.data?.truncated ? ( | ||
| 220 | <div className="shrink-0 border-b border-amber-500/20 bg-amber-500/8 px-3 py-1.5 text-[11px] text-amber-700 dark:text-amber-300"> | ||
| 221 | Preview limited to the first 1 MB of a {file.data.byteLength.toLocaleString()} byte file. | ||
| 222 | </div> | ||
| 223 | ) : null} | ||
| 224 | <div className="flex min-h-0 flex-1 overflow-hidden"> | ||
| 225 | <div | ||
| 226 | className={cn( | ||
| 227 | "min-w-0 flex-1 flex-col overflow-hidden", | ||
| 228 | relativePath ? "flex" : "hidden", | ||
| 229 | )} | ||
| 230 | > | ||
| 231 | {relativePath && file.error && file.data === null ? ( | ||
| 232 | <div className="flex min-h-0 flex-1 items-center justify-center px-6 text-center text-xs leading-relaxed text-destructive"> | ||
| 233 | {file.error} | ||
| 234 | </div> | ||
| 235 | ) : relativePath && file.data === null ? ( | ||
| 236 | <div className="flex min-h-0 flex-1 items-center justify-center text-muted-foreground"> | ||
| 237 | <LoaderCircle className="size-5 animate-spin" /> | ||
| 238 | </div> | ||
| 239 | ) : relativePath && file.data ? ( | ||
| 240 | file.data.truncated ? ( | ||
| 241 | <Virtualizer | ||
| 242 | key={`${relativePath}:${resolvedTheme}:${file.data.byteLength}`} | ||
| 243 | className="file-preview-virtualizer min-h-0 flex-1 overflow-auto" | ||
| 244 | config={{ | ||
| 245 | overscrollSize: 600, | ||
| 246 | intersectionObserverMargin: 1200, | ||
| 247 | }} | ||
| 248 | > | ||
| 249 | <File | ||
| 250 | file={{ | ||
| 251 | name: relativePath, | ||
| 252 | contents: file.data.contents, | ||
| 253 | cacheKey: projectFileCacheKey(cwd, relativePath, file.data.contents), | ||
| 254 | }} | ||
| 255 | options={{ | ||
| 256 | disableFileHeader: true, | ||
| 257 | overflow: "scroll", | ||
| 258 | theme: resolveDiffThemeName(resolvedTheme), | ||
| 259 | themeType: resolvedTheme, | ||
| 260 | }} | ||
| 261 | className="min-h-full" | ||
| 262 | /> | ||
| 263 | </Virtualizer> | ||
| 264 | ) : ( | ||
| 265 | <EditableFileSurface | ||
| 266 | key={`${relativePath}:${resolvedTheme}`} | ||
| 267 | environmentId={environmentId} | ||
| 268 | cwd={cwd} | ||
| 269 | relativePath={relativePath} | ||
| 270 | contents={file.data.contents} | ||
| 271 | resolvedTheme={resolvedTheme} | ||
| 272 | onPendingChange={onPendingChange} | ||
| 273 | /> | ||
| 274 | ) | ||
| 275 | ) : null} | ||
| 276 | </div> | ||
| 277 | {explorerOpen || relativePath === null ? ( | ||
| 278 | <aside | ||
| 279 | className={cn( | ||
| 280 | "flex min-h-0 shrink-0 bg-background", | ||
| 281 | relativePath | ||
| 282 | ? "w-[min(22rem,46%)] min-w-64 border-l border-border/60" | ||
| 283 | : "min-w-0 flex-1", | ||
| 284 | )} | ||
| 285 | > | ||
| 286 | <FileBrowserPanel | ||
| 287 | key={`${environmentId}:${cwd}`} | ||
| 288 | environmentId={environmentId} | ||
| 289 | cwd={cwd} | ||
| 290 | projectName={projectName} | ||
| 291 | onOpenFile={onOpenFile} | ||
| 292 | /> | ||
| 293 | </aside> | ||
| 294 | ) : null} | ||
| 295 | </div> | ||
| 296 | </div> | ||
| 297 | ); | ||
| 298 | } | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | import { describe, expect, it } from "vite-plus/test"; | ||
| 2 | |||
| 3 | import { fileContentRevision, projectFileCacheKey } from "./fileContentRevision"; | ||
| 4 | |||
| 5 | describe("fileContentRevision", () => { | ||
| 6 | it("changes for same-length edits", () => { | ||
| 7 | expect(fileContentRevision("nodeVersion")).not.toBe(fileContentRevision("nodeVeasdrs")); | ||
| 8 | }); | ||
| 9 | |||
| 10 | it("keeps identical contents stable", () => { | ||
| 11 | expect(projectFileCacheKey("/repo", "file.json", "contents")).toBe( | ||
| 12 | projectFileCacheKey("/repo", "file.json", "contents"), | ||
| 13 | ); | ||
| 14 | }); | ||
| 15 | }); | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | export function fileContentRevision(contents: string): string { | ||
| 2 | let hash = 2_166_136_261; | ||
| 3 | for (let index = 0; index < contents.length; index += 1) { | ||
| 4 | hash ^= contents.charCodeAt(index); | ||
| 5 | hash = Math.imul(hash, 16_777_619); | ||
| 6 | } | ||
| 7 | return `${contents.length}:${(hash >>> 0).toString(36)}`; | ||
| 8 | } | ||
| 9 | |||
| 10 | export function projectFileCacheKey(cwd: string, relativePath: string, contents: string): string { | ||
| 11 | return `${cwd}:${relativePath}:${fileContentRevision(contents)}`; | ||
| 12 | } | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | import { describe, expect, it } from "vite-plus/test"; | ||
| 2 | |||
| 3 | import { fileBreadcrumbs } from "./filePath"; | ||
| 4 | |||
| 5 | describe("fileBreadcrumbs", () => { | ||
| 6 | it("builds project, directory, and file crumbs", () => { | ||
| 7 | expect(fileBreadcrumbs("t3code", "apps/web/src/main.tsx")).toEqual([ | ||
| 8 | { label: "t3code", path: "", kind: "project" }, | ||
| 9 | { label: "apps", path: "apps", kind: "directory" }, | ||
| 10 | { label: "web", path: "apps/web", kind: "directory" }, | ||
| 11 | { label: "src", path: "apps/web/src", kind: "directory" }, | ||
| 12 | { label: "main.tsx", path: "apps/web/src/main.tsx", kind: "file" }, | ||
| 13 | ]); | ||
| 14 | }); | ||
| 15 | |||
| 16 | it("normalizes repeated separators", () => { | ||
| 17 | expect(fileBreadcrumbs("workspace", "/src//index.ts").map((crumb) => crumb.label)).toEqual([ | ||
| 18 | "workspace", | ||
| 19 | "src", | ||
| 20 | "index.ts", | ||
| 21 | ]); | ||
| 22 | }); | ||
| 23 | }); | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | export interface FileBreadcrumb { | ||
| 2 | label: string; | ||
| 3 | path: string; | ||
| 4 | kind: "project" | "directory" | "file"; | ||
| 5 | } | ||
| 6 | |||
| 7 | export function fileBreadcrumbs(projectName: string, relativePath: string): FileBreadcrumb[] { | ||
| 8 | const parts = relativePath.split("/").filter(Boolean); | ||
| 9 | return [ | ||
| 10 | { label: projectName, path: "", kind: "project" }, | ||
| 11 | ...parts.map((part, index) => ({ | ||
| 12 | label: part, | ||
| 13 | path: parts.slice(0, index + 1).join("/"), | ||
| 14 | kind: index === parts.length - 1 ? ("file" as const) : ("directory" as const), | ||
| 15 | })), | ||
| 16 | ]; | ||
| 17 | } | ||
| @@ -0,0 +1,87 @@ | |||
| 1 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; | ||
| 2 | |||
| 3 | import { FileSaveCoordinator } from "./fileSaveCoordinator"; | ||
| 4 | |||
| 5 | function deferred() { | ||
| 6 | let resolve!: () => void; | ||
| 7 | const promise = new Promise<void>((resolvePromise) => { | ||
| 8 | resolve = resolvePromise; | ||
| 9 | }); | ||
| 10 | return { promise, resolve }; | ||
| 11 | } | ||
| 12 | |||
| 13 | describe("FileSaveCoordinator", () => { | ||
| 14 | afterEach(() => { | ||
| 15 | vi.useRealTimers(); | ||
| 16 | }); | ||
| 17 | |||
| 18 | it("debounces edits and persists only the latest contents", async () => { | ||
| 19 | vi.useFakeTimers(); | ||
| 20 | const persist = vi.fn<(contents: string) => Promise<void>>().mockResolvedValue(undefined); | ||
| 21 | const onPendingChange = vi.fn(); | ||
| 22 | const onConfirmed = vi.fn(); | ||
| 23 | const coordinator = new FileSaveCoordinator({ | ||
| 24 | debounceMs: 500, | ||
| 25 | persist, | ||
| 26 | onPendingChange, | ||
| 27 | onConfirmed, | ||
| 28 | }); | ||
| 29 | |||
| 30 | coordinator.change("first"); | ||
| 31 | await vi.advanceTimersByTimeAsync(300); | ||
| 32 | coordinator.change("latest"); | ||
| 33 | await vi.advanceTimersByTimeAsync(499); | ||
| 34 | expect(persist).not.toHaveBeenCalled(); | ||
| 35 | |||
| 36 | await vi.advanceTimersByTimeAsync(1); | ||
| 37 | expect(persist).toHaveBeenCalledOnce(); | ||
| 38 | expect(persist).toHaveBeenCalledWith("latest"); | ||
| 39 | expect(onConfirmed).toHaveBeenCalledWith("latest"); | ||
| 40 | expect(onPendingChange.mock.calls).toEqual([[true], [true], [false]]); | ||
| 41 | }); | ||
| 42 | |||
| 43 | it("keeps pending state until an edit made during a write is also saved", async () => { | ||
| 44 | vi.useFakeTimers(); | ||
| 45 | const firstWrite = deferred(); | ||
| 46 | const persist = vi | ||
| 47 | .fn<(contents: string) => Promise<void>>() | ||
| 48 | .mockReturnValueOnce(firstWrite.promise) | ||
| 49 | .mockResolvedValueOnce(undefined); | ||
| 50 | const onPendingChange = vi.fn(); | ||
| 51 | const coordinator = new FileSaveCoordinator({ | ||
| 52 | debounceMs: 500, | ||
| 53 | persist, | ||
| 54 | onPendingChange, | ||
| 55 | onConfirmed: vi.fn(), | ||
| 56 | }); | ||
| 57 | |||
| 58 | coordinator.change("first"); | ||
| 59 | await vi.advanceTimersByTimeAsync(500); | ||
| 60 | coordinator.change("latest"); | ||
| 61 | await vi.advanceTimersByTimeAsync(500); | ||
| 62 | expect(persist).toHaveBeenCalledTimes(1); | ||
| 63 | |||
| 64 | firstWrite.resolve(); | ||
| 65 | await vi.runAllTimersAsync(); | ||
| 66 | expect(persist).toHaveBeenCalledTimes(2); | ||
| 67 | expect(persist).toHaveBeenLastCalledWith("latest"); | ||
| 68 | expect(onPendingChange.mock.calls.at(-1)).toEqual([false]); | ||
| 69 | }); | ||
| 70 | |||
| 71 | it("leaves the file pending when the latest write fails", async () => { | ||
| 72 | vi.useFakeTimers(); | ||
| 73 | const onPendingChange = vi.fn(); | ||
| 74 | const coordinator = new FileSaveCoordinator({ | ||
| 75 | debounceMs: 500, | ||
| 76 | persist: vi.fn().mockRejectedValue(new Error("write failed")), | ||
| 77 | onPendingChange, | ||
| 78 | onConfirmed: vi.fn(), | ||
| 79 | }); | ||
| 80 | |||
| 81 | coordinator.change("latest"); | ||
| 82 | await vi.advanceTimersByTimeAsync(500); | ||
| 83 | await Promise.resolve(); | ||
| 84 | expect(onPendingChange).toHaveBeenCalledWith(true); | ||
| 85 | expect(onPendingChange).not.toHaveBeenCalledWith(false); | ||
| 86 | }); | ||
| 87 | }); | ||
| @@ -0,0 +1,75 @@ | |||
| 1 | export interface FileSaveCoordinatorOptions { | ||
| 2 | readonly debounceMs: number; | ||
| 3 | readonly persist: (contents: string) => Promise<void>; | ||
| 4 | readonly onPendingChange: (pending: boolean) => void; | ||
| 5 | readonly onConfirmed: (contents: string) => void; | ||
| 6 | } | ||
| 7 | |||
| 8 | export class FileSaveCoordinator { | ||
| 9 | private timer: ReturnType<typeof setTimeout> | null = null; | ||
| 10 | private latestContents = ""; | ||
| 11 | private latestRevision = 0; | ||
| 12 | private lastChangeAt = 0; | ||
| 13 | private saving = false; | ||
| 14 | private disposed = false; | ||
| 15 | |||
| 16 | constructor(private readonly options: FileSaveCoordinatorOptions) {} | ||
| 17 | |||
| 18 | change(contents: string): void { | ||
| 19 | this.latestContents = contents; | ||
| 20 | this.latestRevision += 1; | ||
| 21 | this.lastChangeAt = Date.now(); | ||
| 22 | this.options.onPendingChange(true); | ||
| 23 | this.schedule(this.options.debounceMs); | ||
| 24 | } | ||
| 25 | |||
| 26 | dispose(): void { | ||
| 27 | this.disposed = true; | ||
| 28 | this.clearTimer(); | ||
| 29 | if (this.latestRevision > 0) void this.persistLatest(); | ||
| 30 | } | ||
| 31 | |||
| 32 | private schedule(delay: number): void { | ||
| 33 | this.clearTimer(); | ||
| 34 | this.timer = setTimeout(() => { | ||
| 35 | this.timer = null; | ||
| 36 | void this.persistLatest(); | ||
| 37 | }, delay); | ||
| 38 | } | ||
| 39 | |||
| 40 | private clearTimer(): void { | ||
| 41 | if (this.timer === null) return; | ||
| 42 | clearTimeout(this.timer); | ||
| 43 | this.timer = null; | ||
| 44 | } | ||
| 45 | |||
| 46 | private async persistLatest(): Promise<void> { | ||
| 47 | if (this.saving || this.latestRevision === 0) return; | ||
| 48 | |||
| 49 | this.saving = true; | ||
| 50 | const contents = this.latestContents; | ||
| 51 | const revision = this.latestRevision; | ||
| 52 | let succeeded = false; | ||
| 53 | try { | ||
| 54 | await this.options.persist(contents); | ||
| 55 | succeeded = true; | ||
| 56 | this.options.onConfirmed(contents); | ||
| 57 | } catch {} | ||
| 58 | |||
| 59 | this.saving = false; | ||
| 60 | if (revision === this.latestRevision) { | ||
| 61 | if (succeeded) this.options.onPendingChange(false); | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | |||
| 65 | const remainingDebounce = Math.max( | ||
| 66 | 0, | ||
| 67 | this.options.debounceMs - (Date.now() - this.lastChangeAt), | ||
| 68 | ); | ||
| 69 | if (this.disposed) { | ||
| 70 | void this.persistLatest(); | ||
| 71 | } else { | ||
| 72 | this.schedule(remainingDebounce); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | } | ||
| @@ -0,0 +1,129 @@ | |||
| 1 | import type { | ||
| 2 | EnvironmentApi, | ||
| 3 | ProjectListEntriesResult, | ||
| 4 | ProjectReadFileResult, | ||
| 5 | } from "@t3tools/contracts"; | ||
| 6 | import { EnvironmentId } from "@t3tools/contracts"; | ||
| 7 | import * as Option from "effect/Option"; | ||
| 8 | import { AsyncResult, AtomRegistry } from "effect/unstable/reactivity"; | ||
| 9 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; | ||
| 10 | |||
| 11 | import { | ||
| 12 | __resetEnvironmentApiOverridesForTests, | ||
| 13 | __setEnvironmentApiOverrideForTests, | ||
| 14 | } from "~/environmentApi"; | ||
| 15 | import { appAtomRegistry } from "~/rpc/atomRegistry"; | ||
| 16 | |||
| 17 | import { | ||
| 18 | __resetProjectFileQueryDataForTests, | ||
| 19 | confirmProjectFileQueryData, | ||
| 20 | getProjectEntriesQueryAtom, | ||
| 21 | getProjectFileQueryAtom, | ||
| 22 | resolveProjectFileQueryData, | ||
| 23 | setProjectFileQueryData, | ||
| 24 | } from "./projectFilesQueryState"; | ||
| 25 | |||
| 26 | const environmentId = EnvironmentId.make("environment-project-files-query-test"); | ||
| 27 | |||
| 28 | function deferred<A>() { | ||
| 29 | let resolve!: (value: A) => void; | ||
| 30 | const promise = new Promise<A>((resolvePromise) => { | ||
| 31 | resolve = resolvePromise; | ||
| 32 | }); | ||
| 33 | return { promise, resolve }; | ||
| 34 | } | ||
| 35 | |||
| 36 | describe("project files queries", () => { | ||
| 37 | afterEach(() => { | ||
| 38 | __resetProjectFileQueryDataForTests(); | ||
| 39 | __resetEnvironmentApiOverridesForTests(); | ||
| 40 | vi.unstubAllGlobals(); | ||
| 41 | }); | ||
| 42 | |||
| 43 | it("retains cached entries while explicitly revalidating", async () => { | ||
| 44 | vi.stubGlobal("window", {}); | ||
| 45 | const first = { | ||
| 46 | entries: [{ path: "README.md", kind: "file" }], | ||
| 47 | truncated: false, | ||
| 48 | } satisfies ProjectListEntriesResult; | ||
| 49 | const second = { | ||
| 50 | entries: [ | ||
| 51 | { path: "README.md", kind: "file" }, | ||
| 52 | { path: "src", kind: "directory" }, | ||
| 53 | ], | ||
| 54 | truncated: false, | ||
| 55 | } satisfies ProjectListEntriesResult; | ||
| 56 | const revalidation = deferred<ProjectListEntriesResult>(); | ||
| 57 | const listEntries = vi | ||
| 58 | .fn<EnvironmentApi["projects"]["listEntries"]>() | ||
| 59 | .mockResolvedValueOnce(first) | ||
| 60 | .mockReturnValueOnce(revalidation.promise); | ||
| 61 | __setEnvironmentApiOverrideForTests(environmentId, { | ||
| 62 | projects: { listEntries }, | ||
| 63 | } as unknown as EnvironmentApi); | ||
| 64 | const registry = AtomRegistry.make(); | ||
| 65 | const atom = getProjectEntriesQueryAtom(environmentId, "/repo"); | ||
| 66 | |||
| 67 | registry.get(atom); | ||
| 68 | await vi.waitFor(() => { | ||
| 69 | expect(Option.getOrNull(AsyncResult.value(registry.get(atom)))).toEqual(first); | ||
| 70 | }); | ||
| 71 | |||
| 72 | registry.refresh(atom); | ||
| 73 | await vi.waitFor(() => expect(listEntries).toHaveBeenCalledTimes(2)); | ||
| 74 | const refreshing = registry.get(atom); | ||
| 75 | expect(refreshing.waiting).toBe(true); | ||
| 76 | expect(Option.getOrNull(AsyncResult.value(refreshing))).toEqual(first); | ||
| 77 | |||
| 78 | revalidation.resolve(second); | ||
| 79 | await vi.waitFor(() => { | ||
| 80 | expect(Option.getOrNull(AsyncResult.value(registry.get(atom)))).toEqual(second); | ||
| 81 | }); | ||
| 82 | registry.dispose(); | ||
| 83 | }); | ||
| 84 | |||
| 85 | it("keeps the latest optimistic draft when an older write finishes", async () => { | ||
| 86 | vi.stubGlobal("window", {}); | ||
| 87 | const initial = { | ||
| 88 | relativePath: "convex.json", | ||
| 89 | contents: '{"nodeVersion":"20"}', | ||
| 90 | byteLength: 20, | ||
| 91 | truncated: false, | ||
| 92 | } satisfies ProjectReadFileResult; | ||
| 93 | const readFile = vi.fn<EnvironmentApi["projects"]["readFile"]>().mockResolvedValue(initial); | ||
| 94 | __setEnvironmentApiOverrideForTests(environmentId, { | ||
| 95 | projects: { readFile }, | ||
| 96 | } as unknown as EnvironmentApi); | ||
| 97 | const atom = getProjectFileQueryAtom(environmentId, "/repo", "convex.json"); | ||
| 98 | |||
| 99 | appAtomRegistry.get(atom); | ||
| 100 | await vi.waitFor(() => { | ||
| 101 | expect(Option.getOrNull(AsyncResult.value(appAtomRegistry.get(atom)))).toEqual(initial); | ||
| 102 | }); | ||
| 103 | |||
| 104 | setProjectFileQueryData(environmentId, "/repo", "convex.json", '{"nodeVersion":"220"}'); | ||
| 105 | setProjectFileQueryData(environmentId, "/repo", "convex.json", '{"nodeVersion":"22"}'); | ||
| 106 | |||
| 107 | expect( | ||
| 108 | confirmProjectFileQueryData(environmentId, "/repo", "convex.json", '{"nodeVersion":"220"}'), | ||
| 109 | ).toBe(false); | ||
| 110 | |||
| 111 | expect( | ||
| 112 | resolveProjectFileQueryData( | ||
| 113 | environmentId, | ||
| 114 | "/repo", | ||
| 115 | "convex.json", | ||
| 116 | Option.getOrNull(AsyncResult.value(appAtomRegistry.get(atom))), | ||
| 117 | ), | ||
| 118 | ).toEqual({ | ||
| 119 | relativePath: "convex.json", | ||
| 120 | contents: '{"nodeVersion":"22"}', | ||
| 121 | byteLength: 20, | ||
| 122 | truncated: false, | ||
| 123 | }); | ||
| 124 | |||
| 125 | expect( | ||
| 126 | confirmProjectFileQueryData(environmentId, "/repo", "convex.json", '{"nodeVersion":"22"}'), | ||
| 127 | ).toBe(true); | ||
| 128 | }); | ||
| 129 | }); | ||
| @@ -0,0 +1,206 @@ | |||
| 1 | import { useAtomValue } from "@effect/atom-react"; | ||
| 2 | import type { | ||
| 3 | EnvironmentId, | ||
| 4 | ProjectListEntriesResult, | ||
| 5 | ProjectReadFileResult, | ||
| 6 | } from "@t3tools/contracts"; | ||
| 7 | import * as Cause from "effect/Cause"; | ||
| 8 | import * as Data from "effect/Data"; | ||
| 9 | import * as Effect from "effect/Effect"; | ||
| 10 | import * as Option from "effect/Option"; | ||
| 11 | import { AsyncResult, Atom } from "effect/unstable/reactivity"; | ||
| 12 | import { useCallback, useEffect } from "react"; | ||
| 13 | |||
| 14 | import { ensureEnvironmentApi } from "~/environmentApi"; | ||
| 15 | import { appAtomRegistry } from "~/rpc/atomRegistry"; | ||
| 16 | |||
| 17 | const PROJECT_QUERY_STALE_TIME_MS = 30_000; | ||
| 18 | const PROJECT_QUERY_IDLE_TTL_MS = 5 * 60_000; | ||
| 19 | const EMPTY_PROJECT_FILE_PATH = ""; | ||
| 20 | interface OptimisticProjectFile { | ||
| 21 | readonly data: ProjectReadFileResult; | ||
| 22 | readonly confirmed: boolean; | ||
| 23 | } | ||
| 24 | |||
| 25 | const optimisticProjectFiles = new Map<string, OptimisticProjectFile>(); | ||
| 26 | |||
| 27 | class ProjectQueryError extends Data.TaggedError("ProjectQueryError")<{ | ||
| 28 | readonly message: string; | ||
| 29 | readonly cause?: unknown; | ||
| 30 | }> {} | ||
| 31 | |||
| 32 | function queryError(message: string, cause: unknown): ProjectQueryError { | ||
| 33 | return new ProjectQueryError({ message, cause }); | ||
| 34 | } | ||
| 35 | |||
| 36 | function entriesKey(environmentId: EnvironmentId, cwd: string): string { | ||
| 37 | return [environmentId, cwd].map(encodeURIComponent).join("|"); | ||
| 38 | } | ||
| 39 | |||
| 40 | function fileKey(environmentId: EnvironmentId, cwd: string, relativePath: string): string { | ||
| 41 | return [environmentId, cwd, relativePath].map(encodeURIComponent).join("|"); | ||
| 42 | } | ||
| 43 | |||
| 44 | function keyParts(key: string): string[] { | ||
| 45 | return key.split("|").map(decodeURIComponent); | ||
| 46 | } | ||
| 47 | |||
| 48 | const projectEntriesQueryAtom = Atom.family((key: string) => | ||
| 49 | Atom.make( | ||
| 50 | Effect.tryPromise({ | ||
| 51 | try: () => { | ||
| 52 | const [environmentId, cwd] = keyParts(key) as [EnvironmentId, string]; | ||
| 53 | return ensureEnvironmentApi(environmentId).projects.listEntries({ cwd }); | ||
| 54 | }, | ||
| 55 | catch: (cause) => queryError("Could not load workspace files.", cause), | ||
| 56 | }), | ||
| 57 | ).pipe( | ||
| 58 | Atom.swr({ | ||
| 59 | staleTime: PROJECT_QUERY_STALE_TIME_MS, | ||
| 60 | revalidateOnMount: true, | ||
| 61 | }), | ||
| 62 | Atom.setIdleTTL(PROJECT_QUERY_IDLE_TTL_MS), | ||
| 63 | Atom.withLabel(`projects:entries:${key}`), | ||
| 64 | ), | ||
| 65 | ); | ||
| 66 | |||
| 67 | const projectFileQueryAtom = Atom.family((key: string) => | ||
| 68 | Atom.make( | ||
| 69 | Effect.tryPromise({ | ||
| 70 | try: () => { | ||
| 71 | const [environmentId, cwd, relativePath] = keyParts(key) as [EnvironmentId, string, string]; | ||
| 72 | if (relativePath === EMPTY_PROJECT_FILE_PATH) return Promise.resolve(null); | ||
| 73 | return ensureEnvironmentApi(environmentId).projects.readFile({ cwd, relativePath }); | ||
| 74 | }, | ||
| 75 | catch: (cause) => queryError("Could not read workspace file.", cause), | ||
| 76 | }), | ||
| 77 | ).pipe( | ||
| 78 | Atom.swr({ | ||
| 79 | staleTime: PROJECT_QUERY_STALE_TIME_MS, | ||
| 80 | revalidateOnMount: true, | ||
| 81 | }), | ||
| 82 | Atom.setIdleTTL(PROJECT_QUERY_IDLE_TTL_MS), | ||
| 83 | Atom.withLabel(`projects:file:${key}`), | ||
| 84 | ), | ||
| 85 | ); | ||
| 86 | |||
| 87 | interface ProjectQueryState<A> { | ||
| 88 | readonly data: A | null; | ||
| 89 | readonly error: string | null; | ||
| 90 | readonly isPending: boolean; | ||
| 91 | readonly refresh: () => void; | ||
| 92 | } | ||
| 93 | |||
| 94 | export function getProjectEntriesQueryAtom(environmentId: EnvironmentId, cwd: string) { | ||
| 95 | return projectEntriesQueryAtom(entriesKey(environmentId, cwd)); | ||
| 96 | } | ||
| 97 | |||
| 98 | export function getProjectFileQueryAtom( | ||
| 99 | environmentId: EnvironmentId, | ||
| 100 | cwd: string, | ||
| 101 | relativePath: string | null, | ||
| 102 | ) { | ||
| 103 | return projectFileQueryAtom(fileKey(environmentId, cwd, relativePath ?? EMPTY_PROJECT_FILE_PATH)); | ||
| 104 | } | ||
| 105 | |||
| 106 | export function setProjectFileQueryData( | ||
| 107 | environmentId: EnvironmentId, | ||
| 108 | cwd: string, | ||
| 109 | relativePath: string, | ||
| 110 | contents: string, | ||
| 111 | ): void { | ||
| 112 | const key = fileKey(environmentId, cwd, relativePath); | ||
| 113 | optimisticProjectFiles.set(key, { | ||
| 114 | confirmed: false, | ||
| 115 | data: { | ||
| 116 | relativePath, | ||
| 117 | contents, | ||
| 118 | byteLength: new TextEncoder().encode(contents).byteLength, | ||
| 119 | truncated: false, | ||
| 120 | }, | ||
| 121 | }); | ||
| 122 | } | ||
| 123 | |||
| 124 | export function confirmProjectFileQueryData( | ||
| 125 | environmentId: EnvironmentId, | ||
| 126 | cwd: string, | ||
| 127 | relativePath: string, | ||
| 128 | contents: string, | ||
| 129 | ): boolean { | ||
| 130 | const key = fileKey(environmentId, cwd, relativePath); | ||
| 131 | const optimisticFile = optimisticProjectFiles.get(key); | ||
| 132 | if (optimisticFile?.data.contents !== contents) return false; | ||
| 133 | |||
| 134 | optimisticProjectFiles.set(key, { ...optimisticFile, confirmed: true }); | ||
| 135 | appAtomRegistry.refresh(getProjectFileQueryAtom(environmentId, cwd, relativePath)); | ||
| 136 | return true; | ||
| 137 | } | ||
| 138 | |||
| 139 | export function resolveProjectFileQueryData( | ||
| 140 | environmentId: EnvironmentId, | ||
| 141 | cwd: string, | ||
| 142 | relativePath: string | null, | ||
| 143 | data: ProjectReadFileResult | null, | ||
| 144 | ): ProjectReadFileResult | null { | ||
| 145 | if (relativePath === null) return data; | ||
| 146 | return optimisticProjectFiles.get(fileKey(environmentId, cwd, relativePath))?.data ?? data; | ||
| 147 | } | ||
| 148 | |||
| 149 | export function __resetProjectFileQueryDataForTests(): void { | ||
| 150 | optimisticProjectFiles.clear(); | ||
| 151 | } | ||
| 152 | |||
| 153 | function errorMessage<A>(result: AsyncResult.AsyncResult<A, unknown>): string | null { | ||
| 154 | if (result._tag !== "Failure") return null; | ||
| 155 | const cause = Cause.squash(result.cause); | ||
| 156 | return cause instanceof Error ? cause.message : "Workspace query failed."; | ||
| 157 | } | ||
| 158 | |||
| 159 | export function useProjectEntriesQuery( | ||
| 160 | environmentId: EnvironmentId, | ||
| 161 | cwd: string, | ||
| 162 | ): ProjectQueryState<ProjectListEntriesResult> { | ||
| 163 | const atom = getProjectEntriesQueryAtom(environmentId, cwd); | ||
| 164 | const result = useAtomValue(atom); | ||
| 165 | const refresh = useCallback(() => appAtomRegistry.refresh(atom), [atom]); | ||
| 166 | return { | ||
| 167 | data: Option.getOrNull(AsyncResult.value(result)), | ||
| 168 | error: errorMessage(result), | ||
| 169 | isPending: result.waiting, | ||
| 170 | refresh, | ||
| 171 | }; | ||
| 172 | } | ||
| 173 | |||
| 174 | export function useProjectFileQuery( | ||
| 175 | environmentId: EnvironmentId, | ||
| 176 | cwd: string, | ||
| 177 | relativePath: string | null, | ||
| 178 | ): ProjectQueryState<ProjectReadFileResult> { | ||
| 179 | const atom = getProjectFileQueryAtom(environmentId, cwd, relativePath); | ||
| 180 | const result = useAtomValue(atom); | ||
| 181 | const refresh = useCallback(() => appAtomRegistry.refresh(atom), [atom]); | ||
| 182 | const data = Option.getOrNull(AsyncResult.value(result)); | ||
| 183 | const optimisticFile = | ||
| 184 | relativePath === null | ||
| 185 | ? undefined | ||
| 186 | : optimisticProjectFiles.get(fileKey(environmentId, cwd, relativePath)); | ||
| 187 | |||
| 188 | useEffect(() => { | ||
| 189 | if ( | ||
| 190 | relativePath === null || | ||
| 191 | optimisticFile === undefined || | ||
| 192 | !optimisticFile.confirmed || | ||
| 193 | data?.contents !== optimisticFile.data.contents | ||
| 194 | ) { | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | optimisticProjectFiles.delete(fileKey(environmentId, cwd, relativePath)); | ||
| 198 | }, [cwd, data?.contents, environmentId, optimisticFile, relativePath]); | ||
| 199 | |||
| 200 | return { | ||
| 201 | data: optimisticFile?.data ?? data, | ||
| 202 | error: errorMessage(result), | ||
| 203 | isPending: result.waiting, | ||
| 204 | refresh, | ||
| 205 | }; | ||
| 206 | } | ||
| @@ -21,7 +21,11 @@ const PREVIEW_PANEL_DEFAULT_WIDTH = 540; · 20 unmodified lines | |||
| 21 | * via a drag handle on the left edge; width persists per browser. In | 21 | * via a drag handle on the left edge; width persists per browser. In |
| 22 | * sheet/sidebar modes the parent owns the size. | 22 | * sheet/sidebar modes the parent owns the size. |
| 23 | */ | 23 | */ |
| 24 | export function PreviewPanelShell(props: { mode: PreviewPanelMode; children: ReactNode }) { | 24 | export function PreviewPanelShell(props: { |
| 25 | mode: PreviewPanelMode; | ||
| 26 | maximized?: boolean; | ||
| 27 | children: ReactNode; | ||
| 28 | }) { | ||
| 25 | const useDragRegion = isElectron && props.mode !== "sheet" && props.mode !== "embedded"; | 29 | const useDragRegion = isElectron && props.mode !== "sheet" && props.mode !== "embedded"; |
| 26 | const isInline = props.mode === "inline"; | 30 | const isInline = props.mode === "inline"; |
| 27 | const maxWidth = useViewportClampedMaxWidth(); | 31 | const maxWidth = useViewportClampedMaxWidth(); |
| @@ -37,12 +41,17 @@ export function PreviewPanelShell(props: { mode: PreviewPanelMode; children: Rea · 9 unmodified lines | |||
| 37 | <div | 41 | <div |
| 38 | className={cn( | 42 | className={cn( |
| 39 | "relative flex h-full min-h-0 min-w-0 flex-col self-stretch bg-background", | 43 | "relative flex h-full min-h-0 min-w-0 flex-col self-stretch bg-background", |
| 40 | isInline ? "shrink-0 border-l border-border" : "w-full", | 44 | isInline |
| 45 | ? props.maximized | ||
| 46 | ? "flex-1 border-l border-border" | ||
| 47 | : "shrink-0 border-l border-border" | ||
| 48 | : "w-full", | ||
| 41 | )} | 49 | )} |
| 42 | style={isInline ? { width: `${width}px` } : undefined} | 50 | style={isInline && !props.maximized ? { width: `${width}px` } : undefined} |
| 43 | data-preview-panel-mode={props.mode} | 51 | data-preview-panel-mode={props.mode} |
| 52 | data-preview-panel-maximized={props.maximized ? "true" : "false"} | ||
| 44 | > | 53 | > |
| 45 | {isInline ? <RightPanelResizeHandle handlers={handlers} /> : null} | 54 | {isInline && !props.maximized ? <RightPanelResizeHandle handlers={handlers} /> : null} |
| 46 | {useDragRegion ? <div className="electron-drag-region h-0 w-full" aria-hidden /> : null} | 55 | {useDragRegion ? <div className="electron-drag-region h-0 w-full" aria-hidden /> : null} |
| 47 | {props.children} | 56 | {props.children} |
| 48 | </div> | 57 | </div> |
| @@ -19,6 +19,8 @@ export function createEnvironmentApi(rpcClient: WsRpcClient): EnvironmentApi { · 18 unmodified lines | |||
| 19 | onMetadata: (callback, options) => rpcClient.terminal.onMetadata(callback, options), | 19 | onMetadata: (callback, options) => rpcClient.terminal.onMetadata(callback, options), |
| 20 | }, | 20 | }, |
| 21 | projects: { | 21 | projects: { |
| 22 | listEntries: rpcClient.projects.listEntries, | ||
| 23 | readFile: rpcClient.projects.readFile, | ||
| 22 | searchEntries: rpcClient.projects.searchEntries, | 24 | searchEntries: rpcClient.projects.searchEntries, |
| 23 | writeFile: rpcClient.projects.writeFile, | 25 | writeFile: rpcClient.projects.writeFile, |
| 24 | }, | 26 | }, |
| @@ -121,6 +121,8 @@ vi.mock("@t3tools/client-runtime", async (importOriginal) => { · 120 unmodified lines | |||
| 121 | subscribePorts: vi.fn(() => () => undefined), | 121 | subscribePorts: vi.fn(() => () => undefined), |
| 122 | }, | 122 | }, |
| 123 | projects: { | 123 | projects: { |
| 124 | listEntries: vi.fn(), | ||
| 125 | readFile: vi.fn(), | ||
| 124 | searchEntries: vi.fn(), | 126 | searchEntries: vi.fn(), |
| 125 | writeFile: vi.fn(), | 127 | writeFile: vi.fn(), |
| 126 | }, | 128 | }, |
| @@ -4,6 +4,30 @@ · 3 unmodified lines | |||
| 4 | /* Window Controls Overlay: active when Electron exposes native titlebar control geometry. */ | 4 | /* Window Controls Overlay: active when Electron exposes native titlebar control geometry. */ |
| 5 | @custom-variant wco (&:is(.wco, .wco *)); | 5 | @custom-variant wco (&:is(.wco, .wco *)); |
| 6 | 6 | ||
| 7 | :root { | ||
| 8 | --workspace-topbar-height: 52px; | ||
| 9 | --workspace-controls-top: 0px; | ||
| 10 | --workspace-controls-right: calc(env(safe-area-inset-right) + 0.75rem); | ||
| 11 | --workspace-native-controls-inset: 0px; | ||
| 12 | } | ||
| 13 | |||
| 14 | @media (width >= 40rem) { | ||
| 15 | :root { | ||
| 16 | --workspace-controls-right: calc(env(safe-area-inset-right) + 1.25rem); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | .wco { | ||
| 21 | --workspace-topbar-height: env(titlebar-area-height, 52px); | ||
| 22 | --workspace-controls-top: env(titlebar-area-y, 0px); | ||
| 23 | --workspace-controls-right: calc( | ||
| 24 | 100vw - env(titlebar-area-width, 100vw) - env(titlebar-area-x, 0px) + 1em | ||
| 25 | ); | ||
| 26 | --workspace-native-controls-inset: calc( | ||
| 27 | 100vw - env(titlebar-area-width, 100vw) - env(titlebar-area-x, 0px) + 1em | ||
| 28 | ); | ||
| 29 | } | ||
| 30 | |||
| 7 | @theme inline { | 31 | @theme inline { |
| 8 | --animate-skeleton: skeleton 2s -1s infinite linear; | 32 | --animate-skeleton: skeleton 2s -1s infinite linear; |
| 9 | --font-sans: | 33 | --font-sans: |
| @@ -71,6 +95,25 @@ · 61 unmodified lines | |||
| 71 | } | 95 | } |
| 72 | } | 96 | } |
| 73 | 97 | ||
| 98 | @layer components { | ||
| 99 | .workspace-topbar { | ||
| 100 | display: flex; | ||
| 101 | height: var(--workspace-topbar-height); | ||
| 102 | min-height: var(--workspace-topbar-height); | ||
| 103 | flex-shrink: 0; | ||
| 104 | align-items: center; | ||
| 105 | } | ||
| 106 | |||
| 107 | .workspace-titlebar-controls { | ||
| 108 | position: absolute; | ||
| 109 | top: var(--workspace-controls-top); | ||
| 110 | right: var(--workspace-controls-right); | ||
| 111 | display: flex; | ||
| 112 | height: var(--workspace-topbar-height); | ||
| 113 | align-items: center; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 74 | /* Safe-area inset utilities for surfaces that opt into edge-to-edge rendering. | 117 | /* Safe-area inset utilities for surfaces that opt into edge-to-edge rendering. |
| 75 | Insets resolve to 0 when the browser already constrains the layout viewport | 118 | Insets resolve to 0 when the browser already constrains the layout viewport |
| 76 | to the safe area. */ | 119 | to the safe area. */ |
| @@ -55,6 +55,8 @@ const rpcClientMock = { · 54 unmodified lines | |||
| 55 | ), | 55 | ), |
| 56 | }, | 56 | }, |
| 57 | projects: { | 57 | projects: { |
| 58 | listEntries: vi.fn(), | ||
| 59 | readFile: vi.fn(), | ||
| 58 | searchEntries: vi.fn(), | 60 | searchEntries: vi.fn(), |
| 59 | writeFile: vi.fn(), | 61 | writeFile: vi.fn(), |
| 60 | }, | 62 | }, |
| @@ -83,6 +83,7 @@ describe("resolveMarkdownFileLinkTarget", () => { · 82 unmodified lines | |||
| 83 | ), | 83 | ), |
| 84 | ).toMatchObject({ | 84 | ).toMatchObject({ |
| 85 | displayPath: "t3code/apps/web/src/session-logic.ts:501", | 85 | displayPath: "t3code/apps/web/src/session-logic.ts:501", |
| 86 | workspaceRelativePath: "apps/web/src/session-logic.ts", | ||
| 86 | }); | 87 | }); |
| 87 | }); | 88 | }); |
| 88 | 89 | ||
| @@ -95,6 +96,14 @@ describe("resolveMarkdownFileLinkTarget", () => { · 6 unmodified lines | |||
| 95 | ).toMatchObject({ | 96 | ).toMatchObject({ |
| 96 | displayPath: | 97 | displayPath: |
| 97 | "t3code/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx", | 98 | "t3code/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx", |
| 99 | workspaceRelativePath: | ||
| 100 | "apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx", | ||
| 101 | }); | ||
| 102 | }); | ||
| 103 | |||
| 104 | it("does not create a preview path for files outside the workspace", () => { | ||
| 105 | expect(resolveMarkdownFileLinkMeta("/tmp/report.ts", "/repo/project")).toMatchObject({ | ||
| 106 | workspaceRelativePath: null, | ||
| 98 | }); | 107 | }); |
| 99 | }); | 108 | }); |
| 100 | 109 | ||
| @@ -26,6 +26,7 @@ export interface MarkdownFileLinkMeta { · 25 unmodified lines | |||
| 26 | filePath: string; | 26 | filePath: string; |
| 27 | targetPath: string; | 27 | targetPath: string; |
| 28 | displayPath: string; | 28 | displayPath: string; |
| 29 | workspaceRelativePath: string | null; | ||
| 29 | basename: string; | 30 | basename: string; |
| 30 | line?: number; | 31 | line?: number; |
| 31 | column?: number; | 32 | column?: number; |
| @@ -174,6 +175,19 @@ function basenameOfPath(path: string): string { · 142 unmodified lines | |||
| 174 | return separatorIndex >= 0 ? path.slice(separatorIndex + 1) : path; | 175 | return separatorIndex >= 0 ? path.slice(separatorIndex + 1) : path; |
| 175 | } | 176 | } |
| 176 | 177 | ||
| 178 | function workspaceRelativePath(path: string, workspaceRoot: string | undefined): string | null { | ||
| 179 | if (!workspaceRoot) return null; | ||
| 180 | const normalizedPath = normalizeWindowsDrivePath(path.replaceAll("\\", "/")); | ||
| 181 | const normalizedRoot = normalizeWindowsDrivePath(workspaceRoot.replaceAll("\\", "/")).replace( | ||
| 182 | /\/+$/, | ||
| 183 | "", | ||
| 184 | ); | ||
| 185 | const pathForCompare = normalizedPath.toLowerCase(); | ||
| 186 | const rootForCompare = normalizedRoot.toLowerCase(); | ||
| 187 | if (!pathForCompare.startsWith(`${rootForCompare}/`)) return null; | ||
| 188 | return normalizedPath.slice(normalizedRoot.length + 1); | ||
| 189 | } | ||
| 190 | |||
| 177 | export function resolveMarkdownFileLinkMeta( | 191 | export function resolveMarkdownFileLinkMeta( |
| 178 | href: string | undefined, | 192 | href: string | undefined, |
| 179 | cwd?: string, | 193 | cwd?: string, |
| @@ -191,6 +205,7 @@ export function resolveMarkdownFileLinkMeta( · 11 unmodified lines | |||
| 191 | filePath: path, | 205 | filePath: path, |
| 192 | targetPath, | 206 | targetPath, |
| 193 | displayPath: formatWorkspaceRelativePath(targetPath, cwd), | 207 | displayPath: formatWorkspaceRelativePath(targetPath, cwd), |
| 208 | workspaceRelativePath: workspaceRelativePath(path, cwd), | ||
| 194 | basename: basenameOfPath(path), | 209 | basename: basenameOfPath(path), |
| 195 | ...(lineNumber !== undefined ? { line: lineNumber } : {}), | 210 | ...(lineNumber !== undefined ? { line: lineNumber } : {}), |
| 196 | ...(columnNumber !== undefined ? { column: columnNumber } : {}), | 211 | ...(columnNumber !== undefined ? { column: columnNumber } : {}), |
| @@ -0,0 +1,57 @@ | |||
| 1 | import { assert, describe, it } from "vite-plus/test"; | ||
| 2 | |||
| 3 | import { | ||
| 4 | hasSpecificPierreIconForFileName, | ||
| 5 | resolvePierreIconForEntry, | ||
| 6 | syntheticFileNameForLanguageId, | ||
| 7 | T3_PIERRE_ICONS, | ||
| 8 | } from "./pierre-icons"; | ||
| 9 | |||
| 10 | describe("Pierre file icons", () => { | ||
| 11 | it("uses Pierre exact filename and complete-set extension mappings", () => { | ||
| 12 | assert.equal(resolvePierreIconForEntry("Dockerfile", "file")?.token, "docker"); | ||
| 13 | assert.equal(resolvePierreIconForEntry("src/Button.tsx", "file")?.token, "react"); | ||
| 14 | assert.equal(resolvePierreIconForEntry("vite.config.ts", "file")?.token, "vite"); | ||
| 15 | }); | ||
| 16 | |||
| 17 | it("extends Pierre with T3-specific exact filename icons", () => { | ||
| 18 | assert.equal( | ||
| 19 | resolvePierreIconForEntry("package.json", "file")?.name, | ||
| 20 | "t3-file-icon-package-json", | ||
| 21 | ); | ||
| 22 | assert.equal( | ||
| 23 | resolvePierreIconForEntry("config/tsconfig.json", "file")?.name, | ||
| 24 | "t3-file-icon-tsconfig", | ||
| 25 | ); | ||
| 26 | assert.equal(resolvePierreIconForEntry("AGENTS.md", "file")?.name, "t3-file-icon-agents"); | ||
| 27 | assert.equal(resolvePierreIconForEntry("CLAUDE.md", "file")?.name, "t3-file-icon-claude"); | ||
| 28 | assert.equal(resolvePierreIconForEntry("README.md", "file")?.name, "t3-file-icon-readme"); | ||
| 29 | assert.equal(resolvePierreIconForEntry("pnpm-lock.yaml", "file")?.name, "t3-file-icon-pnpm"); | ||
| 30 | assert.equal( | ||
| 31 | resolvePierreIconForEntry("pnpm-workspace.yaml", "file")?.name, | ||
| 32 | "t3-file-icon-pnpm", | ||
| 33 | ); | ||
| 34 | }); | ||
| 35 | |||
| 36 | it("ships every custom icon referenced by the extended resolver", () => { | ||
| 37 | const customIconNames = new Set(Object.values(T3_PIERRE_ICONS.byFileName)); | ||
| 38 | for (const iconName of customIconNames) { | ||
| 39 | assert.include(T3_PIERRE_ICONS.spriteSheet, `id="${iconName}"`); | ||
| 40 | } | ||
| 41 | }); | ||
| 42 | |||
| 43 | it("uses the Pierre default icon for unknown file types", () => { | ||
| 44 | assert.equal(resolvePierreIconForEntry("artifact.unknown-ext", "file")?.token, "default"); | ||
| 45 | assert.isFalse(hasSpecificPierreIconForFileName("artifact.unknown-ext")); | ||
| 46 | }); | ||
| 47 | |||
| 48 | it("leaves directory rendering to the shared folder fallback", () => { | ||
| 49 | assert.isNull(resolvePierreIconForEntry("packages/client-runtime", "directory")); | ||
| 50 | }); | ||
| 51 | |||
| 52 | it("normalizes common markdown fence language aliases", () => { | ||
| 53 | assert.equal(syntheticFileNameForLanguageId("typescript"), "file.ts"); | ||
| 54 | assert.equal(syntheticFileNameForLanguageId("shellscript"), "file.sh"); | ||
| 55 | assert.equal(syntheticFileNameForLanguageId("python"), "file.py"); | ||
| 56 | }); | ||
| 57 | }); | ||
| @@ -0,0 +1,117 @@ | |||
| 1 | import { | ||
| 2 | createFileTreeIconResolver, | ||
| 3 | getBuiltInSpriteSheet, | ||
| 4 | type FileTreeIcons, | ||
| 5 | } from "@pierre/trees"; | ||
| 6 | |||
| 7 | export interface PierreIconResolution { | ||
| 8 | name: string; | ||
| 9 | token?: string; | ||
| 10 | } | ||
| 11 | |||
| 12 | const PIERRE_ICON_SPRITE_ID = "t3code-pierre-file-icon-sprite"; | ||
| 13 | |||
| 14 | const T3_FILE_ICON_SPRITE = ` | ||
| 15 | <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" aria-hidden="true"> | ||
| 16 | <symbol id="t3-file-icon-package-json" viewBox="0 0 32 32"> | ||
| 17 | <path d="M2 2H30V30H2" fill="#c12127" /> | ||
| 18 | <path d="M7.25 7.25h17.5v17.5h-3.5v-14H16v14H7.25" fill="#fff" /> | ||
| 19 | </symbol> | ||
| 20 | <symbol id="t3-file-icon-tsconfig" viewBox="0 0 32 32"> | ||
| 21 | <path d="M23.827 8.243a4.424 4.424 0 0 1 2.223 1.281 5.853 5.853 0 0 1 .852 1.143c.011.045-1.534 1.083-2.471 1.662-.034.023-.169-.124-.322-.35a2.014 2.014 0 0 0-1.67-1c-1.077-.074-1.771.49-1.766 1.433a1.3 1.3 0 0 0 .153.666c.237.49.677.784 2.059 1.383 2.544 1.1 3.636 1.817 4.31 2.843a5.158 5.158 0 0 1 .416 4.333 4.764 4.764 0 0 1-3.932 2.815 10.9 10.9 0 0 1-2.708-.028 6.531 6.531 0 0 1-3.616-1.884 6.278 6.278 0 0 1-.926-1.371 2.655 2.655 0 0 1 .327-.208c.158-.09.756-.434 1.32-.761l1.024-.6.214.312a4.771 4.771 0 0 0 1.35 1.292 3.3 3.3 0 0 0 3.458-.175 1.545 1.545 0 0 0 .2-1.974c-.276-.4-.84-.727-2.443-1.422a8.8 8.8 0 0 1-3.349-2.055 4.687 4.687 0 0 1-.976-1.777 7.116 7.116 0 0 1-.062-2.268 4.332 4.332 0 0 1 3.644-3.374 9 9 0 0 1 2.71.01ZM15.484 9.726l.011 1.454h-4.63v13.148H7.6V11.183H2.97V9.755a13.986 13.986 0 0 1 .04-1.466c.017-.023 2.832-.034 6.245-.028l6.211.017Z" fill="#007acc" /> | ||
| 22 | <path d="m27.075 25.107.363-.361c1.68.055 1.706 0 1.78-.177l.462-1.124.034-.107-.038-.093c-.02-.049-.081-.2-1.13-1.2v-.526c1.211-1.166 1.185-1.226 1.116-1.4l-.46-1.136c-.069-.17-.1-.237-1.763-.191l-.364-.367a8.138 8.138 0 0 0-.057-1.657l-.047-.106-1.2-.525c-.177-.081-.239-.11-1.372 1.124l-.509-.008c-1.167-1.245-1.222-1.223-1.4-1.152l-1.115.452c-.175.071-.236.1-.169 1.79l-.36.359c-1.68-.055-1.7 0-1.778.177L18.606 20l-.036.108.038.094c.02.048.078.194 1.13 1.2v.525c-1.211 1.166-1.184 1.226-1.115 1.4l.459 1.137c.07.174.1.236 1.763.192l.363.377a8.169 8.169 0 0 0 .055 1.654l.047.107 1.208.528c.176.073.236.1 1.366-1.13l.509.006c1.168 1.247 1.228 1.223 1.4 1.154l1.113-.45c.176-.075.237-.102.169-1.795Zm-4.788-2.632a2 2 0 1 1 2.618 1.14 2.023 2.023 0 0 1-2.618-1.14Z" fill="#99b8c4" /> | ||
| 23 | </symbol> | ||
| 24 | <symbol id="t3-file-icon-agents" viewBox="0 0 32 32"> | ||
| 25 | <path fill="currentColor" d="M27.2 16c0-6.19-5.01-11.2-11.2-11.2C9.81 4.8 4.8 9.81 4.8 16S9.81 27.2 16 27.2c6.19 0 11.2-5.01 11.2-11.2Zm-5.6 2.1a1.4 1.4 0 1 1 0 2.8h-4.2a1.4 1.4 0 1 1 0-2.8Zm-11.2-6.8c.622-.373 1.42-.208 1.84.361l.079.119 2.1 3.5.088.171c.15.351.15.748 0 1.1l-.088.171-2.1 3.5a1.4 1.4 0 0 1-2.4-1.44L11.59 16l-1.67-2.78-.067-.127c-.302-.642-.075-1.42.547-1.79ZM30 16c0 7.73-6.27 14-14 14S2 23.73 2 16 8.27 2 16 2s14 6.27 14 14Z" /> | ||
| 26 | </symbol> | ||
| 27 | <symbol id="t3-file-icon-claude" viewBox="0 0 32 32"> | ||
| 28 | <path fill="#d97757" d="m7.5 20.61 5.5-3.08.1-.27-.1-.15h-.27l-.92-.06a234.2 234.2 0 0 1-8.51-.34l-.67-.14-.62-.82.06-.41.56-.38.8.07c3.08.2 6.15.4 9.21.72h.46l.06-.19-.16-.1-.12-.12-2.74-1.86c-2.04-1.3-3.55-2.43-5.38-3.68l-.43-.54-.18-1.18.76-.84 1.03.07.26.07c2.03 1.6 4.1 3.14 6.17 4.66l.43.36.17-.12.02-.09-.2-.32c-1.43-2.6-2.55-4.62-4-6.96l-.2-.72c-.08-.3-.13-.55-.13-.85l.87-1.18.49-.16 1.16.16.49.42c1.4 3.31 2.76 5.93 4.23 8.83l.29.97.1.3h.19v-.17c.65-3.42 0-6.57 1.22-9.53l.87-.57.68.33.56.8-.08.51c-.37 2.62-.92 5.22-1.4 7.82h.24l.29-.29a68.66 68.66 0 0 1 4.91-5.94l.64-.5h1.2l.89 1.32-.4 1.36a53.45 53.45 0 0 0-4.66 6.47l.09.13.22-.02c2.4-.57 4.84-.99 7.27-1.4l.97.45.1.46-.37.94c-3 .72-6 1.34-9 2.05l-.05.04.06.07c2.7.26 5.62.3 7.99.47l.92.61.55.75-.1.56-1.4.73c-2.93-.7-5.19-1.22-7.91-1.9h-.22v.13c2.18 2.12 4.6 4.27 6.54 6.07l.15.68-.38.53-.4-.06c-2.04-1.43-3.9-3.09-5.8-4.7h-.15v.2l.52.76c1.14 1.79 2.64 3.25 2.87 5.37l-.2.41-.7.25-.78-.14a73.16 73.16 0 0 1-4.58-7.04l-.17.09-.78 8.46-.37.43-.85.33-.71-.54-.38-.87a114 114 0 0 0 1.53-7.97l.2-.73-.01-.05-.16.02a76.67 76.67 0 0 1-6.23 7.88l-.48.2-.84-.44.08-.77.47-.69c2.07-2.57 3.54-4.66 5.54-7v-.19h-.07l-7.4 4.8-1.31.17-.57-.53.07-.87.27-.28 2.23-1.53Z" /> | ||
| 29 | </symbol> | ||
| 30 | <symbol id="t3-file-icon-readme" viewBox="0 0 32 32"> | ||
| 31 | <rect x="2.5" y="7.955" width="27" height="16.091" fill="none" stroke="#b48a5a" /> | ||
| 32 | <path fill="#b48a5a" d="M5.909 20.636v-9.272h2.727l2.728 3.409 2.727-3.409h2.727v9.272h-2.727v-5.318l-2.727 3.409-2.728-3.409v5.318H5.91Zm17.046 0-4.091-4.5h2.727v-4.772h2.727v4.772h2.727l-4.09 4.5Z" /> | ||
| 33 | </symbol> | ||
| 34 | <symbol id="t3-file-icon-pnpm" viewBox="0 0 32 32"> | ||
| 35 | <path fill="#f9ad00" d="M30 10.75h-8.749V2H30Zm-9.626 0h-8.75V2h8.75Zm-9.625 0H2V2h8.749ZM30 20.375h-8.749v-8.75H30Z" /> | ||
| 36 | <path fill="currentColor" d="M20.374 20.375h-8.75v-8.75h8.75Zm0 9.625h-8.75v-8.75h8.75ZM30 30h-8.749v-8.75H30Zm-19.251 0H2v-8.75h8.749Z" /> | ||
| 37 | </symbol> | ||
| 38 | </svg>`; | ||
| 39 | |||
| 40 | export const T3_PIERRE_ICONS = { | ||
| 41 | set: "complete", | ||
| 42 | colored: true, | ||
| 43 | spriteSheet: T3_FILE_ICON_SPRITE, | ||
| 44 | byFileName: { | ||
| 45 | "package.json": "t3-file-icon-package-json", | ||
| 46 | "tsconfig.json": "t3-file-icon-tsconfig", | ||
| 47 | "agents.md": "t3-file-icon-agents", | ||
| 48 | "claude.md": "t3-file-icon-claude", | ||
| 49 | "readme.md": "t3-file-icon-readme", | ||
| 50 | "pnpm-lock.yaml": "t3-file-icon-pnpm", | ||
| 51 | "pnpm-workspace.yaml": "t3-file-icon-pnpm", | ||
| 52 | }, | ||
| 53 | } satisfies FileTreeIcons; | ||
| 54 | |||
| 55 | const completeIconResolver = createFileTreeIconResolver(T3_PIERRE_ICONS); | ||
| 56 | |||
| 57 | const LANGUAGE_EXTENSION_ALIASES: Record<string, string> = { | ||
| 58 | bash: "sh", | ||
| 59 | csharp: "cs", | ||
| 60 | dockerfile: "dockerfile", | ||
| 61 | javascript: "js", | ||
| 62 | jsx: "jsx", | ||
| 63 | markdown: "md", | ||
| 64 | mdx: "mdx", | ||
| 65 | plaintext: "txt", | ||
| 66 | python: "py", | ||
| 67 | ruby: "rb", | ||
| 68 | rust: "rs", | ||
| 69 | shell: "sh", | ||
| 70 | shellscript: "sh", | ||
| 71 | swift: "swift", | ||
| 72 | typescript: "ts", | ||
| 73 | tsx: "tsx", | ||
| 74 | yaml: "yml", | ||
| 75 | }; | ||
| 76 | |||
| 77 | export function basenameOfPath(pathValue: string): string { | ||
| 78 | const slashIndex = pathValue.lastIndexOf("/"); | ||
| 79 | return slashIndex === -1 ? pathValue : pathValue.slice(slashIndex + 1); | ||
| 80 | } | ||
| 81 | |||
| 82 | export function inferEntryKindFromPath(pathValue: string): "file" | "directory" { | ||
| 83 | const base = basenameOfPath(pathValue); | ||
| 84 | if (base.startsWith(".") && !base.slice(1).includes(".")) return "directory"; | ||
| 85 | return base.includes(".") ? "file" : "directory"; | ||
| 86 | } | ||
| 87 | |||
| 88 | export function syntheticFileNameForLanguageId(languageId: string): string { | ||
| 89 | const normalized = languageId.toLowerCase(); | ||
| 90 | return `file.${LANGUAGE_EXTENSION_ALIASES[normalized] ?? normalized}`; | ||
| 91 | } | ||
| 92 | |||
| 93 | export function resolvePierreIconForEntry( | ||
| 94 | pathValue: string, | ||
| 95 | kind: "file" | "directory", | ||
| 96 | ): PierreIconResolution | null { | ||
| 97 | if (kind === "directory") return null; | ||
| 98 | return completeIconResolver.resolveIcon("file-tree-icon-file", pathValue); | ||
| 99 | } | ||
| 100 | |||
| 101 | export function hasSpecificPierreIconForFileName(fileName: string): boolean { | ||
| 102 | return resolvePierreIconForEntry(fileName, "file")?.token !== "default"; | ||
| 103 | } | ||
| 104 | |||
| 105 | export function ensurePierreIconSprite(): void { | ||
| 106 | if (typeof document === "undefined" || document.getElementById(PIERRE_ICON_SPRITE_ID)) return; | ||
| 107 | const container = document.createElement("div"); | ||
| 108 | container.id = PIERRE_ICON_SPRITE_ID; | ||
| 109 | container.setAttribute("aria-hidden", "true"); | ||
| 110 | container.style.position = "absolute"; | ||
| 111 | container.style.width = "0"; | ||
| 112 | container.style.height = "0"; | ||
| 113 | container.style.overflow = "hidden"; | ||
| 114 | container.style.pointerEvents = "none"; | ||
| 115 | container.innerHTML = `${getBuiltInSpriteSheet("complete")}${T3_FILE_ICON_SPRITE}`; | ||
| 116 | document.body.prepend(container); | ||
| 117 | } | ||
| @@ -88,6 +88,54 @@ describe("rightPanelStore", () => { · 87 unmodified lines | |||
| 88 | ).toHaveLength(2); | 88 | ).toHaveLength(2); |
| 89 | }); | 89 | }); |
| 90 | 90 | ||
| 91 | it("keeps files as a singleton surface", () => { | ||
| 92 | useRightPanelStore.getState().open(refA, "files"); | ||
| 93 | useRightPanelStore.getState().open(refA, "files"); | ||
| 94 | expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ | ||
| 95 | isOpen: true, | ||
| 96 | activeSurfaceId: "files", | ||
| 97 | surfaces: [{ id: "files", kind: "files" }], | ||
| 98 | }); | ||
| 99 | }); | ||
| 100 | |||
| 101 | it("replaces the standalone explorer with peer file surfaces", () => { | ||
| 102 | useRightPanelStore.getState().open(refA, "files"); | ||
| 103 | useRightPanelStore.getState().openFile(refA, "src/index.ts"); | ||
| 104 | useRightPanelStore.getState().openFile(refA, "src/index.ts"); | ||
| 105 | useRightPanelStore.getState().openFile(refA, "README.md"); | ||
| 106 | |||
| 107 | expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ | ||
| 108 | isOpen: true, | ||
| 109 | activeSurfaceId: "file:README.md", | ||
| 110 | surfaces: [ | ||
| 111 | { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts" }, | ||
| 112 | { id: "file:README.md", kind: "file", relativePath: "README.md" }, | ||
| 113 | ], | ||
| 114 | }); | ||
| 115 | }); | ||
| 116 | |||
| 117 | it("removes persisted file surfaces when their workspace no longer exists", () => { | ||
| 118 | useRightPanelStore.getState().openFile(refA, "src/index.ts"); | ||
| 119 | useRightPanelStore.getState().open(refA, "plan"); | ||
| 120 | useRightPanelStore.getState().openFile(refA, "README.md"); | ||
| 121 | |||
| 122 | useRightPanelStore.getState().reconcileFileSurfaces(refA, false); | ||
| 123 | |||
| 124 | expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ | ||
| 125 | isOpen: true, | ||
| 126 | activeSurfaceId: "plan", | ||
| 127 | surfaces: [{ id: "plan", kind: "plan" }], | ||
| 128 | }); | ||
| 129 | |||
| 130 | useRightPanelStore.getState().openFile(refB, "conductor.json"); | ||
| 131 | useRightPanelStore.getState().reconcileFileSurfaces(refB, false); | ||
| 132 | expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refB)).toEqual({ | ||
| 133 | isOpen: false, | ||
| 134 | activeSurfaceId: null, | ||
| 135 | surfaces: [], | ||
| 136 | }); | ||
| 137 | }); | ||
| 138 | |||
| 91 | it("close hides the panel without clearing its selected surface", () => { | 139 | it("close hides the panel without clearing its selected surface", () => { |
| 92 | useRightPanelStore.getState().open(refA, "plan"); | 140 | useRightPanelStore.getState().open(refA, "plan"); |
| 93 | useRightPanelStore.getState().close(refA); | 141 | useRightPanelStore.getState().close(refA); |
| @@ -4,8 +4,8 @@ · 3 unmodified lines | |||
| 4 | * This is intentionally a shallow workspace model: it owns an ordered set of | 4 | * This is intentionally a shallow workspace model: it owns an ordered set of |
| 5 | * surface descriptors and the active surface, while each feature continues to | 5 | * surface descriptors and the active surface, while each feature continues to |
| 6 | * own its durable resource state. Browser surfaces point at preview tab ids, | 6 | * own its durable resource state. Browser surfaces point at preview tab ids, |
| 7 | * terminal surfaces point at terminal session ids, and diff/plan remain | 7 | * terminal surfaces point at terminal session ids, file surfaces point at |
| 8 | * singleton surfaces. | 8 | * workspace paths, and diff/plan/files remain singleton surfaces. |
| 9 | */ | 9 | */ |
| 10 | import { scopedThreadKey } from "@t3tools/client-runtime"; | 10 | import { scopedThreadKey } from "@t3tools/client-runtime"; |
| 11 | import type { ScopedThreadRef } from "@t3tools/contracts"; | 11 | import type { ScopedThreadRef } from "@t3tools/contracts"; |
| @@ -14,7 +14,7 @@ import { createJSONStorage, persist } from "zustand/middleware"; · 2 unmodified lines | |||
| 14 | 14 | ||
| 15 | import { resolveStorage } from "./lib/storage"; | 15 | import { resolveStorage } from "./lib/storage"; |
| 16 | 16 | ||
| 17 | export const RIGHT_PANEL_KINDS = ["plan", "diff", "preview", "terminal"] as const; | 17 | export const RIGHT_PANEL_KINDS = ["plan", "diff", "files", "file", "preview", "terminal"] as const; |
| 18 | export type RightPanelKind = (typeof RIGHT_PANEL_KINDS)[number]; | 18 | export type RightPanelKind = (typeof RIGHT_PANEL_KINDS)[number]; |
| 19 | 19 | ||
| 20 | export type RightPanelSurface = | 20 | export type RightPanelSurface = |
| @@ -29,10 +29,12 @@ export type RightPanelSurface = · 8 unmodified lines | |||
| 29 | splitDirection?: "horizontal" | "vertical"; | 29 | splitDirection?: "horizontal" | "vertical"; |
| 30 | } | 30 | } |
| 31 | | { id: "diff"; kind: "diff" } | 31 | | { id: "diff"; kind: "diff" } |
| 32 | | { id: "files"; kind: "files" } | ||
| 33 | | { id: `file:${string}`; kind: "file"; relativePath: string } | ||
| 32 | | { id: "plan"; kind: "plan" }; | 34 | | { id: "plan"; kind: "plan" }; |
| 33 | 35 | ||
| 34 | const RIGHT_PANEL_STORAGE_KEY = "t3code:right-panel-state:v2"; | 36 | const RIGHT_PANEL_STORAGE_KEY = "t3code:right-panel-state:v2"; |
| 35 | const RIGHT_PANEL_STORAGE_VERSION = 5; | 37 | const RIGHT_PANEL_STORAGE_VERSION = 6; |
| 36 | 38 | ||
| 37 | export interface ThreadRightPanelState { | 39 | export interface ThreadRightPanelState { |
| 38 | isOpen: boolean; | 40 | isOpen: boolean; |
| @@ -42,8 +44,9 @@ export interface ThreadRightPanelState { · 3 unmodified lines | |||
| 42 | 44 | ||
| 43 | interface RightPanelStoreState { | 45 | interface RightPanelStoreState { |
| 44 | byThreadKey: Record<string, ThreadRightPanelState>; | 46 | byThreadKey: Record<string, ThreadRightPanelState>; |
| 45 | open: (ref: ScopedThreadRef, kind: Exclude<RightPanelKind, "terminal">) => void; | 47 | open: (ref: ScopedThreadRef, kind: Exclude<RightPanelKind, "file" | "terminal">) => void; |
| 46 | openBrowser: (ref: ScopedThreadRef, tabId: string | null) => void; | 48 | openBrowser: (ref: ScopedThreadRef, tabId: string | null) => void; |
| 49 | openFile: (ref: ScopedThreadRef, relativePath: string) => void; | ||
| 47 | openTerminal: (ref: ScopedThreadRef, terminalId: string) => void; | 50 | openTerminal: (ref: ScopedThreadRef, terminalId: string) => void; |
| 48 | splitTerminal: ( | 51 | splitTerminal: ( |
| 49 | ref: ScopedThreadRef, | 52 | ref: ScopedThreadRef, |
| @@ -56,10 +59,11 @@ interface RightPanelStoreState { · 6 unmodified lines | |||
| 56 | activateSurface: (ref: ScopedThreadRef, surfaceId: string) => void; | 59 | activateSurface: (ref: ScopedThreadRef, surfaceId: string) => void; |
| 57 | closeSurface: (ref: ScopedThreadRef, surfaceId: string) => void; | 60 | closeSurface: (ref: ScopedThreadRef, surfaceId: string) => void; |
| 58 | reconcileBrowserSurfaces: (ref: ScopedThreadRef, tabIds: readonly string[]) => void; | 61 | reconcileBrowserSurfaces: (ref: ScopedThreadRef, tabIds: readonly string[]) => void; |
| 62 | reconcileFileSurfaces: (ref: ScopedThreadRef, workspaceAvailable: boolean) => void; | ||
| 59 | show: (ref: ScopedThreadRef) => void; | 63 | show: (ref: ScopedThreadRef) => void; |
| 60 | close: (ref: ScopedThreadRef) => void; | 64 | close: (ref: ScopedThreadRef) => void; |
| 61 | toggleVisibility: (ref: ScopedThreadRef) => void; | 65 | toggleVisibility: (ref: ScopedThreadRef) => void; |
| 62 | toggle: (ref: ScopedThreadRef, kind: Exclude<RightPanelKind, "terminal">) => void; | 66 | toggle: (ref: ScopedThreadRef, kind: Exclude<RightPanelKind, "file" | "terminal">) => void; |
| 63 | removeThread: (ref: ScopedThreadRef) => void; | 67 | removeThread: (ref: ScopedThreadRef) => void; |
| 64 | } | 68 | } |
| 65 | 69 | ||
| @@ -70,11 +74,13 @@ const EMPTY_THREAD_STATE: ThreadRightPanelState = { · 4 unmodified lines | |||
| 70 | }; | 74 | }; |
| 71 | 75 | ||
| 72 | const singletonSurface = ( | 76 | const singletonSurface = ( |
| 73 | kind: Exclude<RightPanelKind, "preview" | "terminal">, | 77 | kind: Exclude<RightPanelKind, "file" | "preview" | "terminal">, |
| 74 | ): RightPanelSurface => { | 78 | ): RightPanelSurface => { |
| 75 | switch (kind) { | 79 | switch (kind) { |
| 76 | case "diff": | 80 | case "diff": |
| 77 | return { id: "diff", kind }; | 81 | return { id: "diff", kind }; |
| 82 | case "files": | ||
| 83 | return { id: "files", kind }; | ||
| 78 | case "plan": | 84 | case "plan": |
| 79 | return { id: "plan", kind }; | 85 | return { id: "plan", kind }; |
| 80 | } | 86 | } |
| @@ -85,6 +91,12 @@ const browserSurface = (tabId: string | null): RightPanelSurface => · 4 unmodified lines | |||
| 85 | ? { id: `browser:${tabId}`, kind: "preview", resourceId: tabId } | 91 | ? { id: `browser:${tabId}`, kind: "preview", resourceId: tabId } |
| 86 | : { id: "browser:new", kind: "preview", resourceId: null }; | 92 | : { id: "browser:new", kind: "preview", resourceId: null }; |
| 87 | 93 | ||
| 94 | const fileSurface = (relativePath: string): RightPanelSurface => ({ | ||
| 95 | id: `file:${relativePath}`, | ||
| 96 | kind: "file", | ||
| 97 | relativePath, | ||
| 98 | }); | ||
| 99 | |||
| 88 | const terminalSurface = (terminalId: string): RightPanelSurface => ({ | 100 | const terminalSurface = (terminalId: string): RightPanelSurface => ({ |
| 89 | id: `terminal:${terminalId}`, | 101 | id: `terminal:${terminalId}`, |
| 90 | kind: "terminal", | 102 | kind: "terminal", |
| @@ -213,6 +225,18 @@ export const useRightPanelStore = create<RightPanelStoreState>()( · 122 unmodified lines | |||
| 213 | return upsertSurface({ ...current, surfaces: withoutPlaceholder }, surface); | 225 | return upsertSurface({ ...current, surfaces: withoutPlaceholder }, surface); |
| 214 | }), | 226 | }), |
| 215 | })), | 227 | })), |
| 228 | openFile: (ref, relativePath) => | ||
| 229 | set((state) => ({ | ||
| 230 | byThreadKey: updateThread(state.byThreadKey, scopedThreadKey(ref), (current) => { | ||
| 231 | const withoutStandaloneExplorer = current.surfaces.filter( | ||
| 232 | (surface) => surface.kind !== "files", | ||
| 233 | ); | ||
| 234 | return upsertSurface( | ||
| 235 | { ...current, surfaces: withoutStandaloneExplorer }, | ||
| 236 | fileSurface(relativePath), | ||
| 237 | ); | ||
| 238 | }), | ||
| 239 | })), | ||
| 216 | openTerminal: (ref, terminalId) => | 240 | openTerminal: (ref, terminalId) => |
| 217 | set((state) => ({ | 241 | set((state) => ({ |
| 218 | byThreadKey: updateThread(state.byThreadKey, scopedThreadKey(ref), (current) => | 242 | byThreadKey: updateThread(state.byThreadKey, scopedThreadKey(ref), (current) => |
| @@ -339,6 +363,27 @@ export const useRightPanelStore = create<RightPanelStoreState>()( · 120 unmodified lines | |||
| 339 | }; | 363 | }; |
| 340 | }), | 364 | }), |
| 341 | })), | 365 | })), |
| 366 | reconcileFileSurfaces: (ref, workspaceAvailable) => | ||
| 367 | set((state) => ({ | ||
| 368 | byThreadKey: updateThread(state.byThreadKey, scopedThreadKey(ref), (current) => { | ||
| 369 | if (workspaceAvailable) return current; | ||
| 370 | const surfaces = current.surfaces.filter( | ||
| 371 | (surface) => surface.kind !== "files" && surface.kind !== "file", | ||
| 372 | ); | ||
| 373 | if (surfaces.length === current.surfaces.length) return current; | ||
| 374 | const activeStillExists = surfaces.some( | ||
| 375 | (surface) => surface.id === current.activeSurfaceId, | ||
| 376 | ); | ||
| 377 | return { | ||
| 378 | ...current, | ||
| 379 | isOpen: surfaces.length > 0 ? current.isOpen : false, | ||
| 380 | surfaces, | ||
| 381 | activeSurfaceId: activeStillExists | ||
| 382 | ? current.activeSurfaceId | ||
| 383 | : (surfaces.at(-1)?.id ?? null), | ||
| 384 | }; | ||
| 385 | }), | ||
| 386 | })), | ||
| 342 | show: (ref) => | 387 | show: (ref) => |
| 343 | set((state) => ({ | 388 | set((state) => ({ |
| 344 | byThreadKey: updateThread(state.byThreadKey, scopedThreadKey(ref), (current) => | 389 | byThreadKey: updateThread(state.byThreadKey, scopedThreadKey(ref), (current) => |
| @@ -1,481 +0,0 @@ | |||
| 1 | { | ||
| 2 | "version": "12.17.0", | ||
| 3 | "source": "https://raw.githubusercontent.com/vscode-icons/vscode-icons/v12.17.0/src/iconsManifest/languages.ts", | ||
| 4 | "generatedAt": "2026-02-17T20:03:11.362Z", | ||
| 5 | "extensionToLanguageId": { | ||
| 6 | "as": "actionscript", | ||
| 7 | "ada": "ada", | ||
| 8 | "prw": "advpl", | ||
| 9 | "affect": "affectscript", | ||
| 10 | "agda": "agda", | ||
| 11 | "al": "al", | ||
| 12 | "alloy": "alloy", | ||
| 13 | "ansible": "ansible", | ||
| 14 | "g4": "antlr", | ||
| 15 | "any": "anyscript", | ||
| 16 | "htaccess": "apacheconf", | ||
| 17 | "cls": "apex", | ||
| 18 | "apib": "apiblueprint", | ||
| 19 | "apl": "apl", | ||
| 20 | "applescript": "applescript", | ||
| 21 | "adoc": "asciidoc", | ||
| 22 | "asp": "asp", | ||
| 23 | "asm": "arm", | ||
| 24 | "astro": "astro", | ||
| 25 | "ats": "ats", | ||
| 26 | "ahk": "ahk", | ||
| 27 | "au3": "autoit", | ||
| 28 | "am": "automake", | ||
| 29 | "avcs": "avro", | ||
| 30 | "azcli": "azcli", | ||
| 31 | "azure-pipelines.yml": "azure-pipelines", | ||
| 32 | "bal": "ballerina", | ||
| 33 | "bat": "bat", | ||
| 34 | "bats": "bats", | ||
| 35 | "bzl": "bazel", | ||
| 36 | "bf": "befunge", | ||
| 37 | "bicep": "bicep", | ||
| 38 | "bib": "bibtex", | ||
| 39 | "biml": "biml", | ||
| 40 | "bin": "code-text-binary", | ||
| 41 | "rast": "biome_syntax_tree", | ||
| 42 | "blade.php": "blade", | ||
| 43 | "blitzbasic": "blitzbasic", | ||
| 44 | "bolt": "bolt", | ||
| 45 | "bsq": "bosque", | ||
| 46 | "bru": "bruno", | ||
| 47 | "buf.yaml": "buf", | ||
| 48 | "lockb": "bun.lockb", | ||
| 49 | "c": "c", | ||
| 50 | "c3": "c3", | ||
| 51 | "cal": "c-al", | ||
| 52 | "cabal": "cabal", | ||
| 53 | "capnp": "capnp", | ||
| 54 | "casc": "casc", | ||
| 55 | "cddl": "cddl", | ||
| 56 | "ceylon": "ceylon", | ||
| 57 | "cfc": "cfc", | ||
| 58 | "cfm": "cfmhtml", | ||
| 59 | "circom": "circom", | ||
| 60 | "clojure": "clojure", | ||
| 61 | "clojurescript": "clojurescript", | ||
| 62 | "yml": "manifest-yaml", | ||
| 63 | "cmake": "cmake", | ||
| 64 | "cbl": "cobol", | ||
| 65 | "ql": "ql", | ||
| 66 | "coffee": "coffeescript", | ||
| 67 | "cfml": "cfml", | ||
| 68 | "confluence": "confluence", | ||
| 69 | "ckbk": "cookbook", | ||
| 70 | "instructions.md": "instructions", | ||
| 71 | "cpp": "cpp", | ||
| 72 | "cr": "crystal", | ||
| 73 | "cs": "csharp", | ||
| 74 | "css": "css", | ||
| 75 | "wxss": "css", | ||
| 76 | "acss": "css", | ||
| 77 | "mcss": "css", | ||
| 78 | "pcss": "css", | ||
| 79 | "postcss": "css", | ||
| 80 | "nss": "css", | ||
| 81 | "ccss": "css", | ||
| 82 | "less": "css", | ||
| 83 | "scss": "css", | ||
| 84 | "sass": "css", | ||
| 85 | "csv": "csv", | ||
| 86 | "feature": "cucumber", | ||
| 87 | "cu": "cuda", | ||
| 88 | "cypher": "cypher", | ||
| 89 | "pyx": "cython", | ||
| 90 | "dal": "dal", | ||
| 91 | "dart": "dart", | ||
| 92 | "dhall": "dhall", | ||
| 93 | "html": "django-html", | ||
| 94 | "diff": "diff", | ||
| 95 | "d": "d", | ||
| 96 | "hcl": "dockerbake", | ||
| 97 | "dtx": "doctex", | ||
| 98 | "env": "dotenv", | ||
| 99 | "dot": "dotjs", | ||
| 100 | "dox": "doxygen", | ||
| 101 | "drawio": "drawio", | ||
| 102 | "drl": "drools", | ||
| 103 | "dtd": "dtd", | ||
| 104 | "dust": "dustjs", | ||
| 105 | "dylan": "dylan", | ||
| 106 | "earthfile": "earthfile", | ||
| 107 | "edge": "edge", | ||
| 108 | "eex": "eex", | ||
| 109 | "es": "es", | ||
| 110 | "ex": "elixir", | ||
| 111 | "elm": "elm", | ||
| 112 | "erb": "erb", | ||
| 113 | "erl": "erlang", | ||
| 114 | "yaml": "esphome", | ||
| 115 | "xlsx": "excel", | ||
| 116 | "falcon": "falcon", | ||
| 117 | "fql": "fql", | ||
| 118 | "f": "fortran", | ||
| 119 | "ftl": "ftl", | ||
| 120 | "fs": "fsharp", | ||
| 121 | "fthtml": "fthtml", | ||
| 122 | "gspec": "galen", | ||
| 123 | "gml": "gml-gms", | ||
| 124 | "gcode": "gcode", | ||
| 125 | "gen": "genstat", | ||
| 126 | "git": "git-commit", | ||
| 127 | "gleam": "gleam", | ||
| 128 | "gjs": "glimmer-js", | ||
| 129 | "glsl": "glsl", | ||
| 130 | "glyphs": "glyphs", | ||
| 131 | "gp": "gnuplot", | ||
| 132 | "go": "go", | ||
| 133 | "mod": "go.mod", | ||
| 134 | "work": "go.work", | ||
| 135 | "api": "goctl", | ||
| 136 | "gd": "gdscript", | ||
| 137 | "gradle.kts": "gradle-kotlin-dsl", | ||
| 138 | "gr": "grain", | ||
| 139 | "gql": "graphql", | ||
| 140 | "gv": "dot", | ||
| 141 | "grit": "grit", | ||
| 142 | "groovy": "groovy", | ||
| 143 | "haml": "haml", | ||
| 144 | "hbs": "handlebars", | ||
| 145 | "prg": "harbour", | ||
| 146 | "hs": "haskell", | ||
| 147 | "haxe": "haxe", | ||
| 148 | "helm.tpl": "helm", | ||
| 149 | "hjson": "hjson", | ||
| 150 | "hlsl": "hlsl", | ||
| 151 | "hosts": "hosts", | ||
| 152 | "http": "http", | ||
| 153 | "aff": "hunspell.aff", | ||
| 154 | "hy": "hy", | ||
| 155 | "hypr": "hypr", | ||
| 156 | "icl": "icl", | ||
| 157 | "imba": "imba", | ||
| 158 | "4gl": "4GL", | ||
| 159 | "ini": "ini", | ||
| 160 | "ink": "ink", | ||
| 161 | "iss": "innosetup", | ||
| 162 | "io": "io", | ||
| 163 | "janet": "janet", | ||
| 164 | "java": "java", | ||
| 165 | "js": "javascript", | ||
| 166 | "mjs": "javascript", | ||
| 167 | "cjs": "javascript", | ||
| 168 | "es6": "javascript", | ||
| 169 | "jake": "javascript", | ||
| 170 | "jsm": "javascript", | ||
| 171 | "jsx": "javascript", | ||
| 172 | "njs": "javascript", | ||
| 173 | "pac": "javascript", | ||
| 174 | "sjs": "javascript", | ||
| 175 | "ssjs": "javascript", | ||
| 176 | "xsjs": "javascript", | ||
| 177 | "xsjslib": "javascript", | ||
| 178 | "jekyll": "jekyll", | ||
| 179 | "jenkins": "jenkins", | ||
| 180 | "jest-snap": "jest-snapshot", | ||
| 181 | "jinja": "jinja", | ||
| 182 | "json": "json", | ||
| 183 | "jsonc": "jsonc", | ||
| 184 | "jsonl": "jsonl", | ||
| 185 | "jsonnet": "jsonnet", | ||
| 186 | "json5": "json5", | ||
| 187 | "jl": "julia", | ||
| 188 | "id": "iodine", | ||
| 189 | "k": "k", | ||
| 190 | "kv": "kivy", | ||
| 191 | "ks": "kos", | ||
| 192 | "kt": "kotlin", | ||
| 193 | "kusto": "kusto", | ||
| 194 | "tex": "latex", | ||
| 195 | "lark": "lark", | ||
| 196 | "lat": "latino", | ||
| 197 | "lean": "lean4", | ||
| 198 | "flex": "lex", | ||
| 199 | "ly": "lilypond", | ||
| 200 | "lisp": "lisp", | ||
| 201 | "lhs": "literate haskell", | ||
| 202 | "log": "log", | ||
| 203 | "lol": "lolcode", | ||
| 204 | "lsl": "lsl", | ||
| 205 | "lua": "lua", | ||
| 206 | "m4": "m4", | ||
| 207 | "mk": "makefile", | ||
| 208 | "md": "markdown", | ||
| 209 | "markdown": "markdown", | ||
| 210 | "mdown": "markdown", | ||
| 211 | "mkd": "markdown", | ||
| 212 | "marko": "marko", | ||
| 213 | "mat": "matlab", | ||
| 214 | "ms": "maxscript", | ||
| 215 | "mdx": "mdx", | ||
| 216 | "mediawiki": "mediawiki", | ||
| 217 | "mel": "mel", | ||
| 218 | "mmd": "mermaid", | ||
| 219 | "metal": "metal", | ||
| 220 | "mcfunction": "bc-mcfunction", | ||
| 221 | "mjml": "mjml", | ||
| 222 | "pq": "powerquery", | ||
| 223 | "mojo": "mojo", | ||
| 224 | "ep": "mojolicious", | ||
| 225 | "mongo": "mongo", | ||
| 226 | "mson": "mson", | ||
| 227 | "mv": "mv", | ||
| 228 | "mvt": "mvt", | ||
| 229 | "ne": "nearley", | ||
| 230 | "nginx": "nginx", | ||
| 231 | "nim": "nim", | ||
| 232 | "nimble": "nimble", | ||
| 233 | "nix": "nix", | ||
| 234 | "nsi": "nsis", | ||
| 235 | "nunjucks": "nunjucks", | ||
| 236 | "nu": "nushell", | ||
| 237 | "m": "objective-c", | ||
| 238 | "mm": "objective-cpp", | ||
| 239 | "ml": "ocaml", | ||
| 240 | "o3": "ogone", | ||
| 241 | "w": "abl", | ||
| 242 | "things": "openhab", | ||
| 243 | "org": "org", | ||
| 244 | "pas": "pascal", | ||
| 245 | "pddl": "pddl", | ||
| 246 | "plan": "plan", | ||
| 247 | "happenings": "happenings", | ||
| 248 | "pl": "perl", | ||
| 249 | "pl6": "perl6", | ||
| 250 | "pgsql": "pgsql", | ||
| 251 | "php": "php", | ||
| 252 | "php4": "php", | ||
| 253 | "php5": "php", | ||
| 254 | "php7": "php", | ||
| 255 | "phtml": "php", | ||
| 256 | "phps": "php", | ||
| 257 | "phpt": "php", | ||
| 258 | "phar": "php", | ||
| 259 | "aw": "php", | ||
| 260 | "ctp": "php", | ||
| 261 | "inc": "php", | ||
| 262 | "php3": "php", | ||
| 263 | "php8": "php", | ||
| 264 | "module": "php", | ||
| 265 | "theme": "php", | ||
| 266 | "tpl": "php", | ||
| 267 | "pine": "pine", | ||
| 268 | "txt": "plaintext", | ||
| 269 | "dbgasm": "platformio-debug.disassembly", | ||
| 270 | "ddl": "plsql", | ||
| 271 | "po": "po", | ||
| 272 | "dib": "polyglot-notebook", | ||
| 273 | "polymer": "polymer", | ||
| 274 | "pony": "pony", | ||
| 275 | "ps": "postscript", | ||
| 276 | "ps1": "powershell", | ||
| 277 | "prisma": "prisma", | ||
| 278 | "pde": "pde", | ||
| 279 | "pro": "prolog", | ||
| 280 | "rules": "prometheus", | ||
| 281 | "properties": "java-properties", | ||
| 282 | "proto": "proto3", | ||
| 283 | "pug": "jade", | ||
| 284 | "pp": "puppet", | ||
| 285 | "purs": "purescript", | ||
| 286 | "arr": "pyret", | ||
| 287 | "pyscript": "pyscript", | ||
| 288 | "py": "python", | ||
| 289 | "pyi": "python", | ||
| 290 | "pyw": "python", | ||
| 291 | "pyc": "python", | ||
| 292 | "pyd": "python", | ||
| 293 | "pyo": "python", | ||
| 294 | "pxd": "python", | ||
| 295 | "pxi": "python", | ||
| 296 | "rpy": "python", | ||
| 297 | "cpy": "python", | ||
| 298 | "ipy": "python", | ||
| 299 | "pyowo": "pythowo", | ||
| 300 | "qvs": "qlik", | ||
| 301 | "qml": "qml", | ||
| 302 | "qs": "qsharp", | ||
| 303 | "r": "r", | ||
| 304 | "rkt": "racket", | ||
| 305 | "raku": "raku", | ||
| 306 | "cshtml": "razor", | ||
| 307 | "raml": "raml", | ||
| 308 | "re": "reason", | ||
| 309 | "red": "red", | ||
| 310 | "res": "rescript", | ||
| 311 | "rst": "restructuredtext", | ||
| 312 | "rex": "rexx", | ||
| 313 | "tag": "riot", | ||
| 314 | "ripple": "ripple", | ||
| 315 | "rmd": "rmd", | ||
| 316 | "rnc": "rnc", | ||
| 317 | "robot": "robot", | ||
| 318 | "rb": "ruby", | ||
| 319 | "rbw": "ruby", | ||
| 320 | "rake": "ruby", | ||
| 321 | "gemspec": "ruby", | ||
| 322 | "ru": "ruby", | ||
| 323 | "rjs": "ruby", | ||
| 324 | "rxml": "ruby", | ||
| 325 | "rsel": "ruby", | ||
| 326 | "builder": "ruby", | ||
| 327 | "jbuilder": "ruby", | ||
| 328 | "rabl": "ruby", | ||
| 329 | "prawn": "ruby", | ||
| 330 | "thor": "ruby", | ||
| 331 | "rs": "rust", | ||
| 332 | "sl": "s-lang", | ||
| 333 | "san": "san", | ||
| 334 | "sas": "SAS", | ||
| 335 | "sbt": "sbt", | ||
| 336 | "scad": "scad", | ||
| 337 | "scala": "scala", | ||
| 338 | "sce": "scilab", | ||
| 339 | "sdl": "sdl", | ||
| 340 | "code-search": "search-result", | ||
| 341 | "shader": "shaderlab", | ||
| 342 | "sh": "shellscript", | ||
| 343 | "bash": "shellscript", | ||
| 344 | "zsh": "shellscript", | ||
| 345 | "ksh": "shellscript", | ||
| 346 | "fish": "shellscript", | ||
| 347 | "slang": "slang", | ||
| 348 | "ice": "slice", | ||
| 349 | "slim": "slim", | ||
| 350 | "slint": "slint", | ||
| 351 | "sln": "sln", | ||
| 352 | "ss": "silverstripe", | ||
| 353 | "sn": "sino", | ||
| 354 | "eskip": "eskip", | ||
| 355 | "smk": "snakemake", | ||
| 356 | "code-snippets": "snippets", | ||
| 357 | "snort": "snort", | ||
| 358 | "sol": "solidity", | ||
| 359 | "rq": "sparql", | ||
| 360 | "sqf": "sqf", | ||
| 361 | "sql": "sql", | ||
| 362 | "nut": "squirrel", | ||
| 363 | "stan": "stan", | ||
| 364 | "bazel": "starlark", | ||
| 365 | "do": "stata", | ||
| 366 | "stencil": "stencil", | ||
| 367 | "html.stencil": "stencil-html", | ||
| 368 | "st.css": "stylable", | ||
| 369 | "styled": "source.css.styled", | ||
| 370 | "styl": "stylus", | ||
| 371 | "svelte": "svelte", | ||
| 372 | "svg": "svg", | ||
| 373 | "swagger": "Swagger", | ||
| 374 | "swift": "swift", | ||
| 375 | "swig": "swig", | ||
| 376 | "link": "systemd-conf", | ||
| 377 | "sv": "systemverilog", | ||
| 378 | "tt": "t4", | ||
| 379 | "teal": "teal", | ||
| 380 | "templ": "templ", | ||
| 381 | "tt3": "tt", | ||
| 382 | "tera": "tera", | ||
| 383 | "tf": "terraform", | ||
| 384 | "sty": "tex", | ||
| 385 | "textile": "textile", | ||
| 386 | "json-tmlanguage": "json-tmlanguage", | ||
| 387 | "yaml-tmlanguage": "yaml-tmlanguage", | ||
| 388 | "toit": "toit", | ||
| 389 | "toml": "toml", | ||
| 390 | "toon": "toon", | ||
| 391 | "ttcn3": "ttcn", | ||
| 392 | "tuc": "tuc", | ||
| 393 | "twig": "twig", | ||
| 394 | "ts": "typescript", | ||
| 395 | "mts": "typescript", | ||
| 396 | "cts": "typescript", | ||
| 397 | "tsx": "typescriptreact", | ||
| 398 | "typoscript": "typoscript", | ||
| 399 | "ua": "uiua", | ||
| 400 | "u": "unison", | ||
| 401 | "vb": "vb", | ||
| 402 | "wsf": "vbscript", | ||
| 403 | "vm": "velocity", | ||
| 404 | "vto": "vento", | ||
| 405 | "v": "verilog", | ||
| 406 | "vhdl": "vhdl", | ||
| 407 | "vim": "viml", | ||
| 408 | "vitest-snap": "vitest-snapshot", | ||
| 409 | "volt": "volt", | ||
| 410 | "vroom": "vroom", | ||
| 411 | "vue": "vue", | ||
| 412 | "vue2": "vue", | ||
| 413 | "vue3": "vue", | ||
| 414 | "vues": "vue", | ||
| 415 | "vuex": "vue", | ||
| 416 | "vuerc": "vue", | ||
| 417 | "vy": "vyper", | ||
| 418 | "wai": "wai", | ||
| 419 | "wasm": "wasm", | ||
| 420 | "wat": "wasm", | ||
| 421 | "wast": "wasm", | ||
| 422 | "wsm": "wasm", | ||
| 423 | "wast.js": "wasm", | ||
| 424 | "wit": "wasm", | ||
| 425 | "witx": "wasm", | ||
| 426 | "wy": "wenyan", | ||
| 427 | "wgsl": "wgsl", | ||
| 428 | "wt": "wikitext", | ||
| 429 | "wl": "wolfram", | ||
| 430 | "wurst": "wurstlang", | ||
| 431 | "xcompose": "xcompose", | ||
| 432 | "xmake.lua": "xmake", | ||
| 433 | "xml": "xml", | ||
| 434 | "xquery": "xquery", | ||
| 435 | "xsl": "xsl", | ||
| 436 | "bison": "yacc", | ||
| 437 | "yang": "yang", | ||
| 438 | "zig": "zig", | ||
| 439 | "zip": "zip" | ||
| 440 | }, | ||
| 441 | "fileNameToLanguageId": { | ||
| 442 | "browserslist": "browserslist", | ||
| 443 | ".browserslistrc": "browserslist", | ||
| 444 | "caddyfile": "caddyfile", | ||
| 445 | "cmakelists.txt": "cmake", | ||
| 446 | "cmakecache.txt": "cmake-cache", | ||
| 447 | "docker-compose.yml": "dockercompose", | ||
| 448 | "docker-compose.yaml": "dockercompose", | ||
| 449 | "compose.yaml": "dockercompose", | ||
| 450 | "compose.yml": "dockercompose", | ||
| 451 | "dockerfile": "dockerfile", | ||
| 452 | "dockerfile.dev": "dockerfile", | ||
| 453 | "dockerfile.prod": "dockerfile", | ||
| 454 | "dockerfile.test": "dockerfile", | ||
| 455 | ".editorconfig": "editorconfig", | ||
| 456 | "justfile": "just", | ||
| 457 | "meson.build": "meson", | ||
| 458 | ".php-version": "php", | ||
| 459 | "artisan": "php", | ||
| 460 | "requirements.txt": "pip-requirements", | ||
| 461 | "requirements-dev.txt": "pip-requirements", | ||
| 462 | "requirements-test.txt": "pip-requirements", | ||
| 463 | "requirements-prod.txt": "pip-requirements", | ||
| 464 | "setup.py": "python", | ||
| 465 | "setup.cfg": "python", | ||
| 466 | ".python-version": "python", | ||
| 467 | "pipfile": "python", | ||
| 468 | "pipfile.lock": "python", | ||
| 469 | "robots.txt": "robots-txt", | ||
| 470 | "config.ru": "ruby", | ||
| 471 | ".bashrc": "shellscript", | ||
| 472 | ".zshrc": "shellscript", | ||
| 473 | ".profile": "shellscript", | ||
| 474 | ".bash_profile": "shellscript", | ||
| 475 | ".bash_aliases": "shellscript", | ||
| 476 | ".zprofile": "shellscript", | ||
| 477 | "tiltfile": "tiltfile", | ||
| 478 | ".vue-cli-rc": "vue", | ||
| 479 | "yarn.lock": "yarnlock" | ||
| 480 | } | ||
| 481 | } | ||
| @@ -1,8351 +0,0 @@ | |||
| 1 | { | ||
| 2 | "iconDefinitions": { | ||
| 3 | "_file": { "iconPath": "../../icons/default_file.svg" }, | ||
| 4 | "_folder": { "iconPath": "../../icons/default_folder.svg" }, | ||
| 5 | "_folder_open": { "iconPath": "../../icons/default_folder_opened.svg" }, | ||
| 6 | "_root_folder": { "iconPath": "../../icons/default_root_folder.svg" }, | ||
| 7 | "_root_folder_open": { "iconPath": "../../icons/default_root_folder_opened.svg" }, | ||
| 8 | "_file_light": { "iconPath": "" }, | ||
| 9 | "_folder_light": { "iconPath": "" }, | ||
| 10 | "_folder_light_open": { "iconPath": "" }, | ||
| 11 | "_root_folder_light": { "iconPath": "" }, | ||
| 12 | "_root_folder_light_open": { "iconPath": "" }, | ||
| 13 | "_fd_android": { "iconPath": "../../icons/folder_type_android.svg" }, | ||
| 14 | "_fd_android_open": { "iconPath": "../../icons/folder_type_android_opened.svg" }, | ||
| 15 | "_fd_angular": { "iconPath": "../../icons/folder_type_angular.svg" }, | ||
| 16 | "_fd_angular_open": { "iconPath": "../../icons/folder_type_angular_opened.svg" }, | ||
| 17 | "_fd_apache": { "iconPath": "../../icons/folder_type_apache.svg" }, | ||
| 18 | "_fd_apache_open": { "iconPath": "../../icons/folder_type_apache_opened.svg" }, | ||
| 19 | "_fd_api": { "iconPath": "../../icons/folder_type_api.svg" }, | ||
| 20 | "_fd_api_open": { "iconPath": "../../icons/folder_type_api_opened.svg" }, | ||
| 21 | "_fd_app": { "iconPath": "../../icons/folder_type_app.svg" }, | ||
| 22 | "_fd_app_open": { "iconPath": "../../icons/folder_type_app_opened.svg" }, | ||
| 23 | "_fd_arangodb": { "iconPath": "../../icons/folder_type_arangodb.svg" }, | ||
| 24 | "_fd_arangodb_open": { "iconPath": "../../icons/folder_type_arangodb_opened.svg" }, | ||
| 25 | "_fd_asset": { "iconPath": "../../icons/folder_type_asset.svg" }, | ||
| 26 | "_fd_asset_open": { "iconPath": "../../icons/folder_type_asset_opened.svg" }, | ||
| 27 | "_fd_astro": { "iconPath": "../../icons/folder_type_astro.svg" }, | ||
| 28 | "_fd_astro_open": { "iconPath": "../../icons/folder_type_astro_opened.svg" }, | ||
| 29 | "_fd_audio": { "iconPath": "../../icons/folder_type_audio.svg" }, | ||
| 30 | "_fd_audio_open": { "iconPath": "../../icons/folder_type_audio_opened.svg" }, | ||
| 31 | "_fd_aurelia": { "iconPath": "../../icons/folder_type_aurelia.svg" }, | ||
| 32 | "_fd_aurelia_open": { "iconPath": "../../icons/folder_type_aurelia_opened.svg" }, | ||
| 33 | "_fd_aws": { "iconPath": "../../icons/folder_type_aws.svg" }, | ||
| 34 | "_fd_aws_open": { "iconPath": "../../icons/folder_type_aws_opened.svg" }, | ||
| 35 | "_fd_azure": { "iconPath": "../../icons/folder_type_azure.svg" }, | ||
| 36 | "_fd_azure_open": { "iconPath": "../../icons/folder_type_azure_opened.svg" }, | ||
| 37 | "_fd_azurepipelines": { "iconPath": "../../icons/folder_type_azurepipelines.svg" }, | ||
| 38 | "_fd_azurepipelines_open": { "iconPath": "../../icons/folder_type_azurepipelines_opened.svg" }, | ||
| 39 | "_fd_binary": { "iconPath": "../../icons/folder_type_binary.svg" }, | ||
| 40 | "_fd_binary_open": { "iconPath": "../../icons/folder_type_binary_opened.svg" }, | ||
| 41 | "_fd_bloc": { "iconPath": "../../icons/folder_type_bloc.svg" }, | ||
| 42 | "_fd_bloc_open": { "iconPath": "../../icons/folder_type_bloc_opened.svg" }, | ||
| 43 | "_fd_blueprint": { "iconPath": "../../icons/folder_type_blueprint.svg" }, | ||
| 44 | "_fd_blueprint_open": { "iconPath": "../../icons/folder_type_blueprint_opened.svg" }, | ||
| 45 | "_fd_bot": { "iconPath": "../../icons/folder_type_bot.svg" }, | ||
| 46 | "_fd_bot_open": { "iconPath": "../../icons/folder_type_bot_opened.svg" }, | ||
| 47 | "_fd_bower": { "iconPath": "../../icons/folder_type_bower.svg" }, | ||
| 48 | "_fd_bower_open": { "iconPath": "../../icons/folder_type_bower_opened.svg" }, | ||
| 49 | "_fd_buildkite": { "iconPath": "../../icons/folder_type_buildkite.svg" }, | ||
| 50 | "_fd_buildkite_open": { "iconPath": "../../icons/folder_type_buildkite_opened.svg" }, | ||
| 51 | "_fd_cake": { "iconPath": "../../icons/folder_type_cake.svg" }, | ||
| 52 | "_fd_cake_open": { "iconPath": "../../icons/folder_type_cake_opened.svg" }, | ||
| 53 | "_fd_cargo": { "iconPath": "../../icons/folder_type_cargo.svg" }, | ||
| 54 | "_fd_cargo_open": { "iconPath": "../../icons/folder_type_cargo_opened.svg" }, | ||
| 55 | "_fd_certificate": { "iconPath": "../../icons/folder_type_certificate.svg" }, | ||
| 56 | "_fd_certificate_open": { "iconPath": "../../icons/folder_type_certificate_opened.svg" }, | ||
| 57 | "_fd_changesets": { "iconPath": "../../icons/folder_type_changesets.svg" }, | ||
| 58 | "_fd_changesets_open": { "iconPath": "../../icons/folder_type_changesets_opened.svg" }, | ||
| 59 | "_fd_chef": { "iconPath": "../../icons/folder_type_chef.svg" }, | ||
| 60 | "_fd_chef_open": { "iconPath": "../../icons/folder_type_chef_opened.svg" }, | ||
| 61 | "_fd_circleci": { "iconPath": "../../icons/folder_type_circleci.svg" }, | ||
| 62 | "_fd_circleci_open": { "iconPath": "../../icons/folder_type_circleci_opened.svg" }, | ||
| 63 | "_fd_claude": { "iconPath": "../../icons/folder_type_claude.svg" }, | ||
| 64 | "_fd_claude_open": { "iconPath": "../../icons/folder_type_claude_opened.svg" }, | ||
| 65 | "_fd_cli": { "iconPath": "../../icons/folder_type_cli.svg" }, | ||
| 66 | "_fd_cli_open": { "iconPath": "../../icons/folder_type_cli_opened.svg" }, | ||
| 67 | "_fd_client": { "iconPath": "../../icons/folder_type_client.svg" }, | ||
| 68 | "_fd_client_open": { "iconPath": "../../icons/folder_type_client_opened.svg" }, | ||
| 69 | "_fd_cloudflare": { "iconPath": "../../icons/folder_type_cloudflare.svg" }, | ||
| 70 | "_fd_cloudflare_open": { "iconPath": "../../icons/folder_type_cloudflare_opened.svg" }, | ||
| 71 | "_fd_cmake": { "iconPath": "../../icons/folder_type_cmake.svg" }, | ||
| 72 | "_fd_cmake_open": { "iconPath": "../../icons/folder_type_cmake_opened.svg" }, | ||
| 73 | "_fd_common": { "iconPath": "../../icons/folder_type_common.svg" }, | ||
| 74 | "_fd_common_open": { "iconPath": "../../icons/folder_type_common_opened.svg" }, | ||
| 75 | "_fd_component": { "iconPath": "../../icons/folder_type_component.svg" }, | ||
| 76 | "_fd_component_open": { "iconPath": "../../icons/folder_type_component_opened.svg" }, | ||
| 77 | "_fd_composer": { "iconPath": "../../icons/folder_type_composer.svg" }, | ||
| 78 | "_fd_composer_open": { "iconPath": "../../icons/folder_type_composer_opened.svg" }, | ||
| 79 | "_fd_config": { "iconPath": "../../icons/folder_type_config.svg" }, | ||
| 80 | "_fd_config_open": { "iconPath": "../../icons/folder_type_config_opened.svg" }, | ||
| 81 | "_fd_controller": { "iconPath": "../../icons/folder_type_controller.svg" }, | ||
| 82 | "_fd_controller_open": { "iconPath": "../../icons/folder_type_controller_opened.svg" }, | ||
| 83 | "_fd_coverage": { "iconPath": "../../icons/folder_type_coverage.svg" }, | ||
| 84 | "_fd_coverage_open": { "iconPath": "../../icons/folder_type_coverage_opened.svg" }, | ||
| 85 | "_fd_css": { "iconPath": "../../icons/folder_type_css.svg" }, | ||
| 86 | "_fd_css_open": { "iconPath": "../../icons/folder_type_css_opened.svg" }, | ||
| 87 | "_fd_cubit": { "iconPath": "../../icons/folder_type_cubit.svg" }, | ||
| 88 | "_fd_cubit_open": { "iconPath": "../../icons/folder_type_cubit_opened.svg" }, | ||
| 89 | "_fd_cursor": { "iconPath": "../../icons/folder_type_cursor.svg" }, | ||
| 90 | "_fd_cursor_open": { "iconPath": "../../icons/folder_type_cursor_opened.svg" }, | ||
| 91 | "_fd_light_cursor": { "iconPath": "../../icons/folder_type_light_cursor.svg" }, | ||
| 92 | "_fd_light_cursor_open": { "iconPath": "../../icons/folder_type_light_cursor_opened.svg" }, | ||
| 93 | "_fd_cypress": { "iconPath": "../../icons/folder_type_cypress.svg" }, | ||
| 94 | "_fd_cypress_open": { "iconPath": "../../icons/folder_type_cypress_opened.svg" }, | ||
| 95 | "_fd_light_cypress": { "iconPath": "../../icons/folder_type_light_cypress.svg" }, | ||
| 96 | "_fd_light_cypress_open": { "iconPath": "../../icons/folder_type_light_cypress_opened.svg" }, | ||
| 97 | "_fd_dapr": { "iconPath": "../../icons/folder_type_dapr.svg" }, | ||
| 98 | "_fd_dapr_open": { "iconPath": "../../icons/folder_type_dapr_opened.svg" }, | ||
| 99 | "_fd_dart": { "iconPath": "../../icons/folder_type_dart.svg" }, | ||
| 100 | "_fd_dart_open": { "iconPath": "../../icons/folder_type_dart_opened.svg" }, | ||
| 101 | "_fd_datadog": { "iconPath": "../../icons/folder_type_datadog.svg" }, | ||
| 102 | "_fd_datadog_open": { "iconPath": "../../icons/folder_type_datadog_opened.svg" }, | ||
| 103 | "_fd_db": { "iconPath": "../../icons/folder_type_db.svg" }, | ||
| 104 | "_fd_db_open": { "iconPath": "../../icons/folder_type_db_opened.svg" }, | ||
| 105 | "_fd_debian": { "iconPath": "../../icons/folder_type_debian.svg" }, | ||
| 106 | "_fd_debian_open": { "iconPath": "../../icons/folder_type_debian_opened.svg" }, | ||
| 107 | "_fd_dependabot": { "iconPath": "../../icons/folder_type_dependabot.svg" }, | ||
| 108 | "_fd_dependabot_open": { "iconPath": "../../icons/folder_type_dependabot_opened.svg" }, | ||
| 109 | "_fd_devcontainer": { "iconPath": "../../icons/folder_type_devcontainer.svg" }, | ||
| 110 | "_fd_devcontainer_open": { "iconPath": "../../icons/folder_type_devcontainer_opened.svg" }, | ||
| 111 | "_fd_dist": { "iconPath": "../../icons/folder_type_dist.svg" }, | ||
| 112 | "_fd_dist_open": { "iconPath": "../../icons/folder_type_dist_opened.svg" }, | ||
| 113 | "_fd_docker": { "iconPath": "../../icons/folder_type_docker.svg" }, | ||
| 114 | "_fd_docker_open": { "iconPath": "../../icons/folder_type_docker_opened.svg" }, | ||
| 115 | "_fd_docs": { "iconPath": "../../icons/folder_type_docs.svg" }, | ||
| 116 | "_fd_docs_open": { "iconPath": "../../icons/folder_type_docs_opened.svg" }, | ||
| 117 | "_fd_e2e": { "iconPath": "../../icons/folder_type_e2e.svg" }, | ||
| 118 | "_fd_e2e_open": { "iconPath": "../../icons/folder_type_e2e_opened.svg" }, | ||
| 119 | "_fd_elasticbeanstalk": { "iconPath": "../../icons/folder_type_elasticbeanstalk.svg" }, | ||
| 120 | "_fd_elasticbeanstalk_open": { | ||
| 121 | "iconPath": "../../icons/folder_type_elasticbeanstalk_opened.svg" | ||
| 122 | }, | ||
| 123 | "_fd_electron": { "iconPath": "../../icons/folder_type_electron.svg" }, | ||
| 124 | "_fd_electron_open": { "iconPath": "../../icons/folder_type_electron_opened.svg" }, | ||
| 125 | "_fd_light_electron": { "iconPath": "../../icons/folder_type_light_electron.svg" }, | ||
| 126 | "_fd_light_electron_open": { "iconPath": "../../icons/folder_type_light_electron_opened.svg" }, | ||
| 127 | "_fd_expo": { "iconPath": "../../icons/folder_type_expo.svg" }, | ||
| 128 | "_fd_expo_open": { "iconPath": "../../icons/folder_type_expo_opened.svg" }, | ||
| 129 | "_fd_light_expo": { "iconPath": "../../icons/folder_type_light_expo.svg" }, | ||
| 130 | "_fd_light_expo_open": { "iconPath": "../../icons/folder_type_light_expo_opened.svg" }, | ||
| 131 | "_fd_favicon": { "iconPath": "../../icons/folder_type_favicon.svg" }, | ||
| 132 | "_fd_favicon_open": { "iconPath": "../../icons/folder_type_favicon_opened.svg" }, | ||
| 133 | "_fd_flow": { "iconPath": "../../icons/folder_type_flow.svg" }, | ||
| 134 | "_fd_flow_open": { "iconPath": "../../icons/folder_type_flow_opened.svg" }, | ||
| 135 | "_fd_flutter": { "iconPath": "../../icons/folder_type_flutter.svg" }, | ||
| 136 | "_fd_flutter_open": { "iconPath": "../../icons/folder_type_flutter_opened.svg" }, | ||
| 137 | "_fd_fonts": { "iconPath": "../../icons/folder_type_fonts.svg" }, | ||
| 138 | "_fd_fonts_open": { "iconPath": "../../icons/folder_type_fonts_opened.svg" }, | ||
| 139 | "_fd_light_fonts": { "iconPath": "../../icons/folder_type_light_fonts.svg" }, | ||
| 140 | "_fd_light_fonts_open": { "iconPath": "../../icons/folder_type_light_fonts_opened.svg" }, | ||
| 141 | "_fd_frontcommerce": { "iconPath": "../../icons/folder_type_frontcommerce.svg" }, | ||
| 142 | "_fd_frontcommerce_open": { "iconPath": "../../icons/folder_type_frontcommerce_opened.svg" }, | ||
| 143 | "_fd_gcp": { "iconPath": "../../icons/folder_type_gcp.svg" }, | ||
| 144 | "_fd_gcp_open": { "iconPath": "../../icons/folder_type_gcp_opened.svg" }, | ||
| 145 | "_fd_gemini": { "iconPath": "../../icons/folder_type_gemini.svg" }, | ||
| 146 | "_fd_gemini_open": { "iconPath": "../../icons/folder_type_gemini_opened.svg" }, | ||
| 147 | "_fd_git": { "iconPath": "../../icons/folder_type_git.svg" }, | ||
| 148 | "_fd_git_open": { "iconPath": "../../icons/folder_type_git_opened.svg" }, | ||
| 149 | "_fd_github": { "iconPath": "../../icons/folder_type_github.svg" }, | ||
| 150 | "_fd_github_open": { "iconPath": "../../icons/folder_type_github_opened.svg" }, | ||
| 151 | "_fd_gitlab": { "iconPath": "../../icons/folder_type_gitlab.svg" }, | ||
| 152 | "_fd_gitlab_open": { "iconPath": "../../icons/folder_type_gitlab_opened.svg" }, | ||
| 153 | "_fd_godot": { "iconPath": "../../icons/folder_type_godot.svg" }, | ||
| 154 | "_fd_godot_open": { "iconPath": "../../icons/folder_type_godot_opened.svg" }, | ||
| 155 | "_fd_gradle": { "iconPath": "../../icons/folder_type_gradle.svg" }, | ||
| 156 | "_fd_gradle_open": { "iconPath": "../../icons/folder_type_gradle_opened.svg" }, | ||
| 157 | "_fd_light_gradle": { "iconPath": "../../icons/folder_type_light_gradle.svg" }, | ||
| 158 | "_fd_light_gradle_open": { "iconPath": "../../icons/folder_type_light_gradle_opened.svg" }, | ||
| 159 | "_fd_graphql": { "iconPath": "../../icons/folder_type_graphql.svg" }, | ||
| 160 | "_fd_graphql_open": { "iconPath": "../../icons/folder_type_graphql_opened.svg" }, | ||
| 161 | "_fd_grunt": { "iconPath": "../../icons/folder_type_grunt.svg" }, | ||
| 162 | "_fd_grunt_open": { "iconPath": "../../icons/folder_type_grunt_opened.svg" }, | ||
| 163 | "_fd_gulp": { "iconPath": "../../icons/folder_type_gulp.svg" }, | ||
| 164 | "_fd_gulp_open": { "iconPath": "../../icons/folder_type_gulp_opened.svg" }, | ||
| 165 | "_fd_haxelib": { "iconPath": "../../icons/folder_type_haxelib.svg" }, | ||
| 166 | "_fd_haxelib_open": { "iconPath": "../../icons/folder_type_haxelib_opened.svg" }, | ||
| 167 | "_fd_helper": { "iconPath": "../../icons/folder_type_helper.svg" }, | ||
| 168 | "_fd_helper_open": { "iconPath": "../../icons/folder_type_helper_opened.svg" }, | ||
| 169 | "_fd_histoire": { "iconPath": "../../icons/folder_type_histoire.svg" }, | ||
| 170 | "_fd_histoire_open": { "iconPath": "../../icons/folder_type_histoire_opened.svg" }, | ||
| 171 | "_fd_hook": { "iconPath": "../../icons/folder_type_hook.svg" }, | ||
| 172 | "_fd_hook_open": { "iconPath": "../../icons/folder_type_hook_opened.svg" }, | ||
| 173 | "_fd_husky": { "iconPath": "../../icons/folder_type_husky.svg" }, | ||
| 174 | "_fd_husky_open": { "iconPath": "../../icons/folder_type_husky_opened.svg" }, | ||
| 175 | "_fd_idea": { "iconPath": "../../icons/folder_type_idea.svg" }, | ||
| 176 | "_fd_idea_open": { "iconPath": "../../icons/folder_type_idea_opened.svg" }, | ||
| 177 | "_fd_images": { "iconPath": "../../icons/folder_type_images.svg" }, | ||
| 178 | "_fd_images_open": { "iconPath": "../../icons/folder_type_images_opened.svg" }, | ||
| 179 | "_fd_include": { "iconPath": "../../icons/folder_type_include.svg" }, | ||
| 180 | "_fd_include_open": { "iconPath": "../../icons/folder_type_include_opened.svg" }, | ||
| 181 | "_fd_interfaces": { "iconPath": "../../icons/folder_type_interfaces.svg" }, | ||
| 182 | "_fd_interfaces_open": { "iconPath": "../../icons/folder_type_interfaces_opened.svg" }, | ||
| 183 | "_fd_ios": { "iconPath": "../../icons/folder_type_ios.svg" }, | ||
| 184 | "_fd_ios_open": { "iconPath": "../../icons/folder_type_ios_opened.svg" }, | ||
| 185 | "_fd_js": { "iconPath": "../../icons/folder_type_js.svg" }, | ||
| 186 | "_fd_js_open": { "iconPath": "../../icons/folder_type_js_opened.svg" }, | ||
| 187 | "_fd_json": { "iconPath": "../../icons/folder_type_json.svg" }, | ||
| 188 | "_fd_json_open": { "iconPath": "../../icons/folder_type_json_opened.svg" }, | ||
| 189 | "_fd_junie": { "iconPath": "../../icons/folder_type_junie.svg" }, | ||
| 190 | "_fd_junie_open": { "iconPath": "../../icons/folder_type_junie_opened.svg" }, | ||
| 191 | "_fd_kotlin": { "iconPath": "../../icons/folder_type_kotlin.svg" }, | ||
| 192 | "_fd_kotlin_open": { "iconPath": "../../icons/folder_type_kotlin_opened.svg" }, | ||
| 193 | "_fd_kubernetes": { "iconPath": "../../icons/folder_type_kubernetes.svg" }, | ||
| 194 | "_fd_kubernetes_open": { "iconPath": "../../icons/folder_type_kubernetes_opened.svg" }, | ||
| 195 | "_fd_less": { "iconPath": "../../icons/folder_type_less.svg" }, | ||
| 196 | "_fd_less_open": { "iconPath": "../../icons/folder_type_less_opened.svg" }, | ||
| 197 | "_fd_library": { "iconPath": "../../icons/folder_type_library.svg" }, | ||
| 198 | "_fd_library_open": { "iconPath": "../../icons/folder_type_library_opened.svg" }, | ||
| 199 | "_fd_linux": { "iconPath": "../../icons/folder_type_linux.svg" }, | ||
| 200 | "_fd_linux_open": { "iconPath": "../../icons/folder_type_linux_opened.svg" }, | ||
| 201 | "_fd_locale": { "iconPath": "../../icons/folder_type_locale.svg" }, | ||
| 202 | "_fd_locale_open": { "iconPath": "../../icons/folder_type_locale_opened.svg" }, | ||
| 203 | "_fd_log": { "iconPath": "../../icons/folder_type_log.svg" }, | ||
| 204 | "_fd_log_open": { "iconPath": "../../icons/folder_type_log_opened.svg" }, | ||
| 205 | "_fd_macos": { "iconPath": "../../icons/folder_type_macos.svg" }, | ||
| 206 | "_fd_macos_open": { "iconPath": "../../icons/folder_type_macos_opened.svg" }, | ||
| 207 | "_fd_mariadb": { "iconPath": "../../icons/folder_type_mariadb.svg" }, | ||
| 208 | "_fd_mariadb_open": { "iconPath": "../../icons/folder_type_mariadb_opened.svg" }, | ||
| 209 | "_fd_maven": { "iconPath": "../../icons/folder_type_maven.svg" }, | ||
| 210 | "_fd_maven_open": { "iconPath": "../../icons/folder_type_maven_opened.svg" }, | ||
| 211 | "_fd_mediawiki": { "iconPath": "../../icons/folder_type_mediawiki.svg" }, | ||
| 212 | "_fd_mediawiki_open": { "iconPath": "../../icons/folder_type_mediawiki_opened.svg" }, | ||
| 213 | "_fd_memcached": { "iconPath": "../../icons/folder_type_memcached.svg" }, | ||
| 214 | "_fd_memcached_open": { "iconPath": "../../icons/folder_type_memcached_opened.svg" }, | ||
| 215 | "_fd_meteor": { "iconPath": "../../icons/folder_type_meteor.svg" }, | ||
| 216 | "_fd_meteor_open": { "iconPath": "../../icons/folder_type_meteor_opened.svg" }, | ||
| 217 | "_fd_light_meteor": { "iconPath": "../../icons/folder_type_light_meteor.svg" }, | ||
| 218 | "_fd_light_meteor_open": { "iconPath": "../../icons/folder_type_light_meteor_opened.svg" }, | ||
| 219 | "_fd_middleware": { "iconPath": "../../icons/folder_type_middleware.svg" }, | ||
| 220 | "_fd_middleware_open": { "iconPath": "../../icons/folder_type_middleware_opened.svg" }, | ||
| 221 | "_fd_minecraft": { "iconPath": "../../icons/folder_type_minecraft.svg" }, | ||
| 222 | "_fd_minecraft_open": { "iconPath": "../../icons/folder_type_minecraft_opened.svg" }, | ||
| 223 | "_fd_minikube": { "iconPath": "../../icons/folder_type_minikube.svg" }, | ||
| 224 | "_fd_minikube_open": { "iconPath": "../../icons/folder_type_minikube_opened.svg" }, | ||
| 225 | "_fd_mjml": { "iconPath": "../../icons/folder_type_mjml.svg" }, | ||
| 226 | "_fd_mjml_open": { "iconPath": "../../icons/folder_type_mjml_opened.svg" }, | ||
| 227 | "_fd_mock": { "iconPath": "../../icons/folder_type_mock.svg" }, | ||
| 228 | "_fd_mock_open": { "iconPath": "../../icons/folder_type_mock_opened.svg" }, | ||
| 229 | "_fd_model": { "iconPath": "../../icons/folder_type_model.svg" }, | ||
| 230 | "_fd_model_open": { "iconPath": "../../icons/folder_type_model_opened.svg" }, | ||
| 231 | "_fd_module": { "iconPath": "../../icons/folder_type_module.svg" }, | ||
| 232 | "_fd_module_open": { "iconPath": "../../icons/folder_type_module_opened.svg" }, | ||
| 233 | "_fd_mojo": { "iconPath": "../../icons/folder_type_mojo.svg" }, | ||
| 234 | "_fd_mojo_open": { "iconPath": "../../icons/folder_type_mojo_opened.svg" }, | ||
| 235 | "_fd_mongodb": { "iconPath": "../../icons/folder_type_mongodb.svg" }, | ||
| 236 | "_fd_mongodb_open": { "iconPath": "../../icons/folder_type_mongodb_opened.svg" }, | ||
| 237 | "_fd_mypy": { "iconPath": "../../icons/folder_type_mypy.svg" }, | ||
| 238 | "_fd_mypy_open": { "iconPath": "../../icons/folder_type_mypy_opened.svg" }, | ||
| 239 | "_fd_light_mypy": { "iconPath": "../../icons/folder_type_light_mypy.svg" }, | ||
| 240 | "_fd_light_mypy_open": { "iconPath": "../../icons/folder_type_light_mypy_opened.svg" }, | ||
| 241 | "_fd_mysql": { "iconPath": "../../icons/folder_type_mysql.svg" }, | ||
| 242 | "_fd_mysql_open": { "iconPath": "../../icons/folder_type_mysql_opened.svg" }, | ||
| 243 | "_fd_light_mysql": { "iconPath": "../../icons/folder_type_light_mysql.svg" }, | ||
| 244 | "_fd_light_mysql_open": { "iconPath": "../../icons/folder_type_light_mysql_opened.svg" }, | ||
| 245 | "_fd_netlify": { "iconPath": "../../icons/folder_type_netlify.svg" }, | ||
| 246 | "_fd_netlify_open": { "iconPath": "../../icons/folder_type_netlify_opened.svg" }, | ||
| 247 | "_fd_next": { "iconPath": "../../icons/folder_type_next.svg" }, | ||
| 248 | "_fd_next_open": { "iconPath": "../../icons/folder_type_next_opened.svg" }, | ||
| 249 | "_fd_nginx": { "iconPath": "../../icons/folder_type_nginx.svg" }, | ||
| 250 | "_fd_nginx_open": { "iconPath": "../../icons/folder_type_nginx_opened.svg" }, | ||
| 251 | "_fd_nix": { "iconPath": "../../icons/folder_type_nix.svg" }, | ||
| 252 | "_fd_nix_open": { "iconPath": "../../icons/folder_type_nix_opened.svg" }, | ||
| 253 | "_fd_node": { "iconPath": "../../icons/folder_type_node.svg" }, | ||
| 254 | "_fd_node_open": { "iconPath": "../../icons/folder_type_node_opened.svg" }, | ||
| 255 | "_fd_light_node": { "iconPath": "../../icons/folder_type_light_node.svg" }, | ||
| 256 | "_fd_light_node_open": { "iconPath": "../../icons/folder_type_light_node_opened.svg" }, | ||
| 257 | "_fd_notebooks": { "iconPath": "../../icons/folder_type_notebooks.svg" }, | ||
| 258 | "_fd_notebooks_open": { "iconPath": "../../icons/folder_type_notebooks_opened.svg" }, | ||
| 259 | "_fd_notification": { "iconPath": "../../icons/folder_type_notification.svg" }, | ||
| 260 | "_fd_notification_open": { "iconPath": "../../icons/folder_type_notification_opened.svg" }, | ||
| 261 | "_fd_nuget": { "iconPath": "../../icons/folder_type_nuget.svg" }, | ||
| 262 | "_fd_nuget_open": { "iconPath": "../../icons/folder_type_nuget_opened.svg" }, | ||
| 263 | "_fd_nuxt": { "iconPath": "../../icons/folder_type_nuxt.svg" }, | ||
| 264 | "_fd_nuxt_open": { "iconPath": "../../icons/folder_type_nuxt_opened.svg" }, | ||
| 265 | "_fd_package": { "iconPath": "../../icons/folder_type_package.svg" }, | ||
| 266 | "_fd_package_open": { "iconPath": "../../icons/folder_type_package_opened.svg" }, | ||
| 267 | "_fd_paket": { "iconPath": "../../icons/folder_type_paket.svg" }, | ||
| 268 | "_fd_paket_open": { "iconPath": "../../icons/folder_type_paket_opened.svg" }, | ||
| 269 | "_fd_php": { "iconPath": "../../icons/folder_type_php.svg" }, | ||
| 270 | "_fd_php_open": { "iconPath": "../../icons/folder_type_php_opened.svg" }, | ||
| 271 | "_fd_platformio": { "iconPath": "../../icons/folder_type_platformio.svg" }, | ||
| 272 | "_fd_platformio_open": { "iconPath": "../../icons/folder_type_platformio_opened.svg" }, | ||
| 273 | "_fd_plugin": { "iconPath": "../../icons/folder_type_plugin.svg" }, | ||
| 274 | "_fd_plugin_open": { "iconPath": "../../icons/folder_type_plugin_opened.svg" }, | ||
| 275 | "_fd_prisma": { "iconPath": "../../icons/folder_type_prisma.svg" }, | ||
| 276 | "_fd_prisma_open": { "iconPath": "../../icons/folder_type_prisma_opened.svg" }, | ||
| 277 | "_fd_private": { "iconPath": "../../icons/folder_type_private.svg" }, | ||
| 278 | "_fd_private_open": { "iconPath": "../../icons/folder_type_private_opened.svg" }, | ||
| 279 | "_fd_public": { "iconPath": "../../icons/folder_type_public.svg" }, | ||
| 280 | "_fd_public_open": { "iconPath": "../../icons/folder_type_public_opened.svg" }, | ||
| 281 | "_fd_pytest": { "iconPath": "../../icons/folder_type_pytest.svg" }, | ||
| 282 | "_fd_pytest_open": { "iconPath": "../../icons/folder_type_pytest_opened.svg" }, | ||
| 283 | "_fd_python": { "iconPath": "../../icons/folder_type_python.svg" }, | ||
| 284 | "_fd_python_open": { "iconPath": "../../icons/folder_type_python_opened.svg" }, | ||
| 285 | "_fd_ravendb": { "iconPath": "../../icons/folder_type_ravendb.svg" }, | ||
| 286 | "_fd_ravendb_open": { "iconPath": "../../icons/folder_type_ravendb_opened.svg" }, | ||
| 287 | "_fd_redis": { "iconPath": "../../icons/folder_type_redis.svg" }, | ||
| 288 | "_fd_redis_open": { "iconPath": "../../icons/folder_type_redis_opened.svg" }, | ||
| 289 | "_fd_redux": { "iconPath": "../../icons/folder_type_redux.svg" }, | ||
| 290 | "_fd_redux_open": { "iconPath": "../../icons/folder_type_redux_opened.svg" }, | ||
| 291 | "_fd_light_redux": { "iconPath": "../../icons/folder_type_light_redux.svg" }, | ||
| 292 | "_fd_light_redux_open": { "iconPath": "../../icons/folder_type_light_redux_opened.svg" }, | ||
| 293 | "_fd_route": { "iconPath": "../../icons/folder_type_route.svg" }, | ||
| 294 | "_fd_route_open": { "iconPath": "../../icons/folder_type_route_opened.svg" }, | ||
| 295 | "_fd_sass": { "iconPath": "../../icons/folder_type_sass.svg" }, | ||
| 296 | "_fd_sass_open": { "iconPath": "../../icons/folder_type_sass_opened.svg" }, | ||
| 297 | "_fd_light_sass": { "iconPath": "../../icons/folder_type_light_sass.svg" }, | ||
| 298 | "_fd_light_sass_open": { "iconPath": "../../icons/folder_type_light_sass_opened.svg" }, | ||
| 299 | "_fd_script": { "iconPath": "../../icons/folder_type_script.svg" }, | ||
| 300 | "_fd_script_open": { "iconPath": "../../icons/folder_type_script_opened.svg" }, | ||
| 301 | "_fd_seedkit": { "iconPath": "../../icons/folder_type_seedkit.svg" }, | ||
| 302 | "_fd_seedkit_open": { "iconPath": "../../icons/folder_type_seedkit_opened.svg" }, | ||
| 303 | "_fd_server": { "iconPath": "../../icons/folder_type_server.svg" }, | ||
| 304 | "_fd_server_open": { "iconPath": "../../icons/folder_type_server_opened.svg" }, | ||
| 305 | "_fd_services": { "iconPath": "../../icons/folder_type_services.svg" }, | ||
| 306 | "_fd_services_open": { "iconPath": "../../icons/folder_type_services_opened.svg" }, | ||
| 307 | "_fd_shared": { "iconPath": "../../icons/folder_type_shared.svg" }, | ||
| 308 | "_fd_shared_open": { "iconPath": "../../icons/folder_type_shared_opened.svg" }, | ||
| 309 | "_fd_snaplet": { "iconPath": "../../icons/folder_type_snaplet.svg" }, | ||
| 310 | "_fd_snaplet_open": { "iconPath": "../../icons/folder_type_snaplet_opened.svg" }, | ||
| 311 | "_fd_spin": { "iconPath": "../../icons/folder_type_spin.svg" }, | ||
| 312 | "_fd_spin_open": { "iconPath": "../../icons/folder_type_spin_opened.svg" }, | ||
| 313 | "_fd_src": { "iconPath": "../../icons/folder_type_src.svg" }, | ||
| 314 | "_fd_src_open": { "iconPath": "../../icons/folder_type_src_opened.svg" }, | ||
| 315 | "_fd_sso": { "iconPath": "../../icons/folder_type_sso.svg" }, | ||
| 316 | "_fd_sso_open": { "iconPath": "../../icons/folder_type_sso_opened.svg" }, | ||
| 317 | "_fd_story": { "iconPath": "../../icons/folder_type_story.svg" }, | ||
| 318 | "_fd_story_open": { "iconPath": "../../icons/folder_type_story_opened.svg" }, | ||
| 319 | "_fd_style": { "iconPath": "../../icons/folder_type_style.svg" }, | ||
| 320 | "_fd_style_open": { "iconPath": "../../icons/folder_type_style_opened.svg" }, | ||
| 321 | "_fd_supabase": { "iconPath": "../../icons/folder_type_supabase.svg" }, | ||
| 322 | "_fd_supabase_open": { "iconPath": "../../icons/folder_type_supabase_opened.svg" }, | ||
| 323 | "_fd_svelte": { "iconPath": "../../icons/folder_type_svelte.svg" }, | ||
| 324 | "_fd_svelte_open": { "iconPath": "../../icons/folder_type_svelte_opened.svg" }, | ||
| 325 | "_fd_tauri": { "iconPath": "../../icons/folder_type_tauri.svg" }, | ||
| 326 | "_fd_tauri_open": { "iconPath": "../../icons/folder_type_tauri_opened.svg" }, | ||
| 327 | "_fd_temp": { "iconPath": "../../icons/folder_type_temp.svg" }, | ||
| 328 | "_fd_temp_open": { "iconPath": "../../icons/folder_type_temp_opened.svg" }, | ||
| 329 | "_fd_template": { "iconPath": "../../icons/folder_type_template.svg" }, | ||
| 330 | "_fd_template_open": { "iconPath": "../../icons/folder_type_template_opened.svg" }, | ||
| 331 | "_fd_test": { "iconPath": "../../icons/folder_type_test.svg" }, | ||
| 332 | "_fd_test_open": { "iconPath": "../../icons/folder_type_test_opened.svg" }, | ||
| 333 | "_fd_theme": { "iconPath": "../../icons/folder_type_theme.svg" }, | ||
| 334 | "_fd_theme_open": { "iconPath": "../../icons/folder_type_theme_opened.svg" }, | ||
| 335 | "_fd_tools": { "iconPath": "../../icons/folder_type_tools.svg" }, | ||
| 336 | "_fd_tools_open": { "iconPath": "../../icons/folder_type_tools_opened.svg" }, | ||
| 337 | "_fd_travis": { "iconPath": "../../icons/folder_type_travis.svg" }, | ||
| 338 | "_fd_travis_open": { "iconPath": "../../icons/folder_type_travis_opened.svg" }, | ||
| 339 | "_fd_trunk": { "iconPath": "../../icons/folder_type_trunk.svg" }, | ||
| 340 | "_fd_trunk_open": { "iconPath": "../../icons/folder_type_trunk_opened.svg" }, | ||
| 341 | "_fd_turbo": { "iconPath": "../../icons/folder_type_turbo.svg" }, | ||
| 342 | "_fd_turbo_open": { "iconPath": "../../icons/folder_type_turbo_opened.svg" }, | ||
| 343 | "_fd_typescript": { "iconPath": "../../icons/folder_type_typescript.svg" }, | ||
| 344 | "_fd_typescript_open": { "iconPath": "../../icons/folder_type_typescript_opened.svg" }, | ||
| 345 | "_fd_typings": { "iconPath": "../../icons/folder_type_typings.svg" }, | ||
| 346 | "_fd_typings_open": { "iconPath": "../../icons/folder_type_typings_opened.svg" }, | ||
| 347 | "_fd_vagrant": { "iconPath": "../../icons/folder_type_vagrant.svg" }, | ||
| 348 | "_fd_vagrant_open": { "iconPath": "../../icons/folder_type_vagrant_opened.svg" }, | ||
| 349 | "_fd_vercel": { "iconPath": "../../icons/folder_type_vercel.svg" }, | ||
| 350 | "_fd_vercel_open": { "iconPath": "../../icons/folder_type_vercel_opened.svg" }, | ||
| 351 | "_fd_video": { "iconPath": "../../icons/folder_type_video.svg" }, | ||
| 352 | "_fd_video_open": { "iconPath": "../../icons/folder_type_video_opened.svg" }, | ||
| 353 | "_fd_view": { "iconPath": "../../icons/folder_type_view.svg" }, | ||
| 354 | "_fd_view_open": { "iconPath": "../../icons/folder_type_view_opened.svg" }, | ||
| 355 | "_fd_vitepress": { "iconPath": "../../icons/folder_type_vitepress.svg" }, | ||
| 356 | "_fd_vitepress_open": { "iconPath": "../../icons/folder_type_vitepress_opened.svg" }, | ||
| 357 | "_fd_vs": { "iconPath": "../../icons/folder_type_vs.svg" }, | ||
| 358 | "_fd_vs_open": { "iconPath": "../../icons/folder_type_vs_opened.svg" }, | ||
| 359 | "_fd_vscode": { "iconPath": "../../icons/folder_type_vscode.svg" }, | ||
| 360 | "_fd_vscode_open": { "iconPath": "../../icons/folder_type_vscode_opened.svg" }, | ||
| 361 | "_fd_vscode_test": { "iconPath": "../../icons/folder_type_vscode_test.svg" }, | ||
| 362 | "_fd_vscode_test_open": { "iconPath": "../../icons/folder_type_vscode_test_opened.svg" }, | ||
| 363 | "_fd_wasm": { "iconPath": "../../icons/folder_type_wasm.svg" }, | ||
| 364 | "_fd_wasm_open": { "iconPath": "../../icons/folder_type_wasm_opened.svg" }, | ||
| 365 | "_fd_webpack": { "iconPath": "../../icons/folder_type_webpack.svg" }, | ||
| 366 | "_fd_webpack_open": { "iconPath": "../../icons/folder_type_webpack_opened.svg" }, | ||
| 367 | "_fd_windows": { "iconPath": "../../icons/folder_type_windows.svg" }, | ||
| 368 | "_fd_windows_open": { "iconPath": "../../icons/folder_type_windows_opened.svg" }, | ||
| 369 | "_fd_windsurf": { "iconPath": "../../icons/folder_type_windsurf.svg" }, | ||
| 370 | "_fd_windsurf_open": { "iconPath": "../../icons/folder_type_windsurf_opened.svg" }, | ||
| 371 | "_fd_wit": { "iconPath": "../../icons/folder_type_wit.svg" }, | ||
| 372 | "_fd_wit_open": { "iconPath": "../../icons/folder_type_wit_opened.svg" }, | ||
| 373 | "_fd_www": { "iconPath": "../../icons/folder_type_www.svg" }, | ||
| 374 | "_fd_www_open": { "iconPath": "../../icons/folder_type_www_opened.svg" }, | ||
| 375 | "_fd_yarn": { "iconPath": "../../icons/folder_type_yarn.svg" }, | ||
| 376 | "_fd_yarn_open": { "iconPath": "../../icons/folder_type_yarn_opened.svg" }, | ||
| 377 | "_fd_zed": { "iconPath": "../../icons/folder_type_zed.svg" }, | ||
| 378 | "_fd_zed_open": { "iconPath": "../../icons/folder_type_zed_opened.svg" }, | ||
| 379 | "_fd_light_zed": { "iconPath": "../../icons/folder_type_light_zed.svg" }, | ||
| 380 | "_fd_light_zed_open": { "iconPath": "../../icons/folder_type_light_zed_opened.svg" }, | ||
| 381 | "_f_access": { "iconPath": "../../icons/file_type_access.svg" }, | ||
| 382 | "_f_actionscript": { "iconPath": "../../icons/file_type_actionscript.svg" }, | ||
| 383 | "_f_ada": { "iconPath": "../../icons/file_type_ada.svg" }, | ||
| 384 | "_f_light_ada": { "iconPath": "../../icons/file_type_light_ada.svg" }, | ||
| 385 | "_f_advpl": { "iconPath": "../../icons/file_type_advpl.svg" }, | ||
| 386 | "_f_affectscript": { "iconPath": "../../icons/file_type_affectscript.svg" }, | ||
| 387 | "_f_affinity": { "iconPath": "../../icons/file_type_affinity.svg" }, | ||
| 388 | "_f_affinitydesigner": { "iconPath": "../../icons/file_type_affinitydesigner.svg" }, | ||
| 389 | "_f_affinityphoto": { "iconPath": "../../icons/file_type_affinityphoto.svg" }, | ||
| 390 | "_f_affinitypublisher": { "iconPath": "../../icons/file_type_affinitypublisher.svg" }, | ||
| 391 | "_f_agda": { "iconPath": "../../icons/file_type_agda.svg" }, | ||
| 392 | "_f_light_agda": { "iconPath": "../../icons/file_type_light_agda.svg" }, | ||
| 393 | "_f_agents": { "iconPath": "../../icons/file_type_agents.svg" }, | ||
| 394 | "_f_light_agents": { "iconPath": "../../icons/file_type_light_agents.svg" }, | ||
| 395 | "_f_ai": { "iconPath": "../../icons/file_type_ai.svg" }, | ||
| 396 | "_f_al": { "iconPath": "../../icons/file_type_al.svg" }, | ||
| 397 | "_f_al_dal": { "iconPath": "../../icons/file_type_al_dal.svg" }, | ||
| 398 | "_f_alchemy": { "iconPath": "../../icons/file_type_alchemy.svg" }, | ||
| 399 | "_f_allcontributors": { "iconPath": "../../icons/file_type_allcontributors.svg" }, | ||
| 400 | "_f_alloy": { "iconPath": "../../icons/file_type_alloy.svg" }, | ||
| 401 | "_f_allure": { "iconPath": "../../icons/file_type_allure.svg" }, | ||
| 402 | "_f_angular": { "iconPath": "../../icons/file_type_angular.svg" }, | ||
| 403 | "_f_ansible": { "iconPath": "../../icons/file_type_ansible.svg" }, | ||
| 404 | "_f_antlers_html": { "iconPath": "../../icons/file_type_antlers_html.svg" }, | ||
| 405 | "_f_antlr": { "iconPath": "../../icons/file_type_antlr.svg" }, | ||
| 406 | "_f_anyscript": { "iconPath": "../../icons/file_type_anyscript.svg" }, | ||
| 407 | "_f_apache": { "iconPath": "../../icons/file_type_apache.svg" }, | ||
| 408 | "_f_apex": { "iconPath": "../../icons/file_type_apex.svg" }, | ||
| 409 | "_f_api_extractor": { "iconPath": "../../icons/file_type_api_extractor.svg" }, | ||
| 410 | "_f_apib": { "iconPath": "../../icons/file_type_apib.svg" }, | ||
| 411 | "_f_apl": { "iconPath": "../../icons/file_type_apl.svg" }, | ||
| 412 | "_f_light_apl": { "iconPath": "../../icons/file_type_light_apl.svg" }, | ||
| 413 | "_f_applescript": { "iconPath": "../../icons/file_type_applescript.svg" }, | ||
| 414 | "_f_appscript": { "iconPath": "../../icons/file_type_appscript.svg" }, | ||
| 415 | "_f_appsemble": { "iconPath": "../../icons/file_type_appsemble.svg" }, | ||
| 416 | "_f_appveyor": { "iconPath": "../../icons/file_type_appveyor.svg" }, | ||
| 417 | "_f_arduino": { "iconPath": "../../icons/file_type_arduino.svg" }, | ||
| 418 | "_f_asciidoc": { "iconPath": "../../icons/file_type_asciidoc.svg" }, | ||
| 419 | "_f_aseprite": { "iconPath": "../../icons/file_type_aseprite.svg" }, | ||
| 420 | "_f_asp": { "iconPath": "../../icons/file_type_asp.svg" }, | ||
| 421 | "_f_aspx": { "iconPath": "../../icons/file_type_aspx.svg" }, | ||
| 422 | "_f_assembly": { "iconPath": "../../icons/file_type_assembly.svg" }, | ||
| 423 | "_f_assembly_script": { "iconPath": "../../icons/file_type_assembly_script.svg" }, | ||
| 424 | "_f_astro": { "iconPath": "../../icons/file_type_astro.svg" }, | ||
| 425 | "_f_light_astro": { "iconPath": "../../icons/file_type_light_astro.svg" }, | ||
| 426 | "_f_astroconfig": { "iconPath": "../../icons/file_type_astroconfig.svg" }, | ||
| 427 | "_f_light_astroconfig": { "iconPath": "../../icons/file_type_light_astroconfig.svg" }, | ||
| 428 | "_f_atom": { "iconPath": "../../icons/file_type_atom.svg" }, | ||
| 429 | "_f_ats": { "iconPath": "../../icons/file_type_ats.svg" }, | ||
| 430 | "_f_attw": { "iconPath": "../../icons/file_type_attw.svg" }, | ||
| 431 | "_f_audio": { "iconPath": "../../icons/file_type_audio.svg" }, | ||
| 432 | "_f_aurelia": { "iconPath": "../../icons/file_type_aurelia.svg" }, | ||
| 433 | "_f_autohotkey": { "iconPath": "../../icons/file_type_autohotkey.svg" }, | ||
| 434 | "_f_autoit": { "iconPath": "../../icons/file_type_autoit.svg" }, | ||
| 435 | "_f_avif": { "iconPath": "../../icons/file_type_avif.svg" }, | ||
| 436 | "_f_avro": { "iconPath": "../../icons/file_type_avro.svg" }, | ||
| 437 | "_f_awk": { "iconPath": "../../icons/file_type_awk.svg" }, | ||
| 438 | "_f_aws": { "iconPath": "../../icons/file_type_aws.svg" }, | ||
| 439 | "_f_azure": { "iconPath": "../../icons/file_type_azure.svg" }, | ||
| 440 | "_f_azurepipelines": { "iconPath": "../../icons/file_type_azurepipelines.svg" }, | ||
| 441 | "_f_babel": { "iconPath": "../../icons/file_type_babel.svg" }, | ||
| 442 | "_f_light_babel": { "iconPath": "../../icons/file_type_light_babel.svg" }, | ||
| 443 | "_f_bak": { "iconPath": "../../icons/file_type_bak.svg" }, | ||
| 444 | "_f_ballerina": { "iconPath": "../../icons/file_type_ballerina.svg" }, | ||
| 445 | "_f_bat": { "iconPath": "../../icons/file_type_bat.svg" }, | ||
| 446 | "_f_bats": { "iconPath": "../../icons/file_type_bats.svg" }, | ||
| 447 | "_f_bazaar": { "iconPath": "../../icons/file_type_bazaar.svg" }, | ||
| 448 | "_f_bazel": { "iconPath": "../../icons/file_type_bazel.svg" }, | ||
| 449 | "_f_bazel_ignore": { "iconPath": "../../icons/file_type_bazel_ignore.svg" }, | ||
| 450 | "_f_bazel_version": { "iconPath": "../../icons/file_type_bazel_version.svg" }, | ||
| 451 | "_f_befunge": { "iconPath": "../../icons/file_type_befunge.svg" }, | ||
| 452 | "_f_bicep": { "iconPath": "../../icons/file_type_bicep.svg" }, | ||
| 453 | "_f_biml": { "iconPath": "../../icons/file_type_biml.svg" }, | ||
| 454 | "_f_binary": { "iconPath": "../../icons/file_type_binary.svg" }, | ||
| 455 | "_f_biome": { "iconPath": "../../icons/file_type_biome.svg" }, | ||
| 456 | "_f_bitbucketpipeline": { "iconPath": "../../icons/file_type_bitbucketpipeline.svg" }, | ||
| 457 | "_f_bithound": { "iconPath": "../../icons/file_type_bithound.svg" }, | ||
| 458 | "_f_blade": { "iconPath": "../../icons/file_type_blade.svg" }, | ||
| 459 | "_f_blender": { "iconPath": "../../icons/file_type_blender.svg" }, | ||
| 460 | "_f_blitzbasic": { "iconPath": "../../icons/file_type_blitzbasic.svg" }, | ||
| 461 | "_f_bolt": { "iconPath": "../../icons/file_type_bolt.svg" }, | ||
| 462 | "_f_bosque": { "iconPath": "../../icons/file_type_bosque.svg" }, | ||
| 463 | "_f_bower": { "iconPath": "../../icons/file_type_bower.svg" }, | ||
| 464 | "_f_browserslist": { "iconPath": "../../icons/file_type_browserslist.svg" }, | ||
| 465 | "_f_bruno": { "iconPath": "../../icons/file_type_bruno.svg" }, | ||
| 466 | "_f_buckbuild": { "iconPath": "../../icons/file_type_buckbuild.svg" }, | ||
| 467 | "_f_buf": { "iconPath": "../../icons/file_type_buf.svg" }, | ||
| 468 | "_f_bun": { "iconPath": "../../icons/file_type_bun.svg" }, | ||
| 469 | "_f_bundlemon": { "iconPath": "../../icons/file_type_bundlemon.svg" }, | ||
| 470 | "_f_bundler": { "iconPath": "../../icons/file_type_bundler.svg" }, | ||
| 471 | "_f_bunfig": { "iconPath": "../../icons/file_type_bunfig.svg" }, | ||
| 472 | "_f_c": { "iconPath": "../../icons/file_type_c.svg" }, | ||
| 473 | "_f_c3": { "iconPath": "../../icons/file_type_c3.svg" }, | ||
| 474 | "_f_c_al": { "iconPath": "../../icons/file_type_c_al.svg" }, | ||
| 475 | "_f_cabal": { "iconPath": "../../icons/file_type_cabal.svg" }, | ||
| 476 | "_f_caddy": { "iconPath": "../../icons/file_type_caddy.svg" }, | ||
| 477 | "_f_cake": { "iconPath": "../../icons/file_type_cake.svg" }, | ||
| 478 | "_f_cakephp": { "iconPath": "../../icons/file_type_cakephp.svg" }, | ||
| 479 | "_f_capacitor": { "iconPath": "../../icons/file_type_capacitor.svg" }, | ||
| 480 | "_f_capnp": { "iconPath": "../../icons/file_type_capnp.svg" }, | ||
| 481 | "_f_cargo": { "iconPath": "../../icons/file_type_cargo.svg" }, | ||
| 482 | "_f_casc": { "iconPath": "../../icons/file_type_casc.svg" }, | ||
| 483 | "_f_cddl": { "iconPath": "../../icons/file_type_cddl.svg" }, | ||
| 484 | "_f_cert": { "iconPath": "../../icons/file_type_cert.svg" }, | ||
| 485 | "_f_ceylon": { "iconPath": "../../icons/file_type_ceylon.svg" }, | ||
| 486 | "_f_cf": { "iconPath": "../../icons/file_type_cf.svg" }, | ||
| 487 | "_f_cfc": { "iconPath": "../../icons/file_type_cfc.svg" }, | ||
| 488 | "_f_cfm": { "iconPath": "../../icons/file_type_cfm.svg" }, | ||
| 489 | "_f_changie": { "iconPath": "../../icons/file_type_changie.svg" }, | ||
| 490 | "_f_cheader": { "iconPath": "../../icons/file_type_cheader.svg" }, | ||
| 491 | "_f_chef": { "iconPath": "../../icons/file_type_chef.svg" }, | ||
| 492 | "_f_chef_cookbook": { "iconPath": "../../icons/file_type_chef_cookbook.svg" }, | ||
| 493 | "_f_circleci": { "iconPath": "../../icons/file_type_circleci.svg" }, | ||
| 494 | "_f_light_circleci": { "iconPath": "../../icons/file_type_light_circleci.svg" }, | ||
| 495 | "_f_circom": { "iconPath": "../../icons/file_type_circom.svg" }, | ||
| 496 | "_f_class": { "iconPath": "../../icons/file_type_class.svg" }, | ||
| 497 | "_f_claude": { "iconPath": "../../icons/file_type_claude.svg" }, | ||
| 498 | "_f_clojure": { "iconPath": "../../icons/file_type_clojure.svg" }, | ||
| 499 | "_f_clojurescript": { "iconPath": "../../icons/file_type_clojurescript.svg" }, | ||
| 500 | "_f_cloudflare": { "iconPath": "../../icons/file_type_cloudflare.svg" }, | ||
| 501 | "_f_cloudfoundry": { "iconPath": "../../icons/file_type_cloudfoundry.svg" }, | ||
| 502 | "_f_light_cloudfoundry": { "iconPath": "../../icons/file_type_light_cloudfoundry.svg" }, | ||
| 503 | "_f_cmake": { "iconPath": "../../icons/file_type_cmake.svg" }, | ||
| 504 | "_f_cobol": { "iconPath": "../../icons/file_type_cobol.svg" }, | ||
| 505 | "_f_codacy": { "iconPath": "../../icons/file_type_codacy.svg" }, | ||
| 506 | "_f_light_codacy": { "iconPath": "../../icons/file_type_light_codacy.svg" }, | ||
| 507 | "_f_codeclimate": { "iconPath": "../../icons/file_type_codeclimate.svg" }, | ||
| 508 | "_f_light_codeclimate": { "iconPath": "../../icons/file_type_light_codeclimate.svg" }, | ||
| 509 | "_f_codecov": { "iconPath": "../../icons/file_type_codecov.svg" }, | ||
| 510 | "_f_codekit": { "iconPath": "../../icons/file_type_codekit.svg" }, | ||
| 511 | "_f_codemagic": { "iconPath": "../../icons/file_type_codemagic.svg" }, | ||
| 512 | "_f_codeowners": { "iconPath": "../../icons/file_type_codeowners.svg" }, | ||
| 513 | "_f_light_codeowners": { "iconPath": "../../icons/file_type_light_codeowners.svg" }, | ||
| 514 | "_f_codeql": { "iconPath": "../../icons/file_type_codeql.svg" }, | ||
| 515 | "_f_coderabbit": { "iconPath": "../../icons/file_type_coderabbit.svg" }, | ||
| 516 | "_f_coffeelint": { "iconPath": "../../icons/file_type_coffeelint.svg" }, | ||
| 517 | "_f_coffeescript": { "iconPath": "../../icons/file_type_coffeescript.svg" }, | ||
| 518 | "_f_commitizen": { "iconPath": "../../icons/file_type_commitizen.svg" }, | ||
| 519 | "_f_commitlint": { "iconPath": "../../icons/file_type_commitlint.svg" }, | ||
| 520 | "_f_compass": { "iconPath": "../../icons/file_type_compass.svg" }, | ||
| 521 | "_f_composer": { "iconPath": "../../icons/file_type_composer.svg" }, | ||
| 522 | "_f_conan": { "iconPath": "../../icons/file_type_conan.svg" }, | ||
| 523 | "_f_conda": { "iconPath": "../../icons/file_type_conda.svg" }, | ||
| 524 | "_f_config": { "iconPath": "../../icons/file_type_config.svg" }, | ||
| 525 | "_f_light_config": { "iconPath": "../../icons/file_type_light_config.svg" }, | ||
| 526 | "_f_confluence": { "iconPath": "../../icons/file_type_confluence.svg" }, | ||
| 527 | "_f_copilot": { "iconPath": "../../icons/file_type_copilot.svg" }, | ||
| 528 | "_f_light_copilot": { "iconPath": "../../icons/file_type_light_copilot.svg" }, | ||
| 529 | "_f_coverage": { "iconPath": "../../icons/file_type_coverage.svg" }, | ||
| 530 | "_f_coveralls": { "iconPath": "../../icons/file_type_coveralls.svg" }, | ||
| 531 | "_f_cpp": { "iconPath": "../../icons/file_type_cpp.svg" }, | ||
| 532 | "_f_cppheader": { "iconPath": "../../icons/file_type_cppheader.svg" }, | ||
| 533 | "_f_craco": { "iconPath": "../../icons/file_type_craco.svg" }, | ||
| 534 | "_f_crowdin": { "iconPath": "../../icons/file_type_crowdin.svg" }, | ||
| 535 | "_f_crystal": { "iconPath": "../../icons/file_type_crystal.svg" }, | ||
| 536 | "_f_light_crystal": { "iconPath": "../../icons/file_type_light_crystal.svg" }, | ||
| 537 | "_f_csharp": { "iconPath": "../../icons/file_type_csharp.svg" }, | ||
| 538 | "_f_cspell": { "iconPath": "../../icons/file_type_cspell.svg" }, | ||
| 539 | "_f_csproj": { "iconPath": "../../icons/file_type_csproj.svg" }, | ||
| 540 | "_f_css": { "iconPath": "../../icons/file_type_css.svg" }, | ||
| 541 | "_f_csscomb": { "iconPath": "../../icons/file_type_csscomb.svg" }, | ||
| 542 | "_f_csslint": { "iconPath": "../../icons/file_type_csslint.svg" }, | ||
| 543 | "_f_cssmap": { "iconPath": "../../icons/file_type_cssmap.svg" }, | ||
| 544 | "_f_cucumber": { "iconPath": "../../icons/file_type_cucumber.svg" }, | ||
| 545 | "_f_cuda": { "iconPath": "../../icons/file_type_cuda.svg" }, | ||
| 546 | "_f_cursorrules": { "iconPath": "../../icons/file_type_cursorrules.svg" }, | ||
| 547 | "_f_cvs": { "iconPath": "../../icons/file_type_cvs.svg" }, | ||
| 548 | "_f_cypress": { "iconPath": "../../icons/file_type_cypress.svg" }, | ||
| 549 | "_f_light_cypress": { "iconPath": "../../icons/file_type_light_cypress.svg" }, | ||
| 550 | "_f_cypress_spec": { "iconPath": "../../icons/file_type_cypress_spec.svg" }, | ||
| 551 | "_f_light_cypress_spec": { "iconPath": "../../icons/file_type_light_cypress_spec.svg" }, | ||
| 552 | "_f_cython": { "iconPath": "../../icons/file_type_cython.svg" }, | ||
| 553 | "_f_dal": { "iconPath": "../../icons/file_type_dal.svg" }, | ||
| 554 | "_f_darcs": { "iconPath": "../../icons/file_type_darcs.svg" }, | ||
| 555 | "_f_dartlang": { "iconPath": "../../icons/file_type_dartlang.svg" }, | ||
| 556 | "_f_dartlang_generated": { "iconPath": "../../icons/file_type_dartlang_generated.svg" }, | ||
| 557 | "_f_dartlang_ignore": { "iconPath": "../../icons/file_type_dartlang_ignore.svg" }, | ||
| 558 | "_f_datadog": { "iconPath": "../../icons/file_type_datadog.svg" }, | ||
| 559 | "_f_db": { "iconPath": "../../icons/file_type_db.svg" }, | ||
| 560 | "_f_light_db": { "iconPath": "../../icons/file_type_light_db.svg" }, | ||
| 561 | "_f_debian": { "iconPath": "../../icons/file_type_debian.svg" }, | ||
| 562 | "_f_delphi": { "iconPath": "../../icons/file_type_delphi.svg" }, | ||
| 563 | "_f_deno": { "iconPath": "../../icons/file_type_deno.svg" }, | ||
| 564 | "_f_denoify": { "iconPath": "../../icons/file_type_denoify.svg" }, | ||
| 565 | "_f_dependabot": { "iconPath": "../../icons/file_type_dependabot.svg" }, | ||
| 566 | "_f_dependencies": { "iconPath": "../../icons/file_type_dependencies.svg" }, | ||
| 567 | "_f_design_tokens": { "iconPath": "../../icons/file_type_design_tokens.svg" }, | ||
| 568 | "_f_devcontainer": { "iconPath": "../../icons/file_type_devcontainer.svg" }, | ||
| 569 | "_f_devvit": { "iconPath": "../../icons/file_type_devvit.svg" }, | ||
| 570 | "_f_dhall": { "iconPath": "../../icons/file_type_dhall.svg" }, | ||
| 571 | "_f_light_dhall": { "iconPath": "../../icons/file_type_light_dhall.svg" }, | ||
| 572 | "_f_diff": { "iconPath": "../../icons/file_type_diff.svg" }, | ||
| 573 | "_f_django": { "iconPath": "../../icons/file_type_django.svg" }, | ||
| 574 | "_f_dlang": { "iconPath": "../../icons/file_type_dlang.svg" }, | ||
| 575 | "_f_docker": { "iconPath": "../../icons/file_type_docker.svg" }, | ||
| 576 | "_f_dockertest": { "iconPath": "../../icons/file_type_dockertest.svg" }, | ||
| 577 | "_f_docpad": { "iconPath": "../../icons/file_type_docpad.svg" }, | ||
| 578 | "_f_light_docpad": { "iconPath": "../../icons/file_type_light_docpad.svg" }, | ||
| 579 | "_f_docusaurus": { "iconPath": "../../icons/file_type_docusaurus.svg" }, | ||
| 580 | "_f_docz": { "iconPath": "../../icons/file_type_docz.svg" }, | ||
| 581 | "_f_dojo": { "iconPath": "../../icons/file_type_dojo.svg" }, | ||
| 582 | "_f_doppler": { "iconPath": "../../icons/file_type_doppler.svg" }, | ||
| 583 | "_f_dotenv": { "iconPath": "../../icons/file_type_dotenv.svg" }, | ||
| 584 | "_f_dotjs": { "iconPath": "../../icons/file_type_dotjs.svg" }, | ||
| 585 | "_f_doxygen": { "iconPath": "../../icons/file_type_doxygen.svg" }, | ||
| 586 | "_f_drawio": { "iconPath": "../../icons/file_type_drawio.svg" }, | ||
| 587 | "_f_drone": { "iconPath": "../../icons/file_type_drone.svg" }, | ||
| 588 | "_f_light_drone": { "iconPath": "../../icons/file_type_light_drone.svg" }, | ||
| 589 | "_f_drools": { "iconPath": "../../icons/file_type_drools.svg" }, | ||
| 590 | "_f_dtd": { "iconPath": "../../icons/file_type_dtd.svg" }, | ||
| 591 | "_f_dune": { "iconPath": "../../icons/file_type_dune.svg" }, | ||
| 592 | "_f_dustjs": { "iconPath": "../../icons/file_type_dustjs.svg" }, | ||
| 593 | "_f_dvc": { "iconPath": "../../icons/file_type_dvc.svg" }, | ||
| 594 | "_f_dylan": { "iconPath": "../../icons/file_type_dylan.svg" }, | ||
| 595 | "_f_earthly": { "iconPath": "../../icons/file_type_earthly.svg" }, | ||
| 596 | "_f_eas-metadata": { "iconPath": "../../icons/file_type_eas-metadata.svg" }, | ||
| 597 | "_f_light_eas-metadata": { "iconPath": "../../icons/file_type_light_eas-metadata.svg" }, | ||
| 598 | "_f_edge": { "iconPath": "../../icons/file_type_edge.svg" }, | ||
| 599 | "_f_editorconfig": { "iconPath": "../../icons/file_type_editorconfig.svg" }, | ||
| 600 | "_f_eex": { "iconPath": "../../icons/file_type_eex.svg" }, | ||
| 601 | "_f_ejs": { "iconPath": "../../icons/file_type_ejs.svg" }, | ||
| 602 | "_f_elastic": { "iconPath": "../../icons/file_type_elastic.svg" }, | ||
| 603 | "_f_elasticbeanstalk": { "iconPath": "../../icons/file_type_elasticbeanstalk.svg" }, | ||
| 604 | "_f_electron": { "iconPath": "../../icons/file_type_electron.svg" }, | ||
| 605 | "_f_eleventy": { "iconPath": "../../icons/file_type_eleventy.svg" }, | ||
| 606 | "_f_light_eleventy": { "iconPath": "../../icons/file_type_light_eleventy.svg" }, | ||
| 607 | "_f_elixir": { "iconPath": "../../icons/file_type_elixir.svg" }, | ||
| 608 | "_f_elm": { "iconPath": "../../icons/file_type_elm.svg" }, | ||
| 609 | "_f_emacs": { "iconPath": "../../icons/file_type_emacs.svg" }, | ||
| 610 | "_f_ember": { "iconPath": "../../icons/file_type_ember.svg" }, | ||
| 611 | "_f_ensime": { "iconPath": "../../icons/file_type_ensime.svg" }, | ||
| 612 | "_f_eps": { "iconPath": "../../icons/file_type_eps.svg" }, | ||
| 613 | "_f_epub": { "iconPath": "../../icons/file_type_epub.svg" }, | ||
| 614 | "_f_erb": { "iconPath": "../../icons/file_type_erb.svg" }, | ||
| 615 | "_f_erlang": { "iconPath": "../../icons/file_type_erlang.svg" }, | ||
| 616 | "_f_esbuild": { "iconPath": "../../icons/file_type_esbuild.svg" }, | ||
| 617 | "_f_eslint": { "iconPath": "../../icons/file_type_eslint.svg" }, | ||
| 618 | "_f_esphome": { "iconPath": "../../icons/file_type_esphome.svg" }, | ||
| 619 | "_f_light_esphome": { "iconPath": "../../icons/file_type_light_esphome.svg" }, | ||
| 620 | "_f_excalidraw": { "iconPath": "../../icons/file_type_excalidraw.svg" }, | ||
| 621 | "_f_excel": { "iconPath": "../../icons/file_type_excel.svg" }, | ||
| 622 | "_f_expo": { "iconPath": "../../icons/file_type_expo.svg" }, | ||
| 623 | "_f_light_expo": { "iconPath": "../../icons/file_type_light_expo.svg" }, | ||
| 624 | "_f_falcon": { "iconPath": "../../icons/file_type_falcon.svg" }, | ||
| 625 | "_f_fantasticon": { "iconPath": "../../icons/file_type_fantasticon.svg" }, | ||
| 626 | "_f_fastly": { "iconPath": "../../icons/file_type_fastly.svg" }, | ||
| 627 | "_f_fauna": { "iconPath": "../../icons/file_type_fauna.svg" }, | ||
| 628 | "_f_favicon": { "iconPath": "../../icons/file_type_favicon.svg" }, | ||
| 629 | "_f_fbx": { "iconPath": "../../icons/file_type_fbx.svg" }, | ||
| 630 | "_f_firebase": { "iconPath": "../../icons/file_type_firebase.svg" }, | ||
| 631 | "_f_firebasehosting": { "iconPath": "../../icons/file_type_firebasehosting.svg" }, | ||
| 632 | "_f_light_firebasehosting": { "iconPath": "../../icons/file_type_light_firebasehosting.svg" }, | ||
| 633 | "_f_firebasestorage": { "iconPath": "../../icons/file_type_firebasestorage.svg" }, | ||
| 634 | "_f_firestore": { "iconPath": "../../icons/file_type_firestore.svg" }, | ||
| 635 | "_f_fitbit": { "iconPath": "../../icons/file_type_fitbit.svg" }, | ||
| 636 | "_f_fla": { "iconPath": "../../icons/file_type_fla.svg" }, | ||
| 637 | "_f_light_fla": { "iconPath": "../../icons/file_type_light_fla.svg" }, | ||
| 638 | "_f_flareact": { "iconPath": "../../icons/file_type_flareact.svg" }, | ||
| 639 | "_f_flash": { "iconPath": "../../icons/file_type_flash.svg" }, | ||
| 640 | "_f_floobits": { "iconPath": "../../icons/file_type_floobits.svg" }, | ||
| 641 | "_f_flow": { "iconPath": "../../icons/file_type_flow.svg" }, | ||
| 642 | "_f_flutter": { "iconPath": "../../icons/file_type_flutter.svg" }, | ||
| 643 | "_f_flutter_package": { "iconPath": "../../icons/file_type_flutter_package.svg" }, | ||
| 644 | "_f_flyio": { "iconPath": "../../icons/file_type_flyio.svg" }, | ||
| 645 | "_f_font": { "iconPath": "../../icons/file_type_font.svg" }, | ||
| 646 | "_f_light_font": { "iconPath": "../../icons/file_type_light_font.svg" }, | ||
| 647 | "_f_formkit": { "iconPath": "../../icons/file_type_formkit.svg" }, | ||
| 648 | "_f_fortran": { "iconPath": "../../icons/file_type_fortran.svg" }, | ||
| 649 | "_f_fossa": { "iconPath": "../../icons/file_type_fossa.svg" }, | ||
| 650 | "_f_fossil": { "iconPath": "../../icons/file_type_fossil.svg" }, | ||
| 651 | "_f_freemarker": { "iconPath": "../../icons/file_type_freemarker.svg" }, | ||
| 652 | "_f_frontcommerce": { "iconPath": "../../icons/file_type_frontcommerce.svg" }, | ||
| 653 | "_f_fsharp": { "iconPath": "../../icons/file_type_fsharp.svg" }, | ||
| 654 | "_f_fsproj": { "iconPath": "../../icons/file_type_fsproj.svg" }, | ||
| 655 | "_f_fthtml": { "iconPath": "../../icons/file_type_fthtml.svg" }, | ||
| 656 | "_f_funding": { "iconPath": "../../icons/file_type_funding.svg" }, | ||
| 657 | "_f_fusebox": { "iconPath": "../../icons/file_type_fusebox.svg" }, | ||
| 658 | "_f_galen": { "iconPath": "../../icons/file_type_galen.svg" }, | ||
| 659 | "_f_gamemaker": { "iconPath": "../../icons/file_type_gamemaker.svg" }, | ||
| 660 | "_f_gamemaker2": { "iconPath": "../../icons/file_type_gamemaker2.svg" }, | ||
| 661 | "_f_light_gamemaker2": { "iconPath": "../../icons/file_type_light_gamemaker2.svg" }, | ||
| 662 | "_f_gamemaker81": { "iconPath": "../../icons/file_type_gamemaker81.svg" }, | ||
| 663 | "_f_gatsby": { "iconPath": "../../icons/file_type_gatsby.svg" }, | ||
| 664 | "_f_gcloud": { "iconPath": "../../icons/file_type_gcloud.svg" }, | ||
| 665 | "_f_gcode": { "iconPath": "../../icons/file_type_gcode.svg" }, | ||
| 666 | "_f_gdscript": { "iconPath": "../../icons/file_type_gdscript.svg" }, | ||
| 667 | "_f_gduid": { "iconPath": "../../icons/file_type_gduid.svg" }, | ||
| 668 | "_f_gemini": { "iconPath": "../../icons/file_type_gemini.svg" }, | ||
| 669 | "_f_genstat": { "iconPath": "../../icons/file_type_genstat.svg" }, | ||
| 670 | "_f_geojson": { "iconPath": "../../icons/file_type_geojson.svg" }, | ||
| 671 | "_f_gimp": { "iconPath": "../../icons/file_type_gimp.svg" }, | ||
| 672 | "_f_git": { "iconPath": "../../icons/file_type_git.svg" }, | ||
| 673 | "_f_gitlab": { "iconPath": "../../icons/file_type_gitlab.svg" }, | ||
| 674 | "_f_gitpod": { "iconPath": "../../icons/file_type_gitpod.svg" }, | ||
| 675 | "_f_gleam": { "iconPath": "../../icons/file_type_gleam.svg" }, | ||
| 676 | "_f_gleamconfig": { "iconPath": "../../icons/file_type_gleamconfig.svg" }, | ||
| 677 | "_f_glide": { "iconPath": "../../icons/file_type_glide.svg" }, | ||
| 678 | "_f_glimmer": { "iconPath": "../../icons/file_type_glimmer.svg" }, | ||
| 679 | "_f_glitter": { "iconPath": "../../icons/file_type_glitter.svg" }, | ||
| 680 | "_f_glsl": { "iconPath": "../../icons/file_type_glsl.svg" }, | ||
| 681 | "_f_gltf": { "iconPath": "../../icons/file_type_gltf.svg" }, | ||
| 682 | "_f_glyphs": { "iconPath": "../../icons/file_type_glyphs.svg" }, | ||
| 683 | "_f_gnu": { "iconPath": "../../icons/file_type_gnu.svg" }, | ||
| 684 | "_f_gnuplot": { "iconPath": "../../icons/file_type_gnuplot.svg" }, | ||
| 685 | "_f_go": { "iconPath": "../../icons/file_type_go.svg" }, | ||
| 686 | "_f_go_package": { "iconPath": "../../icons/file_type_go_package.svg" }, | ||
| 687 | "_f_go_work": { "iconPath": "../../icons/file_type_go_work.svg" }, | ||
| 688 | "_f_goctl": { "iconPath": "../../icons/file_type_goctl.svg" }, | ||
| 689 | "_f_godot": { "iconPath": "../../icons/file_type_godot.svg" }, | ||
| 690 | "_f_gpg": { "iconPath": "../../icons/file_type_gpg.svg" }, | ||
| 691 | "_f_gradle": { "iconPath": "../../icons/file_type_gradle.svg" }, | ||
| 692 | "_f_light_gradle": { "iconPath": "../../icons/file_type_light_gradle.svg" }, | ||
| 693 | "_f_grain": { "iconPath": "../../icons/file_type_grain.svg" }, | ||
| 694 | "_f_graphql": { "iconPath": "../../icons/file_type_graphql.svg" }, | ||
| 695 | "_f_graphql_config": { "iconPath": "../../icons/file_type_graphql_config.svg" }, | ||
| 696 | "_f_graphviz": { "iconPath": "../../icons/file_type_graphviz.svg" }, | ||
| 697 | "_f_greenkeeper": { "iconPath": "../../icons/file_type_greenkeeper.svg" }, | ||
| 698 | "_f_gridsome": { "iconPath": "../../icons/file_type_gridsome.svg" }, | ||
| 699 | "_f_grit": { "iconPath": "../../icons/file_type_grit.svg" }, | ||
| 700 | "_f_groovy": { "iconPath": "../../icons/file_type_groovy.svg" }, | ||
| 701 | "_f_grunt": { "iconPath": "../../icons/file_type_grunt.svg" }, | ||
| 702 | "_f_gulp": { "iconPath": "../../icons/file_type_gulp.svg" }, | ||
| 703 | "_f_haml": { "iconPath": "../../icons/file_type_haml.svg" }, | ||
| 704 | "_f_handlebars": { "iconPath": "../../icons/file_type_handlebars.svg" }, | ||
| 705 | "_f_harbour": { "iconPath": "../../icons/file_type_harbour.svg" }, | ||
| 706 | "_f_hardhat": { "iconPath": "../../icons/file_type_hardhat.svg" }, | ||
| 707 | "_f_hashicorp": { "iconPath": "../../icons/file_type_hashicorp.svg" }, | ||
| 708 | "_f_light_hashicorp": { "iconPath": "../../icons/file_type_light_hashicorp.svg" }, | ||
| 709 | "_f_haskell": { "iconPath": "../../icons/file_type_haskell.svg" }, | ||
| 710 | "_f_haxe": { "iconPath": "../../icons/file_type_haxe.svg" }, | ||
| 711 | "_f_haxecheckstyle": { "iconPath": "../../icons/file_type_haxecheckstyle.svg" }, | ||
| 712 | "_f_haxedevelop": { "iconPath": "../../icons/file_type_haxedevelop.svg" }, | ||
| 713 | "_f_helix": { "iconPath": "../../icons/file_type_helix.svg" }, | ||
| 714 | "_f_helm": { "iconPath": "../../icons/file_type_helm.svg" }, | ||
| 715 | "_f_histoire": { "iconPath": "../../icons/file_type_histoire.svg" }, | ||
| 716 | "_f_hjson": { "iconPath": "../../icons/file_type_hjson.svg" }, | ||
| 717 | "_f_light_hjson": { "iconPath": "../../icons/file_type_light_hjson.svg" }, | ||
| 718 | "_f_hlsl": { "iconPath": "../../icons/file_type_hlsl.svg" }, | ||
| 719 | "_f_homeassistant": { "iconPath": "../../icons/file_type_homeassistant.svg" }, | ||
| 720 | "_f_horusec": { "iconPath": "../../icons/file_type_horusec.svg" }, | ||
| 721 | "_f_host": { "iconPath": "../../icons/file_type_host.svg" }, | ||
| 722 | "_f_html": { "iconPath": "../../icons/file_type_html.svg" }, | ||
| 723 | "_f_htmlhint": { "iconPath": "../../icons/file_type_htmlhint.svg" }, | ||
| 724 | "_f_htmlvalidate": { "iconPath": "../../icons/file_type_htmlvalidate.svg" }, | ||
| 725 | "_f_http": { "iconPath": "../../icons/file_type_http.svg" }, | ||
| 726 | "_f_hugo": { "iconPath": "../../icons/file_type_hugo.svg" }, | ||
| 727 | "_f_humanstxt": { "iconPath": "../../icons/file_type_humanstxt.svg" }, | ||
| 728 | "_f_hunspell": { "iconPath": "../../icons/file_type_hunspell.svg" }, | ||
| 729 | "_f_husky": { "iconPath": "../../icons/file_type_husky.svg" }, | ||
| 730 | "_f_hy": { "iconPath": "../../icons/file_type_hy.svg" }, | ||
| 731 | "_f_hygen": { "iconPath": "../../icons/file_type_hygen.svg" }, | ||
| 732 | "_f_hypr": { "iconPath": "../../icons/file_type_hypr.svg" }, | ||
| 733 | "_f_icl": { "iconPath": "../../icons/file_type_icl.svg" }, | ||
| 734 | "_f_idris": { "iconPath": "../../icons/file_type_idris.svg" }, | ||
| 735 | "_f_idrisbin": { "iconPath": "../../icons/file_type_idrisbin.svg" }, | ||
| 736 | "_f_idrispkg": { "iconPath": "../../icons/file_type_idrispkg.svg" }, | ||
| 737 | "_f_image": { "iconPath": "../../icons/file_type_image.svg" }, | ||
| 738 | "_f_imba": { "iconPath": "../../icons/file_type_imba.svg" }, | ||
| 739 | "_f_inc": { "iconPath": "../../icons/file_type_inc.svg" }, | ||
| 740 | "_f_infopath": { "iconPath": "../../icons/file_type_infopath.svg" }, | ||
| 741 | "_f_informix": { "iconPath": "../../icons/file_type_informix.svg" }, | ||
| 742 | "_f_ini": { "iconPath": "../../icons/file_type_ini.svg" }, | ||
| 743 | "_f_light_ini": { "iconPath": "../../icons/file_type_light_ini.svg" }, | ||
| 744 | "_f_ink": { "iconPath": "../../icons/file_type_ink.svg" }, | ||
| 745 | "_f_innosetup": { "iconPath": "../../icons/file_type_innosetup.svg" }, | ||
| 746 | "_f_io": { "iconPath": "../../icons/file_type_io.svg" }, | ||
| 747 | "_f_light_io": { "iconPath": "../../icons/file_type_light_io.svg" }, | ||
| 748 | "_f_iodine": { "iconPath": "../../icons/file_type_iodine.svg" }, | ||
| 749 | "_f_ionic": { "iconPath": "../../icons/file_type_ionic.svg" }, | ||
| 750 | "_f_jake": { "iconPath": "../../icons/file_type_jake.svg" }, | ||
| 751 | "_f_janet": { "iconPath": "../../icons/file_type_janet.svg" }, | ||
| 752 | "_f_jar": { "iconPath": "../../icons/file_type_jar.svg" }, | ||
| 753 | "_f_jasmine": { "iconPath": "../../icons/file_type_jasmine.svg" }, | ||
| 754 | "_f_java": { "iconPath": "../../icons/file_type_java.svg" }, | ||
| 755 | "_f_jbuilder": { "iconPath": "../../icons/file_type_jbuilder.svg" }, | ||
| 756 | "_f_jekyll": { "iconPath": "../../icons/file_type_jekyll.svg" }, | ||
| 757 | "_f_jenkins": { "iconPath": "../../icons/file_type_jenkins.svg" }, | ||
| 758 | "_f_jest": { "iconPath": "../../icons/file_type_jest.svg" }, | ||
| 759 | "_f_jest_snapshot": { "iconPath": "../../icons/file_type_jest_snapshot.svg" }, | ||
| 760 | "_f_jetbrains": { "iconPath": "../../icons/file_type_jetbrains.svg" }, | ||
| 761 | "_f_jinja": { "iconPath": "../../icons/file_type_jinja.svg" }, | ||
| 762 | "_f_jpm": { "iconPath": "../../icons/file_type_jpm.svg" }, | ||
| 763 | "_f_js": { "iconPath": "../../icons/file_type_js.svg" }, | ||
| 764 | "_f_light_js": { "iconPath": "../../icons/file_type_light_js.svg" }, | ||
| 765 | "_f_jsbeautify": { "iconPath": "../../icons/file_type_jsbeautify.svg" }, | ||
| 766 | "_f_jsconfig": { "iconPath": "../../icons/file_type_jsconfig.svg" }, | ||
| 767 | "_f_light_jsconfig": { "iconPath": "../../icons/file_type_light_jsconfig.svg" }, | ||
| 768 | "_f_jscpd": { "iconPath": "../../icons/file_type_jscpd.svg" }, | ||
| 769 | "_f_jshint": { "iconPath": "../../icons/file_type_jshint.svg" }, | ||
| 770 | "_f_jsmap": { "iconPath": "../../icons/file_type_jsmap.svg" }, | ||
| 771 | "_f_light_jsmap": { "iconPath": "../../icons/file_type_light_jsmap.svg" }, | ||
| 772 | "_f_json": { "iconPath": "../../icons/file_type_json.svg" }, | ||
| 773 | "_f_light_json": { "iconPath": "../../icons/file_type_light_json.svg" }, | ||
| 774 | "_f_json5": { "iconPath": "../../icons/file_type_json5.svg" }, | ||
| 775 | "_f_light_json5": { "iconPath": "../../icons/file_type_light_json5.svg" }, | ||
| 776 | "_f_json_schema": { "iconPath": "../../icons/file_type_json_schema.svg" }, | ||
| 777 | "_f_light_json_schema": { "iconPath": "../../icons/file_type_light_json_schema.svg" }, | ||
| 778 | "_f_jsonld": { "iconPath": "../../icons/file_type_jsonld.svg" }, | ||
| 779 | "_f_light_jsonld": { "iconPath": "../../icons/file_type_light_jsonld.svg" }, | ||
| 780 | "_f_jsonnet": { "iconPath": "../../icons/file_type_jsonnet.svg" }, | ||
| 781 | "_f_jsp": { "iconPath": "../../icons/file_type_jsp.svg" }, | ||
| 782 | "_f_jsr": { "iconPath": "../../icons/file_type_jsr.svg" }, | ||
| 783 | "_f_jss": { "iconPath": "../../icons/file_type_jss.svg" }, | ||
| 784 | "_f_juice": { "iconPath": "../../icons/file_type_juice.svg" }, | ||
| 785 | "_f_julia": { "iconPath": "../../icons/file_type_julia.svg" }, | ||
| 786 | "_f_jupyter": { "iconPath": "../../icons/file_type_jupyter.svg" }, | ||
| 787 | "_f_just": { "iconPath": "../../icons/file_type_just.svg" }, | ||
| 788 | "_f_k": { "iconPath": "../../icons/file_type_k.svg" }, | ||
| 789 | "_f_karma": { "iconPath": "../../icons/file_type_karma.svg" }, | ||
| 790 | "_f_key": { "iconPath": "../../icons/file_type_key.svg" }, | ||
| 791 | "_f_kitchenci": { "iconPath": "../../icons/file_type_kitchenci.svg" }, | ||
| 792 | "_f_kite": { "iconPath": "../../icons/file_type_kite.svg" }, | ||
| 793 | "_f_light_kite": { "iconPath": "../../icons/file_type_light_kite.svg" }, | ||
| 794 | "_f_kivy": { "iconPath": "../../icons/file_type_kivy.svg" }, | ||
| 795 | "_f_knip": { "iconPath": "../../icons/file_type_knip.svg" }, | ||
| 796 | "_f_kos": { "iconPath": "../../icons/file_type_kos.svg" }, | ||
| 797 | "_f_kotlin": { "iconPath": "../../icons/file_type_kotlin.svg" }, | ||
| 798 | "_f_kusto": { "iconPath": "../../icons/file_type_kusto.svg" }, | ||
| 799 | "_f_language_configuration": { "iconPath": "../../icons/file_type_language_configuration.svg" }, | ||
| 800 | "_f_lark": { "iconPath": "../../icons/file_type_lark.svg" }, | ||
| 801 | "_f_light_lark": { "iconPath": "../../icons/file_type_light_lark.svg" }, | ||
| 802 | "_f_latino": { "iconPath": "../../icons/file_type_latino.svg" }, | ||
| 803 | "_f_layout": { "iconPath": "../../icons/file_type_layout.svg" }, | ||
| 804 | "_f_lean": { "iconPath": "../../icons/file_type_lean.svg" }, | ||
| 805 | "_f_light_lean": { "iconPath": "../../icons/file_type_light_lean.svg" }, | ||
| 806 | "_f_leanconfig": { "iconPath": "../../icons/file_type_leanconfig.svg" }, | ||
| 807 | "_f_light_leanconfig": { "iconPath": "../../icons/file_type_light_leanconfig.svg" }, | ||
| 808 | "_f_lefthook": { "iconPath": "../../icons/file_type_lefthook.svg" }, | ||
| 809 | "_f_lerna": { "iconPath": "../../icons/file_type_lerna.svg" }, | ||
| 810 | "_f_light_lerna": { "iconPath": "../../icons/file_type_light_lerna.svg" }, | ||
| 811 | "_f_less": { "iconPath": "../../icons/file_type_less.svg" }, | ||
| 812 | "_f_lex": { "iconPath": "../../icons/file_type_lex.svg" }, | ||
| 813 | "_f_liara": { "iconPath": "../../icons/file_type_liara.svg" }, | ||
| 814 | "_f_libreoffice_base": { "iconPath": "../../icons/file_type_libreoffice_base.svg" }, | ||
| 815 | "_f_libreoffice_calc": { "iconPath": "../../icons/file_type_libreoffice_calc.svg" }, | ||
| 816 | "_f_libreoffice_draw": { "iconPath": "../../icons/file_type_libreoffice_draw.svg" }, | ||
| 817 | "_f_libreoffice_impress": { "iconPath": "../../icons/file_type_libreoffice_impress.svg" }, | ||
| 818 | "_f_libreoffice_math": { "iconPath": "../../icons/file_type_libreoffice_math.svg" }, | ||
| 819 | "_f_libreoffice_writer": { "iconPath": "../../icons/file_type_libreoffice_writer.svg" }, | ||
| 820 | "_f_license": { "iconPath": "../../icons/file_type_license.svg" }, | ||
| 821 | "_f_licensebat": { "iconPath": "../../icons/file_type_licensebat.svg" }, | ||
| 822 | "_f_lighthouse": { "iconPath": "../../icons/file_type_lighthouse.svg" }, | ||
| 823 | "_f_lilypond": { "iconPath": "../../icons/file_type_lilypond.svg" }, | ||
| 824 | "_f_lime": { "iconPath": "../../icons/file_type_lime.svg" }, | ||
| 825 | "_f_lintstagedrc": { "iconPath": "../../icons/file_type_lintstagedrc.svg" }, | ||
| 826 | "_f_liquid": { "iconPath": "../../icons/file_type_liquid.svg" }, | ||
| 827 | "_f_lisp": { "iconPath": "../../icons/file_type_lisp.svg" }, | ||
| 828 | "_f_livescript": { "iconPath": "../../icons/file_type_livescript.svg" }, | ||
| 829 | "_f_lnk": { "iconPath": "../../icons/file_type_lnk.svg" }, | ||
| 830 | "_f_locale": { "iconPath": "../../icons/file_type_locale.svg" }, | ||
| 831 | "_f_log": { "iconPath": "../../icons/file_type_log.svg" }, | ||
| 832 | "_f_lolcode": { "iconPath": "../../icons/file_type_lolcode.svg" }, | ||
| 833 | "_f_lsl": { "iconPath": "../../icons/file_type_lsl.svg" }, | ||
| 834 | "_f_lua": { "iconPath": "../../icons/file_type_lua.svg" }, | ||
| 835 | "_f_luau": { "iconPath": "../../icons/file_type_luau.svg" }, | ||
| 836 | "_f_lync": { "iconPath": "../../icons/file_type_lync.svg" }, | ||
| 837 | "_f_mailing": { "iconPath": "../../icons/file_type_mailing.svg" }, | ||
| 838 | "_f_light_mailing": { "iconPath": "../../icons/file_type_light_mailing.svg" }, | ||
| 839 | "_f_manifest": { "iconPath": "../../icons/file_type_manifest.svg" }, | ||
| 840 | "_f_manifest_bak": { "iconPath": "../../icons/file_type_manifest_bak.svg" }, | ||
| 841 | "_f_manifest_skip": { "iconPath": "../../icons/file_type_manifest_skip.svg" }, | ||
| 842 | "_f_map": { "iconPath": "../../icons/file_type_map.svg" }, | ||
| 843 | "_f_markdown": { "iconPath": "../../icons/file_type_markdown.svg" }, | ||
| 844 | "_f_markdownlint": { "iconPath": "../../icons/file_type_markdownlint.svg" }, | ||
| 845 | "_f_markdownlint_ignore": { "iconPath": "../../icons/file_type_markdownlint_ignore.svg" }, | ||
| 846 | "_f_marko": { "iconPath": "../../icons/file_type_marko.svg" }, | ||
| 847 | "_f_markojs": { "iconPath": "../../icons/file_type_markojs.svg" }, | ||
| 848 | "_f_markuplint": { "iconPath": "../../icons/file_type_markuplint.svg" }, | ||
| 849 | "_f_light_markuplint": { "iconPath": "../../icons/file_type_light_markuplint.svg" }, | ||
| 850 | "_f_master-co": { "iconPath": "../../icons/file_type_master-co.svg" }, | ||
| 851 | "_f_matlab": { "iconPath": "../../icons/file_type_matlab.svg" }, | ||
| 852 | "_f_maven": { "iconPath": "../../icons/file_type_maven.svg" }, | ||
| 853 | "_f_maxscript": { "iconPath": "../../icons/file_type_maxscript.svg" }, | ||
| 854 | "_f_maya": { "iconPath": "../../icons/file_type_maya.svg" }, | ||
| 855 | "_f_mcp": { "iconPath": "../../icons/file_type_mcp.svg" }, | ||
| 856 | "_f_light_mcp": { "iconPath": "../../icons/file_type_light_mcp.svg" }, | ||
| 857 | "_f_mdx": { "iconPath": "../../icons/file_type_mdx.svg" }, | ||
| 858 | "_f_light_mdx": { "iconPath": "../../icons/file_type_light_mdx.svg" }, | ||
| 859 | "_f_mdx-components": { "iconPath": "../../icons/file_type_mdx-components.svg" }, | ||
| 860 | "_f_light_mdx-components": { "iconPath": "../../icons/file_type_light_mdx-components.svg" }, | ||
| 861 | "_f_mdxlint": { "iconPath": "../../icons/file_type_mdxlint.svg" }, | ||
| 862 | "_f_mediawiki": { "iconPath": "../../icons/file_type_mediawiki.svg" }, | ||
| 863 | "_f_mercurial": { "iconPath": "../../icons/file_type_mercurial.svg" }, | ||
| 864 | "_f_mermaid": { "iconPath": "../../icons/file_type_mermaid.svg" }, | ||
| 865 | "_f_meson": { "iconPath": "../../icons/file_type_meson.svg" }, | ||
| 866 | "_f_metal": { "iconPath": "../../icons/file_type_metal.svg" }, | ||
| 867 | "_f_meteor": { "iconPath": "../../icons/file_type_meteor.svg" }, | ||
| 868 | "_f_minecraft": { "iconPath": "../../icons/file_type_minecraft.svg" }, | ||
| 869 | "_f_mivascript": { "iconPath": "../../icons/file_type_mivascript.svg" }, | ||
| 870 | "_f_mjml": { "iconPath": "../../icons/file_type_mjml.svg" }, | ||
| 871 | "_f_mlang": { "iconPath": "../../icons/file_type_mlang.svg" }, | ||
| 872 | "_f_light_mlang": { "iconPath": "../../icons/file_type_light_mlang.svg" }, | ||
| 873 | "_f_mocha": { "iconPath": "../../icons/file_type_mocha.svg" }, | ||
| 874 | "_f_modernizr": { "iconPath": "../../icons/file_type_modernizr.svg" }, | ||
| 875 | "_f_mojo": { "iconPath": "../../icons/file_type_mojo.svg" }, | ||
| 876 | "_f_mojolicious": { "iconPath": "../../icons/file_type_mojolicious.svg" }, | ||
| 877 | "_f_moleculer": { "iconPath": "../../icons/file_type_moleculer.svg" }, | ||
| 878 | "_f_mondoo": { "iconPath": "../../icons/file_type_mondoo.svg" }, | ||
| 879 | "_f_mongo": { "iconPath": "../../icons/file_type_mongo.svg" }, | ||
| 880 | "_f_monotone": { "iconPath": "../../icons/file_type_monotone.svg" }, | ||
| 881 | "_f_motif": { "iconPath": "../../icons/file_type_motif.svg" }, | ||
| 882 | "_f_mson": { "iconPath": "../../icons/file_type_mson.svg" }, | ||
| 883 | "_f_mustache": { "iconPath": "../../icons/file_type_mustache.svg" }, | ||
| 884 | "_f_light_mustache": { "iconPath": "../../icons/file_type_light_mustache.svg" }, | ||
| 885 | "_f_mvt": { "iconPath": "../../icons/file_type_mvt.svg" }, | ||
| 886 | "_f_mvtcss": { "iconPath": "../../icons/file_type_mvtcss.svg" }, | ||
| 887 | "_f_mvtjs": { "iconPath": "../../icons/file_type_mvtjs.svg" }, | ||
| 888 | "_f_mypy": { "iconPath": "../../icons/file_type_mypy.svg" }, | ||
| 889 | "_f_light_mypy": { "iconPath": "../../icons/file_type_light_mypy.svg" }, | ||
| 890 | "_f_nanostaged": { "iconPath": "../../icons/file_type_nanostaged.svg" }, | ||
| 891 | "_f_ndst": { "iconPath": "../../icons/file_type_ndst.svg" }, | ||
| 892 | "_f_nearly": { "iconPath": "../../icons/file_type_nearly.svg" }, | ||
| 893 | "_f_neo4j": { "iconPath": "../../icons/file_type_neo4j.svg" }, | ||
| 894 | "_f_light_neo4j": { "iconPath": "../../icons/file_type_light_neo4j.svg" }, | ||
| 895 | "_f_nestjs": { "iconPath": "../../icons/file_type_nestjs.svg" }, | ||
| 896 | "_f_netlify": { "iconPath": "../../icons/file_type_netlify.svg" }, | ||
| 897 | "_f_light_netlify": { "iconPath": "../../icons/file_type_light_netlify.svg" }, | ||
| 898 | "_f_next": { "iconPath": "../../icons/file_type_next.svg" }, | ||
| 899 | "_f_light_next": { "iconPath": "../../icons/file_type_light_next.svg" }, | ||
| 900 | "_f_nextflow": { "iconPath": "../../icons/file_type_nextflow.svg" }, | ||
| 901 | "_f_ng_tailwind": { "iconPath": "../../icons/file_type_ng_tailwind.svg" }, | ||
| 902 | "_f_nginx": { "iconPath": "../../icons/file_type_nginx.svg" }, | ||
| 903 | "_f_nim": { "iconPath": "../../icons/file_type_nim.svg" }, | ||
| 904 | "_f_nimble": { "iconPath": "../../icons/file_type_nimble.svg" }, | ||
| 905 | "_f_ninja": { "iconPath": "../../icons/file_type_ninja.svg" }, | ||
| 906 | "_f_nix": { "iconPath": "../../icons/file_type_nix.svg" }, | ||
| 907 | "_f_njsproj": { "iconPath": "../../icons/file_type_njsproj.svg" }, | ||
| 908 | "_f_noc": { "iconPath": "../../icons/file_type_noc.svg" }, | ||
| 909 | "_f_node": { "iconPath": "../../icons/file_type_node.svg" }, | ||
| 910 | "_f_nodemon": { "iconPath": "../../icons/file_type_nodemon.svg" }, | ||
| 911 | "_f_npm": { "iconPath": "../../icons/file_type_npm.svg" }, | ||
| 912 | "_f_npmpackagejsonlint": { "iconPath": "../../icons/file_type_npmpackagejsonlint.svg" }, | ||
| 913 | "_f_nsi": { "iconPath": "../../icons/file_type_nsi.svg" }, | ||
| 914 | "_f_nsri": { "iconPath": "../../icons/file_type_nsri.svg" }, | ||
| 915 | "_f_nsri-integrity": { "iconPath": "../../icons/file_type_nsri-integrity.svg" }, | ||
| 916 | "_f_nuget": { "iconPath": "../../icons/file_type_nuget.svg" }, | ||
| 917 | "_f_numpy": { "iconPath": "../../icons/file_type_numpy.svg" }, | ||
| 918 | "_f_nunjucks": { "iconPath": "../../icons/file_type_nunjucks.svg" }, | ||
| 919 | "_f_nushell": { "iconPath": "../../icons/file_type_nushell.svg" }, | ||
| 920 | "_f_nuxt": { "iconPath": "../../icons/file_type_nuxt.svg" }, | ||
| 921 | "_f_nx": { "iconPath": "../../icons/file_type_nx.svg" }, | ||
| 922 | "_f_light_nx": { "iconPath": "../../icons/file_type_light_nx.svg" }, | ||
| 923 | "_f_nyc": { "iconPath": "../../icons/file_type_nyc.svg" }, | ||
| 924 | "_f_objectivec": { "iconPath": "../../icons/file_type_objectivec.svg" }, | ||
| 925 | "_f_objectivecpp": { "iconPath": "../../icons/file_type_objectivecpp.svg" }, | ||
| 926 | "_f_objidconfig": { "iconPath": "../../icons/file_type_objidconfig.svg" }, | ||
| 927 | "_f_light_objidconfig": { "iconPath": "../../icons/file_type_light_objidconfig.svg" }, | ||
| 928 | "_f_ocaml": { "iconPath": "../../icons/file_type_ocaml.svg" }, | ||
| 929 | "_f_ocaml_intf": { "iconPath": "../../icons/file_type_ocaml_intf.svg" }, | ||
| 930 | "_f_ogone": { "iconPath": "../../icons/file_type_ogone.svg" }, | ||
| 931 | "_f_onenote": { "iconPath": "../../icons/file_type_onenote.svg" }, | ||
| 932 | "_f_opam": { "iconPath": "../../icons/file_type_opam.svg" }, | ||
| 933 | "_f_openHAB": { "iconPath": "../../icons/file_type_openHAB.svg" }, | ||
| 934 | "_f_light_openHAB": { "iconPath": "../../icons/file_type_light_openHAB.svg" }, | ||
| 935 | "_f_opencl": { "iconPath": "../../icons/file_type_opencl.svg" }, | ||
| 936 | "_f_openscad": { "iconPath": "../../icons/file_type_openscad.svg" }, | ||
| 937 | "_f_opentofu": { "iconPath": "../../icons/file_type_opentofu.svg" }, | ||
| 938 | "_f_org": { "iconPath": "../../icons/file_type_org.svg" }, | ||
| 939 | "_f_outlook": { "iconPath": "../../icons/file_type_outlook.svg" }, | ||
| 940 | "_f_ovpn": { "iconPath": "../../icons/file_type_ovpn.svg" }, | ||
| 941 | "_f_oxc": { "iconPath": "../../icons/file_type_oxc.svg" }, | ||
| 942 | "_f_light_oxc": { "iconPath": "../../icons/file_type_light_oxc.svg" }, | ||
| 943 | "_f_package": { "iconPath": "../../icons/file_type_package.svg" }, | ||
| 944 | "_f_packship": { "iconPath": "../../icons/file_type_packship.svg" }, | ||
| 945 | "_f_light_packship": { "iconPath": "../../icons/file_type_light_packship.svg" }, | ||
| 946 | "_f_paket": { "iconPath": "../../icons/file_type_paket.svg" }, | ||
| 947 | "_f_pandacss": { "iconPath": "../../icons/file_type_pandacss.svg" }, | ||
| 948 | "_f_patch": { "iconPath": "../../icons/file_type_patch.svg" }, | ||
| 949 | "_f_pcl": { "iconPath": "../../icons/file_type_pcl.svg" }, | ||
| 950 | "_f_light_pcl": { "iconPath": "../../icons/file_type_light_pcl.svg" }, | ||
| 951 | "_f_pddl": { "iconPath": "../../icons/file_type_pddl.svg" }, | ||
| 952 | "_f_pddl_happenings": { "iconPath": "../../icons/file_type_pddl_happenings.svg" }, | ||
| 953 | "_f_pddl_plan": { "iconPath": "../../icons/file_type_pddl_plan.svg" }, | ||
| 954 | "_f_pdf": { "iconPath": "../../icons/file_type_pdf.svg" }, | ||
| 955 | "_f_pdm": { "iconPath": "../../icons/file_type_pdm.svg" }, | ||
| 956 | "_f_peeky": { "iconPath": "../../icons/file_type_peeky.svg" }, | ||
| 957 | "_f_perl": { "iconPath": "../../icons/file_type_perl.svg" }, | ||
| 958 | "_f_perl6": { "iconPath": "../../icons/file_type_perl6.svg" }, | ||
| 959 | "_f_pgsql": { "iconPath": "../../icons/file_type_pgsql.svg" }, | ||
| 960 | "_f_photoshop": { "iconPath": "../../icons/file_type_photoshop.svg" }, | ||
| 961 | "_f_php": { "iconPath": "../../icons/file_type_php.svg" }, | ||
| 962 | "_f_phpcsfixer": { "iconPath": "../../icons/file_type_phpcsfixer.svg" }, | ||
| 963 | "_f_phpstan": { "iconPath": "../../icons/file_type_phpstan.svg" }, | ||
| 964 | "_f_phpunit": { "iconPath": "../../icons/file_type_phpunit.svg" }, | ||
| 965 | "_f_phraseapp": { "iconPath": "../../icons/file_type_phraseapp.svg" }, | ||
| 966 | "_f_pine": { "iconPath": "../../icons/file_type_pine.svg" }, | ||
| 967 | "_f_pip": { "iconPath": "../../icons/file_type_pip.svg" }, | ||
| 968 | "_f_pipeline": { "iconPath": "../../icons/file_type_pipeline.svg" }, | ||
| 969 | "_f_plantuml": { "iconPath": "../../icons/file_type_plantuml.svg" }, | ||
| 970 | "_f_platformio": { "iconPath": "../../icons/file_type_platformio.svg" }, | ||
| 971 | "_f_playwright": { "iconPath": "../../icons/file_type_playwright.svg" }, | ||
| 972 | "_f_plsql": { "iconPath": "../../icons/file_type_plsql.svg" }, | ||
| 973 | "_f_plsql_package": { "iconPath": "../../icons/file_type_plsql_package.svg" }, | ||
| 974 | "_f_plsql_package_body": { "iconPath": "../../icons/file_type_plsql_package_body.svg" }, | ||
| 975 | "_f_plsql_package_header": { "iconPath": "../../icons/file_type_plsql_package_header.svg" }, | ||
| 976 | "_f_plsql_package_spec": { "iconPath": "../../icons/file_type_plsql_package_spec.svg" }, | ||
| 977 | "_f_pm2": { "iconPath": "../../icons/file_type_pm2.svg" }, | ||
| 978 | "_f_pnpm": { "iconPath": "../../icons/file_type_pnpm.svg" }, | ||
| 979 | "_f_light_pnpm": { "iconPath": "../../icons/file_type_light_pnpm.svg" }, | ||
| 980 | "_f_poedit": { "iconPath": "../../icons/file_type_poedit.svg" }, | ||
| 981 | "_f_poetry": { "iconPath": "../../icons/file_type_poetry.svg" }, | ||
| 982 | "_f_polyglot": { "iconPath": "../../icons/file_type_polyglot.svg" }, | ||
| 983 | "_f_polymer": { "iconPath": "../../icons/file_type_polymer.svg" }, | ||
| 984 | "_f_pony": { "iconPath": "../../icons/file_type_pony.svg" }, | ||
| 985 | "_f_postcss": { "iconPath": "../../icons/file_type_postcss.svg" }, | ||
| 986 | "_f_postcssconfig": { "iconPath": "../../icons/file_type_postcssconfig.svg" }, | ||
| 987 | "_f_postman": { "iconPath": "../../icons/file_type_postman.svg" }, | ||
| 988 | "_f_postscript": { "iconPath": "../../icons/file_type_postscript.svg" }, | ||
| 989 | "_f_powerpoint": { "iconPath": "../../icons/file_type_powerpoint.svg" }, | ||
| 990 | "_f_powershell": { "iconPath": "../../icons/file_type_powershell.svg" }, | ||
| 991 | "_f_powershell_format": { "iconPath": "../../icons/file_type_powershell_format.svg" }, | ||
| 992 | "_f_powershell_psd": { "iconPath": "../../icons/file_type_powershell_psd.svg" }, | ||
| 993 | "_f_powershell_psm": { "iconPath": "../../icons/file_type_powershell_psm.svg" }, | ||
| 994 | "_f_powershell_types": { "iconPath": "../../icons/file_type_powershell_types.svg" }, | ||
| 995 | "_f_preact": { "iconPath": "../../icons/file_type_preact.svg" }, | ||
| 996 | "_f_precommit": { "iconPath": "../../icons/file_type_precommit.svg" }, | ||
| 997 | "_f_prettier": { "iconPath": "../../icons/file_type_prettier.svg" }, | ||
| 998 | "_f_light_prettier": { "iconPath": "../../icons/file_type_light_prettier.svg" }, | ||
| 999 | "_f_prisma": { "iconPath": "../../icons/file_type_prisma.svg" }, | ||
| 1000 | "_f_light_prisma": { "iconPath": "../../icons/file_type_light_prisma.svg" }, | ||
| 1001 | "_f_prismaconfig": { "iconPath": "../../icons/file_type_prismaconfig.svg" }, | ||
| 1002 | "_f_processinglang": { "iconPath": "../../icons/file_type_processinglang.svg" }, | ||
| 1003 | "_f_procfile": { "iconPath": "../../icons/file_type_procfile.svg" }, | ||
| 1004 | "_f_progress": { "iconPath": "../../icons/file_type_progress.svg" }, | ||
| 1005 | "_f_prolog": { "iconPath": "../../icons/file_type_prolog.svg" }, | ||
| 1006 | "_f_prometheus": { "iconPath": "../../icons/file_type_prometheus.svg" }, | ||
| 1007 | "_f_protobuf": { "iconPath": "../../icons/file_type_protobuf.svg" }, | ||
| 1008 | "_f_protractor": { "iconPath": "../../icons/file_type_protractor.svg" }, | ||
| 1009 | "_f_publiccode": { "iconPath": "../../icons/file_type_publiccode.svg" }, | ||
| 1010 | "_f_publisher": { "iconPath": "../../icons/file_type_publisher.svg" }, | ||
| 1011 | "_f_pug": { "iconPath": "../../icons/file_type_pug.svg" }, | ||
| 1012 | "_f_pulumi": { "iconPath": "../../icons/file_type_pulumi.svg" }, | ||
| 1013 | "_f_puppet": { "iconPath": "../../icons/file_type_puppet.svg" }, | ||
| 1014 | "_f_purescript": { "iconPath": "../../icons/file_type_purescript.svg" }, | ||
| 1015 | "_f_light_purescript": { "iconPath": "../../icons/file_type_light_purescript.svg" }, | ||
| 1016 | "_f_purgecss": { "iconPath": "../../icons/file_type_purgecss.svg" }, | ||
| 1017 | "_f_pyenv": { "iconPath": "../../icons/file_type_pyenv.svg" }, | ||
| 1018 | "_f_pypi": { "iconPath": "../../icons/file_type_pypi.svg" }, | ||
| 1019 | "_f_pyret": { "iconPath": "../../icons/file_type_pyret.svg" }, | ||
| 1020 | "_f_pyscript": { "iconPath": "../../icons/file_type_pyscript.svg" }, | ||
| 1021 | "_f_pytest": { "iconPath": "../../icons/file_type_pytest.svg" }, | ||
| 1022 | "_f_python": { "iconPath": "../../icons/file_type_python.svg" }, | ||
| 1023 | "_f_pythowo": { "iconPath": "../../icons/file_type_pythowo.svg" }, | ||
| 1024 | "_f_pytyped": { "iconPath": "../../icons/file_type_pytyped.svg" }, | ||
| 1025 | "_f_pyup": { "iconPath": "../../icons/file_type_pyup.svg" }, | ||
| 1026 | "_f_q": { "iconPath": "../../icons/file_type_q.svg" }, | ||
| 1027 | "_f_qbs": { "iconPath": "../../icons/file_type_qbs.svg" }, | ||
| 1028 | "_f_qlikview": { "iconPath": "../../icons/file_type_qlikview.svg" }, | ||
| 1029 | "_f_qml": { "iconPath": "../../icons/file_type_qml.svg" }, | ||
| 1030 | "_f_qmldir": { "iconPath": "../../icons/file_type_qmldir.svg" }, | ||
| 1031 | "_f_qsharp": { "iconPath": "../../icons/file_type_qsharp.svg" }, | ||
| 1032 | "_f_quasar": { "iconPath": "../../icons/file_type_quasar.svg" }, | ||
| 1033 | "_f_light_quasar": { "iconPath": "../../icons/file_type_light_quasar.svg" }, | ||
| 1034 | "_f_r": { "iconPath": "../../icons/file_type_r.svg" }, | ||
| 1035 | "_f_ra_syntax_tree": { "iconPath": "../../icons/file_type_ra_syntax_tree.svg" }, | ||
| 1036 | "_f_racket": { "iconPath": "../../icons/file_type_racket.svg" }, | ||
| 1037 | "_f_rails": { "iconPath": "../../icons/file_type_rails.svg" }, | ||
| 1038 | "_f_rake": { "iconPath": "../../icons/file_type_rake.svg" }, | ||
| 1039 | "_f_raku": { "iconPath": "../../icons/file_type_raku.svg" }, | ||
| 1040 | "_f_light_raku": { "iconPath": "../../icons/file_type_light_raku.svg" }, | ||
| 1041 | "_f_raml": { "iconPath": "../../icons/file_type_raml.svg" }, | ||
| 1042 | "_f_razor": { "iconPath": "../../icons/file_type_razor.svg" }, | ||
| 1043 | "_f_razzle": { "iconPath": "../../icons/file_type_razzle.svg" }, | ||
| 1044 | "_f_light_razzle": { "iconPath": "../../icons/file_type_light_razzle.svg" }, | ||
| 1045 | "_f_reactjs": { "iconPath": "../../icons/file_type_reactjs.svg" }, | ||
| 1046 | "_f_reactrouter": { "iconPath": "../../icons/file_type_reactrouter.svg" }, | ||
| 1047 | "_f_light_reactrouter": { "iconPath": "../../icons/file_type_light_reactrouter.svg" }, | ||
| 1048 | "_f_reacttemplate": { "iconPath": "../../icons/file_type_reacttemplate.svg" }, | ||
| 1049 | "_f_reactts": { "iconPath": "../../icons/file_type_reactts.svg" }, | ||
| 1050 | "_f_reason": { "iconPath": "../../icons/file_type_reason.svg" }, | ||
| 1051 | "_f_red": { "iconPath": "../../icons/file_type_red.svg" }, | ||
| 1052 | "_f_registry": { "iconPath": "../../icons/file_type_registry.svg" }, | ||
| 1053 | "_f_rego": { "iconPath": "../../icons/file_type_rego.svg" }, | ||
| 1054 | "_f_rehype": { "iconPath": "../../icons/file_type_rehype.svg" }, | ||
| 1055 | "_f_light_rehype": { "iconPath": "../../icons/file_type_light_rehype.svg" }, | ||
| 1056 | "_f_remark": { "iconPath": "../../icons/file_type_remark.svg" }, | ||
| 1057 | "_f_light_remark": { "iconPath": "../../icons/file_type_light_remark.svg" }, | ||
| 1058 | "_f_renovate": { "iconPath": "../../icons/file_type_renovate.svg" }, | ||
| 1059 | "_f_replit": { "iconPath": "../../icons/file_type_replit.svg" }, | ||
| 1060 | "_f_light_replit": { "iconPath": "../../icons/file_type_light_replit.svg" }, | ||
| 1061 | "_f_rescript": { "iconPath": "../../icons/file_type_rescript.svg" }, | ||
| 1062 | "_f_rest": { "iconPath": "../../icons/file_type_rest.svg" }, | ||
| 1063 | "_f_retext": { "iconPath": "../../icons/file_type_retext.svg" }, | ||
| 1064 | "_f_light_retext": { "iconPath": "../../icons/file_type_light_retext.svg" }, | ||
| 1065 | "_f_rexx": { "iconPath": "../../icons/file_type_rexx.svg" }, | ||
| 1066 | "_f_riot": { "iconPath": "../../icons/file_type_riot.svg" }, | ||
| 1067 | "_f_ripple": { "iconPath": "../../icons/file_type_ripple.svg" }, | ||
| 1068 | "_f_rmd": { "iconPath": "../../icons/file_type_rmd.svg" }, | ||
| 1069 | "_f_rnc": { "iconPath": "../../icons/file_type_rnc.svg" }, | ||
| 1070 | "_f_robotframework": { "iconPath": "../../icons/file_type_robotframework.svg" }, | ||
| 1071 | "_f_robots": { "iconPath": "../../icons/file_type_robots.svg" }, | ||
| 1072 | "_f_rolldown": { "iconPath": "../../icons/file_type_rolldown.svg" }, | ||
| 1073 | "_f_light_rolldown": { "iconPath": "../../icons/file_type_light_rolldown.svg" }, | ||
| 1074 | "_f_rollup": { "iconPath": "../../icons/file_type_rollup.svg" }, | ||
| 1075 | "_f_rome": { "iconPath": "../../icons/file_type_rome.svg" }, | ||
| 1076 | "_f_light_rome": { "iconPath": "../../icons/file_type_light_rome.svg" }, | ||
| 1077 | "_f_ron": { "iconPath": "../../icons/file_type_ron.svg" }, | ||
| 1078 | "_f_rproj": { "iconPath": "../../icons/file_type_rproj.svg" }, | ||
| 1079 | "_f_rspec": { "iconPath": "../../icons/file_type_rspec.svg" }, | ||
| 1080 | "_f_rss": { "iconPath": "../../icons/file_type_rss.svg" }, | ||
| 1081 | "_f_rubocop": { "iconPath": "../../icons/file_type_rubocop.svg" }, | ||
| 1082 | "_f_light_rubocop": { "iconPath": "../../icons/file_type_light_rubocop.svg" }, | ||
| 1083 | "_f_ruby": { "iconPath": "../../icons/file_type_ruby.svg" }, | ||
| 1084 | "_f_rust": { "iconPath": "../../icons/file_type_rust.svg" }, | ||
| 1085 | "_f_light_rust": { "iconPath": "../../icons/file_type_light_rust.svg" }, | ||
| 1086 | "_f_rust_toolchain": { "iconPath": "../../icons/file_type_rust_toolchain.svg" }, | ||
| 1087 | "_f_light_rust_toolchain": { "iconPath": "../../icons/file_type_light_rust_toolchain.svg" }, | ||
| 1088 | "_f_s-lang": { "iconPath": "../../icons/file_type_s-lang.svg" }, | ||
| 1089 | "_f_safetensors": { "iconPath": "../../icons/file_type_safetensors.svg" }, | ||
| 1090 | "_f_light_safetensors": { "iconPath": "../../icons/file_type_light_safetensors.svg" }, | ||
| 1091 | "_f_sails": { "iconPath": "../../icons/file_type_sails.svg" }, | ||
| 1092 | "_f_saltstack": { "iconPath": "../../icons/file_type_saltstack.svg" }, | ||
| 1093 | "_f_san": { "iconPath": "../../icons/file_type_san.svg" }, | ||
| 1094 | "_f_sapphire_framework_cli": { "iconPath": "../../icons/file_type_sapphire_framework_cli.svg" }, | ||
| 1095 | "_f_sas": { "iconPath": "../../icons/file_type_sas.svg" }, | ||
| 1096 | "_f_sass": { "iconPath": "../../icons/file_type_sass.svg" }, | ||
| 1097 | "_f_sbt": { "iconPath": "../../icons/file_type_sbt.svg" }, | ||
| 1098 | "_f_scala": { "iconPath": "../../icons/file_type_scala.svg" }, | ||
| 1099 | "_f_scilab": { "iconPath": "../../icons/file_type_scilab.svg" }, | ||
| 1100 | "_f_script": { "iconPath": "../../icons/file_type_script.svg" }, | ||
| 1101 | "_f_scss": { "iconPath": "../../icons/file_type_scss.svg" }, | ||
| 1102 | "_f_sdlang": { "iconPath": "../../icons/file_type_sdlang.svg" }, | ||
| 1103 | "_f_search_result": { "iconPath": "../../icons/file_type_search_result.svg" }, | ||
| 1104 | "_f_seedkit": { "iconPath": "../../icons/file_type_seedkit.svg" }, | ||
| 1105 | "_f_sentry": { "iconPath": "../../icons/file_type_sentry.svg" }, | ||
| 1106 | "_f_sequelize": { "iconPath": "../../icons/file_type_sequelize.svg" }, | ||
| 1107 | "_f_serverless": { "iconPath": "../../icons/file_type_serverless.svg" }, | ||
| 1108 | "_f_shadcn": { "iconPath": "../../icons/file_type_shadcn.svg" }, | ||
| 1109 | "_f_light_shadcn": { "iconPath": "../../icons/file_type_light_shadcn.svg" }, | ||
| 1110 | "_f_shaderlab": { "iconPath": "../../icons/file_type_shaderlab.svg" }, | ||
| 1111 | "_f_light_shaderlab": { "iconPath": "../../icons/file_type_light_shaderlab.svg" }, | ||
| 1112 | "_f_shell": { "iconPath": "../../icons/file_type_shell.svg" }, | ||
| 1113 | "_f_shellcheck": { "iconPath": "../../icons/file_type_shellcheck.svg" }, | ||
| 1114 | "_f_shuttle": { "iconPath": "../../icons/file_type_shuttle.svg" }, | ||
| 1115 | "_f_silverstripe": { "iconPath": "../../icons/file_type_silverstripe.svg" }, | ||
| 1116 | "_f_sino": { "iconPath": "../../icons/file_type_sino.svg" }, | ||
| 1117 | "_f_sitemap": { "iconPath": "../../icons/file_type_sitemap.svg" }, | ||
| 1118 | "_f_siyuan": { "iconPath": "../../icons/file_type_siyuan.svg" }, | ||
| 1119 | "_f_sketch": { "iconPath": "../../icons/file_type_sketch.svg" }, | ||
| 1120 | "_f_skipper": { "iconPath": "../../icons/file_type_skipper.svg" }, | ||
| 1121 | "_f_slang": { "iconPath": "../../icons/file_type_slang.svg" }, | ||
| 1122 | "_f_slashup": { "iconPath": "../../icons/file_type_slashup.svg" }, | ||
| 1123 | "_f_slice": { "iconPath": "../../icons/file_type_slice.svg" }, | ||
| 1124 | "_f_slim": { "iconPath": "../../icons/file_type_slim.svg" }, | ||
| 1125 | "_f_slint": { "iconPath": "../../icons/file_type_slint.svg" }, | ||
| 1126 | "_f_sln": { "iconPath": "../../icons/file_type_sln.svg" }, | ||
| 1127 | "_f_smarty": { "iconPath": "../../icons/file_type_smarty.svg" }, | ||
| 1128 | "_f_smithery": { "iconPath": "../../icons/file_type_smithery.svg" }, | ||
| 1129 | "_f_snakemake": { "iconPath": "../../icons/file_type_snakemake.svg" }, | ||
| 1130 | "_f_snapcraft": { "iconPath": "../../icons/file_type_snapcraft.svg" }, | ||
| 1131 | "_f_snaplet": { "iconPath": "../../icons/file_type_snaplet.svg" }, | ||
| 1132 | "_f_snort": { "iconPath": "../../icons/file_type_snort.svg" }, | ||
| 1133 | "_f_snyk": { "iconPath": "../../icons/file_type_snyk.svg" }, | ||
| 1134 | "_f_solidarity": { "iconPath": "../../icons/file_type_solidarity.svg" }, | ||
| 1135 | "_f_solidity": { "iconPath": "../../icons/file_type_solidity.svg" }, | ||
| 1136 | "_f_light_solidity": { "iconPath": "../../icons/file_type_light_solidity.svg" }, | ||
| 1137 | "_f_source": { "iconPath": "../../icons/file_type_source.svg" }, | ||
| 1138 | "_f_spacengine": { "iconPath": "../../icons/file_type_spacengine.svg" }, | ||
| 1139 | "_f_sparql": { "iconPath": "../../icons/file_type_sparql.svg" }, | ||
| 1140 | "_f_spin": { "iconPath": "../../icons/file_type_spin.svg" }, | ||
| 1141 | "_f_light_spin": { "iconPath": "../../icons/file_type_light_spin.svg" }, | ||
| 1142 | "_f_sqf": { "iconPath": "../../icons/file_type_sqf.svg" }, | ||
| 1143 | "_f_sql": { "iconPath": "../../icons/file_type_sql.svg" }, | ||
| 1144 | "_f_sqlite": { "iconPath": "../../icons/file_type_sqlite.svg" }, | ||
| 1145 | "_f_squirrel": { "iconPath": "../../icons/file_type_squirrel.svg" }, | ||
| 1146 | "_f_sss": { "iconPath": "../../icons/file_type_sss.svg" }, | ||
| 1147 | "_f_sst": { "iconPath": "../../icons/file_type_sst.svg" }, | ||
| 1148 | "_f_stackblitz": { "iconPath": "../../icons/file_type_stackblitz.svg" }, | ||
| 1149 | "_f_stan": { "iconPath": "../../icons/file_type_stan.svg" }, | ||
| 1150 | "_f_stata": { "iconPath": "../../icons/file_type_stata.svg" }, | ||
| 1151 | "_f_stencil": { "iconPath": "../../icons/file_type_stencil.svg" }, | ||
| 1152 | "_f_storyboard": { "iconPath": "../../icons/file_type_storyboard.svg" }, | ||
| 1153 | "_f_storybook": { "iconPath": "../../icons/file_type_storybook.svg" }, | ||
| 1154 | "_f_stryker": { "iconPath": "../../icons/file_type_stryker.svg" }, | ||
| 1155 | "_f_stylable": { "iconPath": "../../icons/file_type_stylable.svg" }, | ||
| 1156 | "_f_style": { "iconPath": "../../icons/file_type_style.svg" }, | ||
| 1157 | "_f_styled": { "iconPath": "../../icons/file_type_styled.svg" }, | ||
| 1158 | "_f_stylelint": { "iconPath": "../../icons/file_type_stylelint.svg" }, | ||
| 1159 | "_f_light_stylelint": { "iconPath": "../../icons/file_type_light_stylelint.svg" }, | ||
| 1160 | "_f_stylish_haskell": { "iconPath": "../../icons/file_type_stylish_haskell.svg" }, | ||
| 1161 | "_f_stylus": { "iconPath": "../../icons/file_type_stylus.svg" }, | ||
| 1162 | "_f_light_stylus": { "iconPath": "../../icons/file_type_light_stylus.svg" }, | ||
| 1163 | "_f_sublime": { "iconPath": "../../icons/file_type_sublime.svg" }, | ||
| 1164 | "_f_subversion": { "iconPath": "../../icons/file_type_subversion.svg" }, | ||
| 1165 | "_f_svelte": { "iconPath": "../../icons/file_type_svelte.svg" }, | ||
| 1166 | "_f_svelteconfig": { "iconPath": "../../icons/file_type_svelteconfig.svg" }, | ||
| 1167 | "_f_svg": { "iconPath": "../../icons/file_type_svg.svg" }, | ||
| 1168 | "_f_svgo": { "iconPath": "../../icons/file_type_svgo.svg" }, | ||
| 1169 | "_f_swagger": { "iconPath": "../../icons/file_type_swagger.svg" }, | ||
| 1170 | "_f_swc": { "iconPath": "../../icons/file_type_swc.svg" }, | ||
| 1171 | "_f_swift": { "iconPath": "../../icons/file_type_swift.svg" }, | ||
| 1172 | "_f_swig": { "iconPath": "../../icons/file_type_swig.svg" }, | ||
| 1173 | "_f_symfony": { "iconPath": "../../icons/file_type_symfony.svg" }, | ||
| 1174 | "_f_light_symfony": { "iconPath": "../../icons/file_type_light_symfony.svg" }, | ||
| 1175 | "_f_syncpack": { "iconPath": "../../icons/file_type_syncpack.svg" }, | ||
| 1176 | "_f_systemd": { "iconPath": "../../icons/file_type_systemd.svg" }, | ||
| 1177 | "_f_light_systemd": { "iconPath": "../../icons/file_type_light_systemd.svg" }, | ||
| 1178 | "_f_systemverilog": { "iconPath": "../../icons/file_type_systemverilog.svg" }, | ||
| 1179 | "_f_light_systemverilog": { "iconPath": "../../icons/file_type_light_systemverilog.svg" }, | ||
| 1180 | "_f_t4tt": { "iconPath": "../../icons/file_type_t4tt.svg" }, | ||
| 1181 | "_f_tailwind": { "iconPath": "../../icons/file_type_tailwind.svg" }, | ||
| 1182 | "_f_tamagui": { "iconPath": "../../icons/file_type_tamagui.svg" }, | ||
| 1183 | "_f_taplo": { "iconPath": "../../icons/file_type_taplo.svg" }, | ||
| 1184 | "_f_taskfile": { "iconPath": "../../icons/file_type_taskfile.svg" }, | ||
| 1185 | "_f_tauri": { "iconPath": "../../icons/file_type_tauri.svg" }, | ||
| 1186 | "_f_tcl": { "iconPath": "../../icons/file_type_tcl.svg" }, | ||
| 1187 | "_f_teal": { "iconPath": "../../icons/file_type_teal.svg" }, | ||
| 1188 | "_f_templ": { "iconPath": "../../icons/file_type_templ.svg" }, | ||
| 1189 | "_f_tera": { "iconPath": "../../icons/file_type_tera.svg" }, | ||
| 1190 | "_f_terraform": { "iconPath": "../../icons/file_type_terraform.svg" }, | ||
| 1191 | "_f_test": { "iconPath": "../../icons/file_type_test.svg" }, | ||
| 1192 | "_f_testcafe": { "iconPath": "../../icons/file_type_testcafe.svg" }, | ||
| 1193 | "_f_light_testcafe": { "iconPath": "../../icons/file_type_light_testcafe.svg" }, | ||
| 1194 | "_f_testjs": { "iconPath": "../../icons/file_type_testjs.svg" }, | ||
| 1195 | "_f_light_testjs": { "iconPath": "../../icons/file_type_light_testjs.svg" }, | ||
| 1196 | "_f_testplane": { "iconPath": "../../icons/file_type_testplane.svg" }, | ||
| 1197 | "_f_testts": { "iconPath": "../../icons/file_type_testts.svg" }, | ||
| 1198 | "_f_tex": { "iconPath": "../../icons/file_type_tex.svg" }, | ||
| 1199 | "_f_light_tex": { "iconPath": "../../icons/file_type_light_tex.svg" }, | ||
| 1200 | "_f_text": { "iconPath": "../../icons/file_type_text.svg" }, | ||
| 1201 | "_f_textile": { "iconPath": "../../icons/file_type_textile.svg" }, | ||
| 1202 | "_f_tfs": { "iconPath": "../../icons/file_type_tfs.svg" }, | ||
| 1203 | "_f_tiltfile": { "iconPath": "../../icons/file_type_tiltfile.svg" }, | ||
| 1204 | "_f_tm": { "iconPath": "../../icons/file_type_tm.svg" }, | ||
| 1205 | "_f_light_tm": { "iconPath": "../../icons/file_type_light_tm.svg" }, | ||
| 1206 | "_f_tmux": { "iconPath": "../../icons/file_type_tmux.svg" }, | ||
| 1207 | "_f_light_tmux": { "iconPath": "../../icons/file_type_light_tmux.svg" }, | ||
| 1208 | "_f_todo": { "iconPath": "../../icons/file_type_todo.svg" }, | ||
| 1209 | "_f_light_todo": { "iconPath": "../../icons/file_type_light_todo.svg" }, | ||
| 1210 | "_f_toit": { "iconPath": "../../icons/file_type_toit.svg" }, | ||
| 1211 | "_f_light_toit": { "iconPath": "../../icons/file_type_light_toit.svg" }, | ||
| 1212 | "_f_toml": { "iconPath": "../../icons/file_type_toml.svg" }, | ||
| 1213 | "_f_light_toml": { "iconPath": "../../icons/file_type_light_toml.svg" }, | ||
| 1214 | "_f_toon": { "iconPath": "../../icons/file_type_toon.svg" }, | ||
| 1215 | "_f_light_toon": { "iconPath": "../../icons/file_type_light_toon.svg" }, | ||
| 1216 | "_f_tox": { "iconPath": "../../icons/file_type_tox.svg" }, | ||
| 1217 | "_f_travis": { "iconPath": "../../icons/file_type_travis.svg" }, | ||
| 1218 | "_f_tree": { "iconPath": "../../icons/file_type_tree.svg" }, | ||
| 1219 | "_f_light_tree": { "iconPath": "../../icons/file_type_light_tree.svg" }, | ||
| 1220 | "_f_tres": { "iconPath": "../../icons/file_type_tres.svg" }, | ||
| 1221 | "_f_truffle": { "iconPath": "../../icons/file_type_truffle.svg" }, | ||
| 1222 | "_f_trunk": { "iconPath": "../../icons/file_type_trunk.svg" }, | ||
| 1223 | "_f_tsbuildinfo": { "iconPath": "../../icons/file_type_tsbuildinfo.svg" }, | ||
| 1224 | "_f_tscn": { "iconPath": "../../icons/file_type_tscn.svg" }, | ||
| 1225 | "_f_tsconfig": { "iconPath": "../../icons/file_type_tsconfig.svg" }, | ||
| 1226 | "_f_tsdoc": { "iconPath": "../../icons/file_type_tsdoc.svg" }, | ||
| 1227 | "_f_tsdown": { "iconPath": "../../icons/file_type_tsdown.svg" }, | ||
| 1228 | "_f_tslint": { "iconPath": "../../icons/file_type_tslint.svg" }, | ||
| 1229 | "_f_tt": { "iconPath": "../../icons/file_type_tt.svg" }, | ||
| 1230 | "_f_ttcn": { "iconPath": "../../icons/file_type_ttcn.svg" }, | ||
| 1231 | "_f_tuc": { "iconPath": "../../icons/file_type_tuc.svg" }, | ||
| 1232 | "_f_turbo": { "iconPath": "../../icons/file_type_turbo.svg" }, | ||
| 1233 | "_f_light_turbo": { "iconPath": "../../icons/file_type_light_turbo.svg" }, | ||
| 1234 | "_f_twig": { "iconPath": "../../icons/file_type_twig.svg" }, | ||
| 1235 | "_f_typedoc": { "iconPath": "../../icons/file_type_typedoc.svg" }, | ||
| 1236 | "_f_typescript": { "iconPath": "../../icons/file_type_typescript.svg" }, | ||
| 1237 | "_f_typescriptdef": { "iconPath": "../../icons/file_type_typescriptdef.svg" }, | ||
| 1238 | "_f_typo3": { "iconPath": "../../icons/file_type_typo3.svg" }, | ||
| 1239 | "_f_uiua": { "iconPath": "../../icons/file_type_uiua.svg" }, | ||
| 1240 | "_f_unibeautify": { "iconPath": "../../icons/file_type_unibeautify.svg" }, | ||
| 1241 | "_f_light_unibeautify": { "iconPath": "../../icons/file_type_light_unibeautify.svg" }, | ||
| 1242 | "_f_unison": { "iconPath": "../../icons/file_type_unison.svg" }, | ||
| 1243 | "_f_unlicense": { "iconPath": "../../icons/file_type_unlicense.svg" }, | ||
| 1244 | "_f_unocss": { "iconPath": "../../icons/file_type_unocss.svg" }, | ||
| 1245 | "_f_uv": { "iconPath": "../../icons/file_type_uv.svg" }, | ||
| 1246 | "_f_vagrant": { "iconPath": "../../icons/file_type_vagrant.svg" }, | ||
| 1247 | "_f_vala": { "iconPath": "../../icons/file_type_vala.svg" }, | ||
| 1248 | "_f_vanilla_extract": { "iconPath": "../../icons/file_type_vanilla_extract.svg" }, | ||
| 1249 | "_f_vapi": { "iconPath": "../../icons/file_type_vapi.svg" }, | ||
| 1250 | "_f_vapor": { "iconPath": "../../icons/file_type_vapor.svg" }, | ||
| 1251 | "_f_vash": { "iconPath": "../../icons/file_type_vash.svg" }, | ||
| 1252 | "_f_light_vash": { "iconPath": "../../icons/file_type_light_vash.svg" }, | ||
| 1253 | "_f_vb": { "iconPath": "../../icons/file_type_vb.svg" }, | ||
| 1254 | "_f_vba": { "iconPath": "../../icons/file_type_vba.svg" }, | ||
| 1255 | "_f_vbhtml": { "iconPath": "../../icons/file_type_vbhtml.svg" }, | ||
| 1256 | "_f_vbproj": { "iconPath": "../../icons/file_type_vbproj.svg" }, | ||
| 1257 | "_f_vcxproj": { "iconPath": "../../icons/file_type_vcxproj.svg" }, | ||
| 1258 | "_f_velocity": { "iconPath": "../../icons/file_type_velocity.svg" }, | ||
| 1259 | "_f_vento": { "iconPath": "../../icons/file_type_vento.svg" }, | ||
| 1260 | "_f_vercel": { "iconPath": "../../icons/file_type_vercel.svg" }, | ||
| 1261 | "_f_light_vercel": { "iconPath": "../../icons/file_type_light_vercel.svg" }, | ||
| 1262 | "_f_verilog": { "iconPath": "../../icons/file_type_verilog.svg" }, | ||
| 1263 | "_f_vhdl": { "iconPath": "../../icons/file_type_vhdl.svg" }, | ||
| 1264 | "_f_video": { "iconPath": "../../icons/file_type_video.svg" }, | ||
| 1265 | "_f_view": { "iconPath": "../../icons/file_type_view.svg" }, | ||
| 1266 | "_f_vim": { "iconPath": "../../icons/file_type_vim.svg" }, | ||
| 1267 | "_f_vite": { "iconPath": "../../icons/file_type_vite.svg" }, | ||
| 1268 | "_f_light_vite": { "iconPath": "../../icons/file_type_light_vite.svg" }, | ||
| 1269 | "_f_vitest": { "iconPath": "../../icons/file_type_vitest.svg" }, | ||
| 1270 | "_f_light_vitest": { "iconPath": "../../icons/file_type_light_vitest.svg" }, | ||
| 1271 | "_f_vlang": { "iconPath": "../../icons/file_type_vlang.svg" }, | ||
| 1272 | "_f_volt": { "iconPath": "../../icons/file_type_volt.svg" }, | ||
| 1273 | "_f_vroom": { "iconPath": "../../icons/file_type_vroom.svg" }, | ||
| 1274 | "_f_vscode": { "iconPath": "../../icons/file_type_vscode.svg" }, | ||
| 1275 | "_f_vscode_test": { "iconPath": "../../icons/file_type_vscode_test.svg" }, | ||
| 1276 | "_f_vsix": { "iconPath": "../../icons/file_type_vsix.svg" }, | ||
| 1277 | "_f_light_vsix": { "iconPath": "../../icons/file_type_light_vsix.svg" }, | ||
| 1278 | "_f_vsixmanifest": { "iconPath": "../../icons/file_type_vsixmanifest.svg" }, | ||
| 1279 | "_f_light_vsixmanifest": { "iconPath": "../../icons/file_type_light_vsixmanifest.svg" }, | ||
| 1280 | "_f_vue": { "iconPath": "../../icons/file_type_vue.svg" }, | ||
| 1281 | "_f_vueconfig": { "iconPath": "../../icons/file_type_vueconfig.svg" }, | ||
| 1282 | "_f_vvvvvv": { "iconPath": "../../icons/file_type_vvvvvv.svg" }, | ||
| 1283 | "_f_vyper": { "iconPath": "../../icons/file_type_vyper.svg" }, | ||
| 1284 | "_f_wallaby": { "iconPath": "../../icons/file_type_wallaby.svg" }, | ||
| 1285 | "_f_wally": { "iconPath": "../../icons/file_type_wally.svg" }, | ||
| 1286 | "_f_wasm": { "iconPath": "../../icons/file_type_wasm.svg" }, | ||
| 1287 | "_f_watchmanconfig": { "iconPath": "../../icons/file_type_watchmanconfig.svg" }, | ||
| 1288 | "_f_wdio": { "iconPath": "../../icons/file_type_wdio.svg" }, | ||
| 1289 | "_f_weblate": { "iconPath": "../../icons/file_type_weblate.svg" }, | ||
| 1290 | "_f_webpack": { "iconPath": "../../icons/file_type_webpack.svg" }, | ||
| 1291 | "_f_wenyan": { "iconPath": "../../icons/file_type_wenyan.svg" }, | ||
| 1292 | "_f_wercker": { "iconPath": "../../icons/file_type_wercker.svg" }, | ||
| 1293 | "_f_wgsl": { "iconPath": "../../icons/file_type_wgsl.svg" }, | ||
| 1294 | "_f_wikitext": { "iconPath": "../../icons/file_type_wikitext.svg" }, | ||
| 1295 | "_f_windi": { "iconPath": "../../icons/file_type_windi.svg" }, | ||
| 1296 | "_f_wit": { "iconPath": "../../icons/file_type_wit.svg" }, | ||
| 1297 | "_f_wolfram": { "iconPath": "../../icons/file_type_wolfram.svg" }, | ||
| 1298 | "_f_word": { "iconPath": "../../icons/file_type_word.svg" }, | ||
| 1299 | "_f_wpml": { "iconPath": "../../icons/file_type_wpml.svg" }, | ||
| 1300 | "_f_wurst": { "iconPath": "../../icons/file_type_wurst.svg" }, | ||
| 1301 | "_f_wxml": { "iconPath": "../../icons/file_type_wxml.svg" }, | ||
| 1302 | "_f_wxss": { "iconPath": "../../icons/file_type_wxss.svg" }, | ||
| 1303 | "_f_wxt": { "iconPath": "../../icons/file_type_wxt.svg" }, | ||
| 1304 | "_f_xaml": { "iconPath": "../../icons/file_type_xaml.svg" }, | ||
| 1305 | "_f_xcode": { "iconPath": "../../icons/file_type_xcode.svg" }, | ||
| 1306 | "_f_xfl": { "iconPath": "../../icons/file_type_xfl.svg" }, | ||
| 1307 | "_f_light_xfl": { "iconPath": "../../icons/file_type_light_xfl.svg" }, | ||
| 1308 | "_f_xib": { "iconPath": "../../icons/file_type_xib.svg" }, | ||
| 1309 | "_f_xliff": { "iconPath": "../../icons/file_type_xliff.svg" }, | ||
| 1310 | "_f_xmake": { "iconPath": "../../icons/file_type_xmake.svg" }, | ||
| 1311 | "_f_xml": { "iconPath": "../../icons/file_type_xml.svg" }, | ||
| 1312 | "_f_xo": { "iconPath": "../../icons/file_type_xo.svg" }, | ||
| 1313 | "_f_xorg": { "iconPath": "../../icons/file_type_xorg.svg" }, | ||
| 1314 | "_f_light_xorg": { "iconPath": "../../icons/file_type_light_xorg.svg" }, | ||
| 1315 | "_f_xquery": { "iconPath": "../../icons/file_type_xquery.svg" }, | ||
| 1316 | "_f_xsl": { "iconPath": "../../icons/file_type_xsl.svg" }, | ||
| 1317 | "_f_yacc": { "iconPath": "../../icons/file_type_yacc.svg" }, | ||
| 1318 | "_f_yaml": { "iconPath": "../../icons/file_type_yaml.svg" }, | ||
| 1319 | "_f_light_yaml": { "iconPath": "../../icons/file_type_light_yaml.svg" }, | ||
| 1320 | "_f_yamllint": { "iconPath": "../../icons/file_type_yamllint.svg" }, | ||
| 1321 | "_f_yandex": { "iconPath": "../../icons/file_type_yandex.svg" }, | ||
| 1322 | "_f_yang": { "iconPath": "../../icons/file_type_yang.svg" }, | ||
| 1323 | "_f_yarn": { "iconPath": "../../icons/file_type_yarn.svg" }, | ||
| 1324 | "_f_yeoman": { "iconPath": "../../icons/file_type_yeoman.svg" }, | ||
| 1325 | "_f_zig": { "iconPath": "../../icons/file_type_zig.svg" }, | ||
| 1326 | "_f_zip": { "iconPath": "../../icons/file_type_zip.svg" } | ||
| 1327 | }, | ||
| 1328 | "file": "_file", | ||
| 1329 | "folder": "_folder", | ||
| 1330 | "folderExpanded": "_folder_open", | ||
| 1331 | "rootFolder": "_root_folder", | ||
| 1332 | "rootFolderExpanded": "_root_folder_open", | ||
| 1333 | "folderNames": { | ||
| 1334 | "android": "_fd_android", | ||
| 1335 | ".angular": "_fd_angular", | ||
| 1336 | "apache": "_fd_apache", | ||
| 1337 | "apache2": "_fd_apache", | ||
| 1338 | "httpd": "_fd_apache", | ||
| 1339 | "api": "_fd_api", | ||
| 1340 | ".api": "_fd_api", | ||
| 1341 | "apis": "_fd_api", | ||
| 1342 | ".apis": "_fd_api", | ||
| 1343 | "app": "_fd_app", | ||
| 1344 | "apps": "_fd_app", | ||
| 1345 | ".app": "_fd_app", | ||
| 1346 | "application": "_fd_app", | ||
| 1347 | "applications": "_fd_app", | ||
| 1348 | "arangodb": "_fd_arangodb", | ||
| 1349 | "arango": "_fd_arangodb", | ||
| 1350 | "assets": "_fd_asset", | ||
| 1351 | ".assets": "_fd_asset", | ||
| 1352 | ".astro": "_fd_astro", | ||
| 1353 | "audio": "_fd_audio", | ||
| 1354 | ".audio": "_fd_audio", | ||
| 1355 | "audios": "_fd_audio", | ||
| 1356 | ".audios": "_fd_audio", | ||
| 1357 | "sound": "_fd_audio", | ||
| 1358 | ".sound": "_fd_audio", | ||
| 1359 | "sounds": "_fd_audio", | ||
| 1360 | ".sounds": "_fd_audio", | ||
| 1361 | "aurelia_project": "_fd_aurelia", | ||
| 1362 | "aws": "_fd_aws", | ||
| 1363 | ".aws": "_fd_aws", | ||
| 1364 | "azure": "_fd_azure", | ||
| 1365 | ".azure": "_fd_azure", | ||
| 1366 | "azure-pipelines": "_fd_azurepipelines", | ||
| 1367 | ".azure-pipelines": "_fd_azurepipelines", | ||
| 1368 | "bin": "_fd_binary", | ||
| 1369 | ".bin": "_fd_binary", | ||
| 1370 | "blocs": "_fd_bloc", | ||
| 1371 | "bloc": "_fd_bloc", | ||
| 1372 | "blueprint": "_fd_blueprint", | ||
| 1373 | ".blueprint": "_fd_blueprint", | ||
| 1374 | "blueprints": "_fd_blueprint", | ||
| 1375 | ".blueprints": "_fd_blueprint", | ||
| 1376 | "bot": "_fd_bot", | ||
| 1377 | ".bot": "_fd_bot", | ||
| 1378 | "bower_components": "_fd_bower", | ||
| 1379 | ".buildkite": "_fd_buildkite", | ||
| 1380 | "cake": "_fd_cake", | ||
| 1381 | ".cake": "_fd_cake", | ||
| 1382 | "cargo": "_fd_cargo", | ||
| 1383 | ".cargo": "_fd_cargo", | ||
| 1384 | "crates": "_fd_cargo", | ||
| 1385 | "certificates": "_fd_certificate", | ||
| 1386 | ".certificates": "_fd_certificate", | ||
| 1387 | "certs": "_fd_certificate", | ||
| 1388 | "certs.": "_fd_certificate", | ||
| 1389 | ".changeset": "_fd_changesets", | ||
| 1390 | "chef": "_fd_chef", | ||
| 1391 | ".chef": "_fd_chef", | ||
| 1392 | ".circleci": "_fd_circleci", | ||
| 1393 | ".claude": "_fd_claude", | ||
| 1394 | "cli": "_fd_cli", | ||
| 1395 | "cmd": "_fd_cli", | ||
| 1396 | "command": "_fd_cli", | ||
| 1397 | "commands": "_fd_cli", | ||
| 1398 | "commandline": "_fd_cli", | ||
| 1399 | "console": "_fd_cli", | ||
| 1400 | "client": "_fd_client", | ||
| 1401 | "clients": "_fd_client", | ||
| 1402 | ".cloudflare": "_fd_cloudflare", | ||
| 1403 | "cloudflare": "_fd_cloudflare", | ||
| 1404 | ".cmake": "_fd_cmake", | ||
| 1405 | "cmake": "_fd_cmake", | ||
| 1406 | "common": "_fd_common", | ||
| 1407 | "component": "_fd_component", | ||
| 1408 | "components": "_fd_component", | ||
| 1409 | ".components": "_fd_component", | ||
| 1410 | "gui": "_fd_component", | ||
| 1411 | "src-ui": "_fd_component", | ||
| 1412 | "ui": "_fd_component", | ||
| 1413 | "widgets": "_fd_component", | ||
| 1414 | "composer": "_fd_composer", | ||
| 1415 | ".composer": "_fd_composer", | ||
| 1416 | "conf": "_fd_config", | ||
| 1417 | ".conf": "_fd_config", | ||
| 1418 | "config": "_fd_config", | ||
| 1419 | ".config": "_fd_config", | ||
| 1420 | "configs": "_fd_config", | ||
| 1421 | ".configs": "_fd_config", | ||
| 1422 | "configuration": "_fd_config", | ||
| 1423 | ".configuration": "_fd_config", | ||
| 1424 | "configurations": "_fd_config", | ||
| 1425 | ".configurations": "_fd_config", | ||
| 1426 | "setting": "_fd_config", | ||
| 1427 | ".setting": "_fd_config", | ||
| 1428 | "settings": "_fd_config", | ||
| 1429 | ".settings": "_fd_config", | ||
| 1430 | "ini": "_fd_config", | ||
| 1431 | ".ini": "_fd_config", | ||
| 1432 | "initializers": "_fd_config", | ||
| 1433 | ".initializers": "_fd_config", | ||
| 1434 | "__controller__": "_fd_controller", | ||
| 1435 | "__controllers__": "_fd_controller", | ||
| 1436 | "controller": "_fd_controller", | ||
| 1437 | "controllers": "_fd_controller", | ||
| 1438 | ".controllers": "_fd_controller", | ||
| 1439 | "__handler__": "_fd_controller", | ||
| 1440 | "__handlers__": "_fd_controller", | ||
| 1441 | "handler": "_fd_controller", | ||
| 1442 | ".handler": "_fd_controller", | ||
| 1443 | "handlers": "_fd_controller", | ||
| 1444 | ".handlers": "_fd_controller", | ||
| 1445 | "coverage": "_fd_coverage", | ||
| 1446 | "css": "_fd_css", | ||
| 1447 | "_css": "_fd_css", | ||
| 1448 | "cubits": "_fd_cubit", | ||
| 1449 | "cubit": "_fd_cubit", | ||
| 1450 | ".cursor": "_fd_cursor", | ||
| 1451 | "cypress": "_fd_cypress", | ||
| 1452 | ".dapr": "_fd_dapr", | ||
| 1453 | "dapr": "_fd_dapr", | ||
| 1454 | "dart": "_fd_dart", | ||
| 1455 | ".dart_tool": "_fd_dart", | ||
| 1456 | "datadog": "_fd_datadog", | ||
| 1457 | ".datadog": "_fd_datadog", | ||
| 1458 | "db": "_fd_db", | ||
| 1459 | "database": "_fd_db", | ||
| 1460 | "sql": "_fd_db", | ||
| 1461 | "data": "_fd_db", | ||
| 1462 | "repo": "_fd_db", | ||
| 1463 | "repository": "_fd_db", | ||
| 1464 | "repositories": "_fd_db", | ||
| 1465 | "store": "_fd_db", | ||
| 1466 | "stores": "_fd_db", | ||
| 1467 | "debian": "_fd_debian", | ||
| 1468 | "deb": "_fd_debian", | ||
| 1469 | ".dependabot": "_fd_dependabot", | ||
| 1470 | ".devcontainer": "_fd_devcontainer", | ||
| 1471 | "dist": "_fd_dist", | ||
| 1472 | ".dist": "_fd_dist", | ||
| 1473 | "dists": "_fd_dist", | ||
| 1474 | "out": "_fd_dist", | ||
| 1475 | "outs": "_fd_dist", | ||
| 1476 | "export": "_fd_dist", | ||
| 1477 | "exports": "_fd_dist", | ||
| 1478 | "build": "_fd_dist", | ||
| 1479 | ".build": "_fd_dist", | ||
| 1480 | "builds": "_fd_dist", | ||
| 1481 | "release": "_fd_dist", | ||
| 1482 | "releases": "_fd_dist", | ||
| 1483 | "target": "_fd_dist", | ||
| 1484 | "targets": "_fd_dist", | ||
| 1485 | "docker": "_fd_docker", | ||
| 1486 | ".docker": "_fd_docker", | ||
| 1487 | "docs": "_fd_docs", | ||
| 1488 | "doc": "_fd_docs", | ||
| 1489 | "document": "_fd_docs", | ||
| 1490 | "documents": "_fd_docs", | ||
| 1491 | "e2e": "_fd_e2e", | ||
| 1492 | ".elasticbeanstalk": "_fd_elasticbeanstalk", | ||
| 1493 | ".ebextensions": "_fd_elasticbeanstalk", | ||
| 1494 | "electron": "_fd_electron", | ||
| 1495 | ".expo": "_fd_expo", | ||
| 1496 | ".expo-shared": "_fd_expo", | ||
| 1497 | "favicon": "_fd_favicon", | ||
| 1498 | "favicons": "_fd_favicon", | ||
| 1499 | "flow": "_fd_flow", | ||
| 1500 | "flow-typed": "_fd_flow", | ||
| 1501 | "flutter": "_fd_flutter", | ||
| 1502 | "Flutter": "_fd_flutter", | ||
| 1503 | "fonts": "_fd_fonts", | ||
| 1504 | "font": "_fd_fonts", | ||
| 1505 | "fnt": "_fd_fonts", | ||
| 1506 | "webfonts": "_fd_fonts", | ||
| 1507 | ".front-commerce": "_fd_frontcommerce", | ||
| 1508 | "gcp": "_fd_gcp", | ||
| 1509 | ".gcp": "_fd_gcp", | ||
| 1510 | ".gemini": "_fd_gemini", | ||
| 1511 | ".git": "_fd_git", | ||
| 1512 | "submodules": "_fd_git", | ||
| 1513 | ".submodules": "_fd_git", | ||
| 1514 | ".github": "_fd_github", | ||
| 1515 | ".gitlab": "_fd_gitlab", | ||
| 1516 | "godot": "_fd_godot", | ||
| 1517 | ".godot": "_fd_godot", | ||
| 1518 | "gradle": "_fd_gradle", | ||
| 1519 | ".gradle": "_fd_gradle", | ||
| 1520 | "graphql": "_fd_graphql", | ||
| 1521 | "grunt": "_fd_grunt", | ||
| 1522 | "gulp": "_fd_gulp", | ||
| 1523 | "gulpfile.js": "_fd_gulp", | ||
| 1524 | "gulpfile.coffee": "_fd_gulp", | ||
| 1525 | "gulpfile.ts": "_fd_gulp", | ||
| 1526 | "gulpfile.babel.js": "_fd_gulp", | ||
| 1527 | "gulpfile.babel.coffee": "_fd_gulp", | ||
| 1528 | "gulpfile.babel.ts": "_fd_gulp", | ||
| 1529 | ".haxelib": "_fd_haxelib", | ||
| 1530 | "haxe_libraries": "_fd_haxelib", | ||
| 1531 | "helper": "_fd_helper", | ||
| 1532 | ".helper": "_fd_helper", | ||
| 1533 | "helpers": "_fd_helper", | ||
| 1534 | ".helpers": "_fd_helper", | ||
| 1535 | ".histoire": "_fd_histoire", | ||
| 1536 | "hook": "_fd_hook", | ||
| 1537 | ".hook": "_fd_hook", | ||
| 1538 | "hooks": "_fd_hook", | ||
| 1539 | ".hooks": "_fd_hook", | ||
| 1540 | ".husky": "_fd_husky", | ||
| 1541 | ".idea": "_fd_idea", | ||
| 1542 | ".fig": "_fd_images", | ||
| 1543 | ".figs": "_fd_images", | ||
| 1544 | "images": "_fd_images", | ||
| 1545 | "image": "_fd_images", | ||
| 1546 | ".img": "_fd_images", | ||
| 1547 | "img": "_fd_images", | ||
| 1548 | ".imgs": "_fd_images", | ||
| 1549 | "imgs": "_fd_images", | ||
| 1550 | "icons": "_fd_images", | ||
| 1551 | "icon": "_fd_images", | ||
| 1552 | "ico": "_fd_images", | ||
| 1553 | "screenshot": "_fd_images", | ||
| 1554 | "screenshots": "_fd_images", | ||
| 1555 | "svg": "_fd_images", | ||
| 1556 | "texture": "_fd_images", | ||
| 1557 | "textures": "_fd_images", | ||
| 1558 | "include": "_fd_include", | ||
| 1559 | "includes": "_fd_include", | ||
| 1560 | "incl": "_fd_include", | ||
| 1561 | "inc": "_fd_include", | ||
| 1562 | ".include": "_fd_include", | ||
| 1563 | ".includes": "_fd_include", | ||
| 1564 | ".incl": "_fd_include", | ||
| 1565 | ".inc": "_fd_include", | ||
| 1566 | "_include": "_fd_include", | ||
| 1567 | "_includes": "_fd_include", | ||
| 1568 | "_incl": "_fd_include", | ||
| 1569 | "_inc": "_fd_include", | ||
| 1570 | "interface": "_fd_interfaces", | ||
| 1571 | "interfaces": "_fd_interfaces", | ||
| 1572 | "ios": "_fd_ios", | ||
| 1573 | "js": "_fd_js", | ||
| 1574 | "json": "_fd_json", | ||
| 1575 | ".junie": "_fd_junie", | ||
| 1576 | "kotlin": "_fd_kotlin", | ||
| 1577 | "Kotlin": "_fd_kotlin", | ||
| 1578 | ".kotlin": "_fd_kotlin", | ||
| 1579 | "kubernetes": "_fd_kubernetes", | ||
| 1580 | "k8s": "_fd_kubernetes", | ||
| 1581 | "kube": "_fd_kubernetes", | ||
| 1582 | "kuber": "_fd_kubernetes", | ||
| 1583 | ".kubernetes": "_fd_kubernetes", | ||
| 1584 | ".k8s": "_fd_kubernetes", | ||
| 1585 | ".kube": "_fd_kubernetes", | ||
| 1586 | ".kuber": "_fd_kubernetes", | ||
| 1587 | "less": "_fd_less", | ||
| 1588 | "_less": "_fd_less", | ||
| 1589 | "lib": "_fd_library", | ||
| 1590 | "libs": "_fd_library", | ||
| 1591 | ".lib": "_fd_library", | ||
| 1592 | ".libs": "_fd_library", | ||
| 1593 | "__lib__": "_fd_library", | ||
| 1594 | "__libs__": "_fd_library", | ||
| 1595 | "library": "_fd_library", | ||
| 1596 | "libraries": "_fd_library", | ||
| 1597 | "linux": "_fd_linux", | ||
| 1598 | "lang": "_fd_locale", | ||
| 1599 | "language": "_fd_locale", | ||
| 1600 | "languages": "_fd_locale", | ||
| 1601 | "locale": "_fd_locale", | ||
| 1602 | "locales": "_fd_locale", | ||
| 1603 | "_locale": "_fd_locale", | ||
| 1604 | "_locales": "_fd_locale", | ||
| 1605 | "internationalization": "_fd_locale", | ||
| 1606 | "globalization": "_fd_locale", | ||
| 1607 | "localization": "_fd_locale", | ||
| 1608 | "i18n": "_fd_locale", | ||
| 1609 | "g11n": "_fd_locale", | ||
| 1610 | "l10n": "_fd_locale", | ||
| 1611 | "log": "_fd_log", | ||
| 1612 | "logs": "_fd_log", | ||
| 1613 | "macos": "_fd_macos", | ||
| 1614 | "darwin": "_fd_macos", | ||
| 1615 | "mariadb": "_fd_mariadb", | ||
| 1616 | "maria": "_fd_mariadb", | ||
| 1617 | ".mvn": "_fd_maven", | ||
| 1618 | "mediawiki": "_fd_mediawiki", | ||
| 1619 | "memcached": "_fd_memcached", | ||
| 1620 | ".memcached": "_fd_memcached", | ||
| 1621 | ".meteor": "_fd_meteor", | ||
| 1622 | "middleware": "_fd_middleware", | ||
| 1623 | "middlewares": "_fd_middleware", | ||
| 1624 | ".minecraft": "_fd_minecraft", | ||
| 1625 | "minikube": "_fd_minikube", | ||
| 1626 | "minik8s": "_fd_minikube", | ||
| 1627 | "minikuber": "_fd_minikube", | ||
| 1628 | "mjml": "_fd_mjml", | ||
| 1629 | ".mjml": "_fd_mjml", | ||
| 1630 | "mocks": "_fd_mock", | ||
| 1631 | ".mocks": "_fd_mock", | ||
| 1632 | "__mocks__": "_fd_mock", | ||
| 1633 | "model": "_fd_model", | ||
| 1634 | ".model": "_fd_model", | ||
| 1635 | "models": "_fd_model", | ||
| 1636 | ".models": "_fd_model", | ||
| 1637 | "entities": "_fd_model", | ||
| 1638 | ".entities": "_fd_model", | ||
| 1639 | "modules": "_fd_module", | ||
| 1640 | "mojo": "_fd_mojo", | ||
| 1641 | "mongodb": "_fd_mongodb", | ||
| 1642 | "mongo": "_fd_mongodb", | ||
| 1643 | ".mypy_cache": "_fd_mypy", | ||
| 1644 | "mysqldb": "_fd_mysql", | ||
| 1645 | "mysql": "_fd_mysql", | ||
| 1646 | "netlify": "_fd_netlify", | ||
| 1647 | ".next": "_fd_next", | ||
| 1648 | "nginx": "_fd_nginx", | ||
| 1649 | "conf.d": "_fd_nginx", | ||
| 1650 | ".niv": "_fd_nix", | ||
| 1651 | ".nix": "_fd_nix", | ||
| 1652 | "nix": "_fd_nix", | ||
| 1653 | "niv": "_fd_nix", | ||
| 1654 | "node_modules": "_fd_node", | ||
| 1655 | "notebooks": "_fd_notebooks", | ||
| 1656 | "notebook": "_fd_notebooks", | ||
| 1657 | "notification": "_fd_notification", | ||
| 1658 | "notifications": "_fd_notification", | ||
| 1659 | "event": "_fd_notification", | ||
| 1660 | "events": "_fd_notification", | ||
| 1661 | ".nuget": "_fd_nuget", | ||
| 1662 | "nuxt": "_fd_nuxt", | ||
| 1663 | ".nuxt": "_fd_nuxt", | ||
| 1664 | "package": "_fd_package", | ||
| 1665 | "packages": "_fd_package", | ||
| 1666 | ".package": "_fd_package", | ||
| 1667 | ".packages": "_fd_package", | ||
| 1668 | "pkg": "_fd_package", | ||
| 1669 | ".paket": "_fd_paket", | ||
| 1670 | "php": "_fd_php", | ||
| 1671 | ".pio": "_fd_platformio", | ||
| 1672 | ".pioenvs": "_fd_platformio", | ||
| 1673 | "plugin": "_fd_plugin", | ||
| 1674 | ".plugin": "_fd_plugin", | ||
| 1675 | "plugins": "_fd_plugin", | ||
| 1676 | ".plugins": "_fd_plugin", | ||
| 1677 | "extension": "_fd_plugin", | ||
| 1678 | ".extension": "_fd_plugin", | ||
| 1679 | "extensions": "_fd_plugin", | ||
| 1680 | ".extensions": "_fd_plugin", | ||
| 1681 | "prisma": "_fd_prisma", | ||
| 1682 | "private": "_fd_private", | ||
| 1683 | ".private": "_fd_private", | ||
| 1684 | "public": "_fd_public", | ||
| 1685 | ".public": "_fd_public", | ||
| 1686 | ".pytest_cache": "_fd_pytest", | ||
| 1687 | ".venv": "_fd_python", | ||
| 1688 | ".virtualenv": "_fd_python", | ||
| 1689 | "__pycache__": "_fd_python", | ||
| 1690 | "ravendb": "_fd_ravendb", | ||
| 1691 | "redis": "_fd_redis", | ||
| 1692 | "redux": "_fd_redux", | ||
| 1693 | "route": "_fd_route", | ||
| 1694 | "routes": "_fd_route", | ||
| 1695 | "_route": "_fd_route", | ||
| 1696 | "_routes": "_fd_route", | ||
| 1697 | "router": "_fd_route", | ||
| 1698 | "routers": "_fd_route", | ||
| 1699 | "sass": "_fd_sass", | ||
| 1700 | "scss": "_fd_sass", | ||
| 1701 | "_sass": "_fd_sass", | ||
| 1702 | "_scss": "_fd_sass", | ||
| 1703 | "script": "_fd_script", | ||
| 1704 | "scripts": "_fd_script", | ||
| 1705 | "seedkit": "_fd_seedkit", | ||
| 1706 | ".seedkit": "_fd_seedkit", | ||
| 1707 | "server": "_fd_server", | ||
| 1708 | "service": "_fd_services", | ||
| 1709 | "services": "_fd_services", | ||
| 1710 | "share": "_fd_shared", | ||
| 1711 | "shared": "_fd_shared", | ||
| 1712 | ".share": "_fd_shared", | ||
| 1713 | ".shared": "_fd_shared", | ||
| 1714 | "__shared__": "_fd_shared", | ||
| 1715 | "__share__": "_fd_shared", | ||
| 1716 | ".snaplet": "_fd_snaplet", | ||
| 1717 | ".spin": "_fd_spin", | ||
| 1718 | "src": "_fd_src", | ||
| 1719 | "source": "_fd_src", | ||
| 1720 | "sources": "_fd_src", | ||
| 1721 | "__src__": "_fd_src", | ||
| 1722 | "sso": "_fd_sso", | ||
| 1723 | "story": "_fd_story", | ||
| 1724 | "stories": "_fd_story", | ||
| 1725 | "__stories__": "_fd_story", | ||
| 1726 | ".storybook": "_fd_story", | ||
| 1727 | "style": "_fd_style", | ||
| 1728 | "styles": "_fd_style", | ||
| 1729 | "supabase": "_fd_supabase", | ||
| 1730 | "svelte": "_fd_svelte", | ||
| 1731 | ".svelte-kit": "_fd_svelte", | ||
| 1732 | "src-tauri": "_fd_tauri", | ||
| 1733 | "temp": "_fd_temp", | ||
| 1734 | ".temp": "_fd_temp", | ||
| 1735 | "tmp": "_fd_temp", | ||
| 1736 | ".tmp": "_fd_temp", | ||
| 1737 | "template": "_fd_template", | ||
| 1738 | ".template": "_fd_template", | ||
| 1739 | "templates": "_fd_template", | ||
| 1740 | ".templates": "_fd_template", | ||
| 1741 | "tests": "_fd_test", | ||
| 1742 | ".tests": "_fd_test", | ||
| 1743 | "test": "_fd_test", | ||
| 1744 | ".test": "_fd_test", | ||
| 1745 | "__tests__": "_fd_test", | ||
| 1746 | "__test__": "_fd_test", | ||
| 1747 | "spec": "_fd_test", | ||
| 1748 | ".spec": "_fd_test", | ||
| 1749 | "specs": "_fd_test", | ||
| 1750 | ".specs": "_fd_test", | ||
| 1751 | "integration": "_fd_test", | ||
| 1752 | "theme": "_fd_theme", | ||
| 1753 | "themes": "_fd_theme", | ||
| 1754 | "tool": "_fd_tools", | ||
| 1755 | "tools": "_fd_tools", | ||
| 1756 | ".tools": "_fd_tools", | ||
| 1757 | "util": "_fd_tools", | ||
| 1758 | "utils": "_fd_tools", | ||
| 1759 | "utilities": "_fd_tools", | ||
| 1760 | "tooling": "_fd_tools", | ||
| 1761 | ".travis": "_fd_travis", | ||
| 1762 | ".trunk": "_fd_trunk", | ||
| 1763 | ".turbo": "_fd_turbo", | ||
| 1764 | "typescript": "_fd_typescript", | ||
| 1765 | "ts": "_fd_typescript", | ||
| 1766 | "typings": "_fd_typings", | ||
| 1767 | "types": "_fd_typings", | ||
| 1768 | "@types": "_fd_typings", | ||
| 1769 | "vagrant": "_fd_vagrant", | ||
| 1770 | ".vagrant": "_fd_vagrant", | ||
| 1771 | ".vercel": "_fd_vercel", | ||
| 1772 | "video": "_fd_video", | ||
| 1773 | ".video": "_fd_video", | ||
| 1774 | "videos": "_fd_video", | ||
| 1775 | ".videos": "_fd_video", | ||
| 1776 | "html": "_fd_view", | ||
| 1777 | "view": "_fd_view", | ||
| 1778 | "views": "_fd_view", | ||
| 1779 | "layout": "_fd_view", | ||
| 1780 | "layouts": "_fd_view", | ||
| 1781 | "page": "_fd_view", | ||
| 1782 | "pages": "_fd_view", | ||
| 1783 | "_view": "_fd_view", | ||
| 1784 | "_views": "_fd_view", | ||
| 1785 | "_layout": "_fd_view", | ||
| 1786 | "_layouts": "_fd_view", | ||
| 1787 | "_page": "_fd_view", | ||
| 1788 | "_pages": "_fd_view", | ||
| 1789 | ".vitepress": "_fd_vitepress", | ||
| 1790 | ".vs": "_fd_vs", | ||
| 1791 | ".vscode": "_fd_vscode", | ||
| 1792 | "vscode": "_fd_vscode", | ||
| 1793 | ".vscode-test": "_fd_vscode_test", | ||
| 1794 | "wasm": "_fd_wasm", | ||
| 1795 | "WASM": "_fd_wasm", | ||
| 1796 | "webassembly": "_fd_wasm", | ||
| 1797 | "WebAssembly": "_fd_wasm", | ||
| 1798 | "webpack": "_fd_webpack", | ||
| 1799 | ".webpack": "_fd_webpack", | ||
| 1800 | "windows": "_fd_windows", | ||
| 1801 | "win32": "_fd_windows", | ||
| 1802 | ".windsurf": "_fd_windsurf", | ||
| 1803 | "wit": "_fd_wit", | ||
| 1804 | ".web": "_fd_www", | ||
| 1805 | "www": "_fd_www", | ||
| 1806 | "wwwroot": "_fd_www", | ||
| 1807 | "web": "_fd_www", | ||
| 1808 | ".yarn": "_fd_yarn", | ||
| 1809 | ".zed": "_fd_zed" | ||
| 1810 | }, | ||
| 1811 | "folderNamesExpanded": { | ||
| 1812 | "android": "_fd_android_open", | ||
| 1813 | ".angular": "_fd_angular_open", | ||
| 1814 | "apache": "_fd_apache_open", | ||
| 1815 | "apache2": "_fd_apache_open", | ||
| 1816 | "httpd": "_fd_apache_open", | ||
| 1817 | "api": "_fd_api_open", | ||
| 1818 | ".api": "_fd_api_open", | ||
| 1819 | "apis": "_fd_api_open", | ||
| 1820 | ".apis": "_fd_api_open", | ||
| 1821 | "app": "_fd_app_open", | ||
| 1822 | "apps": "_fd_app_open", | ||
| 1823 | ".app": "_fd_app_open", | ||
| 1824 | "application": "_fd_app_open", | ||
| 1825 | "applications": "_fd_app_open", | ||
| 1826 | "arangodb": "_fd_arangodb_open", | ||
| 1827 | "arango": "_fd_arangodb_open", | ||
| 1828 | "assets": "_fd_asset_open", | ||
| 1829 | ".assets": "_fd_asset_open", | ||
| 1830 | ".astro": "_fd_astro_open", | ||
| 1831 | "audio": "_fd_audio_open", | ||
| 1832 | ".audio": "_fd_audio_open", | ||
| 1833 | "audios": "_fd_audio_open", | ||
| 1834 | ".audios": "_fd_audio_open", | ||
| 1835 | "sound": "_fd_audio_open", | ||
| 1836 | ".sound": "_fd_audio_open", | ||
| 1837 | "sounds": "_fd_audio_open", | ||
| 1838 | ".sounds": "_fd_audio_open", | ||
| 1839 | "aurelia_project": "_fd_aurelia_open", | ||
| 1840 | "aws": "_fd_aws_open", | ||
| 1841 | ".aws": "_fd_aws_open", | ||
| 1842 | "azure": "_fd_azure_open", | ||
| 1843 | ".azure": "_fd_azure_open", | ||
| 1844 | "azure-pipelines": "_fd_azurepipelines_open", | ||
| 1845 | ".azure-pipelines": "_fd_azurepipelines_open", | ||
| 1846 | "bin": "_fd_binary_open", | ||
| 1847 | ".bin": "_fd_binary_open", | ||
| 1848 | "blocs": "_fd_bloc_open", | ||
| 1849 | "bloc": "_fd_bloc_open", | ||
| 1850 | "blueprint": "_fd_blueprint_open", | ||
| 1851 | ".blueprint": "_fd_blueprint_open", | ||
| 1852 | "blueprints": "_fd_blueprint_open", | ||
| 1853 | ".blueprints": "_fd_blueprint_open", | ||
| 1854 | "bot": "_fd_bot_open", | ||
| 1855 | ".bot": "_fd_bot_open", | ||
| 1856 | "bower_components": "_fd_bower_open", | ||
| 1857 | ".buildkite": "_fd_buildkite_open", | ||
| 1858 | "cake": "_fd_cake_open", | ||
| 1859 | ".cake": "_fd_cake_open", | ||
| 1860 | "cargo": "_fd_cargo_open", | ||
| 1861 | ".cargo": "_fd_cargo_open", | ||
| 1862 | "crates": "_fd_cargo_open", | ||
| 1863 | "certificates": "_fd_certificate_open", | ||
| 1864 | ".certificates": "_fd_certificate_open", | ||
| 1865 | "certs": "_fd_certificate_open", | ||
| 1866 | "certs.": "_fd_certificate_open", | ||
| 1867 | ".changeset": "_fd_changesets_open", | ||
| 1868 | "chef": "_fd_chef_open", | ||
| 1869 | ".chef": "_fd_chef_open", | ||
| 1870 | ".circleci": "_fd_circleci_open", | ||
| 1871 | ".claude": "_fd_claude_open", | ||
| 1872 | "cli": "_fd_cli_open", | ||
| 1873 | "cmd": "_fd_cli_open", | ||
| 1874 | "command": "_fd_cli_open", | ||
| 1875 | "commands": "_fd_cli_open", | ||
| 1876 | "commandline": "_fd_cli_open", | ||
| 1877 | "console": "_fd_cli_open", | ||
| 1878 | "client": "_fd_client_open", | ||
| 1879 | "clients": "_fd_client_open", | ||
| 1880 | ".cloudflare": "_fd_cloudflare_open", | ||
| 1881 | "cloudflare": "_fd_cloudflare_open", | ||
| 1882 | ".cmake": "_fd_cmake_open", | ||
| 1883 | "cmake": "_fd_cmake_open", | ||
| 1884 | "common": "_fd_common_open", | ||
| 1885 | "component": "_fd_component_open", | ||
| 1886 | "components": "_fd_component_open", | ||
| 1887 | ".components": "_fd_component_open", | ||
| 1888 | "gui": "_fd_component_open", | ||
| 1889 | "src-ui": "_fd_component_open", | ||
| 1890 | "ui": "_fd_component_open", | ||
| 1891 | "widgets": "_fd_component_open", | ||
| 1892 | "composer": "_fd_composer_open", | ||
| 1893 | ".composer": "_fd_composer_open", | ||
| 1894 | "conf": "_fd_config_open", | ||
| 1895 | ".conf": "_fd_config_open", | ||
| 1896 | "config": "_fd_config_open", | ||
| 1897 | ".config": "_fd_config_open", | ||
| 1898 | "configs": "_fd_config_open", | ||
| 1899 | ".configs": "_fd_config_open", | ||
| 1900 | "configuration": "_fd_config_open", | ||
| 1901 | ".configuration": "_fd_config_open", | ||
| 1902 | "configurations": "_fd_config_open", | ||
| 1903 | ".configurations": "_fd_config_open", | ||
| 1904 | "setting": "_fd_config_open", | ||
| 1905 | ".setting": "_fd_config_open", | ||
| 1906 | "settings": "_fd_config_open", | ||
| 1907 | ".settings": "_fd_config_open", | ||
| 1908 | "ini": "_fd_config_open", | ||
| 1909 | ".ini": "_fd_config_open", | ||
| 1910 | "initializers": "_fd_config_open", | ||
| 1911 | ".initializers": "_fd_config_open", | ||
| 1912 | "__controller__": "_fd_controller_open", | ||
| 1913 | "__controllers__": "_fd_controller_open", | ||
| 1914 | "controller": "_fd_controller_open", | ||
| 1915 | "controllers": "_fd_controller_open", | ||
| 1916 | ".controllers": "_fd_controller_open", | ||
| 1917 | "__handler__": "_fd_controller_open", | ||
| 1918 | "__handlers__": "_fd_controller_open", | ||
| 1919 | "handler": "_fd_controller_open", | ||
| 1920 | ".handler": "_fd_controller_open", | ||
| 1921 | "handlers": "_fd_controller_open", | ||
| 1922 | ".handlers": "_fd_controller_open", | ||
| 1923 | "coverage": "_fd_coverage_open", | ||
| 1924 | "css": "_fd_css_open", | ||
| 1925 | "_css": "_fd_css_open", | ||
| 1926 | "cubits": "_fd_cubit_open", | ||
| 1927 | "cubit": "_fd_cubit_open", | ||
| 1928 | ".cursor": "_fd_cursor_open", | ||
| 1929 | "cypress": "_fd_cypress_open", | ||
| 1930 | ".dapr": "_fd_dapr_open", | ||
| 1931 | "dapr": "_fd_dapr_open", | ||
| 1932 | "dart": "_fd_dart_open", | ||
| 1933 | ".dart_tool": "_fd_dart_open", | ||
| 1934 | "datadog": "_fd_datadog_open", | ||
| 1935 | ".datadog": "_fd_datadog_open", | ||
| 1936 | "db": "_fd_db_open", | ||
| 1937 | "database": "_fd_db_open", | ||
| 1938 | "sql": "_fd_db_open", | ||
| 1939 | "data": "_fd_db_open", | ||
| 1940 | "repo": "_fd_db_open", | ||
| 1941 | "repository": "_fd_db_open", | ||
| 1942 | "repositories": "_fd_db_open", | ||
| 1943 | "store": "_fd_db_open", | ||
| 1944 | "stores": "_fd_db_open", | ||
| 1945 | "debian": "_fd_debian_open", | ||
| 1946 | "deb": "_fd_debian_open", | ||
| 1947 | ".dependabot": "_fd_dependabot_open", | ||
| 1948 | ".devcontainer": "_fd_devcontainer_open", | ||
| 1949 | "dist": "_fd_dist_open", | ||
| 1950 | ".dist": "_fd_dist_open", | ||
| 1951 | "dists": "_fd_dist_open", | ||
| 1952 | "out": "_fd_dist_open", | ||
| 1953 | "outs": "_fd_dist_open", | ||
| 1954 | "export": "_fd_dist_open", | ||
| 1955 | "exports": "_fd_dist_open", | ||
| 1956 | "build": "_fd_dist_open", | ||
| 1957 | ".build": "_fd_dist_open", | ||
| 1958 | "builds": "_fd_dist_open", | ||
| 1959 | "release": "_fd_dist_open", | ||
| 1960 | "releases": "_fd_dist_open", | ||
| 1961 | "target": "_fd_dist_open", | ||
| 1962 | "targets": "_fd_dist_open", | ||
| 1963 | "docker": "_fd_docker_open", | ||
| 1964 | ".docker": "_fd_docker_open", | ||
| 1965 | "docs": "_fd_docs_open", | ||
| 1966 | "doc": "_fd_docs_open", | ||
| 1967 | "document": "_fd_docs_open", | ||
| 1968 | "documents": "_fd_docs_open", | ||
| 1969 | "e2e": "_fd_e2e_open", | ||
| 1970 | ".elasticbeanstalk": "_fd_elasticbeanstalk_open", | ||
| 1971 | ".ebextensions": "_fd_elasticbeanstalk_open", | ||
| 1972 | "electron": "_fd_electron_open", | ||
| 1973 | ".expo": "_fd_expo_open", | ||
| 1974 | ".expo-shared": "_fd_expo_open", | ||
| 1975 | "favicon": "_fd_favicon_open", | ||
| 1976 | "favicons": "_fd_favicon_open", | ||
| 1977 | "flow": "_fd_flow_open", | ||
| 1978 | "flow-typed": "_fd_flow_open", | ||
| 1979 | "flutter": "_fd_flutter_open", | ||
| 1980 | "Flutter": "_fd_flutter_open", | ||
| 1981 | "fonts": "_fd_fonts_open", | ||
| 1982 | "font": "_fd_fonts_open", | ||
| 1983 | "fnt": "_fd_fonts_open", | ||
| 1984 | "webfonts": "_fd_fonts_open", | ||
| 1985 | ".front-commerce": "_fd_frontcommerce_open", | ||
| 1986 | "gcp": "_fd_gcp_open", | ||
| 1987 | ".gcp": "_fd_gcp_open", | ||
| 1988 | ".gemini": "_fd_gemini_open", | ||
| 1989 | ".git": "_fd_git_open", | ||
| 1990 | "submodules": "_fd_git_open", | ||
| 1991 | ".submodules": "_fd_git_open", | ||
| 1992 | ".github": "_fd_github_open", | ||
| 1993 | ".gitlab": "_fd_gitlab_open", | ||
| 1994 | "godot": "_fd_godot_open", | ||
| 1995 | ".godot": "_fd_godot_open", | ||
| 1996 | "gradle": "_fd_gradle_open", | ||
| 1997 | ".gradle": "_fd_gradle_open", | ||
| 1998 | "graphql": "_fd_graphql_open", | ||
| 1999 | "grunt": "_fd_grunt_open", | ||
| 2000 | "gulp": "_fd_gulp_open", | ||
| 2001 | "gulpfile.js": "_fd_gulp_open", | ||
| 2002 | "gulpfile.coffee": "_fd_gulp_open", | ||
| 2003 | "gulpfile.ts": "_fd_gulp_open", | ||
| 2004 | "gulpfile.babel.js": "_fd_gulp_open", | ||
| 2005 | "gulpfile.babel.coffee": "_fd_gulp_open", | ||
| 2006 | "gulpfile.babel.ts": "_fd_gulp_open", | ||
| 2007 | ".haxelib": "_fd_haxelib_open", | ||
| 2008 | "haxe_libraries": "_fd_haxelib_open", | ||
| 2009 | "helper": "_fd_helper_open", | ||
| 2010 | ".helper": "_fd_helper_open", | ||
| 2011 | "helpers": "_fd_helper_open", | ||
| 2012 | ".helpers": "_fd_helper_open", | ||
| 2013 | ".histoire": "_fd_histoire_open", | ||
| 2014 | "hook": "_fd_hook_open", | ||
| 2015 | ".hook": "_fd_hook_open", | ||
| 2016 | "hooks": "_fd_hook_open", | ||
| 2017 | ".hooks": "_fd_hook_open", | ||
| 2018 | ".husky": "_fd_husky_open", | ||
| 2019 | ".idea": "_fd_idea_open", | ||
| 2020 | ".fig": "_fd_images_open", | ||
| 2021 | ".figs": "_fd_images_open", | ||
| 2022 | "images": "_fd_images_open", | ||
| 2023 | "image": "_fd_images_open", | ||
| 2024 | ".img": "_fd_images_open", | ||
| 2025 | "img": "_fd_images_open", | ||
| 2026 | ".imgs": "_fd_images_open", | ||
| 2027 | "imgs": "_fd_images_open", | ||
| 2028 | "icons": "_fd_images_open", | ||
| 2029 | "icon": "_fd_images_open", | ||
| 2030 | "ico": "_fd_images_open", | ||
| 2031 | "screenshot": "_fd_images_open", | ||
| 2032 | "screenshots": "_fd_images_open", | ||
| 2033 | "svg": "_fd_images_open", | ||
| 2034 | "texture": "_fd_images_open", | ||
| 2035 | "textures": "_fd_images_open", | ||
| 2036 | "include": "_fd_include_open", | ||
| 2037 | "includes": "_fd_include_open", | ||
| 2038 | "incl": "_fd_include_open", | ||
| 2039 | "inc": "_fd_include_open", | ||
| 2040 | ".include": "_fd_include_open", | ||
| 2041 | ".includes": "_fd_include_open", | ||
| 2042 | ".incl": "_fd_include_open", | ||
| 2043 | ".inc": "_fd_include_open", | ||
| 2044 | "_include": "_fd_include_open", | ||
| 2045 | "_includes": "_fd_include_open", | ||
| 2046 | "_incl": "_fd_include_open", | ||
| 2047 | "_inc": "_fd_include_open", | ||
| 2048 | "interface": "_fd_interfaces_open", | ||
| 2049 | "interfaces": "_fd_interfaces_open", | ||
| 2050 | "ios": "_fd_ios_open", | ||
| 2051 | "js": "_fd_js_open", | ||
| 2052 | "json": "_fd_json_open", | ||
| 2053 | ".junie": "_fd_junie_open", | ||
| 2054 | "kotlin": "_fd_kotlin_open", | ||
| 2055 | "Kotlin": "_fd_kotlin_open", | ||
| 2056 | ".kotlin": "_fd_kotlin_open", | ||
| 2057 | "kubernetes": "_fd_kubernetes_open", | ||
| 2058 | "k8s": "_fd_kubernetes_open", | ||
| 2059 | "kube": "_fd_kubernetes_open", | ||
| 2060 | "kuber": "_fd_kubernetes_open", | ||
| 2061 | ".kubernetes": "_fd_kubernetes_open", | ||
| 2062 | ".k8s": "_fd_kubernetes_open", | ||
| 2063 | ".kube": "_fd_kubernetes_open", | ||
| 2064 | ".kuber": "_fd_kubernetes_open", | ||
| 2065 | "less": "_fd_less_open", | ||
| 2066 | "_less": "_fd_less_open", | ||
| 2067 | "lib": "_fd_library_open", | ||
| 2068 | "libs": "_fd_library_open", | ||
| 2069 | ".lib": "_fd_library_open", | ||
| 2070 | ".libs": "_fd_library_open", | ||
| 2071 | "__lib__": "_fd_library_open", | ||
| 2072 | "__libs__": "_fd_library_open", | ||
| 2073 | "library": "_fd_library_open", | ||
| 2074 | "libraries": "_fd_library_open", | ||
| 2075 | "linux": "_fd_linux_open", | ||
| 2076 | "lang": "_fd_locale_open", | ||
| 2077 | "language": "_fd_locale_open", | ||
| 2078 | "languages": "_fd_locale_open", | ||
| 2079 | "locale": "_fd_locale_open", | ||
| 2080 | "locales": "_fd_locale_open", | ||
| 2081 | "_locale": "_fd_locale_open", | ||
| 2082 | "_locales": "_fd_locale_open", | ||
| 2083 | "internationalization": "_fd_locale_open", | ||
| 2084 | "globalization": "_fd_locale_open", | ||
| 2085 | "localization": "_fd_locale_open", | ||
| 2086 | "i18n": "_fd_locale_open", | ||
| 2087 | "g11n": "_fd_locale_open", | ||
| 2088 | "l10n": "_fd_locale_open", | ||
| 2089 | "log": "_fd_log_open", | ||
| 2090 | "logs": "_fd_log_open", | ||
| 2091 | "macos": "_fd_macos_open", | ||
| 2092 | "darwin": "_fd_macos_open", | ||
| 2093 | "mariadb": "_fd_mariadb_open", | ||
| 2094 | "maria": "_fd_mariadb_open", | ||
| 2095 | ".mvn": "_fd_maven_open", | ||
| 2096 | "mediawiki": "_fd_mediawiki_open", | ||
| 2097 | "memcached": "_fd_memcached_open", | ||
| 2098 | ".memcached": "_fd_memcached_open", | ||
| 2099 | ".meteor": "_fd_meteor_open", | ||
| 2100 | "middleware": "_fd_middleware_open", | ||
| 2101 | "middlewares": "_fd_middleware_open", | ||
| 2102 | ".minecraft": "_fd_minecraft_open", | ||
| 2103 | "minikube": "_fd_minikube_open", | ||
| 2104 | "minik8s": "_fd_minikube_open", | ||
| 2105 | "minikuber": "_fd_minikube_open", | ||
| 2106 | "mjml": "_fd_mjml_open", | ||
| 2107 | ".mjml": "_fd_mjml_open", | ||
| 2108 | "mocks": "_fd_mock_open", | ||
| 2109 | ".mocks": "_fd_mock_open", | ||
| 2110 | "__mocks__": "_fd_mock_open", | ||
| 2111 | "model": "_fd_model_open", | ||
| 2112 | ".model": "_fd_model_open", | ||
| 2113 | "models": "_fd_model_open", | ||
| 2114 | ".models": "_fd_model_open", | ||
| 2115 | "entities": "_fd_model_open", | ||
| 2116 | ".entities": "_fd_model_open", | ||
| 2117 | "modules": "_fd_module_open", | ||
| 2118 | "mojo": "_fd_mojo_open", | ||
| 2119 | "mongodb": "_fd_mongodb_open", | ||
| 2120 | "mongo": "_fd_mongodb_open", | ||
| 2121 | ".mypy_cache": "_fd_mypy_open", | ||
| 2122 | "mysqldb": "_fd_mysql_open", | ||
| 2123 | "mysql": "_fd_mysql_open", | ||
| 2124 | "netlify": "_fd_netlify_open", | ||
| 2125 | ".next": "_fd_next_open", | ||
| 2126 | "nginx": "_fd_nginx_open", | ||
| 2127 | "conf.d": "_fd_nginx_open", | ||
| 2128 | ".niv": "_fd_nix_open", | ||
| 2129 | ".nix": "_fd_nix_open", | ||
| 2130 | "nix": "_fd_nix_open", | ||
| 2131 | "niv": "_fd_nix_open", | ||
| 2132 | "node_modules": "_fd_node_open", | ||
| 2133 | "notebooks": "_fd_notebooks_open", | ||
| 2134 | "notebook": "_fd_notebooks_open", | ||
| 2135 | "notification": "_fd_notification_open", | ||
| 2136 | "notifications": "_fd_notification_open", | ||
| 2137 | "event": "_fd_notification_open", | ||
| 2138 | "events": "_fd_notification_open", | ||
| 2139 | ".nuget": "_fd_nuget_open", | ||
| 2140 | "nuxt": "_fd_nuxt_open", | ||
| 2141 | ".nuxt": "_fd_nuxt_open", | ||
| 2142 | "package": "_fd_package_open", | ||
| 2143 | "packages": "_fd_package_open", | ||
| 2144 | ".package": "_fd_package_open", | ||
| 2145 | ".packages": "_fd_package_open", | ||
| 2146 | "pkg": "_fd_package_open", | ||
| 2147 | ".paket": "_fd_paket_open", | ||
| 2148 | "php": "_fd_php_open", | ||
| 2149 | ".pio": "_fd_platformio_open", | ||
| 2150 | ".pioenvs": "_fd_platformio_open", | ||
| 2151 | "plugin": "_fd_plugin_open", | ||
| 2152 | ".plugin": "_fd_plugin_open", | ||
| 2153 | "plugins": "_fd_plugin_open", | ||
| 2154 | ".plugins": "_fd_plugin_open", | ||
| 2155 | "extension": "_fd_plugin_open", | ||
| 2156 | ".extension": "_fd_plugin_open", | ||
| 2157 | "extensions": "_fd_plugin_open", | ||
| 2158 | ".extensions": "_fd_plugin_open", | ||
| 2159 | "prisma": "_fd_prisma_open", | ||
| 2160 | "private": "_fd_private_open", | ||
| 2161 | ".private": "_fd_private_open", | ||
| 2162 | "public": "_fd_public_open", | ||
| 2163 | ".public": "_fd_public_open", | ||
| 2164 | ".pytest_cache": "_fd_pytest_open", | ||
| 2165 | ".venv": "_fd_python_open", | ||
| 2166 | ".virtualenv": "_fd_python_open", | ||
| 2167 | "__pycache__": "_fd_python_open", | ||
| 2168 | "ravendb": "_fd_ravendb_open", | ||
| 2169 | "redis": "_fd_redis_open", | ||
| 2170 | "redux": "_fd_redux_open", | ||
| 2171 | "route": "_fd_route_open", | ||
| 2172 | "routes": "_fd_route_open", | ||
| 2173 | "_route": "_fd_route_open", | ||
| 2174 | "_routes": "_fd_route_open", | ||
| 2175 | "router": "_fd_route_open", | ||
| 2176 | "routers": "_fd_route_open", | ||
| 2177 | "sass": "_fd_sass_open", | ||
| 2178 | "scss": "_fd_sass_open", | ||
| 2179 | "_sass": "_fd_sass_open", | ||
| 2180 | "_scss": "_fd_sass_open", | ||
| 2181 | "script": "_fd_script_open", | ||
| 2182 | "scripts": "_fd_script_open", | ||
| 2183 | "seedkit": "_fd_seedkit_open", | ||
| 2184 | ".seedkit": "_fd_seedkit_open", | ||
| 2185 | "server": "_fd_server_open", | ||
| 2186 | "service": "_fd_services_open", | ||
| 2187 | "services": "_fd_services_open", | ||
| 2188 | "share": "_fd_shared_open", | ||
| 2189 | "shared": "_fd_shared_open", | ||
| 2190 | ".share": "_fd_shared_open", | ||
| 2191 | ".shared": "_fd_shared_open", | ||
| 2192 | "__shared__": "_fd_shared_open", | ||
| 2193 | "__share__": "_fd_shared_open", | ||
| 2194 | ".snaplet": "_fd_snaplet_open", | ||
| 2195 | ".spin": "_fd_spin_open", | ||
| 2196 | "src": "_fd_src_open", | ||
| 2197 | "source": "_fd_src_open", | ||
| 2198 | "sources": "_fd_src_open", | ||
| 2199 | "__src__": "_fd_src_open", | ||
| 2200 | "sso": "_fd_sso_open", | ||
| 2201 | "story": "_fd_story_open", | ||
| 2202 | "stories": "_fd_story_open", | ||
| 2203 | "__stories__": "_fd_story_open", | ||
| 2204 | ".storybook": "_fd_story_open", | ||
| 2205 | "style": "_fd_style_open", | ||
| 2206 | "styles": "_fd_style_open", | ||
| 2207 | "supabase": "_fd_supabase_open", | ||
| 2208 | "svelte": "_fd_svelte_open", | ||
| 2209 | ".svelte-kit": "_fd_svelte_open", | ||
| 2210 | "src-tauri": "_fd_tauri_open", | ||
| 2211 | "temp": "_fd_temp_open", | ||
| 2212 | ".temp": "_fd_temp_open", | ||
| 2213 | "tmp": "_fd_temp_open", | ||
| 2214 | ".tmp": "_fd_temp_open", | ||
| 2215 | "template": "_fd_template_open", | ||
| 2216 | ".template": "_fd_template_open", | ||
| 2217 | "templates": "_fd_template_open", | ||
| 2218 | ".templates": "_fd_template_open", | ||
| 2219 | "tests": "_fd_test_open", | ||
| 2220 | ".tests": "_fd_test_open", | ||
| 2221 | "test": "_fd_test_open", | ||
| 2222 | ".test": "_fd_test_open", | ||
| 2223 | "__tests__": "_fd_test_open", | ||
| 2224 | "__test__": "_fd_test_open", | ||
| 2225 | "spec": "_fd_test_open", | ||
| 2226 | ".spec": "_fd_test_open", | ||
| 2227 | "specs": "_fd_test_open", | ||
| 2228 | ".specs": "_fd_test_open", | ||
| 2229 | "integration": "_fd_test_open", | ||
| 2230 | "theme": "_fd_theme_open", | ||
| 2231 | "themes": "_fd_theme_open", | ||
| 2232 | "tool": "_fd_tools_open", | ||
| 2233 | "tools": "_fd_tools_open", | ||
| 2234 | ".tools": "_fd_tools_open", | ||
| 2235 | "util": "_fd_tools_open", | ||
| 2236 | "utils": "_fd_tools_open", | ||
| 2237 | "utilities": "_fd_tools_open", | ||
| 2238 | "tooling": "_fd_tools_open", | ||
| 2239 | ".travis": "_fd_travis_open", | ||
| 2240 | ".trunk": "_fd_trunk_open", | ||
| 2241 | ".turbo": "_fd_turbo_open", | ||
| 2242 | "typescript": "_fd_typescript_open", | ||
| 2243 | "ts": "_fd_typescript_open", | ||
| 2244 | "typings": "_fd_typings_open", | ||
| 2245 | "types": "_fd_typings_open", | ||
| 2246 | "@types": "_fd_typings_open", | ||
| 2247 | "vagrant": "_fd_vagrant_open", | ||
| 2248 | ".vagrant": "_fd_vagrant_open", | ||
| 2249 | ".vercel": "_fd_vercel_open", | ||
| 2250 | "video": "_fd_video_open", | ||
| 2251 | ".video": "_fd_video_open", | ||
| 2252 | "videos": "_fd_video_open", | ||
| 2253 | ".videos": "_fd_video_open", | ||
| 2254 | "html": "_fd_view_open", | ||
| 2255 | "view": "_fd_view_open", | ||
| 2256 | "views": "_fd_view_open", | ||
| 2257 | "layout": "_fd_view_open", | ||
| 2258 | "layouts": "_fd_view_open", | ||
| 2259 | "page": "_fd_view_open", | ||
| 2260 | "pages": "_fd_view_open", | ||
| 2261 | "_view": "_fd_view_open", | ||
| 2262 | "_views": "_fd_view_open", | ||
| 2263 | "_layout": "_fd_view_open", | ||
| 2264 | "_layouts": "_fd_view_open", | ||
| 2265 | "_page": "_fd_view_open", | ||
| 2266 | "_pages": "_fd_view_open", | ||
| 2267 | ".vitepress": "_fd_vitepress_open", | ||
| 2268 | ".vs": "_fd_vs_open", | ||
| 2269 | ".vscode": "_fd_vscode_open", | ||
| 2270 | "vscode": "_fd_vscode_open", | ||
| 2271 | ".vscode-test": "_fd_vscode_test_open", | ||
| 2272 | "wasm": "_fd_wasm_open", | ||
| 2273 | "WASM": "_fd_wasm_open", | ||
| 2274 | "webassembly": "_fd_wasm_open", | ||
| 2275 | "WebAssembly": "_fd_wasm_open", | ||
| 2276 | "webpack": "_fd_webpack_open", | ||
| 2277 | ".webpack": "_fd_webpack_open", | ||
| 2278 | "windows": "_fd_windows_open", | ||
| 2279 | "win32": "_fd_windows_open", | ||
| 2280 | ".windsurf": "_fd_windsurf_open", | ||
| 2281 | "wit": "_fd_wit_open", | ||
| 2282 | ".web": "_fd_www_open", | ||
| 2283 | "www": "_fd_www_open", | ||
| 2284 | "wwwroot": "_fd_www_open", | ||
| 2285 | "web": "_fd_www_open", | ||
| 2286 | ".yarn": "_fd_yarn_open", | ||
| 2287 | ".zed": "_fd_zed_open" | ||
| 2288 | }, | ||
| 2289 | "fileExtensions": { | ||
| 2290 | "accdb": "_f_access", | ||
| 2291 | "accdt": "_f_access", | ||
| 2292 | "mdb": "_f_access", | ||
| 2293 | "accda": "_f_access", | ||
| 2294 | "accdc": "_f_access", | ||
| 2295 | "accde": "_f_access", | ||
| 2296 | "accdp": "_f_access", | ||
| 2297 | "accdr": "_f_access", | ||
| 2298 | "accdu": "_f_access", | ||
| 2299 | "ade": "_f_access", | ||
| 2300 | "adp": "_f_access", | ||
| 2301 | "laccdb": "_f_access", | ||
| 2302 | "ldb": "_f_access", | ||
| 2303 | "mam": "_f_access", | ||
| 2304 | "maq": "_f_access", | ||
| 2305 | "mdw": "_f_access", | ||
| 2306 | "af": "_f_affinity", | ||
| 2307 | "aftemplate": "_f_affinity", | ||
| 2308 | "afdesign": "_f_affinitydesigner", | ||
| 2309 | "affinitydesigner": "_f_affinitydesigner", | ||
| 2310 | "afphoto": "_f_affinityphoto", | ||
| 2311 | "affinityphoto": "_f_affinityphoto", | ||
| 2312 | "afpub": "_f_affinitypublisher", | ||
| 2313 | "affinitypublisher": "_f_affinitypublisher", | ||
| 2314 | "ai": "_f_ai", | ||
| 2315 | "dal": "_f_al_dal", | ||
| 2316 | "gs": "_f_appscript", | ||
| 2317 | "ino": "_f_arduino", | ||
| 2318 | "pde": "_f_arduino", | ||
| 2319 | "ase": "_f_aseprite", | ||
| 2320 | "aseprite": "_f_aseprite", | ||
| 2321 | "aspx": "_f_aspx", | ||
| 2322 | "ascx": "_f_aspx", | ||
| 2323 | "asm": "_f_assembly", | ||
| 2324 | "s": "_f_assembly", | ||
| 2325 | "astro": "_f_astro", | ||
| 2326 | "atom": "_f_atom", | ||
| 2327 | "aac": "_f_audio", | ||
| 2328 | "act": "_f_audio", | ||
| 2329 | "aiff": "_f_audio", | ||
| 2330 | "amr": "_f_audio", | ||
| 2331 | "ape": "_f_audio", | ||
| 2332 | "au": "_f_audio", | ||
| 2333 | "dct": "_f_audio", | ||
| 2334 | "dss": "_f_audio", | ||
| 2335 | "dvf": "_f_audio", | ||
| 2336 | "flac": "_f_audio", | ||
| 2337 | "gsm": "_f_audio", | ||
| 2338 | "iklax": "_f_audio", | ||
| 2339 | "ivs": "_f_audio", | ||
| 2340 | "m4a": "_f_audio", | ||
| 2341 | "m4b": "_f_audio", | ||
| 2342 | "m4p": "_f_audio", | ||
| 2343 | "mmf": "_f_audio", | ||
| 2344 | "mogg": "_f_audio", | ||
| 2345 | "mp3": "_f_audio", | ||
| 2346 | "mpc": "_f_audio", | ||
| 2347 | "msv": "_f_audio", | ||
| 2348 | "oga": "_f_audio", | ||
| 2349 | "ogg": "_f_audio", | ||
| 2350 | "opus": "_f_audio", | ||
| 2351 | "ra": "_f_audio", | ||
| 2352 | "raw": "_f_audio", | ||
| 2353 | "tta": "_f_audio", | ||
| 2354 | "vox": "_f_audio", | ||
| 2355 | "wav": "_f_audio", | ||
| 2356 | "wma": "_f_audio", | ||
| 2357 | "avif": "_f_avif", | ||
| 2358 | "awk": "_f_awk", | ||
| 2359 | "back": "_f_bak", | ||
| 2360 | "backup": "_f_bak", | ||
| 2361 | "bak": "_f_bak", | ||
| 2362 | "a": "_f_binary", | ||
| 2363 | "app": "_f_binary", | ||
| 2364 | "bin": "_f_binary", | ||
| 2365 | "cmo": "_f_binary", | ||
| 2366 | "cmx": "_f_binary", | ||
| 2367 | "cma": "_f_binary", | ||
| 2368 | "cmxa": "_f_binary", | ||
| 2369 | "cmi": "_f_binary", | ||
| 2370 | "dll": "_f_binary", | ||
| 2371 | "exe": "_f_binary", | ||
| 2372 | "hl": "_f_binary", | ||
| 2373 | "ilk": "_f_binary", | ||
| 2374 | "lib": "_f_binary", | ||
| 2375 | "n": "_f_binary", | ||
| 2376 | "ndll": "_f_binary", | ||
| 2377 | "o": "_f_binary", | ||
| 2378 | "obj": "_f_binary", | ||
| 2379 | "pyc": "_f_binary", | ||
| 2380 | "pyd": "_f_binary", | ||
| 2381 | "pyo": "_f_binary", | ||
| 2382 | "pdb": "_f_binary", | ||
| 2383 | "scpt": "_f_binary", | ||
| 2384 | "scptd": "_f_binary", | ||
| 2385 | "so": "_f_binary", | ||
| 2386 | "blend": "_f_blender", | ||
| 2387 | "bb": "_f_blitzbasic", | ||
| 2388 | "buf.yaml": "_f_buf", | ||
| 2389 | "buf.yml": "_f_buf", | ||
| 2390 | "buf.gen.yml": "_f_buf", | ||
| 2391 | "buf.gen.yaml": "_f_buf", | ||
| 2392 | "buf.work.yaml": "_f_buf", | ||
| 2393 | "buf.work.yml": "_f_buf", | ||
| 2394 | "gemfile": "_f_bundler", | ||
| 2395 | "gemfile.lock": "_f_bundler", | ||
| 2396 | "cake": "_f_cake", | ||
| 2397 | "csr": "_f_cert", | ||
| 2398 | "crt": "_f_cert", | ||
| 2399 | "cer": "_f_cert", | ||
| 2400 | "der": "_f_cert", | ||
| 2401 | "pfx": "_f_cert", | ||
| 2402 | "p12": "_f_cert", | ||
| 2403 | "p7b": "_f_cert", | ||
| 2404 | "p7r": "_f_cert", | ||
| 2405 | "src": "_f_cert", | ||
| 2406 | "crl": "_f_cert", | ||
| 2407 | "sst": "_f_cert", | ||
| 2408 | "stl": "_f_cert", | ||
| 2409 | "lucee": "_f_cf", | ||
| 2410 | "h": "_f_cheader", | ||
| 2411 | "class": "_f_class", | ||
| 2412 | "cjm": "_f_clojure", | ||
| 2413 | "cljc": "_f_clojure", | ||
| 2414 | "cljs": "_f_clojurescript", | ||
| 2415 | "kit": "_f_codekit", | ||
| 2416 | "plist": "_f_config", | ||
| 2417 | "lcov": "_f_coverage", | ||
| 2418 | "hpp": "_f_cppheader", | ||
| 2419 | "hh": "_f_cppheader", | ||
| 2420 | "hxx": "_f_cppheader", | ||
| 2421 | "h++": "_f_cppheader", | ||
| 2422 | "csx": "_f_csharp", | ||
| 2423 | "csproj": "_f_csproj", | ||
| 2424 | "css.map": "_f_cssmap", | ||
| 2425 | "cy.js": "_f_cypress_spec", | ||
| 2426 | "cy.mjs": "_f_cypress_spec", | ||
| 2427 | "cy.cjs": "_f_cypress_spec", | ||
| 2428 | "cy.coffee": "_f_cypress_spec", | ||
| 2429 | "cy.ts": "_f_cypress_spec", | ||
| 2430 | "cy.tsx": "_f_cypress_spec", | ||
| 2431 | "cy.jsx": "_f_cypress_spec", | ||
| 2432 | "g.dart": "_f_dartlang_generated", | ||
| 2433 | "freezed.dart": "_f_dartlang_generated", | ||
| 2434 | "db": "_f_db", | ||
| 2435 | "deb": "_f_debian", | ||
| 2436 | "resolver.json": "_f_design_tokens", | ||
| 2437 | "resolver.json5": "_f_design_tokens", | ||
| 2438 | "resolver.jsonc": "_f_design_tokens", | ||
| 2439 | "tokens.json": "_f_design_tokens", | ||
| 2440 | "tokens.json5": "_f_design_tokens", | ||
| 2441 | "tokens.jsonc": "_f_design_tokens", | ||
| 2442 | "djt": "_f_django", | ||
| 2443 | "eco": "_f_docpad", | ||
| 2444 | "drawio": "_f_drawio", | ||
| 2445 | "dio": "_f_drawio", | ||
| 2446 | "drawio.png": "_f_drawio", | ||
| 2447 | "drawio.svg": "_f_drawio", | ||
| 2448 | "dio.png": "_f_drawio", | ||
| 2449 | "dio.svg": "_f_drawio", | ||
| 2450 | "dtd": "_f_dtd", | ||
| 2451 | "eex": "_f_eex", | ||
| 2452 | "heex": "_f_eex", | ||
| 2453 | "phoenix-heex": "_f_eex", | ||
| 2454 | "html-heex": "_f_eex", | ||
| 2455 | "ejs": "_f_ejs", | ||
| 2456 | "el": "_f_emacs", | ||
| 2457 | "elc": "_f_emacs", | ||
| 2458 | "ensime": "_f_ensime", | ||
| 2459 | "eps": "_f_eps", | ||
| 2460 | "epub": "_f_epub", | ||
| 2461 | "excalidraw": "_f_excalidraw", | ||
| 2462 | "excalidraw.json": "_f_excalidraw", | ||
| 2463 | "excalidraw.svg": "_f_excalidraw", | ||
| 2464 | "excalidraw.png": "_f_excalidraw", | ||
| 2465 | "xls": "_f_excel", | ||
| 2466 | "xlsx": "_f_excel", | ||
| 2467 | "xlsm": "_f_excel", | ||
| 2468 | "ods": "_f_libreoffice_calc", | ||
| 2469 | "fods": "_f_libreoffice_calc", | ||
| 2470 | "xlsb": "_f_excel", | ||
| 2471 | "fbx": "_f_fbx", | ||
| 2472 | "fba": "_f_fitbit", | ||
| 2473 | "fla": "_f_fla", | ||
| 2474 | "swf": "_f_flash", | ||
| 2475 | "swc": "_f_flash", | ||
| 2476 | "js.flow": "_f_flow", | ||
| 2477 | "woff": "_f_font", | ||
| 2478 | "woff2": "_f_font", | ||
| 2479 | "ttf": "_f_font", | ||
| 2480 | "otf": "_f_libreoffice_math", | ||
| 2481 | "eot": "_f_font", | ||
| 2482 | "pfa": "_f_font", | ||
| 2483 | "pfb": "_f_font", | ||
| 2484 | "sfd": "_f_font", | ||
| 2485 | "fsproj": "_f_fsproj", | ||
| 2486 | "gmx": "_f_gamemaker", | ||
| 2487 | "yy": "_f_gamemaker2", | ||
| 2488 | "yyp": "_f_gamemaker2", | ||
| 2489 | "gd.uid": "_f_gduid", | ||
| 2490 | "geojson": "_f_geojson", | ||
| 2491 | "xcf": "_f_gimp", | ||
| 2492 | "gleam": "_f_gleam", | ||
| 2493 | "glb": "_f_gltf", | ||
| 2494 | "gltf": "_f_gltf", | ||
| 2495 | "am": "_f_gnu", | ||
| 2496 | "ld": "_f_gnu", | ||
| 2497 | "m4": "_f_gnu", | ||
| 2498 | "makefile": "_f_gnu", | ||
| 2499 | "godot": "_f_godot", | ||
| 2500 | "gpg": "_f_gpg", | ||
| 2501 | "pgp": "_f_gpg", | ||
| 2502 | "gradle": "_f_gradle", | ||
| 2503 | "gr": "_f_grain", | ||
| 2504 | "hcl2": "_f_hashicorp", | ||
| 2505 | "sentinel": "_f_hashicorp", | ||
| 2506 | "hxproj": "_f_haxedevelop", | ||
| 2507 | "ejs.t": "_f_hygen", | ||
| 2508 | "idr": "_f_idris", | ||
| 2509 | "lidr": "_f_idris", | ||
| 2510 | "ibc": "_f_idrisbin", | ||
| 2511 | "ipkg": "_f_idrispkg", | ||
| 2512 | "jpeg": "_f_image", | ||
| 2513 | "jpg": "_f_image", | ||
| 2514 | "gif": "_f_image", | ||
| 2515 | "png": "_f_image", | ||
| 2516 | "bmp": "_f_image", | ||
| 2517 | "tiff": "_f_image", | ||
| 2518 | "heic": "_f_image", | ||
| 2519 | "ico": "_f_image", | ||
| 2520 | "icns": "_f_image", | ||
| 2521 | "webp": "_f_image", | ||
| 2522 | "imba": "_f_imba", | ||
| 2523 | "imba2": "_f_imba", | ||
| 2524 | "inc": "_f_inc", | ||
| 2525 | "include": "_f_inc", | ||
| 2526 | "infopathxml": "_f_infopath", | ||
| 2527 | "xsn": "_f_infopath", | ||
| 2528 | "xsf": "_f_infopath", | ||
| 2529 | "xtp2": "_f_infopath", | ||
| 2530 | "jar": "_f_jar", | ||
| 2531 | "jbuilder": "_f_jbuilder", | ||
| 2532 | "iml": "_f_jetbrains", | ||
| 2533 | "js.map": "_f_jsmap", | ||
| 2534 | "cjs.map": "_f_jsmap", | ||
| 2535 | "mjs.map": "_f_jsmap", | ||
| 2536 | "jsonl": "_f_json", | ||
| 2537 | "ndjson": "_f_json", | ||
| 2538 | "json5": "_f_json5", | ||
| 2539 | "schema.json": "_f_json_schema", | ||
| 2540 | "jsonld": "_f_jsonld", | ||
| 2541 | "json-ld": "_f_jsonld", | ||
| 2542 | "jsp": "_f_jsp", | ||
| 2543 | "jss": "_f_jss", | ||
| 2544 | "juice": "_f_juice", | ||
| 2545 | "ipynb": "_f_jupyter", | ||
| 2546 | "key": "_f_key", | ||
| 2547 | "pem": "_f_key", | ||
| 2548 | "ktm": "_f_kotlin", | ||
| 2549 | "language-configuration.json": "_f_language_configuration", | ||
| 2550 | "master": "_f_layout", | ||
| 2551 | "layout.html": "_f_layout", | ||
| 2552 | "layout.htm": "_f_layout", | ||
| 2553 | "odb": "_f_libreoffice_base", | ||
| 2554 | "otb": "_f_libreoffice_base", | ||
| 2555 | "ots": "_f_libreoffice_calc", | ||
| 2556 | "odg": "_f_libreoffice_draw", | ||
| 2557 | "otg": "_f_libreoffice_draw", | ||
| 2558 | "odp": "_f_libreoffice_impress", | ||
| 2559 | "otp": "_f_libreoffice_impress", | ||
| 2560 | "odf": "_f_libreoffice_math", | ||
| 2561 | "odt": "_f_libreoffice_writer", | ||
| 2562 | "ott": "_f_libreoffice_writer", | ||
| 2563 | "enc": "_f_license", | ||
| 2564 | "license": "_f_license", | ||
| 2565 | "lic": "_f_license", | ||
| 2566 | "hxp": "_f_lime", | ||
| 2567 | "liquid": "_f_liquid", | ||
| 2568 | "ls": "_f_livescript", | ||
| 2569 | "lnk": "_f_lnk", | ||
| 2570 | "log": "_f_log", | ||
| 2571 | "tlg": "_f_log", | ||
| 2572 | "luau": "_f_luau", | ||
| 2573 | "crec": "_f_lync", | ||
| 2574 | "ocrec": "_f_lync", | ||
| 2575 | "map": "_f_map", | ||
| 2576 | "mdown": "_f_markdown", | ||
| 2577 | "markdown": "_f_markdown", | ||
| 2578 | "marko.js": "_f_markojs", | ||
| 2579 | "fig": "_f_matlab", | ||
| 2580 | "mex": "_f_matlab", | ||
| 2581 | "mexn": "_f_matlab", | ||
| 2582 | "mexrs6": "_f_matlab", | ||
| 2583 | "mn": "_f_matlab", | ||
| 2584 | "mum": "_f_matlab", | ||
| 2585 | "mx": "_f_matlab", | ||
| 2586 | "mx3": "_f_matlab", | ||
| 2587 | "rwd": "_f_matlab", | ||
| 2588 | "slx": "_f_matlab", | ||
| 2589 | "slddc": "_f_matlab", | ||
| 2590 | "smv": "_f_matlab", | ||
| 2591 | "xvc": "_f_matlab", | ||
| 2592 | "mca": "_f_minecraft", | ||
| 2593 | "mcmeta": "_f_minecraft", | ||
| 2594 | "mojo": "_f_mojo", | ||
| 2595 | "🔥": "_f_mojo", | ||
| 2596 | "mql.yaml": "_f_mondoo", | ||
| 2597 | "mql.yml": "_f_mondoo", | ||
| 2598 | "mustache": "_f_mustache", | ||
| 2599 | "mst": "_f_mustache", | ||
| 2600 | "ndst.yaml": "_f_ndst", | ||
| 2601 | "ndst.yml": "_f_ndst", | ||
| 2602 | "ndst.json": "_f_ndst", | ||
| 2603 | "njsproj": "_f_njsproj", | ||
| 2604 | "noc": "_f_noc", | ||
| 2605 | "nupkg": "_f_nuget", | ||
| 2606 | "snupkg": "_f_nuget", | ||
| 2607 | "nuspec": "_f_nuget", | ||
| 2608 | "psmdcp": "_f_nuget", | ||
| 2609 | "npy": "_f_numpy", | ||
| 2610 | "npz": "_f_numpy", | ||
| 2611 | "nunj": "_f_nunjucks", | ||
| 2612 | "njs": "_f_nunjucks", | ||
| 2613 | "mli": "_f_ocaml_intf", | ||
| 2614 | "one": "_f_onenote", | ||
| 2615 | "onepkg": "_f_onenote", | ||
| 2616 | "onetoc": "_f_onenote", | ||
| 2617 | "onetoc2": "_f_onenote", | ||
| 2618 | "sig": "_f_onenote", | ||
| 2619 | "opam": "_f_opam", | ||
| 2620 | "cl": "_f_opencl", | ||
| 2621 | "opencl": "_f_opencl", | ||
| 2622 | "tofu": "_f_opentofu", | ||
| 2623 | "tofu.json": "_f_opentofu", | ||
| 2624 | "tofutest.hcl": "_f_opentofu", | ||
| 2625 | "tofutest.json": "_f_opentofu", | ||
| 2626 | "org": "_f_org", | ||
| 2627 | "pst": "_f_outlook", | ||
| 2628 | "bcmx": "_f_outlook", | ||
| 2629 | "otm": "_f_outlook", | ||
| 2630 | "msg": "_f_outlook", | ||
| 2631 | "oft": "_f_outlook", | ||
| 2632 | "ovpn": "_f_ovpn", | ||
| 2633 | "pkg": "_f_package", | ||
| 2634 | "paket.references": "_f_paket", | ||
| 2635 | "paket.template": "_f_paket", | ||
| 2636 | "patch": "_f_patch", | ||
| 2637 | "pcd": "_f_pcl", | ||
| 2638 | "pdf": "_f_pdf", | ||
| 2639 | "psd": "_f_photoshop", | ||
| 2640 | "php1": "_f_php", | ||
| 2641 | "php2": "_f_php", | ||
| 2642 | "php3": "_f_php", | ||
| 2643 | "php4": "_f_php", | ||
| 2644 | "php5": "_f_php", | ||
| 2645 | "php6": "_f_php", | ||
| 2646 | "phps": "_f_php", | ||
| 2647 | "phpsa": "_f_php", | ||
| 2648 | "phpt": "_f_php", | ||
| 2649 | "phtml": "_f_php", | ||
| 2650 | "phar": "_f_php", | ||
| 2651 | "pipeline": "_f_pipeline", | ||
| 2652 | "pu": "_f_plantuml", | ||
| 2653 | "plantuml": "_f_plantuml", | ||
| 2654 | "iuml": "_f_plantuml", | ||
| 2655 | "puml": "_f_plantuml", | ||
| 2656 | "pck": "_f_plsql_package", | ||
| 2657 | "pkb": "_f_plsql_package_body", | ||
| 2658 | "pkh": "_f_plsql_package_header", | ||
| 2659 | "pks": "_f_plsql_package_spec", | ||
| 2660 | "po": "_f_poedit", | ||
| 2661 | "mo": "_f_poedit", | ||
| 2662 | "postman_collection.json": "_f_postman", | ||
| 2663 | "postman_environment.json": "_f_postman", | ||
| 2664 | "postman_globals.json": "_f_postman", | ||
| 2665 | "pot": "_f_powerpoint", | ||
| 2666 | "potx": "_f_powerpoint", | ||
| 2667 | "potm": "_f_powerpoint", | ||
| 2668 | "pps": "_f_powerpoint", | ||
| 2669 | "ppsx": "_f_powerpoint", | ||
| 2670 | "ppsm": "_f_powerpoint", | ||
| 2671 | "ppt": "_f_powerpoint", | ||
| 2672 | "pptx": "_f_powerpoint", | ||
| 2673 | "pptm": "_f_powerpoint", | ||
| 2674 | "pa": "_f_powerpoint", | ||
| 2675 | "ppa": "_f_powerpoint", | ||
| 2676 | "ppam": "_f_powerpoint", | ||
| 2677 | "sldm": "_f_powerpoint", | ||
| 2678 | "sldx": "_f_powerpoint", | ||
| 2679 | "format.ps1xml": "_f_powershell_format", | ||
| 2680 | "psd1": "_f_powershell_psd", | ||
| 2681 | "psm1": "_f_powershell_psm", | ||
| 2682 | "types.ps1xml": "_f_powershell_types", | ||
| 2683 | "pro": "_f_prolog", | ||
| 2684 | "pub": "_f_publisher", | ||
| 2685 | "puz": "_f_publisher", | ||
| 2686 | "pyowo": "_f_pythowo", | ||
| 2687 | "q": "_f_q", | ||
| 2688 | "qbs": "_f_qbs", | ||
| 2689 | "qvd": "_f_qlikview", | ||
| 2690 | "qvw": "_f_qlikview", | ||
| 2691 | "rast": "_f_ra_syntax_tree", | ||
| 2692 | "rake": "_f_rake", | ||
| 2693 | "rt": "_f_reacttemplate", | ||
| 2694 | "reg": "_f_registry", | ||
| 2695 | "rego": "_f_rego", | ||
| 2696 | "ripple": "_f_ripple", | ||
| 2697 | "rnc": "_f_rnc", | ||
| 2698 | "ron": "_f_ron", | ||
| 2699 | "rproj": "_f_rproj", | ||
| 2700 | "rss": "_f_rss", | ||
| 2701 | "rbs": "_f_ruby", | ||
| 2702 | "safetensors": "_f_safetensors", | ||
| 2703 | "sls": "_f_saltstack", | ||
| 2704 | "sass": "_f_sass", | ||
| 2705 | "scssm": "_f_scss", | ||
| 2706 | "unity": "_f_shaderlab", | ||
| 2707 | "fish": "_f_shell", | ||
| 2708 | "sy": "_f_siyuan", | ||
| 2709 | "sketch": "_f_sketch", | ||
| 2710 | "eskip": "_f_skipper", | ||
| 2711 | "sln": "_f_sln", | ||
| 2712 | "slnx": "_f_sln", | ||
| 2713 | "slnf": "_f_sln", | ||
| 2714 | "spe": "_f_spacengine", | ||
| 2715 | "sqlite": "_f_sqlite", | ||
| 2716 | "sqlite3": "_f_sqlite", | ||
| 2717 | "db3": "_f_sqlite", | ||
| 2718 | "sss": "_f_sss", | ||
| 2719 | "dta": "_f_stata", | ||
| 2720 | "storyboard": "_f_storyboard", | ||
| 2721 | "story.js": "_f_storybook", | ||
| 2722 | "story.jsx": "_f_storybook", | ||
| 2723 | "story.ts": "_f_storybook", | ||
| 2724 | "story.tsx": "_f_storybook", | ||
| 2725 | "story.mdx": "_f_storybook", | ||
| 2726 | "story.svelte": "_f_storybook", | ||
| 2727 | "stories.js": "_f_storybook", | ||
| 2728 | "stories.jsx": "_f_storybook", | ||
| 2729 | "stories.ts": "_f_storybook", | ||
| 2730 | "stories.tsx": "_f_storybook", | ||
| 2731 | "stories.mdx": "_f_storybook", | ||
| 2732 | "stories.svelte": "_f_storybook", | ||
| 2733 | "sublime-project": "_f_sublime", | ||
| 2734 | "svg": "_f_svg", | ||
| 2735 | "tcl": "_f_tcl", | ||
| 2736 | "exp": "_f_tcl", | ||
| 2737 | "templ": "_f_templ", | ||
| 2738 | "tfstate": "_f_terraform", | ||
| 2739 | "tfvars": "_f_terraform", | ||
| 2740 | "tf": "_f_terraform", | ||
| 2741 | "tf.json": "_f_terraform", | ||
| 2742 | "tst": "_f_test", | ||
| 2743 | "test.js": "_f_testjs", | ||
| 2744 | "test.jsx": "_f_testjs", | ||
| 2745 | "test.mjs": "_f_testjs", | ||
| 2746 | "spec.js": "_f_testjs", | ||
| 2747 | "spec.jsx": "_f_testjs", | ||
| 2748 | "spec.mjs": "_f_testjs", | ||
| 2749 | "testplane.ts": "_f_testplane", | ||
| 2750 | "testplane.js": "_f_testplane", | ||
| 2751 | "testplane.cts": "_f_testplane", | ||
| 2752 | "testplane.cjs": "_f_testplane", | ||
| 2753 | "testplane.tsx": "_f_testplane", | ||
| 2754 | "testplane.jsx": "_f_testplane", | ||
| 2755 | "test.ts": "_f_testts", | ||
| 2756 | "test.tsx": "_f_testts", | ||
| 2757 | "test.mts": "_f_testts", | ||
| 2758 | "spec.ts": "_f_testts", | ||
| 2759 | "spec.tsx": "_f_testts", | ||
| 2760 | "spec.mts": "_f_testts", | ||
| 2761 | "e2e-test.ts": "_f_testts", | ||
| 2762 | "e2e-test.tsx": "_f_testts", | ||
| 2763 | "e2e-test.mts": "_f_testts", | ||
| 2764 | "e2e-spec.ts": "_f_testts", | ||
| 2765 | "e2e-spec.tsx": "_f_testts", | ||
| 2766 | "e2e-spec.mts": "_f_testts", | ||
| 2767 | "test-d.ts": "_f_testts", | ||
| 2768 | "test-d.tsx": "_f_testts", | ||
| 2769 | "test-d.mts": "_f_testts", | ||
| 2770 | "texi": "_f_tex", | ||
| 2771 | "tikz": "_f_tex", | ||
| 2772 | "csv": "_f_text", | ||
| 2773 | "tsv": "_f_text", | ||
| 2774 | "tm": "_f_tm", | ||
| 2775 | "tm.hcl": "_f_tm", | ||
| 2776 | "todo": "_f_todo", | ||
| 2777 | "tree": "_f_tree", | ||
| 2778 | "tres": "_f_tres", | ||
| 2779 | "tsbuildinfo": "_f_tsbuildinfo", | ||
| 2780 | "tscn": "_f_tscn", | ||
| 2781 | "tt2": "_f_tt", | ||
| 2782 | "d.ts": "_f_typescriptdef", | ||
| 2783 | "d.cts": "_f_typescriptdef", | ||
| 2784 | "d.mts": "_f_typescriptdef", | ||
| 2785 | "ua": "_f_uiua", | ||
| 2786 | "u": "_f_unison", | ||
| 2787 | "vala": "_f_vala", | ||
| 2788 | "css.ts": "_f_vanilla_extract", | ||
| 2789 | "vapi": "_f_vapi", | ||
| 2790 | "vash": "_f_vash", | ||
| 2791 | "vbhtml": "_f_vbhtml", | ||
| 2792 | "vbproj": "_f_vbproj", | ||
| 2793 | "vcxproj": "_f_vcxproj", | ||
| 2794 | "vto": "_f_vento", | ||
| 2795 | "vento": "_f_vento", | ||
| 2796 | "3g2": "_f_video", | ||
| 2797 | "3gp": "_f_video", | ||
| 2798 | "asf": "_f_video", | ||
| 2799 | "amv": "_f_video", | ||
| 2800 | "avi": "_f_video", | ||
| 2801 | "divx": "_f_video", | ||
| 2802 | "qt": "_f_video", | ||
| 2803 | "f4a": "_f_video", | ||
| 2804 | "f4b": "_f_video", | ||
| 2805 | "f4p": "_f_video", | ||
| 2806 | "f4v": "_f_video", | ||
| 2807 | "flv": "_f_video", | ||
| 2808 | "m2v": "_f_video", | ||
| 2809 | "m4v": "_f_video", | ||
| 2810 | "mkv": "_f_video", | ||
| 2811 | "mk3d": "_f_video", | ||
| 2812 | "mov": "_f_video", | ||
| 2813 | "mp2": "_f_video", | ||
| 2814 | "mp4": "_f_video", | ||
| 2815 | "mpe": "_f_video", | ||
| 2816 | "mpeg": "_f_video", | ||
| 2817 | "mpeg2": "_f_video", | ||
| 2818 | "mpg": "_f_video", | ||
| 2819 | "mpv": "_f_video", | ||
| 2820 | "nsv": "_f_video", | ||
| 2821 | "ogv": "_f_video", | ||
| 2822 | "rm": "_f_video", | ||
| 2823 | "rmvb": "_f_video", | ||
| 2824 | "svi": "_f_video", | ||
| 2825 | "vob": "_f_video", | ||
| 2826 | "webm": "_f_video", | ||
| 2827 | "wmv": "_f_video", | ||
| 2828 | "code-snippets": "_f_vscode", | ||
| 2829 | "code-workspace": "_f_vscode", | ||
| 2830 | "vsix": "_f_vsix", | ||
| 2831 | "vsixmanifest": "_f_vsixmanifest", | ||
| 2832 | "vvvvvv": "_f_vvvvvv", | ||
| 2833 | "vyi": "_f_vyper", | ||
| 2834 | "wasm": "_f_wasm", | ||
| 2835 | "wikitext": "_f_wikitext", | ||
| 2836 | "wit": "_f_wit", | ||
| 2837 | "doc": "_f_word", | ||
| 2838 | "docx": "_f_word", | ||
| 2839 | "docm": "_f_word", | ||
| 2840 | "dot": "_f_word", | ||
| 2841 | "dotx": "_f_word", | ||
| 2842 | "dotm": "_f_word", | ||
| 2843 | "wll": "_f_word", | ||
| 2844 | "wxml": "_f_wxml", | ||
| 2845 | "wxss": "_f_wxss", | ||
| 2846 | "xaml": "_f_xaml", | ||
| 2847 | "axaml": "_f_xaml", | ||
| 2848 | "xcodeproj": "_f_xcode", | ||
| 2849 | "xfl": "_f_xfl", | ||
| 2850 | "xib": "_f_xib", | ||
| 2851 | "xliff": "_f_xliff", | ||
| 2852 | "xlf": "_f_xliff", | ||
| 2853 | "pex": "_f_xml", | ||
| 2854 | "tmlanguage": "_f_xml", | ||
| 2855 | "zip": "_f_zip", | ||
| 2856 | "rar": "_f_zip", | ||
| 2857 | "7z": "_f_zip", | ||
| 2858 | "tar": "_f_zip", | ||
| 2859 | "tgz": "_f_zip", | ||
| 2860 | "bz": "_f_zip", | ||
| 2861 | "gz": "_f_zip", | ||
| 2862 | "bzip2": "_f_zip", | ||
| 2863 | "xz": "_f_zip", | ||
| 2864 | "bz2": "_f_zip", | ||
| 2865 | "whl": "_f_zip", | ||
| 2866 | "zipx": "_f_zip", | ||
| 2867 | "br": "_f_zip" | ||
| 2868 | }, | ||
| 2869 | "fileNames": { | ||
| 2870 | "agents.md": "_f_agents", | ||
| 2871 | "alchemy.run.ts": "_f_alchemy", | ||
| 2872 | ".all-contributorsrc": "_f_allcontributors", | ||
| 2873 | "allurerc.js": "_f_allure", | ||
| 2874 | "allurerc.mjs": "_f_allure", | ||
| 2875 | "allurerc.cjs": "_f_allure", | ||
| 2876 | "allurerc.json": "_f_allure", | ||
| 2877 | "allurerc.yaml": "_f_allure", | ||
| 2878 | "allurerc.yml": "_f_allure", | ||
| 2879 | ".angular-cli.json": "_f_angular", | ||
| 2880 | "angular-cli.json": "_f_angular", | ||
| 2881 | "angular.json": "_f_angular", | ||
| 2882 | ".angular.json": "_f_angular", | ||
| 2883 | "antlers.html": "_f_antlers_html", | ||
| 2884 | "api-extractor.json": "_f_api_extractor", | ||
| 2885 | "api-extractor-base.json": "_f_api_extractor", | ||
| 2886 | ".appsemblerc.yaml": "_f_appsemble", | ||
| 2887 | "app-definition.yaml": "_f_appsemble", | ||
| 2888 | "appveyor.yml": "_f_appveyor", | ||
| 2889 | ".appveyor.yml": "_f_appveyor", | ||
| 2890 | "asconfig.json": "_f_assembly_script", | ||
| 2891 | "astro.config.js": "_f_astroconfig", | ||
| 2892 | "astro.config.cjs": "_f_astroconfig", | ||
| 2893 | "astro.config.mjs": "_f_astroconfig", | ||
| 2894 | "astro.config.ts": "_f_astroconfig", | ||
| 2895 | "astro.config.cts": "_f_astroconfig", | ||
| 2896 | "astro.config.mts": "_f_astroconfig", | ||
| 2897 | ".attw.json": "_f_attw", | ||
| 2898 | "aurelia.json": "_f_aurelia", | ||
| 2899 | "azure-pipelines.yml": "_f_azurepipelines", | ||
| 2900 | ".vsts-ci.yml": "_f_azurepipelines", | ||
| 2901 | ".babelrc": "_f_babel", | ||
| 2902 | ".babelignore": "_f_babel", | ||
| 2903 | ".babelrc.js": "_f_babel", | ||
| 2904 | ".babelrc.cjs": "_f_babel", | ||
| 2905 | ".babelrc.mjs": "_f_babel", | ||
| 2906 | ".babelrc.json": "_f_babel", | ||
| 2907 | "babel.config.js": "_f_babel", | ||
| 2908 | "babel.config.cjs": "_f_babel", | ||
| 2909 | "babel.config.mjs": "_f_babel", | ||
| 2910 | "babel.config.json": "_f_babel", | ||
| 2911 | ".bzrignore": "_f_bazaar", | ||
| 2912 | "BUILD.bazel": "_f_bazel", | ||
| 2913 | ".bazelrc": "_f_bazel", | ||
| 2914 | "bazel.rc": "_f_bazel", | ||
| 2915 | "bazel.bazelrc": "_f_bazel", | ||
| 2916 | ".bazelignore": "_f_bazel_ignore", | ||
| 2917 | ".bazelversion": "_f_bazel_version", | ||
| 2918 | "biome.json": "_f_biome", | ||
| 2919 | "biome.jsonc": "_f_biome", | ||
| 2920 | "bitbucket-pipelines.yml": "_f_bitbucketpipeline", | ||
| 2921 | ".bithoundrc": "_f_bithound", | ||
| 2922 | ".bowerrc": "_f_bower", | ||
| 2923 | "bower.json": "_f_bower", | ||
| 2924 | ".browserslistrc": "_f_browserslist", | ||
| 2925 | "browserslist": "_f_browserslist", | ||
| 2926 | ".buckconfig": "_f_buckbuild", | ||
| 2927 | ".bunfig.toml": "_f_bun", | ||
| 2928 | "bunfig.toml": "_f_bunfig", | ||
| 2929 | "bun.lockb": "_f_bun", | ||
| 2930 | "bun.lock": "_f_bun", | ||
| 2931 | ".bundlemonrc": "_f_bundlemon", | ||
| 2932 | "bundlemon.config.js": "_f_bundlemon", | ||
| 2933 | "bundlemon.config.mjs": "_f_bundlemon", | ||
| 2934 | "bundlemon.config.cjs": "_f_bundlemon", | ||
| 2935 | ".bundlemonrc.js": "_f_bundlemon", | ||
| 2936 | ".bundlemonrc.mjs": "_f_bundlemon", | ||
| 2937 | ".bundlemonrc.cjs": "_f_bundlemon", | ||
| 2938 | ".bundlemonrc.json": "_f_bundlemon", | ||
| 2939 | ".bundlemonrc.yaml": "_f_bundlemon", | ||
| 2940 | ".bundlemonrc.yml": "_f_bundlemon", | ||
| 2941 | "gemfile": "_f_bundler", | ||
| 2942 | "gemfile.lock": "_f_bundler", | ||
| 2943 | "capacitor.config.json": "_f_capacitor", | ||
| 2944 | "capacitor.config.ts": "_f_capacitor", | ||
| 2945 | "Cargo.toml": "_f_cargo", | ||
| 2946 | "Cargo.lock": "_f_cargo", | ||
| 2947 | ".changie.yaml": "_f_changie", | ||
| 2948 | ".changie.yml": "_f_changie", | ||
| 2949 | "chefignore": "_f_chef", | ||
| 2950 | "berksfile": "_f_chef", | ||
| 2951 | "berksfile.lock": "_f_chef", | ||
| 2952 | "policyfile.rb": "_f_chef", | ||
| 2953 | "policyfile.lock.json": "_f_chef", | ||
| 2954 | "circle.yml": "_f_circleci", | ||
| 2955 | "claude.md": "_f_claude", | ||
| 2956 | "wrangler.toml": "_f_cloudflare", | ||
| 2957 | ".cfignore": "_f_cloudfoundry", | ||
| 2958 | ".codacy.yml": "_f_codacy", | ||
| 2959 | ".codacy.yaml": "_f_codacy", | ||
| 2960 | ".codeclimate.yml": "_f_codeclimate", | ||
| 2961 | "codecov.yml": "_f_codecov", | ||
| 2962 | ".codecov.yml": "_f_codecov", | ||
| 2963 | "config.codekit": "_f_codekit", | ||
| 2964 | "config.codekit2": "_f_codekit", | ||
| 2965 | "config.codekit3": "_f_codekit", | ||
| 2966 | ".config.codekit": "_f_codekit", | ||
| 2967 | ".config.codekit2": "_f_codekit", | ||
| 2968 | ".config.codekit3": "_f_codekit", | ||
| 2969 | "codemagic.yaml": "_f_codemagic", | ||
| 2970 | "codeowners": "_f_codeowners", | ||
| 2971 | ".coderabbit.yaml": "_f_coderabbit", | ||
| 2972 | "coffeelint.json": "_f_coffeelint", | ||
| 2973 | ".coffeelintignore": "_f_coffeelint", | ||
| 2974 | ".czrc": "_f_commitizen", | ||
| 2975 | ".cz.json": "_f_commitizen", | ||
| 2976 | ".commitlintrc": "_f_commitlint", | ||
| 2977 | "commitlint.config.js": "_f_commitlint", | ||
| 2978 | "commitlint.config.cjs": "_f_commitlint", | ||
| 2979 | "commitlint.config.mjs": "_f_commitlint", | ||
| 2980 | "commitlint.config.ts": "_f_commitlint", | ||
| 2981 | "commitlint.config.cts": "_f_commitlint", | ||
| 2982 | ".commitlintrc.json": "_f_commitlint", | ||
| 2983 | ".commitlintrc.yaml": "_f_commitlint", | ||
| 2984 | ".commitlintrc.yml": "_f_commitlint", | ||
| 2985 | ".commitlintrc.js": "_f_commitlint", | ||
| 2986 | ".commitlintrc.cjs": "_f_commitlint", | ||
| 2987 | ".commitlintrc.mjs": "_f_commitlint", | ||
| 2988 | ".commitlintrc.ts": "_f_commitlint", | ||
| 2989 | ".commitlintrc.cts": "_f_commitlint", | ||
| 2990 | "composer.json": "_f_composer", | ||
| 2991 | "composer.lock": "_f_composer", | ||
| 2992 | "conanfile.txt": "_f_conan", | ||
| 2993 | "conanfile.py": "_f_conan", | ||
| 2994 | ".condarc": "_f_conda", | ||
| 2995 | ".tool-versions": "_f_config", | ||
| 2996 | "copilot-instructions.md": "_f_copilot", | ||
| 2997 | "github-copilot.xml": "_f_copilot", | ||
| 2998 | ".coverage": "_f_coverage", | ||
| 2999 | "lcov.info": "_f_coverage", | ||
| 3000 | ".coveralls.yml": "_f_coveralls", | ||
| 3001 | "craco.config.ts": "_f_craco", | ||
| 3002 | "craco.config.js": "_f_craco", | ||
| 3003 | "craco.config.cjs": "_f_craco", | ||
| 3004 | ".cracorc.ts": "_f_craco", | ||
| 3005 | ".cracorc.js": "_f_craco", | ||
| 3006 | ".cracorc": "_f_craco", | ||
| 3007 | "crowdin.yml": "_f_crowdin", | ||
| 3008 | "cspell.config.json": "_f_cspell", | ||
| 3009 | "cspell.config.js": "_f_cspell", | ||
| 3010 | "cspell.config.mjs": "_f_cspell", | ||
| 3011 | "cspell.config.cjs": "_f_cspell", | ||
| 3012 | "cspell.config.yaml": "_f_cspell", | ||
| 3013 | "cspell.config.yml": "_f_cspell", | ||
| 3014 | "cspell.json": "_f_cspell", | ||
| 3015 | "cspell.js": "_f_cspell", | ||
| 3016 | "cspell.mjs": "_f_cspell", | ||
| 3017 | "cspell.cjs": "_f_cspell", | ||
| 3018 | "cspell.yaml": "_f_cspell", | ||
| 3019 | "cspell.yml": "_f_cspell", | ||
| 3020 | ".cspell.json": "_f_cspell", | ||
| 3021 | ".cspell.js": "_f_cspell", | ||
| 3022 | ".cspell.mjs": "_f_cspell", | ||
| 3023 | ".cspell.cjs": "_f_cspell", | ||
| 3024 | ".cspell.yaml": "_f_cspell", | ||
| 3025 | ".cspell.yml": "_f_cspell", | ||
| 3026 | ".csscomb.json": "_f_csscomb", | ||
| 3027 | ".csslintrc": "_f_csslint", | ||
| 3028 | ".cursorignore": "_f_cursorrules", | ||
| 3029 | ".cursorindexingignore": "_f_cursorrules", | ||
| 3030 | ".cursorrules": "_f_cursorrules", | ||
| 3031 | ".cvsignore": "_f_cvs", | ||
| 3032 | "cypress.json": "_f_cypress", | ||
| 3033 | "cypress.env.json": "_f_cypress", | ||
| 3034 | "cypress.config.js": "_f_cypress", | ||
| 3035 | "cypress.config.ts": "_f_cypress", | ||
| 3036 | "cypress.config.cjs": "_f_cypress", | ||
| 3037 | "cypress.config.mjs": "_f_cypress", | ||
| 3038 | ".boringignore": "_f_darcs", | ||
| 3039 | ".pubignore": "_f_dartlang_ignore", | ||
| 3040 | "service.datadog.yaml": "_f_datadog", | ||
| 3041 | "datadog-ci.json": "_f_datadog", | ||
| 3042 | "static-analysis.datadog.yml": "_f_datadog", | ||
| 3043 | "static-analysis.datadog.yaml": "_f_datadog", | ||
| 3044 | "aptfile": "_f_debian", | ||
| 3045 | "deno.json": "_f_deno", | ||
| 3046 | "deno.jsonc": "_f_deno", | ||
| 3047 | "deno.lock": "_f_deno", | ||
| 3048 | ".denoifyrc": "_f_denoify", | ||
| 3049 | "denoify.config.json": "_f_denoify", | ||
| 3050 | "denoify.config.js": "_f_denoify", | ||
| 3051 | "dependabot.yml": "_f_dependabot", | ||
| 3052 | "dependabot.yaml": "_f_dependabot", | ||
| 3053 | "dependencies.yml": "_f_dependencies", | ||
| 3054 | "devcontainer.json": "_f_devcontainer", | ||
| 3055 | ".devcontainer.json": "_f_devcontainer", | ||
| 3056 | "devvit.json": "_f_devvit", | ||
| 3057 | "devvit.dev.json": "_f_devvit", | ||
| 3058 | "devvit.prod.json": "_f_devvit", | ||
| 3059 | "devvit.test.json": "_f_devvit", | ||
| 3060 | "devvit.config.js": "_f_devvit", | ||
| 3061 | "devvit.config.cjs": "_f_devvit", | ||
| 3062 | "devvit.config.mjs": "_f_devvit", | ||
| 3063 | "devvit.config.ts": "_f_devvit", | ||
| 3064 | "devvit.config.mts": "_f_devvit", | ||
| 3065 | "devvit.config.dev.js": "_f_devvit", | ||
| 3066 | "devvit.config.dev.cjs": "_f_devvit", | ||
| 3067 | "devvit.config.dev.mjs": "_f_devvit", | ||
| 3068 | "devvit.config.dev.ts": "_f_devvit", | ||
| 3069 | "devvit.config.dev.mts": "_f_devvit", | ||
| 3070 | "devvit.config.prod.js": "_f_devvit", | ||
| 3071 | "devvit.config.prod.cjs": "_f_devvit", | ||
| 3072 | "devvit.config.prod.mjs": "_f_devvit", | ||
| 3073 | "devvit.config.prod.ts": "_f_devvit", | ||
| 3074 | "devvit.config.prod.mts": "_f_devvit", | ||
| 3075 | "devvit.config.test.js": "_f_devvit", | ||
| 3076 | "devvit.config.test.cjs": "_f_devvit", | ||
| 3077 | "devvit.config.test.mjs": "_f_devvit", | ||
| 3078 | "devvit.config.test.ts": "_f_devvit", | ||
| 3079 | "devvit.config.test.mts": "_f_devvit", | ||
| 3080 | ".dockerignore": "_f_docker", | ||
| 3081 | "compose.yaml": "_f_docker", | ||
| 3082 | "compose.yml": "_f_docker", | ||
| 3083 | "docker-compose.yaml": "_f_docker", | ||
| 3084 | "docker-compose.yml": "_f_docker", | ||
| 3085 | "docker-compose.debug.yaml": "_f_docker", | ||
| 3086 | "docker-compose.debug.yml": "_f_docker", | ||
| 3087 | "docker-compose.ci-build.yaml": "_f_docker", | ||
| 3088 | "docker-compose.ci-build.yml": "_f_docker", | ||
| 3089 | "docker-compose.override.yaml": "_f_docker", | ||
| 3090 | "docker-compose.override.yml": "_f_docker", | ||
| 3091 | "docker-compose.vs.debug.yaml": "_f_docker", | ||
| 3092 | "docker-compose.vs.debug.yml": "_f_docker", | ||
| 3093 | "docker-compose.vs.release.yaml": "_f_docker", | ||
| 3094 | "docker-compose.vs.release.yml": "_f_docker", | ||
| 3095 | "docker-cloud.yaml": "_f_docker", | ||
| 3096 | "docker-cloud.yml": "_f_docker", | ||
| 3097 | "docker-compose.test.yml": "_f_dockertest", | ||
| 3098 | "docusaurus.config.ts": "_f_docusaurus", | ||
| 3099 | "docusaurus.config.mts": "_f_docusaurus", | ||
| 3100 | "docusaurus.config.cts": "_f_docusaurus", | ||
| 3101 | "docusaurus.config.js": "_f_docusaurus", | ||
| 3102 | "docusaurus.config.mjs": "_f_docusaurus", | ||
| 3103 | "docusaurus.config.cjs": "_f_docusaurus", | ||
| 3104 | ".doczrc": "_f_docz", | ||
| 3105 | "docz.js": "_f_docz", | ||
| 3106 | "docz.json": "_f_docz", | ||
| 3107 | ".docz.js": "_f_docz", | ||
| 3108 | ".docz.json": "_f_docz", | ||
| 3109 | "doczrc.js": "_f_docz", | ||
| 3110 | "doczrc.json": "_f_docz", | ||
| 3111 | "docz.config.js": "_f_docz", | ||
| 3112 | "docz.config.json": "_f_docz", | ||
| 3113 | ".dojorc": "_f_dojo", | ||
| 3114 | "doppler.yaml": "_f_doppler", | ||
| 3115 | "doppler-template.yaml": "_f_doppler", | ||
| 3116 | ".drone.yml": "_f_drone", | ||
| 3117 | ".drone.yml.sig": "_f_drone", | ||
| 3118 | "dune": "_f_dune", | ||
| 3119 | "dune-project": "_f_dune", | ||
| 3120 | "dune-workspace": "_f_dune", | ||
| 3121 | ".dvc": "_f_dvc", | ||
| 3122 | ".earthlyignore": "_f_earthly", | ||
| 3123 | "Earthfile": "_f_earthly", | ||
| 3124 | "store.config.json": "_f_eas-metadata", | ||
| 3125 | ".editorconfig": "_f_editorconfig", | ||
| 3126 | "forge.config.js": "_f_electron", | ||
| 3127 | "forge.config.ts": "_f_electron", | ||
| 3128 | ".eleventy.js": "_f_eleventy", | ||
| 3129 | "eleventy.config.js": "_f_eleventy", | ||
| 3130 | "eleventy.config.cjs": "_f_eleventy", | ||
| 3131 | "eleventy.config.mjs": "_f_eleventy", | ||
| 3132 | "elm-package.json": "_f_elm", | ||
| 3133 | ".ember-cli": "_f_ember", | ||
| 3134 | "emakefile": "_f_erlang", | ||
| 3135 | ".emakerfile": "_f_erlang", | ||
| 3136 | "esbuild.js": "_f_esbuild", | ||
| 3137 | "esbuild.mjs": "_f_esbuild", | ||
| 3138 | "esbuild.cjs": "_f_esbuild", | ||
| 3139 | "esbuild.ts": "_f_esbuild", | ||
| 3140 | "esbuild.config.js": "_f_esbuild", | ||
| 3141 | "esbuild.config.mjs": "_f_esbuild", | ||
| 3142 | "esbuild.config.cjs": "_f_esbuild", | ||
| 3143 | "esbuild.config.ts": "_f_esbuild", | ||
| 3144 | ".eslintrc": "_f_eslint", | ||
| 3145 | ".eslintignore": "_f_eslint", | ||
| 3146 | ".eslintcache": "_f_eslint", | ||
| 3147 | "eslint.config.js": "_f_eslint", | ||
| 3148 | "eslint.config.mjs": "_f_eslint", | ||
| 3149 | "eslint.config.cjs": "_f_eslint", | ||
| 3150 | "eslint.config.ts": "_f_eslint", | ||
| 3151 | "eslint.config.mts": "_f_eslint", | ||
| 3152 | "eslint.config.cts": "_f_eslint", | ||
| 3153 | ".eslintrc.js": "_f_eslint", | ||
| 3154 | ".eslintrc.mjs": "_f_eslint", | ||
| 3155 | ".eslintrc.cjs": "_f_eslint", | ||
| 3156 | ".eslintrc.ts": "_f_eslint", | ||
| 3157 | ".eslintrc.mts": "_f_eslint", | ||
| 3158 | ".eslintrc.cts": "_f_eslint", | ||
| 3159 | ".eslintrc.json": "_f_eslint", | ||
| 3160 | ".eslintrc.yaml": "_f_eslint", | ||
| 3161 | ".eslintrc.yml": "_f_eslint", | ||
| 3162 | "app.json": "_f_expo", | ||
| 3163 | "app.config.js": "_f_expo", | ||
| 3164 | "app.config.json": "_f_expo", | ||
| 3165 | "app.config.json5": "_f_expo", | ||
| 3166 | ".fantasticonrc": "_f_fantasticon", | ||
| 3167 | "fantasticonrc": "_f_fantasticon", | ||
| 3168 | ".fantasticonrc.json": "_f_fantasticon", | ||
| 3169 | "fantasticonrc.json": "_f_fantasticon", | ||
| 3170 | ".fantasticonrc.js": "_f_fantasticon", | ||
| 3171 | "fantasticonrc.js": "_f_fantasticon", | ||
| 3172 | "fastly.toml": "_f_fastly", | ||
| 3173 | ".faunarc": "_f_fauna", | ||
| 3174 | "favicon.ico": "_f_favicon", | ||
| 3175 | ".firebaserc": "_f_firebase", | ||
| 3176 | "firebase.json": "_f_firebasehosting", | ||
| 3177 | "storage.rules": "_f_firebasestorage", | ||
| 3178 | "firestore.rules": "_f_firestore", | ||
| 3179 | "firestore.indexes.json": "_f_firestore", | ||
| 3180 | "flareact.config.js": "_f_flareact", | ||
| 3181 | ".flooignore": "_f_floobits", | ||
| 3182 | ".flowconfig": "_f_flow", | ||
| 3183 | ".flutter-plugins": "_f_flutter", | ||
| 3184 | ".metadata": "_f_flutter", | ||
| 3185 | ".flutter-plugins-dependencies": "_f_flutter", | ||
| 3186 | "pubspec.lock": "_f_flutter_package", | ||
| 3187 | "pubspec.yaml": "_f_flutter_package", | ||
| 3188 | ".packages": "_f_flutter_package", | ||
| 3189 | "fly.toml": "_f_flyio", | ||
| 3190 | "formkit.config.js": "_f_formkit", | ||
| 3191 | "formkit.config.mjs": "_f_formkit", | ||
| 3192 | "formkit.config.cjs": "_f_formkit", | ||
| 3193 | "formkit.config.ts": "_f_formkit", | ||
| 3194 | ".fossaignore": "_f_fossa", | ||
| 3195 | "ignore-glob": "_f_fossil", | ||
| 3196 | ".front-commerce.js": "_f_frontcommerce", | ||
| 3197 | "front-commerce.config.ts": "_f_frontcommerce", | ||
| 3198 | "funding.yml": "_f_funding", | ||
| 3199 | "fuse.js": "_f_fusebox", | ||
| 3200 | "gatsby-browser.js": "_f_gatsby", | ||
| 3201 | "gatsby-browser.ts": "_f_gatsby", | ||
| 3202 | "gatsby-browser.tsx": "_f_gatsby", | ||
| 3203 | "gatsby-ssr.js": "_f_gatsby", | ||
| 3204 | "gatsby-ssr.ts": "_f_gatsby", | ||
| 3205 | "gatsby-ssr.tsx": "_f_gatsby", | ||
| 3206 | "gatsby-config.js": "_f_gatsby", | ||
| 3207 | "gatsby-config.ts": "_f_gatsby", | ||
| 3208 | "gatsby-config.mjs": "_f_gatsby", | ||
| 3209 | "gatsby-node.js": "_f_gatsby", | ||
| 3210 | "gatsby-node.ts": "_f_gatsby", | ||
| 3211 | "gatsby-node.mjs": "_f_gatsby", | ||
| 3212 | ".gcloudignore": "_f_gcloud", | ||
| 3213 | "gemini.md": "_f_gemini", | ||
| 3214 | "GEMINI.md": "_f_gemini", | ||
| 3215 | ".git": "_f_git", | ||
| 3216 | ".gitattributes": "_f_git", | ||
| 3217 | ".gitconfig": "_f_git", | ||
| 3218 | ".gitignore": "_f_git", | ||
| 3219 | ".gitmodules": "_f_git", | ||
| 3220 | ".gitkeep": "_f_git", | ||
| 3221 | ".git-blame-ignore-revs": "_f_git", | ||
| 3222 | ".mailmap": "_f_git", | ||
| 3223 | ".issuetracker": "_f_git", | ||
| 3224 | ".gitlab-ci.yml": "_f_gitlab", | ||
| 3225 | ".gitpod.yaml": "_f_gitpod", | ||
| 3226 | ".gitpod.yml": "_f_gitpod", | ||
| 3227 | "gitpod.yaml": "_f_gitpod", | ||
| 3228 | "gitpod.yml": "_f_gitpod", | ||
| 3229 | "gleam.toml": "_f_gleamconfig", | ||
| 3230 | "glide.yml": "_f_glide", | ||
| 3231 | ".glitterrc": "_f_glitter", | ||
| 3232 | "go.sum": "_f_go_package", | ||
| 3233 | "go.mod": "_f_go_package", | ||
| 3234 | "go.work": "_f_go_work", | ||
| 3235 | "go.work.sum": "_f_go_work", | ||
| 3236 | ".gqlconfig": "_f_graphql", | ||
| 3237 | ".graphqlconfig": "_f_graphql_config", | ||
| 3238 | ".graphqlconfig.yml": "_f_graphql_config", | ||
| 3239 | ".graphqlconfig.yaml": "_f_graphql_config", | ||
| 3240 | "greenkeeper.json": "_f_greenkeeper", | ||
| 3241 | "gridsome.config.js": "_f_gridsome", | ||
| 3242 | "gridsome.config.ts": "_f_gridsome", | ||
| 3243 | "gridsome.server.js": "_f_gridsome", | ||
| 3244 | "gridsome.server.ts": "_f_gridsome", | ||
| 3245 | "gridsome.client.js": "_f_gridsome", | ||
| 3246 | "gridsome.client.ts": "_f_gridsome", | ||
| 3247 | "gruntfile.js": "_f_grunt", | ||
| 3248 | "gruntfile.cjs": "_f_grunt", | ||
| 3249 | "gruntfile.coffee": "_f_grunt", | ||
| 3250 | "gruntfile.ts": "_f_grunt", | ||
| 3251 | "gruntfile.babel.js": "_f_grunt", | ||
| 3252 | "gruntfile.babel.cjs": "_f_grunt", | ||
| 3253 | "gruntfile.babel.coffee": "_f_grunt", | ||
| 3254 | "gruntfile.babel.ts": "_f_grunt", | ||
| 3255 | "gulpfile.js": "_f_gulp", | ||
| 3256 | "gulpfile.coffee": "_f_gulp", | ||
| 3257 | "gulpfile.ts": "_f_gulp", | ||
| 3258 | "gulpfile.mjs": "_f_gulp", | ||
| 3259 | "gulpfile.esm.js": "_f_gulp", | ||
| 3260 | "gulpfile.esm.coffee": "_f_gulp", | ||
| 3261 | "gulpfile.esm.ts": "_f_gulp", | ||
| 3262 | "gulpfile.esm.mjs": "_f_gulp", | ||
| 3263 | "gulpfile.babel.js": "_f_gulp", | ||
| 3264 | "gulpfile.babel.coffee": "_f_gulp", | ||
| 3265 | "gulpfile.babel.ts": "_f_gulp", | ||
| 3266 | "gulpfile.babel.mjs": "_f_gulp", | ||
| 3267 | "hardhat.config.cjs": "_f_hardhat", | ||
| 3268 | "hardhat.config.js": "_f_hardhat", | ||
| 3269 | "hardhat.config.ts": "_f_hardhat", | ||
| 3270 | "haxelib.json": "_f_haxe", | ||
| 3271 | "checkstyle.json": "_f_haxecheckstyle", | ||
| 3272 | ".p4ignore": "_f_helix", | ||
| 3273 | "chart.lock": "_f_helm", | ||
| 3274 | "chart.yaml": "_f_helm", | ||
| 3275 | "histoire.config.ts": "_f_histoire", | ||
| 3276 | "histoire.config.js": "_f_histoire", | ||
| 3277 | ".histoire.ts": "_f_histoire", | ||
| 3278 | ".histoire.js": "_f_histoire", | ||
| 3279 | "horusec-config.json": "_f_horusec", | ||
| 3280 | ".htmlhintrc": "_f_htmlhint", | ||
| 3281 | ".htmlvalidateignore": "_f_htmlvalidate", | ||
| 3282 | ".htmlvalidate.js": "_f_htmlvalidate", | ||
| 3283 | ".htmlvalidate.cjs": "_f_htmlvalidate", | ||
| 3284 | ".htmlvalidate.json": "_f_htmlvalidate", | ||
| 3285 | "hugo.json": "_f_hugo", | ||
| 3286 | "hugo.toml": "_f_hugo", | ||
| 3287 | "hugo.yaml": "_f_hugo", | ||
| 3288 | ".hugo_build.lock": "_f_hugo", | ||
| 3289 | "humans.txt": "_f_humanstxt", | ||
| 3290 | ".huskyrc": "_f_husky", | ||
| 3291 | "husky.config.js": "_f_husky", | ||
| 3292 | ".huskyrc.js": "_f_husky", | ||
| 3293 | ".huskyrc.json": "_f_husky", | ||
| 3294 | ".huskyrc.yaml": "_f_husky", | ||
| 3295 | ".huskyrc.yml": "_f_husky", | ||
| 3296 | "ionic.project": "_f_ionic", | ||
| 3297 | "ionic.config.json": "_f_ionic", | ||
| 3298 | "jakefile": "_f_jake", | ||
| 3299 | "jakefile.js": "_f_jake", | ||
| 3300 | "jasmine.json": "_f_jasmine", | ||
| 3301 | ".nojekyll": "_f_jekyll", | ||
| 3302 | "jest.json": "_f_jest", | ||
| 3303 | "jest.config.babel.js": "_f_jest", | ||
| 3304 | ".jestrc": "_f_jest", | ||
| 3305 | ".jestrc.js": "_f_jest", | ||
| 3306 | ".jestrc.json": "_f_jest", | ||
| 3307 | "jest.config.js": "_f_jest", | ||
| 3308 | "jest.config.cjs": "_f_jest", | ||
| 3309 | "jest.config.mjs": "_f_jest", | ||
| 3310 | "jest.config.json": "_f_jest", | ||
| 3311 | "jest.config.ts": "_f_jest", | ||
| 3312 | "jest.config.base.js": "_f_jest", | ||
| 3313 | "jest.config.base.cjs": "_f_jest", | ||
| 3314 | "jest.config.base.mjs": "_f_jest", | ||
| 3315 | "jest.config.base.json": "_f_jest", | ||
| 3316 | "jest.config.base.ts": "_f_jest", | ||
| 3317 | "jest.config.common.js": "_f_jest", | ||
| 3318 | "jest.config.common.cjs": "_f_jest", | ||
| 3319 | "jest.config.common.mjs": "_f_jest", | ||
| 3320 | "jest.config.common.json": "_f_jest", | ||
| 3321 | "jest.config.common.ts": "_f_jest", | ||
| 3322 | "jest.config.e2e.js": "_f_jest", | ||
| 3323 | "jest.config.e2e.cjs": "_f_jest", | ||
| 3324 | "jest.config.e2e.mjs": "_f_jest", | ||
| 3325 | "jest.config.e2e.json": "_f_jest", | ||
| 3326 | "jest.config.e2e.ts": "_f_jest", | ||
| 3327 | "jest.config.int.js": "_f_jest", | ||
| 3328 | "jest.config.int.cjs": "_f_jest", | ||
| 3329 | "jest.config.int.mjs": "_f_jest", | ||
| 3330 | "jest.config.int.json": "_f_jest", | ||
| 3331 | "jest.config.int.ts": "_f_jest", | ||
| 3332 | "jest.config.integration.js": "_f_jest", | ||
| 3333 | "jest.config.integration.cjs": "_f_jest", | ||
| 3334 | "jest.config.integration.mjs": "_f_jest", | ||
| 3335 | "jest.config.integration.json": "_f_jest", | ||
| 3336 | "jest.config.integration.ts": "_f_jest", | ||
| 3337 | "jest.config.unit.js": "_f_jest", | ||
| 3338 | "jest.config.unit.cjs": "_f_jest", | ||
| 3339 | "jest.config.unit.mjs": "_f_jest", | ||
| 3340 | "jest.config.unit.json": "_f_jest", | ||
| 3341 | "jest.config.unit.ts": "_f_jest", | ||
| 3342 | ".jpmignore": "_f_jpm", | ||
| 3343 | ".jsbeautifyrc": "_f_jsbeautify", | ||
| 3344 | "jsbeautifyrc": "_f_jsbeautify", | ||
| 3345 | ".jsbeautify": "_f_jsbeautify", | ||
| 3346 | "jsbeautify": "_f_jsbeautify", | ||
| 3347 | "jsconfig.json": "_f_jsconfig", | ||
| 3348 | ".jscpd.json": "_f_jscpd", | ||
| 3349 | "jscpd-report.xml": "_f_jscpd", | ||
| 3350 | "jscpd-report.json": "_f_jscpd", | ||
| 3351 | "jscpd-report.html": "_f_jscpd", | ||
| 3352 | ".jshintrc": "_f_jshint", | ||
| 3353 | ".jshintignore": "_f_jshint", | ||
| 3354 | "jsr.json": "_f_jsr", | ||
| 3355 | "karma.conf.js": "_f_karma", | ||
| 3356 | "karma.conf.coffee": "_f_karma", | ||
| 3357 | "karma.conf.ts": "_f_karma", | ||
| 3358 | ".kitchen.yml": "_f_kitchenci", | ||
| 3359 | "kitchen.yml": "_f_kitchenci", | ||
| 3360 | ".kiteignore": "_f_kite", | ||
| 3361 | "knip.json": "_f_knip", | ||
| 3362 | "knip.jsonc": "_f_knip", | ||
| 3363 | ".knip.json": "_f_knip", | ||
| 3364 | ".knip.jsonc": "_f_knip", | ||
| 3365 | "knip.ts": "_f_knip", | ||
| 3366 | "knip.js": "_f_knip", | ||
| 3367 | "knip.config.ts": "_f_knip", | ||
| 3368 | "knip.config.js": "_f_knip", | ||
| 3369 | "language-configuration.json": "_f_language_configuration", | ||
| 3370 | "layout.html": "_f_layout", | ||
| 3371 | "layout.htm": "_f_layout", | ||
| 3372 | "lakefile.lean": "_f_leanconfig", | ||
| 3373 | "lakefile.toml": "_f_leanconfig", | ||
| 3374 | "lake-manifest.json": "_f_leanconfig", | ||
| 3375 | "lean-toolchain": "_f_leanconfig", | ||
| 3376 | "lefthook.json": "_f_lefthook", | ||
| 3377 | "lefthook.toml": "_f_lefthook", | ||
| 3378 | "lefthook.yaml": "_f_lefthook", | ||
| 3379 | "lefthook.yml": "_f_lefthook", | ||
| 3380 | "lefthook-local.json": "_f_lefthook", | ||
| 3381 | "lefthook-local.toml": "_f_lefthook", | ||
| 3382 | "lefthook-local.yaml": "_f_lefthook", | ||
| 3383 | "lefthook-local.yml": "_f_lefthook", | ||
| 3384 | ".lefthook.json": "_f_lefthook", | ||
| 3385 | ".lefthook.toml": "_f_lefthook", | ||
| 3386 | ".lefthook.yaml": "_f_lefthook", | ||
| 3387 | ".lefthook.yml": "_f_lefthook", | ||
| 3388 | ".lefthook-local.json": "_f_lefthook", | ||
| 3389 | ".lefthook-local.toml": "_f_lefthook", | ||
| 3390 | ".lefthook-local.yaml": "_f_lefthook", | ||
| 3391 | ".lefthook-local.yml": "_f_lefthook", | ||
| 3392 | "lerna.json": "_f_lerna", | ||
| 3393 | "liara.json": "_f_liara", | ||
| 3394 | ".liaraignore": "_f_liara", | ||
| 3395 | "licence": "_f_license", | ||
| 3396 | "LICENCE": "_f_license", | ||
| 3397 | "license": "_f_license", | ||
| 3398 | "LICENSE": "_f_license", | ||
| 3399 | "copying": "_f_license", | ||
| 3400 | "copying.lesser": "_f_license", | ||
| 3401 | "LICENSE-MIT": "_f_license", | ||
| 3402 | "license-mit": "_f_license", | ||
| 3403 | "LICENSE-APACHE": "_f_license", | ||
| 3404 | "license-apache": "_f_license", | ||
| 3405 | "LICENSE-GPL": "_f_license", | ||
| 3406 | "license-gpl": "_f_license", | ||
| 3407 | "LICENSE-AGPL": "_f_license", | ||
| 3408 | "license-agpl": "_f_license", | ||
| 3409 | "LICENCE.md": "_f_license", | ||
| 3410 | "LICENCE.txt": "_f_license", | ||
| 3411 | "licence.md": "_f_license", | ||
| 3412 | "licence.txt": "_f_license", | ||
| 3413 | "LICENSE.md": "_f_license", | ||
| 3414 | "LICENSE.txt": "_f_license", | ||
| 3415 | "license.md": "_f_license", | ||
| 3416 | "license.txt": "_f_license", | ||
| 3417 | "copying.md": "_f_license", | ||
| 3418 | "copying.txt": "_f_license", | ||
| 3419 | "copying.lesser.md": "_f_license", | ||
| 3420 | "copying.lesser.txt": "_f_license", | ||
| 3421 | "LICENSE-MIT.md": "_f_license", | ||
| 3422 | "LICENSE-MIT.txt": "_f_license", | ||
| 3423 | "license-mit.md": "_f_license", | ||
| 3424 | "license-mit.txt": "_f_license", | ||
| 3425 | "LICENSE-APACHE.md": "_f_license", | ||
| 3426 | "LICENSE-APACHE.txt": "_f_license", | ||
| 3427 | "license-apache.md": "_f_license", | ||
| 3428 | "license-apache.txt": "_f_license", | ||
| 3429 | "LICENSE-GPL.md": "_f_license", | ||
| 3430 | "LICENSE-GPL.txt": "_f_license", | ||
| 3431 | "license-gpl.md": "_f_license", | ||
| 3432 | "license-gpl.txt": "_f_license", | ||
| 3433 | "LICENSE-AGPL.md": "_f_license", | ||
| 3434 | "LICENSE-AGPL.txt": "_f_license", | ||
| 3435 | "license-agpl.md": "_f_license", | ||
| 3436 | "license-agpl.txt": "_f_license", | ||
| 3437 | ".licrc": "_f_licensebat", | ||
| 3438 | "budget.json": "_f_lighthouse", | ||
| 3439 | "budgets.json": "_f_lighthouse", | ||
| 3440 | ".lighthouserc.cjs": "_f_lighthouse", | ||
| 3441 | ".lighthouserc.js": "_f_lighthouse", | ||
| 3442 | ".lighthouserc.json": "_f_lighthouse", | ||
| 3443 | ".lighthouserc.yaml": "_f_lighthouse", | ||
| 3444 | ".lighthouserc.yml": "_f_lighthouse", | ||
| 3445 | "include.xml": "_f_lime", | ||
| 3446 | ".lintstagedrc": "_f_lintstagedrc", | ||
| 3447 | ".lintstagedrc.json": "_f_lintstagedrc", | ||
| 3448 | ".lintstagedrc.yaml": "_f_lintstagedrc", | ||
| 3449 | ".lintstagedrc.yml": "_f_lintstagedrc", | ||
| 3450 | ".lintstagedrc.mjs": "_f_lintstagedrc", | ||
| 3451 | ".lintstagedrc.mts": "_f_lintstagedrc", | ||
| 3452 | ".lintstagedrc.js": "_f_lintstagedrc", | ||
| 3453 | ".lintstagedrc.ts": "_f_lintstagedrc", | ||
| 3454 | ".lintstagedrc.cjs": "_f_lintstagedrc", | ||
| 3455 | ".lintstagedrc.cts": "_f_lintstagedrc", | ||
| 3456 | "lint-staged.config.mjs": "_f_lintstagedrc", | ||
| 3457 | "lint-staged.config.mts": "_f_lintstagedrc", | ||
| 3458 | "lint-staged.config.js": "_f_lintstagedrc", | ||
| 3459 | "lint-staged.config.ts": "_f_lintstagedrc", | ||
| 3460 | "lint-staged.config.cjs": "_f_lintstagedrc", | ||
| 3461 | "lint-staged.config.cts": "_f_lintstagedrc", | ||
| 3462 | "mailing.config.json": "_f_mailing", | ||
| 3463 | "manifest": "_f_manifest", | ||
| 3464 | "manifest.bak": "_f_manifest_bak", | ||
| 3465 | "manifest.skip": "_f_manifest_skip", | ||
| 3466 | ".markdownlintrc": "_f_markdownlint", | ||
| 3467 | ".markdownlint.json": "_f_markdownlint", | ||
| 3468 | ".markdownlint.jsonc": "_f_markdownlint", | ||
| 3469 | ".markdownlint.yml": "_f_markdownlint", | ||
| 3470 | ".markdownlint.yaml": "_f_markdownlint", | ||
| 3471 | ".markdownlint.cjs": "_f_markdownlint", | ||
| 3472 | ".markdownlint-cli2.json": "_f_markdownlint", | ||
| 3473 | ".markdownlint-cli2.jsonc": "_f_markdownlint", | ||
| 3474 | ".markdownlint-cli2.yml": "_f_markdownlint", | ||
| 3475 | ".markdownlint-cli2.yaml": "_f_markdownlint", | ||
| 3476 | ".markdownlint-cli2.cjs": "_f_markdownlint", | ||
| 3477 | ".markdownlintignore": "_f_markdownlint_ignore", | ||
| 3478 | ".markuplintrc": "_f_markuplint", | ||
| 3479 | ".markuplintrc.json": "_f_markuplint", | ||
| 3480 | ".markuplintrc.yaml": "_f_markuplint", | ||
| 3481 | ".markuplintrc.yml": "_f_markuplint", | ||
| 3482 | ".markuplintrc.js": "_f_markuplint", | ||
| 3483 | ".markuplintrc.cjs": "_f_markuplint", | ||
| 3484 | ".markuplintrc.mjs": "_f_markuplint", | ||
| 3485 | ".markuplintrc.ts": "_f_markuplint", | ||
| 3486 | "markuplint.config.json": "_f_markuplint", | ||
| 3487 | "markuplint.config.yaml": "_f_markuplint", | ||
| 3488 | "markuplint.config.yml": "_f_markuplint", | ||
| 3489 | "markuplint.config.js": "_f_markuplint", | ||
| 3490 | "markuplint.config.cjs": "_f_markuplint", | ||
| 3491 | "markuplint.config.mjs": "_f_markuplint", | ||
| 3492 | "markuplint.config.ts": "_f_markuplint", | ||
| 3493 | "master.js": "_f_master-co", | ||
| 3494 | "master.ts": "_f_master-co", | ||
| 3495 | "master.mjs": "_f_master-co", | ||
| 3496 | "master.json": "_f_master-co", | ||
| 3497 | "master.css.js": "_f_master-co", | ||
| 3498 | "master.css.ts": "_f_master-co", | ||
| 3499 | "master.css.mjs": "_f_master-co", | ||
| 3500 | "master.css.json": "_f_master-co", | ||
| 3501 | "maven.config": "_f_maven", | ||
| 3502 | "pom.xml": "_f_maven", | ||
| 3503 | "extensions.xml": "_f_maven", | ||
| 3504 | "settings.xml": "_f_maven", | ||
| 3505 | "mcp.json": "_f_mcp", | ||
| 3506 | "mdx-components.cjs": "_f_mdx-components", | ||
| 3507 | "mdx-components.cts": "_f_mdx-components", | ||
| 3508 | "mdx-components.js": "_f_mdx-components", | ||
| 3509 | "mdx-components.jsx": "_f_mdx-components", | ||
| 3510 | "mdx-components.mjs": "_f_mdx-components", | ||
| 3511 | "mdx-components.mts": "_f_mdx-components", | ||
| 3512 | "mdx-components.ts": "_f_mdx-components", | ||
| 3513 | "mdx-components.tsx": "_f_mdx-components", | ||
| 3514 | ".mdxlintrc": "_f_mdxlint", | ||
| 3515 | ".mdxlintignore": "_f_mdxlint", | ||
| 3516 | ".mdxlintrc.cjs": "_f_mdxlint", | ||
| 3517 | ".mdxlintrc.js": "_f_mdxlint", | ||
| 3518 | ".mdxlintrc.json": "_f_mdxlint", | ||
| 3519 | ".mdxlintrc.mjs": "_f_mdxlint", | ||
| 3520 | ".mdxlintrc.yml": "_f_mdxlint", | ||
| 3521 | ".mdxlintrc.yaml": "_f_mdxlint", | ||
| 3522 | ".hgignore": "_f_mercurial", | ||
| 3523 | "mocha.opts": "_f_mocha", | ||
| 3524 | ".mocharc.cjs": "_f_mocha", | ||
| 3525 | ".mocharc.js": "_f_mocha", | ||
| 3526 | ".mocharc.json": "_f_mocha", | ||
| 3527 | ".mocharc.jsonc": "_f_mocha", | ||
| 3528 | ".mocharc.mjs": "_f_mocha", | ||
| 3529 | ".mocharc.yaml": "_f_mocha", | ||
| 3530 | ".mocharc.yml": "_f_mocha", | ||
| 3531 | "modernizr": "_f_modernizr", | ||
| 3532 | "modernizr.js": "_f_modernizr", | ||
| 3533 | "modernizrrc.js": "_f_modernizr", | ||
| 3534 | ".modernizr.js": "_f_modernizr", | ||
| 3535 | ".modernizrrc.js": "_f_modernizr", | ||
| 3536 | "moleculer.config.js": "_f_moleculer", | ||
| 3537 | "moleculer.config.json": "_f_moleculer", | ||
| 3538 | "moleculer.config.ts": "_f_moleculer", | ||
| 3539 | ".mtn-ignore": "_f_monotone", | ||
| 3540 | "motif.json": "_f_motif", | ||
| 3541 | "mypy.ini": "_f_mypy", | ||
| 3542 | ".mypy.ini": "_f_mypy", | ||
| 3543 | ".nano-staged.js": "_f_nanostaged", | ||
| 3544 | "nano-staged.js": "_f_nanostaged", | ||
| 3545 | ".nano-staged.cjs": "_f_nanostaged", | ||
| 3546 | "nano-staged.cjs": "_f_nanostaged", | ||
| 3547 | ".nano-staged.mjs": "_f_nanostaged", | ||
| 3548 | "nano-staged.mjs": "_f_nanostaged", | ||
| 3549 | ".nano-staged.json": "_f_nanostaged", | ||
| 3550 | "nano-staged.json": "_f_nanostaged", | ||
| 3551 | ".nanostagedrc": "_f_nanostaged", | ||
| 3552 | ".nest-cli.json": "_f_nestjs", | ||
| 3553 | "nest-cli.json": "_f_nestjs", | ||
| 3554 | "nestconfig.json": "_f_nestjs", | ||
| 3555 | ".nestconfig.json": "_f_nestjs", | ||
| 3556 | "netlify.toml": "_f_netlify", | ||
| 3557 | "next.config.js": "_f_next", | ||
| 3558 | "next.config.cjs": "_f_next", | ||
| 3559 | "next.config.mjs": "_f_next", | ||
| 3560 | "next.config.ts": "_f_next", | ||
| 3561 | ".nf": "_f_nextflow", | ||
| 3562 | "ng-tailwind.js": "_f_ng_tailwind", | ||
| 3563 | "nginx.conf": "_f_nginx", | ||
| 3564 | "build.ninja": "_f_ninja", | ||
| 3565 | "flake.lock": "_f_nix", | ||
| 3566 | ".node-version": "_f_node", | ||
| 3567 | ".nvmrc": "_f_node", | ||
| 3568 | "node.config.json": "_f_node", | ||
| 3569 | "nodemon.json": "_f_nodemon", | ||
| 3570 | ".npmignore": "_f_npm", | ||
| 3571 | ".npmrc": "_f_npm", | ||
| 3572 | ".package-lock.json": "_f_npm", | ||
| 3573 | "package.json": "_f_npm", | ||
| 3574 | "package-lock.json": "_f_npm", | ||
| 3575 | "npm-shrinkwrap.json": "_f_npm", | ||
| 3576 | ".npmpackagejsonlintrc": "_f_npmpackagejsonlint", | ||
| 3577 | ".npmpackagejsonlintrc.cjs": "_f_npmpackagejsonlint", | ||
| 3578 | ".npmpackagejsonlintrc.js": "_f_npmpackagejsonlint", | ||
| 3579 | ".npmpackagejsonlintrc.json": "_f_npmpackagejsonlint", | ||
| 3580 | ".npmpackagejsonlintrc.yaml": "_f_npmpackagejsonlint", | ||
| 3581 | ".npmpackagejsonlintrc.yml": "_f_npmpackagejsonlint", | ||
| 3582 | ".npmpackagejsonlintrc.mjs": "_f_npmpackagejsonlint", | ||
| 3583 | ".npmpackagejsonlintignore": "_f_npmpackagejsonlint", | ||
| 3584 | "npmpackagejsonlint.config.cjs": "_f_npmpackagejsonlint", | ||
| 3585 | "npmpackagejsonlint.config.js": "_f_npmpackagejsonlint", | ||
| 3586 | "npmpackagejsonlint.config.mjs": "_f_npmpackagejsonlint", | ||
| 3587 | ".nsrirc": "_f_nsri", | ||
| 3588 | ".nsriignore": "_f_nsri", | ||
| 3589 | "nsri.config.js": "_f_nsri", | ||
| 3590 | ".nsrirc.js": "_f_nsri", | ||
| 3591 | ".nsrirc.json": "_f_nsri", | ||
| 3592 | ".nsrirc.yaml": "_f_nsri", | ||
| 3593 | ".nsrirc.yml": "_f_nsri", | ||
| 3594 | ".integrity.json": "_f_nsri-integrity", | ||
| 3595 | ".nuxtignore": "_f_nuxt", | ||
| 3596 | ".nuxtrc": "_f_nuxt", | ||
| 3597 | "nuxt.config.js": "_f_nuxt", | ||
| 3598 | "nuxt.config.ts": "_f_nuxt", | ||
| 3599 | "nuxt.config.mjs": "_f_nuxt", | ||
| 3600 | "nuxt.js": "_f_nuxt", | ||
| 3601 | "nuxt.ts": "_f_nuxt", | ||
| 3602 | "nuxt.mjs": "_f_nuxt", | ||
| 3603 | "nx.json": "_f_nx", | ||
| 3604 | ".nycrc": "_f_nyc", | ||
| 3605 | ".nycrc.json": "_f_nyc", | ||
| 3606 | ".objidconfig": "_f_objidconfig", | ||
| 3607 | ".merlin": "_f_ocaml", | ||
| 3608 | ".oxlintignore": "_f_oxc", | ||
| 3609 | ".oxlintrc.json": "_f_oxc", | ||
| 3610 | ".oxlintrc.jsonc": "_f_oxc", | ||
| 3611 | ".oxfmtrc.json": "_f_oxc", | ||
| 3612 | ".oxfmtrc.jsonc": "_f_oxc", | ||
| 3613 | ".packshiprc": "_f_packship", | ||
| 3614 | ".packshiprc.json": "_f_packship", | ||
| 3615 | ".packshiprc.js": "_f_packship", | ||
| 3616 | ".packshiprc.ts": "_f_packship", | ||
| 3617 | "packship.config.js": "_f_packship", | ||
| 3618 | "packship.config.ts": "_f_packship", | ||
| 3619 | "packship.config.mjs": "_f_packship", | ||
| 3620 | "packship.config.mts": "_f_packship", | ||
| 3621 | "packship.config.json": "_f_packship", | ||
| 3622 | "paket.dependencies": "_f_paket", | ||
| 3623 | "paket.lock": "_f_paket", | ||
| 3624 | "paket.references": "_f_paket", | ||
| 3625 | "paket.template": "_f_paket", | ||
| 3626 | "paket.local": "_f_paket", | ||
| 3627 | "panda.config.js": "_f_pandacss", | ||
| 3628 | "panda.config.mjs": "_f_pandacss", | ||
| 3629 | "panda.config.ts": "_f_pandacss", | ||
| 3630 | ".pdm-python": "_f_pdm", | ||
| 3631 | "pdm.lock": "_f_pdm", | ||
| 3632 | "pdm.toml": "_f_pdm", | ||
| 3633 | "peeky.config.ts": "_f_peeky", | ||
| 3634 | "peeky.config.js": "_f_peeky", | ||
| 3635 | "peeky.config.mjs": "_f_peeky", | ||
| 3636 | ".php-cs-fixer.php": "_f_phpcsfixer", | ||
| 3637 | ".php-cs-fixer.dist.php": "_f_phpcsfixer", | ||
| 3638 | ".php_cs": "_f_phpcsfixer", | ||
| 3639 | ".php_cs.dist": "_f_phpcsfixer", | ||
| 3640 | "phpstan.neon": "_f_phpstan", | ||
| 3641 | "phpstan.dist.neon": "_f_phpstan", | ||
| 3642 | "phpunit": "_f_phpunit", | ||
| 3643 | "phpunit.xml": "_f_phpunit", | ||
| 3644 | "phpunit.xml.dist": "_f_phpunit", | ||
| 3645 | ".phraseapp.yml": "_f_phraseapp", | ||
| 3646 | "pipfile": "_f_pip", | ||
| 3647 | "pipfile.lock": "_f_pip", | ||
| 3648 | "platformio.ini": "_f_platformio", | ||
| 3649 | "playwright.config.js": "_f_playwright", | ||
| 3650 | "playwright.config.ts": "_f_playwright", | ||
| 3651 | "playwright.config.mts": "_f_playwright", | ||
| 3652 | "playwright.config.mjs": "_f_playwright", | ||
| 3653 | "playwright.config.cts": "_f_playwright", | ||
| 3654 | "playwright.config.cjs": "_f_playwright", | ||
| 3655 | "ecosystem.config.js": "_f_pm2", | ||
| 3656 | "ecosystem.config.cjs": "_f_pm2", | ||
| 3657 | "ecosystem.config.json": "_f_pm2", | ||
| 3658 | "ecosystem.config.yaml": "_f_pm2", | ||
| 3659 | "ecosystem.config.yml": "_f_pm2", | ||
| 3660 | ".pnpmfile.cjs": "_f_pnpm", | ||
| 3661 | "pnpmfile.js": "_f_pnpm", | ||
| 3662 | "pnpm-lock.yaml": "_f_pnpm", | ||
| 3663 | "pnpm-workspace.yaml": "_f_pnpm", | ||
| 3664 | "poetry.lock": "_f_poetry", | ||
| 3665 | ".postcssrc": "_f_postcssconfig", | ||
| 3666 | ".postcssrc.json": "_f_postcssconfig", | ||
| 3667 | ".postcssrc.yaml": "_f_postcssconfig", | ||
| 3668 | ".postcssrc.yml": "_f_postcssconfig", | ||
| 3669 | ".postcssrc.ts": "_f_postcssconfig", | ||
| 3670 | ".postcssrc.cts": "_f_postcssconfig", | ||
| 3671 | ".postcssrc.mts": "_f_postcssconfig", | ||
| 3672 | ".postcssrc.js": "_f_postcssconfig", | ||
| 3673 | ".postcssrc.cjs": "_f_postcssconfig", | ||
| 3674 | ".postcssrc.mjs": "_f_postcssconfig", | ||
| 3675 | "postcss.config.ts": "_f_postcssconfig", | ||
| 3676 | "postcss.config.cts": "_f_postcssconfig", | ||
| 3677 | "postcss.config.mts": "_f_postcssconfig", | ||
| 3678 | "postcss.config.js": "_f_postcssconfig", | ||
| 3679 | "postcss.config.cjs": "_f_postcssconfig", | ||
| 3680 | "postcss.config.mjs": "_f_postcssconfig", | ||
| 3681 | "preact.config.js": "_f_preact", | ||
| 3682 | ".pre-commit-config.yaml": "_f_precommit", | ||
| 3683 | ".prettierrc": "_f_prettier", | ||
| 3684 | ".prettierignore": "_f_prettier", | ||
| 3685 | "prettier.config.js": "_f_prettier", | ||
| 3686 | "prettier.config.cjs": "_f_prettier", | ||
| 3687 | "prettier.config.mjs": "_f_prettier", | ||
| 3688 | "prettier.config.ts": "_f_prettier", | ||
| 3689 | "prettier.config.coffee": "_f_prettier", | ||
| 3690 | ".prettierrc.js": "_f_prettier", | ||
| 3691 | ".prettierrc.cjs": "_f_prettier", | ||
| 3692 | ".prettierrc.mjs": "_f_prettier", | ||
| 3693 | ".prettierrc.json": "_f_prettier", | ||
| 3694 | ".prettierrc.json5": "_f_prettier", | ||
| 3695 | ".prettierrc.yml": "_f_prettier", | ||
| 3696 | ".prettierrc.yaml": "_f_prettier", | ||
| 3697 | ".prettierrc.toml": "_f_prettier", | ||
| 3698 | "prisma.config.js": "_f_prismaconfig", | ||
| 3699 | "prisma.config.ts": "_f_prismaconfig", | ||
| 3700 | "procfile": "_f_procfile", | ||
| 3701 | "protractor.conf.js": "_f_protractor", | ||
| 3702 | "protractor.conf.coffee": "_f_protractor", | ||
| 3703 | "protractor.conf.ts": "_f_protractor", | ||
| 3704 | "publiccode.yml": "_f_publiccode", | ||
| 3705 | ".jade-lintrc": "_f_pug", | ||
| 3706 | ".pug-lintrc": "_f_pug", | ||
| 3707 | ".jade-lint.json": "_f_pug", | ||
| 3708 | ".pug-lintrc.js": "_f_pug", | ||
| 3709 | ".pug-lintrc.json": "_f_pug", | ||
| 3710 | "Pulumi.yaml": "_f_pulumi", | ||
| 3711 | "Pulumi.yml": "_f_pulumi", | ||
| 3712 | "Pulumi.dev.yaml": "_f_pulumi", | ||
| 3713 | "Pulumi.dev.yml": "_f_pulumi", | ||
| 3714 | "Pulumi.prod.yaml": "_f_pulumi", | ||
| 3715 | "Pulumi.prod.yml": "_f_pulumi", | ||
| 3716 | "purgecss.config.js": "_f_purgecss", | ||
| 3717 | ".python-version": "_f_pyenv", | ||
| 3718 | "pyproject.toml": "_f_pypi", | ||
| 3719 | "pytest.ini": "_f_pytest", | ||
| 3720 | ".pytest.ini": "_f_pytest", | ||
| 3721 | "pytest.toml": "_f_pytest", | ||
| 3722 | ".pytest.toml": "_f_pytest", | ||
| 3723 | "py.typed": "_f_pytyped", | ||
| 3724 | ".pyup": "_f_pyup", | ||
| 3725 | ".pyup.yml": "_f_pyup", | ||
| 3726 | "qmldir": "_f_qmldir", | ||
| 3727 | "quasar.conf.js": "_f_quasar", | ||
| 3728 | "quasar.config.js": "_f_quasar", | ||
| 3729 | "quasar.config.mjs": "_f_quasar", | ||
| 3730 | "quasar.config.cjs": "_f_quasar", | ||
| 3731 | "quasar.config.ts": "_f_quasar", | ||
| 3732 | "Rakefile": "_f_rake", | ||
| 3733 | "razzle.config.js": "_f_razzle", | ||
| 3734 | "react-router.config.js": "_f_reactrouter", | ||
| 3735 | "react-router.config.ts": "_f_reactrouter", | ||
| 3736 | ".rehyperc": "_f_rehype", | ||
| 3737 | ".rehypeignore": "_f_rehype", | ||
| 3738 | ".rehyperc.cjs": "_f_rehype", | ||
| 3739 | ".rehyperc.js": "_f_rehype", | ||
| 3740 | ".rehyperc.json": "_f_rehype", | ||
| 3741 | ".rehyperc.mjs": "_f_rehype", | ||
| 3742 | ".rehyperc.yml": "_f_rehype", | ||
| 3743 | ".rehyperc.yaml": "_f_rehype", | ||
| 3744 | ".remarkrc": "_f_remark", | ||
| 3745 | ".remarkignore": "_f_remark", | ||
| 3746 | ".remarkrc.cjs": "_f_remark", | ||
| 3747 | ".remarkrc.js": "_f_remark", | ||
| 3748 | ".remarkrc.json": "_f_remark", | ||
| 3749 | ".remarkrc.mjs": "_f_remark", | ||
| 3750 | ".remarkrc.yml": "_f_remark", | ||
| 3751 | ".remarkrc.yaml": "_f_remark", | ||
| 3752 | ".renovaterc": "_f_renovate", | ||
| 3753 | ".renovaterc.json": "_f_renovate", | ||
| 3754 | "renovate.json": "_f_renovate", | ||
| 3755 | "renovate.json5": "_f_renovate", | ||
| 3756 | ".replit": "_f_replit", | ||
| 3757 | "replit.nix": "_f_replit", | ||
| 3758 | ".retextrc": "_f_retext", | ||
| 3759 | ".retextignore": "_f_retext", | ||
| 3760 | ".retextrc.cjs": "_f_retext", | ||
| 3761 | ".retextrc.js": "_f_retext", | ||
| 3762 | ".retextrc.json": "_f_retext", | ||
| 3763 | ".retextrc.mjs": "_f_retext", | ||
| 3764 | ".retextrc.yml": "_f_retext", | ||
| 3765 | ".retextrc.yaml": "_f_retext", | ||
| 3766 | "robots.txt": "_f_robots", | ||
| 3767 | "rolldown.config.js": "_f_rolldown", | ||
| 3768 | "rolldown.config.cjs": "_f_rolldown", | ||
| 3769 | "rolldown.config.mjs": "_f_rolldown", | ||
| 3770 | "rolldown.config.coffee": "_f_rolldown", | ||
| 3771 | "rolldown.config.ts": "_f_rolldown", | ||
| 3772 | "rolldown.config.mts": "_f_rolldown", | ||
| 3773 | "rolldown.config.cts": "_f_rolldown", | ||
| 3774 | "rolldown.config.common.js": "_f_rolldown", | ||
| 3775 | "rolldown.config.common.cjs": "_f_rolldown", | ||
| 3776 | "rolldown.config.common.mjs": "_f_rolldown", | ||
| 3777 | "rolldown.config.common.coffee": "_f_rolldown", | ||
| 3778 | "rolldown.config.common.ts": "_f_rolldown", | ||
| 3779 | "rolldown.config.common.mts": "_f_rolldown", | ||
| 3780 | "rolldown.config.common.cts": "_f_rolldown", | ||
| 3781 | "rolldown.config.dev.js": "_f_rolldown", | ||
| 3782 | "rolldown.config.dev.cjs": "_f_rolldown", | ||
| 3783 | "rolldown.config.dev.mjs": "_f_rolldown", | ||
| 3784 | "rolldown.config.dev.coffee": "_f_rolldown", | ||
| 3785 | "rolldown.config.dev.ts": "_f_rolldown", | ||
| 3786 | "rolldown.config.dev.mts": "_f_rolldown", | ||
| 3787 | "rolldown.config.dev.cts": "_f_rolldown", | ||
| 3788 | "rolldown.config.prod.js": "_f_rolldown", | ||
| 3789 | "rolldown.config.prod.cjs": "_f_rolldown", | ||
| 3790 | "rolldown.config.prod.mjs": "_f_rolldown", | ||
| 3791 | "rolldown.config.prod.coffee": "_f_rolldown", | ||
| 3792 | "rolldown.config.prod.ts": "_f_rolldown", | ||
| 3793 | "rolldown.config.prod.mts": "_f_rolldown", | ||
| 3794 | "rolldown.config.prod.cts": "_f_rolldown", | ||
| 3795 | "rollup.config.js": "_f_rollup", | ||
| 3796 | "rollup.config.cjs": "_f_rollup", | ||
| 3797 | "rollup.config.mjs": "_f_rollup", | ||
| 3798 | "rollup.config.coffee": "_f_rollup", | ||
| 3799 | "rollup.config.ts": "_f_rollup", | ||
| 3800 | "rollup.config.common.js": "_f_rollup", | ||
| 3801 | "rollup.config.common.cjs": "_f_rollup", | ||
| 3802 | "rollup.config.common.mjs": "_f_rollup", | ||
| 3803 | "rollup.config.common.coffee": "_f_rollup", | ||
| 3804 | "rollup.config.common.ts": "_f_rollup", | ||
| 3805 | "rollup.config.dev.js": "_f_rollup", | ||
| 3806 | "rollup.config.dev.cjs": "_f_rollup", | ||
| 3807 | "rollup.config.dev.mjs": "_f_rollup", | ||
| 3808 | "rollup.config.dev.coffee": "_f_rollup", | ||
| 3809 | "rollup.config.dev.ts": "_f_rollup", | ||
| 3810 | "rollup.config.prod.js": "_f_rollup", | ||
| 3811 | "rollup.config.prod.cjs": "_f_rollup", | ||
| 3812 | "rollup.config.prod.mjs": "_f_rollup", | ||
| 3813 | "rollup.config.prod.coffee": "_f_rollup", | ||
| 3814 | "rollup.config.prod.ts": "_f_rollup", | ||
| 3815 | "rome.json": "_f_rome", | ||
| 3816 | ".rspec": "_f_rspec", | ||
| 3817 | ".rubocop.yml": "_f_rubocop", | ||
| 3818 | ".rubocop_todo.yml": "_f_rubocop", | ||
| 3819 | ".ruby-version": "_f_ruby", | ||
| 3820 | "rust-toolchain": "_f_rust_toolchain", | ||
| 3821 | "rust-toolchain.toml": "_f_rust_toolchain", | ||
| 3822 | ".slshrc": "_f_s-lang", | ||
| 3823 | ".isisrc": "_f_s-lang", | ||
| 3824 | ".jedrc": "_f_s-lang", | ||
| 3825 | ".sailsrc": "_f_sails", | ||
| 3826 | ".sapphirerc.json": "_f_sapphire_framework_cli", | ||
| 3827 | ".sapphirerc.yml": "_f_sapphire_framework_cli", | ||
| 3828 | ".sapphirerc": "_f_sapphire_framework_cli", | ||
| 3829 | "seedkit.config.js": "_f_seedkit", | ||
| 3830 | "seedkit.config.ts": "_f_seedkit", | ||
| 3831 | "seedkit.config.mjs": "_f_seedkit", | ||
| 3832 | ".sentryclirc": "_f_sentry", | ||
| 3833 | ".sequelizerc": "_f_sequelize", | ||
| 3834 | ".sequelizerc.js": "_f_sequelize", | ||
| 3835 | ".sequelizerc.json": "_f_sequelize", | ||
| 3836 | "serverless.yml": "_f_serverless", | ||
| 3837 | "serverless.json": "_f_serverless", | ||
| 3838 | "serverless.js": "_f_serverless", | ||
| 3839 | "serverless.ts": "_f_serverless", | ||
| 3840 | "components.json": "_f_shadcn", | ||
| 3841 | ".shellcheckrc": "_f_shellcheck", | ||
| 3842 | "Shuttle.toml": "_f_shuttle", | ||
| 3843 | "sitemap.xml": "_f_sitemap", | ||
| 3844 | "sitemap.rss": "_f_sitemap", | ||
| 3845 | "sitemap.txt": "_f_sitemap", | ||
| 3846 | "sitemap.atom": "_f_sitemap", | ||
| 3847 | "slash-up.config.js": "_f_slashup", | ||
| 3848 | "smithery.yaml": "_f_smithery", | ||
| 3849 | "snapcraft.yaml": "_f_snapcraft", | ||
| 3850 | "snaplet.config.js": "_f_snaplet", | ||
| 3851 | "snaplet.config.ts": "_f_snaplet", | ||
| 3852 | ".snyk": "_f_snyk", | ||
| 3853 | ".solidarity": "_f_solidarity", | ||
| 3854 | ".solidarity.json": "_f_solidarity", | ||
| 3855 | "spin.toml": "_f_spin", | ||
| 3856 | "sst-env.d.ts": "_f_sst", | ||
| 3857 | "sst-env.ts": "_f_sst", | ||
| 3858 | "sst-env.js": "_f_sst", | ||
| 3859 | "sst.config.d.ts": "_f_sst", | ||
| 3860 | "sst.config.ts": "_f_sst", | ||
| 3861 | "sst.config.js": "_f_sst", | ||
| 3862 | ".stackblitzrc": "_f_stackblitz", | ||
| 3863 | "stryker.conf.mjs": "_f_stryker", | ||
| 3864 | "stryker.conf.cjs": "_f_stryker", | ||
| 3865 | "stryker.conf.js": "_f_stryker", | ||
| 3866 | "stryker.conf.conf": "_f_stryker", | ||
| 3867 | "stryker.conf.json": "_f_stryker", | ||
| 3868 | ".stryker.conf.mjs": "_f_stryker", | ||
| 3869 | ".stryker.conf.cjs": "_f_stryker", | ||
| 3870 | ".stryker.conf.js": "_f_stryker", | ||
| 3871 | ".stryker.conf.conf": "_f_stryker", | ||
| 3872 | ".stryker.conf.json": "_f_stryker", | ||
| 3873 | "stryker.config.mjs": "_f_stryker", | ||
| 3874 | "stryker.config.cjs": "_f_stryker", | ||
| 3875 | "stryker.config.js": "_f_stryker", | ||
| 3876 | "stryker.config.conf": "_f_stryker", | ||
| 3877 | "stryker.config.json": "_f_stryker", | ||
| 3878 | ".stryker.config.mjs": "_f_stryker", | ||
| 3879 | ".stryker.config.cjs": "_f_stryker", | ||
| 3880 | ".stryker.config.js": "_f_stryker", | ||
| 3881 | ".stryker.config.conf": "_f_stryker", | ||
| 3882 | ".stryker.config.json": "_f_stryker", | ||
| 3883 | "stryker-config.mjs": "_f_stryker", | ||
| 3884 | "stryker-config.cjs": "_f_stryker", | ||
| 3885 | "stryker-config.js": "_f_stryker", | ||
| 3886 | "stryker-config.conf": "_f_stryker", | ||
| 3887 | "stryker-config.json": "_f_stryker", | ||
| 3888 | "stryker4s.mjs": "_f_stryker", | ||
| 3889 | "stryker4s.cjs": "_f_stryker", | ||
| 3890 | "stryker4s.js": "_f_stryker", | ||
| 3891 | "stryker4s.conf": "_f_stryker", | ||
| 3892 | "stryker4s.json": "_f_stryker", | ||
| 3893 | ".stylelintrc": "_f_stylelint", | ||
| 3894 | ".stylelintignore": "_f_stylelint", | ||
| 3895 | ".stylelintcache": "_f_stylelint", | ||
| 3896 | "stylelint.config.js": "_f_stylelint", | ||
| 3897 | "stylelint.config.json": "_f_stylelint", | ||
| 3898 | "stylelint.config.yaml": "_f_stylelint", | ||
| 3899 | "stylelint.config.yml": "_f_stylelint", | ||
| 3900 | "stylelint.config.ts": "_f_stylelint", | ||
| 3901 | "stylelint.config.cjs": "_f_stylelint", | ||
| 3902 | "stylelint.config.mjs": "_f_stylelint", | ||
| 3903 | ".stylelintrc.js": "_f_stylelint", | ||
| 3904 | ".stylelintrc.json": "_f_stylelint", | ||
| 3905 | ".stylelintrc.yaml": "_f_stylelint", | ||
| 3906 | ".stylelintrc.yml": "_f_stylelint", | ||
| 3907 | ".stylelintrc.ts": "_f_stylelint", | ||
| 3908 | ".stylelintrc.cjs": "_f_stylelint", | ||
| 3909 | ".stylelintrc.mjs": "_f_stylelint", | ||
| 3910 | ".stylish-haskell.yaml": "_f_stylish_haskell", | ||
| 3911 | ".svnignore": "_f_subversion", | ||
| 3912 | "svelte.config.js": "_f_svelteconfig", | ||
| 3913 | "svelte.config.ts": "_f_svelteconfig", | ||
| 3914 | "svgo.config.cjs": "_f_svgo", | ||
| 3915 | "svgo.config.js": "_f_svgo", | ||
| 3916 | "svgo.config.mjs": "_f_svgo", | ||
| 3917 | ".swcrc": "_f_swc", | ||
| 3918 | "package.pins": "_f_swift", | ||
| 3919 | "symfony.lock": "_f_symfony", | ||
| 3920 | ".syncpackrc": "_f_syncpack", | ||
| 3921 | ".syncpackrc.json": "_f_syncpack", | ||
| 3922 | ".syncpackrc.yaml": "_f_syncpack", | ||
| 3923 | ".syncpackrc.yml": "_f_syncpack", | ||
| 3924 | ".syncpackrc.js": "_f_syncpack", | ||
| 3925 | ".syncpackrc.cjs": "_f_syncpack", | ||
| 3926 | "syncpack.config.js": "_f_syncpack", | ||
| 3927 | "syncpack.config.cjs": "_f_syncpack", | ||
| 3928 | "tailwind.js": "_f_tailwind", | ||
| 3929 | "tailwind.cjs": "_f_tailwind", | ||
| 3930 | "tailwind.coffee": "_f_tailwind", | ||
| 3931 | "tailwind.ts": "_f_tailwind", | ||
| 3932 | "tailwind.json": "_f_tailwind", | ||
| 3933 | "tailwind.mjs": "_f_tailwind", | ||
| 3934 | "tailwind.config.js": "_f_tailwind", | ||
| 3935 | "tailwind.config.cjs": "_f_tailwind", | ||
| 3936 | "tailwind.config.coffee": "_f_tailwind", | ||
| 3937 | "tailwind.config.ts": "_f_tailwind", | ||
| 3938 | "tailwind.config.json": "_f_tailwind", | ||
| 3939 | "tailwind.config.mjs": "_f_tailwind", | ||
| 3940 | ".tailwind.js": "_f_tailwind", | ||
| 3941 | ".tailwind.cjs": "_f_tailwind", | ||
| 3942 | ".tailwind.coffee": "_f_tailwind", | ||
| 3943 | ".tailwind.ts": "_f_tailwind", | ||
| 3944 | ".tailwind.json": "_f_tailwind", | ||
| 3945 | ".tailwind.mjs": "_f_tailwind", | ||
| 3946 | ".tailwindrc.js": "_f_tailwind", | ||
| 3947 | ".tailwindrc.cjs": "_f_tailwind", | ||
| 3948 | ".tailwindrc.coffee": "_f_tailwind", | ||
| 3949 | ".tailwindrc.ts": "_f_tailwind", | ||
| 3950 | ".tailwindrc.json": "_f_tailwind", | ||
| 3951 | ".tailwindrc.mjs": "_f_tailwind", | ||
| 3952 | "tamagui.js": "_f_tamagui", | ||
| 3953 | "tamagui.mjs": "_f_tamagui", | ||
| 3954 | "tamagui.cjs": "_f_tamagui", | ||
| 3955 | "tamagui.ts": "_f_tamagui", | ||
| 3956 | "tamagui.mts": "_f_tamagui", | ||
| 3957 | "tamagui.cts": "_f_tamagui", | ||
| 3958 | "tamagui.config.js": "_f_tamagui", | ||
| 3959 | "tamagui.config.mjs": "_f_tamagui", | ||
| 3960 | "tamagui.config.cjs": "_f_tamagui", | ||
| 3961 | "tamagui.config.ts": "_f_tamagui", | ||
| 3962 | "tamagui.config.mts": "_f_tamagui", | ||
| 3963 | "tamagui.config.cts": "_f_tamagui", | ||
| 3964 | ".taplo.toml": "_f_taplo", | ||
| 3965 | "taplo.toml": "_f_taplo", | ||
| 3966 | "taskfile.yml": "_f_taskfile", | ||
| 3967 | "taskfile.yaml": "_f_taskfile", | ||
| 3968 | "taskfile.dist.yml": "_f_taskfile", | ||
| 3969 | "taskfile.dist.yaml": "_f_taskfile", | ||
| 3970 | "tauri.conf.json": "_f_tauri", | ||
| 3971 | ".taurignore": "_f_tauri", | ||
| 3972 | ".testcaferc.json": "_f_testcafe", | ||
| 3973 | "testplane.conf.ts": "_f_testplane", | ||
| 3974 | "testplane.conf.js": "_f_testplane", | ||
| 3975 | "testplane.conf.cts": "_f_testplane", | ||
| 3976 | "testplane.conf.cjs": "_f_testplane", | ||
| 3977 | "testplane.config.ts": "_f_testplane", | ||
| 3978 | "testplane.config.js": "_f_testplane", | ||
| 3979 | "testplane.config.cts": "_f_testplane", | ||
| 3980 | "testplane.config.cjs": "_f_testplane", | ||
| 3981 | ".tfignore": "_f_tfs", | ||
| 3982 | ".tiltignore": "_f_tiltfile", | ||
| 3983 | ".tmux.conf": "_f_tmux", | ||
| 3984 | "tox.ini": "_f_tox", | ||
| 3985 | ".travis.yml": "_f_travis", | ||
| 3986 | "truffle-config.js": "_f_truffle", | ||
| 3987 | "truffle-config.ts": "_f_truffle", | ||
| 3988 | "trunk.yaml": "_f_trunk", | ||
| 3989 | "tsconfig.json": "_f_tsconfig", | ||
| 3990 | "tsconfig.app.json": "_f_tsconfig", | ||
| 3991 | "tsconfig.base.json": "_f_tsconfig", | ||
| 3992 | "tsconfig.build.json": "_f_tsconfig", | ||
| 3993 | "tsconfig.cjs.json": "_f_tsconfig", | ||
| 3994 | "tsconfig.common.json": "_f_tsconfig", | ||
| 3995 | "tsconfig.debug.json": "_f_tsconfig", | ||
| 3996 | "tsconfig.dev.json": "_f_tsconfig", | ||
| 3997 | "tsconfig.development.json": "_f_tsconfig", | ||
| 3998 | "tsconfig.e2e.json": "_f_tsconfig", | ||
| 3999 | "tsconfig.eslint.json": "_f_tsconfig", | ||
| 4000 | "tsconfig.esm.json": "_f_tsconfig", | ||
| 4001 | "tsconfig.mjs.json": "_f_tsconfig", | ||
| 4002 | "tsconfig.node.json": "_f_tsconfig", | ||
| 4003 | "tsconfig.prod.json": "_f_tsconfig", | ||
| 4004 | "tsconfig.production.json": "_f_tsconfig", | ||
| 4005 | "tsconfig.release.json": "_f_tsconfig", | ||
| 4006 | "tsconfig.server.json": "_f_tsconfig", | ||
| 4007 | "tsconfig.spec.json": "_f_tsconfig", | ||
| 4008 | "tsconfig.staging.json": "_f_tsconfig", | ||
| 4009 | "tsconfig.test.json": "_f_tsconfig", | ||
| 4010 | "tsconfig.types.json": "_f_tsconfig", | ||
| 4011 | "tsconfig.lib.json": "_f_tsconfig", | ||
| 4012 | "tsconfig.lib.prod.json": "_f_tsconfig", | ||
| 4013 | "tsdoc.json": "_f_tsdoc", | ||
| 4014 | "tsdown.config.ts": "_f_tsdown", | ||
| 4015 | "tsdown.config.mts": "_f_tsdown", | ||
| 4016 | "tsdown.config.cts": "_f_tsdown", | ||
| 4017 | "tsdown.config.js": "_f_tsdown", | ||
| 4018 | "tsdown.config.mjs": "_f_tsdown", | ||
| 4019 | "tsdown.config.cjs": "_f_tsdown", | ||
| 4020 | "tsdown.config.json": "_f_tsdown", | ||
| 4021 | "tslint.json": "_f_tslint", | ||
| 4022 | "tslint.yaml": "_f_tslint", | ||
| 4023 | "tslint.yml": "_f_tslint", | ||
| 4024 | "turbo.json": "_f_turbo", | ||
| 4025 | "turbo.jsonc": "_f_turbo", | ||
| 4026 | "microfrontends.json": "_f_turbo", | ||
| 4027 | "microfrontends.jsonc": "_f_turbo", | ||
| 4028 | "typedoc.cjs": "_f_typedoc", | ||
| 4029 | "typedoc.js": "_f_typedoc", | ||
| 4030 | "typedoc.json": "_f_typedoc", | ||
| 4031 | "typedoc.jsonc": "_f_typedoc", | ||
| 4032 | "typedoc.mjs": "_f_typedoc", | ||
| 4033 | "typedoc.config.cjs": "_f_typedoc", | ||
| 4034 | "typedoc.config.js": "_f_typedoc", | ||
| 4035 | "typedoc.config.json": "_f_typedoc", | ||
| 4036 | "typedoc.config.jsonc": "_f_typedoc", | ||
| 4037 | "typedoc.config.mjs": "_f_typedoc", | ||
| 4038 | ".unibeautifyrc": "_f_unibeautify", | ||
| 4039 | "unibeautify.config.js": "_f_unibeautify", | ||
| 4040 | ".unibeautifyrc.js": "_f_unibeautify", | ||
| 4041 | ".unibeautifyrc.json": "_f_unibeautify", | ||
| 4042 | ".unibeautifyrc.yaml": "_f_unibeautify", | ||
| 4043 | ".unibeautifyrc.yml": "_f_unibeautify", | ||
| 4044 | "unlicense": "_f_unlicense", | ||
| 4045 | "unlicence": "_f_unlicense", | ||
| 4046 | "UNLICENSE": "_f_unlicense", | ||
| 4047 | "UNLICENCE": "_f_unlicense", | ||
| 4048 | "unlicense.md": "_f_unlicense", | ||
| 4049 | "unlicense.txt": "_f_unlicense", | ||
| 4050 | "unlicence.md": "_f_unlicense", | ||
| 4051 | "unlicence.txt": "_f_unlicense", | ||
| 4052 | "UNLICENSE.md": "_f_unlicense", | ||
| 4053 | "UNLICENSE.txt": "_f_unlicense", | ||
| 4054 | "UNLICENCE.md": "_f_unlicense", | ||
| 4055 | "UNLICENCE.txt": "_f_unlicense", | ||
| 4056 | "uno.config.js": "_f_unocss", | ||
| 4057 | "uno.config.mjs": "_f_unocss", | ||
| 4058 | "uno.config.ts": "_f_unocss", | ||
| 4059 | "uno.config.mts": "_f_unocss", | ||
| 4060 | "unocss.config.js": "_f_unocss", | ||
| 4061 | "unocss.config.mjs": "_f_unocss", | ||
| 4062 | "unocss.config.ts": "_f_unocss", | ||
| 4063 | "unocss.config.mts": "_f_unocss", | ||
| 4064 | "uv.lock": "_f_uv", | ||
| 4065 | "vagrantfile": "_f_vagrant", | ||
| 4066 | "vapor.yml": "_f_vapor", | ||
| 4067 | "now.json": "_f_vercel", | ||
| 4068 | ".nowignore": "_f_vercel", | ||
| 4069 | "vercel.json": "_f_vercel", | ||
| 4070 | ".vercelignore": "_f_vercel", | ||
| 4071 | ".vimrc": "_f_vim", | ||
| 4072 | ".gvimrc": "_f_vim", | ||
| 4073 | "vite.config.js": "_f_vite", | ||
| 4074 | "vite.config.mjs": "_f_vite", | ||
| 4075 | "vite.config.ts": "_f_vite", | ||
| 4076 | "vite.config.cjs": "_f_vite", | ||
| 4077 | "vite.config.mts": "_f_vite", | ||
| 4078 | "vite.config.cts": "_f_vite", | ||
| 4079 | "vitest.config.js": "_f_vitest", | ||
| 4080 | "vitest.config.mjs": "_f_vitest", | ||
| 4081 | "vitest.config.ts": "_f_vitest", | ||
| 4082 | "vitest.config.cjs": "_f_vitest", | ||
| 4083 | "vitest.config.mts": "_f_vitest", | ||
| 4084 | "vitest.config.cts": "_f_vitest", | ||
| 4085 | "vitest.workspace.json": "_f_vitest", | ||
| 4086 | "vitest.workspace.js": "_f_vitest", | ||
| 4087 | "vitest.workspace.mjs": "_f_vitest", | ||
| 4088 | "vitest.workspace.ts": "_f_vitest", | ||
| 4089 | "vitest.workspace.cjs": "_f_vitest", | ||
| 4090 | "vitest.workspace.mts": "_f_vitest", | ||
| 4091 | "vitest.workspace.cts": "_f_vitest", | ||
| 4092 | "vitest.projects.json": "_f_vitest", | ||
| 4093 | "vitest.projects.js": "_f_vitest", | ||
| 4094 | "vitest.projects.mjs": "_f_vitest", | ||
| 4095 | "vitest.projects.ts": "_f_vitest", | ||
| 4096 | "vitest.projects.cjs": "_f_vitest", | ||
| 4097 | "vitest.projects.mts": "_f_vitest", | ||
| 4098 | "vitest.projects.cts": "_f_vitest", | ||
| 4099 | ".vscodeignore": "_f_vscode", | ||
| 4100 | "launch.json": "_f_vscode", | ||
| 4101 | "tasks.json": "_f_vscode", | ||
| 4102 | "vscodeignore.json": "_f_vscode", | ||
| 4103 | ".vscode-test.js": "_f_vscode_test", | ||
| 4104 | ".vscode-test.json": "_f_vscode_test", | ||
| 4105 | ".vscode-test.mjs": "_f_vscode_test", | ||
| 4106 | ".vuerc": "_f_vueconfig", | ||
| 4107 | "vue.config.js": "_f_vueconfig", | ||
| 4108 | "vue.config.cjs": "_f_vueconfig", | ||
| 4109 | "vue.config.mjs": "_f_vueconfig", | ||
| 4110 | "wallaby.json": "_f_wallaby", | ||
| 4111 | "wallaby.js": "_f_wallaby", | ||
| 4112 | "wallaby.ts": "_f_wallaby", | ||
| 4113 | "wallaby.coffee": "_f_wallaby", | ||
| 4114 | "wallaby.conf.json": "_f_wallaby", | ||
| 4115 | "wallaby.conf.js": "_f_wallaby", | ||
| 4116 | "wallaby.conf.ts": "_f_wallaby", | ||
| 4117 | "wallaby.conf.coffee": "_f_wallaby", | ||
| 4118 | ".wallaby.json": "_f_wallaby", | ||
| 4119 | ".wallaby.js": "_f_wallaby", | ||
| 4120 | ".wallaby.ts": "_f_wallaby", | ||
| 4121 | ".wallaby.coffee": "_f_wallaby", | ||
| 4122 | ".wallaby.conf.json": "_f_wallaby", | ||
| 4123 | ".wallaby.conf.js": "_f_wallaby", | ||
| 4124 | ".wallaby.conf.ts": "_f_wallaby", | ||
| 4125 | ".wallaby.conf.coffee": "_f_wallaby", | ||
| 4126 | "wally.toml": "_f_wally", | ||
| 4127 | "wally.lock": "_f_wally", | ||
| 4128 | ".watchmanconfig": "_f_watchmanconfig", | ||
| 4129 | "wdio.json": "_f_wdio", | ||
| 4130 | "wdio.js": "_f_wdio", | ||
| 4131 | "wdio.mjs": "_f_wdio", | ||
| 4132 | "wdio.cjs": "_f_wdio", | ||
| 4133 | "wdio.ts": "_f_wdio", | ||
| 4134 | "wdio.mts": "_f_wdio", | ||
| 4135 | "wdio.cts": "_f_wdio", | ||
| 4136 | "wdio.conf.json": "_f_wdio", | ||
| 4137 | "wdio.conf.js": "_f_wdio", | ||
| 4138 | "wdio.conf.mjs": "_f_wdio", | ||
| 4139 | "wdio.conf.cjs": "_f_wdio", | ||
| 4140 | "wdio.conf.ts": "_f_wdio", | ||
| 4141 | "wdio.conf.mts": "_f_wdio", | ||
| 4142 | "wdio.conf.cts": "_f_wdio", | ||
| 4143 | ".weblate": "_f_weblate", | ||
| 4144 | ".weblate.ini": "_f_weblate", | ||
| 4145 | "weblate": "_f_weblate", | ||
| 4146 | "weblate.ini": "_f_weblate", | ||
| 4147 | "webpack.base.conf.js": "_f_webpack", | ||
| 4148 | "webpack.base.conf.cjs": "_f_webpack", | ||
| 4149 | "webpack.base.conf.mjs": "_f_webpack", | ||
| 4150 | "webpack.base.conf.coffee": "_f_webpack", | ||
| 4151 | "webpack.base.conf.ts": "_f_webpack", | ||
| 4152 | "webpack.common.js": "_f_webpack", | ||
| 4153 | "webpack.common.cjs": "_f_webpack", | ||
| 4154 | "webpack.common.mjs": "_f_webpack", | ||
| 4155 | "webpack.common.coffee": "_f_webpack", | ||
| 4156 | "webpack.common.ts": "_f_webpack", | ||
| 4157 | "webpack.config.js": "_f_webpack", | ||
| 4158 | "webpack.config.cjs": "_f_webpack", | ||
| 4159 | "webpack.config.mjs": "_f_webpack", | ||
| 4160 | "webpack.config.coffee": "_f_webpack", | ||
| 4161 | "webpack.config.ts": "_f_webpack", | ||
| 4162 | "webpack.config.base.js": "_f_webpack", | ||
| 4163 | "webpack.config.base.cjs": "_f_webpack", | ||
| 4164 | "webpack.config.base.mjs": "_f_webpack", | ||
| 4165 | "webpack.config.base.coffee": "_f_webpack", | ||
| 4166 | "webpack.config.base.ts": "_f_webpack", | ||
| 4167 | "webpack.config.build.js": "_f_webpack", | ||
| 4168 | "webpack.config.build.cjs": "_f_webpack", | ||
| 4169 | "webpack.config.build.mjs": "_f_webpack", | ||
| 4170 | "webpack.config.build.coffee": "_f_webpack", | ||
| 4171 | "webpack.config.build.ts": "_f_webpack", | ||
| 4172 | "webpack.config.common.js": "_f_webpack", | ||
| 4173 | "webpack.config.common.cjs": "_f_webpack", | ||
| 4174 | "webpack.config.common.mjs": "_f_webpack", | ||
| 4175 | "webpack.config.common.coffee": "_f_webpack", | ||
| 4176 | "webpack.config.common.ts": "_f_webpack", | ||
| 4177 | "webpack.config.dev.js": "_f_webpack", | ||
| 4178 | "webpack.config.dev.cjs": "_f_webpack", | ||
| 4179 | "webpack.config.dev.mjs": "_f_webpack", | ||
| 4180 | "webpack.config.dev.coffee": "_f_webpack", | ||
| 4181 | "webpack.config.dev.ts": "_f_webpack", | ||
| 4182 | "webpack.config.development.js": "_f_webpack", | ||
| 4183 | "webpack.config.development.cjs": "_f_webpack", | ||
| 4184 | "webpack.config.development.mjs": "_f_webpack", | ||
| 4185 | "webpack.config.development.coffee": "_f_webpack", | ||
| 4186 | "webpack.config.development.ts": "_f_webpack", | ||
| 4187 | "webpack.config.staging.js": "_f_webpack", | ||
| 4188 | "webpack.config.staging.cjs": "_f_webpack", | ||
| 4189 | "webpack.config.staging.mjs": "_f_webpack", | ||
| 4190 | "webpack.config.staging.coffee": "_f_webpack", | ||
| 4191 | "webpack.config.staging.ts": "_f_webpack", | ||
| 4192 | "webpack.config.test.js": "_f_webpack", | ||
| 4193 | "webpack.config.test.cjs": "_f_webpack", | ||
| 4194 | "webpack.config.test.mjs": "_f_webpack", | ||
| 4195 | "webpack.config.test.coffee": "_f_webpack", | ||
| 4196 | "webpack.config.test.ts": "_f_webpack", | ||
| 4197 | "webpack.config.prod.js": "_f_webpack", | ||
| 4198 | "webpack.config.prod.cjs": "_f_webpack", | ||
| 4199 | "webpack.config.prod.mjs": "_f_webpack", | ||
| 4200 | "webpack.config.prod.coffee": "_f_webpack", | ||
| 4201 | "webpack.config.prod.ts": "_f_webpack", | ||
| 4202 | "webpack.config.production.js": "_f_webpack", | ||
| 4203 | "webpack.config.production.cjs": "_f_webpack", | ||
| 4204 | "webpack.config.production.mjs": "_f_webpack", | ||
| 4205 | "webpack.config.production.coffee": "_f_webpack", | ||
| 4206 | "webpack.config.production.ts": "_f_webpack", | ||
| 4207 | "webpack.config.babel.js": "_f_webpack", | ||
| 4208 | "webpack.config.babel.cjs": "_f_webpack", | ||
| 4209 | "webpack.config.babel.mjs": "_f_webpack", | ||
| 4210 | "webpack.config.babel.coffee": "_f_webpack", | ||
| 4211 | "webpack.config.babel.ts": "_f_webpack", | ||
| 4212 | "webpack.config.base.babel.js": "_f_webpack", | ||
| 4213 | "webpack.config.base.babel.cjs": "_f_webpack", | ||
| 4214 | "webpack.config.base.babel.mjs": "_f_webpack", | ||
| 4215 | "webpack.config.base.babel.coffee": "_f_webpack", | ||
| 4216 | "webpack.config.base.babel.ts": "_f_webpack", | ||
| 4217 | "webpack.config.common.babel.js": "_f_webpack", | ||
| 4218 | "webpack.config.common.babel.cjs": "_f_webpack", | ||
| 4219 | "webpack.config.common.babel.mjs": "_f_webpack", | ||
| 4220 | "webpack.config.common.babel.coffee": "_f_webpack", | ||
| 4221 | "webpack.config.common.babel.ts": "_f_webpack", | ||
| 4222 | "webpack.config.dev.babel.js": "_f_webpack", | ||
| 4223 | "webpack.config.dev.babel.cjs": "_f_webpack", | ||
| 4224 | "webpack.config.dev.babel.mjs": "_f_webpack", | ||
| 4225 | "webpack.config.dev.babel.coffee": "_f_webpack", | ||
| 4226 | "webpack.config.dev.babel.ts": "_f_webpack", | ||
| 4227 | "webpack.config.development.babel.js": "_f_webpack", | ||
| 4228 | "webpack.config.development.babel.cjs": "_f_webpack", | ||
| 4229 | "webpack.config.development.babel.mjs": "_f_webpack", | ||
| 4230 | "webpack.config.development.babel.coffee": "_f_webpack", | ||
| 4231 | "webpack.config.development.babel.ts": "_f_webpack", | ||
| 4232 | "webpack.config.staging.babel.js": "_f_webpack", | ||
| 4233 | "webpack.config.staging.babel.cjs": "_f_webpack", | ||
| 4234 | "webpack.config.staging.babel.mjs": "_f_webpack", | ||
| 4235 | "webpack.config.staging.babel.coffee": "_f_webpack", | ||
| 4236 | "webpack.config.staging.babel.ts": "_f_webpack", | ||
| 4237 | "webpack.config.test.babel.js": "_f_webpack", | ||
| 4238 | "webpack.config.test.babel.cjs": "_f_webpack", | ||
| 4239 | "webpack.config.test.babel.mjs": "_f_webpack", | ||
| 4240 | "webpack.config.test.babel.coffee": "_f_webpack", | ||
| 4241 | "webpack.config.test.babel.ts": "_f_webpack", | ||
| 4242 | "webpack.config.prod.babel.js": "_f_webpack", | ||
| 4243 | "webpack.config.prod.babel.cjs": "_f_webpack", | ||
| 4244 | "webpack.config.prod.babel.mjs": "_f_webpack", | ||
| 4245 | "webpack.config.prod.babel.coffee": "_f_webpack", | ||
| 4246 | "webpack.config.prod.babel.ts": "_f_webpack", | ||
| 4247 | "webpack.config.production.babel.js": "_f_webpack", | ||
| 4248 | "webpack.config.production.babel.cjs": "_f_webpack", | ||
| 4249 | "webpack.config.production.babel.mjs": "_f_webpack", | ||
| 4250 | "webpack.config.production.babel.coffee": "_f_webpack", | ||
| 4251 | "webpack.config.production.babel.ts": "_f_webpack", | ||
| 4252 | "webpack.dev.js": "_f_webpack", | ||
| 4253 | "webpack.dev.cjs": "_f_webpack", | ||
| 4254 | "webpack.dev.mjs": "_f_webpack", | ||
| 4255 | "webpack.dev.coffee": "_f_webpack", | ||
| 4256 | "webpack.dev.ts": "_f_webpack", | ||
| 4257 | "webpack.dev.conf.js": "_f_webpack", | ||
| 4258 | "webpack.dev.conf.cjs": "_f_webpack", | ||
| 4259 | "webpack.dev.conf.mjs": "_f_webpack", | ||
| 4260 | "webpack.dev.conf.coffee": "_f_webpack", | ||
| 4261 | "webpack.dev.conf.ts": "_f_webpack", | ||
| 4262 | "webpack.local.js": "_f_webpack", | ||
| 4263 | "webpack.local.cjs": "_f_webpack", | ||
| 4264 | "webpack.local.mjs": "_f_webpack", | ||
| 4265 | "webpack.local.coffee": "_f_webpack", | ||
| 4266 | "webpack.local.ts": "_f_webpack", | ||
| 4267 | "webpack.prod.js": "_f_webpack", | ||
| 4268 | "webpack.prod.cjs": "_f_webpack", | ||
| 4269 | "webpack.prod.mjs": "_f_webpack", | ||
| 4270 | "webpack.prod.coffee": "_f_webpack", | ||
| 4271 | "webpack.prod.ts": "_f_webpack", | ||
| 4272 | "webpack.prod.conf.js": "_f_webpack", | ||
| 4273 | "webpack.prod.conf.cjs": "_f_webpack", | ||
| 4274 | "webpack.prod.conf.mjs": "_f_webpack", | ||
| 4275 | "webpack.prod.conf.coffee": "_f_webpack", | ||
| 4276 | "webpack.prod.conf.ts": "_f_webpack", | ||
| 4277 | "webpack.main.config.js": "_f_webpack", | ||
| 4278 | "webpack.main.config.cjs": "_f_webpack", | ||
| 4279 | "webpack.main.config.mjs": "_f_webpack", | ||
| 4280 | "webpack.main.config.coffee": "_f_webpack", | ||
| 4281 | "webpack.main.config.ts": "_f_webpack", | ||
| 4282 | "webpack.mix.js": "_f_webpack", | ||
| 4283 | "webpack.mix.cjs": "_f_webpack", | ||
| 4284 | "webpack.mix.mjs": "_f_webpack", | ||
| 4285 | "webpack.mix.coffee": "_f_webpack", | ||
| 4286 | "webpack.mix.ts": "_f_webpack", | ||
| 4287 | "webpack.plugins.js": "_f_webpack", | ||
| 4288 | "webpack.plugins.cjs": "_f_webpack", | ||
| 4289 | "webpack.plugins.mjs": "_f_webpack", | ||
| 4290 | "webpack.plugins.coffee": "_f_webpack", | ||
| 4291 | "webpack.plugins.ts": "_f_webpack", | ||
| 4292 | "webpack.renderer.config.js": "_f_webpack", | ||
| 4293 | "webpack.renderer.config.cjs": "_f_webpack", | ||
| 4294 | "webpack.renderer.config.mjs": "_f_webpack", | ||
| 4295 | "webpack.renderer.config.coffee": "_f_webpack", | ||
| 4296 | "webpack.renderer.config.ts": "_f_webpack", | ||
| 4297 | "webpack.rules.js": "_f_webpack", | ||
| 4298 | "webpack.rules.cjs": "_f_webpack", | ||
| 4299 | "webpack.rules.mjs": "_f_webpack", | ||
| 4300 | "webpack.rules.coffee": "_f_webpack", | ||
| 4301 | "webpack.rules.ts": "_f_webpack", | ||
| 4302 | "webpack.test.conf.js": "_f_webpack", | ||
| 4303 | "webpack.test.conf.cjs": "_f_webpack", | ||
| 4304 | "webpack.test.conf.mjs": "_f_webpack", | ||
| 4305 | "webpack.test.conf.coffee": "_f_webpack", | ||
| 4306 | "webpack.test.conf.ts": "_f_webpack", | ||
| 4307 | "wercker.yml": "_f_wercker", | ||
| 4308 | "windi.config.ts": "_f_windi", | ||
| 4309 | "windi.config.js": "_f_windi", | ||
| 4310 | "wpml-config.xml": "_f_wpml", | ||
| 4311 | "wxt.config.js": "_f_wxt", | ||
| 4312 | "wxt.config.cjs": "_f_wxt", | ||
| 4313 | "wxt.config.mjs": "_f_wxt", | ||
| 4314 | "wxt.config.ts": "_f_wxt", | ||
| 4315 | "wxt.config.cts": "_f_wxt", | ||
| 4316 | "wxt.config.mts": "_f_wxt", | ||
| 4317 | ".xo-config": "_f_xo", | ||
| 4318 | "xo.config.js": "_f_xo", | ||
| 4319 | "xo.config.cjs": "_f_xo", | ||
| 4320 | "xo.config.mjs": "_f_xo", | ||
| 4321 | "xo.config.ts": "_f_xo", | ||
| 4322 | "xo.config.cts": "_f_xo", | ||
| 4323 | "xo.config.mts": "_f_xo", | ||
| 4324 | ".xo-config.js": "_f_xo", | ||
| 4325 | ".xo-config.json": "_f_xo", | ||
| 4326 | ".xo-config.cjs": "_f_xo", | ||
| 4327 | ".xcompose": "_f_xorg", | ||
| 4328 | ".yamllint": "_f_yamllint", | ||
| 4329 | ".yaspellerrc": "_f_yandex", | ||
| 4330 | ".yaspeller.json": "_f_yandex", | ||
| 4331 | "yarn.lock": "_f_yarn", | ||
| 4332 | ".yarnrc": "_f_yarn", | ||
| 4333 | ".yarnrc.yml": "_f_yarn", | ||
| 4334 | ".yarnclean": "_f_yarn", | ||
| 4335 | ".yarn-integrity": "_f_yarn", | ||
| 4336 | ".yarn-metadata.json": "_f_yarn", | ||
| 4337 | ".yarn-state.yml": "_f_yarn", | ||
| 4338 | ".yarnignore": "_f_yarn", | ||
| 4339 | ".yo-rc.json": "_f_yeoman" | ||
| 4340 | }, | ||
| 4341 | "languageIds": { | ||
| 4342 | "actionscript": "_f_actionscript", | ||
| 4343 | "ada": "_f_ada", | ||
| 4344 | "advpl": "_f_advpl", | ||
| 4345 | "affectscript": "_f_affectscript", | ||
| 4346 | "agda": "_f_agda", | ||
| 4347 | "lagda-md": "_f_agda", | ||
| 4348 | "lagda-rst": "_f_agda", | ||
| 4349 | "lagda-tex": "_f_agda", | ||
| 4350 | "al": "_f_al", | ||
| 4351 | "alloy": "_f_alloy", | ||
| 4352 | "ansible": "_f_ansible", | ||
| 4353 | "antlr": "_f_antlr", | ||
| 4354 | "anyscript": "_f_anyscript", | ||
| 4355 | "apacheconf": "_f_apache", | ||
| 4356 | "apex": "_f_apex", | ||
| 4357 | "apiblueprint": "_f_apib", | ||
| 4358 | "apl": "_f_apl", | ||
| 4359 | "applescript": "_f_applescript", | ||
| 4360 | "asciidoc": "_f_asciidoc", | ||
| 4361 | "asp": "_f_asp", | ||
| 4362 | "asp (html)": "_f_asp", | ||
| 4363 | "arm": "_f_assembly", | ||
| 4364 | "asm": "_f_assembly", | ||
| 4365 | "asm-intel-x86-generic": "_f_assembly", | ||
| 4366 | "platformio-debug.asm": "_f_platformio", | ||
| 4367 | "asm-collection": "_f_assembly", | ||
| 4368 | "astro": "_f_astro", | ||
| 4369 | "ats": "_f_ats", | ||
| 4370 | "ahk": "_f_autohotkey", | ||
| 4371 | "ahk2": "_f_autohotkey", | ||
| 4372 | "autoit": "_f_autoit", | ||
| 4373 | "avro": "_f_avro", | ||
| 4374 | "azcli": "_f_azure", | ||
| 4375 | "azure-pipelines": "_f_azurepipelines", | ||
| 4376 | "ballerina": "_f_ballerina", | ||
| 4377 | "bat": "_f_bat", | ||
| 4378 | "bats": "_f_bats", | ||
| 4379 | "bazel": "_f_bazel", | ||
| 4380 | "bazelrc": "_f_bazel", | ||
| 4381 | "starlark": "_f_bazel", | ||
| 4382 | "befunge": "_f_befunge", | ||
| 4383 | "befunge98": "_f_befunge", | ||
| 4384 | "bicep": "_f_bicep", | ||
| 4385 | "biml": "_f_biml", | ||
| 4386 | "code-text-binary": "_f_binary", | ||
| 4387 | "biome_syntax_tree": "_f_biome", | ||
| 4388 | "blade": "_f_blade", | ||
| 4389 | "laravel-blade": "_f_blade", | ||
| 4390 | "blitzbasic": "_f_blitzbasic", | ||
| 4391 | "bolt": "_f_bolt", | ||
| 4392 | "bosque": "_f_bosque", | ||
| 4393 | "browserslist": "_f_browserslist", | ||
| 4394 | "bruno": "_f_bruno", | ||
| 4395 | "buf": "_f_buf", | ||
| 4396 | "buf-gen": "_f_buf", | ||
| 4397 | "bun.lockb": "_f_bun", | ||
| 4398 | "c": "_f_c", | ||
| 4399 | "c3": "_f_c3", | ||
| 4400 | "c-al": "_f_c_al", | ||
| 4401 | "cabal": "_f_cabal", | ||
| 4402 | "caddyfile": "_f_caddy", | ||
| 4403 | "capnp": "_f_capnp", | ||
| 4404 | "capnproto": "_f_capnp", | ||
| 4405 | "casc": "_f_casc", | ||
| 4406 | "cddl": "_f_cddl", | ||
| 4407 | "ceylon": "_f_ceylon", | ||
| 4408 | "cfml": "_f_cf", | ||
| 4409 | "lang-cfml": "_f_cf", | ||
| 4410 | "cfc": "_f_cfc", | ||
| 4411 | "cfmhtml": "_f_cfm", | ||
| 4412 | "cookbook": "_f_chef_cookbook", | ||
| 4413 | "circom": "_f_circom", | ||
| 4414 | "clojure": "_f_clojure", | ||
| 4415 | "clojurescript": "_f_clojurescript", | ||
| 4416 | "manifest-yaml": "_f_cloudfoundry", | ||
| 4417 | "cmake": "_f_cmake", | ||
| 4418 | "cmake-cache": "_f_cmake", | ||
| 4419 | "cobol": "_f_cobol", | ||
| 4420 | "ql": "_f_codeql", | ||
| 4421 | "coffeescript": "_f_coffeescript", | ||
| 4422 | "java-properties": "_f_config", | ||
| 4423 | "properties": "_f_config", | ||
| 4424 | "spring-boot-properties": "_f_config", | ||
| 4425 | "confluence": "_f_confluence", | ||
| 4426 | "instructions": "_f_copilot", | ||
| 4427 | "prompt": "_f_copilot", | ||
| 4428 | "cpp": "_f_cpp", | ||
| 4429 | "crystal": "_f_crystal", | ||
| 4430 | "csharp": "_f_csharp", | ||
| 4431 | "css": "_f_css", | ||
| 4432 | "cucumber": "_f_cucumber", | ||
| 4433 | "feature": "_f_cucumber", | ||
| 4434 | "cuda": "_f_cuda", | ||
| 4435 | "cuda-cpp": "_f_cuda", | ||
| 4436 | "cython": "_f_cython", | ||
| 4437 | "dal": "_f_dal", | ||
| 4438 | "dart": "_f_dartlang", | ||
| 4439 | "debian-changelog": "_f_debian", | ||
| 4440 | "debian-control": "_f_debian", | ||
| 4441 | "debian-copyright": "_f_debian", | ||
| 4442 | "debian-upstream-metadata": "_f_debian", | ||
| 4443 | "pascal": "_f_delphi", | ||
| 4444 | "objectpascal": "_f_delphi", | ||
| 4445 | "dhall": "_f_dhall", | ||
| 4446 | "diff": "_f_diff", | ||
| 4447 | "django-html": "_f_django", | ||
| 4448 | "django-txt": "_f_django", | ||
| 4449 | "d": "_f_dlang", | ||
| 4450 | "dscript": "_f_dlang", | ||
| 4451 | "dml": "_f_dlang", | ||
| 4452 | "diet": "_f_dlang", | ||
| 4453 | "dockerbake": "_f_docker", | ||
| 4454 | "dockercompose": "_f_docker", | ||
| 4455 | "dockerfile": "_f_docker", | ||
| 4456 | "dotenv": "_f_dotenv", | ||
| 4457 | "env": "_f_dotenv", | ||
| 4458 | "dotjs": "_f_dotjs", | ||
| 4459 | "doxygen": "_f_doxygen", | ||
| 4460 | "drawio": "_f_drawio", | ||
| 4461 | "drools": "_f_drools", | ||
| 4462 | "dtd": "_f_dtd", | ||
| 4463 | "dustjs": "_f_dustjs", | ||
| 4464 | "dylan": "_f_dylan", | ||
| 4465 | "dylan-lid": "_f_dylan", | ||
| 4466 | "earthfile": "_f_earthly", | ||
| 4467 | "edge": "_f_edge", | ||
| 4468 | "editorconfig": "_f_editorconfig", | ||
| 4469 | "eex": "_f_eex", | ||
| 4470 | "html-eex": "_f_eex", | ||
| 4471 | "es": "_f_elastic", | ||
| 4472 | "elixir": "_f_elixir", | ||
| 4473 | "elm": "_f_elm", | ||
| 4474 | "erb": "_f_erb", | ||
| 4475 | "html.erb": "_f_erb", | ||
| 4476 | "erlang": "_f_erlang", | ||
| 4477 | "esphome": "_f_esphome", | ||
| 4478 | "excel": "_f_excel", | ||
| 4479 | "falcon": "_f_falcon", | ||
| 4480 | "fql": "_f_fauna", | ||
| 4481 | "fortran": "_f_fortran", | ||
| 4482 | "fortran-modern": "_f_fortran", | ||
| 4483 | "FortranFreeForm": "_f_fortran", | ||
| 4484 | "FortranFixedForm": "_f_fortran", | ||
| 4485 | "fortran_fixed-form": "_f_fortran", | ||
| 4486 | "ftl": "_f_freemarker", | ||
| 4487 | "fsharp": "_f_fsharp", | ||
| 4488 | "fthtml": "_f_fthtml", | ||
| 4489 | "galen": "_f_galen", | ||
| 4490 | "gml-gms": "_f_gamemaker", | ||
| 4491 | "gml-gms2": "_f_gamemaker2", | ||
| 4492 | "gml-gm81": "_f_gamemaker81", | ||
| 4493 | "gcode": "_f_gcode", | ||
| 4494 | "gdscript": "_f_gdscript", | ||
| 4495 | "genstat": "_f_genstat", | ||
| 4496 | "git-commit": "_f_git", | ||
| 4497 | "git-rebase": "_f_git", | ||
| 4498 | "ignore": "_f_git", | ||
| 4499 | "gleam": "_f_gleam", | ||
| 4500 | "glimmer-js": "_f_glimmer", | ||
| 4501 | "glimmer-ts": "_f_glimmer", | ||
| 4502 | "glsl": "_f_glsl", | ||
| 4503 | "glyphs": "_f_glyphs", | ||
| 4504 | "automake": "_f_gnu", | ||
| 4505 | "m4": "_f_gnu", | ||
| 4506 | "makefile": "_f_gnu", | ||
| 4507 | "makefile2": "_f_gnu", | ||
| 4508 | "gnuplot": "_f_gnuplot", | ||
| 4509 | "go": "_f_go", | ||
| 4510 | "go.mod": "_f_go_package", | ||
| 4511 | "go.work": "_f_go_work", | ||
| 4512 | "goctl": "_f_goctl", | ||
| 4513 | "gradle-kotlin-dsl": "_f_gradle", | ||
| 4514 | "grain": "_f_grain", | ||
| 4515 | "graphql": "_f_graphql", | ||
| 4516 | "dot": "_f_graphviz", | ||
| 4517 | "grit": "_f_grit", | ||
| 4518 | "groovy": "_f_groovy", | ||
| 4519 | "haml": "_f_haml", | ||
| 4520 | "handlebars": "_f_handlebars", | ||
| 4521 | "harbour": "_f_harbour", | ||
| 4522 | "hcl": "_f_hashicorp", | ||
| 4523 | "haskell": "_f_haskell", | ||
| 4524 | "literate haskell": "_f_haskell", | ||
| 4525 | "haxe": "_f_haxe", | ||
| 4526 | "hxml": "_f_haxe", | ||
| 4527 | "Haxe AST dump": "_f_haxe", | ||
| 4528 | "helm": "_f_helm", | ||
| 4529 | "hjson": "_f_hjson", | ||
| 4530 | "hlsl": "_f_hlsl", | ||
| 4531 | "home-assistant": "_f_homeassistant", | ||
| 4532 | "hosts": "_f_host", | ||
| 4533 | "html": "_f_html", | ||
| 4534 | "http": "_f_http", | ||
| 4535 | "hunspell.aff": "_f_hunspell", | ||
| 4536 | "hunspell.dic": "_f_hunspell", | ||
| 4537 | "hy": "_f_hy", | ||
| 4538 | "hypr": "_f_hypr", | ||
| 4539 | "icl": "_f_icl", | ||
| 4540 | "imba": "_f_imba", | ||
| 4541 | "4GL": "_f_informix", | ||
| 4542 | "ini": "_f_ini", | ||
| 4543 | "ink": "_f_ink", | ||
| 4544 | "innosetup": "_f_innosetup", | ||
| 4545 | "io": "_f_io", | ||
| 4546 | "iodine": "_f_iodine", | ||
| 4547 | "janet": "_f_janet", | ||
| 4548 | "java": "_f_java", | ||
| 4549 | "jekyll": "_f_jekyll", | ||
| 4550 | "jenkins": "_f_jenkins", | ||
| 4551 | "declarative": "_f_jenkins", | ||
| 4552 | "jenkinsfile": "_f_jenkins", | ||
| 4553 | "jest-snapshot": "_f_jest_snapshot", | ||
| 4554 | "jinja": "_f_jinja", | ||
| 4555 | "jinja-java": "_f_jinja", | ||
| 4556 | "jinja-html": "_f_jinja", | ||
| 4557 | "jinja-xml": "_f_jinja", | ||
| 4558 | "jinja-css": "_f_jinja", | ||
| 4559 | "jinja-json": "_f_jinja", | ||
| 4560 | "jinja-md": "_f_jinja", | ||
| 4561 | "jinja-py": "_f_jinja", | ||
| 4562 | "jinja-rb": "_f_jinja", | ||
| 4563 | "jinja-js": "_f_jinja", | ||
| 4564 | "jinja-yaml": "_f_jinja", | ||
| 4565 | "jinja-toml": "_f_jinja", | ||
| 4566 | "jinja-latex": "_f_jinja", | ||
| 4567 | "jinja-lua": "_f_jinja", | ||
| 4568 | "jinja-properties": "_f_jinja", | ||
| 4569 | "jinja-shell": "_f_jinja", | ||
| 4570 | "jinja-dockerfile": "_f_jinja", | ||
| 4571 | "jinja-sql": "_f_jinja", | ||
| 4572 | "jinja-terraform": "_f_jinja", | ||
| 4573 | "jinja-nginx": "_f_jinja", | ||
| 4574 | "jinja-groovy": "_f_jinja", | ||
| 4575 | "jinja-systemd": "_f_jinja", | ||
| 4576 | "jinja-cpp": "_f_jinja", | ||
| 4577 | "javascript": "_f_js", | ||
| 4578 | "json": "_f_json", | ||
| 4579 | "json-tmlanguage": "_f_json", | ||
| 4580 | "jsonc": "_f_json", | ||
| 4581 | "jsonl": "_f_json", | ||
| 4582 | "json5": "_f_json5", | ||
| 4583 | "jsonnet": "_f_jsonnet", | ||
| 4584 | "julia": "_f_julia", | ||
| 4585 | "juliamarkdown": "_f_julia", | ||
| 4586 | "just": "_f_just", | ||
| 4587 | "k": "_f_k", | ||
| 4588 | "kivy": "_f_kivy", | ||
| 4589 | "kos": "_f_kos", | ||
| 4590 | "kotlin": "_f_kotlin", | ||
| 4591 | "kotlinscript": "_f_kotlin", | ||
| 4592 | "kusto": "_f_kusto", | ||
| 4593 | "lark": "_f_lark", | ||
| 4594 | "latino": "_f_latino", | ||
| 4595 | "lean4": "_f_lean", | ||
| 4596 | "lean4markdown": "_f_lean", | ||
| 4597 | "less": "_f_less", | ||
| 4598 | "lex": "_f_lex", | ||
| 4599 | "lilypond": "_f_lilypond", | ||
| 4600 | "lisp": "_f_lisp", | ||
| 4601 | "autolisp": "_f_lisp", | ||
| 4602 | "autolispdcl": "_f_lisp", | ||
| 4603 | "log": "_f_log", | ||
| 4604 | "lolcode": "_f_lolcode", | ||
| 4605 | "lsl": "_f_lsl", | ||
| 4606 | "lua": "_f_lua", | ||
| 4607 | "markdown": "_f_markdown", | ||
| 4608 | "marko": "_f_marko", | ||
| 4609 | "matlab": "_f_matlab", | ||
| 4610 | "maxscript": "_f_maxscript", | ||
| 4611 | "mel": "_f_maya", | ||
| 4612 | "mdx": "_f_mdx", | ||
| 4613 | "mediawiki": "_f_mediawiki", | ||
| 4614 | "mermaid": "_f_mermaid", | ||
| 4615 | "meson": "_f_meson", | ||
| 4616 | "metal": "_f_metal", | ||
| 4617 | "bc-mcfunction": "_f_minecraft", | ||
| 4618 | "bc-minecraft-language": "_f_minecraft", | ||
| 4619 | "bc-minecraft-molang": "_f_minecraft", | ||
| 4620 | "bc-minecraft-project": "_f_minecraft", | ||
| 4621 | "mcdoc": "_f_minecraft", | ||
| 4622 | "mcfunction": "_f_minecraft", | ||
| 4623 | "mcmeta": "_f_minecraft", | ||
| 4624 | "mcscript": "_f_minecraft", | ||
| 4625 | "minecraft-lang": "_f_minecraft", | ||
| 4626 | "options-txt": "_f_minecraft", | ||
| 4627 | "snbt": "_f_minecraft", | ||
| 4628 | "mv": "_f_mivascript", | ||
| 4629 | "mjml": "_f_mjml", | ||
| 4630 | "powerquery": "_f_mlang", | ||
| 4631 | "mojo": "_f_mojo", | ||
| 4632 | "mojolicious": "_f_mojolicious", | ||
| 4633 | "mongo": "_f_mongo", | ||
| 4634 | "mson": "_f_mson", | ||
| 4635 | "mvt": "_f_mvt", | ||
| 4636 | "mvtcss": "_f_mvtcss", | ||
| 4637 | "mvtjs": "_f_mvtjs", | ||
| 4638 | "nearley": "_f_nearly", | ||
| 4639 | "cypher": "_f_neo4j", | ||
| 4640 | "nginx": "_f_nginx", | ||
| 4641 | "nim": "_f_nim", | ||
| 4642 | "nimble": "_f_nimble", | ||
| 4643 | "nix": "_f_nix", | ||
| 4644 | "nsis": "_f_nsi", | ||
| 4645 | "nfl": "_f_nsi", | ||
| 4646 | "nsl": "_f_nsi", | ||
| 4647 | "bridlensis": "_f_nsi", | ||
| 4648 | "nunjucks": "_f_nunjucks", | ||
| 4649 | "nushell": "_f_nushell", | ||
| 4650 | "objective-c": "_f_objectivec", | ||
| 4651 | "objective-cpp": "_f_objectivecpp", | ||
| 4652 | "ocaml": "_f_ocaml", | ||
| 4653 | "ocamllex": "_f_ocaml", | ||
| 4654 | "menhir": "_f_ocaml", | ||
| 4655 | "ogone": "_f_ogone", | ||
| 4656 | "openhab": "_f_openHAB", | ||
| 4657 | "scad": "_f_openscad", | ||
| 4658 | "org": "_f_org", | ||
| 4659 | "pddl": "_f_pddl", | ||
| 4660 | "happenings": "_f_pddl_happenings", | ||
| 4661 | "plan": "_f_pddl_plan", | ||
| 4662 | "perl": "_f_perl", | ||
| 4663 | "perl6": "_f_perl6", | ||
| 4664 | "pgsql": "_f_pgsql", | ||
| 4665 | "php": "_f_php", | ||
| 4666 | "pine": "_f_pine", | ||
| 4667 | "pinescript": "_f_pine", | ||
| 4668 | "pip-requirements": "_f_pip", | ||
| 4669 | "platformio-debug.disassembly": "_f_platformio", | ||
| 4670 | "platformio-debug.memoryview": "_f_platformio", | ||
| 4671 | "plsql": "_f_plsql", | ||
| 4672 | "oracle": "_f_plsql", | ||
| 4673 | "oraclesql": "_f_plsql", | ||
| 4674 | "oracle-sql": "_f_plsql", | ||
| 4675 | "po": "_f_poedit", | ||
| 4676 | "polyglot-notebook": "_f_polyglot", | ||
| 4677 | "polymer": "_f_polymer", | ||
| 4678 | "pony": "_f_pony", | ||
| 4679 | "postcss": "_f_postcss", | ||
| 4680 | "postscript": "_f_postscript", | ||
| 4681 | "powershell": "_f_powershell", | ||
| 4682 | "prisma": "_f_prisma", | ||
| 4683 | "pde": "_f_processinglang", | ||
| 4684 | "abl": "_f_progress", | ||
| 4685 | "prolog": "_f_prolog", | ||
| 4686 | "prometheus": "_f_prometheus", | ||
| 4687 | "proto3": "_f_protobuf", | ||
| 4688 | "proto": "_f_protobuf", | ||
| 4689 | "prototext": "_f_protobuf", | ||
| 4690 | "jade": "_f_pug", | ||
| 4691 | "puppet": "_f_puppet", | ||
| 4692 | "purescript": "_f_purescript", | ||
| 4693 | "pyret": "_f_pyret", | ||
| 4694 | "pyscript": "_f_pyscript", | ||
| 4695 | "python": "_f_python", | ||
| 4696 | "pythowo": "_f_pythowo", | ||
| 4697 | "qlik": "_f_qlikview", | ||
| 4698 | "qml": "_f_qml", | ||
| 4699 | "qsharp": "_f_qsharp", | ||
| 4700 | "r": "_f_r", | ||
| 4701 | "ra_syntax_tree": "_f_ra_syntax_tree", | ||
| 4702 | "racket": "_f_racket", | ||
| 4703 | "raku": "_f_raku", | ||
| 4704 | "raml": "_f_raml", | ||
| 4705 | "razor": "_f_razor", | ||
| 4706 | "aspnetcorerazor": "_f_razor", | ||
| 4707 | "javascriptreact": "_f_reactjs", | ||
| 4708 | "typescriptreact": "_f_reactts", | ||
| 4709 | "reason": "_f_reason", | ||
| 4710 | "red": "_f_red", | ||
| 4711 | "rescript": "_f_rescript", | ||
| 4712 | "restructuredtext": "_f_rest", | ||
| 4713 | "rexx": "_f_rexx", | ||
| 4714 | "riot": "_f_riot", | ||
| 4715 | "ripple": "_f_ripple", | ||
| 4716 | "rmd": "_f_rmd", | ||
| 4717 | "rnc": "_f_rnc", | ||
| 4718 | "robot": "_f_robotframework", | ||
| 4719 | "robots-txt": "_f_robots", | ||
| 4720 | "ruby": "_f_ruby", | ||
| 4721 | "rust": "_f_rust", | ||
| 4722 | "s-lang": "_f_s-lang", | ||
| 4723 | "san": "_f_san", | ||
| 4724 | "SAS": "_f_sas", | ||
| 4725 | "sass": "_f_sass", | ||
| 4726 | "sass.hover": "_f_sass", | ||
| 4727 | "sbt": "_f_sbt", | ||
| 4728 | "scala": "_f_scala", | ||
| 4729 | "scilab": "_f_scilab", | ||
| 4730 | "vbscript": "_f_script", | ||
| 4731 | "scss": "_f_scss", | ||
| 4732 | "sdl": "_f_sdlang", | ||
| 4733 | "search-result": "_f_search_result", | ||
| 4734 | "shaderlab": "_f_shaderlab", | ||
| 4735 | "shellscript": "_f_shell", | ||
| 4736 | "silverstripe": "_f_silverstripe", | ||
| 4737 | "sino": "_f_sino", | ||
| 4738 | "eskip": "_f_skipper", | ||
| 4739 | "slang": "_f_slang", | ||
| 4740 | "slice": "_f_slice", | ||
| 4741 | "slim": "_f_slim", | ||
| 4742 | "slint": "_f_slint", | ||
| 4743 | "sln": "_f_sln", | ||
| 4744 | "smarty": "_f_smarty", | ||
| 4745 | "snakemake": "_f_snakemake", | ||
| 4746 | "snort": "_f_snort", | ||
| 4747 | "solidity": "_f_solidity", | ||
| 4748 | "sparql": "_f_sparql", | ||
| 4749 | "sqf": "_f_sqf", | ||
| 4750 | "sql": "_f_sql", | ||
| 4751 | "squirrel": "_f_squirrel", | ||
| 4752 | "stan": "_f_stan", | ||
| 4753 | "stata": "_f_stata", | ||
| 4754 | "stencil": "_f_stencil", | ||
| 4755 | "stencil-html": "_f_stencil", | ||
| 4756 | "stylable": "_f_stylable", | ||
| 4757 | "source.css.styled": "_f_styled", | ||
| 4758 | "stylus": "_f_stylus", | ||
| 4759 | "svelte": "_f_svelte", | ||
| 4760 | "svg": "_f_svg", | ||
| 4761 | "Swagger": "_f_swagger", | ||
| 4762 | "swagger": "_f_swagger", | ||
| 4763 | "swift": "_f_swift", | ||
| 4764 | "swig": "_f_swig", | ||
| 4765 | "systemd-conf": "_f_systemd", | ||
| 4766 | "systemd-unit-file": "_f_systemd", | ||
| 4767 | "systemverilog": "_f_systemverilog", | ||
| 4768 | "t4": "_f_t4tt", | ||
| 4769 | "tailwindcss": "_f_tailwind", | ||
| 4770 | "teal": "_f_teal", | ||
| 4771 | "templ": "_f_templ", | ||
| 4772 | "tera": "_f_tera", | ||
| 4773 | "terraform": "_f_terraform", | ||
| 4774 | "tex": "_f_tex", | ||
| 4775 | "latex": "_f_tex", | ||
| 4776 | "bibtex": "_f_tex", | ||
| 4777 | "doctex": "_f_tex", | ||
| 4778 | "csv": "_f_text", | ||
| 4779 | "csv (pipe)": "_f_text", | ||
| 4780 | "csv (semicolon)": "_f_text", | ||
| 4781 | "csv (whitespace)": "_f_text", | ||
| 4782 | "dynamic csv": "_f_text", | ||
| 4783 | "tsv": "_f_text", | ||
| 4784 | "plaintext": "_f_text", | ||
| 4785 | "vim-help": "_f_text", | ||
| 4786 | "textile": "_f_textile", | ||
| 4787 | "tiltfile": "_f_tiltfile", | ||
| 4788 | "toit": "_f_toit", | ||
| 4789 | "toml": "_f_toml", | ||
| 4790 | "toon": "_f_toon", | ||
| 4791 | "tt": "_f_tt", | ||
| 4792 | "ttcn": "_f_ttcn", | ||
| 4793 | "tuc": "_f_tuc", | ||
| 4794 | "twig": "_f_twig", | ||
| 4795 | "typescript": "_f_typescript", | ||
| 4796 | "typoscript": "_f_typo3", | ||
| 4797 | "uiua": "_f_uiua", | ||
| 4798 | "unison": "_f_unison", | ||
| 4799 | "vb": "_f_vb", | ||
| 4800 | "vba": "_f_vba", | ||
| 4801 | "velocity": "_f_velocity", | ||
| 4802 | "vento": "_f_vento", | ||
| 4803 | "verilog": "_f_verilog", | ||
| 4804 | "vhdl": "_f_vhdl", | ||
| 4805 | "viml": "_f_vim", | ||
| 4806 | "vim-snippet": "_f_vim", | ||
| 4807 | "vitest-snapshot": "_f_vitest", | ||
| 4808 | "v": "_f_vlang", | ||
| 4809 | "volt": "_f_volt", | ||
| 4810 | "vroom": "_f_vroom", | ||
| 4811 | "snippets": "_f_vscode", | ||
| 4812 | "vue": "_f_vue", | ||
| 4813 | "vyper": "_f_vyper", | ||
| 4814 | "wasm": "_f_wasm", | ||
| 4815 | "wat": "_f_wasm", | ||
| 4816 | "wenyan": "_f_wenyan", | ||
| 4817 | "wgsl": "_f_wgsl", | ||
| 4818 | "wikitext": "_f_wikitext", | ||
| 4819 | "wai": "_f_wit", | ||
| 4820 | "wolfram": "_f_wolfram", | ||
| 4821 | "wurstlang": "_f_wurst", | ||
| 4822 | "wurst": "_f_wurst", | ||
| 4823 | "xmake": "_f_xmake", | ||
| 4824 | "xml": "_f_xml", | ||
| 4825 | "xcompose": "_f_xorg", | ||
| 4826 | "xquery": "_f_xquery", | ||
| 4827 | "xsl": "_f_xsl", | ||
| 4828 | "xslt": "_f_xsl", | ||
| 4829 | "yacc": "_f_yacc", | ||
| 4830 | "yaml": "_f_yaml", | ||
| 4831 | "yaml-tmlanguage": "_f_yaml", | ||
| 4832 | "spring-boot-properties-yaml": "_f_yaml", | ||
| 4833 | "yang": "_f_yang", | ||
| 4834 | "yarnlock": "_f_yarn", | ||
| 4835 | "zig": "_f_zig", | ||
| 4836 | "zip": "_f_zip" | ||
| 4837 | }, | ||
| 4838 | "light": { | ||
| 4839 | "file": "_file_light", | ||
| 4840 | "folder": "_folder_light", | ||
| 4841 | "folderExpanded": "_folder_light_open", | ||
| 4842 | "rootFolder": "_root_folder_light", | ||
| 4843 | "rootFolderExpanded": "_root_folder_light_open", | ||
| 4844 | "folderNames": { | ||
| 4845 | "android": "_fd_android", | ||
| 4846 | ".angular": "_fd_angular", | ||
| 4847 | "apache": "_fd_apache", | ||
| 4848 | "apache2": "_fd_apache", | ||
| 4849 | "httpd": "_fd_apache", | ||
| 4850 | "api": "_fd_api", | ||
| 4851 | ".api": "_fd_api", | ||
| 4852 | "apis": "_fd_api", | ||
| 4853 | ".apis": "_fd_api", | ||
| 4854 | "app": "_fd_app", | ||
| 4855 | "apps": "_fd_app", | ||
| 4856 | ".app": "_fd_app", | ||
| 4857 | "application": "_fd_app", | ||
| 4858 | "applications": "_fd_app", | ||
| 4859 | "arangodb": "_fd_arangodb", | ||
| 4860 | "arango": "_fd_arangodb", | ||
| 4861 | "assets": "_fd_asset", | ||
| 4862 | ".assets": "_fd_asset", | ||
| 4863 | ".astro": "_fd_astro", | ||
| 4864 | "audio": "_fd_audio", | ||
| 4865 | ".audio": "_fd_audio", | ||
| 4866 | "audios": "_fd_audio", | ||
| 4867 | ".audios": "_fd_audio", | ||
| 4868 | "sound": "_fd_audio", | ||
| 4869 | ".sound": "_fd_audio", | ||
| 4870 | "sounds": "_fd_audio", | ||
| 4871 | ".sounds": "_fd_audio", | ||
| 4872 | "aurelia_project": "_fd_aurelia", | ||
| 4873 | "aws": "_fd_aws", | ||
| 4874 | ".aws": "_fd_aws", | ||
| 4875 | "azure": "_fd_azure", | ||
| 4876 | ".azure": "_fd_azure", | ||
| 4877 | "azure-pipelines": "_fd_azurepipelines", | ||
| 4878 | ".azure-pipelines": "_fd_azurepipelines", | ||
| 4879 | "bin": "_fd_binary", | ||
| 4880 | ".bin": "_fd_binary", | ||
| 4881 | "blocs": "_fd_bloc", | ||
| 4882 | "bloc": "_fd_bloc", | ||
| 4883 | "blueprint": "_fd_blueprint", | ||
| 4884 | ".blueprint": "_fd_blueprint", | ||
| 4885 | "blueprints": "_fd_blueprint", | ||
| 4886 | ".blueprints": "_fd_blueprint", | ||
| 4887 | "bot": "_fd_bot", | ||
| 4888 | ".bot": "_fd_bot", | ||
| 4889 | "bower_components": "_fd_bower", | ||
| 4890 | ".buildkite": "_fd_buildkite", | ||
| 4891 | "cake": "_fd_cake", | ||
| 4892 | ".cake": "_fd_cake", | ||
| 4893 | "cargo": "_fd_cargo", | ||
| 4894 | ".cargo": "_fd_cargo", | ||
| 4895 | "crates": "_fd_cargo", | ||
| 4896 | "certificates": "_fd_certificate", | ||
| 4897 | ".certificates": "_fd_certificate", | ||
| 4898 | "certs": "_fd_certificate", | ||
| 4899 | "certs.": "_fd_certificate", | ||
| 4900 | ".changeset": "_fd_changesets", | ||
| 4901 | "chef": "_fd_chef", | ||
| 4902 | ".chef": "_fd_chef", | ||
| 4903 | ".circleci": "_fd_circleci", | ||
| 4904 | ".claude": "_fd_claude", | ||
| 4905 | "cli": "_fd_cli", | ||
| 4906 | "cmd": "_fd_cli", | ||
| 4907 | "command": "_fd_cli", | ||
| 4908 | "commands": "_fd_cli", | ||
| 4909 | "commandline": "_fd_cli", | ||
| 4910 | "console": "_fd_cli", | ||
| 4911 | "client": "_fd_client", | ||
| 4912 | "clients": "_fd_client", | ||
| 4913 | ".cloudflare": "_fd_cloudflare", | ||
| 4914 | "cloudflare": "_fd_cloudflare", | ||
| 4915 | ".cmake": "_fd_cmake", | ||
| 4916 | "cmake": "_fd_cmake", | ||
| 4917 | "common": "_fd_common", | ||
| 4918 | "component": "_fd_component", | ||
| 4919 | "components": "_fd_component", | ||
| 4920 | ".components": "_fd_component", | ||
| 4921 | "gui": "_fd_component", | ||
| 4922 | "src-ui": "_fd_component", | ||
| 4923 | "ui": "_fd_component", | ||
| 4924 | "widgets": "_fd_component", | ||
| 4925 | "composer": "_fd_composer", | ||
| 4926 | ".composer": "_fd_composer", | ||
| 4927 | "conf": "_fd_config", | ||
| 4928 | ".conf": "_fd_config", | ||
| 4929 | "config": "_fd_config", | ||
| 4930 | ".config": "_fd_config", | ||
| 4931 | "configs": "_fd_config", | ||
| 4932 | ".configs": "_fd_config", | ||
| 4933 | "configuration": "_fd_config", | ||
| 4934 | ".configuration": "_fd_config", | ||
| 4935 | "configurations": "_fd_config", | ||
| 4936 | ".configurations": "_fd_config", | ||
| 4937 | "setting": "_fd_config", | ||
| 4938 | ".setting": "_fd_config", | ||
| 4939 | "settings": "_fd_config", | ||
| 4940 | ".settings": "_fd_config", | ||
| 4941 | "ini": "_fd_config", | ||
| 4942 | ".ini": "_fd_config", | ||
| 4943 | "initializers": "_fd_config", | ||
| 4944 | ".initializers": "_fd_config", | ||
| 4945 | "__controller__": "_fd_controller", | ||
| 4946 | "__controllers__": "_fd_controller", | ||
| 4947 | "controller": "_fd_controller", | ||
| 4948 | "controllers": "_fd_controller", | ||
| 4949 | ".controllers": "_fd_controller", | ||
| 4950 | "__handler__": "_fd_controller", | ||
| 4951 | "__handlers__": "_fd_controller", | ||
| 4952 | "handler": "_fd_controller", | ||
| 4953 | ".handler": "_fd_controller", | ||
| 4954 | "handlers": "_fd_controller", | ||
| 4955 | ".handlers": "_fd_controller", | ||
| 4956 | "coverage": "_fd_coverage", | ||
| 4957 | "css": "_fd_css", | ||
| 4958 | "_css": "_fd_css", | ||
| 4959 | "cubits": "_fd_cubit", | ||
| 4960 | "cubit": "_fd_cubit", | ||
| 4961 | ".cursor": "_fd_light_cursor", | ||
| 4962 | "cypress": "_fd_light_cypress", | ||
| 4963 | ".dapr": "_fd_dapr", | ||
| 4964 | "dapr": "_fd_dapr", | ||
| 4965 | "dart": "_fd_dart", | ||
| 4966 | ".dart_tool": "_fd_dart", | ||
| 4967 | "datadog": "_fd_datadog", | ||
| 4968 | ".datadog": "_fd_datadog", | ||
| 4969 | "db": "_fd_db", | ||
| 4970 | "database": "_fd_db", | ||
| 4971 | "sql": "_fd_db", | ||
| 4972 | "data": "_fd_db", | ||
| 4973 | "repo": "_fd_db", | ||
| 4974 | "repository": "_fd_db", | ||
| 4975 | "repositories": "_fd_db", | ||
| 4976 | "store": "_fd_db", | ||
| 4977 | "stores": "_fd_db", | ||
| 4978 | "debian": "_fd_debian", | ||
| 4979 | "deb": "_fd_debian", | ||
| 4980 | ".dependabot": "_fd_dependabot", | ||
| 4981 | ".devcontainer": "_fd_devcontainer", | ||
| 4982 | "dist": "_fd_dist", | ||
| 4983 | ".dist": "_fd_dist", | ||
| 4984 | "dists": "_fd_dist", | ||
| 4985 | "out": "_fd_dist", | ||
| 4986 | "outs": "_fd_dist", | ||
| 4987 | "export": "_fd_dist", | ||
| 4988 | "exports": "_fd_dist", | ||
| 4989 | "build": "_fd_dist", | ||
| 4990 | ".build": "_fd_dist", | ||
| 4991 | "builds": "_fd_dist", | ||
| 4992 | "release": "_fd_dist", | ||
| 4993 | "releases": "_fd_dist", | ||
| 4994 | "target": "_fd_dist", | ||
| 4995 | "targets": "_fd_dist", | ||
| 4996 | "docker": "_fd_docker", | ||
| 4997 | ".docker": "_fd_docker", | ||
| 4998 | "docs": "_fd_docs", | ||
| 4999 | "doc": "_fd_docs", | ||
3352 more lines aren’t shown here.
| @@ -1,52 +0,0 @@ | |||
| 1 | import { assert, describe, it } from "vite-plus/test"; | ||
| 2 | |||
| 3 | import { getVscodeIconUrlForEntry } from "./vscode-icons"; | ||
| 4 | |||
| 5 | describe("getVscodeIconUrlForEntry", () => { | ||
| 6 | it("uses exact filename matches from the vscode-icons manifest", () => { | ||
| 7 | const darkUrl = getVscodeIconUrlForEntry("pnpm-workspace.yaml", "file", "dark"); | ||
| 8 | const lightUrl = getVscodeIconUrlForEntry("pnpm-workspace.yaml", "file", "light"); | ||
| 9 | |||
| 10 | assert.isTrue(darkUrl.endsWith("/file_type_pnpm.svg")); | ||
| 11 | assert.isTrue(lightUrl.endsWith("/file_type_light_pnpm.svg")); | ||
| 12 | }); | ||
| 13 | |||
| 14 | it("uses longest extension match for compound extensions", () => { | ||
| 15 | const iconUrl = getVscodeIconUrlForEntry("tsconfig.tsbuildinfo", "file", "dark"); | ||
| 16 | const manifestStyleUrl = getVscodeIconUrlForEntry("buf.yaml", "file", "dark"); | ||
| 17 | assert.isTrue(iconUrl.endsWith("/file_type_tsbuildinfo.svg")); | ||
| 18 | assert.isTrue(manifestStyleUrl.endsWith("/file_type_buf.svg")); | ||
| 19 | }); | ||
| 20 | |||
| 21 | it("uses folder mappings and light-aware filename mappings", () => { | ||
| 22 | const folderUrl = getVscodeIconUrlForEntry("packages/src", "directory", "light"); | ||
| 23 | const fileUrl = getVscodeIconUrlForEntry("AGENTS.md", "file", "light"); | ||
| 24 | |||
| 25 | assert.isTrue(folderUrl.endsWith("/folder_type_src.svg")); | ||
| 26 | assert.isTrue(fileUrl.endsWith("/file_type_light_agents.svg")); | ||
| 27 | }); | ||
| 28 | |||
| 29 | it("falls back to language-based mappings for path-only cases", () => { | ||
| 30 | const tsxUrl = getVscodeIconUrlForEntry("checkbox.tsx", "file", "light"); | ||
| 31 | const dockerfileUrl = getVscodeIconUrlForEntry("Dockerfile", "file", "dark"); | ||
| 32 | const shellUrl = getVscodeIconUrlForEntry("entrypoint.sh", "file", "dark"); | ||
| 33 | const htmlUrl = getVscodeIconUrlForEntry("index.html", "file", "dark"); | ||
| 34 | const cursorRulesUrl = getVscodeIconUrlForEntry("general.mdc", "file", "dark"); | ||
| 35 | const githubWorkflowUrl = getVscodeIconUrlForEntry(".github/workflows/ci.yml", "file", "light"); | ||
| 36 | |||
| 37 | assert.isTrue(tsxUrl.endsWith("/file_type_reactts.svg")); | ||
| 38 | assert.isTrue(dockerfileUrl.endsWith("/file_type_docker.svg")); | ||
| 39 | assert.isTrue(shellUrl.endsWith("/file_type_shell.svg")); | ||
| 40 | assert.isTrue(htmlUrl.endsWith("/file_type_html.svg")); | ||
| 41 | assert.isTrue(cursorRulesUrl.endsWith("/file_type_markdown.svg")); | ||
| 42 | assert.isTrue(githubWorkflowUrl.endsWith("/file_type_light_yaml.svg")); | ||
| 43 | }); | ||
| 44 | |||
| 45 | it("falls back to defaults when there is no match", () => { | ||
| 46 | const fileUrl = getVscodeIconUrlForEntry("foo.unknown-ext", "file", "dark"); | ||
| 47 | const folderUrl = getVscodeIconUrlForEntry("totally-unknown-folder", "directory", "dark"); | ||
| 48 | |||
| 49 | assert.isTrue(fileUrl.endsWith("/default_file.svg")); | ||
| 50 | assert.isTrue(folderUrl.endsWith("/default_folder.svg")); | ||
| 51 | }); | ||
| 52 | }); | ||
| @@ -1,211 +0,0 @@ | |||
| 1 | import vscodeIconsManifest from "./vscode-icons-manifest.json"; | ||
| 2 | import languageAssociationsData from "./vscode-icons-language-associations.json"; | ||
| 3 | |||
| 4 | const VSCODE_ICONS_VERSION = "v12.17.0"; | ||
| 5 | const VSCODE_ICONS_BASE_URL = `https://cdn.jsdelivr.net/gh/vscode-icons/vscode-icons@${VSCODE_ICONS_VERSION}/icons`; | ||
| 6 | |||
| 7 | interface IconDefinition { | ||
| 8 | iconPath: string; | ||
| 9 | } | ||
| 10 | |||
| 11 | interface IconLookupSection { | ||
| 12 | file?: string; | ||
| 13 | folder?: string; | ||
| 14 | fileNames: Record<string, string>; | ||
| 15 | fileExtensions: Record<string, string>; | ||
| 16 | folderNames: Record<string, string>; | ||
| 17 | languageIds?: Record<string, string>; | ||
| 18 | } | ||
| 19 | |||
| 20 | interface VscodeIconsManifest extends IconLookupSection { | ||
| 21 | iconDefinitions: Record<string, IconDefinition>; | ||
| 22 | light: IconLookupSection; | ||
| 23 | } | ||
| 24 | |||
| 25 | interface LanguageAssociations { | ||
| 26 | version: string; | ||
| 27 | extensionToLanguageId: Record<string, string>; | ||
| 28 | fileNameToLanguageId: Record<string, string>; | ||
| 29 | } | ||
| 30 | |||
| 31 | const manifest = vscodeIconsManifest as VscodeIconsManifest; | ||
| 32 | const languageAssociations = languageAssociationsData as LanguageAssociations; | ||
| 33 | const iconDefinitions = manifest.iconDefinitions; | ||
| 34 | |||
| 35 | const darkFileNames = toLowercaseLookup(manifest.fileNames); | ||
| 36 | const lightFileNames = toLowercaseLookup(manifest.light.fileNames); | ||
| 37 | const darkFileExtensions = toLowercaseLookup(manifest.fileExtensions); | ||
| 38 | const lightFileExtensions = toLowercaseLookup(manifest.light.fileExtensions); | ||
| 39 | const darkFolderNames = toLowercaseLookup(manifest.folderNames); | ||
| 40 | const lightFolderNames = toLowercaseLookup(manifest.light.folderNames); | ||
| 41 | const darkLanguageIds = toLowercaseLookup(manifest.languageIds ?? {}); | ||
| 42 | const lightLanguageIds = toLowercaseLookup(manifest.light.languageIds ?? {}); | ||
| 43 | const languageIdByExtension = toLowercaseLookup(languageAssociations.extensionToLanguageId); | ||
| 44 | const languageIdByFileName = toLowercaseLookup(languageAssociations.fileNameToLanguageId); | ||
| 45 | const localLanguageIdByExtensionOverrides = { | ||
| 46 | // Cursor rules files (*.mdc) are commonly treated as markdown in VSCode/Cursor. | ||
| 47 | mdc: "markdown", | ||
| 48 | // Upstream languages.ts currently maps .html to django-html before html. | ||
| 49 | // Prefer the base HTML icon for standalone HTML files. | ||
| 50 | html: "html", | ||
| 51 | // Upstream languages.ts maps yml/yaml to specialized language ids that can produce | ||
| 52 | // non-generic YAML icons (for example cloudfoundry/esphome). Prefer the base YAML icon | ||
| 53 | // unless a more specific basename/extension match (e.g. azure-pipelines.yml) is found. | ||
| 54 | yml: "yaml", | ||
| 55 | yaml: "yaml", | ||
| 56 | } as const; | ||
| 57 | |||
| 58 | const defaultDarkFileIconDefinition = manifest.file ?? "_file"; | ||
| 59 | const defaultLightFileIconDefinition = manifest.light.file ?? defaultDarkFileIconDefinition; | ||
| 60 | const defaultDarkFolderIconDefinition = manifest.folder ?? "_folder"; | ||
| 61 | const defaultLightFolderIconDefinition = manifest.light.folder ?? defaultDarkFolderIconDefinition; | ||
| 62 | |||
| 63 | function toLowercaseLookup(source: Record<string, string>): Record<string, string> { | ||
| 64 | const entries = Object.entries(source); | ||
| 65 | const lookup: Record<string, string> = {}; | ||
| 66 | for (const [key, value] of entries) { | ||
| 67 | lookup[key.toLowerCase()] = value; | ||
| 68 | } | ||
| 69 | return lookup; | ||
| 70 | } | ||
| 71 | |||
| 72 | const extensionByLanguageId: Record<string, string> = {}; | ||
| 73 | for (const [extension, languageId] of Object.entries(languageAssociations.extensionToLanguageId)) { | ||
| 74 | const key = languageId.toLowerCase(); | ||
| 75 | if (!(key in extensionByLanguageId)) { | ||
| 76 | extensionByLanguageId[key] = extension.toLowerCase(); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Synthesizes a file name whose icon resolution best represents a markdown | ||
| 82 | * fence language id — handles both extension-style ids ("ts", "py") and | ||
| 83 | * language ids ("typescript", "python", "shellscript"). | ||
| 84 | */ | ||
| 85 | export function syntheticFileNameForLanguageId(languageId: string): string { | ||
| 86 | const normalized = languageId.toLowerCase(); | ||
| 87 | return `file.${extensionByLanguageId[normalized] ?? normalized}`; | ||
| 88 | } | ||
| 89 | |||
| 90 | export function basenameOfPath(pathValue: string): string { | ||
| 91 | const slashIndex = pathValue.lastIndexOf("/"); | ||
| 92 | if (slashIndex === -1) return pathValue; | ||
| 93 | return pathValue.slice(slashIndex + 1); | ||
| 94 | } | ||
| 95 | |||
| 96 | export function inferEntryKindFromPath(pathValue: string): "file" | "directory" { | ||
| 97 | const base = basenameOfPath(pathValue); | ||
| 98 | if (base.startsWith(".") && !base.slice(1).includes(".")) { | ||
| 99 | return "directory"; | ||
| 100 | } | ||
| 101 | if (base.includes(".")) { | ||
| 102 | return "file"; | ||
| 103 | } | ||
| 104 | return "directory"; | ||
| 105 | } | ||
| 106 | |||
| 107 | function extensionCandidates(fileName: string): string[] { | ||
| 108 | const candidates = new Set<string>(); | ||
| 109 | if (fileName.includes(".")) { | ||
| 110 | candidates.add(fileName); | ||
| 111 | } | ||
| 112 | let dotIndex = fileName.indexOf("."); | ||
| 113 | while (dotIndex !== -1 && dotIndex < fileName.length - 1) { | ||
| 114 | const candidate = fileName.slice(dotIndex + 1); | ||
| 115 | if (candidate.length > 0) { | ||
| 116 | candidates.add(candidate); | ||
| 117 | } | ||
| 118 | dotIndex = fileName.indexOf(".", dotIndex + 1); | ||
| 119 | } | ||
| 120 | return [...candidates]; | ||
| 121 | } | ||
| 122 | |||
| 123 | function resolveLanguageFallbackDefinition( | ||
| 124 | pathValue: string, | ||
| 125 | theme: "light" | "dark", | ||
| 126 | ): string | null { | ||
| 127 | const basename = basenameOfPath(pathValue).toLowerCase(); | ||
| 128 | const languageIds = theme === "light" ? lightLanguageIds : darkLanguageIds; | ||
| 129 | |||
| 130 | const fromBasenameLanguage = languageIdByFileName[basename]; | ||
| 131 | if (fromBasenameLanguage) { | ||
| 132 | return languageIds[fromBasenameLanguage] ?? darkLanguageIds[fromBasenameLanguage] ?? null; | ||
| 133 | } | ||
| 134 | |||
| 135 | for (const candidate of extensionCandidates(basename)) { | ||
| 136 | const languageId = | ||
| 137 | localLanguageIdByExtensionOverrides[ | ||
| 138 | candidate as keyof typeof localLanguageIdByExtensionOverrides | ||
| 139 | ] ?? languageIdByExtension[candidate]; | ||
| 140 | if (!languageId) continue; | ||
| 141 | return languageIds[languageId] ?? darkLanguageIds[languageId] ?? null; | ||
| 142 | } | ||
| 143 | |||
| 144 | return null; | ||
| 145 | } | ||
| 146 | |||
| 147 | function iconFilenameForDefinitionKey(definitionKey: string | undefined): string | null { | ||
| 148 | if (!definitionKey) return null; | ||
| 149 | const iconPath = iconDefinitions[definitionKey]?.iconPath; | ||
| 150 | if (!iconPath) return null; | ||
| 151 | const slashIndex = iconPath.lastIndexOf("/"); | ||
| 152 | if (slashIndex === -1) { | ||
| 153 | return iconPath; | ||
| 154 | } | ||
| 155 | return iconPath.slice(slashIndex + 1); | ||
| 156 | } | ||
| 157 | |||
| 158 | function resolveFileDefinition(pathValue: string, theme: "light" | "dark"): string { | ||
| 159 | const basename = basenameOfPath(pathValue).toLowerCase(); | ||
| 160 | const fileNames = theme === "light" ? lightFileNames : darkFileNames; | ||
| 161 | const fileExtensions = theme === "light" ? lightFileExtensions : darkFileExtensions; | ||
| 162 | |||
| 163 | const fromFileName = fileNames[basename] ?? darkFileNames[basename]; | ||
| 164 | if (fromFileName) return fromFileName; | ||
| 165 | |||
| 166 | for (const candidate of extensionCandidates(basename)) { | ||
| 167 | const fromExtension = fileExtensions[candidate] ?? darkFileExtensions[candidate]; | ||
| 168 | if (fromExtension) return fromExtension; | ||
| 169 | } | ||
| 170 | |||
| 171 | const fromLanguage = resolveLanguageFallbackDefinition(pathValue, theme); | ||
| 172 | if (fromLanguage) return fromLanguage; | ||
| 173 | |||
| 174 | return theme === "light" ? defaultLightFileIconDefinition : defaultDarkFileIconDefinition; | ||
| 175 | } | ||
| 176 | |||
| 177 | function resolveFolderDefinition(pathValue: string, theme: "light" | "dark"): string { | ||
| 178 | const basename = basenameOfPath(pathValue).toLowerCase(); | ||
| 179 | const folderNames = theme === "light" ? lightFolderNames : darkFolderNames; | ||
| 180 | return ( | ||
| 181 | folderNames[basename] ?? | ||
| 182 | darkFolderNames[basename] ?? | ||
| 183 | (theme === "light" ? defaultLightFolderIconDefinition : defaultDarkFolderIconDefinition) | ||
| 184 | ); | ||
| 185 | } | ||
| 186 | |||
| 187 | /** True when the file name resolves to a real icon rather than the generic default. */ | ||
| 188 | export function hasSpecificVscodeIconForFileName( | ||
| 189 | fileName: string, | ||
| 190 | theme: "light" | "dark", | ||
| 191 | ): boolean { | ||
| 192 | const definition = resolveFileDefinition(fileName, theme); | ||
| 193 | return ( | ||
| 194 | definition !== defaultDarkFileIconDefinition && definition !== defaultLightFileIconDefinition | ||
| 195 | ); | ||
| 196 | } | ||
| 197 | |||
| 198 | export function getVscodeIconUrlForEntry( | ||
| 199 | pathValue: string, | ||
| 200 | kind: "file" | "directory", | ||
| 201 | theme: "light" | "dark", | ||
| 202 | ): string { | ||
| 203 | const definitionKey = | ||
| 204 | kind === "directory" | ||
| 205 | ? resolveFolderDefinition(pathValue, theme) | ||
| 206 | : resolveFileDefinition(pathValue, theme); | ||
| 207 | const iconFilename = | ||
| 208 | iconFilenameForDefinitionKey(definitionKey) ?? | ||
| 209 | (kind === "directory" ? "default_folder.svg" : "default_file.svg"); | ||
| 210 | return `${VSCODE_ICONS_BASE_URL}/${iconFilename}`; | ||
| 211 | } | ||
| @@ -121,6 +121,7 @@ export default defineConfig(() => { · 120 unmodified lines | |||
| 121 | optimizeDeps: { | 121 | optimizeDeps: { |
| 122 | include: [ | 122 | include: [ |
| 123 | "@pierre/diffs", | 123 | "@pierre/diffs", |
| 124 | "@pierre/diffs/editor", | ||
| 124 | "@pierre/diffs/react", | 125 | "@pierre/diffs/react", |
| 125 | "@pierre/diffs/worker/worker.js", | 126 | "@pierre/diffs/worker/worker.js", |
| 126 | "effect/Array", | 127 | "effect/Array", |
| @@ -35,7 +35,6 @@ · 34 unmodified lines | |||
| 35 | "dist:desktop:win:x64": "node scripts/build-desktop-artifact.ts --platform win --target nsis --arch x64", | 35 | "dist:desktop:win:x64": "node scripts/build-desktop-artifact.ts --platform win --target nsis --arch x64", |
| 36 | "release:smoke": "node scripts/release-smoke.ts", | 36 | "release:smoke": "node scripts/release-smoke.ts", |
| 37 | "clean": "rm -rf node_modules apps/*/node_modules packages/*/node_modules apps/*/dist apps/*/dist-electron packages/*/dist .vite-plus apps/*/.vite-plus packages/*/.vite-plus", | 37 | "clean": "rm -rf node_modules apps/*/node_modules packages/*/node_modules apps/*/dist apps/*/dist-electron packages/*/dist .vite-plus apps/*/.vite-plus packages/*/.vite-plus", |
| 38 | "sync:vscode-icons": "node scripts/sync-vscode-icons.mjs", | ||
| 39 | "sync:repos": "node scripts/sync-reference-repos.ts" | 38 | "sync:repos": "node scripts/sync-reference-repos.ts" |
| 40 | }, | 39 | }, |
| 41 | "devDependencies": { | 40 | "devDependencies": { |
| @@ -96,6 +96,8 @@ export interface WsRpcClient { · 95 unmodified lines | |||
| 96 | readonly subscribePorts: RpcStreamMethod<typeof WS_METHODS.subscribeDiscoveredLocalServers>; | 96 | readonly subscribePorts: RpcStreamMethod<typeof WS_METHODS.subscribeDiscoveredLocalServers>; |
| 97 | }; | 97 | }; |
| 98 | readonly projects: { | 98 | readonly projects: { |
| 99 | readonly listEntries: RpcUnaryMethod<typeof WS_METHODS.projectsListEntries>; | ||
| 100 | readonly readFile: RpcUnaryMethod<typeof WS_METHODS.projectsReadFile>; | ||
| 99 | readonly searchEntries: RpcUnaryMethod<typeof WS_METHODS.projectsSearchEntries>; | 101 | readonly searchEntries: RpcUnaryMethod<typeof WS_METHODS.projectsSearchEntries>; |
| 100 | readonly writeFile: RpcUnaryMethod<typeof WS_METHODS.projectsWriteFile>; | 102 | readonly writeFile: RpcUnaryMethod<typeof WS_METHODS.projectsWriteFile>; |
| 101 | }; | 103 | }; |
| @@ -267,6 +269,10 @@ export function createWsRpcClient( · 165 unmodified lines | |||
| 267 | ), | 269 | ), |
| 268 | }, | 270 | }, |
| 269 | projects: { | 271 | projects: { |
| 272 | listEntries: (input) => | ||
| 273 | transport.request((client) => client[WS_METHODS.projectsListEntries](input)), | ||
| 274 | readFile: (input) => | ||
| 275 | transport.request((client) => client[WS_METHODS.projectsReadFile](input)), | ||
| 270 | searchEntries: (input) => | 276 | searchEntries: (input) => |
| 271 | transport.request((client) => client[WS_METHODS.projectsSearchEntries](input)), | 277 | transport.request((client) => client[WS_METHODS.projectsSearchEntries](input)), |
| 272 | writeFile: (input) => | 278 | writeFile: (input) => |
| @@ -22,6 +22,10 @@ import type { ReviewDiffPreviewInput, ReviewDiffPreviewResult } from "./review.t · 21 unmodified lines | |||
| 22 | import type { FilesystemBrowseInput, FilesystemBrowseResult } from "./filesystem.ts"; | 22 | import type { FilesystemBrowseInput, FilesystemBrowseResult } from "./filesystem.ts"; |
| 23 | import type { AssetCreateUrlInput, AssetCreateUrlResult } from "./assets.ts"; | 23 | import type { AssetCreateUrlInput, AssetCreateUrlResult } from "./assets.ts"; |
| 24 | import type { | 24 | import type { |
| 25 | ProjectListEntriesInput, | ||
| 26 | ProjectListEntriesResult, | ||
| 27 | ProjectReadFileInput, | ||
| 28 | ProjectReadFileResult, | ||
| 25 | ProjectSearchEntriesInput, | 29 | ProjectSearchEntriesInput, |
| 26 | ProjectSearchEntriesResult, | 30 | ProjectSearchEntriesResult, |
| 27 | ProjectWriteFileInput, | 31 | ProjectWriteFileInput, |
| @@ -1110,6 +1114,8 @@ export interface EnvironmentApi { · 1082 unmodified lines | |||
| 1110 | ) => () => void; | 1114 | ) => () => void; |
| 1111 | }; | 1115 | }; |
| 1112 | projects: { | 1116 | projects: { |
| 1117 | listEntries: (input: ProjectListEntriesInput) => Promise<ProjectListEntriesResult>; | ||
| 1118 | readFile: (input: ProjectReadFileInput) => Promise<ProjectReadFileResult>; | ||
| 1113 | searchEntries: (input: ProjectSearchEntriesInput) => Promise<ProjectSearchEntriesResult>; | 1119 | searchEntries: (input: ProjectSearchEntriesInput) => Promise<ProjectSearchEntriesResult>; |
| 1114 | writeFile: (input: ProjectWriteFileInput) => Promise<ProjectWriteFileResult>; | 1120 | writeFile: (input: ProjectWriteFileInput) => Promise<ProjectWriteFileResult>; |
| 1115 | }; | 1121 | }; |
| @@ -1,8 +1,9 @@ | |||
| 1 | import * as Schema from "effect/Schema"; | 1 | import * as Schema from "effect/Schema"; |
| 2 | import { PositiveInt, TrimmedNonEmptyString } from "./baseSchemas.ts"; | 2 | import { NonNegativeInt, PositiveInt, TrimmedNonEmptyString } from "./baseSchemas.ts"; |
| 3 | 3 | ||
| 4 | const PROJECT_SEARCH_ENTRIES_MAX_LIMIT = 200; | 4 | const PROJECT_SEARCH_ENTRIES_MAX_LIMIT = 200; |
| 5 | const PROJECT_WRITE_FILE_PATH_MAX_LENGTH = 512; | 5 | const PROJECT_WRITE_FILE_PATH_MAX_LENGTH = 512; |
| 6 | const PROJECT_READ_FILE_PATH_MAX_LENGTH = 512; | ||
| 6 | 7 | ||
| 7 | export const ProjectSearchEntriesInput = Schema.Struct({ | 8 | export const ProjectSearchEntriesInput = Schema.Struct({ |
| 8 | cwd: TrimmedNonEmptyString, | 9 | cwd: TrimmedNonEmptyString, |
| @@ -26,6 +27,17 @@ export const ProjectSearchEntriesResult = Schema.Struct({ · 17 unmodified lines | |||
| 26 | }); | 27 | }); |
| 27 | export type ProjectSearchEntriesResult = typeof ProjectSearchEntriesResult.Type; | 28 | export type ProjectSearchEntriesResult = typeof ProjectSearchEntriesResult.Type; |
| 28 | 29 | ||
| 30 | export const ProjectListEntriesInput = Schema.Struct({ | ||
| 31 | cwd: TrimmedNonEmptyString, | ||
| 32 | }); | ||
| 33 | export type ProjectListEntriesInput = typeof ProjectListEntriesInput.Type; | ||
| 34 | |||
| 35 | export const ProjectListEntriesResult = Schema.Struct({ | ||
| 36 | entries: Schema.Array(ProjectEntry), | ||
| 37 | truncated: Schema.Boolean, | ||
| 38 | }); | ||
| 39 | export type ProjectListEntriesResult = typeof ProjectListEntriesResult.Type; | ||
| 40 | |||
| 29 | export class ProjectSearchEntriesError extends Schema.TaggedErrorClass<ProjectSearchEntriesError>()( | 41 | export class ProjectSearchEntriesError extends Schema.TaggedErrorClass<ProjectSearchEntriesError>()( |
| 30 | "ProjectSearchEntriesError", | 42 | "ProjectSearchEntriesError", |
| 31 | { | 43 | { |
| @@ -34,6 +46,36 @@ export class ProjectSearchEntriesError extends Schema.TaggedErrorClass<ProjectSe · 2 unmodified lines | |||
| 34 | }, | 46 | }, |
| 35 | ) {} | 47 | ) {} |
| 36 | 48 | ||
| 49 | export class ProjectListEntriesError extends Schema.TaggedErrorClass<ProjectListEntriesError>()( | ||
| 50 | "ProjectListEntriesError", | ||
| 51 | { | ||
| 52 | message: TrimmedNonEmptyString, | ||
| 53 | cause: Schema.optional(Schema.Defect()), | ||
| 54 | }, | ||
| 55 | ) {} | ||
| 56 | |||
| 57 | export const ProjectReadFileInput = Schema.Struct({ | ||
| 58 | cwd: TrimmedNonEmptyString, | ||
| 59 | relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_READ_FILE_PATH_MAX_LENGTH)), | ||
| 60 | }); | ||
| 61 | export type ProjectReadFileInput = typeof ProjectReadFileInput.Type; | ||
| 62 | |||
| 63 | export const ProjectReadFileResult = Schema.Struct({ | ||
| 64 | relativePath: TrimmedNonEmptyString, | ||
| 65 | contents: Schema.String, | ||
| 66 | byteLength: NonNegativeInt, | ||
| 67 | truncated: Schema.Boolean, | ||
| 68 | }); | ||
| 69 | export type ProjectReadFileResult = typeof ProjectReadFileResult.Type; | ||
| 70 | |||
| 71 | export class ProjectReadFileError extends Schema.TaggedErrorClass<ProjectReadFileError>()( | ||
| 72 | "ProjectReadFileError", | ||
| 73 | { | ||
| 74 | message: TrimmedNonEmptyString, | ||
| 75 | cause: Schema.optional(Schema.Defect()), | ||
| 76 | }, | ||
| 77 | ) {} | ||
| 78 | |||
| 37 | export const ProjectWriteFileInput = Schema.Struct({ | 79 | export const ProjectWriteFileInput = Schema.Struct({ |
| 38 | cwd: TrimmedNonEmptyString, | 80 | cwd: TrimmedNonEmptyString, |
| 39 | relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_WRITE_FILE_PATH_MAX_LENGTH)), | 81 | relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_WRITE_FILE_PATH_MAX_LENGTH)), |
| @@ -65,6 +65,12 @@ import { · 64 unmodified lines | |||
| 65 | RelayClientStatusSchema, | 65 | RelayClientStatusSchema, |
| 66 | } from "./relayClient.ts"; | 66 | } from "./relayClient.ts"; |
| 67 | import { | 67 | import { |
| 68 | ProjectListEntriesError, | ||
| 69 | ProjectListEntriesInput, | ||
| 70 | ProjectListEntriesResult, | ||
| 71 | ProjectReadFileError, | ||
| 72 | ProjectReadFileInput, | ||
| 73 | ProjectReadFileResult, | ||
| 68 | ProjectSearchEntriesError, | 74 | ProjectSearchEntriesError, |
| 69 | ProjectSearchEntriesInput, | 75 | ProjectSearchEntriesInput, |
| 70 | ProjectSearchEntriesResult, | 76 | ProjectSearchEntriesResult, |
| @@ -141,6 +147,8 @@ export const WS_METHODS = { · 70 unmodified lines | |||
| 141 | projectsList: "projects.list", | 147 | projectsList: "projects.list", |
| 142 | projectsAdd: "projects.add", | 148 | projectsAdd: "projects.add", |
| 143 | projectsRemove: "projects.remove", | 149 | projectsRemove: "projects.remove", |
| 150 | projectsListEntries: "projects.listEntries", | ||
| 151 | projectsReadFile: "projects.readFile", | ||
| 144 | projectsSearchEntries: "projects.searchEntries", | 152 | projectsSearchEntries: "projects.searchEntries", |
| 145 | projectsWriteFile: "projects.writeFile", | 153 | projectsWriteFile: "projects.writeFile", |
| 146 | 154 | ||
| @@ -350,6 +358,18 @@ export const WsProjectsSearchEntriesRpc = Rpc.make(WS_METHODS.projectsSearchEntr · 203 unmodified lines | |||
| 350 | error: Schema.Union([ProjectSearchEntriesError, EnvironmentAuthorizationError]), | 358 | error: Schema.Union([ProjectSearchEntriesError, EnvironmentAuthorizationError]), |
| 351 | }); | 359 | }); |
| 352 | 360 | ||
| 361 | export const WsProjectsListEntriesRpc = Rpc.make(WS_METHODS.projectsListEntries, { | ||
| 362 | payload: ProjectListEntriesInput, | ||
| 363 | success: ProjectListEntriesResult, | ||
| 364 | error: Schema.Union([ProjectListEntriesError, EnvironmentAuthorizationError]), | ||
| 365 | }); | ||
| 366 | |||
| 367 | export const WsProjectsReadFileRpc = Rpc.make(WS_METHODS.projectsReadFile, { | ||
| 368 | payload: ProjectReadFileInput, | ||
| 369 | success: ProjectReadFileResult, | ||
| 370 | error: Schema.Union([ProjectReadFileError, EnvironmentAuthorizationError]), | ||
| 371 | }); | ||
| 372 | |||
| 353 | export const WsProjectsWriteFileRpc = Rpc.make(WS_METHODS.projectsWriteFile, { | 373 | export const WsProjectsWriteFileRpc = Rpc.make(WS_METHODS.projectsWriteFile, { |
| 354 | payload: ProjectWriteFileInput, | 374 | payload: ProjectWriteFileInput, |
| 355 | success: ProjectWriteFileResult, | 375 | success: ProjectWriteFileResult, |
| @@ -676,6 +696,8 @@ export const WsRpcGroup = RpcGroup.make( · 320 unmodified lines | |||
| 676 | WsSourceControlLookupRepositoryRpc, | 696 | WsSourceControlLookupRepositoryRpc, |
| 677 | WsSourceControlCloneRepositoryRpc, | 697 | WsSourceControlCloneRepositoryRpc, |
| 678 | WsSourceControlPublishRepositoryRpc, | 698 | WsSourceControlPublishRepositoryRpc, |
| 699 | WsProjectsListEntriesRpc, | ||
| 700 | WsProjectsReadFileRpc, | ||
| 679 | WsProjectsSearchEntriesRpc, | 701 | WsProjectsSearchEntriesRpc, |
| 680 | WsProjectsWriteFileRpc, | 702 | WsProjectsWriteFileRpc, |
| 681 | WsShellOpenInEditorRpc, | 703 | WsShellOpenInEditorRpc, |
| @@ -1,5 +1,5 @@ | |||
| 1 | diff --git a/package.json b/package.json | 1 | diff --git a/package.json b/package.json |
| 2 | index c0e762b13b56247b256520754e439cbc16bb797d..d298b87c175ec891d1b50f681c9031f4b1929e67 100644 | 2 | index b18c94f3f7b40bdb15084ab7cabcb19dd29c61f7..ab96ac589d368e806ef45480283d6e0fa199117f 100644 |
| 3 | --- a/package.json | 3 | --- a/package.json |
| 4 | +++ b/package.json | 4 | +++ b/package.json |
| 5 | @@ -51,6 +51,18 @@ | 5 | @@ -51,6 +51,18 @@ |
| @@ -20,4 +20,4 @@ index c0e762b13b56247b256520754e439cbc16bb797d..d298b87c175ec891d1b50f681c9031f4 · 14 unmodified lines | |||
| 20 | + "import": "./dist/utils/parsePatchFiles.js" | 20 | + "import": "./dist/utils/parsePatchFiles.js" |
| 21 | } | 21 | } |
| 22 | }, | 22 | }, |
| 23 | "scripts": { | 23 | "publishConfig": { |
| @@ -19,8 +19,8 @@ catalogs: · 18 unmodified lines | |||
| 19 | specifier: 1.8.0 | 19 | specifier: 1.8.0 |
| 20 | version: 1.8.0 | 20 | version: 1.8.0 |
| 21 | '@pierre/diffs': | 21 | '@pierre/diffs': |
| 22 | specifier: 1.1.20 | 22 | specifier: 1.3.0-beta.4 |
| 23 | version: 1.1.20 | 23 | version: 1.3.0-beta.4 |
| 24 | '@typescript/native-preview': | 24 | '@typescript/native-preview': |
| 25 | specifier: 7.0.0-dev.20260604.1 | 25 | specifier: 7.0.0-dev.20260604.1 |
| 26 | version: 7.0.0-dev.20260604.1 | 26 | version: 7.0.0-dev.20260604.1 |
| @@ -66,9 +66,9 @@ patchedDependencies: · 39 unmodified lines | |||
| 66 | '@expo/metro-config@56.0.13': | 66 | '@expo/metro-config@56.0.13': |
| 67 | hash: 8cb08b5bb7051ed9d2dbe46a2c293c5a1e17f1bd6ddf30de27909e18c921ff46 | 67 | hash: 8cb08b5bb7051ed9d2dbe46a2c293c5a1e17f1bd6ddf30de27909e18c921ff46 |
| 68 | path: patches/@expo%2Fmetro-config@56.0.13.patch | 68 | path: patches/@expo%2Fmetro-config@56.0.13.patch |
| 69 | '@pierre/diffs@1.1.20': | 69 | '@pierre/diffs@1.3.0-beta.4': |
| 70 | hash: e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0 | 70 | hash: f5d41705ce94bbafc731d92e9cb1671db710df046dd135cb894e3e3e9164a75b |
| 71 | path: patches/@pierre%2Fdiffs@1.1.20.patch | 71 | path: patches/@pierre%2Fdiffs@1.3.0-beta.4.patch |
| 72 | effect@4.0.0-beta.78: | 72 | effect@4.0.0-beta.78: |
| 73 | hash: 883249d8efbb462e928e21fefef96027b66aec50751178cafdce45f08eee3754 | 73 | hash: 883249d8efbb462e928e21fefef96027b66aec50751178cafdce45f08eee3754 |
| 74 | path: patches/effect@4.0.0-beta.78.patch | 74 | path: patches/effect@4.0.0-beta.78.patch |
| @@ -198,7 +198,7 @@ importers: · 123 unmodified lines | |||
| 198 | version: 1.8.0 | 198 | version: 1.8.0 |
| 199 | '@pierre/diffs': | 199 | '@pierre/diffs': |
| 200 | specifier: 'catalog:' | 200 | specifier: 'catalog:' |
| 201 | version: 1.1.20(patch_hash=e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) | 201 | version: 1.3.0-beta.4(patch_hash=f5d41705ce94bbafc731d92e9cb1671db710df046dd135cb894e3e3e9164a75b)(@shikijs/themes@3.23.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) |
| 202 | '@react-native-menu/menu': | 202 | '@react-native-menu/menu': |
| 203 | specifier: ^2.0.0 | 203 | specifier: ^2.0.0 |
| 204 | version: 2.0.0(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) | 204 | version: 2.0.0(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) |
| @@ -400,7 +400,7 @@ importers: · 195 unmodified lines | |||
| 400 | version: 1.15.13 | 400 | version: 1.15.13 |
| 401 | '@pierre/diffs': | 401 | '@pierre/diffs': |
| 402 | specifier: 'catalog:' | 402 | specifier: 'catalog:' |
| 403 | version: 1.1.20(patch_hash=e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) | 403 | version: 1.3.0-beta.4(patch_hash=f5d41705ce94bbafc731d92e9cb1671db710df046dd135cb894e3e3e9164a75b)(@shikijs/themes@4.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) |
| 404 | effect: | 404 | effect: |
| 405 | specifier: 4.0.0-beta.78 | 405 | specifier: 4.0.0-beta.78 |
| 406 | version: 4.0.0-beta.78(patch_hash=883249d8efbb462e928e21fefef96027b66aec50751178cafdce45f08eee3754) | 406 | version: 4.0.0-beta.78(patch_hash=883249d8efbb462e928e21fefef96027b66aec50751178cafdce45f08eee3754) |
| @@ -482,7 +482,10 @@ importers: · 75 unmodified lines | |||
| 482 | version: 0.41.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(yjs@13.6.31) | 482 | version: 0.41.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(yjs@13.6.31) |
| 483 | '@pierre/diffs': | 483 | '@pierre/diffs': |
| 484 | specifier: 'catalog:' | 484 | specifier: 'catalog:' |
| 485 | version: 1.1.20(patch_hash=e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) | 485 | version: 1.3.0-beta.4(patch_hash=f5d41705ce94bbafc731d92e9cb1671db710df046dd135cb894e3e3e9164a75b)(@shikijs/themes@4.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) |
| 486 | '@pierre/trees': | ||
| 487 | specifier: 1.0.0-beta.4 | ||
| 488 | version: 1.0.0-beta.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) | ||
| 486 | '@t3tools/client-runtime': | 489 | '@t3tools/client-runtime': |
| 487 | specifier: workspace:* | 490 | specifier: workspace:* |
| 488 | version: link:../../packages/client-runtime | 491 | version: link:../../packages/client-runtime |
| @@ -3203,16 +3206,42 @@ packages: · 2714 unmodified lines | |||
| 3203 | resolution: {integrity: sha512-titLmukUt/h8ho7Svlf0xSBjoy2ccZKrXjpXpZCj+v6V4CJccC2KyP45BLSCMx8YIpifMyiDyUptM4+5sruKbQ==} | 3206 | resolution: {integrity: sha512-titLmukUt/h8ho7Svlf0xSBjoy2ccZKrXjpXpZCj+v6V4CJccC2KyP45BLSCMx8YIpifMyiDyUptM4+5sruKbQ==} |
| 3204 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | 3207 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} |
| 3205 | 3208 | ||
| 3206 | '@pierre/diffs@1.1.20': | 3209 | '@pierre/diffs@1.3.0-beta.4': |
| 3207 | resolution: {integrity: sha512-lLi+3sLCm3QDd5/aLO9pw+WbF6UzhrkWm2oTZ5WZJTGemOyUNRJ4DDhcEKmVusu4C4bXx9Nssh6fF+wQcapb5w==} | 3210 | resolution: {integrity: sha512-poFcsvhcQt9lH/InzAPaGs47WYHMidnFCjuYGNU41HiVLJP4mkIQDSdvcnPIkBuh/cYbPOQg/YE3T1kSpr01GA==} |
| 3208 | peerDependencies: | 3211 | peerDependencies: |
| 3209 | react: ^18.3.1 || ^19.0.0 | 3212 | react: ^18.3.1 || ^19.0.0 |
| 3210 | react-dom: ^18.3.1 || ^19.0.0 | 3213 | react-dom: ^18.3.1 || ^19.0.0 |
| 3211 | 3214 | ||
| 3212 | '@pierre/theme@0.0.28': | 3215 | '@pierre/theme@1.0.3': |
| 3213 | resolution: {integrity: sha512-1j/H/fECBuc9dEvntdWI+l435HZapw+RCJTlqCA6BboQ5TjlnE005j/ROWutXIs8aq5OAc82JI2Kwk4A1WWBgw==} | 3216 | resolution: {integrity: sha512-sWHv11TMoqKxKDgTIk5VbhQjdPhs8DCcBxbjh3mRlS3YOM/OcrWoGX6MM8eBGn9cUu3M46Py0JnxsG2nJaFTuA==} |
| 3214 | engines: {vscode: ^1.0.0} | 3217 | engines: {vscode: ^1.0.0} |
| 3215 | 3218 | ||
| 3219 | '@pierre/theming@0.0.1': | ||
| 3220 | resolution: {integrity: sha512-1thlEtJbqdyLzc1ZS2KQa1q7FzDGHT4dTEdKHoyQjOMeWWOmbVG5/ndEfOKfAb5Fzkz8cNJrOjFLiZoDH/A03A==} | ||
| 3221 | peerDependencies: | ||
| 3222 | '@pierre/theme': ^1.0.0 | ||
| 3223 | '@shikijs/themes': ^3.0.0 || ^4.0.0 | ||
| 3224 | react: ^18.3.1 || ^19.0.0 | ||
| 3225 | react-dom: ^18.3.1 || ^19.0.0 | ||
| 3226 | shiki: ^3.0.0 || ^4.0.0 | ||
| 3227 | peerDependenciesMeta: | ||
| 3228 | '@pierre/theme': | ||
| 3229 | optional: true | ||
| 3230 | '@shikijs/themes': | ||
| 3231 | optional: true | ||
| 3232 | react: | ||
| 3233 | optional: true | ||
| 3234 | react-dom: | ||
| 3235 | optional: true | ||
| 3236 | shiki: | ||
| 3237 | optional: true | ||
| 3238 | |||
| 3239 | '@pierre/trees@1.0.0-beta.4': | ||
| 3240 | resolution: {integrity: sha512-OfT1yk9ne8Te5+GB5zUY8yqE6B8BqjBHQJleH4lu8ltwNpoocZl4vXt1AzlEExpxI/pp+AFX5QG+lR3JjtTEag==} | ||
| 3241 | peerDependencies: | ||
| 3242 | react: ^18.3.1 || ^19.0.0 | ||
| 3243 | react-dom: ^18.3.1 || ^19.0.0 | ||
| 3244 | |||
| 3216 | '@polka/url@1.0.0-next.29': | 3245 | '@polka/url@1.0.0-next.29': |
| 3217 | resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} | 3246 | resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} |
| 3218 | 3247 | ||
| @@ -8078,6 +8107,14 @@ packages: · 4859 unmodified lines | |||
| 8078 | engines: {node: '>=14.0.0'} | 8107 | engines: {node: '>=14.0.0'} |
| 8079 | hasBin: true | 8108 | hasBin: true |
| 8080 | 8109 | ||
| 8110 | preact-render-to-string@6.6.5: | ||
| 8111 | resolution: {integrity: sha512-O6MHzYNIKYaiSX3bOw0gGZfEbOmlIDtDfWwN1JJdc/T3ihzRT6tGGSEWE088dWrEDGa1u7101q+6fzQnO9XCPA==} | ||
| 8112 | peerDependencies: | ||
| 8113 | preact: '>=10 || >= 11.0.0-0' | ||
| 8114 | |||
| 8115 | preact@11.0.0-beta.0: | ||
| 8116 | resolution: {integrity: sha512-IcODoASASYwJ9kxz7+MJeiJhvLriwSb4y4mHIyxdgaRZp6kPUud7xytrk/6GZw8U3y6EFJaRb5wi9SrEK+8+lg==} | ||
| 8117 | |||
| 8081 | prettier@3.8.3: | 8118 | prettier@3.8.3: |
| 8082 | resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} | 8119 | resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} |
| 8083 | engines: {node: '>=14'} | 8120 | engines: {node: '>=14'} |
| @@ -12439,9 +12476,10 @@ snapshots: · 4355 unmodified lines | |||
| 12439 | 12476 | ||
| 12440 | '@oxlint/plugins@1.68.0': {} | 12477 | '@oxlint/plugins@1.68.0': {} |
| 12441 | 12478 | ||
| 12442 | '@pierre/diffs@1.1.20(patch_hash=e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': | 12479 | '@pierre/diffs@1.3.0-beta.4(patch_hash=f5d41705ce94bbafc731d92e9cb1671db710df046dd135cb894e3e3e9164a75b)(@shikijs/themes@3.23.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': |
| 12443 | dependencies: | 12480 | dependencies: |
| 12444 | '@pierre/theme': 0.0.28 | 12481 | '@pierre/theme': 1.0.3 |
| 12482 | '@pierre/theming': 0.0.1(@pierre/theme@1.0.3)(@shikijs/themes@3.23.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(shiki@3.23.0) | ||
| 12445 | '@shikijs/transformers': 3.23.0 | 12483 | '@shikijs/transformers': 3.23.0 |
| 12446 | diff: 8.0.3 | 12484 | diff: 8.0.3 |
| 12447 | hast-util-to-html: 9.0.5 | 12485 | hast-util-to-html: 9.0.5 |
| @@ -12449,10 +12487,13 @@ snapshots: · 1 unmodified line | |||
| 12449 | react: 19.2.3 | 12487 | react: 19.2.3 |
| 12450 | react-dom: 19.2.3(react@19.2.3) | 12488 | react-dom: 19.2.3(react@19.2.3) |
| 12451 | shiki: 3.23.0 | 12489 | shiki: 3.23.0 |
| 12490 | transitivePeerDependencies: | ||
| 12491 | - '@shikijs/themes' | ||
| 12452 | 12492 | ||
| 12453 | '@pierre/diffs@1.1.20(patch_hash=e4e35ba95100de3708f900e0d9ea62bca732b1e4486024b5055f48cd128dd9e0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': | 12493 | '@pierre/diffs@1.3.0-beta.4(patch_hash=f5d41705ce94bbafc731d92e9cb1671db710df046dd135cb894e3e3e9164a75b)(@shikijs/themes@4.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': |
| 12454 | dependencies: | 12494 | dependencies: |
| 12455 | '@pierre/theme': 0.0.28 | 12495 | '@pierre/theme': 1.0.3 |
| 12496 | '@pierre/theming': 0.0.1(@pierre/theme@1.0.3)(@shikijs/themes@4.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(shiki@3.23.0) | ||
| 12456 | '@shikijs/transformers': 3.23.0 | 12497 | '@shikijs/transformers': 3.23.0 |
| 12457 | diff: 8.0.3 | 12498 | diff: 8.0.3 |
| 12458 | hast-util-to-html: 9.0.5 | 12499 | hast-util-to-html: 9.0.5 |
| @@ -12460,8 +12501,33 @@ snapshots: · 1 unmodified line | |||
| 12460 | react: 19.2.6 | 12501 | react: 19.2.6 |
| 12461 | react-dom: 19.2.6(react@19.2.6) | 12502 | react-dom: 19.2.6(react@19.2.6) |
| 12462 | shiki: 3.23.0 | 12503 | shiki: 3.23.0 |
| 12504 | transitivePeerDependencies: | ||
| 12505 | - '@shikijs/themes' | ||
| 12463 | 12506 | ||
| 12464 | '@pierre/theme@0.0.28': {} | 12507 | '@pierre/theme@1.0.3': {} |
| 12508 | |||
| 12509 | '@pierre/theming@0.0.1(@pierre/theme@1.0.3)(@shikijs/themes@3.23.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(shiki@3.23.0)': | ||
| 12510 | optionalDependencies: | ||
| 12511 | '@pierre/theme': 1.0.3 | ||
| 12512 | '@shikijs/themes': 3.23.0 | ||
| 12513 | react: 19.2.3 | ||
| 12514 | react-dom: 19.2.3(react@19.2.3) | ||
| 12515 | shiki: 3.23.0 | ||
| 12516 | |||
| 12517 | '@pierre/theming@0.0.1(@pierre/theme@1.0.3)(@shikijs/themes@4.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(shiki@3.23.0)': | ||
| 12518 | optionalDependencies: | ||
| 12519 | '@pierre/theme': 1.0.3 | ||
| 12520 | '@shikijs/themes': 4.1.0 | ||
| 12521 | react: 19.2.6 | ||
| 12522 | react-dom: 19.2.6(react@19.2.6) | ||
| 12523 | shiki: 3.23.0 | ||
| 12524 | |||
| 12525 | '@pierre/trees@1.0.0-beta.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': | ||
| 12526 | dependencies: | ||
| 12527 | preact: 11.0.0-beta.0 | ||
| 12528 | preact-render-to-string: 6.6.5(preact@11.0.0-beta.0) | ||
| 12529 | react: 19.2.6 | ||
| 12530 | react-dom: 19.2.6(react@19.2.6) | ||
| 12465 | 12531 | ||
| 12466 | '@polka/url@1.0.0-next.29': {} | 12532 | '@polka/url@1.0.0-next.29': {} |
| 12467 | 12533 | ||
| @@ -17748,6 +17814,12 @@ snapshots: · 5280 unmodified lines | |||
| 17748 | commander: 9.5.0 | 17814 | commander: 9.5.0 |
| 17749 | optional: true | 17815 | optional: true |
| 17750 | 17816 | ||
| 17817 | preact-render-to-string@6.6.5(preact@11.0.0-beta.0): | ||
| 17818 | dependencies: | ||
| 17819 | preact: 11.0.0-beta.0 | ||
| 17820 | |||
| 17821 | preact@11.0.0-beta.0: {} | ||
| 17822 | |||
| 17751 | prettier@3.8.3: {} | 17823 | prettier@3.8.3: {} |
| 17752 | 17824 | ||
| 17753 | pretty-cache-header@1.0.0: | 17825 | pretty-cache-header@1.0.0: |
| @@ -28,7 +28,7 @@ catalog: · 27 unmodified lines | |||
| 28 | "@effect/tsgo": 0.13.2 | 28 | "@effect/tsgo": 0.13.2 |
| 29 | "@noble/curves": 1.9.1 | 29 | "@noble/curves": 1.9.1 |
| 30 | "@noble/hashes": 1.8.0 | 30 | "@noble/hashes": 1.8.0 |
| 31 | "@pierre/diffs": 1.1.20 | 31 | "@pierre/diffs": 1.3.0-beta.4 |
| 32 | "@vitest/runner": 4.1.8 | 32 | "@vitest/runner": 4.1.8 |
| 33 | "@types/node": 24.12.4 | 33 | "@types/node": 24.12.4 |
| 34 | "@typescript/native-preview": 7.0.0-dev.20260604.1 | 34 | "@typescript/native-preview": 7.0.0-dev.20260604.1 |
| @@ -83,8 +83,10 @@ packageExtensions: · 48 unmodified lines | |||
| 83 | dependencies: | 83 | dependencies: |
| 84 | vite: "catalog:" | 84 | vite: "catalog:" |
| 85 | patchedDependencies: | 85 | patchedDependencies: |
| 86 | # Keep non-browser consumers off the root entrypoint, which eagerly imports | ||
| 87 | # DOM-dependent renderers. These utility/type subpaths are safe for mobile. | ||
| 88 | "@pierre/diffs@1.3.0-beta.4": patches/@pierre%2Fdiffs@1.3.0-beta.4.patch | ||
| 86 | "@effect/vitest@4.0.0-beta.78": patches/@effect__vitest@4.0.0-beta.78.patch | 89 | "@effect/vitest@4.0.0-beta.78": patches/@effect__vitest@4.0.0-beta.78.patch |
| 87 | "@expo/metro-config@56.0.13": patches/@expo%2Fmetro-config@56.0.13.patch | 90 | "@expo/metro-config@56.0.13": patches/@expo%2Fmetro-config@56.0.13.patch |
| 88 | "@pierre/diffs@1.1.20": patches/@pierre%2Fdiffs@1.1.20.patch | ||
| 89 | effect@4.0.0-beta.78: patches/effect@4.0.0-beta.78.patch | 91 | effect@4.0.0-beta.78: patches/effect@4.0.0-beta.78.patch |
| 90 | react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch | 92 | react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch |
| @@ -1,153 +0,0 @@ | |||
| 1 | #!/usr/bin/env node | ||
| 2 | |||
| 3 | import fs from "node:fs/promises"; | ||
| 4 | import os from "node:os"; | ||
| 5 | import path from "node:path"; | ||
| 6 | import vm from "node:vm"; | ||
| 7 | import { execFile } from "node:child_process"; | ||
| 8 | import { promisify } from "node:util"; | ||
| 9 | |||
| 10 | const execFileAsync = promisify(execFile); | ||
| 11 | |||
| 12 | const VERSION = process.argv[2] ?? "12.17.0"; | ||
| 13 | const VERSION_TAG = `v${VERSION}`; | ||
| 14 | const VSIX_URL = `https://open-vsx.org/api/vscode-icons-team/vscode-icons/${VERSION}/file/vscode-icons-team.vscode-icons-${VERSION}.vsix`; | ||
| 15 | const LANGUAGES_URL = `https://raw.githubusercontent.com/vscode-icons/vscode-icons/${VERSION_TAG}/src/iconsManifest/languages.ts`; | ||
| 16 | |||
| 17 | const REPO_ROOT = process.cwd(); | ||
| 18 | const MANIFEST_PATH = path.join(REPO_ROOT, "apps/web/src/vscode-icons-manifest.json"); | ||
| 19 | const ASSOCIATIONS_PATH = path.join( | ||
| 20 | REPO_ROOT, | ||
| 21 | "apps/web/src/vscode-icons-language-associations.json", | ||
| 22 | ); | ||
| 23 | |||
| 24 | function normalizeExtension(value) { | ||
| 25 | return value.trim().toLowerCase().replace(/^\./, ""); | ||
| 26 | } | ||
| 27 | |||
| 28 | function normalizeFileName(value) { | ||
| 29 | return value.trim().toLowerCase(); | ||
| 30 | } | ||
| 31 | |||
| 32 | function putIfAbsent(target, key, value) { | ||
| 33 | if (!(key in target)) { | ||
| 34 | target[key] = value; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | async function downloadVsix(tmpDir) { | ||
| 39 | const vsixPath = path.join(tmpDir, `vscode-icons-${VERSION}.vsix`); | ||
| 40 | const response = await fetch(VSIX_URL); | ||
| 41 | if (!response.ok) { | ||
| 42 | throw new Error(`Failed to download VSIX: ${response.status} ${response.statusText}`); | ||
| 43 | } | ||
| 44 | const bytes = Buffer.from(await response.arrayBuffer()); | ||
| 45 | await fs.writeFile(vsixPath, bytes); | ||
| 46 | return vsixPath; | ||
| 47 | } | ||
| 48 | |||
| 49 | async function extractManifestFromVsix(vsixPath) { | ||
| 50 | const { stdout } = await execFileAsync("unzip", [ | ||
| 51 | "-p", | ||
| 52 | vsixPath, | ||
| 53 | "extension/dist/src/vsicons-icon-theme.json", | ||
| 54 | ]); | ||
| 55 | if (!stdout || stdout.trim().length === 0) { | ||
| 56 | throw new Error("Could not extract vsicons-icon-theme.json from VSIX"); | ||
| 57 | } | ||
| 58 | return JSON.parse(stdout); | ||
| 59 | } | ||
| 60 | |||
| 61 | async function loadLanguagesCollection() { | ||
| 62 | const response = await fetch(LANGUAGES_URL); | ||
| 63 | if (!response.ok) { | ||
| 64 | throw new Error(`Failed to fetch languages.ts: ${response.status} ${response.statusText}`); | ||
| 65 | } | ||
| 66 | const rawSource = await response.text(); | ||
| 67 | const source = rawSource | ||
| 68 | .replace(/^import[^;]+;\s*/gm, "") | ||
| 69 | .replace(/export const languages(?:\s*:\s*[^=]+)?\s*=/, "const languages =") | ||
| 70 | .replace(/\}\s*satisfies\s*Record<[^;]+>;/, "};"); | ||
| 71 | |||
| 72 | const context = {}; | ||
| 73 | vm.createContext(context); | ||
| 74 | vm.runInContext(`${source}\n;globalThis.__languages = languages;`, context); | ||
| 75 | const languages = context.__languages; | ||
| 76 | if (!languages || typeof languages !== "object") { | ||
| 77 | throw new Error("Failed to parse languages.ts into a collection"); | ||
| 78 | } | ||
| 79 | return languages; | ||
| 80 | } | ||
| 81 | |||
| 82 | function buildLanguageAssociations(manifest, languages) { | ||
| 83 | const availableLanguageIds = new Set(Object.keys(manifest.languageIds ?? {})); | ||
| 84 | const extensionToLanguageId = {}; | ||
| 85 | const fileNameToLanguageId = {}; | ||
| 86 | |||
| 87 | for (const entry of Object.values(languages)) { | ||
| 88 | if (!entry || typeof entry !== "object") continue; | ||
| 89 | const idsRaw = entry.ids; | ||
| 90 | const ids = Array.isArray(idsRaw) ? idsRaw : [idsRaw]; | ||
| 91 | const knownExtensions = Array.isArray(entry.knownExtensions) ? entry.knownExtensions : []; | ||
| 92 | const knownFilenames = Array.isArray(entry.knownFilenames) ? entry.knownFilenames : []; | ||
| 93 | |||
| 94 | for (const idValue of ids) { | ||
| 95 | if (typeof idValue !== "string") continue; | ||
| 96 | const languageId = idValue.trim(); | ||
| 97 | if (languageId.length === 0) continue; | ||
| 98 | if (!availableLanguageIds.has(languageId)) continue; | ||
| 99 | |||
| 100 | for (const extensionValue of knownExtensions) { | ||
| 101 | if (typeof extensionValue !== "string") continue; | ||
| 102 | const extension = normalizeExtension(extensionValue); | ||
| 103 | if (extension.length === 0) continue; | ||
| 104 | putIfAbsent(extensionToLanguageId, extension, languageId); | ||
| 105 | } | ||
| 106 | |||
| 107 | for (const fileNameValue of knownFilenames) { | ||
| 108 | if (typeof fileNameValue !== "string") continue; | ||
| 109 | const fileName = normalizeFileName(fileNameValue); | ||
| 110 | if (fileName.length === 0) continue; | ||
| 111 | putIfAbsent(fileNameToLanguageId, fileName, languageId); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | return { | ||
| 117 | version: VERSION, | ||
| 118 | source: LANGUAGES_URL, | ||
| 119 | generatedAt: new Date().toISOString(), | ||
| 120 | extensionToLanguageId, | ||
| 121 | fileNameToLanguageId, | ||
| 122 | }; | ||
| 123 | } | ||
| 124 | |||
| 125 | async function main() { | ||
| 126 | const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "t3-vscode-icons-sync-")); | ||
| 127 | try { | ||
| 128 | const vsixPath = await downloadVsix(tmpDir); | ||
| 129 | const manifest = await extractManifestFromVsix(vsixPath); | ||
| 130 | const languages = await loadLanguagesCollection(); | ||
| 131 | const associations = buildLanguageAssociations(manifest, languages); | ||
| 132 | |||
| 133 | await fs.writeFile(MANIFEST_PATH, `${JSON.stringify(manifest)}\n`, "utf8"); | ||
| 134 | await fs.writeFile(ASSOCIATIONS_PATH, `${JSON.stringify(associations)}\n`, "utf8"); | ||
| 135 | |||
| 136 | process.stdout.write( | ||
| 137 | [ | ||
| 138 | `Synced vscode-icons ${VERSION}`, | ||
| 139 | `manifest: ${MANIFEST_PATH}`, | ||
| 140 | `language associations: ${ASSOCIATIONS_PATH}`, | ||
| 141 | `extension mappings: ${Object.keys(associations.extensionToLanguageId).length}`, | ||
| 142 | `filename mappings: ${Object.keys(associations.fileNameToLanguageId).length}`, | ||
| 143 | ].join("\n") + "\n", | ||
| 144 | ); | ||
| 145 | } finally { | ||
| 146 | await fs.rm(tmpDir, { recursive: true, force: true }); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | main().catch((error) => { | ||
| 151 | process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); | ||
| 152 | process.exit(1); | ||
| 153 | }); | ||