fix(teacher): 改善只读工具分页与读取预算
This commit is contained in:
@@ -277,6 +277,32 @@ export class CodingProjectFileService {
|
||||
}));
|
||||
}
|
||||
|
||||
async *textChunks(projectPath: string, requestedPath: string, signal: AbortSignal): AsyncGenerator<string> {
|
||||
const relativePath = normalizeRelativePath(requestedPath);
|
||||
const target = await containedExistingTarget(projectPath, relativePath);
|
||||
if (!(await lstat(target)).isFile()) throw new Error('Project file path is not a file');
|
||||
const handle = await open(target, 'r');
|
||||
const stream = handle.createReadStream({ autoClose: false });
|
||||
const decoder = new TextDecoder('utf-8', { fatal: true });
|
||||
let pendingCR = '';
|
||||
try {
|
||||
for await (const chunk of stream) {
|
||||
signal.throwIfAborted();
|
||||
let text = pendingCR + decoder.decode(chunk as Buffer, { stream: true });
|
||||
if (text.includes('\0')) throw new Error('Project file is not UTF-8 text');
|
||||
// A Windows newline can straddle two filesystem chunks.
|
||||
pendingCR = text.endsWith('\r') ? '\r' : '';
|
||||
if (pendingCR) text = text.slice(0, -1);
|
||||
if (text) yield text.replaceAll('\r\n', '\n');
|
||||
}
|
||||
const final = pendingCR + decoder.decode();
|
||||
if (final) yield final;
|
||||
} finally {
|
||||
stream.destroy();
|
||||
await handle.close();
|
||||
}
|
||||
}
|
||||
|
||||
async content(projectPath: string, requestedPath: string): Promise<CodingProjectFileContent> {
|
||||
const relativePath = normalizeRelativePath(requestedPath);
|
||||
const result = await readBoundedFile(projectPath, relativePath, MAX_CONTENT_BYTES);
|
||||
|
||||
Reference in New Issue
Block a user