fix: make file tree loading more reliable
Avoid gitignore filtering during folder browsing Show folder load errors instead of empty folders Add timeout fallback for gitignore checks
This commit is contained in:
@@ -6,6 +6,14 @@ import { execGit } from './bridge-git-process-runtime';
|
||||
|
||||
const MAX_FILE_ATTACH_SIZE_BYTES = 10 * 1024 * 1024;
|
||||
|
||||
const createGitCheckIgnoreTimeoutMs = () => {
|
||||
const raw = Number(process.env.OPENCHAMBER_GIT_CHECK_IGNORE_TIMEOUT_MS);
|
||||
if (Number.isFinite(raw) && raw >= 0) return raw;
|
||||
return 2500;
|
||||
};
|
||||
|
||||
const GIT_CHECK_IGNORE_TIMEOUT_MS = createGitCheckIgnoreTimeoutMs();
|
||||
|
||||
const guessMimeTypeFromExtension = (ext: string) => {
|
||||
switch (ext) {
|
||||
case '.png':
|
||||
@@ -114,12 +122,35 @@ const isPathInside = (candidatePath: string, parentPath: string): boolean => {
|
||||
|
||||
export const normalizeFsPath = (value: string) => value.replace(/\\/g, '/');
|
||||
|
||||
const execGitCheckIgnore = async (args: string[], cwd: string): Promise<{ stdout: string; stderr: string; exitCode: number } | null> => {
|
||||
if (GIT_CHECK_IGNORE_TIMEOUT_MS <= 0) {
|
||||
return execGit(args, cwd);
|
||||
}
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
try {
|
||||
return await Promise.race([
|
||||
execGit(args, cwd),
|
||||
new Promise<null>((resolve) => {
|
||||
timeout = setTimeout(() => resolve(null), GIT_CHECK_IGNORE_TIMEOUT_MS);
|
||||
}),
|
||||
]);
|
||||
} finally {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const gitCheckIgnoreNames = async (cwd: string, names: string[]): Promise<Set<string>> => {
|
||||
if (names.length === 0) {
|
||||
return new Set();
|
||||
}
|
||||
|
||||
const result = await execGit(['check-ignore', '--', ...names], cwd);
|
||||
const result = await execGitCheckIgnore(['check-ignore', '--', ...names], cwd);
|
||||
if (!result) {
|
||||
return new Set();
|
||||
}
|
||||
if (result.exitCode !== 0 || !result.stdout) {
|
||||
return new Set();
|
||||
}
|
||||
@@ -137,7 +168,10 @@ const gitCheckIgnorePaths = async (cwd: string, paths: string[]): Promise<Set<st
|
||||
return new Set();
|
||||
}
|
||||
|
||||
const result = await execGit(['check-ignore', '--', ...paths], cwd);
|
||||
const result = await execGitCheckIgnore(['check-ignore', '--', ...paths], cwd);
|
||||
if (!result) {
|
||||
return new Set();
|
||||
}
|
||||
if (result.exitCode !== 0 || !result.stdout) {
|
||||
return new Set();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@ const createGitReadCacheTtlMs = () => {
|
||||
return 30 * 1000;
|
||||
};
|
||||
|
||||
const createGitCheckIgnoreTimeoutMs = () => {
|
||||
const raw = Number(process.env.OPENCHAMBER_GIT_CHECK_IGNORE_TIMEOUT_MS);
|
||||
if (Number.isFinite(raw) && raw >= 0) return raw;
|
||||
return 2500;
|
||||
};
|
||||
|
||||
const normalizeCommand = (command: unknown): string =>
|
||||
typeof command === 'string' ? command.trim().replace(/\s+/g, ' ') : '';
|
||||
|
||||
@@ -60,6 +66,7 @@ const isCacheableGitReadCommand = (command: string): boolean => {
|
||||
};
|
||||
|
||||
const GIT_READ_CACHE_TTL_MS = createGitReadCacheTtlMs();
|
||||
const GIT_CHECK_IGNORE_TIMEOUT_MS = createGitCheckIgnoreTimeoutMs();
|
||||
const GIT_READ_CACHE_MAX_ENTRIES = 500;
|
||||
const GIT_READ_CACHE_MAX_BYTES = 1024 * 1024;
|
||||
const gitReadCache = new Map<string, { result: FsExecCommandResult; at: number }>();
|
||||
@@ -115,6 +122,30 @@ type FsDeps = {
|
||||
readUriAsAttachment: (uri: vscode.Uri, name: string) => Promise<ReadUriAsAttachmentResult>;
|
||||
};
|
||||
|
||||
const runGitCheckIgnore = async (
|
||||
execGit: FsDeps['execGit'],
|
||||
args: string[],
|
||||
cwd: string,
|
||||
): Promise<{ stdout: string; stderr: string; exitCode: number } | null> => {
|
||||
if (GIT_CHECK_IGNORE_TIMEOUT_MS <= 0) {
|
||||
return execGit(args, cwd);
|
||||
}
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
try {
|
||||
return await Promise.race([
|
||||
execGit(args, cwd),
|
||||
new Promise<null>((resolve) => {
|
||||
timeout = setTimeout(() => resolve(null), GIT_CHECK_IGNORE_TIMEOUT_MS);
|
||||
}),
|
||||
]);
|
||||
} finally {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export async function handleFsBridgeMessage(
|
||||
message: BridgeMessageInput,
|
||||
deps: FsDeps,
|
||||
@@ -177,7 +208,10 @@ export async function handleFsBridgeMessage(
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await deps.execGit(['check-ignore', '--', ...pathsToCheck], normalized);
|
||||
const result = await runGitCheckIgnore(deps.execGit, ['check-ignore', '--', ...pathsToCheck], normalized);
|
||||
if (!result) {
|
||||
return { id, type, success: true, data: { entries, directory: normalized, path: normalized } };
|
||||
}
|
||||
const ignoredNames = new Set(
|
||||
result.stdout
|
||||
.split('\n')
|
||||
|
||||
Reference in New Issue
Block a user