@fresh-editor/fresh-editor 0.3.8 → 0.3.10
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 +77 -0
- package/README.md +0 -1
- package/package.json +1 -1
- package/plugins/audit_mode.ts +35 -1
- package/plugins/config-schema.json +9 -3
- package/plugins/dashboard.ts +3 -3
- package/plugins/diagnostics_panel.ts +10 -0
- package/plugins/env-manager.i18n.json +338 -0
- package/plugins/env-manager.ts +23 -33
- package/plugins/examples/bookmarks.ts +3 -2
- package/plugins/lib/finder.ts +101 -17
- package/plugins/lib/fresh.d.ts +100 -42
- package/plugins/lib/widgets.ts +8 -0
- package/plugins/live_diff.ts +12 -1
- package/plugins/live_grep.i18n.json +349 -27
- package/plugins/live_grep.ts +660 -141
- package/plugins/markdown_compose.ts +3 -1
- package/plugins/orchestrator.ts +1493 -504
- package/plugins/schemas/theme.schema.json +15 -2
- package/plugins/search_replace.ts +70 -28
- package/plugins/theme_editor.i18n.json +28 -0
- package/plugins/vi_mode.ts +3 -3
|
@@ -221,6 +221,7 @@
|
|
|
221
221
|
30,
|
|
222
222
|
30
|
|
223
223
|
],
|
|
224
|
+
"suggestion_fg": null,
|
|
224
225
|
"suggestion_selected_bg": [
|
|
225
226
|
58,
|
|
226
227
|
79,
|
|
@@ -691,7 +692,7 @@
|
|
|
691
692
|
}
|
|
692
693
|
},
|
|
693
694
|
"UiColors": {
|
|
694
|
-
"description": "UI element colors (tabs, menus, status bar, etc.)",
|
|
695
|
+
"description": "UI element colors (tabs, menus, status bar, etc.)\n\nNaming convention: every `*_bg` key that has text drawn on top of\nit MUST have a matching `*_fg` key, and renderers must pair them\n(never borrow a foreground from an unrelated surface — doing so is\nhow text ends up invisible when a theme's borrowed fg matches the\nreal bg). `popup_text_fg` is the foreground for `popup_bg` (kept\nunder its historical name with a `popup_fg` serde alias).\n\n`*_bg` keys WITHOUT a matching `*_fg` are intentional — they don't\ndraw their own text and inherit the surrounding foreground:\n - lines / borders / separators: `tab_separator_bg`,\n `popup_border_fg`, `menu_border_fg`, `menu_separator_fg`,\n `split_separator_fg`, `scrollbar_*`, `tab_drop_zone_border`\n - selection / hover / highlight tints layered over a surface that\n keeps its base fg: `*_selection_bg`, `*_hover_bg`,\n `suggestion_selected_bg`, `text_input_selection_bg`,\n `semantic_highlight_bg`, `compose_margin_bg`, `inline_code_bg`",
|
|
695
696
|
"type": "object",
|
|
696
697
|
"properties": {
|
|
697
698
|
"tab_active_fg": {
|
|
@@ -1011,7 +1012,7 @@
|
|
|
1011
1012
|
]
|
|
1012
1013
|
},
|
|
1013
1014
|
"popup_text_fg": {
|
|
1014
|
-
"description": "Popup window text color",
|
|
1015
|
+
"description": "Popup window text color. Per the `*_bg`/`*_fg` convention this\nis the foreground for `popup_bg`; `popup_fg` is accepted as an\nalias so theme JSON can use the convention-consistent name.",
|
|
1015
1016
|
"$ref": "#/$defs/ColorDef",
|
|
1016
1017
|
"default": "White"
|
|
1017
1018
|
},
|
|
@@ -1024,6 +1025,18 @@
|
|
|
1024
1025
|
30
|
|
1025
1026
|
]
|
|
1026
1027
|
},
|
|
1028
|
+
"suggestion_fg": {
|
|
1029
|
+
"description": "Text color for content drawn on `suggestion_bg` (autocomplete\nitems, the overlay-prompt title/input field). Falls back to\n`popup_text_fg` so existing themes need no change.",
|
|
1030
|
+
"anyOf": [
|
|
1031
|
+
{
|
|
1032
|
+
"$ref": "#/$defs/ColorDef"
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
"type": "null"
|
|
1036
|
+
}
|
|
1037
|
+
],
|
|
1038
|
+
"default": null
|
|
1039
|
+
},
|
|
1027
1040
|
"suggestion_selected_bg": {
|
|
1028
1041
|
"description": "Selected suggestion background",
|
|
1029
1042
|
"$ref": "#/$defs/ColorDef",
|
|
@@ -68,16 +68,19 @@ interface PanelState {
|
|
|
68
68
|
caseSensitive: boolean;
|
|
69
69
|
useRegex: boolean;
|
|
70
70
|
wholeWords: boolean;
|
|
71
|
-
// Scope (§1): when false, results are restricted to
|
|
71
|
+
// Scope (§1): when false, results are restricted to the source buffer.
|
|
72
72
|
// `sourceBufferPath` is the absolute path of the buffer that was
|
|
73
73
|
// active when the panel opened; `sourceBufferRelPath` is the
|
|
74
|
-
// cwd-relative display form.
|
|
75
|
-
// unsaved
|
|
76
|
-
//
|
|
77
|
-
//
|
|
74
|
+
// cwd-relative display form. An empty path means the source buffer is
|
|
75
|
+
// unnamed/unsaved — in that case scope filtering falls back to
|
|
76
|
+
// `sourceBufferId`, and the host searches that buffer's in-memory
|
|
77
|
+
// content directly (it has no on-disk file the project walk can find).
|
|
78
78
|
allFiles: boolean;
|
|
79
79
|
sourceBufferPath: string;
|
|
80
80
|
sourceBufferRelPath: string;
|
|
81
|
+
// Buffer id of the source buffer, used to scope/replace unnamed buffers
|
|
82
|
+
// by id when there's no path to match on. 0 means "unknown".
|
|
83
|
+
sourceBufferId: number;
|
|
81
84
|
// Layout
|
|
82
85
|
viewportWidth: number;
|
|
83
86
|
// State
|
|
@@ -918,12 +921,16 @@ function updatePanelContent(): void {
|
|
|
918
921
|
// trailing match-count stats.
|
|
919
922
|
// * `Row{ Toggle, Toggle, Toggle, Spacer, Button }`
|
|
920
923
|
// — case/regex/whole + Replace All.
|
|
924
|
+
// * `HintBar{ ... }` — keyboard-hint row, sits
|
|
925
|
+
// directly above the matches
|
|
926
|
+
// section.
|
|
921
927
|
// * `Raw{ separator entry }` — matches divider.
|
|
922
928
|
// * `List{ ... }` or `Raw{empty msg}` — virtual-scrolled match
|
|
923
929
|
// rows (host owns scroll +
|
|
924
930
|
// selection styling +
|
|
925
|
-
// click routing).
|
|
926
|
-
//
|
|
931
|
+
// click routing). Last child
|
|
932
|
+
// so the match list is the
|
|
933
|
+
// final thing in the buffer.
|
|
927
934
|
if (!panel.widgetPanel) {
|
|
928
935
|
panel.widgetPanel = new WidgetPanel(panel.resultsBufferId);
|
|
929
936
|
}
|
|
@@ -932,9 +939,9 @@ function updatePanelContent(): void {
|
|
|
932
939
|
buildLine1Spec(),
|
|
933
940
|
buildOptionsRowSpec(),
|
|
934
941
|
buildScopeRowSpec(),
|
|
942
|
+
hintBar(buildHelpHints()),
|
|
935
943
|
raw(buildPanelEntries("postOptions"), "separator"),
|
|
936
944
|
buildMatchListSpec(),
|
|
937
|
-
hintBar(buildHelpHints()),
|
|
938
945
|
),
|
|
939
946
|
);
|
|
940
947
|
// The Tree's `expandedKeys` field on the spec is initial-only —
|
|
@@ -1060,6 +1067,9 @@ async function performSearch(pattern: string, silent?: boolean): Promise<SearchR
|
|
|
1060
1067
|
caseSensitive: panel.caseSensitive,
|
|
1061
1068
|
maxResults: MAX_RESULTS,
|
|
1062
1069
|
wholeWords: panel.wholeWords,
|
|
1070
|
+
// Lets the host search an unnamed/unsaved source buffer in-memory;
|
|
1071
|
+
// it has no on-disk file the project walk could otherwise reach.
|
|
1072
|
+
sourceBufferId: panel.sourceBufferId,
|
|
1063
1073
|
});
|
|
1064
1074
|
activeSearchHandle = handle;
|
|
1065
1075
|
|
|
@@ -1108,10 +1118,15 @@ async function performSearch(pattern: string, silent?: boolean): Promise<SearchR
|
|
|
1108
1118
|
const newExpandedKeys: string[] = []; // file rows added this batch
|
|
1109
1119
|
for (const m of chunk) {
|
|
1110
1120
|
// §1 scope filter: when scope is "current file only", drop
|
|
1111
|
-
// matches from any other
|
|
1112
|
-
// host grep API is project-wide.
|
|
1113
|
-
//
|
|
1114
|
-
|
|
1121
|
+
// matches from any other source. Done client-side because the
|
|
1122
|
+
// host grep API is project-wide. A named buffer matches by path;
|
|
1123
|
+
// an unnamed/unsaved buffer (empty sourceBufferPath) matches by
|
|
1124
|
+
// buffer id instead — the host tags its in-memory matches with it.
|
|
1125
|
+
if (!panel.allFiles) {
|
|
1126
|
+
const sameFile = !!panel.sourceBufferPath && m.file === panel.sourceBufferPath;
|
|
1127
|
+
const sameBuffer = !!panel.sourceBufferId && m.bufferId === panel.sourceBufferId;
|
|
1128
|
+
if (!sameFile && !sameBuffer) continue;
|
|
1129
|
+
}
|
|
1115
1130
|
const result: SearchResult = { match: m, selected: true };
|
|
1116
1131
|
allResults.push(result);
|
|
1117
1132
|
let fileIdx = streamingFileIndexByPath?.get(m.file);
|
|
@@ -1276,8 +1291,10 @@ async function openPanel(opts?: { allFiles?: boolean }): Promise<void> {
|
|
|
1276
1291
|
// Try to pre-fill search from editor selection
|
|
1277
1292
|
let prefill = "";
|
|
1278
1293
|
let sourceBufferPath = "";
|
|
1294
|
+
let sourceBufferId = 0;
|
|
1279
1295
|
try {
|
|
1280
1296
|
const activeId = editor.getActiveBufferId();
|
|
1297
|
+
sourceBufferId = activeId;
|
|
1281
1298
|
sourceBufferPath = editor.getBufferPath(activeId) || "";
|
|
1282
1299
|
const cursor = editor.getPrimaryCursor();
|
|
1283
1300
|
if (cursor && cursor.selection) {
|
|
@@ -1304,6 +1321,7 @@ async function openPanel(opts?: { allFiles?: boolean }): Promise<void> {
|
|
|
1304
1321
|
panel.allFiles = allFiles;
|
|
1305
1322
|
panel.sourceBufferPath = sourceBufferPath;
|
|
1306
1323
|
panel.sourceBufferRelPath = sourceBufferRelPath;
|
|
1324
|
+
panel.sourceBufferId = sourceBufferId;
|
|
1307
1325
|
updatePanelContent();
|
|
1308
1326
|
if (panel.searchPattern) rerunSearchDebounced();
|
|
1309
1327
|
return;
|
|
@@ -1329,6 +1347,7 @@ async function openPanel(opts?: { allFiles?: boolean }): Promise<void> {
|
|
|
1329
1347
|
allFiles,
|
|
1330
1348
|
sourceBufferPath,
|
|
1331
1349
|
sourceBufferRelPath,
|
|
1350
|
+
sourceBufferId,
|
|
1332
1351
|
viewportWidth: DEFAULT_WIDTH,
|
|
1333
1352
|
busy: false,
|
|
1334
1353
|
searchPerformed: false,
|
|
@@ -1383,29 +1402,42 @@ async function executeReplacements(results?: SearchResult[]): Promise<string> {
|
|
|
1383
1402
|
return editor.t("status.no_selected");
|
|
1384
1403
|
}
|
|
1385
1404
|
|
|
1386
|
-
|
|
1405
|
+
// Group edits per target. Matches in an open buffer carry a non-zero
|
|
1406
|
+
// bufferId; key by it so an unnamed buffer (whose `file` is a shared
|
|
1407
|
+
// "[No Name]" label) still resolves to the right buffer rather than
|
|
1408
|
+
// colliding with another unnamed buffer's matches. On-disk files
|
|
1409
|
+
// (bufferId 0) key by path and are opened/saved by the host as before.
|
|
1410
|
+
type Group = { filePath: string; bufferId: number; matches: Array<[number, number]> };
|
|
1411
|
+
const groups: Map<string, Group> = new Map();
|
|
1387
1412
|
for (const result of toReplace) {
|
|
1388
|
-
const
|
|
1389
|
-
|
|
1390
|
-
|
|
1413
|
+
const bufferId = result.match.bufferId || 0;
|
|
1414
|
+
const key = bufferId > 0 ? `buf:${bufferId}` : result.match.file;
|
|
1415
|
+
let group = groups.get(key);
|
|
1416
|
+
if (!group) {
|
|
1417
|
+
group = { filePath: result.match.file, bufferId, matches: [] };
|
|
1418
|
+
groups.set(key, group);
|
|
1391
1419
|
}
|
|
1392
|
-
|
|
1420
|
+
group.matches.push([result.match.byteOffset, result.match.length]);
|
|
1393
1421
|
}
|
|
1394
1422
|
|
|
1395
1423
|
let filesModified = 0;
|
|
1396
1424
|
let replacementsCount = 0;
|
|
1397
1425
|
const errors: string[] = [];
|
|
1398
1426
|
|
|
1399
|
-
const
|
|
1400
|
-
|
|
1401
|
-
for (const
|
|
1402
|
-
const matches = fileGroups.get(filePath)!;
|
|
1427
|
+
const groupList: Group[] = [];
|
|
1428
|
+
groups.forEach((g) => groupList.push(g));
|
|
1429
|
+
for (const group of groupList) {
|
|
1403
1430
|
try {
|
|
1404
|
-
const result = await editor.replaceInFile(
|
|
1431
|
+
const result = await editor.replaceInFile(
|
|
1432
|
+
group.filePath,
|
|
1433
|
+
group.matches,
|
|
1434
|
+
panel.replaceText,
|
|
1435
|
+
group.bufferId
|
|
1436
|
+
);
|
|
1405
1437
|
replacementsCount += result.replacements;
|
|
1406
1438
|
if (result.replacements > 0) filesModified++;
|
|
1407
1439
|
} catch (e) {
|
|
1408
|
-
errors.push(`${filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
1440
|
+
errors.push(`${group.filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
1409
1441
|
}
|
|
1410
1442
|
}
|
|
1411
1443
|
|
|
@@ -1451,12 +1483,22 @@ async function rerunSearch(): Promise<void> {
|
|
|
1451
1483
|
if (panel && currentSearchGeneration === myGen) {
|
|
1452
1484
|
panel.busy = false;
|
|
1453
1485
|
panel.searchPerformed = true;
|
|
1454
|
-
// Only one tiny mutation needed: refresh matchStats since it
|
|
1455
|
-
// depends on the busy flag and searchPerformed (showing
|
|
1456
|
-
// "No matches" vs "Searching…"). The tree's nodes already
|
|
1457
|
-
// reflect the final state — no full re-emit needed.
|
|
1458
1486
|
if (panel.widgetPanel) {
|
|
1459
|
-
panel.
|
|
1487
|
+
if (panel.searchResults.length === 0) {
|
|
1488
|
+
// Zero matches: the match-list body is an empty-state `raw()`
|
|
1489
|
+
// last rendered while `busy` was still true → "Searching…".
|
|
1490
|
+
// `setRawEntries("matchStats", …)` only refreshes the small
|
|
1491
|
+
// count label next to the inputs, not the body, so without a
|
|
1492
|
+
// full re-emit the body stays stuck on "Searching…". Re-emit
|
|
1493
|
+
// now that the flags are final so it shows "No matches".
|
|
1494
|
+
// Cheap: the tree is empty (no per-node serialization cost).
|
|
1495
|
+
updatePanelContent();
|
|
1496
|
+
} else {
|
|
1497
|
+
// Only one tiny mutation needed: refresh matchStats since it
|
|
1498
|
+
// depends on the busy flag and searchPerformed. The tree's
|
|
1499
|
+
// nodes already reflect the final state — no full re-emit.
|
|
1500
|
+
panel.widgetPanel.setRawEntries("matchStats", buildMatchStatsEntries());
|
|
1501
|
+
}
|
|
1460
1502
|
}
|
|
1461
1503
|
}
|
|
1462
1504
|
}
|
|
@@ -219,6 +219,8 @@
|
|
|
219
219
|
"field.text_input_selection_bg_desc": "pozadí pro vybraný text uvnitř textového pole widgetu",
|
|
220
220
|
"field.suggestion_bg": "Suggestion pozadí",
|
|
221
221
|
"field.suggestion_bg_desc": "Autocomplete suggestion pozadí",
|
|
222
|
+
"field.suggestion_fg": "Suggestion popředí",
|
|
223
|
+
"field.suggestion_fg_desc": "barva textu na pozadí návrhu",
|
|
222
224
|
"field.suggestion_selected_bg": "Suggestion Selected pozadí",
|
|
223
225
|
"field.suggestion_selected_bg_desc": "Selected suggestion pozadí",
|
|
224
226
|
"field.help_bg": "Help pozadí",
|
|
@@ -534,6 +536,8 @@
|
|
|
534
536
|
"field.text_input_selection_bg_desc": "Hintergrund der Auswahl in einer Widget-Texteingabe",
|
|
535
537
|
"field.suggestion_bg": "Vorschlag Hintergrund",
|
|
536
538
|
"field.suggestion_bg_desc": "Hintergrund der Autovervollstaendigung",
|
|
539
|
+
"field.suggestion_fg": "Vorschlag Vordergrund",
|
|
540
|
+
"field.suggestion_fg_desc": "Textfarbe auf dem Vorschlagshintergrund",
|
|
537
541
|
"field.suggestion_selected_bg": "Ausgewaehlter Vorschlag Hintergrund",
|
|
538
542
|
"field.suggestion_selected_bg_desc": "Hintergrund des ausgewaehlten Vorschlags",
|
|
539
543
|
"field.help_bg": "Hilfe Hintergrund",
|
|
@@ -925,6 +929,8 @@
|
|
|
925
929
|
"field.text_input_selection_bg_desc": "Background for selected text inside a widget text input",
|
|
926
930
|
"field.suggestion_bg": "Suggestion Background",
|
|
927
931
|
"field.suggestion_bg_desc": "Autocomplete suggestion background",
|
|
932
|
+
"field.suggestion_fg": "Suggestion Foreground",
|
|
933
|
+
"field.suggestion_fg_desc": "Text color drawn on the suggestion background",
|
|
928
934
|
"field.suggestion_selected_bg": "Suggestion Selected Background",
|
|
929
935
|
"field.suggestion_selected_bg_desc": "Selected suggestion background",
|
|
930
936
|
"field.help_bg": "Help Background",
|
|
@@ -1236,6 +1242,8 @@
|
|
|
1236
1242
|
"field.text_input_selection_bg_desc": "Color de fondo del texto seleccionado dentro de un campo de texto de widget",
|
|
1237
1243
|
"field.suggestion_bg": "Fondo de sugerencia",
|
|
1238
1244
|
"field.suggestion_bg_desc": "Fondo de sugerencia de autocompletado",
|
|
1245
|
+
"field.suggestion_fg": "Primer plano de sugerencia",
|
|
1246
|
+
"field.suggestion_fg_desc": "Color de texto sobre el fondo de sugerencia",
|
|
1239
1247
|
"field.suggestion_selected_bg": "Fondo de sugerencia seleccionada",
|
|
1240
1248
|
"field.suggestion_selected_bg_desc": "Fondo de sugerencia seleccionada",
|
|
1241
1249
|
"field.help_bg": "Fondo de ayuda",
|
|
@@ -1587,6 +1595,8 @@
|
|
|
1587
1595
|
"field.text_input_selection_bg_desc": "Couleur de fond du texte selectionne dans un champ de saisie de widget",
|
|
1588
1596
|
"field.suggestion_bg": "Arriere-plan suggestion",
|
|
1589
1597
|
"field.suggestion_bg_desc": "Arriere-plan de l'autocompletion",
|
|
1598
|
+
"field.suggestion_fg": "Premier plan suggestion",
|
|
1599
|
+
"field.suggestion_fg_desc": "Couleur du texte sur l'arriere-plan de suggestion",
|
|
1590
1600
|
"field.suggestion_selected_bg": "Arriere-plan suggestion selectionnee",
|
|
1591
1601
|
"field.suggestion_selected_bg_desc": "Arriere-plan de la suggestion selectionnee",
|
|
1592
1602
|
"field.help_bg": "Arriere-plan aide",
|
|
@@ -1938,6 +1948,8 @@
|
|
|
1938
1948
|
"field.text_input_selection_bg_desc": "ウィジェットのテキスト入力欄で選択されたテキストの背景色",
|
|
1939
1949
|
"field.suggestion_bg": "候補背景",
|
|
1940
1950
|
"field.suggestion_bg_desc": "オートコンプリート候補の背景",
|
|
1951
|
+
"field.suggestion_fg": "候補前景",
|
|
1952
|
+
"field.suggestion_fg_desc": "候補背景上のテキスト色",
|
|
1941
1953
|
"field.suggestion_selected_bg": "選択候補背景",
|
|
1942
1954
|
"field.suggestion_selected_bg_desc": "選択された候補の背景",
|
|
1943
1955
|
"field.help_bg": "ヘルプ背景",
|
|
@@ -2325,6 +2337,8 @@
|
|
|
2325
2337
|
"field.text_input_selection_bg_desc": "위젯 텍스트 입력란에서 선택된 텍스트의 배경색",
|
|
2326
2338
|
"field.suggestion_bg": "Suggestion 배경",
|
|
2327
2339
|
"field.suggestion_bg_desc": "Autocomplete suggestion 배경",
|
|
2340
|
+
"field.suggestion_fg": "Suggestion 전경",
|
|
2341
|
+
"field.suggestion_fg_desc": "추천 배경 위의 텍스트 색상",
|
|
2328
2342
|
"field.suggestion_selected_bg": "Suggestion Selected 배경",
|
|
2329
2343
|
"field.suggestion_selected_bg_desc": "Selected suggestion 배경",
|
|
2330
2344
|
"field.help_bg": "Help 배경",
|
|
@@ -2676,6 +2690,8 @@
|
|
|
2676
2690
|
"field.text_input_selection_bg_desc": "cor de fundo do texto selecionado dentro de um campo de entrada de widget",
|
|
2677
2691
|
"field.suggestion_bg": "Suggestion fundo",
|
|
2678
2692
|
"field.suggestion_bg_desc": "Autocomplete suggestion fundo",
|
|
2693
|
+
"field.suggestion_fg": "Suggestion primeiro plano",
|
|
2694
|
+
"field.suggestion_fg_desc": "Cor do texto sobre o fundo de sugestão",
|
|
2679
2695
|
"field.suggestion_selected_bg": "Suggestion Selected fundo",
|
|
2680
2696
|
"field.suggestion_selected_bg_desc": "Selected suggestion fundo",
|
|
2681
2697
|
"field.help_bg": "Help fundo",
|
|
@@ -3027,6 +3043,8 @@
|
|
|
3027
3043
|
"field.text_input_selection_bg_desc": "цвет фона выделенного текста внутри текстового поля виджета",
|
|
3028
3044
|
"field.suggestion_bg": "Suggestion фон",
|
|
3029
3045
|
"field.suggestion_bg_desc": "Autocomplete suggestion фон",
|
|
3046
|
+
"field.suggestion_fg": "Suggestion передний план",
|
|
3047
|
+
"field.suggestion_fg_desc": "Цвет текста на фоне подсказки",
|
|
3030
3048
|
"field.suggestion_selected_bg": "Suggestion Selected фон",
|
|
3031
3049
|
"field.suggestion_selected_bg_desc": "Selected suggestion фон",
|
|
3032
3050
|
"field.help_bg": "Help фон",
|
|
@@ -3378,6 +3396,8 @@
|
|
|
3378
3396
|
"field.text_input_selection_bg_desc": "สีพื้นหลังของข้อความที่เลือกในช่องป้อนข้อความของวิดเจ็ต",
|
|
3379
3397
|
"field.suggestion_bg": "Suggestion พื้นหลัง",
|
|
3380
3398
|
"field.suggestion_bg_desc": "Autocomplete suggestion พื้นหลัง",
|
|
3399
|
+
"field.suggestion_fg": "Suggestion พื้นหน้า",
|
|
3400
|
+
"field.suggestion_fg_desc": "สีข้อความบนพื้นหลังคำแนะนำ",
|
|
3381
3401
|
"field.suggestion_selected_bg": "Suggestion Selected พื้นหลัง",
|
|
3382
3402
|
"field.suggestion_selected_bg_desc": "Selected suggestion พื้นหลัง",
|
|
3383
3403
|
"field.help_bg": "Help พื้นหลัง",
|
|
@@ -3729,6 +3749,8 @@
|
|
|
3729
3749
|
"field.text_input_selection_bg_desc": "колір фону виділеного тексту всередині текстового поля віджета",
|
|
3730
3750
|
"field.suggestion_bg": "Suggestion фон",
|
|
3731
3751
|
"field.suggestion_bg_desc": "Autocomplete suggestion фон",
|
|
3752
|
+
"field.suggestion_fg": "Suggestion передній план",
|
|
3753
|
+
"field.suggestion_fg_desc": "Колір тексту на тлі підказки",
|
|
3732
3754
|
"field.suggestion_selected_bg": "Suggestion Selected фон",
|
|
3733
3755
|
"field.suggestion_selected_bg_desc": "Selected suggestion фон",
|
|
3734
3756
|
"field.help_bg": "Help фон",
|
|
@@ -4080,6 +4102,8 @@
|
|
|
4080
4102
|
"field.text_input_selection_bg_desc": "Màu nền của văn bản đã chọn bên trong ô nhập văn bản của widget",
|
|
4081
4103
|
"field.suggestion_bg": "Nền gợi ý",
|
|
4082
4104
|
"field.suggestion_bg_desc": "Nền gợi ý tự động hoàn thành",
|
|
4105
|
+
"field.suggestion_fg": "Tiền cảnh gợi ý",
|
|
4106
|
+
"field.suggestion_fg_desc": "Màu văn bản trên nền gợi ý",
|
|
4083
4107
|
"field.suggestion_selected_bg": "Nền gợi ý đã chọn",
|
|
4084
4108
|
"field.suggestion_selected_bg_desc": "Nền gợi ý đã chọn",
|
|
4085
4109
|
"field.help_bg": "Nền trợ giúp",
|
|
@@ -4395,6 +4419,8 @@
|
|
|
4395
4419
|
"field.text_input_selection_bg_desc": "小部件文本输入框中所选文本的背景颜色",
|
|
4396
4420
|
"field.suggestion_bg": "建议背景",
|
|
4397
4421
|
"field.suggestion_bg_desc": "自动补全建议背景",
|
|
4422
|
+
"field.suggestion_fg": "建议前景",
|
|
4423
|
+
"field.suggestion_fg_desc": "建议背景上的文本颜色",
|
|
4398
4424
|
"field.suggestion_selected_bg": "选中建议背景",
|
|
4399
4425
|
"field.suggestion_selected_bg_desc": "选中建议的背景",
|
|
4400
4426
|
"field.help_bg": "帮助背景",
|
|
@@ -4758,6 +4784,8 @@
|
|
|
4758
4784
|
"field.text_input_selection_bg_desc": "Colore di sfondo del testo selezionato all'interno di un campo di testo widget",
|
|
4759
4785
|
"field.suggestion_bg": "Sfondo suggerimento",
|
|
4760
4786
|
"field.suggestion_bg_desc": "Sfondo del suggerimento di completamento automatico",
|
|
4787
|
+
"field.suggestion_fg": "Primo piano suggerimento",
|
|
4788
|
+
"field.suggestion_fg_desc": "Colore del testo sullo sfondo del suggerimento",
|
|
4761
4789
|
"field.suggestion_selected_bg": "Sfondo suggerimento selezionato",
|
|
4762
4790
|
"field.suggestion_selected_bg_desc": "Sfondo del suggerimento selezionato",
|
|
4763
4791
|
"field.help_bg": "Sfondo aiuto",
|
package/plugins/vi_mode.ts
CHANGED
|
@@ -395,7 +395,7 @@ registerHandler("vi_line_end", vi_line_end);
|
|
|
395
395
|
async function vi_first_non_blank() : Promise<void> {
|
|
396
396
|
consumeCount(); // Count doesn't apply
|
|
397
397
|
// Get line start position directly (avoids stale snapshot from executeAction)
|
|
398
|
-
const line = editor.
|
|
398
|
+
const line = editor.getPrimaryCursor()?.line ?? 0;
|
|
399
399
|
const bufferId = editor.getActiveBufferId();
|
|
400
400
|
const lineStart = await editor.getLineStartPosition(line);
|
|
401
401
|
if (lineStart === null) {
|
|
@@ -939,7 +939,7 @@ async function vi_visual_block() : Promise<void> {
|
|
|
939
939
|
// Calculate line and column for block anchor
|
|
940
940
|
const cursorPos = editor.getCursorPosition();
|
|
941
941
|
if (cursorPos !== null) {
|
|
942
|
-
const line = editor.
|
|
942
|
+
const line = editor.getPrimaryCursor()?.line ?? 1;
|
|
943
943
|
const lineStart = await editor.getLineStartPosition(line);
|
|
944
944
|
const col = lineStart !== null ? cursorPos - lineStart : 0;
|
|
945
945
|
state.visualBlockAnchor = { line, col };
|
|
@@ -2702,7 +2702,7 @@ async function executeCommand(
|
|
|
2702
2702
|
if (info) {
|
|
2703
2703
|
const modified = info.modified ? editor.t("info.modified") : "";
|
|
2704
2704
|
const path = info.path || editor.t("info.no_name");
|
|
2705
|
-
const line = editor.
|
|
2705
|
+
const line = editor.getPrimaryCursor()?.line ?? 0;
|
|
2706
2706
|
return { message: editor.t("info.file", { path, modified, line: String(line), bytes: String(info.length) }) };
|
|
2707
2707
|
}
|
|
2708
2708
|
return { error: editor.t("error.no_buffer") };
|