@workbench-kit/react 0.0.2-prototype.0.2.4 → 0.0.2-prototype.0.2.41
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/README.md +172 -0
- package/package.json +38 -21
- package/src/index.ts +74 -34
- package/src/jdw/JsonCodeEditorPane.tsx +7 -6
- package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +1 -3
- package/src/jdw/createBuiltinJdwRegistry.ts +1 -4
- package/src/jdw/cssRenderBackend.tsx +1 -4
- package/src/jdw/fixtures/jdw-fixtures.ts +0 -15
- package/src/json-config/JsonConfigWorkbench.tsx +1 -1
- package/src/layout/index.ts +11 -2
- package/src/layout/panel/Panel.tsx +0 -3
- package/src/layout/panel/index.ts +0 -2
- package/src/layout/sidebar/SideBarTree.tsx +301 -0
- package/src/layout/sidebar/SidebarActionIconBar.tsx +3 -3
- package/src/layout/sidebar/WorkbenchSidebarActions.tsx +1 -1
- package/src/layout/sidebar/index.ts +13 -0
- package/src/modal/Modal.tsx +55 -25
- package/src/modal/ModalTitlebar.tsx +8 -8
- package/src/modal/modalPosition.ts +3 -6
- package/src/modal/useModalFocusTrap.ts +142 -0
- package/src/modal/useModalWindowFrame.ts +2 -2
- package/src/overlay/ContextMenu.tsx +133 -21
- package/src/overlay/context-menu-density.css +22 -0
- package/src/overlay/context-menu-item.ts +17 -0
- package/src/overlay/context-menu.css +6 -2
- package/src/overlay/index.ts +6 -1
- package/src/overlay/measureAnchoredOverlayPanel.ts +4 -6
- package/src/overlay/pointerPassthroughRegion.ts +17 -1
- package/src/overlay/usePointerPassthroughRegion.ts +35 -6
- package/src/primitives/absolute-box/AbsoluteBox.tsx +4 -4
- package/src/primitives/app-icon/AppIcon.tsx +33 -0
- package/src/primitives/app-icon/app-icon.css +28 -0
- package/src/primitives/button/Button.tsx +4 -4
- package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +6 -6
- package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +39 -32
- package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +4 -0
- package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +2 -2
- package/src/primitives/checkbox/Checkbox.tsx +1 -1
- package/src/primitives/chip/Chip.tsx +3 -12
- package/src/primitives/chip/index.ts +2 -2
- package/src/primitives/codicon/Codicon.tsx +1 -1
- package/src/primitives/file-icon/FileIcon.tsx +1 -1
- package/src/primitives/icon-button/IconButton.tsx +1 -1
- package/src/primitives/index.ts +7 -2
- package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +123 -9
- package/src/primitives/library-detail-layout/library-detail-layout.css +57 -0
- package/src/primitives/library-detail-layout/resolve-hero-cover-media.ts +80 -0
- package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +12 -12
- package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +4 -4
- package/src/primitives/number-input/NumberInput.tsx +5 -5
- package/src/primitives/primitives.css +1 -0
- package/src/primitives/record-media-hero/RecordMediaHero.tsx +10 -6
- package/src/primitives/scroll-area/ScrollArea.tsx +5 -5
- package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +5 -5
- package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +7 -7
- package/src/primitives/select/Select.tsx +1 -13
- package/src/primitives/text-area/TextArea.tsx +1 -1
- package/src/primitives/text-input/TextInput.tsx +1 -1
- package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +2 -2
- package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +16 -10
- package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +4 -4
- package/src/scrollbars.css +2 -6
- package/src/styles/core.css +16 -0
- package/src/styles/foundation.css +4 -0
- package/src/styles/overlay.css +2 -0
- package/src/styles.css +1 -15
- package/src/utils/clamp.ts +4 -0
- package/src/utils/normalizeKeyToken.ts +13 -0
- package/src/utils/readNumber.ts +4 -0
- package/src/widget-tree/WidgetSourceEditor.tsx +0 -14
- package/src/widget-tree/WidgetTreeCanvasPreview.tsx +3 -10
- package/src/widget-tree/WidgetTreeLab.tsx +2 -23
- package/src/widget-tree/WidgetTreeSidePanel.tsx +0 -5
- package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +2 -2
- package/src/widget-tree/index.ts +1 -5
- package/src/workbench/auth/WorkbenchLoginView.tsx +1 -2
- package/src/workbench/auth/auth-flows.css +14 -0
- package/src/workbench/chat/ChatCommandProposalCard.tsx +4 -4
- package/src/workbench/chat/ChatConversationBar.tsx +3 -3
- package/src/workbench/chat/ChatHistoryMenu.tsx +1 -1
- package/src/workbench/chat/ChatMessageCollapsible.tsx +4 -0
- package/src/workbench/chat/ChatMessageItem.tsx +68 -10
- package/src/workbench/chat/ChatMessageList.tsx +1 -1
- package/src/workbench/chat/ChatPanel.tsx +32 -23
- package/src/workbench/chat/ChatPhasedRunProgress.tsx +86 -13
- package/src/workbench/chat/ChatRenameDialog.tsx +1 -1
- package/src/workbench/chat/chat-conversation.css +2 -2
- package/src/workbench/chat/chat-ui.css +8 -0
- package/src/workbench/chat/chatConversation.ts +2 -2
- package/src/workbench/chat/chatMessageMeta.tsx +4 -4
- package/src/workbench/chat/index.ts +1 -0
- package/src/workbench/chat/types.ts +7 -7
- package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +4 -4
- package/src/workbench/chat/useChatPrependPagination.ts +10 -10
- package/src/workbench/chat/useSlashCommandSuggest.ts +1 -1
- package/src/workbench/{WorkbenchModalPortal.tsx → chrome/WorkbenchModalPortal.tsx} +1 -1
- package/src/workbench/chrome/workbench-chrome.css +4 -0
- package/src/workbench/chrome/workbench-layout-regions.css +13 -0
- package/src/workbench/chrome/workbench-shell-titlebar.css +0 -8
- package/src/workbench/{CommandGroupShell.tsx → commands/CommandGroupShell.tsx} +2 -2
- package/src/workbench/{CommandList.tsx → commands/CommandList.tsx} +6 -5
- package/src/workbench/{CommandPalette.tsx → commands/CommandPalette.tsx} +16 -42
- package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +5 -5
- package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +17 -13
- package/src/workbench/commands/WorkbenchQuickOpen.tsx +462 -0
- package/src/workbench/{command-model.ts → commands/command-model.ts} +5 -1
- package/src/workbench/commands/command-ui.ts +3 -0
- package/src/workbench/{commands.ts → commands/commands.ts} +45 -1
- package/src/workbench/commands/createWorkspaceFilesQuickOpenProvider.ts +86 -0
- package/src/workbench/commands/quick-open-model.ts +66 -0
- package/src/workbench/{WorkbenchEditorTabs.tsx → editor/WorkbenchEditorTabs.tsx} +13 -3
- package/src/workbench/{editor-tabs-dnd.ts → editor/editor-tabs-dnd.ts} +1 -1
- package/src/workbench/{editorTabContextMenu.ts → editor/editorTabContextMenu.ts} +43 -4
- package/src/workbench/{useEditorTabsStripDnd.ts → editor/useEditorTabsStripDnd.ts} +1 -1
- package/src/workbench/{useWorkbenchEditorTabContextMenu.tsx → editor/useWorkbenchEditorTabContextMenu.tsx} +16 -2
- package/src/workbench/editor-tabs/index.ts +10 -9
- package/src/workbench/index.ts +114 -74
- package/src/workbench/management/CommandManagementSidebar.tsx +16 -30
- package/src/workbench/management/ExtensionManagementPanel.tsx +84 -46
- package/src/workbench/management/ExtensionManagementSidebar.tsx +79 -45
- package/src/workbench/management/IntegrationCommandActions.tsx +8 -1
- package/src/workbench/management/IntegrationSettingsSurface.tsx +2 -5
- package/src/workbench/management/IntegrationsShell.tsx +1 -1
- package/src/workbench/management/KeybindingCaptureField.tsx +1 -9
- package/src/workbench/management/WorkbenchDialogFrame.tsx +2 -2
- package/src/workbench/management/WorkbenchNotice.tsx +17 -12
- package/src/workbench/management/createWorkbenchNotify.tsx +88 -0
- package/src/workbench/management/extension-install-approval.ts +72 -0
- package/src/workbench/management/extension-management-filters.ts +38 -0
- package/src/workbench/management/index.ts +18 -3
- package/src/workbench/management/management.css +28 -0
- package/src/workbench/management/types.ts +23 -1
- package/src/workbench/management/useWorkbenchNotify.ts +10 -0
- package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +22 -7
- package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
- package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
- package/src/workbench/schema/workbenchDocumentRenderer.tsx +48 -121
- package/src/workbench/settings/StructuredDataForm.tsx +1 -4
- package/src/workbench/settings/StructuredDataSchemaPanel.tsx +39 -44
- package/src/workbench/settings/sectionedPanelScrollSpy.ts +0 -81
- package/src/workbench/settings/structuredDataFormModel.ts +2 -1
- package/src/workbench/settings/structuredDataSchema.ts +24 -13
- package/src/workbench/settings/structuredDataSchemaSection.ts +4 -0
- package/src/workbench/settings/structuredDataSchemaTable.ts +5 -2
- package/src/workbench/{ActivityBar.tsx → shell/ActivityBar.tsx} +8 -12
- package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +25 -25
- package/src/workbench/{SplitView.tsx → shell/SplitView.tsx} +3 -3
- package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +8 -8
- package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
- package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +77 -20
- package/src/workbench/{WorkbenchCanvasShell.defaults.ts → shell/WorkbenchCanvasShell.defaults.ts} +1 -1
- package/src/workbench/{WorkbenchCanvasShell.model.ts → shell/WorkbenchCanvasShell.model.ts} +5 -5
- package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +6 -6
- package/src/workbench/{WorkbenchDesktopTitleBar.tsx → shell/WorkbenchDesktopTitleBar.tsx} +15 -15
- package/src/workbench/{WorkbenchShell.tsx → shell/WorkbenchShell.tsx} +45 -6
- package/src/workbench/{WorkbenchShellTitleBarLayoutControls.tsx → shell/WorkbenchShellTitleBarLayoutControls.tsx} +16 -19
- package/src/workbench/{WorkbenchStandaloneShell.tsx → shell/WorkbenchStandaloneShell.tsx} +15 -22
- package/src/workbench/{WorkbenchViewEditor.tsx → shell/WorkbenchViewEditor.tsx} +7 -7
- package/src/workbench/{WorkbenchViewSidebar.tsx → shell/WorkbenchViewSidebar.tsx} +7 -7
- package/src/workbench/{WorkbenchWindowChromeControls.tsx → shell/WorkbenchWindowChromeControls.tsx} +18 -15
- package/src/workbench/shell/activity-bar.css +47 -0
- package/src/workbench/{activityBarOrder.ts → shell/activityBarOrder.ts} +2 -1
- package/src/workbench/{shell.ts → shell/shell.ts} +20 -13
- package/src/workbench/{shellViewModel.ts → shell/shellViewModel.ts} +3 -3
- package/src/workbench/{standalone.ts → shell/standalone.ts} +14 -2
- package/src/workbench/{useDeferredWorkbenchMount.ts → shell/useDeferredWorkbenchMount.ts} +3 -3
- package/src/workbench/{useWorkbenchAppearanceDocumentSync.tsx → shell/useWorkbenchAppearanceDocumentSync.tsx} +1 -1
- package/src/workbench/{useWorkbenchSidebarActionBarDnd.ts → shell/useWorkbenchSidebarActionBarDnd.ts} +1 -1
- package/src/workbench/{useWorkbenchSidebarViewPlacementDropZone.ts → shell/useWorkbenchSidebarViewPlacementDropZone.ts} +2 -2
- package/src/workbench/{workbenchSidebarLayoutContext.ts → shell/workbenchSidebarLayoutContext.ts} +0 -6
- package/src/workbench/{workbenchViewRouteState.ts → shell/workbenchViewRouteState.ts} +4 -4
- package/src/workbench/{WorkbenchThemeProvider.tsx → theme/WorkbenchThemeProvider.tsx} +4 -4
- package/src/workbench/{theme.ts → theme/theme.ts} +1 -1
- package/src/workbench/{themePresets.ts → theme/themePresets.ts} +39 -64
- package/src/workbench/views/command-list-density.css +36 -0
- package/src/workbench/views/command-list.css +2 -0
- package/src/workbench/views/extensions-sidebar.css +2 -0
- package/src/workbench/views/view-hosts.css +3 -3
- package/src/workbench/workspace/WorkspaceEditorPanel.tsx +1 -1
- package/src/workbench/workspace/WorkspaceExplorer.tsx +105 -4
- package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +1 -14
- package/src/workbench/workspace/workspaceExplorerKeyboard.ts +109 -0
- package/src/workbench/workspace/workspaceJsonDiagnostics.ts +6 -5
- package/src/workbench-menu-surfaces.css +3 -57
- package/src/brand/TilepaperAppIcon.tsx +0 -181
- package/src/brand/index.ts +0 -2
- package/src/brand/tilepaper-app-icon-geometry.ts +0 -201
- package/src/primitives/absolute-box/index.ts +0 -1
- package/src/primitives/catalog-browse-card/index.ts +0 -1
- package/src/primitives/catalog-browse-pane/index.ts +0 -3
- package/src/primitives/catalog-filter-overlay/index.ts +0 -1
- package/src/primitives/codicon/index.ts +0 -1
- package/src/primitives/external-link-button/index.ts +0 -1
- package/src/primitives/library-detail-layout/index.ts +0 -1
- package/src/primitives/library-facet-filter-panel/index.ts +0 -1
- package/src/primitives/library-facet-filter-strip/index.ts +0 -1
- package/src/primitives/panel-loading/index.ts +0 -1
- package/src/primitives/scroll-area-infinite-load/index.ts +0 -2
- package/src/primitives/workbench-thumbnail/index.ts +0 -1
- package/src/test-utils/workbenchMonacoMock.tsx +0 -37
- package/src/workbench/jdw/jdw-editors.css +0 -4
- package/src/workbench/jdw/jdw.css +0 -2
- package/src/workbench/management/integration-command-action.ts +0 -25
- package/src/workbench/markdownRemarkPlugins.ts +0 -4
- package/src/workbench/workbench-chrome.css +0 -4
- /package/src/workbench/{WorkbenchPlatformContext.tsx → chrome/WorkbenchPlatformContext.tsx} +0 -0
- /package/src/workbench/{workbenchModalViewState.ts → chrome/workbenchModalViewState.ts} +0 -0
- /package/src/workbench/{workbenchOverlaysContext.tsx → chrome/workbenchOverlaysContext.tsx} +0 -0
- /package/src/workbench/{workbenchPlatformChrome.ts → chrome/workbenchPlatformChrome.ts} +0 -0
- /package/src/workbench/{command-execution-policy.ts → commands/command-execution-policy.ts} +0 -0
- /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
- /package/src/workbench/{workbenchContextMenu.ts → commands/workbenchContextMenu.ts} +0 -0
- /package/src/workbench/{appearanceLabels.ts → shell/appearanceLabels.ts} +0 -0
- /package/src/workbench/{hardReset.ts → shell/hardReset.ts} +0 -0
- /package/src/workbench/{shellPresets.ts → shell/shellPresets.ts} +0 -0
- /package/src/workbench/{shellState.ts → shell/shellState.ts} +0 -0
- /package/src/workbench/{sidebarViewPlacementDnd.ts → shell/sidebarViewPlacementDnd.ts} +0 -0
- /package/src/workbench/{status.ts → shell/status.ts} +0 -0
- /package/src/workbench/{useWorkbenchSidebarLayout.tsx → shell/useWorkbenchSidebarLayout.tsx} +0 -0
- /package/src/workbench/{useWorkbenchStandaloneShellStateSync.tsx → shell/useWorkbenchStandaloneShellStateSync.tsx} +0 -0
- /package/src/workbench/{workbenchStandaloneShellReactContext.tsx → shell/workbenchStandaloneShellReactContext.tsx} +0 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useId,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
type ComponentPropsWithRef,
|
|
9
|
+
type KeyboardEvent,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { useModalFocusTrap } from '../../modal/useModalFocusTrap';
|
|
13
|
+
import { Button } from '../../primitives/button';
|
|
14
|
+
import { EmptyState } from '../../primitives/empty-state';
|
|
15
|
+
import { IconButton } from '../../primitives/icon-button';
|
|
16
|
+
import { TextInput } from '../../primitives/text-input';
|
|
17
|
+
import { cxCodicon } from '../../utils/codicon';
|
|
18
|
+
import { cx } from '../../utils/cx';
|
|
19
|
+
import {
|
|
20
|
+
DEFAULT_QUICK_OPEN_SEARCH_DEBOUNCE_MS,
|
|
21
|
+
getNextQuickOpenItemIndex,
|
|
22
|
+
isQuickOpenItemSelectable,
|
|
23
|
+
type QuickOpenItem,
|
|
24
|
+
type QuickOpenProvider,
|
|
25
|
+
type QuickOpenSelectContext,
|
|
26
|
+
} from './quick-open-model';
|
|
27
|
+
|
|
28
|
+
interface WorkbenchQuickOpenKeyEvent {
|
|
29
|
+
key: string;
|
|
30
|
+
preventDefault: () => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface QuickOpenResult {
|
|
34
|
+
item: QuickOpenItem;
|
|
35
|
+
key: string;
|
|
36
|
+
provider: QuickOpenProvider;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function useControllableQuery({
|
|
40
|
+
defaultQuery = '',
|
|
41
|
+
query,
|
|
42
|
+
onQueryChange,
|
|
43
|
+
}: {
|
|
44
|
+
defaultQuery?: string | undefined;
|
|
45
|
+
query?: string | undefined;
|
|
46
|
+
onQueryChange?: ((query: string) => void) | undefined;
|
|
47
|
+
}) {
|
|
48
|
+
const [uncontrolledQuery, setUncontrolledQuery] = useState(defaultQuery);
|
|
49
|
+
const resolvedQuery = query ?? uncontrolledQuery;
|
|
50
|
+
|
|
51
|
+
const setQuery = (nextQuery: string) => {
|
|
52
|
+
if (query === undefined) {
|
|
53
|
+
setUncontrolledQuery(nextQuery);
|
|
54
|
+
}
|
|
55
|
+
onQueryChange?.(nextQuery);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return [resolvedQuery, setQuery] as const;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface WorkbenchQuickOpenProps extends Omit<
|
|
62
|
+
ComponentPropsWithRef<'div'>,
|
|
63
|
+
'children' | 'onSelect' | 'title'
|
|
64
|
+
> {
|
|
65
|
+
activeItemId?: string | undefined;
|
|
66
|
+
closeLabel?: string | undefined;
|
|
67
|
+
debounceMs?: number | undefined;
|
|
68
|
+
defaultQuery?: string | undefined;
|
|
69
|
+
emptyLabel?: ReactNode | undefined;
|
|
70
|
+
onActiveItemChange?: ((itemId: string) => void) | undefined;
|
|
71
|
+
onClose: () => void;
|
|
72
|
+
onProviderError?: ((error: unknown, provider: QuickOpenProvider) => void) | undefined;
|
|
73
|
+
onQueryChange?: ((query: string) => void) | undefined;
|
|
74
|
+
onSelectItem?: ((item: QuickOpenItem, context: QuickOpenSelectContext) => void) | undefined;
|
|
75
|
+
open?: boolean | undefined;
|
|
76
|
+
placeholder?: string | undefined;
|
|
77
|
+
/** Restrict search to one provider. When omitted, all providers contribute. */
|
|
78
|
+
providerId?: string | undefined;
|
|
79
|
+
providers: readonly QuickOpenProvider[];
|
|
80
|
+
query?: string | undefined;
|
|
81
|
+
restoreFocusOnClose?: boolean | undefined;
|
|
82
|
+
title?: ReactNode | undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function WorkbenchQuickOpen({
|
|
86
|
+
activeItemId,
|
|
87
|
+
className,
|
|
88
|
+
closeLabel = 'Close Quick Open',
|
|
89
|
+
debounceMs = DEFAULT_QUICK_OPEN_SEARCH_DEBOUNCE_MS,
|
|
90
|
+
defaultQuery,
|
|
91
|
+
emptyLabel = 'No matching files',
|
|
92
|
+
onActiveItemChange,
|
|
93
|
+
onClose,
|
|
94
|
+
onProviderError,
|
|
95
|
+
onQueryChange,
|
|
96
|
+
onSelectItem,
|
|
97
|
+
open = true,
|
|
98
|
+
placeholder = 'Search files by name',
|
|
99
|
+
providerId,
|
|
100
|
+
providers,
|
|
101
|
+
query,
|
|
102
|
+
restoreFocusOnClose = true,
|
|
103
|
+
title = 'Quick Open',
|
|
104
|
+
...props
|
|
105
|
+
}: WorkbenchQuickOpenProps) {
|
|
106
|
+
const titleId = useId();
|
|
107
|
+
const listId = useId();
|
|
108
|
+
const dialogRef = useRef<HTMLDivElement>(null);
|
|
109
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
110
|
+
const [uncontrolledActiveResultKey, setUncontrolledActiveResultKey] = useState<string>();
|
|
111
|
+
const [results, setResults] = useState<QuickOpenResult[]>([]);
|
|
112
|
+
const [searching, setSearching] = useState(false);
|
|
113
|
+
const onProviderErrorRef = useRef(onProviderError);
|
|
114
|
+
const [resolvedQuery, setResolvedQuery] = useControllableQuery({
|
|
115
|
+
defaultQuery,
|
|
116
|
+
onQueryChange,
|
|
117
|
+
query,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
onProviderErrorRef.current = onProviderError;
|
|
122
|
+
}, [onProviderError]);
|
|
123
|
+
|
|
124
|
+
const activeProviders = useMemo(() => {
|
|
125
|
+
if (providerId) {
|
|
126
|
+
const provider = providers.find((candidate) => candidate.id === providerId);
|
|
127
|
+
return provider ? [provider] : [];
|
|
128
|
+
}
|
|
129
|
+
return providers;
|
|
130
|
+
}, [providerId, providers]);
|
|
131
|
+
|
|
132
|
+
const items = useMemo(() => results.map(({ item }) => item), [results]);
|
|
133
|
+
const controlledActiveResult = activeItemId
|
|
134
|
+
? results.find(({ item }) => item.id === activeItemId && isQuickOpenItemSelectable(item))
|
|
135
|
+
: undefined;
|
|
136
|
+
const uncontrolledActiveResult = results.find(
|
|
137
|
+
({ item, key }) => key === uncontrolledActiveResultKey && isQuickOpenItemSelectable(item),
|
|
138
|
+
);
|
|
139
|
+
const activeResult =
|
|
140
|
+
controlledActiveResult ??
|
|
141
|
+
uncontrolledActiveResult ??
|
|
142
|
+
results.find(({ item }) => isQuickOpenItemSelectable(item));
|
|
143
|
+
const resolvedActiveResultKey = activeResult?.key;
|
|
144
|
+
const activeIndex = activeResult ? results.indexOf(activeResult) : -1;
|
|
145
|
+
|
|
146
|
+
const updateActiveItem = useCallback(
|
|
147
|
+
(result: QuickOpenResult | undefined) => {
|
|
148
|
+
if (!result) return;
|
|
149
|
+
if (activeItemId === undefined) {
|
|
150
|
+
setUncontrolledActiveResultKey(result.key);
|
|
151
|
+
}
|
|
152
|
+
onActiveItemChange?.(result.item.id);
|
|
153
|
+
},
|
|
154
|
+
[activeItemId, onActiveItemChange],
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
useModalFocusTrap({
|
|
158
|
+
enabled: open,
|
|
159
|
+
containerRef: dialogRef,
|
|
160
|
+
initialFocusRef: inputRef,
|
|
161
|
+
onClose,
|
|
162
|
+
restoreFocusOnClose,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
if (!open || activeProviders.length === 0) {
|
|
167
|
+
setResults([]);
|
|
168
|
+
setSearching(false);
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const controller = new AbortController();
|
|
173
|
+
let cancelled = false;
|
|
174
|
+
const runSearch = async () => {
|
|
175
|
+
setResults([]);
|
|
176
|
+
setSearching(true);
|
|
177
|
+
const providerResults = activeProviders.map<QuickOpenResult[] | undefined>(() => undefined);
|
|
178
|
+
const publishAvailableResults = () => {
|
|
179
|
+
setResults(providerResults.flatMap((providerItems) => providerItems ?? []));
|
|
180
|
+
};
|
|
181
|
+
const searches = activeProviders.map(async (provider, providerIndex) => {
|
|
182
|
+
try {
|
|
183
|
+
const providerItems = await Promise.resolve(
|
|
184
|
+
provider.search(resolvedQuery, { signal: controller.signal }),
|
|
185
|
+
);
|
|
186
|
+
if (cancelled) return;
|
|
187
|
+
|
|
188
|
+
providerResults[providerIndex] = providerItems.map((item, itemIndex) => ({
|
|
189
|
+
item,
|
|
190
|
+
key: `${providerIndex}:${itemIndex}:${provider.id}:${item.id}`,
|
|
191
|
+
provider,
|
|
192
|
+
}));
|
|
193
|
+
publishAvailableResults();
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (cancelled) return;
|
|
196
|
+
providerResults[providerIndex] = [];
|
|
197
|
+
publishAvailableResults();
|
|
198
|
+
onProviderErrorRef.current?.(error, provider);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await Promise.allSettled(searches);
|
|
203
|
+
if (!cancelled) setSearching(false);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Empty query (recent / top-level) should paint immediately; debounce typed queries.
|
|
207
|
+
const delay = resolvedQuery.trim() ? Math.max(0, debounceMs) : 0;
|
|
208
|
+
if (delay === 0) {
|
|
209
|
+
void runSearch();
|
|
210
|
+
return () => {
|
|
211
|
+
cancelled = true;
|
|
212
|
+
controller.abort();
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const timer = window.setTimeout(() => {
|
|
217
|
+
void runSearch();
|
|
218
|
+
}, delay);
|
|
219
|
+
|
|
220
|
+
return () => {
|
|
221
|
+
cancelled = true;
|
|
222
|
+
controller.abort();
|
|
223
|
+
window.clearTimeout(timer);
|
|
224
|
+
};
|
|
225
|
+
}, [activeProviders, debounceMs, open, resolvedQuery]);
|
|
226
|
+
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
if (!open) return;
|
|
229
|
+
if (activeItemId !== undefined) return;
|
|
230
|
+
|
|
231
|
+
setUncontrolledActiveResultKey((currentResultKey) => {
|
|
232
|
+
const currentResult = results.find(({ key }) => key === currentResultKey);
|
|
233
|
+
if (currentResult && isQuickOpenItemSelectable(currentResult.item)) {
|
|
234
|
+
return currentResultKey;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return results.find(({ item }) => isQuickOpenItemSelectable(item))?.key;
|
|
238
|
+
});
|
|
239
|
+
}, [activeItemId, open, results]);
|
|
240
|
+
|
|
241
|
+
const selectItem = useCallback(
|
|
242
|
+
(result: QuickOpenResult, index: number) => {
|
|
243
|
+
if (!isQuickOpenItemSelectable(result.item)) return;
|
|
244
|
+
onSelectItem?.(result.item, {
|
|
245
|
+
index,
|
|
246
|
+
providerId: result.provider.id,
|
|
247
|
+
query: resolvedQuery,
|
|
248
|
+
});
|
|
249
|
+
},
|
|
250
|
+
[onSelectItem, resolvedQuery],
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const handleQuickOpenKeyDown = useCallback(
|
|
254
|
+
(event: WorkbenchQuickOpenKeyEvent) => {
|
|
255
|
+
if (
|
|
256
|
+
event.key !== 'ArrowDown' &&
|
|
257
|
+
event.key !== 'ArrowUp' &&
|
|
258
|
+
event.key !== 'Home' &&
|
|
259
|
+
event.key !== 'End' &&
|
|
260
|
+
event.key !== 'PageDown' &&
|
|
261
|
+
event.key !== 'PageUp' &&
|
|
262
|
+
event.key !== 'Enter'
|
|
263
|
+
) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (event.key === 'Enter') {
|
|
268
|
+
if (!activeResult) return;
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
selectItem(activeResult, Math.max(activeIndex, 0));
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
event.preventDefault();
|
|
275
|
+
|
|
276
|
+
const direction =
|
|
277
|
+
event.key === 'ArrowUp' || event.key === 'End' || event.key === 'PageUp'
|
|
278
|
+
? 'previous'
|
|
279
|
+
: 'next';
|
|
280
|
+
const stepCount = event.key === 'PageDown' || event.key === 'PageUp' ? 5 : 1;
|
|
281
|
+
let nextIndex =
|
|
282
|
+
event.key === 'Home'
|
|
283
|
+
? getNextQuickOpenItemIndex({
|
|
284
|
+
currentIndex: -1,
|
|
285
|
+
direction: 'next',
|
|
286
|
+
items,
|
|
287
|
+
})
|
|
288
|
+
: event.key === 'End'
|
|
289
|
+
? getNextQuickOpenItemIndex({
|
|
290
|
+
currentIndex: 0,
|
|
291
|
+
direction: 'previous',
|
|
292
|
+
items,
|
|
293
|
+
})
|
|
294
|
+
: activeIndex;
|
|
295
|
+
|
|
296
|
+
if (event.key !== 'Home' && event.key !== 'End') {
|
|
297
|
+
for (let step = 0; step < stepCount; step += 1) {
|
|
298
|
+
const steppedIndex = getNextQuickOpenItemIndex({
|
|
299
|
+
currentIndex: nextIndex,
|
|
300
|
+
direction,
|
|
301
|
+
items,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (steppedIndex < 0 || steppedIndex === nextIndex) break;
|
|
305
|
+
nextIndex = steppedIndex;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (nextIndex >= 0) {
|
|
310
|
+
updateActiveItem(results[nextIndex]);
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
[activeIndex, activeResult, items, results, selectItem, updateActiveItem],
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
if (!open) return undefined;
|
|
318
|
+
|
|
319
|
+
const onKeyDown = (event: globalThis.KeyboardEvent) => {
|
|
320
|
+
if (event.defaultPrevented) return;
|
|
321
|
+
handleQuickOpenKeyDown(event);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
window.addEventListener('keydown', onKeyDown);
|
|
325
|
+
return () => {
|
|
326
|
+
window.removeEventListener('keydown', onKeyDown);
|
|
327
|
+
};
|
|
328
|
+
}, [handleQuickOpenKeyDown, open]);
|
|
329
|
+
|
|
330
|
+
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
|
331
|
+
handleQuickOpenKeyDown(event);
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
useEffect(() => {
|
|
335
|
+
if (!resolvedActiveResultKey) return;
|
|
336
|
+
|
|
337
|
+
const activeElement = Array.from(
|
|
338
|
+
dialogRef.current?.querySelectorAll<HTMLElement>('[data-quick-open-id]') ?? [],
|
|
339
|
+
).find((element) => element.dataset.quickOpenId === resolvedActiveResultKey);
|
|
340
|
+
|
|
341
|
+
activeElement?.scrollIntoView?.({ block: 'nearest' });
|
|
342
|
+
}, [resolvedActiveResultKey, results]);
|
|
343
|
+
|
|
344
|
+
if (!open) return null;
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<div className="ui-workbench-command-palette-overlay" onClick={onClose}>
|
|
348
|
+
<div
|
|
349
|
+
aria-labelledby={titleId}
|
|
350
|
+
aria-modal="true"
|
|
351
|
+
className={cx('ui-workbench-command-palette', className)}
|
|
352
|
+
data-testid="workbench-quick-open"
|
|
353
|
+
role="dialog"
|
|
354
|
+
{...props}
|
|
355
|
+
ref={dialogRef}
|
|
356
|
+
onClick={(event) => event.stopPropagation()}
|
|
357
|
+
>
|
|
358
|
+
<div className="ui-workbench-command-palette__header">
|
|
359
|
+
<span id={titleId} className="ui-workbench-command-palette__title">
|
|
360
|
+
{title}
|
|
361
|
+
</span>
|
|
362
|
+
<IconButton
|
|
363
|
+
className="ui-workbench-command-palette__close"
|
|
364
|
+
icon="codicon-close"
|
|
365
|
+
label={closeLabel}
|
|
366
|
+
onClick={onClose}
|
|
367
|
+
/>
|
|
368
|
+
</div>
|
|
369
|
+
<div className="ui-workbench-command-palette__search">
|
|
370
|
+
<i aria-hidden="true" className="codicon codicon-search" />
|
|
371
|
+
<TextInput
|
|
372
|
+
ref={inputRef}
|
|
373
|
+
aria-activedescendant={
|
|
374
|
+
activeResult ? `${listId}-${activeResult.key.replace(/[^\w-]/g, '_')}` : undefined
|
|
375
|
+
}
|
|
376
|
+
aria-controls={listId}
|
|
377
|
+
aria-label={placeholder}
|
|
378
|
+
className="ui-workbench-command-palette__input"
|
|
379
|
+
controlWidth="full"
|
|
380
|
+
placeholder={placeholder}
|
|
381
|
+
type="search"
|
|
382
|
+
value={resolvedQuery}
|
|
383
|
+
onValueChange={setResolvedQuery}
|
|
384
|
+
onKeyDown={handleKeyDown}
|
|
385
|
+
/>
|
|
386
|
+
</div>
|
|
387
|
+
<div
|
|
388
|
+
id={listId}
|
|
389
|
+
aria-busy={searching || undefined}
|
|
390
|
+
aria-label="Quick Open results"
|
|
391
|
+
className={cx('ui-workbench-command-list', 'ui-workbench-scrollbar')}
|
|
392
|
+
role="listbox"
|
|
393
|
+
>
|
|
394
|
+
{results.length === 0 ? (
|
|
395
|
+
<EmptyState compact icon="codicon-search">
|
|
396
|
+
{emptyLabel}
|
|
397
|
+
</EmptyState>
|
|
398
|
+
) : (
|
|
399
|
+
results.map((result, index) => {
|
|
400
|
+
const { item, key, provider } = result;
|
|
401
|
+
const active = key === resolvedActiveResultKey;
|
|
402
|
+
const itemDomId = `${listId}-${key.replace(/[^\w-]/g, '_')}`;
|
|
403
|
+
const descriptionId = item.description ? `${itemDomId}-description` : undefined;
|
|
404
|
+
|
|
405
|
+
return (
|
|
406
|
+
<Button
|
|
407
|
+
key={key}
|
|
408
|
+
id={itemDomId}
|
|
409
|
+
aria-describedby={descriptionId}
|
|
410
|
+
aria-selected={active}
|
|
411
|
+
className="ui-workbench-command-item"
|
|
412
|
+
data-active={active ? 'true' : undefined}
|
|
413
|
+
data-quick-open-id={key}
|
|
414
|
+
disabled={item.disabled}
|
|
415
|
+
role="option"
|
|
416
|
+
onClick={() => selectItem(result, index)}
|
|
417
|
+
onMouseEnter={() => updateActiveItem(result)}
|
|
418
|
+
>
|
|
419
|
+
<span className="ui-workbench-command-item__icon">
|
|
420
|
+
{item.icon ? <i aria-hidden="true" className={cxCodicon(item.icon)} /> : null}
|
|
421
|
+
</span>
|
|
422
|
+
<span className="ui-workbench-command-item__content">
|
|
423
|
+
<span className="ui-workbench-command-item__label">{item.label}</span>
|
|
424
|
+
{item.description ? (
|
|
425
|
+
<span id={descriptionId} className="ui-workbench-command-item__description">
|
|
426
|
+
{item.description}
|
|
427
|
+
</span>
|
|
428
|
+
) : null}
|
|
429
|
+
</span>
|
|
430
|
+
<span className="ui-workbench-command-item__meta">
|
|
431
|
+
{item.detail ? (
|
|
432
|
+
<span className="ui-workbench-command-item__category">{item.detail}</span>
|
|
433
|
+
) : null}
|
|
434
|
+
<span className="ui-workbench-command-item__category">{provider.label}</span>
|
|
435
|
+
</span>
|
|
436
|
+
</Button>
|
|
437
|
+
);
|
|
438
|
+
})
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export type {
|
|
447
|
+
QuickOpenItem,
|
|
448
|
+
QuickOpenProvider,
|
|
449
|
+
QuickOpenSearchContext,
|
|
450
|
+
QuickOpenSelectContext,
|
|
451
|
+
} from './quick-open-model';
|
|
452
|
+
export {
|
|
453
|
+
DEFAULT_QUICK_OPEN_SEARCH_DEBOUNCE_MS,
|
|
454
|
+
getNextQuickOpenItemIndex,
|
|
455
|
+
isQuickOpenItemSelectable,
|
|
456
|
+
} from './quick-open-model';
|
|
457
|
+
export {
|
|
458
|
+
WORKSPACE_FILES_QUICK_OPEN_PROVIDER_ID,
|
|
459
|
+
createWorkspaceFilesQuickOpenProvider,
|
|
460
|
+
resolveQuickOpenItemPath,
|
|
461
|
+
} from './createWorkspaceFilesQuickOpenProvider';
|
|
462
|
+
export type { CreateWorkspaceFilesQuickOpenProviderOptions } from './createWorkspaceFilesQuickOpenProvider';
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { CommandMenuItem, ResolvedCommandMenuCommandItem } from '@workbench-kit/platform';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getWorkbenchStatusLabel,
|
|
5
|
+
isWorkbenchStatusDisabled,
|
|
6
|
+
type WorkbenchStatus,
|
|
7
|
+
} from '../shell/status';
|
|
4
8
|
|
|
5
9
|
export type WorkbenchCommandStatus = WorkbenchStatus;
|
|
6
10
|
|
|
@@ -10,9 +10,10 @@ import {
|
|
|
10
10
|
type CommandValue,
|
|
11
11
|
} from '@workbench-kit/platform';
|
|
12
12
|
|
|
13
|
-
import type { ContextMenuItem } from '
|
|
13
|
+
import type { ContextMenuItem } from '../../overlay/ContextMenu';
|
|
14
14
|
|
|
15
15
|
export const WORKBENCH_OPEN_SETTINGS_COMMAND_ID = 'workbench.openSettings';
|
|
16
|
+
export const WORKBENCH_TOGGLE_FOCUS_MODE_COMMAND_ID = 'workbench.toggleFocusMode';
|
|
16
17
|
export const WORKBENCH_TOGGLE_PRIMARY_SIDEBAR_COMMAND_ID = 'workbench.togglePrimarySidebar';
|
|
17
18
|
export const WORKBENCH_EDITOR_SAVE_COMMAND_ID = 'editor.save';
|
|
18
19
|
export const WORKBENCH_EDITOR_DISCARD_CHANGES_COMMAND_ID = 'editor.discardChanges';
|
|
@@ -22,6 +23,7 @@ export const WORKBENCH_EDITOR_SPLIT_RIGHT_COMMAND_ID = 'editor.splitRight';
|
|
|
22
23
|
export const WORKBENCH_EDITOR_SPLIT_DOWN_COMMAND_ID = 'editor.splitDown';
|
|
23
24
|
export const WORKBENCH_EDITOR_CLOSE_COMMAND_ID = 'editor.close';
|
|
24
25
|
export const WORKBENCH_EDITOR_CLOSE_OTHERS_COMMAND_ID = 'editor.closeOthers';
|
|
26
|
+
export const WORKBENCH_EDITOR_CLOSE_TO_RIGHT_COMMAND_ID = 'editor.closeToRight';
|
|
25
27
|
export const WORKBENCH_EDITOR_CLOSE_ALL_COMMAND_ID = 'editor.closeAll';
|
|
26
28
|
export const WORKBENCH_EDITOR_DELETE_COMMAND_ID = 'editor.delete';
|
|
27
29
|
export const WORKBENCH_WORKSPACE_NEW_FILE_COMMAND_ID = 'workspace.newFile';
|
|
@@ -54,9 +56,11 @@ export interface WorkbenchShellCommandActivity<TActivityId extends string = stri
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export interface WorkbenchShellCommandContext<TActivityId extends string = string> {
|
|
59
|
+
isFocusModeActive?: boolean | undefined;
|
|
57
60
|
isPrimarySidebarVisible: boolean;
|
|
58
61
|
openSettings: () => void;
|
|
59
62
|
showActivity: (activityId: TActivityId) => void;
|
|
63
|
+
toggleFocusMode?: (() => void) | undefined;
|
|
60
64
|
togglePrimarySidebar: () => void;
|
|
61
65
|
}
|
|
62
66
|
|
|
@@ -96,6 +100,7 @@ function applyWorkbenchCommandOverrides<TContext>(
|
|
|
96
100
|
|
|
97
101
|
export interface WorkbenchShellCommandPresetOptions<TActivityId extends string = string> {
|
|
98
102
|
activities: WorkbenchShellCommandActivity<TActivityId>[];
|
|
103
|
+
includeFocusModeToggle?: boolean | undefined;
|
|
99
104
|
includeSettings?: boolean | undefined;
|
|
100
105
|
includeSidebarToggle?: boolean | undefined;
|
|
101
106
|
menuSeparatorId?: string | undefined;
|
|
@@ -109,6 +114,8 @@ export interface WorkbenchShellCommandPresetOptions<TActivityId extends string =
|
|
|
109
114
|
export interface WorkbenchEditorCommandContext {
|
|
110
115
|
canCloseAll: boolean;
|
|
111
116
|
canCloseOthers: boolean;
|
|
117
|
+
/** Optional so existing public command-context object literals remain source-compatible. */
|
|
118
|
+
canCloseToRight?: boolean | undefined;
|
|
112
119
|
canClosePath: boolean;
|
|
113
120
|
canCopyPath: boolean;
|
|
114
121
|
canDeletePath: boolean;
|
|
@@ -119,6 +126,8 @@ export interface WorkbenchEditorCommandContext {
|
|
|
119
126
|
canTogglePinned: boolean;
|
|
120
127
|
closeAll: () => void;
|
|
121
128
|
closeOthers: () => void;
|
|
129
|
+
/** Presence advertises support and makes Close to the right visible. */
|
|
130
|
+
closeToRight?: (() => void) | undefined;
|
|
122
131
|
closePath: () => void;
|
|
123
132
|
copyPath: () => void;
|
|
124
133
|
deletePath: () => void;
|
|
@@ -159,6 +168,7 @@ export function getWorkbenchShowActivityCommandId(activityId: string) {
|
|
|
159
168
|
|
|
160
169
|
export function createWorkbenchShellCommands<TActivityId extends string>({
|
|
161
170
|
activities,
|
|
171
|
+
includeFocusModeToggle = true,
|
|
162
172
|
includeSettings = true,
|
|
163
173
|
includeSidebarToggle = true,
|
|
164
174
|
settingsIcon = 'codicon-settings-gear',
|
|
@@ -179,6 +189,19 @@ export function createWorkbenchShellCommands<TActivityId extends string>({
|
|
|
179
189
|
|
|
180
190
|
const shellCommands: CommandDefinition<WorkbenchShellCommandContext<TActivityId>>[] = [];
|
|
181
191
|
|
|
192
|
+
if (includeFocusModeToggle) {
|
|
193
|
+
shellCommands.push({
|
|
194
|
+
id: WORKBENCH_TOGGLE_FOCUS_MODE_COMMAND_ID,
|
|
195
|
+
icon: 'codicon-screen-full',
|
|
196
|
+
isEnabled: ({ toggleFocusMode }) => toggleFocusMode !== undefined,
|
|
197
|
+
label: ({ isFocusModeActive }) =>
|
|
198
|
+
isFocusModeActive ? 'Exit Focus Mode' : 'Enter Focus Mode',
|
|
199
|
+
run: ({ toggleFocusMode }) => toggleFocusMode?.(),
|
|
200
|
+
shortcut: 'Ctrl/Cmd+Shift+F11',
|
|
201
|
+
title: 'Toggle Focus Mode',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
182
205
|
if (includeSidebarToggle) {
|
|
183
206
|
shellCommands.push({
|
|
184
207
|
id: WORKBENCH_TOGGLE_PRIMARY_SIDEBAR_COMMAND_ID,
|
|
@@ -207,6 +230,7 @@ export function createWorkbenchShellCommands<TActivityId extends string>({
|
|
|
207
230
|
|
|
208
231
|
export function createWorkbenchShellMenuEntries<TActivityId extends string>({
|
|
209
232
|
activities,
|
|
233
|
+
includeFocusModeToggle = true,
|
|
210
234
|
includeSettings = true,
|
|
211
235
|
includeSidebarToggle = true,
|
|
212
236
|
menuSeparatorId = 'workbench-shell-separator',
|
|
@@ -223,6 +247,15 @@ export function createWorkbenchShellMenuEntries<TActivityId extends string>({
|
|
|
223
247
|
);
|
|
224
248
|
const shellEntries: CommandMenuEntry<WorkbenchShellCommandContext<TActivityId>>[] = [];
|
|
225
249
|
|
|
250
|
+
if (includeFocusModeToggle) {
|
|
251
|
+
shellEntries.push(
|
|
252
|
+
commandMenuEntry<WorkbenchShellCommandContext<TActivityId>>(
|
|
253
|
+
WORKBENCH_TOGGLE_FOCUS_MODE_COMMAND_ID,
|
|
254
|
+
{ surfaces: [WORKBENCH_COMMAND_SURFACE_ACTIVITY_BAR] },
|
|
255
|
+
),
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
226
259
|
if (includeSidebarToggle) {
|
|
227
260
|
shellEntries.push(
|
|
228
261
|
commandMenuEntry<WorkbenchShellCommandContext<TActivityId>>(
|
|
@@ -314,6 +347,14 @@ export function createWorkbenchEditorCommands({
|
|
|
314
347
|
label: 'Close others',
|
|
315
348
|
run: ({ closeOthers }) => closeOthers(),
|
|
316
349
|
},
|
|
350
|
+
{
|
|
351
|
+
id: WORKBENCH_EDITOR_CLOSE_TO_RIGHT_COMMAND_ID,
|
|
352
|
+
icon: 'codicon-close-all',
|
|
353
|
+
isEnabled: ({ canCloseToRight, filePath }) => Boolean(filePath && canCloseToRight),
|
|
354
|
+
isVisible: ({ closeToRight }) => Boolean(closeToRight),
|
|
355
|
+
label: 'Close to the right',
|
|
356
|
+
run: ({ closeToRight }) => closeToRight?.(),
|
|
357
|
+
},
|
|
317
358
|
{
|
|
318
359
|
id: WORKBENCH_EDITOR_CLOSE_ALL_COMMAND_ID,
|
|
319
360
|
icon: 'codicon-close-all',
|
|
@@ -379,6 +420,9 @@ export function createWorkbenchStandaloneEditorTabMenuEntries(): CommandMenuEntr
|
|
|
379
420
|
commandMenuEntry<WorkbenchEditorCommandContext>(WORKBENCH_EDITOR_CLOSE_OTHERS_COMMAND_ID, {
|
|
380
421
|
surfaces: [WORKBENCH_COMMAND_SURFACE_EDITOR],
|
|
381
422
|
}),
|
|
423
|
+
commandMenuEntry<WorkbenchEditorCommandContext>(WORKBENCH_EDITOR_CLOSE_TO_RIGHT_COMMAND_ID, {
|
|
424
|
+
surfaces: [WORKBENCH_COMMAND_SURFACE_EDITOR],
|
|
425
|
+
}),
|
|
382
426
|
commandMenuEntry<WorkbenchEditorCommandContext>(WORKBENCH_EDITOR_CLOSE_ALL_COMMAND_ID, {
|
|
383
427
|
surfaces: [WORKBENCH_COMMAND_SURFACE_EDITOR],
|
|
384
428
|
}),
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { searchWorkspaceFiles, type WorkspaceFile } from '@workbench-kit/workspace';
|
|
2
|
+
|
|
3
|
+
import type { QuickOpenItem, QuickOpenProvider } from './quick-open-model';
|
|
4
|
+
|
|
5
|
+
export const WORKSPACE_FILES_QUICK_OPEN_PROVIDER_ID = 'workspace.files' as const;
|
|
6
|
+
|
|
7
|
+
export interface CreateWorkspaceFilesQuickOpenProviderOptions {
|
|
8
|
+
/** Current workspace files, or a getter read on each search. */
|
|
9
|
+
files: readonly WorkspaceFile[] | (() => readonly WorkspaceFile[]);
|
|
10
|
+
id?: string | undefined;
|
|
11
|
+
label?: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* When the query is empty, these paths appear first (still present in `files`).
|
|
14
|
+
* Remaining files follow in `searchWorkspaceFiles` order.
|
|
15
|
+
*/
|
|
16
|
+
recentPaths?: readonly string[] | undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveFiles(
|
|
20
|
+
files: CreateWorkspaceFilesQuickOpenProviderOptions['files'],
|
|
21
|
+
): readonly WorkspaceFile[] {
|
|
22
|
+
return typeof files === 'function' ? files() : files;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function toQuickOpenItem(path: string, matchedBy?: string, preview?: string): QuickOpenItem {
|
|
26
|
+
const segments = path.split('/');
|
|
27
|
+
const label = segments[segments.length - 1] || path;
|
|
28
|
+
const parent = segments.length > 1 ? segments.slice(0, -1).join('/') : undefined;
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
data: { path },
|
|
32
|
+
description: parent,
|
|
33
|
+
detail: matchedBy ?? preview,
|
|
34
|
+
icon: 'codicon-file',
|
|
35
|
+
id: path,
|
|
36
|
+
label,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function createWorkspaceFilesQuickOpenProvider(
|
|
41
|
+
options: CreateWorkspaceFilesQuickOpenProviderOptions,
|
|
42
|
+
): QuickOpenProvider {
|
|
43
|
+
const providerId = options.id ?? WORKSPACE_FILES_QUICK_OPEN_PROVIDER_ID;
|
|
44
|
+
const providerLabel = options.label ?? 'Files';
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
id: providerId,
|
|
48
|
+
label: providerLabel,
|
|
49
|
+
search(query: string) {
|
|
50
|
+
const files = [...resolveFiles(options.files)];
|
|
51
|
+
const results = searchWorkspaceFiles(files, query);
|
|
52
|
+
const items = results.map((result) =>
|
|
53
|
+
toQuickOpenItem(result.path, result.matchedBy, result.preview),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (query.trim() || !options.recentPaths?.length) {
|
|
57
|
+
return items;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const recentSet = new Set(options.recentPaths);
|
|
61
|
+
const byPath = new Map(items.map((item) => [item.id, item]));
|
|
62
|
+
const recentItems: QuickOpenItem[] = [];
|
|
63
|
+
|
|
64
|
+
for (const path of options.recentPaths) {
|
|
65
|
+
const item = byPath.get(path);
|
|
66
|
+
if (item) {
|
|
67
|
+
recentItems.push({ ...item, detail: 'Recent' });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const rest = items.filter((item) => !recentSet.has(item.id));
|
|
72
|
+
return [...recentItems, ...rest];
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function resolveQuickOpenItemPath(item: QuickOpenItem): string | undefined {
|
|
78
|
+
if (typeof item.data === 'object' && item.data !== null && 'path' in item.data) {
|
|
79
|
+
const path = (item.data as { path?: unknown }).path;
|
|
80
|
+
if (typeof path === 'string' && path.length > 0) {
|
|
81
|
+
return path;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return item.id || undefined;
|
|
86
|
+
}
|