@fresh-editor/fresh-editor 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/package.json +1 -1
- package/plugins/config-schema.json +39 -5
- package/plugins/diff_nav.ts +20 -1
- package/plugins/flash.ts +11 -3
- package/plugins/live_diff.i18n.json +450 -0
- package/plugins/live_diff.ts +946 -0
- package/plugins/schemas/theme.schema.json +48 -0
- package/plugins/theme_editor.i18n.json +112 -0
- package/plugins/tsconfig.json +1 -0
- package/themes/dark.json +2 -0
- package/themes/dracula.json +2 -0
- package/themes/high-contrast.json +2 -0
- package/themes/light.json +2 -0
- package/themes/nord.json +2 -0
- package/themes/nostalgia.json +2 -0
- package/themes/solarized-dark.json +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **Live Diff plugin** (experimental): Unified-diff overlay rendered live in the editable buffer. If your file is unmodified in the editor, it updates as the file changes on disk when auto-revert kicks in - great for watching an agent edit your file. Opt-in via `Live Diff: Toggle (Global)` / `Live Diff: Toggle (Buffer)`. Reference selectable per buffer: `vs HEAD` / `vs Disk` / `vs Branch...` / `vs Default Branch`.
|
|
8
|
+
|
|
9
|
+
* **New Startup section in Settings** (open Settings and search "Startup") groups everything that fires on launch:
|
|
10
|
+
- **Blank-workspace flow** (#1753) — *Auto Create Empty Buffer On Last Buffer Close* (Editor) and *Auto Open On Last Buffer Close* (File Explorer). With both off, closing the last buffer leaves a truly blank pane (no `[No Name]`, no gutter, no `~`); buffer-specific status-bar items and menu entries are suppressed, and a subdued centered hint shows the keys to escape (`Ctrl+P` / `Ctrl+O` / `Ctrl+E`).
|
|
11
|
+
- *Skip Session Restore When Files Passed* — `fresh src/main.rs` opens just that file; bare `fresh` and `fresh some/dir` still restore. Hot-exit recovery still runs. `--restore` overrides.
|
|
12
|
+
- *Restore Previous Session* (existing, moved into Startup).
|
|
13
|
+
|
|
14
|
+
* **File explorer side** (thanks @paveloparev!): *Side* under File Explorer in Settings — left or right.
|
|
15
|
+
|
|
16
|
+
* **Prompt Line now hidden by default**: *Show Prompt Line* now defaults off — the prompt line only appears while a prompt is active. Turn it back on via Settings.
|
|
17
|
+
|
|
18
|
+
* **Mark mode preserved through Go to Line** so you can extend selections across the jump. Use **Set Mark** command followed by **Goto Line** to start a selection and extend it to the target line.
|
|
19
|
+
|
|
20
|
+
* **Copy File Path commands**: New commands: "Copy File Path" and "Copy Relative File Path" to copy current buffer's path to your clipboard. Also available by right-clicking on a tab name.
|
|
21
|
+
|
|
22
|
+
* **CLI Help Localization**: The `--help` output is now fully localized using runtime i18n lookups.
|
|
23
|
+
|
|
24
|
+
* **Relative +/- Goto Line**: Infers absolute vs relative jumps from a leading sign (e.g., `:+10` jumps 10 lines down, `:10` jumps to line 10).
|
|
25
|
+
|
|
26
|
+
* **Rust Toolchain Update**: Updated to Rust 1.95 in `rust-toolchain.toml` to fix compatibility issues with newer LLVM/clang versions on systems like Arch Linux (#1782).
|
|
27
|
+
|
|
28
|
+
### Improvements
|
|
29
|
+
|
|
30
|
+
* **Plugin loading deferred off the boot critical path** — another ~225 ms saved. Same load order, same hooks, just async.
|
|
31
|
+
|
|
32
|
+
* **Popup focus**: LSP popups that auto-show on file open (status popup, hover, signature help, plugin Text overlays) no longer steal the next keystroke. They show unfocused with an `[Alt+T to focus]` hint; user-invoked popups (Completion, code actions, status-bar `{remote}`, LSP-status menu) still grab focus on show. Settings / Menu / Prompt modals take precedence over unfocused buffer popups for `Esc` / `popup_focus`.
|
|
33
|
+
|
|
34
|
+
* **Status Bar visual integration** (#1711): The "Palette: Ctrl+P" hint and "LSP (on)" indicator now blend into the status bar by default. Built-in themes have been updated with coherent prominent colors for these indicators.
|
|
35
|
+
|
|
36
|
+
* **Prompt interaction and scrolling** (#1660):
|
|
37
|
+
- Minimal scrolling: the suggestion list no longer recenters the selection on every move, preventing "row jumping" during navigation.
|
|
38
|
+
- Clicks no longer cause accidental list shifts; double-click correctly confirms selections.
|
|
39
|
+
- Preview-on-click supported for "Reload with encoding".
|
|
40
|
+
|
|
41
|
+
* **Global Menu Bar**: "Toggle Menu Bar" state is now persisted globally across all workspaces.
|
|
42
|
+
|
|
43
|
+
* **Windows integration**: High-quality app icon applied to the running window; app manifest and version info embedded in the binary.
|
|
44
|
+
|
|
45
|
+
### Bug Fixes
|
|
46
|
+
|
|
47
|
+
* **Windows subprocesses**: Transient console windows are now hidden when spawning subprocesses (e.g., formatters, linters).
|
|
48
|
+
|
|
49
|
+
* **Terminal CWD**: Fixed shell spawning failure on Windows when the current directory has a `\\?\` UNC prefix.
|
|
50
|
+
|
|
51
|
+
* **Live Diff stability**: Fixed crashes on surrogate-pair content (emojis) and corrected gutter rendering for empty lines inside added blocks.
|
|
52
|
+
|
|
53
|
+
### Under the Hood
|
|
54
|
+
|
|
55
|
+
* **Syntax Highlight Caching**: New multi-phase caching system (memoised scope lookups and whole-file cache for small files) significantly reduces CPU usage during rendering.
|
|
56
|
+
|
|
3
57
|
## 0.3.1
|
|
4
58
|
|
|
5
59
|
### Features
|
package/package.json
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"{palette}"
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
|
-
"show_prompt_line":
|
|
66
|
+
"show_prompt_line": false,
|
|
67
67
|
"show_vertical_scrollbar": true,
|
|
68
68
|
"show_horizontal_scrollbar": false,
|
|
69
69
|
"show_tilde": true,
|
|
@@ -103,6 +103,8 @@
|
|
|
103
103
|
"auto_save_interval_secs": 30,
|
|
104
104
|
"hot_exit": true,
|
|
105
105
|
"restore_previous_session": true,
|
|
106
|
+
"skip_session_restore_when_files_passed": true,
|
|
107
|
+
"auto_create_empty_buffer_on_last_buffer_close": true,
|
|
106
108
|
"recovery_enabled": true,
|
|
107
109
|
"auto_recovery_save_interval_secs": 2,
|
|
108
110
|
"auto_revert_poll_interval_ms": 2000,
|
|
@@ -128,7 +130,9 @@
|
|
|
128
130
|
"show_gitignored": false,
|
|
129
131
|
"custom_ignore_patterns": [],
|
|
130
132
|
"width": "30%",
|
|
131
|
-
"preview_tabs": true
|
|
133
|
+
"preview_tabs": true,
|
|
134
|
+
"side": "left",
|
|
135
|
+
"auto_open_on_last_buffer_close": true
|
|
132
136
|
}
|
|
133
137
|
},
|
|
134
138
|
"file_browser": {
|
|
@@ -389,9 +393,9 @@
|
|
|
389
393
|
"x-section": "Status Bar"
|
|
390
394
|
},
|
|
391
395
|
"show_prompt_line": {
|
|
392
|
-
"description": "Whether the prompt line is visible
|
|
396
|
+
"description": "Whether the prompt line is always visible.\nThe prompt line is the bottom-most line used for search, file open, and other prompts.\nWhen `false` (the default), the prompt line auto-hides — it only appears\nwhile a prompt is active and disappears again once the prompt closes.\nWhen `true`, the prompt line is always reserved at the bottom of the screen.\nDefault: false",
|
|
393
397
|
"type": "boolean",
|
|
394
|
-
"default":
|
|
398
|
+
"default": false,
|
|
395
399
|
"x-section": "Display"
|
|
396
400
|
},
|
|
397
401
|
"show_vertical_scrollbar": {
|
|
@@ -643,7 +647,19 @@
|
|
|
643
647
|
"description": "Whether to auto-open previously opened files (session restore) when\nstarting Fresh in a directory. When enabled (the default), tabs,\nsplits, cursor positions and the file explorer state are restored\nfrom the last clean exit in the same working directory. When\ndisabled, Fresh starts with a clean workspace. The workspace file\non disk is still written on exit, so re-enabling this setting picks\nup whatever state was saved at the most recent clean exit. The\n`--no-restore` CLI flag is a stronger override: it skips both\nrestoring and saving the workspace.\nDefault: true",
|
|
644
648
|
"type": "boolean",
|
|
645
649
|
"default": true,
|
|
646
|
-
"x-section": "
|
|
650
|
+
"x-section": "Startup"
|
|
651
|
+
},
|
|
652
|
+
"skip_session_restore_when_files_passed": {
|
|
653
|
+
"description": "When Fresh is launched with one or more file arguments (e.g.\n`fresh src/main.rs README.md`), skip the workspace session restore\nand open only the files passed on the command line. Hot-exit\ncontent (unsaved modified files and unnamed `[No Name]` buffers\nwith content) is still restored so in-progress work is never lost.\nPure-directory invocations (`fresh some/dir`) and bare invocations\n(`fresh` with no args) still restore the previous session normally.\nDisable this option to keep the legacy behavior of always\nrestoring the previous session even when files are passed.\nDefault: true",
|
|
654
|
+
"type": "boolean",
|
|
655
|
+
"default": true,
|
|
656
|
+
"x-section": "Startup"
|
|
657
|
+
},
|
|
658
|
+
"auto_create_empty_buffer_on_last_buffer_close": {
|
|
659
|
+
"description": "Whether to auto-create a fresh empty `[No Name]` buffer when the\nlast open buffer is closed. When `false`, the editor still creates\nan internal placeholder buffer (it always needs at least one) but\nhides it from the tab bar so the workspace looks blank. Combined\nwith `file_explorer.auto_open_on_last_buffer_close = false`, this\ngives a fully blank workspace where nothing opens automatically.\nDefault: true",
|
|
660
|
+
"type": "boolean",
|
|
661
|
+
"default": true,
|
|
662
|
+
"x-section": "Startup"
|
|
647
663
|
},
|
|
648
664
|
"recovery_enabled": {
|
|
649
665
|
"description": "Whether to enable file recovery (Emacs-style auto-save)\nWhen enabled, buffers are periodically saved to recovery files\nso they can be recovered if the editor crashes.",
|
|
@@ -918,6 +934,16 @@
|
|
|
918
934
|
"description": "Open files in a \"preview\" (ephemeral) tab on single-click in the\nfile explorer. The preview tab is replaced by the next single-click\ninstead of accumulating tabs. Editing the file, double-clicking\n(or pressing Enter) on it in the explorer, or dragging its tab\npromotes the tab to a permanent tab.\nDefault: true",
|
|
919
935
|
"type": "boolean",
|
|
920
936
|
"default": true
|
|
937
|
+
},
|
|
938
|
+
"side": {
|
|
939
|
+
"description": "Which side of the screen to show the file explorer on.\nDefault: left",
|
|
940
|
+
"$ref": "#/$defs/FileExplorerSide",
|
|
941
|
+
"default": "left"
|
|
942
|
+
},
|
|
943
|
+
"auto_open_on_last_buffer_close": {
|
|
944
|
+
"description": "Automatically focus the file explorer when the last buffer is\nclosed. Set to `false` for a \"blank workspace\" workflow where\nnothing opens automatically and the user explicitly invokes the\nfile explorer (e.g. via keybinding or command palette).\nDefault: true",
|
|
945
|
+
"type": "boolean",
|
|
946
|
+
"default": true
|
|
921
947
|
}
|
|
922
948
|
}
|
|
923
949
|
},
|
|
@@ -926,6 +952,14 @@
|
|
|
926
952
|
"type": "string",
|
|
927
953
|
"pattern": "^(100%|[1-9]?[0-9]%|\\d+)$"
|
|
928
954
|
},
|
|
955
|
+
"FileExplorerSide": {
|
|
956
|
+
"description": "Side placement for the file explorer panel.",
|
|
957
|
+
"type": "string",
|
|
958
|
+
"enum": [
|
|
959
|
+
"left",
|
|
960
|
+
"right"
|
|
961
|
+
]
|
|
962
|
+
},
|
|
929
963
|
"FileBrowserConfig": {
|
|
930
964
|
"description": "File browser configuration (for Open File dialog)",
|
|
931
965
|
"type": "object",
|
package/plugins/diff_nav.ts
CHANGED
|
@@ -22,6 +22,13 @@ interface DiffHunk {
|
|
|
22
22
|
lineCount: number;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** Hunk shape published by live_diff.ts on `live_diff_hunks` view state. */
|
|
26
|
+
interface LiveDiffHunk {
|
|
27
|
+
kind: "added" | "removed" | "modified";
|
|
28
|
+
newStart: number; // 0-indexed
|
|
29
|
+
newCount: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
/** A jump target with a byte position for sorting/deduplication */
|
|
26
33
|
interface JumpTarget {
|
|
27
34
|
bytePos: number;
|
|
@@ -47,7 +54,19 @@ async function collectTargets(bid: number): Promise<JumpTarget[]> {
|
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
// Source 2:
|
|
57
|
+
// Source 2: live-diff hunks (head/disk/branch comparison from live_diff.ts)
|
|
58
|
+
const liveHunks = editor.getViewState(bid, "live_diff_hunks") as LiveDiffHunk[] | null;
|
|
59
|
+
if (liveHunks && liveHunks.length > 0) {
|
|
60
|
+
for (const hunk of liveHunks) {
|
|
61
|
+
const line = Math.max(0, hunk.newStart);
|
|
62
|
+
const pos = await editor.getLineStartPosition(line);
|
|
63
|
+
if (pos !== null) {
|
|
64
|
+
targets.push({ bytePos: pos, line });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Source 3: saved-diff (unsaved changes)
|
|
51
70
|
const diff = editor.getBufferSavedDiff(bid);
|
|
52
71
|
if (diff && !diff.equal) {
|
|
53
72
|
for (const [start, _end] of diff.byte_ranges) {
|
package/plugins/flash.ts
CHANGED
|
@@ -493,10 +493,19 @@ async function flashJump(): Promise<void> {
|
|
|
493
493
|
// enough to survive status-bar truncation. Includes the current
|
|
494
494
|
// pattern so tests (and careful users) can confirm the plugin has
|
|
495
495
|
// accepted each typed key.
|
|
496
|
+
//
|
|
497
|
+
// The banner doubles as a synchronization barrier for tests: as long
|
|
498
|
+
// as setStatus runs AFTER redraw within the same loop iteration, any
|
|
499
|
+
// observer that sees `Flash[<pattern>]` on screen is guaranteed to
|
|
500
|
+
// also see the conceals/labels for that same pattern — they were
|
|
501
|
+
// committed in the redraw immediately before. Setting the banner
|
|
502
|
+
// earlier (e.g. in the keypress handler before `continue`) breaks
|
|
503
|
+
// this invariant: the new banner reaches the screen while the
|
|
504
|
+
// previous iteration's conceals are still painted, so a renderer
|
|
505
|
+
// tick in that window shows banner=N with conceals=N-1.
|
|
496
506
|
const setStatusForPattern = (): void => {
|
|
497
507
|
editor.setStatus("Flash[" + state.pattern + "]");
|
|
498
508
|
};
|
|
499
|
-
setStatusForPattern();
|
|
500
509
|
|
|
501
510
|
try {
|
|
502
511
|
while (true) {
|
|
@@ -522,6 +531,7 @@ async function flashJump(): Promise<void> {
|
|
|
522
531
|
if (m.label) state.prevLabelByKey.set(matchKey(m), m.label);
|
|
523
532
|
}
|
|
524
533
|
redraw(state.matches, views);
|
|
534
|
+
setStatusForPattern();
|
|
525
535
|
|
|
526
536
|
const ev = await editor.getNextKey();
|
|
527
537
|
|
|
@@ -538,7 +548,6 @@ async function flashJump(): Promise<void> {
|
|
|
538
548
|
if (state.pattern.length > 0) {
|
|
539
549
|
state.pattern = state.pattern.slice(0, -1);
|
|
540
550
|
}
|
|
541
|
-
setStatusForPattern();
|
|
542
551
|
continue;
|
|
543
552
|
}
|
|
544
553
|
|
|
@@ -551,7 +560,6 @@ async function flashJump(): Promise<void> {
|
|
|
551
560
|
break;
|
|
552
561
|
}
|
|
553
562
|
state.pattern += ev.key;
|
|
554
|
-
setStatusForPattern();
|
|
555
563
|
continue;
|
|
556
564
|
}
|
|
557
565
|
|