Skip to content

Commit 699945d

Browse files
ozgesolidkeyclaude
andcommitted
Canvas minimap: adaptive density (up to 10k buckets) + GPU-rendered heatmap
- Analyzer: DENSITY_BUCKETS now adaptive based on file size (max 10,000) vs fixed 200 — 50x better resolution at same O(N) cost - Minimap: replaced DOM density strip with <canvas> + ImageData.putImageData() — GPU-rendered, O(canvas_height) render regardless of file size - Compare: removed redundant + button, added Compare button that opens two files side by side with a three-panel comparison header: File A minimap | pixel-diff strip (bright = different) | File B minimap - Diff strip: normalised bucket comparison, error-weighted — bright red where error density differs, dark where files have similar patterns Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 142d428 commit 699945d

7 files changed

Lines changed: 336 additions & 12 deletions

File tree

src/main/analyzers/columnAwareAnalyzer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ export class ColumnAwareAnalyzer implements LogAnalyzer {
6565
error: 0, warning: 0, info: 0, debug: 0, trace: 0
6666
};
6767

68-
// Density buckets — 200 buckets keyed by byte position
68+
// Density buckets — adaptive count based on file size (500–10,000)
6969
// Used by the minimap to draw a heat map by log level
70-
const DENSITY_BUCKETS = 200;
70+
const DENSITY_BUCKETS = Math.min(Math.max(Math.ceil(fileSize / 500), 500), 10000);
7171
const densityError = new Uint32Array(DENSITY_BUCKETS);
7272
const densityWarning = new Uint32Array(DENSITY_BUCKETS);
7373
const densityInfo = new Uint32Array(DENSITY_BUCKETS);

src/main/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4123,6 +4123,27 @@ ipcMain.handle('analyze-file', async (_, analyzerName?: string, options?: Analyz
41234123
}
41244124
});
41254125

4126+
// Run analysis on a specific file path (used by compare feature)
4127+
ipcMain.handle('analyze-file-path', async (_, filePath: string) => {
4128+
if (!filePath) {
4129+
return { success: false, error: 'No file path provided' };
4130+
}
4131+
4132+
const analyzer = analyzerRegistry.getDefault();
4133+
if (!analyzer) {
4134+
return { success: false, error: 'Analyzer not found' };
4135+
}
4136+
4137+
const compareSignal = { cancelled: false };
4138+
try {
4139+
const result = await analyzer.analyze(filePath, {}, undefined, compareSignal);
4140+
cacheAnalysisResult(filePath, result);
4141+
return { success: true, result };
4142+
} catch (error) {
4143+
return { success: false, error: String(error) };
4144+
}
4145+
});
4146+
41264147
// Cancel analysis
41274148
ipcMain.handle('cancel-analysis', async () => {
41284149
analyzeSignal.cancelled = true;

src/preload/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ const api = {
234234
analyzeFile: (analyzerName?: string, options?: any): Promise<{ success: boolean; result?: any; error?: string }> =>
235235
ipcRenderer.invoke('analyze-file', analyzerName, options),
236236

237+
analyzeFilePath: (filePath: string): Promise<{ success: boolean; result?: any; error?: string }> =>
238+
ipcRenderer.invoke('analyze-file-path', filePath),
239+
237240
cancelAnalysis: (): Promise<{ success: boolean }> =>
238241
ipcRenderer.invoke('cancel-analysis'),
239242

src/renderer/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
</div>
4242
<div id="tabs-container" class="tabs-container"></div>
4343
<div class="tab-bar-right">
44-
<button id="btn-new-tab" class="tab-bar-btn" title="Open new file">+</button>
44+
<button id="btn-compare" class="tab-bar-btn" title="Compare two log files (Ctrl+Shift+C)">
45+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="9" height="18" rx="1"/><rect x="13" y="3" width="9" height="18" rx="1"/></svg>
46+
</button>
4547
<div class="tab-bar-separator"></div>
4648
<button id="btn-search-toggle" class="tab-bar-btn" title="Search (Ctrl+F)">
4749
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>

0 commit comments

Comments
 (0)