@fresh-editor/fresh-editor 0.3.5 → 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.
Files changed (39) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +9 -2
  3. package/package.json +1 -1
  4. package/plugins/audit_mode.i18n.json +84 -0
  5. package/plugins/audit_mode.ts +139 -3
  6. package/plugins/config-schema.json +33 -3
  7. package/plugins/dashboard.ts +34 -111
  8. package/plugins/flash.ts +22 -4
  9. package/plugins/git_blame.ts +10 -6
  10. package/plugins/git_log.ts +705 -323
  11. package/plugins/git_statusbar.i18n.json +72 -0
  12. package/plugins/git_statusbar.ts +133 -0
  13. package/plugins/goto_with_selection.i18n.json +58 -0
  14. package/plugins/goto_with_selection.ts +17 -0
  15. package/plugins/lib/fresh.d.ts +911 -15
  16. package/plugins/lib/index.ts +34 -0
  17. package/plugins/lib/widgets.ts +903 -0
  18. package/plugins/live_diff.ts +442 -32
  19. package/plugins/merge_conflict.ts +89 -64
  20. package/plugins/orchestrator.ts +3425 -0
  21. package/plugins/pkg.ts +235 -54
  22. package/plugins/rust-lsp.ts +58 -40
  23. package/plugins/schemas/theme.schema.json +18 -0
  24. package/plugins/search_replace.i18n.json +140 -28
  25. package/plugins/search_replace.ts +1335 -515
  26. package/plugins/tab_actions.i18n.json +212 -0
  27. package/plugins/tab_actions.ts +76 -0
  28. package/plugins/theme_editor.i18n.json +112 -0
  29. package/plugins/theme_editor.ts +30 -5
  30. package/plugins/tsconfig.json +3 -0
  31. package/plugins/vi_mode.ts +49 -17
  32. package/themes/dark.json +1 -0
  33. package/themes/dracula.json +1 -0
  34. package/themes/high-contrast.json +1 -0
  35. package/themes/light.json +1 -0
  36. package/themes/nord.json +1 -0
  37. package/themes/nostalgia.json +1 -0
  38. package/themes/solarized-dark.json +1 -0
  39. package/themes/terminal.json +4 -0
@@ -0,0 +1,72 @@
1
+ {
2
+ "cs": {
3
+ "status.detecting_branch": "Detekuji větev ...",
4
+ "status.not_in_git": "Není v git",
5
+ "status.git_branch": "Git: větev"
6
+ },
7
+ "de": {
8
+ "status.detecting_branch": "Branch erkennen ...",
9
+ "status.not_in_git": "Nicht in git",
10
+ "status.git_branch": "Git: Branch"
11
+ },
12
+ "en": {
13
+ "status.detecting_branch": "Detecting branch ...",
14
+ "status.not_in_git": "Not in git",
15
+ "status.git_branch": "Git: branch"
16
+ },
17
+ "es": {
18
+ "status.detecting_branch": "Detectando rama ...",
19
+ "status.not_in_git": "No está en git",
20
+ "status.git_branch": "Git: rama"
21
+ },
22
+ "fr": {
23
+ "status.detecting_branch": "Détection de la branche ...",
24
+ "status.not_in_git": "Pas dans git",
25
+ "status.git_branch": "Git : branche"
26
+ },
27
+ "it": {
28
+ "status.detecting_branch": "Rilevamento branch ...",
29
+ "status.not_in_git": "Non in git",
30
+ "status.git_branch": "Git: branch"
31
+ },
32
+ "ja": {
33
+ "status.detecting_branch": "ブランチを検出中...",
34
+ "status.not_in_git": "git外",
35
+ "status.git_branch": "Git: ブランチ"
36
+ },
37
+ "ko": {
38
+ "status.detecting_branch": "브랜치 감지 중...",
39
+ "status.not_in_git": "git 아님",
40
+ "status.git_branch": "Git: 브랜치"
41
+ },
42
+ "pt-BR": {
43
+ "status.detecting_branch": "Detectando ramo ...",
44
+ "status.not_in_git": "Não está em git",
45
+ "status.git_branch": "Git: ramo"
46
+ },
47
+ "ru": {
48
+ "status.detecting_branch": "Определение ветки ...",
49
+ "status.not_in_git": "Не в git",
50
+ "status.git_branch": "Git: ветка"
51
+ },
52
+ "th": {
53
+ "status.detecting_branch": "กำลังตรวจจับสาขา ...",
54
+ "status.not_in_git": "ไม่ได้อยู่ใน git",
55
+ "status.git_branch": "Git: สาขา"
56
+ },
57
+ "uk": {
58
+ "status.detecting_branch": "Визначення гілки ...",
59
+ "status.not_in_git": "Не в git",
60
+ "status.git_branch": "Git: гілка"
61
+ },
62
+ "vi": {
63
+ "status.detecting_branch": "Đang phát hiện nhánh ...",
64
+ "status.not_in_git": "Không trong git",
65
+ "status.git_branch": "Git: nhánh"
66
+ },
67
+ "zh-CN": {
68
+ "status.detecting_branch": "正在检测分支...",
69
+ "status.not_in_git": "不在 git 中",
70
+ "status.git_branch": "Git: 分支"
71
+ }
72
+ }
@@ -0,0 +1,133 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+
3
+ const editor = getEditor();
4
+
5
+ const GIT_BRANCH = "branch";
6
+
7
+ let lastDetectedBranch = editor.t("status.detecting_branch");
8
+ let inFlight: Promise<string> | null = null;
9
+
10
+ // HEAD-file watcher. Branch changes correspond exactly to mutations of
11
+ // the `HEAD` file inside the relevant git dir (resolved by
12
+ // `git rev-parse --git-path HEAD` so worktrees / submodules / `--git-dir`
13
+ // setups work). When HEAD changes we re-spawn `git rev-parse --abbrev-ref`
14
+ // and push the new value; otherwise we never spawn git on the hot path.
15
+ let headWatchHandle: number | null = null;
16
+ let watchedCwd: string | null = null;
17
+ let watchedHeadPath: string | null = null;
18
+ let ensureWatchInFlight: Promise<void> | null = null;
19
+
20
+ async function discoverHeadPath(cwd: string): Promise<string | null> {
21
+ const result = await editor.spawnProcess(
22
+ "git",
23
+ ["rev-parse", "--git-path", "HEAD"],
24
+ cwd,
25
+ );
26
+ if (result.exit_code !== 0) return null;
27
+ const headPath = result.stdout.trim();
28
+ if (!headPath) return null;
29
+ // `--git-path` returns a path relative to cwd unless the git dir is
30
+ // outside (e.g. worktree). Make absolute so notify gets a stable target.
31
+ return headPath.startsWith("/") ? headPath : `${cwd}/${headPath}`;
32
+ }
33
+
34
+ async function ensureHeadWatch(): Promise<void> {
35
+ const cwd = editor.getCwd();
36
+ if (watchedCwd === cwd && headWatchHandle !== null) return;
37
+ if (ensureWatchInFlight) return ensureWatchInFlight;
38
+
39
+ ensureWatchInFlight = (async () => {
40
+ try {
41
+ if (headWatchHandle !== null) {
42
+ editor.unwatchPath(headWatchHandle);
43
+ headWatchHandle = null;
44
+ watchedHeadPath = null;
45
+ }
46
+ watchedCwd = cwd;
47
+ const headPath = await discoverHeadPath(cwd);
48
+ if (!headPath) return;
49
+ try {
50
+ headWatchHandle = await editor.watchPath(headPath, false);
51
+ watchedHeadPath = headPath;
52
+ } catch (_e) {
53
+ // Watch registration failed (path missing, kernel limit). Fall
54
+ // back to event-driven refresh — getCurrentGitBranch is still
55
+ // gated by inFlight + the per-event invocation pattern below.
56
+ }
57
+ } finally {
58
+ ensureWatchInFlight = null;
59
+ }
60
+ })();
61
+ return ensureWatchInFlight;
62
+ }
63
+
64
+ async function getCurrentGitBranch(): Promise<string> {
65
+ if (inFlight) return inFlight;
66
+ inFlight = (async () => {
67
+ try {
68
+ const cwd = editor.getCwd();
69
+ const result = await editor.spawnProcess(
70
+ "git",
71
+ ["rev-parse", "--abbrev-ref", "HEAD"],
72
+ cwd,
73
+ );
74
+ if (result.exit_code === 0) {
75
+ const branch = result.stdout.trim();
76
+ lastDetectedBranch = branch || "HEAD";
77
+ } else {
78
+ lastDetectedBranch = editor.t("status.not_in_git");
79
+ }
80
+ return lastDetectedBranch;
81
+ } finally {
82
+ inFlight = null;
83
+ }
84
+ })();
85
+ return inFlight;
86
+ }
87
+
88
+ async function refreshForActiveBuffer(): Promise<void> {
89
+ // Lazy: pick up cwd changes (Orchestrator window switch, etc.) the next
90
+ // time anything triggers us.
91
+ ensureHeadWatch();
92
+ const bufferId = editor.getActiveBufferId();
93
+ if (bufferId === 0) return;
94
+ const branch = await getCurrentGitBranch();
95
+ editor.setStatusBarValue(bufferId, GIT_BRANCH, branch);
96
+ }
97
+
98
+ editor.registerStatusBarElement(GIT_BRANCH, editor.t("status.git_branch"));
99
+
100
+ // Refresh the branch label when:
101
+ // - The user switches to a different buffer (the per-buffer value may not
102
+ // be set yet for that buffer).
103
+ // - A file is freshly opened (same reason).
104
+ // - A file is saved (best-effort UX: the user may have committed via an
105
+ // external terminal between events; the watchPath below catches actual
106
+ // HEAD mutations).
107
+ // - The editor regains focus from another window — covers the case of
108
+ // running `git checkout` in an external terminal while fresh was unfocused.
109
+ //
110
+ // Notably *not* in this list (compared to the legacy version): render_start,
111
+ // cursor_moved, after_insert, after_delete, buffer_deactivated, buffer_closed.
112
+ // None of them can change the current branch, and render_start was being
113
+ // fired ~300/s — see #2009 for the feedback-loop investigation.
114
+ [
115
+ "buffer_activated",
116
+ "after_file_open",
117
+ "after_file_save",
118
+ "focus_gained",
119
+ ].forEach((event) => {
120
+ editor.on(event, async () => {
121
+ await refreshForActiveBuffer();
122
+ });
123
+ });
124
+
125
+ // path_changed → HEAD file mutated → branch may have changed.
126
+ editor.on("path_changed", async (args) => {
127
+ if (args.handle !== headWatchHandle) return;
128
+ await refreshForActiveBuffer();
129
+ });
130
+
131
+ // Kick off the first detection at load time so the status bar populates
132
+ // before any user event fires.
133
+ refreshForActiveBuffer();
@@ -0,0 +1,58 @@
1
+ {
2
+ "en": {
3
+ "cmd.goto_line_with_selection": "Go to Line with Selection",
4
+ "cmd.goto_line_with_selection_desc": "Select from current position to target line"
5
+ },
6
+ "cs": {
7
+ "cmd.goto_line_with_selection": "Jít na řádek s výběrem",
8
+ "cmd.goto_line_with_selection_desc": "Vybrat od aktuální pozice po cílový řádek"
9
+ },
10
+ "de": {
11
+ "cmd.goto_line_with_selection": "Zur Zeile mit Auswahl",
12
+ "cmd.goto_line_with_selection_desc": "Von der aktuellen Position zur Zielzeile auswählen"
13
+ },
14
+ "es": {
15
+ "cmd.goto_line_with_selection": "Ir a línea con selección",
16
+ "cmd.goto_line_with_selection_desc": "Seleccionar desde la posición actual hasta la línea destino"
17
+ },
18
+ "fr": {
19
+ "cmd.goto_line_with_selection": "Aller à la ligne avec sélection",
20
+ "cmd.goto_line_with_selection_desc": "Sélectionner de la position actuelle jusqu'à la ligne cible"
21
+ },
22
+ "it": {
23
+ "cmd.goto_line_with_selection": "Vai alla riga con selezione",
24
+ "cmd.goto_line_with_selection_desc": "Seleziona dalla posizione attuale alla riga di destinazione"
25
+ },
26
+ "ja": {
27
+ "cmd.goto_line_with_selection": "選択付きで移動先へ",
28
+ "cmd.goto_line_with_selection_desc": "現在位置から移動先行まで選択"
29
+ },
30
+ "ko": {
31
+ "cmd.goto_line_with_selection": "선택 포함 줄로 이동",
32
+ "cmd.goto_line_with_selection_desc": "현재 위치에서 대상 줄까지 선택"
33
+ },
34
+ "pt-BR": {
35
+ "cmd.goto_line_with_selection": "Ir para linha com seleção",
36
+ "cmd.goto_line_with_selection_desc": "Selecionar da posição atual até a linha de destino"
37
+ },
38
+ "ru": {
39
+ "cmd.goto_line_with_selection": "Перейти к строке с выделением",
40
+ "cmd.goto_line_with_selection_desc": "Выделить от текущей позиции до целевой строки"
41
+ },
42
+ "th": {
43
+ "cmd.goto_line_with_selection": "ไปยังบรรทัดพร้อมการเลือก",
44
+ "cmd.goto_line_with_selection_desc": "เลือกจากตำแหน่งปัจจุบันไปยังบรรทัดเป้าหมาย"
45
+ },
46
+ "uk": {
47
+ "cmd.goto_line_with_selection": "Перейти до рядка з виділенням",
48
+ "cmd.goto_line_with_selection_desc": "Виділити від поточної позиції до цільового рядка"
49
+ },
50
+ "vi": {
51
+ "cmd.goto_line_with_selection": "Đến dòng với lựa chọn",
52
+ "cmd.goto_line_with_selection_desc": "Chọn từ vị trí hiện tại đến dòng đích"
53
+ },
54
+ "zh-CN": {
55
+ "cmd.goto_line_with_selection": "转到行并选中",
56
+ "cmd.goto_line_with_selection_desc": "从当前位置选中到目标行"
57
+ }
58
+ }
@@ -0,0 +1,17 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ async function goto_line_with_selection_handler(): Promise<void> {
5
+ editor.executeActions([
6
+ { action: "set_mark", count: 1 },
7
+ { action: "goto_line", count: 1 },
8
+ ]);
9
+ }
10
+
11
+ registerHandler("goto_line_with_selection", goto_line_with_selection_handler);
12
+
13
+ editor.registerCommand(
14
+ "%cmd.goto_line_with_selection",
15
+ "%cmd.goto_line_with_selection_desc",
16
+ "goto_line_with_selection",
17
+ );