mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
actions
This commit is contained in:
parent
063d9312c4
commit
3fc81f1baf
3 changed files with 163 additions and 117 deletions
147
src/vs/workbench/contrib/void/browser/registerActions.ts
Normal file
147
src/vs/workbench/contrib/void/browser/registerActions.ts
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
|
||||||
|
|
||||||
|
|
||||||
|
import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
||||||
|
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
||||||
|
|
||||||
|
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
|
||||||
|
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
|
||||||
|
import { CodeStagingSelection, IThreadHistoryService } from './registerThreads.js';
|
||||||
|
// import { IVoidConfigService } from './registerSettings.js';
|
||||||
|
// import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||||
|
|
||||||
|
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||||
|
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
||||||
|
import { IRange } from '../../../../editor/common/core/range.js';
|
||||||
|
import { ITextModel } from '../../../../editor/common/model.js';
|
||||||
|
import { IVoidSidebarStateService, VOID_VIEW_ID } from './registerSidebar.js';
|
||||||
|
// import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
||||||
|
|
||||||
|
|
||||||
|
// ---------- Register commands and keybindings ----------
|
||||||
|
|
||||||
|
|
||||||
|
const roundRangeToLines = (range: IRange | null | undefined) => {
|
||||||
|
if (!range)
|
||||||
|
return null
|
||||||
|
let endLine = range.endColumn === 0 ? range.endLineNumber - 1 : range.endLineNumber // e.g. if the user triple clicks, it selects column=0, line=line -> column=0, line=line+1
|
||||||
|
const newRange: IRange = {
|
||||||
|
startLineNumber: range.startLineNumber,
|
||||||
|
startColumn: 0,
|
||||||
|
endLineNumber: endLine,
|
||||||
|
endColumn: Number.MAX_SAFE_INTEGER
|
||||||
|
}
|
||||||
|
return newRange
|
||||||
|
}
|
||||||
|
|
||||||
|
const getContentInRange = (model: ITextModel, range: IRange | null) => {
|
||||||
|
if (!range)
|
||||||
|
return null
|
||||||
|
const content = model.getValueInRange(range)
|
||||||
|
const trimmedContent = content
|
||||||
|
.replace(/^\s*\n/g, '') // trim pure whitespace lines from start
|
||||||
|
.replace(/\n\s*$/g, '') // trim pure whitespace lines from end
|
||||||
|
return trimmedContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action: when press ctrl+L, show the sidebar chat and add to the selection
|
||||||
|
registerAction2(class extends Action2 {
|
||||||
|
constructor() {
|
||||||
|
super({ id: 'void.ctrl+l', title: 'Show Sidebar', keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyL, weight: KeybindingWeight.BuiltinExtension } });
|
||||||
|
}
|
||||||
|
async run(accessor: ServicesAccessor): Promise<void> {
|
||||||
|
|
||||||
|
const model = accessor.get(ICodeEditorService).getActiveCodeEditor()?.getModel()
|
||||||
|
if (!model)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
const stateService = accessor.get(IVoidSidebarStateService)
|
||||||
|
stateService.setState({ isHistoryOpen: false, currentTab: 'chat' })
|
||||||
|
stateService.fireFocusChat()
|
||||||
|
|
||||||
|
// add selection
|
||||||
|
const threadHistoryService = accessor.get(IThreadHistoryService)
|
||||||
|
const currentStaging = threadHistoryService.state._currentStagingSelections
|
||||||
|
const currentStagingEltIdx = currentStaging?.findIndex(s => s.fileURI.fsPath === model.uri.fsPath)
|
||||||
|
|
||||||
|
// if there exists a selection with this URI, replace it
|
||||||
|
const selectionRange = roundRangeToLines(
|
||||||
|
accessor.get(IEditorService).activeTextEditorControl?.getSelection()
|
||||||
|
)
|
||||||
|
|
||||||
|
if (selectionRange) {
|
||||||
|
const selection: CodeStagingSelection = {
|
||||||
|
selectionStr: getContentInRange(model, selectionRange),
|
||||||
|
fileURI: model.uri
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentStagingEltIdx !== undefined && currentStagingEltIdx !== -1) {
|
||||||
|
threadHistoryService.setStaging([
|
||||||
|
...currentStaging!.slice(0, currentStagingEltIdx),
|
||||||
|
selection,
|
||||||
|
...currentStaging!.slice(currentStagingEltIdx + 1, Infinity)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
threadHistoryService.setStaging([...(currentStaging ?? []), selection])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// New chat menu button
|
||||||
|
registerAction2(class extends Action2 {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: 'void.newChatAction',
|
||||||
|
title: 'View past chats',
|
||||||
|
icon: { id: 'add' },
|
||||||
|
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', VOID_VIEW_ID), }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async run(accessor: ServicesAccessor): Promise<void> {
|
||||||
|
const stateService = accessor.get(IVoidSidebarStateService)
|
||||||
|
stateService.setState({ isHistoryOpen: false, currentTab: 'chat' })
|
||||||
|
stateService.fireFocusChat()
|
||||||
|
|
||||||
|
const historyService = accessor.get(IThreadHistoryService)
|
||||||
|
historyService.startNewThread()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// History menu button
|
||||||
|
registerAction2(class extends Action2 {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: 'void.historyAction',
|
||||||
|
title: 'View past chats',
|
||||||
|
icon: { id: 'history' },
|
||||||
|
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', VOID_VIEW_ID), }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async run(accessor: ServicesAccessor): Promise<void> {
|
||||||
|
const stateService = accessor.get(IVoidSidebarStateService)
|
||||||
|
stateService.setState({ isHistoryOpen: !stateService.state.isHistoryOpen, currentTab: 'chat' })
|
||||||
|
stateService.fireBlurChat()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Settings (API config) menu button
|
||||||
|
registerAction2(class extends Action2 {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: 'void.viewSettings',
|
||||||
|
title: 'Void settings',
|
||||||
|
icon: { id: 'settings-gear' },
|
||||||
|
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', VOID_VIEW_ID), }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async run(accessor: ServicesAccessor): Promise<void> {
|
||||||
|
const stateService = accessor.get(IVoidSidebarStateService)
|
||||||
|
stateService.setState({ isHistoryOpen: false, currentTab: 'settings' })
|
||||||
|
stateService.fireBlurChat()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -18,17 +18,14 @@ import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
|
||||||
|
|
||||||
|
|
||||||
import { IViewPaneOptions, ViewPane } from '../../../browser/parts/views/viewPane.js';
|
import { IViewPaneOptions, ViewPane } from '../../../browser/parts/views/viewPane.js';
|
||||||
import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
|
||||||
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
|
||||||
|
|
||||||
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
|
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
|
||||||
import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
|
|
||||||
import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||||
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
|
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
|
||||||
import { IViewsService } from '../../../services/views/common/viewsService.js';
|
import { IViewsService } from '../../../services/views/common/viewsService.js';
|
||||||
import { CodeStagingSelection, IThreadHistoryService } from './registerThreads.js';
|
import { IThreadHistoryService } from './registerThreads.js';
|
||||||
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
||||||
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
|
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
|
||||||
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
|
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
|
||||||
|
|
@ -44,8 +41,6 @@ import mountFn from './react/out/sidebar-tsx/Sidebar.js';
|
||||||
import { IVoidConfigStateService } from './registerConfig.js';
|
import { IVoidConfigStateService } from './registerConfig.js';
|
||||||
import { IFileService } from '../../../../platform/files/common/files.js';
|
import { IFileService } from '../../../../platform/files/common/files.js';
|
||||||
import { IInlineDiffsService } from './registerInlineDiffs.js';
|
import { IInlineDiffsService } from './registerInlineDiffs.js';
|
||||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
|
||||||
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
|
||||||
// import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
// import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -117,12 +112,12 @@ class VoidSidebarViewPane extends ViewPane {
|
||||||
|
|
||||||
// ---------- Register viewpane inside the void container ----------
|
// ---------- Register viewpane inside the void container ----------
|
||||||
|
|
||||||
const voidThemeIcon = Codicon.array;
|
const voidThemeIcon = Codicon.symbolObject;
|
||||||
const voidViewIcon = registerIcon('void-view-icon', voidThemeIcon, localize('voidViewIcon', 'View icon of the Void chat view.'));
|
const voidViewIcon = registerIcon('void-view-icon', voidThemeIcon, localize('voidViewIcon', 'View icon of the Void chat view.'));
|
||||||
|
|
||||||
// called VIEWLET_ID in other places for some reason
|
// called VIEWLET_ID in other places for some reason
|
||||||
const VOID_VIEW_CONTAINER_ID = 'workbench.view.void'
|
export const VOID_VIEW_CONTAINER_ID = 'workbench.view.void'
|
||||||
const SIDEBAR_VIEW_ID = VOID_VIEW_CONTAINER_ID // not sure if we can change this
|
export const VOID_VIEW_ID = VOID_VIEW_CONTAINER_ID // not sure if we can change this
|
||||||
|
|
||||||
// Register view container
|
// Register view container
|
||||||
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||||
|
|
@ -140,7 +135,7 @@ const viewContainer = viewContainerRegistry.registerViewContainer({
|
||||||
// Register search default location to the container (sidebar)
|
// Register search default location to the container (sidebar)
|
||||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
|
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
|
||||||
viewsRegistry.registerViews([{
|
viewsRegistry.registerViews([{
|
||||||
id: SIDEBAR_VIEW_ID,
|
id: VOID_VIEW_ID,
|
||||||
hideByDefault: false, // start open
|
hideByDefault: false, // start open
|
||||||
containerIcon: voidViewIcon,
|
containerIcon: voidViewIcon,
|
||||||
name: nls.localize2('void chat', "Chat"), // this says ... : CHAT
|
name: nls.localize2('void chat', "Chat"), // this says ... : CHAT
|
||||||
|
|
@ -214,7 +209,7 @@ class VoidSidebarStateService extends Disposable implements IVoidSidebarStateSer
|
||||||
|
|
||||||
openView() {
|
openView() {
|
||||||
this._viewsService.openViewContainer(VOID_VIEW_CONTAINER_ID);
|
this._viewsService.openViewContainer(VOID_VIEW_CONTAINER_ID);
|
||||||
this._viewsService.openView(SIDEBAR_VIEW_ID);
|
this._viewsService.openView(VOID_VIEW_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -236,104 +231,3 @@ class VoidSidebarStateService extends Disposable implements IVoidSidebarStateSer
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSingleton(IVoidSidebarStateService, VoidSidebarStateService, InstantiationType.Eager);
|
registerSingleton(IVoidSidebarStateService, VoidSidebarStateService, InstantiationType.Eager);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ---------- Register commands and keybindings ----------
|
|
||||||
|
|
||||||
// Action: when press ctrl+L, show the sidebar chat and add to the selection
|
|
||||||
registerAction2(class extends Action2 {
|
|
||||||
constructor() {
|
|
||||||
super({ id: 'void.ctrl+l', title: 'Show Sidebar', keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyL, weight: KeybindingWeight.BuiltinExtension } });
|
|
||||||
}
|
|
||||||
async run(accessor: ServicesAccessor): Promise<void> {
|
|
||||||
|
|
||||||
const model = accessor.get(ICodeEditorService).getActiveCodeEditor()?.getModel()
|
|
||||||
if (!model)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
const stateService = accessor.get(IVoidSidebarStateService)
|
|
||||||
stateService.setState({ isHistoryOpen: false, currentTab: 'chat' })
|
|
||||||
stateService.fireFocusChat()
|
|
||||||
|
|
||||||
// add selection
|
|
||||||
const threadHistoryService = accessor.get(IThreadHistoryService)
|
|
||||||
const currentStaging = threadHistoryService.state._currentStagingSelections
|
|
||||||
const currentStagingEltIdx = currentStaging?.findIndex(s => s.fileURI.fsPath === model.uri.fsPath)
|
|
||||||
|
|
||||||
// if there exists a selection with this URI, replace it
|
|
||||||
const selectionRange = accessor.get(IEditorService).activeTextEditorControl?.getSelection()
|
|
||||||
|
|
||||||
if (selectionRange) {
|
|
||||||
const selection: CodeStagingSelection = { selectionStr: model.getValueInRange(selectionRange), fileURI: model.uri }
|
|
||||||
|
|
||||||
if (currentStagingEltIdx !== undefined && currentStagingEltIdx !== -1) {
|
|
||||||
threadHistoryService.setStaging([
|
|
||||||
...currentStaging!.slice(0, currentStagingEltIdx),
|
|
||||||
selection,
|
|
||||||
...currentStaging!.slice(currentStagingEltIdx + 1, Infinity)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
threadHistoryService.setStaging([...(currentStaging ?? []), selection])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// New chat menu button
|
|
||||||
registerAction2(class extends Action2 {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
id: 'void.newChatAction',
|
|
||||||
title: 'View past chats',
|
|
||||||
icon: { id: 'add' },
|
|
||||||
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', SIDEBAR_VIEW_ID), }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async run(accessor: ServicesAccessor): Promise<void> {
|
|
||||||
const stateService = accessor.get(IVoidSidebarStateService)
|
|
||||||
stateService.setState({ isHistoryOpen: false, currentTab: 'chat' })
|
|
||||||
stateService.fireFocusChat()
|
|
||||||
|
|
||||||
const historyService = accessor.get(IThreadHistoryService)
|
|
||||||
historyService.startNewThread()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// History menu button
|
|
||||||
registerAction2(class extends Action2 {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
id: 'void.historyAction',
|
|
||||||
title: 'View past chats',
|
|
||||||
icon: { id: 'history' },
|
|
||||||
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', SIDEBAR_VIEW_ID), }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async run(accessor: ServicesAccessor): Promise<void> {
|
|
||||||
const stateService = accessor.get(IVoidSidebarStateService)
|
|
||||||
stateService.setState({ isHistoryOpen: !stateService.state.isHistoryOpen, currentTab: 'chat' })
|
|
||||||
stateService.fireBlurChat()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Settings (API config) menu button
|
|
||||||
registerAction2(class extends Action2 {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
id: 'void.viewSettings',
|
|
||||||
title: 'Void settings',
|
|
||||||
icon: { id: 'settings-gear' },
|
|
||||||
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', SIDEBAR_VIEW_ID), }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async run(accessor: ServicesAccessor): Promise<void> {
|
|
||||||
const stateService = accessor.get(IVoidSidebarStateService)
|
|
||||||
stateService.setState({ isHistoryOpen: false, currentTab: 'settings' })
|
|
||||||
stateService.fireBlurChat()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
|
|
||||||
|
// register keybinds
|
||||||
|
import './registerActions.js'
|
||||||
|
|
||||||
// register Settings
|
// register Settings
|
||||||
import './registerConfig.js'
|
import './registerConfig.js'
|
||||||
|
|
||||||
// register Sidebar chat
|
// register inline diffs
|
||||||
import './registerSidebar.js'
|
import './registerInlineDiffs.js'
|
||||||
|
|
||||||
// register Posthog metrics
|
// register Posthog metrics
|
||||||
import './registerMetrics.js'
|
import './registerMetrics.js'
|
||||||
|
|
||||||
|
// register Sidebar chat
|
||||||
|
import './registerSidebar.js'
|
||||||
|
|
||||||
// register Thread History
|
// register Thread History
|
||||||
import './registerThreads.js'
|
import './registerThreads.js'
|
||||||
|
|
||||||
// register inline diffs
|
|
||||||
import './registerInlineDiffs.js'
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue