diff --git a/frontend/src/components/editor/EditorToolbar.tsx b/frontend/src/components/editor/EditorToolbar.tsx index ef45c420..604a7893 100644 --- a/frontend/src/components/editor/EditorToolbar.tsx +++ b/frontend/src/components/editor/EditorToolbar.tsx @@ -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 } 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'; @@ -551,7 +551,9 @@ export const EditorToolbar = ({ if (stdout.length <= lastStreamedLen) return; const delta = stdout.slice(lastStreamedLen); lastStreamedLen = stdout.length; - const newLines = delta.split('\n').filter((s) => s.trim()); + const newLines = delta + .split('\n') + .filter((s) => s.trim() && !isNoiseBuildLine(s)); if (!newLines.length) return; const now = new Date(); setCompileLogs((prev: CompilationLog[]) => [ @@ -581,8 +583,9 @@ export const EditorToolbar = ({ // 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. - const resultLogs = parseCompileResult(result, boardLabel, boardTarget); + // colour + the auto-switch-to-errors filter. streamedLive tells it not + // to reprint the stdout the stream above already showed. + const resultLogs = parseCompileResult(result, boardLabel, boardTarget, lastStreamedLen > 0); setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]); if (result.success) { @@ -1057,7 +1060,9 @@ export const EditorToolbar = ({ if (stdout.length <= lastStreamedLen) return; const delta = stdout.slice(lastStreamedLen); lastStreamedLen = stdout.length; - const newLines = delta.split('\n').filter((s) => s.trim()); + const newLines = delta + .split('\n') + .filter((s) => s.trim() && !isNoiseBuildLine(s)); if (!newLines.length) return; const now = new Date(); setCompileLogs((prev: CompilationLog[]) => [ @@ -1074,7 +1079,7 @@ export const EditorToolbar = ({ { boardOptions: board.boardOptions, spiffsFiles: board.spiffsFiles, libraries: board.libraries?.length ? board.libraries : null, language: board.languageMode === 'espidf' ? 'espidf' : undefined }, ); - const resultLogs = parseCompileResult(result, label, boardTarget); + const resultLogs = parseCompileResult(result, label, boardTarget, lastStreamedLen > 0); setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]); if (result.success) { diff --git a/frontend/src/utils/compilationLogger.ts b/frontend/src/utils/compilationLogger.ts index 0a3cf92a..6b169b07 100644 --- a/frontend/src/utils/compilationLogger.ts +++ b/frontend/src/utils/compilationLogger.ts @@ -21,10 +21,40 @@ export interface CompilationLog { target?: CompileTarget; } +/** Build-system chatter with no signal for the user: CMake configure status, + * git-metadata probes inside the build container (the tree is a synthesized + * project, never a git repo — those "fatal:" lines are expected), IDF + * component-manager dependency solving, Python env checks. The full log is + * still available server-side; the console only drops these lines. */ +const NOISE_LINE_PATTERNS: RegExp[] = [ + /^-- /, // CMake configure status lines + /^fatal: not a git repository/, + /^Stopping at filesystem boundary/, + /^\.*NOTE: /, // IDF component manager (incl. leading progress dots) + /^warning: unknown kconfig symbol/, + /^Loading defaults file /, + /^Constraint file: /, + /^Requirement files:/, + /^- \/.*requirements[^ ]*\.txt$/, + /^Python being checked: /, + /^Python requirements are satisfied\.?$/, + /Project commit: HEAD-HASH-NOTFOUND/, +]; + +export function isNoiseBuildLine(line: string): boolean { + const stripped = line.trim(); + return NOISE_LINE_PATTERNS.some((re) => re.test(stripped)); +} + export function parseCompileResult( result: CompileResult, board: string, target?: CompileTarget, + /** True when the caller already streamed the live cmake+ninja output into + * the console while the build ran. Skips re-printing result.stdout on + * success, and on failure re-emits only the error/warning lines (for the + * red/yellow highlighting the plain live stream lacked). */ + streamedLive = false, ): CompilationLog[] { const logs: CompilationLog[] = []; const now = new Date(); @@ -40,8 +70,10 @@ export function parseCompileResult( } } - // stdout — for ESP-IDF/ninja builds, compiler errors appear here - if (result.stdout) { + // stdout — for ESP-IDF/ninja builds, compiler errors appear here. + // When the live stream already showed it, a successful build has nothing + // left to say here (re-printing would duplicate the whole log). + if (result.stdout && !(streamedLive && result.success)) { let inFailedBlock = false; for (const line of result.stdout.split('\n')) { if (!line.trim()) continue; @@ -71,6 +103,8 @@ export function parseCompileResult( } else { type = 'info'; } + if (type === 'info' && (streamedLive || isNoiseBuildLine(stripped))) continue; + if (type === 'warning' && isNoiseBuildLine(stripped)) continue; logs.push({ timestamp: now, type, message: line }); } } @@ -79,6 +113,7 @@ export function parseCompileResult( if (result.stderr) { for (const line of result.stderr.split('\n')) { if (!line.trim()) continue; + if (isNoiseBuildLine(line)) continue; let type: CompilationLog['type'] = 'error'; const lower = line.toLowerCase(); if (lower.includes('warning:') || lower.includes('warn ')) { @@ -96,6 +131,9 @@ export function parseCompileResult( ) { type = 'info'; } + // Live-streamed builds already showed the chatter; only re-emit lines + // that gain something from re-classification (red/yellow markers). + if (type === 'info' && streamedLive) continue; logs.push({ timestamp: now, type, message: line }); } }