@fresh-editor/fresh-editor 0.3.6 → 0.3.7
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 +91 -0
- package/package.json +1 -1
- package/plugins/audit_mode.i18n.json +84 -0
- package/plugins/audit_mode.ts +139 -3
- package/plugins/config-schema.json +27 -3
- package/plugins/dashboard.ts +18 -18
- package/plugins/flash.ts +22 -4
- package/plugins/git_blame.ts +10 -6
- package/plugins/git_log.ts +534 -124
- package/plugins/git_statusbar.i18n.json +72 -0
- package/plugins/git_statusbar.ts +133 -0
- package/plugins/lib/fresh.d.ts +305 -6
- package/plugins/lib/widgets.ts +111 -4
- package/plugins/live_diff.ts +156 -41
- package/plugins/merge_conflict.ts +89 -64
- package/plugins/orchestrator.ts +1982 -242
- package/plugins/pkg.ts +1 -1
- package/plugins/schemas/theme.schema.json +14 -0
- package/plugins/search_replace.i18n.json +140 -28
- package/plugins/search_replace.ts +674 -117
- package/plugins/tab_actions.i18n.json +212 -0
- package/plugins/tab_actions.ts +76 -0
- package/plugins/theme_editor.i18n.json +28 -0
- package/plugins/tsconfig.json +1 -0
- package/plugins/vi_mode.ts +11 -0
- package/themes/dark.json +1 -0
- package/themes/dracula.json +1 -0
- package/themes/high-contrast.json +1 -0
- package/themes/light.json +1 -0
- package/themes/nord.json +1 -0
- package/themes/nostalgia.json +1 -0
- package/themes/solarized-dark.json +1 -0
- package/themes/terminal.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,96 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## 0.3.7
|
|
4
|
+
|
|
5
|
+
Introduces an experimental **multi-window orchestrator** command (`Alt+Q`) - a UI that manages multiple Fresh windows side by side in a single Fresh process.
|
|
6
|
+
|
|
7
|
+
### Features / Improvements
|
|
8
|
+
|
|
9
|
+
#### Orchestrator (early experiment)
|
|
10
|
+
|
|
11
|
+
The new orchestrator command (`Alt+Q`) lets one Fresh process juggle several independent windows — switch between sessions, open new ones from a project path / branch, or visit one in a separate Fresh process. This is an early experiment; expect rough edges. Please share your ideas and bug reports!
|
|
12
|
+
|
|
13
|
+
#### Search and Replace
|
|
14
|
+
|
|
15
|
+
Made an effort to improve the search & replace command, tackling several issues:
|
|
16
|
+
|
|
17
|
+
* **All Files** scope toggle + dedicated current-file command.
|
|
18
|
+
* Editor shortcuts (`Ctrl+P` etc.) pass through the panel.
|
|
19
|
+
* Proper empty / searching / no-results states.
|
|
20
|
+
* Large result sets stay responsive — incremental tree, throttled streaming, capped per-iteration work.
|
|
21
|
+
|
|
22
|
+
#### Git Log / Review Diff
|
|
23
|
+
|
|
24
|
+
* **Performance**: Per-commit diffs **stream into file-backed buffers** with full syntax highlighting, per-line add/delete backgrounds, working scrollbar, and `Fold by File` / `Fold by Hunk` commands. Now opens the famous "rewrite bun in rust" commit instantly!
|
|
25
|
+
* **Open file at commit** (#1962): jump from a diff line in the review-branch detail panel to the file at that commit (read-only, `q` to go back).
|
|
26
|
+
|
|
27
|
+
#### File Explorer
|
|
28
|
+
|
|
29
|
+
* **Compact directories** (#1406, thanks @Nandaleio!): a directory containing a single child directory renders inline as `com.example.name`, VSCode/IntelliJ-style. On by default; toggle with `file_explorer.compact_directories`.
|
|
30
|
+
* **Configurable tree indicators** (#1940, reported by @MicTheSquid): expand/collapse glyphs themable via *File Explorer → Tree Indicator Expanded / Collapsed* in the Settings UI.
|
|
31
|
+
|
|
32
|
+
#### Plugins & API
|
|
33
|
+
|
|
34
|
+
* **`git_statusbar` plugin + status-bar token registration API** (thanks @PavelLoparev!): show the current git branch in the status bar; plugins register their own tokens via `editor.registerStatusBarElement`. Add via *Settings → Editor → Status Bar → Left / Right*.
|
|
35
|
+
* **`tab_actions` plugin** (#1844, thanks @PavelLoparev!): close all / to-the-left / to-the-right and move tabs within the current split.
|
|
36
|
+
* **Plugins can register their own config items**: a new typed registration API lets plugins declare settings that appear in the Settings UI alongside built-in ones (sorted at the bottom of the category list), so users can toggle plugin behaviour from the same place as everything else. The bundled `vi_mode` plugin uses it to expose an **autoStart** option.
|
|
37
|
+
|
|
38
|
+
#### Editing & Widgets
|
|
39
|
+
|
|
40
|
+
* **Add Cursors to Line Ends** (#1870, reported by @aquasync): places a cursor at the end of every line in the selection.
|
|
41
|
+
* Widget text inputs gain real selection rendering, `Shift+arrow` / `Ctrl+Shift+arrow` extension, and `Ctrl+C/V/X/A` — used by Search & Replace and plugin dialogs.
|
|
42
|
+
* Floating completion popup on widget `Text` inputs.
|
|
43
|
+
|
|
44
|
+
#### Live Diff
|
|
45
|
+
|
|
46
|
+
* Word-level underline highlights on deletion lines; similarity threshold and size caps are runtime-tunable, so large diffs render as modified lines rather than paired add/remove blocks.
|
|
47
|
+
|
|
48
|
+
### Bug Fixes
|
|
49
|
+
|
|
50
|
+
* **`init.ts` `setAutoOpen(false)` ignored**: dashboard auto-open is now driven by the `ready` hook so user `init.ts` runs first.
|
|
51
|
+
|
|
52
|
+
#### Git Log / Review Diff
|
|
53
|
+
|
|
54
|
+
* **Detail panel `PageUp` / `PageDown`** (action name was wrong); scrollbar now functional on the streamed buffer.
|
|
55
|
+
|
|
56
|
+
#### File Explorer
|
|
57
|
+
|
|
58
|
+
* **UI / navigation shortcuts** (#1903): `Ctrl+P` and friends are no longer swallowed when the file explorer has focus.
|
|
59
|
+
* **Switch Project double-click** (#1931, reported by @SolarLune): double-clicking a directory navigates into it instead of dismissing the dialog.
|
|
60
|
+
|
|
61
|
+
#### Plugins
|
|
62
|
+
|
|
63
|
+
* **Plugin init scaffold** (#1986, @PavelLoparev): new plugins now generate `fresh.entry` (the current entry-point name) instead of stale `fresh.main`.
|
|
64
|
+
* **Idle CPU from git plugins** (#2009, #2012): `git_statusbar` and `merge_conflict` no longer spawn idle subprocesses; `git_statusbar` is driven off `watchPath(.git/HEAD)`.
|
|
65
|
+
|
|
66
|
+
#### Editing
|
|
67
|
+
|
|
68
|
+
* **Smart Home with multiple cursors**: now runs for every cursor, not only the primary.
|
|
69
|
+
* **Soft wrap at trailing space** (#1363, reported by @dragonfyre13): when a trailing space would overflow the wrap column, wrap backs up one word instead of breaking mid-token.
|
|
70
|
+
* **Horizontal scroll-to-view on long lines** (#1873): the viewport now follows the cursor on long lines.
|
|
71
|
+
|
|
72
|
+
#### Live Diff
|
|
73
|
+
|
|
74
|
+
* **Wrapped overlay backgrounds** now extend across every visual row of a wrapped line.
|
|
75
|
+
|
|
76
|
+
#### Rendering
|
|
77
|
+
|
|
78
|
+
* **Highlighter cache preserved across bulk edits** (#1958): large pastes and replace-all no longer trigger a whole-file reparse.
|
|
79
|
+
* **Phantom cursor offscreen** (#1965): a buffer cursor scrolled past the viewport no longer leaves a stray block at the screen edge.
|
|
80
|
+
* **Split separator background** (#1963): separator cells now paint with `editor_bg` so split borders blend with the panes.
|
|
81
|
+
* **Next / Prev Split un-maximizes** (#1961): navigating to another split un-maximizes first.
|
|
82
|
+
* **Stable cursor-position indicator** (#1967): `Ln L, Col C` no longer jitters as the column count grows.
|
|
83
|
+
* **PTY terminal background** now fills the render rect with the editor bg.
|
|
84
|
+
* **Nostalgia theme** (#1890, reported by @NGRIT41): terminal-pane blue now covers full pane.
|
|
85
|
+
* **Column rulers** suppressed on virtual buffers (dashboard, PTY panes, etc.).
|
|
86
|
+
|
|
87
|
+
#### Misc
|
|
88
|
+
|
|
89
|
+
* **No more stray `.fresh/` directory in your working dir** (#1991): orchestrator/cross-restart state now lives under `data_dir` instead of being dropped next to your project files.
|
|
90
|
+
* **Buffer "library path" detection** (#1970, reported by @FF-AntiK): only `.cargo/registry` and `.cargo/git` are treated as Cargo library paths — local `.cargo/config.toml` etc. are no longer flagged.
|
|
91
|
+
* **Julia grammar** (#1852, reported by @goszlanyi): the adjoint operator (`'`) no longer flips the rest of the line into string mode.
|
|
92
|
+
* **`move_word_end` / `select_word_end` labels** (#1878, reported by @sour-dani): translated in all locales.
|
|
93
|
+
|
|
3
94
|
## 0.3.6
|
|
4
95
|
|
|
5
96
|
This version includes a major internal refactoring to support multiple windows in a single Fresh process. The work will be used to add a multi-window orchestrator in a future version.
|
package/package.json
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
"status.review_branch_empty": "No commits in %{base}..HEAD — nothing to review.",
|
|
22
22
|
"panel.review_branch_header": "Commits (%{base}..HEAD)",
|
|
23
23
|
"panel.review_branch_footer": "j/k: navigate | Enter: focus detail | r: refresh | q: close",
|
|
24
|
+
"status.move_to_diff": "Move cursor to a diff line",
|
|
25
|
+
"status.move_to_diff_with_context": "Move cursor to a diff line with file context",
|
|
26
|
+
"status.file_loading": "Loading %{file} at %{hash}...",
|
|
27
|
+
"status.file_not_found": "File %{file} not found at commit %{hash}",
|
|
28
|
+
"status.file_view_ready": "%{file} @ %{hash} (read-only) | Target: line %{line} | q: back",
|
|
29
|
+
"status.failed_open_file": "Failed to open %{file}",
|
|
24
30
|
"cmd.side_by_side_diff": "Side-by-Side Diff",
|
|
25
31
|
"cmd.side_by_side_diff_desc": "Show side-by-side diff for current file",
|
|
26
32
|
"cmd.add_comment": "Review: Add Comment",
|
|
@@ -97,6 +103,12 @@
|
|
|
97
103
|
"status.review_branch_empty": "Žádné commity v %{base}..HEAD — není co revidovat.",
|
|
98
104
|
"panel.review_branch_header": "Commity (%{base}..HEAD)",
|
|
99
105
|
"panel.review_branch_footer": "j/k: navigace | Enter: detail | r: obnovit | q: zavřít",
|
|
106
|
+
"status.move_to_diff": "Presunte kurzor na radek diffu",
|
|
107
|
+
"status.move_to_diff_with_context": "Presunte kurzor na radek diffu s kontextem souboru",
|
|
108
|
+
"status.file_loading": "Nacitam %{file} v %{hash}...",
|
|
109
|
+
"status.file_not_found": "Soubor %{file} nenalezen v commitu %{hash}",
|
|
110
|
+
"status.file_view_ready": "%{file} @ %{hash} (pouze pro cteni) | Cil: radek %{line} | q: zpet",
|
|
111
|
+
"status.failed_open_file": "Nepodarilo se otevrit %{file}",
|
|
100
112
|
"cmd.side_by_side_diff": "Rozdily vedle sebe",
|
|
101
113
|
"cmd.side_by_side_diff_desc": "Zobrazit rozdily aktualniho souboru vedle sebe",
|
|
102
114
|
"cmd.add_comment": "Revize: Pridat komentar",
|
|
@@ -173,6 +185,12 @@
|
|
|
173
185
|
"status.review_branch_empty": "Keine Commits in %{base}..HEAD — nichts zu überprüfen.",
|
|
174
186
|
"panel.review_branch_header": "Commits (%{base}..HEAD)",
|
|
175
187
|
"panel.review_branch_footer": "j/k: Navigation | Enter: Detail | r: Aktualisieren | q: Schließen",
|
|
188
|
+
"status.move_to_diff": "Cursor auf eine Diff-Zeile bewegen",
|
|
189
|
+
"status.move_to_diff_with_context": "Cursor auf eine Diff-Zeile mit Dateikontext bewegen",
|
|
190
|
+
"status.file_loading": "Lade %{file} bei %{hash}...",
|
|
191
|
+
"status.file_not_found": "Datei %{file} nicht gefunden bei Commit %{hash}",
|
|
192
|
+
"status.file_view_ready": "%{file} @ %{hash} (schreibgeschuetzt) | Ziel: Zeile %{line} | q: zurueck",
|
|
193
|
+
"status.failed_open_file": "%{file} konnte nicht geoeffnet werden",
|
|
176
194
|
"cmd.side_by_side_diff": "Nebeneinander-Ansicht",
|
|
177
195
|
"cmd.side_by_side_diff_desc": "Unterschiede der aktuellen Datei nebeneinander anzeigen",
|
|
178
196
|
"cmd.add_comment": "Review: Kommentar hinzufugen",
|
|
@@ -249,6 +267,12 @@
|
|
|
249
267
|
"status.review_branch_empty": "No hay commits en %{base}..HEAD — nada que revisar.",
|
|
250
268
|
"panel.review_branch_header": "Commits (%{base}..HEAD)",
|
|
251
269
|
"panel.review_branch_footer": "j/k: navegar | Enter: detalle | r: actualizar | q: cerrar",
|
|
270
|
+
"status.move_to_diff": "Mueve el cursor a una linea de diff",
|
|
271
|
+
"status.move_to_diff_with_context": "Mueve el cursor a una linea de diff con contexto de archivo",
|
|
272
|
+
"status.file_loading": "Cargando %{file} en %{hash}...",
|
|
273
|
+
"status.file_not_found": "Archivo %{file} no encontrado en commit %{hash}",
|
|
274
|
+
"status.file_view_ready": "%{file} @ %{hash} (solo lectura) | Objetivo: linea %{line} | q: volver",
|
|
275
|
+
"status.failed_open_file": "Error al abrir %{file}",
|
|
252
276
|
"cmd.side_by_side_diff": "Diferencias Lado a Lado",
|
|
253
277
|
"cmd.side_by_side_diff_desc": "Mostrar diferencias lado a lado del archivo actual",
|
|
254
278
|
"cmd.add_comment": "Revision: Agregar Comentario",
|
|
@@ -325,6 +349,12 @@
|
|
|
325
349
|
"status.review_branch_empty": "Aucun commit dans %{base}..HEAD — rien à revoir.",
|
|
326
350
|
"panel.review_branch_header": "Commits (%{base}..HEAD)",
|
|
327
351
|
"panel.review_branch_footer": "j/k : naviguer | Entrée : détail | r : actualiser | q : fermer",
|
|
352
|
+
"status.move_to_diff": "Deplacez le curseur sur une ligne de diff",
|
|
353
|
+
"status.move_to_diff_with_context": "Deplacez le curseur sur une ligne de diff avec contexte de fichier",
|
|
354
|
+
"status.file_loading": "Chargement de %{file} a %{hash}...",
|
|
355
|
+
"status.file_not_found": "Fichier %{file} non trouve au commit %{hash}",
|
|
356
|
+
"status.file_view_ready": "%{file} @ %{hash} (lecture seule) | Cible: ligne %{line} | q: retour",
|
|
357
|
+
"status.failed_open_file": "Echec de l'ouverture de %{file}",
|
|
328
358
|
"cmd.side_by_side_diff": "Differences Cote a Cote",
|
|
329
359
|
"cmd.side_by_side_diff_desc": "Afficher les differences du fichier actuel cote a cote",
|
|
330
360
|
"cmd.add_comment": "Revue: Ajouter un Commentaire",
|
|
@@ -401,6 +431,12 @@
|
|
|
401
431
|
"status.review_branch_empty": "Nessun commit in %{base}..HEAD — niente da revisionare.",
|
|
402
432
|
"panel.review_branch_header": "Commit (%{base}..HEAD)",
|
|
403
433
|
"panel.review_branch_footer": "j/k: naviga | Invio: dettaglio | r: aggiorna | q: chiudi",
|
|
434
|
+
"status.move_to_diff": "Sposta il cursore su una riga di diff",
|
|
435
|
+
"status.move_to_diff_with_context": "Sposta il cursore su una riga di diff con contesto file",
|
|
436
|
+
"status.file_loading": "Caricamento %{file} a %{hash}...",
|
|
437
|
+
"status.file_not_found": "File %{file} non trovato al commit %{hash}",
|
|
438
|
+
"status.file_view_ready": "%{file} @ %{hash} (sola lettura) | Destinazione: riga %{line} | q: indietro",
|
|
439
|
+
"status.failed_open_file": "Apertura di %{file} fallita",
|
|
404
440
|
"cmd.side_by_side_diff": "Diff affiancato",
|
|
405
441
|
"cmd.side_by_side_diff_desc": "Mostra diff affiancato per il file corrente",
|
|
406
442
|
"cmd.add_comment": "Revisione: Aggiungi commento",
|
|
@@ -477,6 +513,12 @@
|
|
|
477
513
|
"status.review_branch_empty": "%{base}..HEAD にコミットはありません — レビューする対象がありません。",
|
|
478
514
|
"panel.review_branch_header": "コミット (%{base}..HEAD)",
|
|
479
515
|
"panel.review_branch_footer": "j/k: 移動 | Enter: 詳細 | r: 更新 | q: 閉じる",
|
|
516
|
+
"status.move_to_diff": "カーソルを差分行に移動してください",
|
|
517
|
+
"status.move_to_diff_with_context": "ファイルコンテキストのある差分行にカーソルを移動してください",
|
|
518
|
+
"status.file_loading": "%{file} を %{hash} で読み込み中...",
|
|
519
|
+
"status.file_not_found": "コミット %{hash} でファイル %{file} が見つかりません",
|
|
520
|
+
"status.file_view_ready": "%{file} @ %{hash} (読み取り専用) | 対象: %{line}行目 | q: 戻る",
|
|
521
|
+
"status.failed_open_file": "%{file} を開けませんでした",
|
|
480
522
|
"cmd.side_by_side_diff": "サイドバイサイド差分",
|
|
481
523
|
"cmd.side_by_side_diff_desc": "現在のファイルの差分を横並びで表示",
|
|
482
524
|
"cmd.add_comment": "レビュー: コメント追加",
|
|
@@ -553,6 +595,12 @@
|
|
|
553
595
|
"status.review_branch_empty": "%{base}..HEAD에 커밋이 없습니다 — 리뷰할 내용이 없습니다.",
|
|
554
596
|
"panel.review_branch_header": "커밋 (%{base}..HEAD)",
|
|
555
597
|
"panel.review_branch_footer": "j/k: 이동 | Enter: 상세 | r: 새로 고침 | q: 닫기",
|
|
598
|
+
"status.move_to_diff": "커서를 diff 줄로 이동하세요",
|
|
599
|
+
"status.move_to_diff_with_context": "파일 컨텍스트가 있는 diff 줄로 커서를 이동하세요",
|
|
600
|
+
"status.file_loading": "%{hash}에서 %{file} 로딩 중...",
|
|
601
|
+
"status.file_not_found": "커밋 %{hash}에서 파일 %{file}을 찾을 수 없습니다",
|
|
602
|
+
"status.file_view_ready": "%{file} @ %{hash} (읽기 전용) | 대상: %{line}행 | q: 뒤로",
|
|
603
|
+
"status.failed_open_file": "%{file}을 열지 못했습니다",
|
|
556
604
|
"cmd.side_by_side_diff": "나란히 비교",
|
|
557
605
|
"cmd.side_by_side_diff_desc": "현재 파일의 차이점을 나란히 표시",
|
|
558
606
|
"cmd.add_comment": "검토: 코멘트 추가",
|
|
@@ -629,6 +677,12 @@
|
|
|
629
677
|
"status.review_branch_empty": "Sem commits em %{base}..HEAD — nada para revisar.",
|
|
630
678
|
"panel.review_branch_header": "Commits (%{base}..HEAD)",
|
|
631
679
|
"panel.review_branch_footer": "j/k: navegar | Enter: detalhe | r: atualizar | q: fechar",
|
|
680
|
+
"status.move_to_diff": "Mova o cursor para uma linha de diff",
|
|
681
|
+
"status.move_to_diff_with_context": "Mova o cursor para uma linha de diff com contexto de arquivo",
|
|
682
|
+
"status.file_loading": "Carregando %{file} em %{hash}...",
|
|
683
|
+
"status.file_not_found": "Arquivo %{file} nao encontrado no commit %{hash}",
|
|
684
|
+
"status.file_view_ready": "%{file} @ %{hash} (somente leitura) | Destino: linha %{line} | q: voltar",
|
|
685
|
+
"status.failed_open_file": "Falha ao abrir %{file}",
|
|
632
686
|
"cmd.side_by_side_diff": "Diferencas Lado a Lado",
|
|
633
687
|
"cmd.side_by_side_diff_desc": "Mostrar diferencas do arquivo atual lado a lado",
|
|
634
688
|
"cmd.add_comment": "Revisao: Adicionar Comentario",
|
|
@@ -705,6 +759,12 @@
|
|
|
705
759
|
"status.review_branch_empty": "Нет коммитов в %{base}..HEAD — нечего просматривать.",
|
|
706
760
|
"panel.review_branch_header": "Коммиты (%{base}..HEAD)",
|
|
707
761
|
"panel.review_branch_footer": "j/k: навигация | Enter: детали | r: обновить | q: закрыть",
|
|
762
|
+
"status.move_to_diff": "Peremesstite kursor na stroku diff",
|
|
763
|
+
"status.move_to_diff_with_context": "Peremesstite kursor na stroku diff s kontekstom fayla",
|
|
764
|
+
"status.file_loading": "Zagruzka %{file} v %{hash}...",
|
|
765
|
+
"status.file_not_found": "Fayl %{file} ne nayden v kommite %{hash}",
|
|
766
|
+
"status.file_view_ready": "%{file} @ %{hash} (tol'ko dlya chteniya) | Tsel': stroka %{line} | q: nazad",
|
|
767
|
+
"status.failed_open_file": "Ne udalos' otkryt' %{file}",
|
|
708
768
|
"cmd.side_by_side_diff": "Сравнение бок о бок",
|
|
709
769
|
"cmd.side_by_side_diff_desc": "Показать изменения текущего файла бок о бок",
|
|
710
770
|
"cmd.add_comment": "Ревью: Добавить комментарий",
|
|
@@ -781,6 +841,12 @@
|
|
|
781
841
|
"status.review_branch_empty": "ไม่มีคอมมิตใน %{base}..HEAD — ไม่มีอะไรต้องตรวจสอบ",
|
|
782
842
|
"panel.review_branch_header": "คอมมิต (%{base}..HEAD)",
|
|
783
843
|
"panel.review_branch_footer": "j/k: นำทาง | Enter: รายละเอียด | r: รีเฟรช | q: ปิด",
|
|
844
|
+
"status.move_to_diff": "เลื่อนเคอร์เซอร์ไปที่บรรทัด diff",
|
|
845
|
+
"status.move_to_diff_with_context": "เลื่อนเคอร์เซอร์ไปที่บรรทัด diff ที่มีบริบทไฟล์",
|
|
846
|
+
"status.file_loading": "กำลังโหลด %{file} ที่ %{hash}...",
|
|
847
|
+
"status.file_not_found": "ไม่พบไฟล์ %{file} ในคอมมิต %{hash}",
|
|
848
|
+
"status.file_view_ready": "%{file} @ %{hash} (อ่านอย่างเดียว) | เป้าหมาย: บรรทัด %{line} | q: กลับ",
|
|
849
|
+
"status.failed_open_file": "ไม่สามารถเปิด %{file} ได้",
|
|
784
850
|
"cmd.side_by_side_diff": "เปรียบเทียบแบบเคียงข้าง",
|
|
785
851
|
"cmd.side_by_side_diff_desc": "แสดงความแตกต่างของไฟล์ปัจจุบันแบบเคียงข้าง",
|
|
786
852
|
"cmd.add_comment": "ตรวจสอบ: เพิ่มความคิดเห็น",
|
|
@@ -857,6 +923,12 @@
|
|
|
857
923
|
"status.review_branch_empty": "Немає комітів у %{base}..HEAD — нічого переглядати.",
|
|
858
924
|
"panel.review_branch_header": "Коміти (%{base}..HEAD)",
|
|
859
925
|
"panel.review_branch_footer": "j/k: навігація | Enter: деталі | r: оновити | q: закрити",
|
|
926
|
+
"status.move_to_diff": "Peremistit' kursor na ryadok diff",
|
|
927
|
+
"status.move_to_diff_with_context": "Peremistit' kursor na ryadok diff z kontekstom faylu",
|
|
928
|
+
"status.file_loading": "Zavantazhennya %{file} v %{hash}...",
|
|
929
|
+
"status.file_not_found": "Fayl %{file} ne znaydeno v komiti %{hash}",
|
|
930
|
+
"status.file_view_ready": "%{file} @ %{hash} (til'ky dlya chytannya) | Tsil': ryadok %{line} | q: nazad",
|
|
931
|
+
"status.failed_open_file": "Ne vdalosya vidkryty %{file}",
|
|
860
932
|
"cmd.side_by_side_diff": "Порівняння поруч",
|
|
861
933
|
"cmd.side_by_side_diff_desc": "Показати зміни поточного файлу поруч",
|
|
862
934
|
"cmd.add_comment": "Рев'ю: Додати коментар",
|
|
@@ -933,6 +1005,12 @@
|
|
|
933
1005
|
"status.review_branch_empty": "Không có commit nào trong %{base}..HEAD — không có gì để xem xét.",
|
|
934
1006
|
"panel.review_branch_header": "Commit (%{base}..HEAD)",
|
|
935
1007
|
"panel.review_branch_footer": "j/k: điều hướng | Enter: chi tiết | r: làm mới | q: đóng",
|
|
1008
|
+
"status.move_to_diff": "Di chuyển con trỏ đến dòng diff",
|
|
1009
|
+
"status.move_to_diff_with_context": "Di chuyển con trỏ đến dòng diff có ngữ cảnh tệp",
|
|
1010
|
+
"status.file_loading": "Đang tải %{file} tại %{hash}...",
|
|
1011
|
+
"status.file_not_found": "Không tìm thấy tệp %{file} tại commit %{hash}",
|
|
1012
|
+
"status.file_view_ready": "%{file} @ %{hash} (chỉ đọc) | Đích: dòng %{line} | q: quay lại",
|
|
1013
|
+
"status.failed_open_file": "Không thể mở %{file}",
|
|
936
1014
|
"cmd.side_by_side_diff": "So sánh song song",
|
|
937
1015
|
"cmd.side_by_side_diff_desc": "Hiển thị khác biệt song song cho tệp hiện tại",
|
|
938
1016
|
"cmd.add_comment": "Xem xét: Thêm nhận xét",
|
|
@@ -1009,6 +1087,12 @@
|
|
|
1009
1087
|
"status.review_branch_empty": "%{base}..HEAD 中没有提交 — 无需审查。",
|
|
1010
1088
|
"panel.review_branch_header": "提交 (%{base}..HEAD)",
|
|
1011
1089
|
"panel.review_branch_footer": "j/k:导航 | Enter:详情 | r:刷新 | q:关闭",
|
|
1090
|
+
"status.move_to_diff": "请将光标移动到差异行",
|
|
1091
|
+
"status.move_to_diff_with_context": "请将光标移动到带有文件上下文的差异行",
|
|
1092
|
+
"status.file_loading": "正在加载 %{file} 于 %{hash}...",
|
|
1093
|
+
"status.file_not_found": "在提交 %{hash} 中未找到文件 %{file}",
|
|
1094
|
+
"status.file_view_ready": "%{file} @ %{hash} (只读) | 目标: 第%{line}行 | q: 返回",
|
|
1095
|
+
"status.failed_open_file": "无法打开 %{file}",
|
|
1012
1096
|
"cmd.side_by_side_diff": "并排差异",
|
|
1013
1097
|
"cmd.side_by_side_diff_desc": "并排显示当前文件的差异",
|
|
1014
1098
|
"cmd.add_comment": "审查: 添加评论",
|
package/plugins/audit_mode.ts
CHANGED
|
@@ -4640,13 +4640,121 @@ async function review_branch_refresh(): Promise<void> {
|
|
|
4640
4640
|
}
|
|
4641
4641
|
registerHandler("review_branch_refresh", review_branch_refresh);
|
|
4642
4642
|
|
|
4643
|
-
/**
|
|
4643
|
+
/** Is the detail panel the currently-focused buffer? */
|
|
4644
|
+
function isReviewBranchDetailFocused(): boolean {
|
|
4645
|
+
return (
|
|
4646
|
+
branchState.detailBufferId !== null &&
|
|
4647
|
+
editor.getActiveBufferId() === branchState.detailBufferId
|
|
4648
|
+
);
|
|
4649
|
+
}
|
|
4650
|
+
|
|
4651
|
+
/** The currently-selected commit in the log panel, or null. */
|
|
4652
|
+
function selectedReviewBranchCommit(): GitCommit | null {
|
|
4653
|
+
if (branchState.commits.length === 0) return null;
|
|
4654
|
+
const i = Math.max(
|
|
4655
|
+
0,
|
|
4656
|
+
Math.min(branchState.selectedIndex, branchState.commits.length - 1),
|
|
4657
|
+
);
|
|
4658
|
+
return branchState.commits[i] ?? null;
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4661
|
+
/**
|
|
4662
|
+
* Enter: on the log panel jumps focus into the detail panel; on the detail
|
|
4663
|
+
* panel opens the file at the cursor position at the selected commit (if any).
|
|
4664
|
+
*/
|
|
4644
4665
|
function review_branch_enter(): void {
|
|
4645
4666
|
if (branchState.groupId === null) return;
|
|
4667
|
+
if (isReviewBranchDetailFocused()) {
|
|
4668
|
+
void review_branch_detail_open_file();
|
|
4669
|
+
return;
|
|
4670
|
+
}
|
|
4646
4671
|
editor.focusBufferGroupPanel(branchState.groupId, "detail");
|
|
4647
4672
|
}
|
|
4648
4673
|
registerHandler("review_branch_enter", review_branch_enter);
|
|
4649
4674
|
|
|
4675
|
+
/**
|
|
4676
|
+
* Open the file at the cursor's `(file, line)` text-properties at the
|
|
4677
|
+
* currently-selected commit, in a read-only virtual buffer. Mirrors the
|
|
4678
|
+
* git-log plugin's `git_log_detail_open_file` so users get the same
|
|
4679
|
+
* drill-down from the review-branch detail panel.
|
|
4680
|
+
*/
|
|
4681
|
+
async function review_branch_detail_open_file(): Promise<void> {
|
|
4682
|
+
if (branchState.detailBufferId === null) return;
|
|
4683
|
+
const commit = selectedReviewBranchCommit();
|
|
4684
|
+
if (!commit) return;
|
|
4685
|
+
|
|
4686
|
+
const props = editor.getTextPropertiesAtCursor(branchState.detailBufferId);
|
|
4687
|
+
if (props.length === 0) {
|
|
4688
|
+
editor.setStatus(editor.t("status.move_to_diff"));
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
const file = props[0].file as string | undefined;
|
|
4692
|
+
const line = (props[0].line as number | undefined) ?? 1;
|
|
4693
|
+
if (!file) {
|
|
4694
|
+
editor.setStatus(editor.t("status.move_to_diff_with_context"));
|
|
4695
|
+
return;
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
editor.setStatus(
|
|
4699
|
+
editor.t("status.file_loading", { file, hash: commit.shortHash }),
|
|
4700
|
+
);
|
|
4701
|
+
const result = await editor.spawnProcess("git", [
|
|
4702
|
+
"show",
|
|
4703
|
+
`${commit.hash}:${file}`,
|
|
4704
|
+
]);
|
|
4705
|
+
if (result.exit_code !== 0) {
|
|
4706
|
+
editor.setStatus(
|
|
4707
|
+
editor.t("status.file_not_found", { file, hash: commit.shortHash }),
|
|
4708
|
+
);
|
|
4709
|
+
return;
|
|
4710
|
+
}
|
|
4711
|
+
|
|
4712
|
+
const lines = result.stdout.split("\n");
|
|
4713
|
+
const entries: TextPropertyEntry[] = lines.map((l, i) => ({
|
|
4714
|
+
text: l + (i < lines.length - 1 ? "\n" : ""),
|
|
4715
|
+
properties: { type: "content", line: i + 1 },
|
|
4716
|
+
}));
|
|
4717
|
+
|
|
4718
|
+
// `*<hash>:<path>*` matches the virtual-name convention the host uses
|
|
4719
|
+
// to detect syntax from the trailing filename's extension.
|
|
4720
|
+
const name = `*${commit.shortHash}:${file}*`;
|
|
4721
|
+
const view = await editor.createVirtualBuffer({
|
|
4722
|
+
name,
|
|
4723
|
+
mode: "review-branch-file-view",
|
|
4724
|
+
readOnly: true,
|
|
4725
|
+
editingDisabled: true,
|
|
4726
|
+
showLineNumbers: true,
|
|
4727
|
+
entries,
|
|
4728
|
+
});
|
|
4729
|
+
if (view) {
|
|
4730
|
+
const byte = await editor.getLineStartPosition(Math.max(0, line - 1));
|
|
4731
|
+
if (byte !== null) editor.setBufferCursor(view.bufferId, byte);
|
|
4732
|
+
editor.setStatus(
|
|
4733
|
+
editor.t("status.file_view_ready", {
|
|
4734
|
+
file,
|
|
4735
|
+
hash: commit.shortHash,
|
|
4736
|
+
line: String(line),
|
|
4737
|
+
}),
|
|
4738
|
+
);
|
|
4739
|
+
} else {
|
|
4740
|
+
editor.setStatus(editor.t("status.failed_open_file", { file }));
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
registerHandler(
|
|
4744
|
+
"review_branch_detail_open_file",
|
|
4745
|
+
review_branch_detail_open_file,
|
|
4746
|
+
);
|
|
4747
|
+
|
|
4748
|
+
/** Tab: toggle focus between the log and detail panels. */
|
|
4749
|
+
function review_branch_tab(): void {
|
|
4750
|
+
if (branchState.groupId === null) return;
|
|
4751
|
+
editor.focusBufferGroupPanel(
|
|
4752
|
+
branchState.groupId,
|
|
4753
|
+
isReviewBranchDetailFocused() ? "log" : "detail",
|
|
4754
|
+
);
|
|
4755
|
+
}
|
|
4756
|
+
registerHandler("review_branch_tab", review_branch_tab);
|
|
4757
|
+
|
|
4650
4758
|
/** q/Escape: focus-back from detail, or close when already on log. */
|
|
4651
4759
|
function review_branch_close_or_back(): void {
|
|
4652
4760
|
if (branchState.groupId === null) return;
|
|
@@ -4683,9 +4791,11 @@ editor.defineMode(
|
|
|
4683
4791
|
// from the Normal keymap via `inheritNormalBindings: true`.
|
|
4684
4792
|
["k", "move_up"],
|
|
4685
4793
|
["j", "move_down"],
|
|
4686
|
-
// Enter: focus the
|
|
4794
|
+
// Enter: from the log, focus the detail panel; from the detail
|
|
4795
|
+
// panel, open the file at the cursor at the selected commit.
|
|
4687
4796
|
["Return", "review_branch_enter"],
|
|
4688
|
-
|
|
4797
|
+
// Tab: toggle focus between the log and detail panels.
|
|
4798
|
+
["Tab", "review_branch_tab"],
|
|
4689
4799
|
["r", "review_branch_refresh"],
|
|
4690
4800
|
["q", "review_branch_close_or_back"],
|
|
4691
4801
|
["Escape", "review_branch_close_or_back"],
|
|
@@ -4695,6 +4805,32 @@ editor.defineMode(
|
|
|
4695
4805
|
true, // inheritNormalBindings — PageUp/PageDown/arrows/Home/End come from Normal
|
|
4696
4806
|
);
|
|
4697
4807
|
|
|
4808
|
+
/** Close the file-view virtual buffer opened from the review-branch detail panel. */
|
|
4809
|
+
function review_branch_file_view_close(): void {
|
|
4810
|
+
const id = editor.getActiveBufferId();
|
|
4811
|
+
if (id) editor.closeBuffer(id);
|
|
4812
|
+
}
|
|
4813
|
+
registerHandler("review_branch_file_view_close", review_branch_file_view_close);
|
|
4814
|
+
|
|
4815
|
+
// Mode for the read-only "git show <hash>:<file>" buffer opened from the
|
|
4816
|
+
// review-branch detail panel. Mirrors git-log's `git-log-file-view`:
|
|
4817
|
+
// q/Escape close the view, j/k alias Up/Down, and all other Normal
|
|
4818
|
+
// bindings (arrows, PageUp/Down, Home/End, Ctrl+C copy) are inherited so
|
|
4819
|
+
// unbound keys don't fall through to edit actions and trip the
|
|
4820
|
+
// `editing_disabled` status message (see #566).
|
|
4821
|
+
editor.defineMode(
|
|
4822
|
+
"review-branch-file-view",
|
|
4823
|
+
[
|
|
4824
|
+
["k", "move_up"],
|
|
4825
|
+
["j", "move_down"],
|
|
4826
|
+
["q", "review_branch_file_view_close"],
|
|
4827
|
+
["Escape", "review_branch_file_view_close"],
|
|
4828
|
+
],
|
|
4829
|
+
true, // read-only
|
|
4830
|
+
false, // allow_text_input
|
|
4831
|
+
true, // inherit Normal-context bindings for unbound keys
|
|
4832
|
+
);
|
|
4833
|
+
|
|
4698
4834
|
// Register Modes and Commands
|
|
4699
4835
|
editor.registerCommand("%cmd.review_diff", "%cmd.review_diff_desc", "start_review_diff", null);
|
|
4700
4836
|
editor.registerCommand("%cmd.review_branch", "%cmd.review_branch_desc", "start_review_branch", null);
|
|
@@ -134,7 +134,10 @@
|
|
|
134
134
|
"preview_tabs": true,
|
|
135
135
|
"side": "left",
|
|
136
136
|
"auto_open_on_last_buffer_close": true,
|
|
137
|
-
"follow_active_buffer": false
|
|
137
|
+
"follow_active_buffer": false,
|
|
138
|
+
"compact_directories": true,
|
|
139
|
+
"tree_indicator_collapsed": ">",
|
|
140
|
+
"tree_indicator_expanded": "▼"
|
|
138
141
|
}
|
|
139
142
|
},
|
|
140
143
|
"file_browser": {
|
|
@@ -793,7 +796,8 @@
|
|
|
793
796
|
"{messages}"
|
|
794
797
|
],
|
|
795
798
|
"x-section": "Status Bar",
|
|
796
|
-
"x-dual-list-sibling": "/editor/status_bar/right"
|
|
799
|
+
"x-dual-list-sibling": "/editor/status_bar/right",
|
|
800
|
+
"x-dynamically-extendable-status-bar-elements": true
|
|
797
801
|
},
|
|
798
802
|
"right": {
|
|
799
803
|
"description": "Elements shown on the right side of the status bar.\nDefault: [\"{line_ending}\", \"{encoding}\", \"{language}\", \"{lsp}\", \"{warnings}\", \"{update}\", \"{palette}\"]",
|
|
@@ -811,7 +815,8 @@
|
|
|
811
815
|
"{palette}"
|
|
812
816
|
],
|
|
813
817
|
"x-section": "Status Bar",
|
|
814
|
-
"x-dual-list-sibling": "/editor/status_bar/left"
|
|
818
|
+
"x-dual-list-sibling": "/editor/status_bar/left",
|
|
819
|
+
"x-dynamically-extendable-status-bar-elements": true
|
|
815
820
|
}
|
|
816
821
|
}
|
|
817
822
|
},
|
|
@@ -958,6 +963,21 @@
|
|
|
958
963
|
"description": "When the file explorer sidebar is open, automatically expand the\ntree and highlight the file that corresponds to the active buffer\nwhenever you switch tabs. Set to `true` to keep the explorer\nselection in sync with the active tab.\nDefault: false",
|
|
959
964
|
"type": "boolean",
|
|
960
965
|
"default": false
|
|
966
|
+
},
|
|
967
|
+
"compact_directories": {
|
|
968
|
+
"description": "Render single-child directory chains on a single line, e.g.\n`src/main/java/com/example`. Only applies when each intermediate\ndirectory in the chain is expanded and has exactly one visible\nchild that is itself a directory. Mirrors VSCode's\n`explorer.compactFolders`.\nDefault: true",
|
|
969
|
+
"type": "boolean",
|
|
970
|
+
"default": true
|
|
971
|
+
},
|
|
972
|
+
"tree_indicator_collapsed": {
|
|
973
|
+
"description": "Symbol shown next to a collapsed (closed) directory in the file\nexplorer tree. A short string (single character recommended).\nA trailing space is added automatically during rendering; the\nrenderer pads narrower indicators so collapsed/expanded rows align.\nDefault: \">\"",
|
|
974
|
+
"type": "string",
|
|
975
|
+
"default": ">"
|
|
976
|
+
},
|
|
977
|
+
"tree_indicator_expanded": {
|
|
978
|
+
"description": "Symbol shown next to an expanded (open) directory in the file\nexplorer tree. A short string (single character recommended).\nA trailing space is added automatically during rendering; the\nrenderer pads narrower indicators so collapsed/expanded rows align.\nDefault: \"▼\"",
|
|
979
|
+
"type": "string",
|
|
980
|
+
"default": "▼"
|
|
961
981
|
}
|
|
962
982
|
}
|
|
963
983
|
},
|
|
@@ -1643,6 +1663,10 @@
|
|
|
1643
1663
|
"null"
|
|
1644
1664
|
],
|
|
1645
1665
|
"readOnly": true
|
|
1666
|
+
},
|
|
1667
|
+
"settings": {
|
|
1668
|
+
"description": "Plugin-specific settings. The shape is defined by each plugin's\n`<plugin_name>.schema.json` sidecar file; the host stores the value as\nuntyped JSON so a malformed plugin schema can't poison the rest of the\nconfig. Plugins read this via `editor.getPluginConfig()` and the\nSettings UI renders it as a sub-category under \"Plugin Settings\".",
|
|
1669
|
+
"readOnly": true
|
|
1646
1670
|
}
|
|
1647
1671
|
},
|
|
1648
1672
|
"x-display-field": "/enabled"
|
package/plugins/dashboard.ts
CHANGED
|
@@ -1586,18 +1586,20 @@ async function dashboardShowOrFocus() {
|
|
|
1586
1586
|
registerHandler("dashboardShowOrFocus", dashboardShowOrFocus);
|
|
1587
1587
|
|
|
1588
1588
|
// Auto-open resolution: the session override (set via the exported
|
|
1589
|
-
// plugin API from init.ts) wins over the user
|
|
1590
|
-
//
|
|
1591
|
-
//
|
|
1592
|
-
|
|
1589
|
+
// plugin API from init.ts) wins over the user-configured value, which
|
|
1590
|
+
// comes from the typed plugin-config field declared below. The field
|
|
1591
|
+
// shows up in the Settings UI under "Plugin Settings → dashboard".
|
|
1592
|
+
editor.defineConfigBoolean("autoOpen", {
|
|
1593
|
+
default: true,
|
|
1594
|
+
description: "Show the dashboard automatically when Fresh starts with no real files open.",
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1593
1597
|
let autoOpenOverride: boolean | null = null;
|
|
1594
1598
|
|
|
1595
1599
|
function autoOpenEnabled(): boolean {
|
|
1596
1600
|
if (autoOpenOverride !== null) return autoOpenOverride;
|
|
1597
|
-
const cfg = editor.
|
|
1598
|
-
|
|
1599
|
-
const dashboard = plugins?.dashboard as Record<string, unknown> | undefined;
|
|
1600
|
-
return dashboard?.["auto-open"] !== false;
|
|
1601
|
+
const cfg = (editor.getPluginConfig() ?? {}) as { autoOpen?: boolean };
|
|
1602
|
+
return cfg.autoOpen !== false;
|
|
1601
1603
|
}
|
|
1602
1604
|
|
|
1603
1605
|
function shouldShowDashboard(): boolean {
|
|
@@ -1801,12 +1803,14 @@ editor.exportPluginApi("dashboard", {
|
|
|
1801
1803
|
// `plugins.dashboard.enabled` is true in the resolved config — so the
|
|
1802
1804
|
// standard settings UI is the single enable/disable surface.
|
|
1803
1805
|
//
|
|
1804
|
-
//
|
|
1805
|
-
//
|
|
1806
|
-
//
|
|
1807
|
-
//
|
|
1808
|
-
//
|
|
1809
|
-
//
|
|
1806
|
+
// Auto-open is driven exclusively by the `ready` hook (and the
|
|
1807
|
+
// `buffer_closed` handler for the last-tab-closed case). We
|
|
1808
|
+
// deliberately do NOT auto-open at module load: dashboard.ts loads
|
|
1809
|
+
// during the startup plugin batch, *before* the user's init.ts has
|
|
1810
|
+
// been evaluated, so an immediate auto-open would race
|
|
1811
|
+
// `setAutoOpen(false)` and dismiss the user's preference. Users who
|
|
1812
|
+
// hot-load the plugin mid-session (toggle on in Settings) get the
|
|
1813
|
+
// dashboard via the "Show Dashboard" command in the palette.
|
|
1810
1814
|
editor.on("ready", "dashboardOnReady");
|
|
1811
1815
|
editor.on("buffer_closed", "dashboardOnBufferClosed");
|
|
1812
1816
|
editor.on("viewport_changed", "dashboardOnViewportChanged");
|
|
@@ -1820,7 +1824,3 @@ editor.registerCommand(
|
|
|
1820
1824
|
"Open the dashboard, or bring it to the front if it's already open",
|
|
1821
1825
|
"dashboardShowOrFocus",
|
|
1822
1826
|
);
|
|
1823
|
-
|
|
1824
|
-
if (editor.listBuffers().length > 0 && shouldShowDashboard()) {
|
|
1825
|
-
openDashboard();
|
|
1826
|
-
}
|
package/plugins/flash.ts
CHANGED
|
@@ -33,7 +33,24 @@ const VTEXT_PREFIX = "flash-";
|
|
|
33
33
|
// the closest jump targets get the most comfortable keys. All
|
|
34
34
|
// lowercase: case-sensitive matching keeps the label letter from also
|
|
35
35
|
// being a valid pattern continuation, which matters for the skip rule.
|
|
36
|
-
|
|
36
|
+
editor.defineConfigString("labelPool", {
|
|
37
|
+
default: "asdfghjklqwertyuiopzxcvbnm",
|
|
38
|
+
description: "Characters used as jump labels, in comfort order. Labels are assigned to matches by distance from the cursor, so leftmost characters here land on the nearest matches.",
|
|
39
|
+
});
|
|
40
|
+
editor.defineConfigBoolean("skipRule", {
|
|
41
|
+
default: true,
|
|
42
|
+
description: "Skip a label character if it is also the next character after a match — prevents ambiguity between extending the search pattern and jumping.",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
function flashSettings(): { labelPool: string; skipRule: boolean } {
|
|
46
|
+
const cfg = (editor.getPluginConfig() ?? {}) as { labelPool?: string; skipRule?: boolean };
|
|
47
|
+
return {
|
|
48
|
+
labelPool: cfg.labelPool && cfg.labelPool.length > 0
|
|
49
|
+
? cfg.labelPool
|
|
50
|
+
: "asdfghjklqwertyuiopzxcvbnm",
|
|
51
|
+
skipRule: cfg.skipRule ?? true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
37
54
|
|
|
38
55
|
interface Match {
|
|
39
56
|
/** Byte offset where the match starts in its buffer. */
|
|
@@ -334,9 +351,10 @@ function assignLabels(
|
|
|
334
351
|
prevLabelByKey: Map<string, string>,
|
|
335
352
|
): Match[] {
|
|
336
353
|
if (matches.length === 0) return matches;
|
|
337
|
-
const
|
|
354
|
+
const { labelPool, skipRule } = flashSettings();
|
|
355
|
+
const skip = skipRule ? buildSkipSet(matches, views, emptyPattern) : new Set<string>();
|
|
338
356
|
const remaining = new Set<string>();
|
|
339
|
-
for (const c of
|
|
357
|
+
for (const c of labelPool) if (!skip.has(c)) remaining.add(c);
|
|
340
358
|
|
|
341
359
|
const sorted = sortMatches(matches, startSplitId, startCursor);
|
|
342
360
|
|
|
@@ -353,7 +371,7 @@ function assignLabels(
|
|
|
353
371
|
// matches in distance order. Iterate the pool in its native
|
|
354
372
|
// (comfort-ranked) order so home-row letters go to nearest matches.
|
|
355
373
|
const orderedRemaining: string[] = [];
|
|
356
|
-
for (const c of
|
|
374
|
+
for (const c of labelPool) if (remaining.has(c)) orderedRemaining.push(c);
|
|
357
375
|
let next = 0;
|
|
358
376
|
for (const m of sorted) {
|
|
359
377
|
if (m.label) continue;
|