fix(console): the final flush speaks in whole lines, from the real buffer
tailAfterStream sliced result.stdout at the live-buffer offset, but the
buffer interleaves stdout+stderr in arrival order while result.stdout is
stdout-only plus a joining newline — offsets never line up, so the flush
could start mid-line ('f/esptool_py && ...'). Instead, the poll loop now
emits one final onProgress(state:'done') with the completed buffer and
the existing delta logic flushes the tail perfectly aligned. tailAfterStream
is gone.
This commit is contained in:
parent
23784568f6
commit
6d6d298130
|
|
@ -24,7 +24,7 @@ import { reportRunEvent } from '../../services/metricsService';
|
|||
import { useProjectStore } from '../../store/useProjectStore';
|
||||
import { LibraryManagerModal } from '../simulator/LibraryManagerModal';
|
||||
import { InstallLibrariesModal } from '../simulator/InstallLibrariesModal';
|
||||
import { parseCompileResult, isNoiseBuildLine, tailAfterStream } from '../../utils/compilationLogger';
|
||||
import { parseCompileResult, isNoiseBuildLine } from '../../utils/compilationLogger';
|
||||
import type { CompilationLog, CompileTarget } from '../../utils/compilationLogger';
|
||||
import { exportToWokwiZip } from '../../utils/wokwiZip';
|
||||
import { importProjectFile, PROJECT_FILE_ACCEPT } from '../../utils/importProject';
|
||||
|
|
@ -580,14 +580,14 @@ export const EditorToolbar = ({
|
|||
},
|
||||
);
|
||||
|
||||
// After the build settles, flush the stdout tail the polling loop never
|
||||
// delivered, then append the structured analysis — parseCompileResult
|
||||
// highlights FAILED blocks and tags compiler errors with type='error',
|
||||
// which the console uses for colour + the auto-switch-to-errors filter.
|
||||
// streamedLive tells it not to reprint the stdout shown above.
|
||||
const tailLogs = tailAfterStream(result.stdout, lastStreamedLen, boardTarget);
|
||||
// After the build settles, append the structured analysis on top of
|
||||
// the live stream — parseCompileResult highlights FAILED blocks and
|
||||
// tags compiler errors with type='error', which the console uses for
|
||||
// colour + the auto-switch-to-errors filter. streamedLive tells it not
|
||||
// to reprint the stdout the stream (final 'done' flush included)
|
||||
// already showed.
|
||||
const resultLogs = parseCompileResult(result, boardLabel, boardTarget, lastStreamedLen > 0);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...tailLogs, ...resultLogs]);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]);
|
||||
|
||||
if (result.success) {
|
||||
const program = result.hex_content ?? result.binary_content ?? null;
|
||||
|
|
@ -1080,9 +1080,8 @@ export const EditorToolbar = ({
|
|||
{ boardOptions: board.boardOptions, spiffsFiles: board.spiffsFiles, libraries: board.libraries?.length ? board.libraries : null, language: board.languageMode === 'espidf' ? 'espidf' : undefined },
|
||||
);
|
||||
|
||||
const tailLogs = tailAfterStream(result.stdout, lastStreamedLen, boardTarget);
|
||||
const resultLogs = parseCompileResult(result, label, boardTarget, lastStreamedLen > 0);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...tailLogs, ...resultLogs]);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]);
|
||||
|
||||
if (result.success) {
|
||||
const program = result.hex_content ?? result.binary_content ?? null;
|
||||
|
|
|
|||
|
|
@ -56,12 +56,15 @@ interface CompileStatusResponse {
|
|||
|
||||
/**
|
||||
* Live progress callback — called on every poll while state ∈ {pending,
|
||||
* running}. `stdout` is the full live cmake + ninja output captured so far
|
||||
* (cap of ~256 KB on the server side, tail kept). Caller can compute a
|
||||
* delta against the previous call if it wants to append-only render.
|
||||
* running}, plus one final call with state 'done' carrying the complete
|
||||
* buffer (the lines that landed between the last running-poll and job
|
||||
* completion would otherwise never be delivered). `stdout` is the full live
|
||||
* cmake + ninja output captured so far (cap of ~256 KB on the server side,
|
||||
* tail kept). Caller can compute a delta against the previous call if it
|
||||
* wants to append-only render.
|
||||
*/
|
||||
export type CompileProgress = (info: {
|
||||
state: 'pending' | 'running';
|
||||
state: 'pending' | 'running' | 'done';
|
||||
stdout: string;
|
||||
elapsedSeconds: number;
|
||||
}) => void;
|
||||
|
|
@ -172,6 +175,15 @@ export async function compileCode(
|
|||
if (status.state === 'done' && status.result) {
|
||||
const elapsed = Math.round((Date.now() - startedAt) / 1000);
|
||||
console.log(`[compile] job ${jobId} done in ${elapsed}s`);
|
||||
// Final flush: the buffer grew between the last running-poll and
|
||||
// completion (esptool + binary-size lines usually live there).
|
||||
if (onProgress) {
|
||||
try {
|
||||
onProgress({ state: 'done', stdout: status.stdout || '', elapsedSeconds: elapsed });
|
||||
} catch (err) {
|
||||
console.warn('[compile] onProgress threw:', err);
|
||||
}
|
||||
}
|
||||
return status.result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,28 +46,6 @@ export function isNoiseBuildLine(line: string): boolean {
|
|||
return NOISE_LINE_PATTERNS.some((re) => re.test(stripped));
|
||||
}
|
||||
|
||||
/** Lines of result.stdout past `streamedLen` — the tail that lands between
|
||||
* the last live-status poll and job completion, which the polling loop never
|
||||
* delivers (esptool output + the binary-size summary usually live there).
|
||||
* Skipped when the backend's live buffer hit its 256 KB tail-trim cap: past
|
||||
* that point buffer offsets no longer line up with the full stdout, and a
|
||||
* slightly short log beats a misaligned one. */
|
||||
export function tailAfterStream(
|
||||
stdout: string | undefined,
|
||||
streamedLen: number,
|
||||
target?: CompileTarget,
|
||||
): CompilationLog[] {
|
||||
const BUFFER_CAP = 262_144;
|
||||
if (!stdout || streamedLen <= 0 || streamedLen >= BUFFER_CAP) return [];
|
||||
if (stdout.length <= streamedLen) return [];
|
||||
const now = new Date();
|
||||
return stdout
|
||||
.slice(streamedLen)
|
||||
.split('\n')
|
||||
.filter((s) => s.trim() && !isNoiseBuildLine(s))
|
||||
.map((message) => ({ timestamp: now, type: 'info' as const, message, target }));
|
||||
}
|
||||
|
||||
export function parseCompileResult(
|
||||
result: CompileResult,
|
||||
board: string,
|
||||
|
|
|
|||
Loading…
Reference in New Issue