You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add notes drawer, bookmark colors, scroll fixes, and engineering cleanup
- Notes drawer overlay (Ctrl+Shift+N): slide-up panel with auto-save
- Bookmark color palette and improved bookmark modal
- Long lines warning with format suggestion on slow scroll detection
- Horizontal trackpad scroll support in log viewer
- Replace fragile setTimeout animations with transitionend events
- Fix transitionend/fallback race condition in overlay hide
- Add console.warn to silent catch blocks for debuggability
- Store terminal.onData disposable for symmetric cleanup
- Guard tab cycling against findIndex returning -1
- Unify highlight creation via shared commitHighlight()
- Replace hardcoded width estimation with measured character width
- Analyzer improvements for column-aware, drain, and rule-based modes
- Add tech debt documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Known issues that aren't urgent but should be addressed as the codebase grows.
4
+
5
+
## Renderer (`src/renderer/renderer.ts`)
6
+
7
+
### Global Mutable State Without Protection
8
+
9
+
**Severity**: Medium | **Effort**: Large
10
+
11
+
The renderer uses ~30+ mutable global variables (`state`, `terminal`, `fitAddon`, `splitDiffState`, `zoomLevel`, etc.) with no encapsulation. Any function can mutate any state, making it hard to trace bugs.
12
+
13
+
**What to do**: Introduce a state management layer — at minimum a centralized state object with accessor functions that validate mutations. A full reactive/reducer pattern would be ideal but is a significant rewrite.
14
+
15
+
### Duplicated Modal Pattern
16
+
17
+
**Severity**: Low | **Effort**: Medium
18
+
19
+
Multiple modals (highlight modal, bookmark modal, rename modal, etc.) each implement their own promise-based show/hide pattern with `pendingResolve` variables. The pattern is copy-pasted across each modal type.
20
+
21
+
**What to do**: Create a generic `showModal<T>(element, setup): Promise<T | null>` helper that handles the promise lifecycle, backdrop clicks, Escape key, and resolve/reject. Each modal specializes only its content and result extraction.
22
+
23
+
### Path Comparison via String Equality
24
+
25
+
**Severity**: Low | **Effort**: Small
26
+
27
+
File paths are compared with `===` throughout (e.g., `file.path === state.filePath`). This can fail with path normalization differences, trailing slashes, symlinks, or mixed separators on Windows.
28
+
29
+
**What to do**: Normalize all paths on entry (e.g., when files are opened) and use a `pathsEqual()` utility for comparisons. Electron's `path` module handles cross-platform normalization.
30
+
31
+
### `void offsetHeight` Reflow Hacks
32
+
33
+
**Severity**: Low | **Effort**: Small
34
+
35
+
Two places use `void overlay.offsetHeight` to force a browser reflow before adding a CSS class, so that CSS transitions trigger from the initial state. This is a well-known browser pattern but is fragile — future CSS changes could make the reflow unnecessary or insufficient.
36
+
37
+
**What to do**: These are acceptable for now. If they become problematic, replace with a double-`requestAnimationFrame` pattern or use the Web Animations API.
38
+
39
+
### Feature Coupling: Word Wrap and Markdown Preview
40
+
41
+
**Severity**: Low | **Effort**: Small
42
+
43
+
`wordWrapEnabled` boolean is checked in both the word-wrap toggle and markdown preview code paths. These are separate features that share a rendering concern (line wrapping) but aren't the same thing.
44
+
45
+
**What to do**: If markdown preview evolves to need different wrapping behavior, split into separate state flags.
46
+
47
+
### Mutation of Filter Rules During Render
48
+
49
+
**Severity**: Low | **Effort**: Medium
50
+
51
+
When filter rule types change (e.g., switching from text to level), `updateFilterRule()` mutates state and triggers `renderAdvancedFilterUI()` inline. If another state change happens during that render cycle, the UI can desync.
52
+
53
+
**What to do**: Batch filter state mutations and render once at the end of the current event loop tick (e.g., via `queueMicrotask`).
54
+
55
+
### Context Menu `setTimeout(0)` for Click-Outside
56
+
57
+
**Severity**: Low | **Effort**: Small
58
+
59
+
Line ~3422 uses `setTimeout(() => document.addEventListener('click', closeMenu), 0)` to defer adding the click-outside handler until after the current click event finishes. This works but is a timing-based workaround.
60
+
61
+
**What to do**: Use `{ once: true }` on the originating event or `pointer-events` CSS to prevent the immediate re-trigger, removing the need for the setTimeout.
0 commit comments