@fresh-editor/fresh-editor 0.2.22 → 0.2.23
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 +41 -0
- package/package.json +1 -1
- package/plugins/audit_mode.i18n.json +141 -379
- package/plugins/audit_mode.ts +1078 -451
- package/plugins/config-schema.json +146 -0
- package/plugins/git_explorer.ts +7 -7
- package/plugins/lib/fresh.d.ts +25 -2
- package/plugins/pkg.ts +151 -397
- package/plugins/theme_editor.i18n.json +182 -14
- package/plugins/theme_editor.ts +192 -85
package/plugins/theme_editor.ts
CHANGED
|
@@ -62,7 +62,8 @@ type ColorValue = RGB | string;
|
|
|
62
62
|
// =============================================================================
|
|
63
63
|
|
|
64
64
|
const LEFT_WIDTH = 38;
|
|
65
|
-
const
|
|
65
|
+
const RIGHT_WIDTH_CONST = 61;
|
|
66
|
+
function RIGHT_WIDTH(): number { return RIGHT_WIDTH_CONST; }
|
|
66
67
|
|
|
67
68
|
type PickerFocusTarget =
|
|
68
69
|
| { type: "hex-input" }
|
|
@@ -375,6 +376,10 @@ interface ThemeEditorState {
|
|
|
375
376
|
viewportHeight: number;
|
|
376
377
|
/** Cached viewport width */
|
|
377
378
|
viewportWidth: number;
|
|
379
|
+
/** Buffer group ID (when using buffer groups) */
|
|
380
|
+
groupId: number | null;
|
|
381
|
+
/** Panel buffer IDs keyed by panel name */
|
|
382
|
+
panelBuffers: Record<string, number>;
|
|
378
383
|
}
|
|
379
384
|
|
|
380
385
|
/**
|
|
@@ -436,30 +441,55 @@ const state: ThemeEditorState = {
|
|
|
436
441
|
treeScrollOffset: 0,
|
|
437
442
|
viewportHeight: 40,
|
|
438
443
|
viewportWidth: 120,
|
|
444
|
+
groupId: null,
|
|
445
|
+
panelBuffers: {},
|
|
439
446
|
};
|
|
440
447
|
|
|
441
448
|
// =============================================================================
|
|
442
449
|
// Color Definitions for UI
|
|
443
450
|
// =============================================================================
|
|
444
451
|
|
|
452
|
+
/**
|
|
453
|
+
* UI palette for the theme editor's own chrome.
|
|
454
|
+
*
|
|
455
|
+
* Each role maps to a theme-key path (e.g. `"syntax.keyword"`). The plugin
|
|
456
|
+
* passes these strings straight through to the core as
|
|
457
|
+
* `OverlayColorSpec::ThemeKey`, and the core's renderer resolves them
|
|
458
|
+
* against the *currently-active* theme on every frame
|
|
459
|
+
* (see `OverlayFace::from_options` → `OverlayFace::ThemedStyle`, and the
|
|
460
|
+
* render-time lookup in `split_rendering.rs`). That means the theme editor
|
|
461
|
+
* inherits the host theme's look and automatically picks up theme switches
|
|
462
|
+
* without the plugin having to rebuild its overlays or even be notified —
|
|
463
|
+
* the `resolve_theme_key` lookup runs with the new theme on the next render.
|
|
464
|
+
*
|
|
465
|
+
* Important: we only use keys that the theme defines as readable on
|
|
466
|
+
* `editor.bg` (since that's the background the theme editor draws over).
|
|
467
|
+
* That rules out `ui.menu_*`, `ui.tab_*`, etc. — those are designed for
|
|
468
|
+
* their own bg pairs (e.g. `ui.menu_active_fg` on `ui.menu_active_bg`) and
|
|
469
|
+
* will clash or go invisible when drawn on `editor.bg` (notoriously in
|
|
470
|
+
* high-contrast, where `ui.menu_active_fg` is pure black). So we only pull
|
|
471
|
+
* from `editor.*` and `syntax.*`, and lean on bold + distinct syntax roles
|
|
472
|
+
* to give each UI element its own visual identity.
|
|
473
|
+
*
|
|
474
|
+
* We don't need a client-side fallback chain: the core's `Theme` struct has
|
|
475
|
+
* serde defaults for every field, so `resolve_theme_key` always returns a
|
|
476
|
+
* value for any key listed here — a stub theme file can omit them and the
|
|
477
|
+
* defaults still apply.
|
|
478
|
+
*/
|
|
445
479
|
const colors = {
|
|
446
|
-
sectionHeader:
|
|
447
|
-
fieldName:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
pickerFocusBg: [40, 60, 100] as RGB, // Picker focused item bg
|
|
460
|
-
filterText: [200, 200, 100] as RGB, // Filter input text
|
|
461
|
-
previewBg: [25, 25, 30] as RGB, // Preview background
|
|
462
|
-
};
|
|
480
|
+
sectionHeader: "syntax.keyword",
|
|
481
|
+
fieldName: "editor.fg",
|
|
482
|
+
customValue: "syntax.string",
|
|
483
|
+
description: "syntax.comment",
|
|
484
|
+
footer: "editor.line_number_fg",
|
|
485
|
+
selectionBg: "editor.selection_bg",
|
|
486
|
+
divider: "editor.line_number_fg",
|
|
487
|
+
header: "syntax.keyword",
|
|
488
|
+
pickerLabel: "editor.fg",
|
|
489
|
+
pickerValue: "syntax.constant",
|
|
490
|
+
pickerFocusBg: "editor.selection_bg",
|
|
491
|
+
filterText: "syntax.function",
|
|
492
|
+
} as const satisfies Record<string, OverlayColorSpec>;
|
|
463
493
|
|
|
464
494
|
// =============================================================================
|
|
465
495
|
// Keyboard Shortcuts (defined once, used in mode and i18n)
|
|
@@ -816,8 +846,8 @@ function buildTreeLines(): TreeLine[] {
|
|
|
816
846
|
type: "header",
|
|
817
847
|
});
|
|
818
848
|
|
|
819
|
-
// Separator
|
|
820
|
-
lines.push({ text: "─".repeat(
|
|
849
|
+
// Separator (adapt to panel width)
|
|
850
|
+
lines.push({ text: "─".repeat(Math.max(10, LEFT_WIDTH - 2)), type: "separator" });
|
|
821
851
|
|
|
822
852
|
// Filter
|
|
823
853
|
if (state.filterText) {
|
|
@@ -825,7 +855,7 @@ function buildTreeLines(): TreeLine[] {
|
|
|
825
855
|
text: `Filter: [${state.filterText}]`,
|
|
826
856
|
type: "filter",
|
|
827
857
|
});
|
|
828
|
-
lines.push({ text: "─".repeat(
|
|
858
|
+
lines.push({ text: "─".repeat(Math.max(10, LEFT_WIDTH - 2)), type: "separator" });
|
|
829
859
|
}
|
|
830
860
|
|
|
831
861
|
// Build visible fields
|
|
@@ -852,11 +882,15 @@ function buildTreeLines(): TreeLine[] {
|
|
|
852
882
|
});
|
|
853
883
|
} else {
|
|
854
884
|
const sel = isSelected && state.focusPanel === "tree" ? "▸" : " ";
|
|
855
|
-
|
|
885
|
+
// Adapt name/value truncation to panel width
|
|
886
|
+
// Layout: " ▸ name.padEnd(nameW) ██ value" = 6 + nameW + 3 + valueW
|
|
887
|
+
const nameW = Math.max(8, LEFT_WIDTH - 18);
|
|
888
|
+
const valueW = Math.max(5, LEFT_WIDTH - nameW - 9);
|
|
889
|
+
const name = field.def.key.length > nameW ? field.def.key.slice(0, nameW - 1) + "…" : field.def.key;
|
|
856
890
|
const colorStr = formatColorValue(field.value);
|
|
857
|
-
const valueStr = colorStr.length >
|
|
891
|
+
const valueStr = colorStr.length > valueW ? colorStr.slice(0, valueW - 1) + "…" : colorStr;
|
|
858
892
|
lines.push({
|
|
859
|
-
text: ` ${sel} ${name.padEnd(
|
|
893
|
+
text: ` ${sel} ${name.padEnd(nameW)} ██ ${valueStr}`,
|
|
860
894
|
type: "tree-field",
|
|
861
895
|
index: i,
|
|
862
896
|
path: field.path,
|
|
@@ -893,7 +927,7 @@ function buildPickerLines(): PickerLine[] {
|
|
|
893
927
|
} else {
|
|
894
928
|
lines.push({ text: "No field selected", type: "picker-title" });
|
|
895
929
|
}
|
|
896
|
-
lines.push({ text: "─".repeat(RIGHT_WIDTH - 2), type: "picker-separator" });
|
|
930
|
+
lines.push({ text: "─".repeat(RIGHT_WIDTH() - 2), type: "picker-separator" });
|
|
897
931
|
lines.push({ text: "Select a color field to edit", type: "picker-desc" });
|
|
898
932
|
return lines;
|
|
899
933
|
}
|
|
@@ -901,7 +935,7 @@ function buildPickerLines(): PickerLine[] {
|
|
|
901
935
|
// Field title
|
|
902
936
|
lines.push({ text: `${field.path} - ${field.def.displayName}`, type: "picker-title" });
|
|
903
937
|
lines.push({ text: `"${field.def.description}"`, type: "picker-desc" });
|
|
904
|
-
lines.push({ text: "─".repeat(RIGHT_WIDTH - 2), type: "picker-separator" });
|
|
938
|
+
lines.push({ text: "─".repeat(RIGHT_WIDTH() - 2), type: "picker-separator" });
|
|
905
939
|
|
|
906
940
|
// Color value display
|
|
907
941
|
const isNamed = typeof field.value === "string" && NAMED_COLORS[field.value] !== undefined;
|
|
@@ -942,7 +976,7 @@ function buildPickerLines(): PickerLine[] {
|
|
|
942
976
|
lines.push({ text: rowText, type: "picker-palette-row", paletteRow: row });
|
|
943
977
|
}
|
|
944
978
|
|
|
945
|
-
lines.push({ text: "─".repeat(RIGHT_WIDTH - 2), type: "picker-separator" });
|
|
979
|
+
lines.push({ text: "─".repeat(RIGHT_WIDTH() - 2), type: "picker-separator" });
|
|
946
980
|
|
|
947
981
|
// Preview section
|
|
948
982
|
lines.push({ text: "Preview:", type: "picker-label" });
|
|
@@ -1241,7 +1275,7 @@ function addBackgroundHighlight(
|
|
|
1241
1275
|
bufferId: number,
|
|
1242
1276
|
start: number,
|
|
1243
1277
|
end: number,
|
|
1244
|
-
bgColor:
|
|
1278
|
+
bgColor: OverlayColorSpec
|
|
1245
1279
|
): void {
|
|
1246
1280
|
editor.addOverlay(bufferId, "theme-sel", start, end, { bg: bgColor });
|
|
1247
1281
|
}
|
|
@@ -1352,10 +1386,99 @@ let isUpdatingDisplay = false;
|
|
|
1352
1386
|
* Full display update — rebuilds content and all overlays.
|
|
1353
1387
|
* Use for structural changes (open, section toggle, color edit, filter).
|
|
1354
1388
|
*/
|
|
1389
|
+
// --- Buffer Group panel content builders ---
|
|
1390
|
+
|
|
1391
|
+
function buildTreePanelEntries(): TextPropertyEntry[] {
|
|
1392
|
+
const entries: TextPropertyEntry[] = [];
|
|
1393
|
+
const allLeftLines = buildTreeLines();
|
|
1394
|
+
for (const item of allLeftLines) {
|
|
1395
|
+
const leftStyle = styleForLeftEntry(item);
|
|
1396
|
+
entries.push({
|
|
1397
|
+
text: " " + item.text + "\n",
|
|
1398
|
+
properties: {
|
|
1399
|
+
type: item.type,
|
|
1400
|
+
index: item.index,
|
|
1401
|
+
path: item.path,
|
|
1402
|
+
selected: item.selected,
|
|
1403
|
+
colorValue: item.colorValue,
|
|
1404
|
+
},
|
|
1405
|
+
style: leftStyle.style,
|
|
1406
|
+
inlineOverlays: leftStyle.inlineOverlays,
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
return entries;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
function buildPickerPanelEntries(): TextPropertyEntry[] {
|
|
1413
|
+
const entries: TextPropertyEntry[] = [];
|
|
1414
|
+
const rightLines = buildPickerLines();
|
|
1415
|
+
for (const item of rightLines) {
|
|
1416
|
+
const rightStyle = styleForRightEntry(item);
|
|
1417
|
+
entries.push({
|
|
1418
|
+
text: " " + item.text + "\n",
|
|
1419
|
+
properties: {
|
|
1420
|
+
type: item.type,
|
|
1421
|
+
namedRow: item.namedRow,
|
|
1422
|
+
paletteRow: item.paletteRow,
|
|
1423
|
+
previewLineIdx: item.previewLineIdx,
|
|
1424
|
+
},
|
|
1425
|
+
style: rightStyle.style,
|
|
1426
|
+
inlineOverlays: rightStyle.inlineOverlays,
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
return entries;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
function buildFooterPanelEntries(): TextPropertyEntry[] {
|
|
1433
|
+
const hintText = " ↑↓ Navigate Tab Switch Panel Enter Edit /Filter Ctrl+S Save Esc Close";
|
|
1434
|
+
return [{ text: hintText + "\n", style: { fg: colors.header } }];
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1355
1437
|
function updateDisplay(): void {
|
|
1356
|
-
if (state.bufferId === null) return;
|
|
1357
1438
|
isUpdatingDisplay = true;
|
|
1358
1439
|
|
|
1440
|
+
// Always refresh viewport dimensions
|
|
1441
|
+
const viewport = editor.getViewport();
|
|
1442
|
+
if (viewport) {
|
|
1443
|
+
state.viewportHeight = viewport.height;
|
|
1444
|
+
state.viewportWidth = viewport.width;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// Buffer group mode: write to each panel separately
|
|
1448
|
+
if (state.groupId !== null) {
|
|
1449
|
+
editor.setPanelContent(state.groupId, "tree", buildTreePanelEntries());
|
|
1450
|
+
editor.setPanelContent(state.groupId, "picker", buildPickerPanelEntries());
|
|
1451
|
+
editor.setPanelContent(state.groupId, "footer", buildFooterPanelEntries());
|
|
1452
|
+
|
|
1453
|
+
// Keep the selected tree row in view. The plugin's `selectedIndex`
|
|
1454
|
+
// navigation doesn't move the buffer cursor, so without this the
|
|
1455
|
+
// core-driven panel viewport would stay at the top even after many
|
|
1456
|
+
// Down-arrow presses, causing the `▸` marker to scroll off-screen
|
|
1457
|
+
// for sections with many fields.
|
|
1458
|
+
const treeBufferId = state.panelBuffers["tree"];
|
|
1459
|
+
if (typeof treeBufferId === "number") {
|
|
1460
|
+
const treeLines = buildTreeLines();
|
|
1461
|
+
let selectedLine = -1;
|
|
1462
|
+
for (let i = 0; i < treeLines.length; i++) {
|
|
1463
|
+
if (treeLines[i].index === state.selectedIndex && treeLines[i].selected) {
|
|
1464
|
+
selectedLine = i;
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
if (selectedLine >= 0) {
|
|
1469
|
+
editor.scrollBufferToLine(treeBufferId, selectedLine);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
isUpdatingDisplay = false;
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
if (state.bufferId === null) {
|
|
1478
|
+
isUpdatingDisplay = false;
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1359
1482
|
const entries = buildDisplayEntries();
|
|
1360
1483
|
|
|
1361
1484
|
// Clear selection overlays BEFORE replacing content to prevent stale
|
|
@@ -1532,11 +1655,7 @@ function onThemeColorPromptConfirmed(args: {
|
|
|
1532
1655
|
setNestedValue(state.themeData, path, result.value);
|
|
1533
1656
|
state.hasChanges = !deepEqual(state.themeData, state.originalThemeData);
|
|
1534
1657
|
|
|
1535
|
-
|
|
1536
|
-
if (state.bufferId !== null) {
|
|
1537
|
-
editor.setVirtualBufferContent(state.bufferId, entries);
|
|
1538
|
-
applySelectionHighlighting(entries);
|
|
1539
|
-
}
|
|
1658
|
+
updateDisplay();
|
|
1540
1659
|
moveCursorToField(path);
|
|
1541
1660
|
editor.setStatus(editor.t("status.updated", { path }));
|
|
1542
1661
|
} else {
|
|
@@ -1793,11 +1912,7 @@ async function saveTheme(name?: string, restorePath?: string | null): Promise<bo
|
|
|
1793
1912
|
state.hasChanges = false;
|
|
1794
1913
|
|
|
1795
1914
|
// Update display
|
|
1796
|
-
|
|
1797
|
-
if (state.bufferId !== null) {
|
|
1798
|
-
editor.setVirtualBufferContent(state.bufferId, entries);
|
|
1799
|
-
applySelectionHighlighting(entries);
|
|
1800
|
-
}
|
|
1915
|
+
updateDisplay();
|
|
1801
1916
|
|
|
1802
1917
|
// Restore cursor position if provided
|
|
1803
1918
|
if (restorePath) {
|
|
@@ -1903,7 +2018,17 @@ function onThemeEditorCursorMoved(data: {
|
|
|
1903
2018
|
new_position: number;
|
|
1904
2019
|
text_properties?: Array<Record<string, any>>;
|
|
1905
2020
|
}): void {
|
|
1906
|
-
if (state.bufferId === null
|
|
2021
|
+
if (state.bufferId === null) return;
|
|
2022
|
+
// Accept cursor_moved events for any of the buffer group's panels
|
|
2023
|
+
// (tree, picker, footer). With buffer groups each panel is its own
|
|
2024
|
+
// buffer, so clicks in the picker fire cursor_moved for the picker
|
|
2025
|
+
// buffer — not the tree buffer (state.bufferId). We must handle
|
|
2026
|
+
// events for all of them so picker clicks (named colors, palette,
|
|
2027
|
+
// hex) still update selection/colors.
|
|
2028
|
+
const groupBufferIds = Object.values(state.panelBuffers || {});
|
|
2029
|
+
const isGroupBuffer =
|
|
2030
|
+
data.buffer_id === state.bufferId || groupBufferIds.includes(data.buffer_id);
|
|
2031
|
+
if (!isGroupBuffer) return;
|
|
1907
2032
|
if (isUpdatingDisplay) return;
|
|
1908
2033
|
|
|
1909
2034
|
const props = data.text_properties || [];
|
|
@@ -1974,20 +2099,6 @@ function onThemeEditorResize(data: { width: number; height: number }): void {
|
|
|
1974
2099
|
registerHandler("onThemeEditorResize", onThemeEditorResize);
|
|
1975
2100
|
editor.on("resize", "onThemeEditorResize");
|
|
1976
2101
|
|
|
1977
|
-
function onThemeEditorMouseScroll(data: { buffer_id: number; delta: number; col: number; row: number }): void {
|
|
1978
|
-
if (state.bufferId === null || data.buffer_id !== state.bufferId) return;
|
|
1979
|
-
|
|
1980
|
-
// Only scroll the tree when mouse is over the left panel area (col < LEFT_WIDTH)
|
|
1981
|
-
if (data.col >= LEFT_WIDTH) return;
|
|
1982
|
-
|
|
1983
|
-
// delta > 0 = scroll down, delta < 0 = scroll up
|
|
1984
|
-
const scrollAmount = data.delta > 0 ? 3 : -3;
|
|
1985
|
-
state.treeScrollOffset = Math.max(0, state.treeScrollOffset + scrollAmount);
|
|
1986
|
-
updateDisplay();
|
|
1987
|
-
}
|
|
1988
|
-
registerHandler("onThemeEditorMouseScroll", onThemeEditorMouseScroll);
|
|
1989
|
-
editor.on("mouse_scroll", "onThemeEditorMouseScroll");
|
|
1990
|
-
|
|
1991
2102
|
/**
|
|
1992
2103
|
* Handle buffer_closed event to reset state when buffer is closed by any means
|
|
1993
2104
|
*/
|
|
@@ -2510,38 +2621,30 @@ async function doOpenThemeEditor(): Promise<void> {
|
|
|
2510
2621
|
}
|
|
2511
2622
|
state.treeScrollOffset = 0;
|
|
2512
2623
|
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
showCursors: false,
|
|
2527
|
-
editingDisabled: true,
|
|
2624
|
+
// Create buffer group with layout: horizontal split (tree | picker) + footer
|
|
2625
|
+
const layout = JSON.stringify({
|
|
2626
|
+
type: "split",
|
|
2627
|
+
direction: "v",
|
|
2628
|
+
ratio: 0.95,
|
|
2629
|
+
first: {
|
|
2630
|
+
type: "split",
|
|
2631
|
+
direction: "h",
|
|
2632
|
+
ratio: 0.38,
|
|
2633
|
+
first: { type: "scrollable", id: "tree" },
|
|
2634
|
+
second: { type: "scrollable", id: "picker" },
|
|
2635
|
+
},
|
|
2636
|
+
second: { type: "fixed", id: "footer", height: 1 },
|
|
2528
2637
|
});
|
|
2529
|
-
const bufferId = result.bufferId;
|
|
2530
|
-
editor.debug(`[theme_editor] doOpenThemeEditor: createVirtualBuffer returned bufferId=${bufferId}`);
|
|
2531
|
-
editor.debug(`[theme_editor] doOpenThemeEditor: checking if bufferId !== null...`);
|
|
2532
|
-
|
|
2533
|
-
if (bufferId !== null) {
|
|
2534
|
-
editor.debug(`[theme_editor] doOpenThemeEditor: bufferId is not null, setting state...`);
|
|
2535
|
-
state.bufferId = bufferId;
|
|
2536
|
-
state.splitId = null;
|
|
2537
2638
|
|
|
2538
|
-
|
|
2539
|
-
|
|
2639
|
+
const groupResult = await editor.createBufferGroup("*Theme Editor*", "theme-editor", layout);
|
|
2640
|
+
state.groupId = groupResult.groupId;
|
|
2641
|
+
state.panelBuffers = groupResult.panels;
|
|
2642
|
+
state.bufferId = groupResult.panels["tree"]; // representative buffer
|
|
2643
|
+
state.splitId = null;
|
|
2540
2644
|
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
editor.debug(`[theme_editor] doOpenThemeEditor: calling setStatus...`);
|
|
2645
|
+
if (state.bufferId !== null) {
|
|
2646
|
+
// Set initial content for all panels
|
|
2647
|
+
updateDisplay();
|
|
2545
2648
|
editor.debug(editor.t("status.ready"));
|
|
2546
2649
|
editor.debug(`[theme_editor] doOpenThemeEditor: completed successfully`);
|
|
2547
2650
|
} else {
|
|
@@ -2575,8 +2678,12 @@ registerHandler("theme_editor_close", theme_editor_close);
|
|
|
2575
2678
|
* Actually close the editor (called after confirmation or when no changes)
|
|
2576
2679
|
*/
|
|
2577
2680
|
function doCloseEditor(): void {
|
|
2578
|
-
// Close the buffer (
|
|
2579
|
-
if (state.
|
|
2681
|
+
// Close the buffer group (or fall back to single buffer close)
|
|
2682
|
+
if (state.groupId !== null) {
|
|
2683
|
+
editor.closeBufferGroup(state.groupId);
|
|
2684
|
+
state.groupId = null;
|
|
2685
|
+
state.panelBuffers = {};
|
|
2686
|
+
} else if (state.bufferId !== null) {
|
|
2580
2687
|
editor.closeBuffer(state.bufferId);
|
|
2581
2688
|
}
|
|
2582
2689
|
|