@fresh-editor/fresh-editor 0.1.77 → 0.1.86

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.
@@ -92,8 +92,7 @@ editor.registerCommand(
92
92
  "%cmd.live_grep",
93
93
  "%cmd.live_grep_desc",
94
94
  "start_live_grep",
95
- "normal"
95
+ null
96
96
  );
97
97
 
98
98
  editor.debug("Live Grep plugin loaded (using Finder abstraction)");
99
- editor.setStatus(editor.t("status.ready"));
@@ -611,4 +611,3 @@ editor.registerCommand(
611
611
 
612
612
  // Initialization
613
613
  editor.debug("Markdown Compose plugin loaded - use 'Markdown: Toggle Compose' command");
614
- editor.setStatus(editor.t("status.plugin_ready"));
@@ -1783,7 +1783,7 @@ const MERGE_MODE_COMMANDS = [
1783
1783
  */
1784
1784
  function registerMergeModeCommands(): void {
1785
1785
  for (const cmd of MERGE_MODE_COMMANDS) {
1786
- editor.registerCommand(cmd.name, cmd.desc, cmd.action, "normal");
1786
+ editor.registerCommand(cmd.name, cmd.desc, cmd.action, null);
1787
1787
  }
1788
1788
  }
1789
1789
 
@@ -1801,12 +1801,11 @@ editor.registerCommand(
1801
1801
  "%cmd.start",
1802
1802
  "%cmd.start_desc",
1803
1803
  "start_merge_conflict",
1804
- "normal"
1804
+ null // Always visible - entry point command
1805
1805
  );
1806
1806
 
1807
1807
  // =============================================================================
1808
1808
  // Plugin Initialization
1809
1809
  // =============================================================================
1810
1810
 
1811
- editor.setStatus(editor.t("status.ready"));
1812
1811
  editor.debug("Merge plugin initialized - Use 'Merge: Start Resolution' for files with conflicts");
@@ -162,4 +162,3 @@ globalThis.onPathCompletePromptChanged = function (args: { prompt_type: string;
162
162
  // Register event handler
163
163
  editor.on("prompt_changed", "onPathCompletePromptChanged");
164
164
 
165
- editor.setStatus(editor.t("status.loaded"));
@@ -478,9 +478,8 @@ editor.registerCommand(
478
478
  "%cmd.search_replace",
479
479
  "%cmd.search_replace_desc",
480
480
  "start_search_replace",
481
- "normal"
481
+ null
482
482
  );
483
483
 
484
484
  // Plugin initialization
485
485
  editor.debug("Search & Replace plugin loaded");
486
- editor.setStatus(editor.t("status.ready"));
@@ -484,10 +484,17 @@ function findThemesDir(): string {
484
484
  */
485
485
  async function loadBuiltinThemes(): Promise<string[]> {
486
486
  try {
487
- const builtinThemes = editor.getBuiltinThemes() as Record<string, string>;
487
+ editor.debug("[theme_editor] loadBuiltinThemes: calling editor.getBuiltinThemes()");
488
+ const rawThemes = editor.getBuiltinThemes();
489
+ editor.debug(`[theme_editor] loadBuiltinThemes: got rawThemes type=${typeof rawThemes}`);
490
+ // getBuiltinThemes returns a JSON string, need to parse it
491
+ const builtinThemes = typeof rawThemes === "string"
492
+ ? JSON.parse(rawThemes) as Record<string, string>
493
+ : rawThemes as Record<string, string>;
494
+ editor.debug(`[theme_editor] loadBuiltinThemes: parsed ${Object.keys(builtinThemes).length} themes`);
488
495
  return Object.keys(builtinThemes);
489
496
  } catch (e) {
490
- editor.debug(`Failed to load built-in themes list: ${e}`);
497
+ editor.debug(`[theme_editor] Failed to load built-in themes list: ${e}`);
491
498
  throw e;
492
499
  }
493
500
  }
@@ -497,13 +504,17 @@ async function loadBuiltinThemes(): Promise<string[]> {
497
504
  */
498
505
  async function loadThemeFile(name: string): Promise<Record<string, unknown> | null> {
499
506
  try {
500
- const builtinThemes = editor.getBuiltinThemes() as Record<string, string>;
507
+ const rawThemes = editor.getBuiltinThemes();
508
+ // getBuiltinThemes returns a JSON string, need to parse it
509
+ const builtinThemes = typeof rawThemes === "string"
510
+ ? JSON.parse(rawThemes) as Record<string, string>
511
+ : rawThemes as Record<string, string>;
501
512
  if (name in builtinThemes) {
502
513
  return JSON.parse(builtinThemes[name]);
503
514
  }
504
515
  return null;
505
516
  } catch (e) {
506
- editor.debug(`Failed to load theme data for '${name}': ${e}`);
517
+ editor.debug(`[theme_editor] Failed to load theme data for '${name}': ${e}`);
507
518
  return null;
508
519
  }
509
520
  }
@@ -1190,7 +1201,12 @@ globalThis.onThemeSelectInitialPromptConfirmed = async function(args: {
1190
1201
  selected_index: number | null;
1191
1202
  input: string;
1192
1203
  }): Promise<boolean> {
1193
- if (args.prompt_type !== "theme-select-initial") return true;
1204
+ editor.debug(`[theme_editor] onThemeSelectInitialPromptConfirmed called with: ${JSON.stringify(args)}`);
1205
+ if (args.prompt_type !== "theme-select-initial") {
1206
+ editor.debug(`[theme_editor] prompt_type mismatch, expected 'theme-select-initial', got '${args.prompt_type}'`);
1207
+ return true;
1208
+ }
1209
+ editor.debug(`[theme_editor] prompt_type matched, processing selection...`);
1194
1210
 
1195
1211
  const value = args.input.trim();
1196
1212
 
@@ -1252,7 +1268,9 @@ globalThis.onThemeSelectInitialPromptConfirmed = async function(args: {
1252
1268
  }
1253
1269
 
1254
1270
  // Now open the editor with loaded theme
1271
+ editor.debug(`[theme_editor] About to call doOpenThemeEditor()`);
1255
1272
  await doOpenThemeEditor();
1273
+ editor.debug(`[theme_editor] doOpenThemeEditor() completed`);
1256
1274
 
1257
1275
  return true;
1258
1276
  };
@@ -1642,7 +1660,9 @@ globalThis.theme_editor_nav_prev_section = function(): void {
1642
1660
  * Open the theme editor - prompts user to select theme first
1643
1661
  */
1644
1662
  globalThis.open_theme_editor = async function(): Promise<void> {
1663
+ editor.debug("[theme_editor] open_theme_editor called");
1645
1664
  if (isThemeEditorOpen()) {
1665
+ editor.debug("[theme_editor] already open, focusing");
1646
1666
  // Focus the existing theme editor split
1647
1667
  if (state.splitId !== null) {
1648
1668
  editor.focusSplit(state.splitId);
@@ -1651,12 +1671,15 @@ globalThis.open_theme_editor = async function(): Promise<void> {
1651
1671
  return;
1652
1672
  }
1653
1673
 
1674
+ editor.debug("[theme_editor] saving context");
1654
1675
  // Save context
1655
1676
  state.sourceSplitId = editor.getActiveSplitId();
1656
1677
  state.sourceBufferId = editor.getActiveBufferId();
1657
1678
 
1679
+ editor.debug("[theme_editor] loading builtin themes...");
1658
1680
  // Load available themes
1659
1681
  state.builtinThemes = await loadBuiltinThemes();
1682
+ editor.debug(`[theme_editor] loaded ${state.builtinThemes.length} builtin themes`);
1660
1683
 
1661
1684
  // Get current theme name from config
1662
1685
  const config = editor.getConfig() as Record<string, unknown>;
@@ -1704,10 +1727,13 @@ globalThis.open_theme_editor = async function(): Promise<void> {
1704
1727
  * Actually open the theme editor with loaded theme data
1705
1728
  */
1706
1729
  async function doOpenThemeEditor(): Promise<void> {
1730
+ editor.debug("[theme_editor] doOpenThemeEditor: building display entries");
1707
1731
  // Build initial entries
1708
1732
  const entries = buildDisplayEntries();
1733
+ editor.debug(`[theme_editor] doOpenThemeEditor: built ${entries.length} entries`);
1709
1734
 
1710
1735
  // Create virtual buffer in current split (no new split)
1736
+ editor.debug("[theme_editor] doOpenThemeEditor: calling createVirtualBuffer...");
1711
1737
  const bufferId = await editor.createVirtualBuffer({
1712
1738
  name: "*Theme Editor*",
1713
1739
  mode: "theme-editor",
@@ -1717,13 +1743,20 @@ async function doOpenThemeEditor(): Promise<void> {
1717
1743
  show_cursors: true,
1718
1744
  editing_disabled: true,
1719
1745
  });
1746
+ editor.debug(`[theme_editor] doOpenThemeEditor: createVirtualBuffer returned bufferId=${bufferId}`);
1747
+ editor.debug(`[theme_editor] doOpenThemeEditor: checking if bufferId !== null...`);
1720
1748
 
1721
1749
  if (bufferId !== null) {
1750
+ editor.debug(`[theme_editor] doOpenThemeEditor: bufferId is not null, setting state...`);
1722
1751
  state.bufferId = bufferId;
1723
1752
  state.splitId = null;
1724
1753
 
1754
+ editor.debug(`[theme_editor] doOpenThemeEditor: calling applyHighlighting...`);
1725
1755
  applyHighlighting();
1756
+ editor.debug(`[theme_editor] doOpenThemeEditor: applyHighlighting completed`);
1757
+ editor.debug(`[theme_editor] doOpenThemeEditor: calling setStatus...`);
1726
1758
  editor.setStatus(editor.t("status.ready"));
1759
+ editor.debug(`[theme_editor] doOpenThemeEditor: completed successfully`);
1727
1760
  } else {
1728
1761
  editor.setStatus(editor.t("status.open_failed"));
1729
1762
  }
@@ -2037,12 +2070,11 @@ globalThis.onThemeDeletePromptConfirmed = async function(args: {
2037
2070
  // Command Registration
2038
2071
  // =============================================================================
2039
2072
 
2040
- // Main command to open theme editor (always available)
2073
+ // Main command to open theme editor (always available - no context restriction)
2041
2074
  editor.registerCommand(
2042
2075
  "%cmd.edit_theme",
2043
2076
  "%cmd.edit_theme_desc",
2044
- "open_theme_editor",
2045
- "normal"
2077
+ "open_theme_editor"
2046
2078
  );
2047
2079
 
2048
2080
  // Buffer-scoped commands - only visible when a buffer with mode "theme-editor" is focused
@@ -2065,5 +2097,4 @@ editor.registerCommand("%cmd.nav_prev", "%cmd.nav_prev_desc", "theme_editor_nav_
2065
2097
  // Plugin Initialization
2066
2098
  // =============================================================================
2067
2099
 
2068
- editor.setStatus(editor.t("status.plugin_loaded"));
2069
2100
  editor.debug("Theme Editor plugin initialized - Use 'Edit Theme' command to open");
@@ -203,5 +203,4 @@ editor.registerCommand(
203
203
  );
204
204
 
205
205
  // Initialization
206
- editor.setStatus(editor.t("status.loaded"));
207
206
  editor.debug("TODO Highlighter initialized with keywords: " + config.keywords.map(k => k.word).join(", "));
@@ -25,10 +25,12 @@
25
25
  "status.line_beyond_end": "Line %{line} beyond end of file, moved to end",
26
26
 
27
27
  "error.no_write_since_change": "No write since last change (use %{cmd} to override)",
28
+ "error.other_buffers_modified": "Other buffers have unsaved changes (use %{cmd} to save all and quit)",
29
+ "error.no_file_name": "No file name (use :w filename)",
28
30
  "error.not_valid_command": "Not a valid command: %{cmd}",
29
31
  "error.unknown_command": "Unknown command: %{cmd}",
30
32
  "error.command_no_bang": "Command does not accept !: %{cmd}",
31
- "error.save_as_not_implemented": "Save as not implemented. Use :w to save current file.",
33
+ "error.save_as_not_implemented": "Save as not implemented. Use Ctrl+Shift+S or File menu.",
32
34
  "error.shell_not_supported": "Shell commands not supported (use terminal)",
33
35
  "error.buffer_not_found": "Buffer %{id} not found",
34
36
  "error.multiple_buffers_match": "Multiple buffers match \"%{pattern}\". Be more specific.",
@@ -144,10 +146,12 @@
144
146
  "status.line_beyond_end": "Radek %{line} za koncem souboru, presunuto na konec",
145
147
 
146
148
  "error.no_write_since_change": "Neulozeno od posledni zmeny (pouzijte %{cmd} pro vynuceni)",
149
+ "error.other_buffers_modified": "Jiné buffery mají neuložené změny (použijte %{cmd} pro uložení všech a ukončení)",
150
+ "error.no_file_name": "Žádný název souboru (použijte :w název_souboru)",
147
151
  "error.not_valid_command": "Neplatny prikaz: %{cmd}",
148
152
  "error.unknown_command": "Neznamy prikaz: %{cmd}",
149
153
  "error.command_no_bang": "Prikaz neprijima !: %{cmd}",
150
- "error.save_as_not_implemented": "Ulozit jako neimplementovano. Pouzijte :w pro ulozeni.",
154
+ "error.save_as_not_implemented": "Uložit jako není implementováno. Použijte Ctrl+Shift+S nebo menu Soubor.",
151
155
  "error.shell_not_supported": "Shell prikazy nepodporovany (pouzijte terminal)",
152
156
  "error.buffer_not_found": "Buffer %{id} nenalezen",
153
157
  "error.multiple_buffers_match": "Vice bufferu odpovida \"%{pattern}\". Bud presnejsi.",
@@ -263,10 +267,12 @@
263
267
  "status.line_beyond_end": "Zeile %{line} ueber Dateiende hinaus, zum Ende bewegt",
264
268
 
265
269
  "error.no_write_since_change": "Nicht gespeichert seit letzter Aenderung (verwende %{cmd} zum Ueberschreiben)",
270
+ "error.other_buffers_modified": "Andere Puffer haben ungespeicherte Änderungen (verwenden Sie %{cmd} um alle zu speichern und zu beenden)",
271
+ "error.no_file_name": "Kein Dateiname (verwenden Sie :w Dateiname)",
266
272
  "error.not_valid_command": "Kein gueltiger Befehl: %{cmd}",
267
273
  "error.unknown_command": "Unbekannter Befehl: %{cmd}",
268
274
  "error.command_no_bang": "Befehl akzeptiert kein !: %{cmd}",
269
- "error.save_as_not_implemented": "Speichern unter nicht implementiert. Verwende :w zum Speichern.",
275
+ "error.save_as_not_implemented": "Speichern unter nicht implementiert. Verwenden Sie Strg+Umschalt+S oder das Datei-Menü.",
270
276
  "error.shell_not_supported": "Shell-Befehle nicht unterstuetzt (verwende Terminal)",
271
277
  "error.buffer_not_found": "Buffer %{id} nicht gefunden",
272
278
  "error.multiple_buffers_match": "Mehrere Buffer passen zu \"%{pattern}\". Sei genauer.",
@@ -382,10 +388,12 @@
382
388
  "status.line_beyond_end": "Linea %{line} mas alla del final, movido al final",
383
389
 
384
390
  "error.no_write_since_change": "Sin guardar desde el ultimo cambio (usa %{cmd} para forzar)",
391
+ "error.other_buffers_modified": "Otros búferes tienen cambios sin guardar (use %{cmd} para guardar todos y salir)",
392
+ "error.no_file_name": "Sin nombre de archivo (use :w nombre_archivo)",
385
393
  "error.not_valid_command": "Comando no valido: %{cmd}",
386
394
  "error.unknown_command": "Comando desconocido: %{cmd}",
387
395
  "error.command_no_bang": "El comando no acepta !: %{cmd}",
388
- "error.save_as_not_implemented": "Guardar como no implementado. Usa :w para guardar.",
396
+ "error.save_as_not_implemented": "Guardar como no implementado. Use Ctrl+Shift+S o el menú Archivo.",
389
397
  "error.shell_not_supported": "Comandos de shell no soportados (usa terminal)",
390
398
  "error.buffer_not_found": "Buffer %{id} no encontrado",
391
399
  "error.multiple_buffers_match": "Multiples buffers coinciden con \"%{pattern}\". Se mas especifico.",
@@ -501,10 +509,12 @@
501
509
  "status.line_beyond_end": "Ligne %{line} au-dela de la fin, deplace a la fin",
502
510
 
503
511
  "error.no_write_since_change": "Non enregistre depuis la derniere modification (utilisez %{cmd} pour forcer)",
512
+ "error.other_buffers_modified": "D'autres tampons ont des modifications non enregistrées (utilisez %{cmd} pour tout enregistrer et quitter)",
513
+ "error.no_file_name": "Pas de nom de fichier (utilisez :w nom_fichier)",
504
514
  "error.not_valid_command": "Commande non valide: %{cmd}",
505
515
  "error.unknown_command": "Commande inconnue: %{cmd}",
506
516
  "error.command_no_bang": "La commande n'accepte pas !: %{cmd}",
507
- "error.save_as_not_implemented": "Enregistrer sous non implemente. Utilisez :w pour enregistrer.",
517
+ "error.save_as_not_implemented": "Enregistrer sous non implémenté. Utilisez Ctrl+Shift+S ou le menu Fichier.",
508
518
  "error.shell_not_supported": "Commandes shell non supportees (utilisez terminal)",
509
519
  "error.buffer_not_found": "Buffer %{id} non trouve",
510
520
  "error.multiple_buffers_match": "Plusieurs buffers correspondent a \"%{pattern}\". Soyez plus precis.",
@@ -620,10 +630,12 @@
620
630
  "status.line_beyond_end": "Riga %{line} oltre la fine del file, spostato alla fine",
621
631
 
622
632
  "error.no_write_since_change": "Non salvato dall'ultima modifica (usa %{cmd} per forzare)",
633
+ "error.other_buffers_modified": "Altri buffer hanno modifiche non salvate (usa %{cmd} per salvare tutto ed uscire)",
634
+ "error.no_file_name": "Nessun nome file (usa :w nome_file)",
623
635
  "error.not_valid_command": "Comando non valido: %{cmd}",
624
636
  "error.unknown_command": "Comando sconosciuto: %{cmd}",
625
637
  "error.command_no_bang": "Il comando non accetta !: %{cmd}",
626
- "error.save_as_not_implemented": "Salva come non implementato. Usa :w per salvare il file corrente.",
638
+ "error.save_as_not_implemented": "Salva con nome non implementato. Usa Ctrl+Shift+S o il menu File.",
627
639
  "error.shell_not_supported": "Comandi shell non supportati (usa il terminale)",
628
640
  "error.buffer_not_found": "Buffer %{id} non trovato",
629
641
  "error.multiple_buffers_match": "Più buffer corrispondono a \"%{pattern}\". Sii più specifico.",
@@ -739,10 +751,12 @@
739
751
  "status.line_beyond_end": "%{line}行目はファイル末尾を超えています。末尾に移動しました",
740
752
 
741
753
  "error.no_write_since_change": "最後の変更以降保存されていません(%{cmd}で強制実行)",
754
+ "error.other_buffers_modified": "他のバッファに未保存の変更があります(%{cmd} で全て保存して終了)",
755
+ "error.no_file_name": "ファイル名がありません(:w ファイル名 を使用)",
742
756
  "error.not_valid_command": "無効なコマンド: %{cmd}",
743
757
  "error.unknown_command": "不明なコマンド: %{cmd}",
744
758
  "error.command_no_bang": "コマンドは!を受け付けません: %{cmd}",
745
- "error.save_as_not_implemented": "名前を付けて保存は未実装です。:wで保存してください。",
759
+ "error.save_as_not_implemented": "名前を付けて保存は未実装です。Ctrl+Shift+S またはファイルメニューを使用してください。",
746
760
  "error.shell_not_supported": "シェルコマンドはサポートされていません(ターミナルを使用)",
747
761
  "error.buffer_not_found": "バッファ%{id}が見つかりません",
748
762
  "error.multiple_buffers_match": "複数のバッファが\"%{pattern}\"に一致します。より具体的に指定してください。",
@@ -858,10 +872,12 @@
858
872
  "status.line_beyond_end": "%{line}줄이 파일 끝을 넘어감, 끝으로 이동함",
859
873
 
860
874
  "error.no_write_since_change": "마지막 변경 후 저장 안 됨 (%{cmd}로 강제 실행)",
875
+ "error.other_buffers_modified": "다른 버퍼에 저장되지 않은 변경사항이 있습니다 (%{cmd}로 모두 저장하고 종료)",
876
+ "error.no_file_name": "파일 이름 없음 (:w 파일이름 사용)",
861
877
  "error.not_valid_command": "유효하지 않은 명령: %{cmd}",
862
878
  "error.unknown_command": "알 수 없는 명령: %{cmd}",
863
879
  "error.command_no_bang": "명령이 !를 지원하지 않음: %{cmd}",
864
- "error.save_as_not_implemented": "다른 이름으로 저장 미구현. :w로 저장하세요.",
880
+ "error.save_as_not_implemented": "다른 이름으로 저장이 구현되지 않았습니다. Ctrl+Shift+S 또는 파일 메뉴를 사용하세요.",
865
881
  "error.shell_not_supported": "셸 명령 지원 안 됨 (터미널 사용)",
866
882
  "error.buffer_not_found": "버퍼 %{id} 찾을 수 없음",
867
883
  "error.multiple_buffers_match": "여러 버퍼가 \"%{pattern}\"와 일치. 더 구체적으로 지정하세요.",
@@ -977,10 +993,12 @@
977
993
  "status.line_beyond_end": "Linha %{line} alem do fim do arquivo, movido para o fim",
978
994
 
979
995
  "error.no_write_since_change": "Nao salvo desde a ultima alteracao (use %{cmd} para forcar)",
996
+ "error.other_buffers_modified": "Outros buffers têm alterações não salvas (use %{cmd} para salvar tudo e sair)",
997
+ "error.no_file_name": "Sem nome de arquivo (use :w nome_arquivo)",
980
998
  "error.not_valid_command": "Comando invalido: %{cmd}",
981
999
  "error.unknown_command": "Comando desconhecido: %{cmd}",
982
1000
  "error.command_no_bang": "Comando nao aceita !: %{cmd}",
983
- "error.save_as_not_implemented": "Salvar como nao implementado. Use :w para salvar.",
1001
+ "error.save_as_not_implemented": "Salvar como não implementado. Use Ctrl+Shift+S ou o menu Arquivo.",
984
1002
  "error.shell_not_supported": "Comandos shell nao suportados (use terminal)",
985
1003
  "error.buffer_not_found": "Buffer %{id} nao encontrado",
986
1004
  "error.multiple_buffers_match": "Multiplos buffers correspondem a \"%{pattern}\". Seja mais especifico.",
@@ -1096,10 +1114,12 @@
1096
1114
  "status.line_beyond_end": "Строка %{line} за концом файла, перемещено в конец",
1097
1115
 
1098
1116
  "error.no_write_since_change": "Не сохранено с последнего изменения (используйте %{cmd} для принудительного выполнения)",
1117
+ "error.other_buffers_modified": "Другие буферы имеют несохранённые изменения (используйте %{cmd} чтобы сохранить всё и выйти)",
1118
+ "error.no_file_name": "Нет имени файла (используйте :w имя_файла)",
1099
1119
  "error.not_valid_command": "Недопустимая команда: %{cmd}",
1100
1120
  "error.unknown_command": "Неизвестная команда: %{cmd}",
1101
1121
  "error.command_no_bang": "Команда не принимает !: %{cmd}",
1102
- "error.save_as_not_implemented": "Сохранить как не реализовано. Используйте :w для сохранения.",
1122
+ "error.save_as_not_implemented": "Сохранить как не реализовано. Используйте Ctrl+Shift+S или меню Файл.",
1103
1123
  "error.shell_not_supported": "Shell команды не поддерживаются (используйте терминал)",
1104
1124
  "error.buffer_not_found": "Буфер %{id} не найден",
1105
1125
  "error.multiple_buffers_match": "Несколько буферов соответствуют \"%{pattern}\". Будьте точнее.",
@@ -1215,10 +1235,12 @@
1215
1235
  "status.line_beyond_end": "บรรทัด %{line} เกินจุดสิ้นสุดไฟล์ ย้ายไปยังจุดสิ้นสุด",
1216
1236
 
1217
1237
  "error.no_write_since_change": "ไม่ได้บันทึกตั้งแต่การเปลี่ยนแปลงล่าสุด (ใช้ %{cmd} เพื่อบังคับ)",
1238
+ "error.other_buffers_modified": "บัฟเฟอร์อื่นมีการเปลี่ยนแปลงที่ไม่ได้บันทึก (ใช้ %{cmd} เพื่อบันทึกทั้งหมดและออก)",
1239
+ "error.no_file_name": "ไม่มีชื่อไฟล์ (ใช้ :w ชื่อไฟล์)",
1218
1240
  "error.not_valid_command": "คำสั่งไม่ถูกต้อง: %{cmd}",
1219
1241
  "error.unknown_command": "คำสั่งไม่รู้จัก: %{cmd}",
1220
1242
  "error.command_no_bang": "คำสั่งไม่รับ !: %{cmd}",
1221
- "error.save_as_not_implemented": "บันทึกเป็นยังไม่ได้ใช้งาน ใช้ :w เพื่อบันทึก",
1243
+ "error.save_as_not_implemented": "บันทึกเป็นยังไม่รองรับ ใช้ Ctrl+Shift+S หรือเมนูไฟล์",
1222
1244
  "error.shell_not_supported": "ไม่รองรับคำสั่ง Shell (ใช้เทอร์มินัล)",
1223
1245
  "error.buffer_not_found": "ไม่พบบัฟเฟอร์ %{id}",
1224
1246
  "error.multiple_buffers_match": "มีหลายบัฟเฟอร์ที่ตรงกับ \"%{pattern}\" โปรดระบุให้ชัดเจนขึ้น",
@@ -1334,10 +1356,12 @@
1334
1356
  "status.line_beyond_end": "Рядок %{line} за кінцем файлу, переміщено в кінець",
1335
1357
 
1336
1358
  "error.no_write_since_change": "Не збережено з останньої зміни (використовуйте %{cmd} для примусового виконання)",
1359
+ "error.other_buffers_modified": "Інші буфери мають незбережені зміни (використайте %{cmd} щоб зберегти все і вийти)",
1360
+ "error.no_file_name": "Немає назви файлу (використайте :w назва_файлу)",
1337
1361
  "error.not_valid_command": "Недійсна команда: %{cmd}",
1338
1362
  "error.unknown_command": "Невідома команда: %{cmd}",
1339
1363
  "error.command_no_bang": "Команда не приймає !: %{cmd}",
1340
- "error.save_as_not_implemented": "Зберегти як не реалізовано. Використовуйте :w для збереження.",
1364
+ "error.save_as_not_implemented": "Зберегти як не реалізовано. Використайте Ctrl+Shift+S або меню Файл.",
1341
1365
  "error.shell_not_supported": "Shell команди не підтримуються (використовуйте термінал)",
1342
1366
  "error.buffer_not_found": "Буфер %{id} не знайдено",
1343
1367
  "error.multiple_buffers_match": "Декілька буферів відповідають \"%{pattern}\". Будьте точнішими.",
@@ -1453,10 +1477,12 @@
1453
1477
  "status.line_beyond_end": "第%{line}行超出文件末尾,已移动到末尾",
1454
1478
 
1455
1479
  "error.no_write_since_change": "上次更改后未保存(使用%{cmd}强制执行)",
1480
+ "error.other_buffers_modified": "其他缓冲区有未保存的更改(使用 %{cmd} 保存全部并退出)",
1481
+ "error.no_file_name": "没有文件名(使用 :w 文件名)",
1456
1482
  "error.not_valid_command": "无效命令: %{cmd}",
1457
1483
  "error.unknown_command": "未知命令: %{cmd}",
1458
1484
  "error.command_no_bang": "命令不接受!: %{cmd}",
1459
- "error.save_as_not_implemented": "另存为未实现。使用:w保存当前文件。",
1485
+ "error.save_as_not_implemented": "另存为未实现。请使用 Ctrl+Shift+S 或文件菜单。",
1460
1486
  "error.shell_not_supported": "不支持Shell命令(请使用终端)",
1461
1487
  "error.buffer_not_found": "未找到缓冲区%{id}",
1462
1488
  "error.multiple_buffers_match": "多个缓冲区匹配\"%{pattern}\"。请更具体。",
@@ -1561,11 +1561,18 @@ editor.defineMode("vi-normal", null, [
1561
1561
 
1562
1562
  // Command mode
1563
1563
  [":", "vi_command_mode"],
1564
+
1565
+ // Pass through to standard editor shortcuts
1566
+ ["C-p", "command_palette"],
1567
+ ["C-q", "quit"],
1564
1568
  ], true); // read_only = true to prevent character insertion
1565
1569
 
1566
1570
  // Define vi-insert mode - only Escape is special, other keys insert text
1567
1571
  editor.defineMode("vi-insert", null, [
1568
1572
  ["Escape", "vi_escape"],
1573
+ // Pass through to standard editor shortcuts
1574
+ ["C-p", "command_palette"],
1575
+ ["C-q", "quit"],
1569
1576
  ], false); // read_only = false to allow normal typing
1570
1577
 
1571
1578
  // Define vi-find-char mode - binds all printable chars to the handler
@@ -1769,6 +1776,10 @@ editor.defineMode("vi-visual", null, [
1769
1776
  // Exit
1770
1777
  ["Escape", "vi_vis_escape"],
1771
1778
  ["v", "vi_vis_escape"], // v again exits visual mode
1779
+
1780
+ // Pass through to standard editor shortcuts
1781
+ ["C-p", "command_palette"],
1782
+ ["C-q", "quit"],
1772
1783
  ], true);
1773
1784
 
1774
1785
  // Define vi-visual-line mode (line-wise)
@@ -1803,6 +1814,10 @@ editor.defineMode("vi-visual-line", null, [
1803
1814
  // Exit
1804
1815
  ["Escape", "vi_vis_escape"],
1805
1816
  ["V", "vi_vis_escape"], // V again exits visual-line mode
1817
+
1818
+ // Pass through to standard editor shortcuts
1819
+ ["C-p", "command_palette"],
1820
+ ["C-q", "quit"],
1806
1821
  ], true);
1807
1822
 
1808
1823
  // Define vi-visual-block mode (column/block selection)
@@ -1841,6 +1856,10 @@ editor.defineMode("vi-visual-block", null, [
1841
1856
  // Exit
1842
1857
  ["Escape", "vi_vblock_escape"],
1843
1858
  ["C-v", "vi_vblock_escape"], // Ctrl-v again exits visual-block mode
1859
+
1860
+ // Pass through to standard editor shortcuts
1861
+ ["C-p", "command_palette"],
1862
+ ["C-q", "quit"],
1844
1863
  ], true);
1845
1864
 
1846
1865
  // ============================================================================
@@ -2177,31 +2196,62 @@ async function executeCommand(
2177
2196
  switch (command) {
2178
2197
  case "write": {
2179
2198
  // :w - save current file
2180
- // :w filename - save as filename (not implemented yet)
2199
+ // :w filename - save to specified filename
2181
2200
  if (args) {
2182
- return { error: editor.t("error.save_as_not_implemented") };
2201
+ const bufferId = editor.getActiveBufferId();
2202
+ // Resolve path (could be relative or absolute)
2203
+ const path = args.startsWith("/") ? args : `${editor.getCwd()}/${args}`;
2204
+ editor.saveBufferToPath(bufferId, path);
2205
+ return { message: editor.t("status.file_saved") };
2183
2206
  }
2184
2207
  editor.executeAction("save");
2185
2208
  return { message: editor.t("status.file_saved") };
2186
2209
  }
2187
2210
 
2188
2211
  case "quit": {
2189
- // :q - quit (close buffer)
2190
- // :q! - force quit (discard changes)
2191
- const bufferId = editor.getActiveBufferId();
2192
- if (!force && editor.isBufferModified(bufferId)) {
2212
+ // :q - quit editor (like vim)
2213
+ // :q! - force quit (discard unsaved changes)
2214
+ if (force) {
2215
+ editor.executeAction("force_quit");
2216
+ return {};
2217
+ }
2218
+ // Check ALL buffers for unsaved changes
2219
+ const buffers = editor.listBuffers() as Array<{ id: number; modified: boolean }>;
2220
+ const hasModified = buffers.some((b) => b.modified);
2221
+ if (hasModified) {
2193
2222
  return { error: editor.t("error.no_write_since_change", { cmd: ":q!" }) };
2194
2223
  }
2195
- editor.executeAction("close_buffer");
2224
+ editor.executeAction("force_quit");
2196
2225
  return {};
2197
2226
  }
2198
2227
 
2199
2228
  case "wq":
2200
2229
  case "xit":
2201
2230
  case "exit": {
2202
- // :wq or :x - save and quit
2203
- editor.executeAction("save");
2204
- editor.executeAction("close_buffer");
2231
+ // :wq or :x - save current buffer and quit
2232
+ // :wq filename - save to filename and quit
2233
+ const wqBufferId = editor.getActiveBufferId();
2234
+
2235
+ if (args) {
2236
+ // Save to specified filename
2237
+ const path = args.startsWith("/") ? args : `${editor.getCwd()}/${args}`;
2238
+ editor.saveBufferToPath(wqBufferId, path);
2239
+ } else {
2240
+ // Save to existing path
2241
+ const wqPath = editor.getBufferPath(wqBufferId);
2242
+ if (!wqPath) {
2243
+ return { error: editor.t("error.no_file_name") };
2244
+ }
2245
+ editor.executeAction("save");
2246
+ }
2247
+
2248
+ // Check if any OTHER buffers have unsaved changes
2249
+ const allBuffers = editor.listBuffers() as Array<{ id: number; modified: boolean }>;
2250
+ const otherModified = allBuffers.some((b: { id: number; modified: boolean }) => b.id !== wqBufferId && b.modified);
2251
+ if (otherModified) {
2252
+ return { error: editor.t("error.other_buffers_modified", { cmd: ":wqa" }) };
2253
+ }
2254
+ editor.executeAction("force_quit");
2205
2255
  return {};
2206
2256
  }
2207
2257
 
@@ -2215,16 +2265,15 @@ async function executeCommand(
2215
2265
  // :qa - quit all
2216
2266
  // :qa! - force quit all
2217
2267
  if (force) {
2218
- editor.executeAction("quit_all");
2268
+ editor.executeAction("force_quit");
2219
2269
  } else {
2220
2270
  // Check if any buffer is modified
2221
- const buffers = editor.listBuffers();
2222
- for (const buf of buffers) {
2223
- if (buf.modified) {
2224
- return { error: editor.t("error.no_write_since_change", { cmd: ":qa!" }) };
2225
- }
2271
+ const allBufs = editor.listBuffers() as Array<{ id: number; modified: boolean }>;
2272
+ const anyModified = allBufs.some((b) => b.modified);
2273
+ if (anyModified) {
2274
+ return { error: editor.t("error.no_write_since_change", { cmd: ":qa!" }) };
2226
2275
  }
2227
- editor.executeAction("quit_all");
2276
+ editor.executeAction("force_quit");
2228
2277
  }
2229
2278
  return {};
2230
2279
  }
@@ -2232,7 +2281,7 @@ async function executeCommand(
2232
2281
  case "wqall": {
2233
2282
  // :wqa or :xa - save all and quit
2234
2283
  editor.executeAction("save_all");
2235
- editor.executeAction("quit_all");
2284
+ editor.executeAction("force_quit");
2236
2285
  return {};
2237
2286
  }
2238
2287
 
@@ -2307,7 +2356,7 @@ async function executeCommand(
2307
2356
  if (!force && editor.isBufferModified(bufferId)) {
2308
2357
  return { error: editor.t("error.no_write_since_change", { cmd: ":bd!" }) };
2309
2358
  }
2310
- editor.executeAction("close_buffer");
2359
+ editor.executeAction("close");
2311
2360
  return {};
2312
2361
  }
2313
2362
 
@@ -2421,7 +2470,7 @@ async function executeCommand(
2421
2470
  if (!force && editor.isBufferModified(bufferId)) {
2422
2471
  return { error: editor.t("error.no_write_since_change", { cmd: ":close!" }) };
2423
2472
  }
2424
- editor.executeAction("close_buffer");
2473
+ editor.executeAction("close");
2425
2474
  return {};
2426
2475
  }
2427
2476
 
@@ -2442,7 +2491,7 @@ async function executeCommand(
2442
2491
  if (!force && editor.isBufferModified(bufferId)) {
2443
2492
  return { error: editor.t("error.no_write_since_change", { cmd: ":tabclose!" }) };
2444
2493
  }
2445
- editor.executeAction("close_buffer");
2494
+ editor.executeAction("close");
2446
2495
  return {};
2447
2496
  }
2448
2497
 
@@ -2724,28 +2773,33 @@ editor.on("prompt_confirmed", "vi_command_handler");
2724
2773
  let viModeEnabled = false;
2725
2774
 
2726
2775
  globalThis.vi_mode_toggle = function (): void {
2776
+ editor.debug("[vi_mode_toggle] called, viModeEnabled was: " + viModeEnabled);
2727
2777
  viModeEnabled = !viModeEnabled;
2778
+ editor.debug("[vi_mode_toggle] viModeEnabled now: " + viModeEnabled);
2728
2779
 
2729
2780
  if (viModeEnabled) {
2781
+ editor.debug("[vi_mode_toggle] enabling vi mode, calling switchMode('normal')");
2730
2782
  switchMode("normal");
2783
+ editor.debug("[vi_mode_toggle] switchMode done, setting status");
2731
2784
  editor.setStatus(editor.t("status.enabled"));
2732
2785
  } else {
2786
+ editor.debug("[vi_mode_toggle] disabling vi mode");
2733
2787
  editor.setEditorMode(null);
2734
2788
  state.mode = "normal";
2735
2789
  state.pendingOperator = null;
2736
2790
  editor.setStatus(editor.t("status.disabled"));
2737
2791
  }
2792
+ editor.debug("[vi_mode_toggle] done");
2738
2793
  };
2739
2794
 
2740
2795
  editor.registerCommand(
2741
2796
  "%cmd.toggle_vi_mode",
2742
2797
  "%cmd.toggle_vi_mode_desc",
2743
2798
  "vi_mode_toggle",
2744
- "normal",
2799
+ null, // Always visible - needed to enable vi mode in the first place
2745
2800
  );
2746
2801
 
2747
2802
  // ============================================================================
2748
2803
  // Initialization
2749
2804
  // ============================================================================
2750
2805
 
2751
- editor.setStatus(editor.t("status.loaded"));