@fresh-editor/fresh-editor 0.1.67 → 0.1.70

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 (64) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +2 -0
  3. package/package.json +1 -1
  4. package/plugins/audit_mode.i18n.json +380 -0
  5. package/plugins/audit_mode.ts +836 -68
  6. package/plugins/buffer_modified.i18n.json +32 -0
  7. package/plugins/buffer_modified.ts +5 -3
  8. package/plugins/calculator.i18n.json +44 -0
  9. package/plugins/calculator.ts +6 -4
  10. package/plugins/clangd-lsp.ts +2 -0
  11. package/plugins/clangd_support.i18n.json +104 -0
  12. package/plugins/clangd_support.ts +18 -16
  13. package/plugins/color_highlighter.i18n.json +68 -0
  14. package/plugins/color_highlighter.ts +12 -10
  15. package/plugins/config-schema.json +28 -145
  16. package/plugins/csharp-lsp.ts +2 -0
  17. package/plugins/csharp_support.i18n.json +38 -0
  18. package/plugins/csharp_support.ts +6 -4
  19. package/plugins/css-lsp.ts +2 -0
  20. package/plugins/diagnostics_panel.i18n.json +110 -0
  21. package/plugins/diagnostics_panel.ts +19 -17
  22. package/plugins/find_references.i18n.json +128 -0
  23. package/plugins/find_references.ts +22 -20
  24. package/plugins/git_blame.i18n.json +230 -0
  25. package/plugins/git_blame.ts +39 -37
  26. package/plugins/git_find_file.i18n.json +146 -0
  27. package/plugins/git_find_file.ts +24 -22
  28. package/plugins/git_grep.i18n.json +80 -0
  29. package/plugins/git_grep.ts +15 -13
  30. package/plugins/git_gutter.i18n.json +44 -0
  31. package/plugins/git_gutter.ts +7 -5
  32. package/plugins/git_log.i18n.json +224 -0
  33. package/plugins/git_log.ts +41 -39
  34. package/plugins/go-lsp.ts +2 -0
  35. package/plugins/html-lsp.ts +2 -0
  36. package/plugins/json-lsp.ts +2 -0
  37. package/plugins/lib/fresh.d.ts +53 -13
  38. package/plugins/lib/index.ts +1 -1
  39. package/plugins/lib/navigation-controller.ts +3 -3
  40. package/plugins/lib/panel-manager.ts +15 -13
  41. package/plugins/lib/virtual-buffer-factory.ts +84 -112
  42. package/plugins/live_grep.i18n.json +80 -0
  43. package/plugins/live_grep.ts +15 -13
  44. package/plugins/markdown_compose.i18n.json +104 -0
  45. package/plugins/markdown_compose.ts +17 -15
  46. package/plugins/merge_conflict.i18n.json +380 -0
  47. package/plugins/merge_conflict.ts +72 -73
  48. package/plugins/path_complete.i18n.json +38 -0
  49. package/plugins/path_complete.ts +6 -4
  50. package/plugins/python-lsp.ts +2 -0
  51. package/plugins/rust-lsp.ts +2 -0
  52. package/plugins/search_replace.i18n.json +188 -0
  53. package/plugins/search_replace.ts +31 -29
  54. package/plugins/test_i18n.i18n.json +12 -0
  55. package/plugins/test_i18n.ts +18 -0
  56. package/plugins/theme_editor.i18n.json +1417 -0
  57. package/plugins/theme_editor.ts +73 -69
  58. package/plugins/todo_highlighter.i18n.json +86 -0
  59. package/plugins/todo_highlighter.ts +15 -13
  60. package/plugins/typescript-lsp.ts +2 -0
  61. package/plugins/vi_mode.i18n.json +716 -0
  62. package/plugins/vi_mode.ts +1195 -78
  63. package/plugins/welcome.i18n.json +110 -0
  64. package/plugins/welcome.ts +18 -16
@@ -1,4 +1,6 @@
1
1
  /// <reference path="../types/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
2
4
 
3
5
  /**
4
6
  * 3-Way Merge Conflict Resolution Plugin
@@ -477,7 +479,7 @@ function buildFullFileEntries(side: "ours" | "theirs"): TextPropertyEntry[] {
477
479
  // If we don't have the git version, fall back to showing conflict regions only
478
480
  if (!content) {
479
481
  entries.push({
480
- text: `(Git version not available - showing conflict regions only)\n\n`,
482
+ text: editor.t("panel.git_unavailable") + "\n\n",
481
483
  properties: { type: "warning" },
482
484
  });
483
485
 
@@ -487,7 +489,7 @@ function buildFullFileEntries(side: "ours" | "theirs"): TextPropertyEntry[] {
487
489
  const isSelected = conflict.index === mergeState.selectedIndex;
488
490
 
489
491
  entries.push({
490
- text: `--- Conflict ${conflict.index + 1} ---\n`,
492
+ text: `--- ${editor.t("panel.conflict", { index: String(conflict.index + 1) })} ---\n`,
491
493
  properties: {
492
494
  type: "conflict-header",
493
495
  conflictIndex: conflict.index,
@@ -496,7 +498,7 @@ function buildFullFileEntries(side: "ours" | "theirs"): TextPropertyEntry[] {
496
498
  });
497
499
 
498
500
  entries.push({
499
- text: (conflictContent || "(empty)") + "\n",
501
+ text: (conflictContent || editor.t("panel.empty")) + "\n",
500
502
  properties: {
501
503
  type: "conflict-content",
502
504
  conflictIndex: conflict.index,
@@ -619,7 +621,7 @@ function buildOursEntries(): TextPropertyEntry[] {
619
621
  properties: { type: "separator" },
620
622
  });
621
623
  entries.push({
622
- text: " OURS (Read-only) - Changes from your branch\n",
624
+ text: " " + editor.t("panel.ours_header") + "\n",
623
625
  properties: { type: "header", panel: "ours" },
624
626
  });
625
627
  entries.push({
@@ -631,10 +633,10 @@ function buildOursEntries(): TextPropertyEntry[] {
631
633
  for (const conflict of mergeState.conflicts) {
632
634
  const isSelected = conflict.index === mergeState.selectedIndex;
633
635
  const marker = isSelected ? "> " : " ";
634
- const status = conflict.resolved ? "[RESOLVED]" : "[PENDING]";
636
+ const status = conflict.resolved ? editor.t("panel.resolved") : editor.t("panel.pending");
635
637
 
636
638
  entries.push({
637
- text: `\n${marker}Conflict ${conflict.index + 1} ${status}\n`,
639
+ text: `\n${marker}${editor.t("panel.conflict", { index: String(conflict.index + 1) })} ${status}\n`,
638
640
  properties: {
639
641
  type: "conflict-header",
640
642
  conflictIndex: conflict.index,
@@ -649,7 +651,7 @@ function buildOursEntries(): TextPropertyEntry[] {
649
651
  });
650
652
 
651
653
  // Content
652
- const content = conflict.ours || "(empty)";
654
+ const content = conflict.ours || editor.t("panel.empty");
653
655
  for (const line of content.split("\n")) {
654
656
  entries.push({
655
657
  text: ` ${line}\n`,
@@ -677,7 +679,7 @@ function buildTheirsEntries(): TextPropertyEntry[] {
677
679
  properties: { type: "separator" },
678
680
  });
679
681
  entries.push({
680
- text: " THEIRS (Read-only) - Incoming changes\n",
682
+ text: " " + editor.t("panel.theirs_header") + "\n",
681
683
  properties: { type: "header", panel: "theirs" },
682
684
  });
683
685
  entries.push({
@@ -689,10 +691,10 @@ function buildTheirsEntries(): TextPropertyEntry[] {
689
691
  for (const conflict of mergeState.conflicts) {
690
692
  const isSelected = conflict.index === mergeState.selectedIndex;
691
693
  const marker = isSelected ? "> " : " ";
692
- const status = conflict.resolved ? "[RESOLVED]" : "[PENDING]";
694
+ const status = conflict.resolved ? editor.t("panel.resolved") : editor.t("panel.pending");
693
695
 
694
696
  entries.push({
695
- text: `\n${marker}Conflict ${conflict.index + 1} ${status}\n`,
697
+ text: `\n${marker}${editor.t("panel.conflict", { index: String(conflict.index + 1) })} ${status}\n`,
696
698
  properties: {
697
699
  type: "conflict-header",
698
700
  conflictIndex: conflict.index,
@@ -707,7 +709,7 @@ function buildTheirsEntries(): TextPropertyEntry[] {
707
709
  });
708
710
 
709
711
  // Content
710
- const content = conflict.theirs || "(empty)";
712
+ const content = conflict.theirs || editor.t("panel.empty");
711
713
  for (const line of content.split("\n")) {
712
714
  entries.push({
713
715
  text: ` ${line}\n`,
@@ -735,7 +737,7 @@ function buildResultEntries(): TextPropertyEntry[] {
735
737
  properties: { type: "separator" },
736
738
  });
737
739
  entries.push({
738
- text: " RESULT (Editable) - Resolved content\n",
740
+ text: " " + editor.t("panel.result_header") + "\n",
739
741
  properties: { type: "header", panel: "result" },
740
742
  });
741
743
  entries.push({
@@ -744,17 +746,16 @@ function buildResultEntries(): TextPropertyEntry[] {
744
746
  });
745
747
 
746
748
  // Build result content
747
- let resultText = "";
748
749
  const unresolvedCount = mergeState.conflicts.filter(c => !c.resolved).length;
749
750
 
750
751
  if (unresolvedCount > 0) {
751
752
  entries.push({
752
- text: `\n ⚠ ${unresolvedCount} conflict(s) remaining\n\n`,
753
+ text: `\n ⚠ ${editor.t("panel.remaining", { count: String(unresolvedCount) })}\n\n`,
753
754
  properties: { type: "warning" },
754
755
  });
755
756
  } else {
756
757
  entries.push({
757
- text: "\n ✓ All conflicts resolved!\n\n",
758
+ text: "\n ✓ " + editor.t("panel.all_resolved") + "\n\n",
758
759
  properties: { type: "success" },
759
760
  });
760
761
  }
@@ -765,7 +766,7 @@ function buildResultEntries(): TextPropertyEntry[] {
765
766
  const marker = isSelected ? "> " : " ";
766
767
 
767
768
  entries.push({
768
- text: `${marker}Conflict ${conflict.index + 1}:\n`,
769
+ text: `${marker}${editor.t("panel.conflict", { index: String(conflict.index + 1) })}:\n`,
769
770
  properties: {
770
771
  type: "conflict-header",
771
772
  conflictIndex: conflict.index,
@@ -776,7 +777,7 @@ function buildResultEntries(): TextPropertyEntry[] {
776
777
  if (conflict.resolved && conflict.resolvedContent !== undefined) {
777
778
  // Show resolved content
778
779
  entries.push({
779
- text: ` [Resolved: ${conflict.resolution}]\n`,
780
+ text: ` ${editor.t("panel.resolved_with", { resolution: conflict.resolution || "" })}\n`,
780
781
  properties: { type: "resolution-info", resolution: conflict.resolution },
781
782
  });
782
783
 
@@ -797,7 +798,7 @@ function buildResultEntries(): TextPropertyEntry[] {
797
798
  properties: { type: "action-prefix" },
798
799
  });
799
800
  entries.push({
800
- text: "[u] Accept Ours",
801
+ text: editor.t("btn.accept_ours"),
801
802
  properties: {
802
803
  type: "action-button",
803
804
  conflictIndex: conflict.index,
@@ -809,7 +810,7 @@ function buildResultEntries(): TextPropertyEntry[] {
809
810
  properties: { type: "action-separator" },
810
811
  });
811
812
  entries.push({
812
- text: "[t] Accept Theirs",
813
+ text: editor.t("btn.accept_theirs"),
813
814
  properties: {
814
815
  type: "action-button",
815
816
  conflictIndex: conflict.index,
@@ -821,7 +822,7 @@ function buildResultEntries(): TextPropertyEntry[] {
821
822
  properties: { type: "action-separator" },
822
823
  });
823
824
  entries.push({
824
- text: "[b] Both",
825
+ text: editor.t("btn.both"),
825
826
  properties: {
826
827
  type: "action-button",
827
828
  conflictIndex: conflict.index,
@@ -847,7 +848,7 @@ function buildResultEntries(): TextPropertyEntry[] {
847
848
  });
848
849
  // Navigation
849
850
  entries.push({
850
- text: "[n] Next",
851
+ text: editor.t("btn.next"),
851
852
  properties: { type: "help-button", onClick: "merge_next_conflict" },
852
853
  });
853
854
  entries.push({
@@ -855,7 +856,7 @@ function buildResultEntries(): TextPropertyEntry[] {
855
856
  properties: { type: "help-separator" },
856
857
  });
857
858
  entries.push({
858
- text: "[p] Prev",
859
+ text: editor.t("btn.prev"),
859
860
  properties: { type: "help-button", onClick: "merge_prev_conflict" },
860
861
  });
861
862
  entries.push({
@@ -864,7 +865,7 @@ function buildResultEntries(): TextPropertyEntry[] {
864
865
  });
865
866
  // Resolution
866
867
  entries.push({
867
- text: "[u] Use Ours",
868
+ text: editor.t("btn.use_ours"),
868
869
  properties: { type: "help-button", onClick: "merge_use_ours" },
869
870
  });
870
871
  entries.push({
@@ -872,7 +873,7 @@ function buildResultEntries(): TextPropertyEntry[] {
872
873
  properties: { type: "help-separator" },
873
874
  });
874
875
  entries.push({
875
- text: "[t] Take Theirs",
876
+ text: editor.t("btn.take_theirs"),
876
877
  properties: { type: "help-button", onClick: "merge_take_theirs" },
877
878
  });
878
879
  entries.push({
@@ -880,7 +881,7 @@ function buildResultEntries(): TextPropertyEntry[] {
880
881
  properties: { type: "help-separator" },
881
882
  });
882
883
  entries.push({
883
- text: "[b] Both",
884
+ text: editor.t("btn.both"),
884
885
  properties: { type: "help-button", onClick: "merge_use_both" },
885
886
  });
886
887
  entries.push({
@@ -889,7 +890,7 @@ function buildResultEntries(): TextPropertyEntry[] {
889
890
  });
890
891
  // Completion
891
892
  entries.push({
892
- text: "[s] Save & Exit",
893
+ text: editor.t("btn.save_exit"),
893
894
  properties: { type: "help-button", onClick: "merge_save_and_exit" },
894
895
  });
895
896
  entries.push({
@@ -897,7 +898,7 @@ function buildResultEntries(): TextPropertyEntry[] {
897
898
  properties: { type: "help-separator" },
898
899
  });
899
900
  entries.push({
900
- text: "[q] Abort",
901
+ text: editor.t("btn.abort"),
901
902
  properties: { type: "help-button", onClick: "merge_abort" },
902
903
  });
903
904
  entries.push({
@@ -1037,9 +1038,9 @@ function updateStatusBar(): void {
1037
1038
  const remaining = total - resolved;
1038
1039
 
1039
1040
  if (remaining > 0) {
1040
- editor.setStatus(`Merge: ${remaining} of ${total} conflicts remaining | Current: ${mergeState.selectedIndex + 1}`);
1041
+ editor.setStatus(editor.t("status.progress", { remaining: String(remaining), total: String(total), current: String(mergeState.selectedIndex + 1) }));
1041
1042
  } else {
1042
- editor.setStatus(`Merge: All ${total} conflicts resolved! Press 's' to save`);
1043
+ editor.setStatus(editor.t("status.all_resolved", { total: String(total) }));
1043
1044
  }
1044
1045
  }
1045
1046
 
@@ -1174,7 +1175,7 @@ function computeResultConflictOffset(conflictIndex: number): number {
1174
1175
  */
1175
1176
  globalThis.start_merge_conflict = async function(): Promise<void> {
1176
1177
  if (mergeState.isActive) {
1177
- editor.setStatus("Merge mode already active");
1178
+ editor.setStatus(editor.t("status.already_active"));
1178
1179
  return;
1179
1180
  }
1180
1181
 
@@ -1182,7 +1183,7 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1182
1183
  const info = editor.getBufferInfo(bufferId);
1183
1184
 
1184
1185
  if (!info || !info.path) {
1185
- editor.setStatus("No file open");
1186
+ editor.setStatus(editor.t("status.no_file"));
1186
1187
  return;
1187
1188
  }
1188
1189
 
@@ -1197,7 +1198,7 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1197
1198
  editor.debug(`Merge: git rev-parse exit_code=${gitCheck.exit_code}, stdout=${gitCheck.stdout.trim()}`);
1198
1199
 
1199
1200
  if (gitCheck.exit_code !== 0 || gitCheck.stdout.trim() !== "true") {
1200
- editor.setStatus("Not in a git repository - merge conflict resolution requires git");
1201
+ editor.setStatus(editor.t("status.not_git_repo"));
1201
1202
  return;
1202
1203
  }
1203
1204
 
@@ -1208,7 +1209,7 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1208
1209
  const hasUnmergedEntries = lsFilesResult.exit_code === 0 && lsFilesResult.stdout.trim().length > 0;
1209
1210
 
1210
1211
  if (!hasUnmergedEntries) {
1211
- editor.setStatus("No unmerged entries - file is not in a merge conflict state");
1212
+ editor.setStatus(editor.t("status.no_unmerged"));
1212
1213
  return;
1213
1214
  }
1214
1215
 
@@ -1221,7 +1222,7 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1221
1222
  editor.debug(`Merge: git show :0: failed, reading working tree file`);
1222
1223
  const fileContent = await editor.readFile(info.path);
1223
1224
  if (!fileContent) {
1224
- editor.setStatus("Failed to read file content");
1225
+ editor.setStatus(editor.t("status.failed_read"));
1225
1226
  return;
1226
1227
  }
1227
1228
  content = fileContent;
@@ -1229,7 +1230,7 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1229
1230
  // The staged version shouldn't have conflict markers, use working tree
1230
1231
  const fileContent = await editor.readFile(info.path);
1231
1232
  if (!fileContent) {
1232
- editor.setStatus("Failed to read file content");
1233
+ editor.setStatus(editor.t("status.failed_read"));
1233
1234
  return;
1234
1235
  }
1235
1236
  content = fileContent;
@@ -1240,11 +1241,11 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1240
1241
  editor.debug(`Merge: file has conflict markers: ${hasMarkers}, content length: ${content.length}`);
1241
1242
 
1242
1243
  if (!hasMarkers) {
1243
- editor.setStatus("No conflict markers found in file content");
1244
+ editor.setStatus(editor.t("status.no_markers"));
1244
1245
  return;
1245
1246
  }
1246
1247
 
1247
- editor.setStatus("Starting merge conflict resolution...");
1248
+ editor.setStatus(editor.t("status.starting"));
1248
1249
 
1249
1250
  // Store original state
1250
1251
  mergeState.sourceBufferId = bufferId;
@@ -1258,7 +1259,7 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1258
1259
  editor.debug(`Merge: parseConflicts found ${mergeState.conflicts.length} conflicts`);
1259
1260
 
1260
1261
  if (mergeState.conflicts.length === 0) {
1261
- editor.setStatus("Failed to parse conflict markers");
1262
+ editor.setStatus(editor.t("status.failed_parse"));
1262
1263
  // Log more detail for debugging
1263
1264
  editor.debug(`Merge: regex failed, content has <<<<<<< at index ${content.indexOf("<<<<<<<")}`);
1264
1265
  editor.debug(`Merge: content around <<<<<<< : ${content.substring(content.indexOf("<<<<<<<") - 20, content.indexOf("<<<<<<<") + 100)}`);
@@ -1308,9 +1309,9 @@ globalThis.start_merge_conflict = async function(): Promise<void> {
1308
1309
 
1309
1310
  const remaining = mergeState.conflicts.length - autoResolved;
1310
1311
  if (remaining > 0) {
1311
- editor.setStatus(`Merge: ${remaining} conflicts to resolve (${autoResolved} auto-resolved)`);
1312
+ editor.setStatus(editor.t("status.conflicts_to_resolve", { remaining: String(remaining), auto_resolved: String(autoResolved) }));
1312
1313
  } else {
1313
- editor.setStatus(`Merge: All ${mergeState.conflicts.length} conflicts auto-resolved! Press 's' to save`);
1314
+ editor.setStatus(editor.t("status.all_auto_resolved", { total: String(mergeState.conflicts.length) }));
1314
1315
  }
1315
1316
  };
1316
1317
 
@@ -1406,16 +1407,16 @@ globalThis.merge_next_conflict = function(): void {
1406
1407
  editor.debug(`merge_next_conflict called, isActive=${mergeState.isActive}, conflicts=${mergeState.conflicts.length}`);
1407
1408
 
1408
1409
  if (!mergeState.isActive) {
1409
- editor.setStatus("No active merge - use 'Merge: Start Resolution' first");
1410
+ editor.setStatus(editor.t("status.no_active_merge"));
1410
1411
  return;
1411
1412
  }
1412
1413
  if (mergeState.conflicts.length === 0) {
1413
- editor.setStatus("No conflicts to navigate");
1414
+ editor.setStatus(editor.t("status.no_conflicts"));
1414
1415
  return;
1415
1416
  }
1416
1417
  if (mergeState.conflicts.length === 1) {
1417
1418
  // Single conflict: just re-scroll to it (useful for re-focusing)
1418
- editor.setStatus("Conflict 1 of 1 (re-focused)");
1419
+ editor.setStatus(editor.t("status.single_refocused"));
1419
1420
  scrollToSelectedConflict();
1420
1421
  return;
1421
1422
  }
@@ -1428,7 +1429,7 @@ globalThis.merge_next_conflict = function(): void {
1428
1429
  while (index !== startIndex) {
1429
1430
  if (!mergeState.conflicts[index].resolved) {
1430
1431
  mergeState.selectedIndex = index;
1431
- editor.setStatus(`Conflict ${index + 1} of ${mergeState.conflicts.length}`);
1432
+ editor.setStatus(editor.t("status.conflict_of", { current: String(index + 1), total: String(mergeState.conflicts.length) }));
1432
1433
  updateViews();
1433
1434
  scrollToSelectedConflict();
1434
1435
  return;
@@ -1438,7 +1439,7 @@ globalThis.merge_next_conflict = function(): void {
1438
1439
 
1439
1440
  // If all resolved, just move to next
1440
1441
  mergeState.selectedIndex = (mergeState.selectedIndex + 1) % mergeState.conflicts.length;
1441
- editor.setStatus(`Conflict ${mergeState.selectedIndex + 1} of ${mergeState.conflicts.length} (all resolved)`);
1442
+ editor.setStatus(editor.t("status.conflict_all_resolved", { current: String(mergeState.selectedIndex + 1), total: String(mergeState.conflicts.length) }));
1442
1443
  updateViews();
1443
1444
  scrollToSelectedConflict();
1444
1445
  };
@@ -1447,16 +1448,16 @@ globalThis.merge_prev_conflict = function(): void {
1447
1448
  editor.debug(`merge_prev_conflict called, isActive=${mergeState.isActive}, conflicts=${mergeState.conflicts.length}`);
1448
1449
 
1449
1450
  if (!mergeState.isActive) {
1450
- editor.setStatus("No active merge - use 'Merge: Start Resolution' first");
1451
+ editor.setStatus(editor.t("status.no_active_merge"));
1451
1452
  return;
1452
1453
  }
1453
1454
  if (mergeState.conflicts.length === 0) {
1454
- editor.setStatus("No conflicts to navigate");
1455
+ editor.setStatus(editor.t("status.no_conflicts"));
1455
1456
  return;
1456
1457
  }
1457
1458
  if (mergeState.conflicts.length === 1) {
1458
1459
  // Single conflict: just re-scroll to it (useful for re-focusing)
1459
- editor.setStatus("Conflict 1 of 1 (re-focused)");
1460
+ editor.setStatus(editor.t("status.single_refocused"));
1460
1461
  scrollToSelectedConflict();
1461
1462
  return;
1462
1463
  }
@@ -1469,7 +1470,7 @@ globalThis.merge_prev_conflict = function(): void {
1469
1470
  while (index !== startIndex) {
1470
1471
  if (!mergeState.conflicts[index].resolved) {
1471
1472
  mergeState.selectedIndex = index;
1472
- editor.setStatus(`Conflict ${index + 1} of ${mergeState.conflicts.length}`);
1473
+ editor.setStatus(editor.t("status.conflict_of", { current: String(index + 1), total: String(mergeState.conflicts.length) }));
1473
1474
  updateViews();
1474
1475
  scrollToSelectedConflict();
1475
1476
  return;
@@ -1479,7 +1480,7 @@ globalThis.merge_prev_conflict = function(): void {
1479
1480
 
1480
1481
  // If all resolved, just move to previous
1481
1482
  mergeState.selectedIndex = (mergeState.selectedIndex - 1 + mergeState.conflicts.length) % mergeState.conflicts.length;
1482
- editor.setStatus(`Conflict ${mergeState.selectedIndex + 1} of ${mergeState.conflicts.length} (all resolved)`);
1483
+ editor.setStatus(editor.t("status.conflict_all_resolved", { current: String(mergeState.selectedIndex + 1), total: String(mergeState.conflicts.length) }));
1483
1484
  updateViews();
1484
1485
  scrollToSelectedConflict();
1485
1486
  };
@@ -1490,7 +1491,7 @@ globalThis.merge_prev_conflict = function(): void {
1490
1491
 
1491
1492
  globalThis.merge_use_ours = function(): void {
1492
1493
  if (!mergeState.isActive) {
1493
- editor.setStatus("No active merge - use 'Merge: Start Resolution' first");
1494
+ editor.setStatus(editor.t("status.no_active_merge"));
1494
1495
  return;
1495
1496
  }
1496
1497
 
@@ -1510,7 +1511,7 @@ globalThis.merge_use_ours = function(): void {
1510
1511
 
1511
1512
  globalThis.merge_take_theirs = function(): void {
1512
1513
  if (!mergeState.isActive) {
1513
- editor.setStatus("No active merge - use 'Merge: Start Resolution' first");
1514
+ editor.setStatus(editor.t("status.no_active_merge"));
1514
1515
  return;
1515
1516
  }
1516
1517
 
@@ -1530,7 +1531,7 @@ globalThis.merge_take_theirs = function(): void {
1530
1531
 
1531
1532
  globalThis.merge_use_both = function(): void {
1532
1533
  if (!mergeState.isActive) {
1533
- editor.setStatus("No active merge - use 'Merge: Start Resolution' first");
1534
+ editor.setStatus(editor.t("status.no_active_merge"));
1534
1535
  return;
1535
1536
  }
1536
1537
 
@@ -1572,7 +1573,7 @@ function moveToNextUnresolved(): void {
1572
1573
 
1573
1574
  globalThis.merge_save_and_exit = async function(): Promise<void> {
1574
1575
  if (!mergeState.isActive) {
1575
- editor.setStatus("No active merge - use 'Merge: Start Resolution' first");
1576
+ editor.setStatus(editor.t("status.no_active_merge"));
1576
1577
  return;
1577
1578
  }
1578
1579
 
@@ -1580,7 +1581,7 @@ globalThis.merge_save_and_exit = async function(): Promise<void> {
1580
1581
 
1581
1582
  if (unresolvedCount > 0) {
1582
1583
  // TODO: Add confirmation prompt
1583
- editor.setStatus(`Cannot save: ${unresolvedCount} unresolved conflicts remaining`);
1584
+ editor.setStatus(editor.t("status.cannot_save", { count: String(unresolvedCount) }));
1584
1585
  return;
1585
1586
  }
1586
1587
 
@@ -1617,12 +1618,12 @@ globalThis.merge_save_and_exit = async function(): Promise<void> {
1617
1618
  // Close merge panels
1618
1619
  closeMergePanels();
1619
1620
 
1620
- editor.setStatus("Merge complete! File updated with resolved content");
1621
+ editor.setStatus(editor.t("status.complete"));
1621
1622
  };
1622
1623
 
1623
1624
  globalThis.merge_abort = function(): void {
1624
1625
  if (!mergeState.isActive) {
1625
- editor.setStatus("No active merge - nothing to abort");
1626
+ editor.setStatus(editor.t("status.nothing_to_abort"));
1626
1627
  return;
1627
1628
  }
1628
1629
 
@@ -1631,7 +1632,7 @@ globalThis.merge_abort = function(): void {
1631
1632
  // Close merge panels without saving
1632
1633
  closeMergePanels();
1633
1634
 
1634
- editor.setStatus("Merge aborted - no changes made");
1635
+ editor.setStatus(editor.t("status.aborted"));
1635
1636
  };
1636
1637
 
1637
1638
  /**
@@ -1692,9 +1693,7 @@ function closeMergePanels(): void {
1692
1693
  // =============================================================================
1693
1694
 
1694
1695
  globalThis.merge_show_help = function(): void {
1695
- editor.setStatus(
1696
- "Merge: [n/p] Navigate | [u] Ours [t] Theirs [b] Both | [s] Save [q] Abort"
1697
- );
1696
+ editor.setStatus(editor.t("status.help"));
1698
1697
  };
1699
1698
 
1700
1699
  // =============================================================================
@@ -1723,7 +1722,7 @@ globalThis.onMergeBufferActivated = async function(data: { buffer_id: number }):
1723
1722
  // Check for unmerged entries
1724
1723
  const lsFiles = await editor.spawnProcess("git", ["ls-files", "-u", info.path], fileDir);
1725
1724
  if (lsFiles.exit_code === 0 && lsFiles.stdout.trim().length > 0) {
1726
- editor.setStatus(`Conflicts detected! Use 'Merge: Start Resolution' or run start_merge_conflict`);
1725
+ editor.setStatus(editor.t("status.detected"));
1727
1726
  }
1728
1727
  } catch (e) {
1729
1728
  // Not in git repo or other error, ignore
@@ -1748,7 +1747,7 @@ globalThis.onMergeAfterFileOpen = async function(data: { buffer_id: number; path
1748
1747
  // Check for unmerged entries
1749
1748
  const lsFiles = await editor.spawnProcess("git", ["ls-files", "-u", data.path], fileDir);
1750
1749
  if (lsFiles.exit_code === 0 && lsFiles.stdout.trim().length > 0) {
1751
- editor.setStatus(`⚠ Merge conflicts detected in ${data.path} - Use 'Merge: Start Resolution'`);
1750
+ editor.setStatus(editor.t("status.detected_file", { path: data.path }));
1752
1751
  }
1753
1752
  } catch (e) {
1754
1753
  // Not in git repo or other error, ignore
@@ -1768,13 +1767,13 @@ editor.on("after_file_open", "onMergeAfterFileOpen");
1768
1767
 
1769
1768
  // Commands that are only available during active merge mode
1770
1769
  const MERGE_MODE_COMMANDS = [
1771
- { name: "Merge: Next Conflict", desc: "Jump to next unresolved conflict", action: "merge_next_conflict" },
1772
- { name: "Merge: Previous Conflict", desc: "Jump to previous unresolved conflict", action: "merge_prev_conflict" },
1773
- { name: "Merge: Use Ours", desc: "Accept our version for current conflict", action: "merge_use_ours" },
1774
- { name: "Merge: Take Theirs", desc: "Accept their version for current conflict", action: "merge_take_theirs" },
1775
- { name: "Merge: Use Both", desc: "Accept both versions for current conflict", action: "merge_use_both" },
1776
- { name: "Merge: Save & Exit", desc: "Save resolved content and exit merge mode", action: "merge_save_and_exit" },
1777
- { name: "Merge: Abort", desc: "Abort merge resolution without saving", action: "merge_abort" },
1770
+ { name: "%cmd.next", desc: "%cmd.next_desc", action: "merge_next_conflict" },
1771
+ { name: "%cmd.prev", desc: "%cmd.prev_desc", action: "merge_prev_conflict" },
1772
+ { name: "%cmd.use_ours", desc: "%cmd.use_ours_desc", action: "merge_use_ours" },
1773
+ { name: "%cmd.take_theirs", desc: "%cmd.take_theirs_desc", action: "merge_take_theirs" },
1774
+ { name: "%cmd.use_both", desc: "%cmd.use_both_desc", action: "merge_use_both" },
1775
+ { name: "%cmd.save_exit", desc: "%cmd.save_exit_desc", action: "merge_save_and_exit" },
1776
+ { name: "%cmd.abort", desc: "%cmd.abort_desc", action: "merge_abort" },
1778
1777
  ];
1779
1778
 
1780
1779
  /**
@@ -1797,8 +1796,8 @@ function unregisterMergeModeCommands(): void {
1797
1796
 
1798
1797
  // Only register "Start Resolution" at plugin load - other commands are registered dynamically
1799
1798
  editor.registerCommand(
1800
- "Merge: Start Resolution",
1801
- "Start 3-way merge conflict resolution for current file",
1799
+ "%cmd.start",
1800
+ "%cmd.start_desc",
1802
1801
  "start_merge_conflict",
1803
1802
  "normal"
1804
1803
  );
@@ -1807,5 +1806,5 @@ editor.registerCommand(
1807
1806
  // Plugin Initialization
1808
1807
  // =============================================================================
1809
1808
 
1810
- editor.setStatus("Merge Conflict Resolution plugin loaded");
1809
+ editor.setStatus(editor.t("status.ready"));
1811
1810
  editor.debug("Merge plugin initialized - Use 'Merge: Start Resolution' for files with conflicts");
@@ -0,0 +1,38 @@
1
+ {
2
+ "en": {
3
+ "status.loaded": "Path completion plugin loaded successfully",
4
+ "suggestion.directory": "directory",
5
+ "suggestion.new_file": "%{filename} (new file)",
6
+ "suggestion.new_file_desc": "File does not exist yet"
7
+ },
8
+ "es": {
9
+ "status.loaded": "Plugin de autocompletado de rutas cargado correctamente",
10
+ "suggestion.directory": "directorio",
11
+ "suggestion.new_file": "%{filename} (archivo nuevo)",
12
+ "suggestion.new_file_desc": "El archivo aún no existe"
13
+ },
14
+ "de": {
15
+ "status.loaded": "Pfadvervollständigungs-Plugin erfolgreich geladen",
16
+ "suggestion.directory": "Verzeichnis",
17
+ "suggestion.new_file": "%{filename} (neue Datei)",
18
+ "suggestion.new_file_desc": "Datei existiert noch nicht"
19
+ },
20
+ "fr": {
21
+ "status.loaded": "Plugin de complétion de chemin chargé avec succès",
22
+ "suggestion.directory": "répertoire",
23
+ "suggestion.new_file": "%{filename} (nouveau fichier)",
24
+ "suggestion.new_file_desc": "Le fichier n'existe pas encore"
25
+ },
26
+ "ja": {
27
+ "status.loaded": "パス補完プラグインを正常に読み込みました",
28
+ "suggestion.directory": "ディレクトリ",
29
+ "suggestion.new_file": "%{filename} (新規ファイル)",
30
+ "suggestion.new_file_desc": "ファイルはまだ存在しません"
31
+ },
32
+ "zh-CN": {
33
+ "status.loaded": "路径补全插件加载成功",
34
+ "suggestion.directory": "目录",
35
+ "suggestion.new_file": "%{filename} (新文件)",
36
+ "suggestion.new_file_desc": "文件尚不存在"
37
+ }
38
+ }
@@ -1,4 +1,6 @@
1
1
  /// <reference path="../types/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
2
4
 
3
5
  /**
4
6
  * Path Completion Plugin
@@ -77,7 +79,7 @@ function entriesToSuggestions(entries: DirEntry[], basePath: string): PromptSugg
77
79
 
78
80
  return {
79
81
  text: displayName,
80
- description: entry.is_dir ? "directory" : undefined,
82
+ description: entry.is_dir ? editor.t("suggestion.directory") : undefined,
81
83
  value: value,
82
84
  disabled: false,
83
85
  };
@@ -108,8 +110,8 @@ function missingFileSuggestion(
108
110
  }
109
111
 
110
112
  return {
111
- text: `${input} (new file)`,
112
- description: "File does not exist yet",
113
+ text: editor.t("suggestion.new_file", { filename: input }),
114
+ description: editor.t("suggestion.new_file_desc"),
113
115
  value: input,
114
116
  };
115
117
  }
@@ -160,4 +162,4 @@ globalThis.onPathCompletePromptChanged = function (args: { prompt_type: string;
160
162
  // Register event handler
161
163
  editor.on("prompt_changed", "onPathCompletePromptChanged");
162
164
 
163
- editor.debug("Path completion plugin loaded successfully");
165
+ editor.setStatus(editor.t("status.loaded"));
@@ -1,4 +1,6 @@
1
1
  /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
2
4
 
3
5
  /**
4
6
  * Python LSP Helper Plugin
@@ -1,4 +1,6 @@
1
1
  /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
2
4
 
3
5
  /**
4
6
  * Rust LSP Helper Plugin