diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index 6de2f47f..3c53d6f1 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -170,6 +170,9 @@ export const titleOfProviderName = (providerName: ProviderName) => { type DisplayInfo = { title: string, placeholder: string, + + helpfulUrl?: string, + urlPurpose?: string, } export const displayInfoOfSettingName = (providerName: ProviderName, settingName: SettingName): DisplayInfo => { if (settingName === 'apiKey') { @@ -182,6 +185,16 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName providerName === 'groq' ? 'gsk_key...' : providerName === 'openAICompatible' ? 'sk-key...' : '(never)', + + helpfulUrl: providerName === 'anthropic' ? 'https://console.anthropic.com/settings/keys' : + providerName === 'openAI' ? 'https://platform.openai.com/api-keys' : + providerName === 'openRouter' ? 'https://openrouter.ai/settings/keys' : + providerName === 'gemini' ? 'https://aistudio.google.com/apikey' : + providerName === 'groq' ? 'https://console.groq.com/keys' : + providerName === 'openAICompatible' ? undefined : + undefined, + + urlPurpose: 'to get your API key.', } } else if (settingName === 'endpoint') { @@ -189,9 +202,16 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName title: providerName === 'ollama' ? 'Your Ollama endpoint' : providerName === 'openAICompatible' ? 'baseURL' // (do not include /chat/completions) : '(never)', + placeholder: providerName === 'ollama' ? customProviderSettingsDefaults.ollama.endpoint : providerName === 'openAICompatible' ? 'https://my-website.com/v1' : '(never)', + + helpfulUrl: providerName === 'ollama' ? 'https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-expose-ollama-on-my-network' + : providerName === 'openAICompatible' ? undefined + : undefined, + + urlPurpose: 'for more information.', } } else if (settingName === 'enabled') { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts index db8ede5f..88c9cf34 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts @@ -4,82 +4,112 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from '../../../../nls.js'; -import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; -import { isMacintosh, isWeb, OS } from '../../../../base/common/platform.js'; +import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; import { IWorkspaceContextService, WorkbenchState } from '../../../../platform/workspace/common/workspace.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { append, clearNode, $, h } from '../../../../base/browser/dom.js'; import { KeybindingLabel } from '../../../../base/browser/ui/keybindingLabel/keybindingLabel.js'; -import { CommandsRegistry } from '../../../../platform/commands/common/commands.js'; -import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { defaultKeybindingLabelStyles } from '../../../../platform/theme/browser/defaultStyles.js'; import { editorForeground, registerColor, transparent } from '../../../../platform/theme/common/colorRegistry.js'; +import { IThemeService } from '../../../../platform/theme/common/themeService.js'; +import { ColorScheme } from '../../../../platform/theme/common/theme.js'; +import { isRecentFolder, IWorkspacesService } from '../../../../platform/workspaces/common/workspaces.js'; +// import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { ICommandService } from '../../../../platform/commands/common/commands.js'; +import { OpenFileFolderAction, OpenFolderAction } from '../../actions/workspaceActions.js'; +import { isMacintosh, isNative, OS } from '../../../../base/common/platform.js'; +import { VOID_CTRL_L_ACTION_ID } from '../../../contrib/void/browser/sidebarActions.js'; +import { VOID_CTRL_K_ACTION_ID } from '../../../contrib/void/browser/quickEditActions.js'; +import { defaultKeybindingLabelStyles } from '../../../../platform/theme/browser/defaultStyles.js'; +import { IWindowOpenable } from '../../../../platform/window/common/window.js'; +import { ILabelService, Verbosity } from '../../../../platform/label/common/label.js'; +import { splitRecentLabel } from '../../../../base/common/labels.js'; +import { IHostService } from '../../../services/host/browser/host.js'; +// import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; registerColor('editorWatermark.foreground', { dark: transparent(editorForeground, 0.6), light: transparent(editorForeground, 0.68), hcDark: editorForeground, hcLight: editorForeground }, localize('editorLineHighlight', 'Foreground color for the labels in the editor watermark.')); -interface WatermarkEntry { - readonly text: string; - readonly id: string; - readonly mac?: boolean; - readonly when?: ContextKeyExpression; -} +// interface WatermarkEntry { +// readonly text: string; +// readonly id: string; +// readonly mac?: boolean; +// readonly when?: ContextKeyExpression; +// } -const showCommands: WatermarkEntry = { text: localize('watermark.showCommands', "Show All Commands"), id: 'workbench.action.showCommands' }; -const quickAccess: WatermarkEntry = { text: localize('watermark.quickAccess', "Go to File"), id: 'workbench.action.quickOpen' }; -const openFileNonMacOnly: WatermarkEntry = { text: localize('watermark.openFile', "Open File"), id: 'workbench.action.files.openFile', mac: false }; -const openFolderNonMacOnly: WatermarkEntry = { text: localize('watermark.openFolder', "Open Folder"), id: 'workbench.action.files.openFolder', mac: false }; -const openFileOrFolderMacOnly: WatermarkEntry = { text: localize('watermark.openFileFolder', "Open File or Folder"), id: 'workbench.action.files.openFileFolder', mac: true }; -const openRecent: WatermarkEntry = { text: localize('watermark.openRecent', "Open Recent"), id: 'workbench.action.openRecent' }; -const newUntitledFileMacOnly: WatermarkEntry = { text: localize('watermark.newUntitledFile', "New Untitled Text File"), id: 'workbench.action.files.newUntitledFile', mac: true }; -const findInFiles: WatermarkEntry = { text: localize('watermark.findInFiles', "Find in Files"), id: 'workbench.action.findInFiles' }; -const toggleTerminal: WatermarkEntry = { text: localize({ key: 'watermark.toggleTerminal', comment: ['toggle is a verb here'] }, "Toggle Terminal"), id: 'workbench.action.terminal.toggleTerminal', when: ContextKeyExpr.equals('terminalProcessSupported', true) }; -const startDebugging: WatermarkEntry = { text: localize('watermark.startDebugging', "Start Debugging"), id: 'workbench.action.debug.start', when: ContextKeyExpr.equals('terminalProcessSupported', true) }; -const toggleFullscreen: WatermarkEntry = { text: localize({ key: 'watermark.toggleFullscreen', comment: ['toggle is a verb here'] }, "Toggle Full Screen"), id: 'workbench.action.toggleFullScreen' }; -const showSettings: WatermarkEntry = { text: localize('watermark.showSettings', "Show Settings"), id: 'workbench.action.openSettings' }; +// const showCommands: WatermarkEntry = { text: localize('watermark.showCommands', "Show All Commands"), id: 'workbench.action.showCommands' }; +// const quickAccess: WatermarkEntry = { text: localize('watermark.quickAccess', "Go to File"), id: 'workbench.action.quickOpen' }; +// const openFileNonMacOnly: WatermarkEntry = { text: localize('watermark.openFile', "Open File"), id: 'workbench.action.files.openFile', mac: false }; +// const openFolderNonMacOnly: WatermarkEntry = { text: localize('watermark.openFolder', "Open Folder"), id: 'workbench.action.files.openFolder', mac: false }; +// const openFileOrFolderMacOnly: WatermarkEntry = { text: localize('watermark.openFileFolder', "Open File or Folder"), id: 'workbench.action.files.openFileFolder', mac: true }; +// const openRecent: WatermarkEntry = { text: localize('watermark.openRecent', "Open Recent"), id: 'workbench.action.openRecent' }; +// const newUntitledFileMacOnly: WatermarkEntry = { text: localize('watermark.newUntitledFile', "New Untitled Text File"), id: 'workbench.action.files.newUntitledFile', mac: true }; +// const findInFiles: WatermarkEntry = { text: localize('watermark.findInFiles', "Find in Files"), id: 'workbench.action.findInFiles' }; +// const toggleTerminal: WatermarkEntry = { text: localize({ key: 'watermark.toggleTerminal', comment: ['toggle is a verb here'] }, "Toggle Terminal"), id: 'workbench.action.terminal.toggleTerminal', when: ContextKeyExpr.equals('terminalProcessSupported', true) }; +// const startDebugging: WatermarkEntry = { text: localize('watermark.startDebugging', "Start Debugging"), id: 'workbench.action.debug.start', when: ContextKeyExpr.equals('terminalProcessSupported', true) }; +// const toggleFullscreen: WatermarkEntry = { text: localize({ key: 'watermark.toggleFullscreen', comment: ['toggle is a verb here'] }, "Toggle Full Screen"), id: 'workbench.action.toggleFullScreen' }; +// const showSettings: WatermarkEntry = { text: localize('watermark.showSettings', "Show Settings"), id: 'workbench.action.openSettings' }; -const noFolderEntries = [ - showCommands, - openFileNonMacOnly, - openFolderNonMacOnly, - openFileOrFolderMacOnly, - openRecent, - newUntitledFileMacOnly -]; +// // shown when Void is emtpty +// const noFolderEntries = [ +// // showCommands, +// openFileNonMacOnly, +// openFolderNonMacOnly, +// openFileOrFolderMacOnly, +// openRecent, +// // newUntitledFileMacOnly +// ]; -const folderEntries = [ - showCommands, - quickAccess, - findInFiles, - startDebugging, - toggleTerminal, - toggleFullscreen, - showSettings -]; +// const folderEntries = [ +// showCommands, +// // quickAccess, +// // findInFiles, +// // startDebugging, +// // toggleTerminal, +// // toggleFullscreen, +// // showSettings +// ]; export class EditorGroupWatermark extends Disposable { private readonly shortcuts: HTMLElement; private readonly transientDisposables = this._register(new DisposableStore()); - private enabled: boolean = false; + // private enabled: boolean = false; private workbenchState: WorkbenchState; - private keybindingLabels = new Set(); + private currentDisposables = new Set(); constructor( container: HTMLElement, @IKeybindingService private readonly keybindingService: IKeybindingService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IConfigurationService private readonly configurationService: IConfigurationService + // @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IThemeService private readonly themeService: IThemeService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, + @ICommandService private readonly commandService: ICommandService, + @IHostService private readonly hostService: IHostService, + @ILabelService private readonly labelService: ILabelService, ) { super(); const elements = h('.editor-group-watermark', [ - h('.letterpress'), + h('.letterpress@icon'), h('.shortcuts@shortcuts'), ]); append(container, elements.root); - this.shortcuts = elements.shortcuts; + this.shortcuts = elements.shortcuts; // shortcuts div is modified on render() + + // void icon style + const updateTheme = () => { + const theme = this.themeService.getColorTheme().type + const isDark = theme === ColorScheme.DARK || theme === ColorScheme.HIGH_CONTRAST_DARK + elements.icon.style.maxWidth = '220px' + elements.icon.style.opacity = '50%' + elements.icon.style.filter = isDark ? 'brightness(.5)' : 'invert(1)' + } + updateTheme() + this._register( + this.themeService.onDidColorThemeChange(updateTheme) + ) this.registerListeners(); @@ -103,56 +133,164 @@ export class EditorGroupWatermark extends Disposable { this.render(); })); - const allEntriesWhenClauses = [...noFolderEntries, ...folderEntries].filter(entry => entry.when !== undefined).map(entry => entry.when!); - const allKeys = new Set(); - allEntriesWhenClauses.forEach(when => when.keys().forEach(key => allKeys.add(key))); - this._register(this.contextKeyService.onDidChangeContext(e => { - if (e.affectsSome(allKeys)) { - this.render(); - } - })); + // const allEntriesWhenClauses = [...noFolderEntries, ...folderEntries].filter(entry => entry.when !== undefined).map(entry => entry.when!); + // const allKeys = new Set(); + // allEntriesWhenClauses.forEach(when => when.keys().forEach(key => allKeys.add(key))); + // this._register(this.contextKeyService.onDidChangeContext(e => { + // if (e.affectsSome(allKeys)) { + // this.render(); + // } + // })); } + + private render(): void { - const enabled = this.configurationService.getValue('workbench.tips.enabled'); + // const enabled = this.configurationService.getValue('workbench.tips.enabled'); - if (enabled === this.enabled) { - return; - } + // if (enabled === this.enabled) { + // return; + // } + + // this.enabled = enabled; + + + // if (!enabled) { + // return; + // } + + // const hasFolder = this.workbenchState !== WorkbenchState.EMPTY; + // const selected = (hasFolder ? folderEntries : noFolderEntries) + // .filter(entry => !('when' in entry) || this.contextKeyService.contextMatchesRules(entry.when)) + // .filter(entry => !('mac' in entry) || entry.mac === (isMacintosh && !isWeb)) + // .filter(entry => !!CommandsRegistry.getCommand(entry.id)) + // .filter(entry => !!this.keybindingService.lookupKeybinding(entry.id)); - this.enabled = enabled; this.clear(); - - if (!enabled) { - return; - } - const box = append(this.shortcuts, $('.watermark-box')); - const folder = this.workbenchState !== WorkbenchState.EMPTY; - const selected = (folder ? folderEntries : noFolderEntries) - .filter(entry => !('when' in entry) || this.contextKeyService.contextMatchesRules(entry.when)) - .filter(entry => !('mac' in entry) || entry.mac === (isMacintosh && !isWeb)) - .filter(entry => !!CommandsRegistry.getCommand(entry.id)) - .filter(entry => !!this.keybindingService.lookupKeybinding(entry.id)); + const boxBelow = append(this.shortcuts, $('')) + + + const update = async () => { - const update = () => { clearNode(box); - this.keybindingLabels.forEach(label => label.dispose()); - this.keybindingLabels.clear(); + clearNode(boxBelow); - for (const entry of selected) { - const keys = this.keybindingService.lookupKeybinding(entry.id); - if (!keys) { - continue; + this.currentDisposables.forEach(label => label.dispose()); + this.currentDisposables.clear(); + + + // Void - if the workbench is empty, show open + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + + // Open Folder + const button = h('button') + button.root.textContent = 'Open Folder' + button.root.onclick = () => { + this.commandService.executeCommand(isMacintosh && isNative ? OpenFileFolderAction.ID : OpenFolderAction.ID) + // if (this.contextKeyService.contextMatchesRules(ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace')))) { + // this.commandService.executeCommand(OpenFolderViaWorkspaceAction.ID); + // } else { + // this.commandService.executeCommand(isMacintosh ? 'workbench.action.files.openFileFolder' : 'workbench.action.files.openFolder'); + // } } + box.appendChild(button.root); + + // Recents + const recentlyOpened = await this.workspacesService.getRecentlyOpened() + .catch(() => ({ files: [], workspaces: [] })).then(w => w.workspaces); + + + + box.append( + ...recentlyOpened.map(w => { + + let fullPath: string; + let windowOpenable: IWindowOpenable; + if (isRecentFolder(w)) { + windowOpenable = { folderUri: w.folderUri }; + fullPath = w.label || this.labelService.getWorkspaceLabel(w.folderUri, { verbose: Verbosity.LONG }); + } + else { + return null + // fullPath = w.label || this.labelService.getWorkspaceLabel(w.workspace, { verbose: Verbosity.LONG }); + // windowOpenable = { workspaceUri: w.workspace.configPath }; + } + + + + const { name, parentPath } = splitRecentLabel(fullPath); + + const li = $('li'); + const link = $('button.button-link'); + + link.innerText = name; + link.title = fullPath; + link.setAttribute('aria-label', localize('welcomePage.openFolderWithPath', "Open folder {0} with path {1}", name, parentPath)); + link.addEventListener('click', e => { + this.hostService.openWindow([windowOpenable], { + forceNewWindow: e.ctrlKey || e.metaKey, + remoteAuthority: w.remoteAuthority || null // local window if remoteAuthority is not set or can not be deducted from the openable + }); + e.preventDefault(); + e.stopPropagation(); + }); + li.appendChild(link); + + const span = $('span'); + span.classList.add('path'); + span.classList.add('detail'); + span.innerText = parentPath; + span.title = fullPath; + li.appendChild(span); + + + return li + }).filter(v => !!v) + ) + + + + } + else { + + // show them Void keybindings + const keys = this.keybindingService.lookupKeybinding(VOID_CTRL_L_ACTION_ID); const dl = append(box, $('dl')); const dt = append(dl, $('dt')); - dt.textContent = entry.text; + dt.textContent = 'Chat' const dd = append(dl, $('dd')); const label = new KeybindingLabel(dd, OS, { renderUnboundKeybindings: true, ...defaultKeybindingLabelStyles }); - label.set(keys); - this.keybindingLabels.add(label); + if (keys) + label.set(keys); + this.currentDisposables.add(label); + + + const keys2 = this.keybindingService.lookupKeybinding(VOID_CTRL_K_ACTION_ID); + const dl2 = append(box, $('dl')); + const dt2 = append(dl2, $('dt')); + dt2.textContent = 'Quick Edit' + const dd2 = append(dl2, $('dd')); + const label2 = new KeybindingLabel(dd2, OS, { renderUnboundKeybindings: true, ...defaultKeybindingLabelStyles }); + if (keys2) + label2.set(keys2); + this.currentDisposables.add(label2); + + const keys3 = this.keybindingService.lookupKeybinding('workbench.action.openGlobalKeybindings'); + const button3 = append(boxBelow, $('button')); + button3.textContent = 'Change Keybindings' + const label3 = new KeybindingLabel(button3, OS, { renderUnboundKeybindings: true, ...defaultKeybindingLabelStyles }); + if (keys3) + label3.set(keys3); + button3.onclick = () => { + this.commandService.executeCommand('workbench.action.openGlobalKeybindings') + } + this.currentDisposables.add(label3); + + + } + }; update(); @@ -167,6 +305,6 @@ export class EditorGroupWatermark extends Disposable { override dispose(): void { super.dispose(); this.clear(); - this.keybindingLabels.forEach(label => label.dispose()); + this.currentDisposables.forEach(label => label.dispose()); } } diff --git a/src/vs/workbench/browser/parts/editor/media/editorgroupview.css b/src/vs/workbench/browser/parts/editor/media/editorgroupview.css index 76c8a561..726a39c9 100644 --- a/src/vs/workbench/browser/parts/editor/media/editorgroupview.css +++ b/src/vs/workbench/browser/parts/editor/media/editorgroupview.css @@ -9,13 +9,15 @@ height: 100%; } -.monaco-workbench .part.editor > .content .editor-group-container.empty { - opacity: 0.5; /* dimmed to indicate inactive state */ +.monaco-workbench .part.editor > .content .editor-group-container.empty { + opacity: 0.5; + /* dimmed to indicate inactive state */ } .monaco-workbench .part.editor > .content .editor-group-container.empty.active, .monaco-workbench .part.editor > .content .editor-group-container.empty.dragged-over { - opacity: 1; /* indicate active/dragged-over group through undimmed state */ + opacity: 1; + /* indicate active/dragged-over group through undimmed state */ } .monaco-workbench .part.editor > .content:not(.empty) .editor-group-container.empty.active:focus { @@ -24,12 +26,13 @@ } .monaco-workbench .part.editor > .content.empty .editor-group-container.empty.active:focus { - outline: none; /* never show outline for empty group if it is the last */ + outline: none; + /* never show outline for empty group if it is the last */ } /* Watermark & shortcuts */ -.monaco-workbench .part.editor > .content .editor-group-container > .editor-group-watermark { +.monaco-workbench .part.editor > .content .editor-group-container > .editor-group-watermark { display: flex; height: 100%; max-width: 290px; @@ -49,26 +52,27 @@ height: calc(100% - 70px); } +/* light */ .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-watermark > .letterpress { width: 100%; max-height: 100%; aspect-ratio: 1/1; - background-image: url('./letterpress-light.svg'); + background-image: url('./void_cube_noshadow.png'); background-size: contain; background-position-x: center; background-repeat: no-repeat; } .monaco-workbench.vs-dark .part.editor > .content .editor-group-container .editor-group-watermark > .letterpress { - background-image: url('./letterpress-dark.svg'); + background-image: url('./void_cube_noshadow.png'); } .monaco-workbench.hc-light .part.editor > .content .editor-group-container .editor-group-watermark > .letterpress { - background-image: url('./letterpress-hcLight.svg'); + background-image: url('./void_cube_noshadow.png'); } .monaco-workbench.hc-black .part.editor > .content .editor-group-container .editor-group-watermark > .letterpress { - background-image: url('./letterpress-hcDark.svg'); + background-image: url('./void_cube_noshadow.png'); } .monaco-workbench .part.editor > .content:not(.empty) .editor-group-container > .editor-group-watermark > .shortcuts, @@ -109,12 +113,13 @@ .monaco-workbench .part.editor > .content .editor-group-container > .title { position: relative; - box-sizing: border-box; + box-sizing: border-box; overflow: hidden; } .monaco-workbench .part.editor > .content .editor-group-container > .title:not(.tabs) { - display: flex; /* when tabs are not shown, use flex layout */ + display: flex; + /* when tabs are not shown, use flex layout */ flex-wrap: nowrap; } @@ -144,7 +149,8 @@ .monaco-workbench .part.editor > .content .editor-group-container.empty.locked > .editor-group-container-toolbar, .monaco-workbench .part.editor > .content:not(.empty) .editor-group-container.empty > .editor-group-container-toolbar, .monaco-workbench .part.editor > .content.auxiliary .editor-group-container.empty > .editor-group-container-toolbar { - display: block; /* show toolbar when more than one editor group or always when auxiliary or locked */ + display: block; + /* show toolbar when more than one editor group or always when auxiliary or locked */ } .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .actions-container { @@ -157,7 +163,7 @@ /* Editor */ -.monaco-workbench .part.editor > .content .editor-group-container.empty > .editor-container { +.monaco-workbench .part.editor > .content .editor-group-container.empty > .editor-container { display: none; } diff --git a/src/vs/workbench/browser/parts/editor/media/slice_of_void.png b/src/vs/workbench/browser/parts/editor/media/slice_of_void.png new file mode 100644 index 00000000..3b2c5319 Binary files /dev/null and b/src/vs/workbench/browser/parts/editor/media/slice_of_void.png differ diff --git a/src/vs/workbench/browser/parts/editor/media/void_cube_noshadow.png b/src/vs/workbench/browser/parts/editor/media/void_cube_noshadow.png new file mode 100644 index 00000000..225179f8 Binary files /dev/null and b/src/vs/workbench/browser/parts/editor/media/void_cube_noshadow.png differ diff --git a/src/vs/workbench/contrib/void/browser/quickEditActions.ts b/src/vs/workbench/contrib/void/browser/quickEditActions.ts new file mode 100644 index 00000000..fcef7270 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/quickEditActions.ts @@ -0,0 +1,28 @@ +import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; +import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; +import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; +import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; +import { IMetricsService } from '../../../../platform/void/common/metricsService.js'; + + +export const VOID_CTRL_K_ACTION_ID = 'void.ctrlKAction' +registerAction2(class extends Action2 { + constructor() { + super({ id: VOID_CTRL_K_ACTION_ID, title: 'Void: Quick Edit', keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyK, weight: KeybindingWeight.BuiltinExtension } }); + } + async run(accessor: ServicesAccessor): Promise { + console.log('hello111!') + + const model = accessor.get(ICodeEditorService).getActiveCodeEditor()?.getModel() + if (!model) + return + + console.log('hello!') + + const metricsService = accessor.get(IMetricsService) + metricsService.capture('User Action', { type: 'Ctrl+K' }) + + console.log('bye!') + } +}); diff --git a/src/vs/workbench/contrib/void/browser/react/src/styles.css b/src/vs/workbench/contrib/void/browser/react/src/styles.css index 9e0d47e7..2ceabda6 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/styles.css +++ b/src/vs/workbench/contrib/void/browser/react/src/styles.css @@ -8,6 +8,15 @@ @tailwind utilities; +@layer components { + .select-ellipsis select { + text-overflow: ellipsis; + white-space: nowrap; + padding-right: 24px; + } +} + + /* html { font-size: var(--vscode-font-size); } diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx index 504b88d2..70be6772 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx @@ -9,8 +9,6 @@ import { IInputBoxStyles, InputBox } from '../../../../../../../base/browser/ui/ import { defaultInputBoxStyles, defaultSelectBoxStyles } from '../../../../../../../platform/theme/browser/defaultStyles.js'; import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'; import { IDisposable } from '../../../../../../../base/common/lifecycle.js'; -import { DomScrollableElement } from '../../../../../../../base/browser/ui/scrollbar/scrollableElement.js'; -import { ScrollableElementCreationOptions } from '../../../../../../../base/browser/ui/scrollbar/scrollableElementOptions.js'; @@ -106,7 +104,7 @@ export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectB let containerRef = useRef(null); return { containerRef.current = container diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx index d9c34da9..943b7bb8 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx @@ -146,38 +146,39 @@ export const ModelDump = () => { const ProviderSetting = ({ providerName, settingName }: { providerName: ProviderName, settingName: SettingName }) => { - const { title, placeholder } = displayInfoOfSettingName(providerName, settingName) + const { title, placeholder, } = displayInfoOfSettingName(providerName, settingName) const voidSettingsService = useService('settingsStateService') let weChangedTextRef = false - return <> - - { - if (weChangedTextRef) return - voidSettingsService.setSettingOfProvider(providerName, settingName, newVal) - }, [voidSettingsService, providerName, settingName])} + return +
+ { + if (weChangedTextRef) return + voidSettingsService.setSettingOfProvider(providerName, settingName, newVal) + }, [voidSettingsService, providerName, settingName])} - // we are responsible for setting the initial value. always sync the instance whenever there's a change to state. - onCreateInstance={useCallback((instance: InputBox) => { - const syncInstance = () => { - const settingsAtProvider = voidSettingsService.state.settingsOfProvider[providerName]; - const stateVal = settingsAtProvider[settingName as SettingName] - // console.log('SYNCING TO', providerName, settingName, stateVal) - weChangedTextRef = true - instance.value = stateVal as string - weChangedTextRef = false - } - syncInstance() - const disposable = voidSettingsService.onDidChangeState(syncInstance) - return [disposable] - }, [voidSettingsService, providerName, settingName])} - multiline={false} - /> - + // we are responsible for setting the initial value. always sync the instance whenever there's a change to state. + onCreateInstance={useCallback((instance: InputBox) => { + const syncInstance = () => { + const settingsAtProvider = voidSettingsService.state.settingsOfProvider[providerName]; + const stateVal = settingsAtProvider[settingName as SettingName] + // console.log('SYNCING TO', providerName, settingName, stateVal) + weChangedTextRef = true + instance.value = stateVal as string + weChangedTextRef = false + } + syncInstance() + const disposable = voidSettingsService.onDidChangeState(syncInstance) + return [disposable] + }, [voidSettingsService, providerName, settingName])} + multiline={false} + /> +
+
} @@ -255,6 +256,7 @@ export const Settings = () => {
+

Providers

diff --git a/src/vs/workbench/contrib/void/browser/sidebarActions.ts b/src/vs/workbench/contrib/void/browser/sidebarActions.ts index e44fc864..7f61c729 100644 --- a/src/vs/workbench/contrib/void/browser/sidebarActions.ts +++ b/src/vs/workbench/contrib/void/browser/sidebarActions.ts @@ -53,9 +53,10 @@ const getContentInRange = (model: ITextModel, range: IRange | null) => { } // Action: when press ctrl+L, show the sidebar chat and add to the selection +export const VOID_CTRL_L_ACTION_ID = 'void.ctrlLAction' registerAction2(class extends Action2 { constructor() { - super({ id: 'void.ctrl+l', title: 'Show Sidebar', keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyL, weight: KeybindingWeight.BuiltinExtension } }); + super({ id: VOID_CTRL_L_ACTION_ID, title: 'Void: Show Sidebar', keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyL, weight: KeybindingWeight.BuiltinExtension } }); } async run(accessor: ServicesAccessor): Promise { @@ -66,7 +67,7 @@ registerAction2(class extends Action2 { const stateService = accessor.get(ISidebarStateService) const metricsService = accessor.get(IMetricsService) - metricsService.capture('Chat Navigation', { type: 'Ctrl+L' }) + metricsService.capture('User Action', { type: 'Ctrl+L' }) stateService.setState({ isHistoryOpen: false, currentTab: 'chat' }) stateService.fireFocusChat() diff --git a/src/vs/workbench/contrib/void/browser/void.contribution.ts b/src/vs/workbench/contrib/void/browser/void.contribution.ts index a67594a7..c8dd051a 100644 --- a/src/vs/workbench/contrib/void/browser/void.contribution.ts +++ b/src/vs/workbench/contrib/void/browser/void.contribution.ts @@ -7,11 +7,14 @@ // register inline diffs import './inlineDiffsService.js' -// register Sidebar pane, state, actions (keybinds, menus) +// register Sidebar pane, state, actions (keybinds, menus) (Ctrl+L) import './sidebarActions.js' import './sidebarPane.js' import './sidebarStateService.js' +// register quick edit (Ctrl+K) +import './quickEditActions.js' + // register Thread History import './threadHistoryService.js'