From a72305819a1b028bdf34ad6b08e1eccdc41ae4ff Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 2 Jan 2025 19:15:08 -0800 Subject: [PATCH 001/111] copy --- src/vs/workbench/contrib/void/browser/inlineDiffsService.ts | 1 - .../void/browser/react/src/void-settings-tsx/Settings.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index 5ccb08ec..ee4b4ef2 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -822,7 +822,6 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { const lastDiff = computedDiffs.pop() if (!lastDiff) { - console.log('!lastDiff') // if the writing is identical so far, display no changes originalCodeStartLine = 1 newCodeEndLine = 1 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 a4835e99..f7af5b15 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 @@ -420,7 +420,7 @@ export const Settings = () => {

Local Providers

{/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} {/*

{`Instructions:`}

*/} -

{`Void can access any model that you host locally. By default, we automatically detect your local models.`}

+

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

From 2519f094cc607ad5bd282fdde21c7ebd79311744 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Fri, 3 Jan 2025 00:00:01 -0800 Subject: [PATCH 002/111] input and dropdown styles --- .../browser/react/src/markdown/BlockCode.tsx | 2 +- .../react/src/markdown/ChatMarkdownRender.tsx | 6 ++-- .../browser/react/src/sidebar-tsx/Sidebar.tsx | 9 +++++- .../react/src/sidebar-tsx/SidebarChat.tsx | 10 +++---- .../void/browser/react/src/util/inputs.tsx | 11 +++++-- .../void/browser/react/tailwind.config.js | 30 +++++++++++++++++-- 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx index e64c43c3..dd095451 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx @@ -69,7 +69,7 @@ export const BlockCode = ({ text, buttonsOnHover, language }: { text: string, bu const isSingleLine = !text.includes('\n') return (<> -
+
{buttonsOnHover === null ? null : (
{buttonsOnHover}
diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx index ef5221f7..12656acb 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx @@ -49,14 +49,14 @@ const CodeButtonsOnHover = ({ text }: { text: string }) => { return <> @@ -202,7 +202,7 @@ export const ModelDump = () => { > {/* left part is width:full */}
- {isNewProviderName ? displayInfoOfProviderName(providerName).title : ''} + {isNewProviderName ? displayInfoOfProviderName(providerName).title : ''} {modelName} {/* {`${modelName} (${providerName})`} */}
@@ -431,7 +431,7 @@ export const Settings = () => {

-

+

{/* TODO we should create UI for downloading models without user going into terminal */}
diff --git a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js index d339138a..5f29d06f 100644 --- a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js +++ b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js @@ -34,6 +34,7 @@ module.exports = { "void-fg-1": "var(--vscode-editor-foreground)", "void-fg-2": "var(--vscode-input-foreground)", "void-fg-3": "var(--vscode-input-placeholderForeground)", + "void-warning": "var(--vscode-charts-orange)", vscode: { From 55ec3365a209afd42592bf3c02edde92672adda5 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Sun, 5 Jan 2025 17:04:05 -0800 Subject: [PATCH 010/111] empty seln --- src/vs/workbench/contrib/void/browser/sidebarActions.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/contrib/void/browser/sidebarActions.ts b/src/vs/workbench/contrib/void/browser/sidebarActions.ts index be76d2aa..69508e18 100644 --- a/src/vs/workbench/contrib/void/browser/sidebarActions.ts +++ b/src/vs/workbench/contrib/void/browser/sidebarActions.ts @@ -29,6 +29,11 @@ import { VOID_OPEN_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; const roundRangeToLines = (range: IRange | null | undefined) => { if (!range) return null + + // treat as no selection if selection is empty + if (range.endColumn === range.startColumn && range.endLineNumber === range.startLineNumber) + return null + // IRange is 1-indexed const endLine = range.endColumn === 1 ? 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 = { From b9e61bf4e2a3594827547e05edc35466de6287c8 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Sun, 5 Jan 2025 17:10:18 -0800 Subject: [PATCH 011/111] styles --- .../react/src/void-settings-tsx/Settings.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 279b1a22..fa27d55a 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 @@ -14,11 +14,11 @@ import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { - return
+ return
- + {text}
@@ -422,14 +422,14 @@ export const Settings = () => {

Local Providers

- {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} - {/*

{`Instructions:`}

*/} - {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} -

{`Host a model locally and use it in Void. Instructions:`}

+ {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} + {/*

{`Instructions:`}

*/} + {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} +

{`Host a model locally and use it in Void. Instructions:`}

-

+

{/* TODO we should create UI for downloading models without user going into terminal */} @@ -440,8 +440,8 @@ export const Settings = () => {

More Providers

-

{`Get access to frontier models. We recommend Anthropic or OpenAI.`}

- {/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} +

{`Get access to frontier models. We recommend Anthropic or OpenAI.`}

+ {/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} From 35091eb8f227bfb14b6336c5fc9df368054cc61c Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Sun, 5 Jan 2025 17:11:10 -0800 Subject: [PATCH 012/111] change wording --- .../void/browser/react/src/void-settings-tsx/ModelDropdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index fb9389c7..d0cd41b4 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -97,7 +97,7 @@ const DummySelectBox = () => { size={14} className='mr-1 brightness-90' /> - Model required + Provider required
// return Date: Sun, 5 Jan 2025 18:03:36 -0800 Subject: [PATCH 013/111] ctrlK --- .../void/browser/inlineDiffsService.ts | 2 +- .../contrib/void/browser/prompt/prompts.ts | 8 +-- .../QuickEdit.tsx} | 6 +- .../QuickEditChat.tsx} | 17 ++++- .../{ctrl-k-tsx => quick-edit-tsx}/index.tsx | 4 +- .../contrib/void/browser/react/tsup.config.js | 2 +- .../contrib/void/browser/sidebarActions.ts | 66 +++++++++---------- 7 files changed, 58 insertions(+), 47 deletions(-) rename src/vs/workbench/contrib/void/browser/react/src/{ctrl-k-tsx/CtrlK.tsx => quick-edit-tsx/QuickEdit.tsx} (83%) rename src/vs/workbench/contrib/void/browser/react/src/{ctrl-k-tsx/CtrlKChat.tsx => quick-edit-tsx/QuickEditChat.tsx} (91%) rename src/vs/workbench/contrib/void/browser/react/src/{ctrl-k-tsx => quick-edit-tsx}/index.tsx (79%) diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index ee4b4ef2..a7db6e6c 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -31,7 +31,7 @@ import { ctrlKStream_prefixAndSuffix, ctrlKStream_prompt, ctrlKStream_systemMess import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; import { IPosition } from '../../../../editor/common/core/position.js'; -import { mountCtrlK } from '../browser/react/out/ctrl-k-tsx/index.js' +import { mountCtrlK } from '../browser/react/out/quick-edit-tsx/index.js' import { QuickEditPropsType } from './quickEditActions.js'; import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js'; import { LLMMessage } from '../../../../platform/void/common/llmMessageTypes.js'; diff --git a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts index be1f0f6c..f65bfcbe 100644 --- a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts +++ b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts @@ -361,10 +361,10 @@ Note that the SELECTION has code that comes before it. This code is indicated wi Note also that the SELECTION has code that comes after it. This code is indicated with <${sufTag}>...after<${sufTag}/>. Instructions: -1. Your OUTPUT should be a SINGLE PIECE OF CODE of the form <${midTag}>...new_selection<${midTag}/> -2. You may ONLY CHANGE the original SELECTION, and NOT the content in the <${preTag}>...<${preTag}/> or <${sufTag}>...<${sufTag}/> tags -3. Make sure all brackets in the new selection are balanced the same as in the original selection -4. Be careful not to duplicate or remove variables, comments, or other syntax by mistake +1. Your OUTPUT should be a SINGLE PIECE OF CODE of the form <${midTag}>...new_selection<${midTag}/>. Do not give any explanation before or after this. ONLY output this format, nothing more. +2. You may ONLY CHANGE the original SELECTION, and NOT the content in the <${preTag}>...<${preTag}/> or <${sufTag}>...<${sufTag}/> tags. +3. Make sure all brackets in the new selection are balanced the same as in the original selection. +4. Be careful not to duplicate or remove variables, comments, or other syntax by mistake. Complete the following: <${preTag}>${prefix} diff --git a/src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/CtrlK.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEdit.tsx similarity index 83% rename from src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/CtrlK.tsx rename to src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEdit.tsx index f10557fe..d17574f2 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/CtrlK.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEdit.tsx @@ -6,16 +6,16 @@ import { useEffect, useState } from 'react' import { useIsDark, useSidebarState } from '../util/services.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' -import { CtrlKChat } from './CtrlKChat.js' +import { QuickEditChat } from './QuickEditChat.js' import { QuickEditPropsType } from '../../../quickEditActions.js' -export const CtrlK = (props: QuickEditPropsType) => { +export const QuickEdit = (props: QuickEditPropsType) => { const isDark = useIsDark() return
- +
diff --git a/src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/CtrlKChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx similarity index 91% rename from src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/CtrlKChat.tsx rename to src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 6f4ff7c0..6925079d 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/CtrlKChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -14,13 +14,14 @@ import { ButtonStop, ButtonSubmit } from '../sidebar-tsx/SidebarChat.js'; import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js'; import { X } from 'lucide-react'; -export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChangeHeight, initText }: QuickEditPropsType) => { +export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChangeHeight, initText }: QuickEditPropsType) => { const accessor = useAccessor() const inlineDiffsService = accessor.get('IInlineDiffsService') const sizerRef = useRef(null) const inputBoxRef: React.MutableRefObject = useRef(null); + useEffect(() => { const inputContainer = sizerRef.current if (!inputContainer) return; @@ -67,6 +68,10 @@ export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChang }, [inlineDiffsService]) + const onX = useCallback(() => { + inlineDiffsService.removeCtrlKZone({ diffareaid }) + }, [inlineDiffsService, diffareaid]) + // sync init value const alreadySetRef = useRef(false) useEffect(() => { @@ -116,9 +121,9 @@ export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChang @@[&_div.monaco-inputbox]:!void-outline-none`} >
-
+
{ inlineDiffsService.removeCtrlKZone({ diffareaid }) }} + onClick={onX} />
@@ -132,6 +137,12 @@ export const CtrlKChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChang onChangeText={onChangeText} onCreateInstance={useCallback((instance: InputBox) => { inputBoxRef.current = instance; + + // if presses the esc key, X + instance.element.addEventListener('keydown', (e) => { + if (e.key === 'Escape') + onX() + }) onGetInputBox(instance); instance.focus() }, [onGetInputBox])} diff --git a/src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/index.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/index.tsx similarity index 79% rename from src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/index.tsx rename to src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/index.tsx index 4d59dbca..c3553893 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/ctrl-k-tsx/index.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/index.tsx @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { mountFnGenerator } from '../util/mountFnGenerator.js' -import { CtrlK } from './CtrlK.js' +import { QuickEdit } from './QuickEdit.js' -export const mountCtrlK = mountFnGenerator(CtrlK) +export const mountCtrlK = mountFnGenerator(QuickEdit) diff --git a/src/vs/workbench/contrib/void/browser/react/tsup.config.js b/src/vs/workbench/contrib/void/browser/react/tsup.config.js index 2a7547a0..9070f8e1 100644 --- a/src/vs/workbench/contrib/void/browser/react/tsup.config.js +++ b/src/vs/workbench/contrib/void/browser/react/tsup.config.js @@ -9,7 +9,7 @@ export default defineConfig({ entry: [ './src2/sidebar-tsx/index.tsx', './src2/void-settings-tsx/index.tsx', - './src2/ctrl-k-tsx/index.tsx', + './src2/quick-edit-tsx/index.tsx', './src2/diff/index.tsx', ], outDir: './out', diff --git a/src/vs/workbench/contrib/void/browser/sidebarActions.ts b/src/vs/workbench/contrib/void/browser/sidebarActions.ts index 69508e18..bd1c753f 100644 --- a/src/vs/workbench/contrib/void/browser/sidebarActions.ts +++ b/src/vs/workbench/contrib/void/browser/sidebarActions.ts @@ -83,45 +83,45 @@ registerAction2(class extends Action2 { ) + // select whole lines if (selectionRange) { - // select whole lines editor?.setSelection({ startLineNumber: selectionRange.startLineNumber, endLineNumber: selectionRange.endLineNumber, startColumn: 1, endColumn: Number.MAX_SAFE_INTEGER }) + } - const selectionStr = getContentInRange(model, selectionRange) + const selectionStr = getContentInRange(model, selectionRange) - const selection: CodeStagingSelection = selectionStr === null || selectionRange.startLineNumber > selectionRange.endLineNumber ? { - type: 'File', - fileURI: model.uri, - selectionStr: null, - range: null, - } : { - type: 'Selection', - fileURI: model.uri, - selectionStr: selectionStr, - range: selectionRange, - } + const selection: CodeStagingSelection = !selectionRange || !selectionStr || (selectionRange.startLineNumber > selectionRange.endLineNumber) ? { + type: 'File', + fileURI: model.uri, + selectionStr: null, + range: null, + } : { + type: 'Selection', + fileURI: model.uri, + selectionStr: selectionStr, + range: selectionRange, + } - // add selection to staging - const threadHistoryService = accessor.get(IThreadHistoryService) - const currentStaging = threadHistoryService.state._currentStagingSelections - const currentStagingEltIdx = currentStaging?.findIndex(s => - s.fileURI.fsPath === model.uri.fsPath - && s.range?.startLineNumber === selection.range?.startLineNumber - && s.range?.endLineNumber === selection.range?.endLineNumber - ) + // add selection to staging + const threadHistoryService = accessor.get(IThreadHistoryService) + const currentStaging = threadHistoryService.state._currentStagingSelections + const currentStagingEltIdx = currentStaging?.findIndex(s => + s.fileURI.fsPath === model.uri.fsPath + && s.range?.startLineNumber === selection.range?.startLineNumber + && s.range?.endLineNumber === selection.range?.endLineNumber + ) - // if matches with existing selection, overwrite - if (currentStagingEltIdx !== undefined && currentStagingEltIdx !== -1) { - threadHistoryService.setStaging([ - ...currentStaging!.slice(0, currentStagingEltIdx), - selection, - ...currentStaging!.slice(currentStagingEltIdx + 1, Infinity) - ]) - } - // if no match, add - else { - threadHistoryService.setStaging([...(currentStaging ?? []), selection]) - } + // if matches with existing selection, overwrite + if (currentStagingEltIdx !== undefined && currentStagingEltIdx !== -1) { + threadHistoryService.setStaging([ + ...currentStaging!.slice(0, currentStagingEltIdx), + selection, + ...currentStaging!.slice(currentStagingEltIdx + 1, Infinity) + ]) + } + // if no match, add + else { + threadHistoryService.setStaging([...(currentStaging ?? []), selection]) } } From 2ba04a78a8bbc6fa1f4ec879c39c9fc0e4d54b6d Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Sun, 5 Jan 2025 21:02:31 -0800 Subject: [PATCH 014/111] add X to ctrlK --- .../react/src/markdown/ChatMarkdownRender.tsx | 8 ++--- .../src/quick-edit-tsx/QuickEditChat.tsx | 17 +++++++---- .../react/src/sidebar-tsx/ErrorDisplay.tsx | 30 +++++++++---------- .../react/src/sidebar-tsx/SidebarChat.tsx | 9 ++---- .../src/sidebar-tsx/SidebarThreadSelector.tsx | 4 +-- .../react/src/void-settings-tsx/Settings.tsx | 17 +++++------ 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx index dc134d6f..e89cb665 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx @@ -49,14 +49,14 @@ const CodeButtonsOnHover = ({ text }: { text: string }) => { return <> )} {showDismiss && onDismiss && ( - )}
@@ -75,10 +75,10 @@ export const ErrorDisplay = ({ {/* Expandable Details */} {isExpanded && details && ( -
+
- Full Error: -
{details}
+ Full Error: +
{details}
)} diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 6b6e3bc3..e34209ae 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -272,7 +272,7 @@ export const SelectedFiles = ( return ( !!selections && selections.length !== 0 && (
{selections.map((selection, i) => { @@ -311,12 +311,7 @@ export const SelectedFiles = ( {/* X button */} {type === 'staging' && { e.stopPropagation(); if (type !== 'staging') return; diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarThreadSelector.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarThreadSelector.tsx index e6adb5f2..130ccf10 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarThreadSelector.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarThreadSelector.tsx @@ -53,7 +53,7 @@ export const SidebarThreadSelector = () => {
{/* a list of all the past threads */} -
+
{sortedThreadIds.map((threadId) => { if (!allThreads) return <>Error: Threads not found. @@ -88,7 +88,7 @@ export const SidebarThreadSelector = () => { ) })} -
+
) 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 fa27d55a..8239ef88 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 @@ -197,7 +197,6 @@ export const ModelDump = () => { return
{/* left part is width:full */} @@ -285,7 +284,7 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider }, [voidSettingsService, providerName, settingName])} multiline={false} /> - {subTextMd === undefined ? null :
+ {subTextMd === undefined ? null :
} @@ -425,13 +424,13 @@ export const Settings = () => { {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} {/*

{`Instructions:`}

*/} {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} -

{`Host a model locally and use it in Void. Instructions:`}

+

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

-

-

-

-

-

+

+

+

+

+

{/* TODO we should create UI for downloading models without user going into terminal */}
@@ -440,7 +439,7 @@ export const Settings = () => {

More Providers

-

{`Get access to frontier models. We recommend Anthropic or OpenAI.`}

+

{`Void can also access models from Anthropic, OpenAI, OpenRouter, and more.`}

{/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} From dd133d2cd5eb131e02d095fb09c6fc9b81cdbe61 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Sun, 5 Jan 2025 21:27:16 -0800 Subject: [PATCH 015/111] ctrlK roundRange --- .../contrib/void/browser/quickEditActions.ts | 3 ++- .../react/src/quick-edit-tsx/QuickEditChat.tsx | 4 ++-- .../browser/react/src/sidebar-tsx/Sidebar.tsx | 2 +- .../void/browser/react/src/util/inputs.tsx | 8 ++++---- .../src/void-settings-tsx/ModelDropdown.tsx | 1 + .../contrib/void/browser/sidebarActions.ts | 16 +++++++++------- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/quickEditActions.ts b/src/vs/workbench/contrib/void/browser/quickEditActions.ts index 39461b18..285e21d2 100644 --- a/src/vs/workbench/contrib/void/browser/quickEditActions.ts +++ b/src/vs/workbench/contrib/void/browser/quickEditActions.ts @@ -11,6 +11,7 @@ import { IMetricsService } from '../../../../platform/void/common/metricsService import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; import { IInlineDiffsService } from './inlineDiffsService.js'; import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js'; +import { roundRangeToLines } from './sidebarActions.js'; export type QuickEditPropsType = { @@ -54,7 +55,7 @@ registerAction2(class extends Action2 { if (!editor) return; const model = editor.getModel() if (!model) return; - const selection = editor.getSelection() + const selection = roundRangeToLines(editor.getSelection(), { emptySelectionBehavior: 'line' }) if (!selection) return; diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 6d66c5a3..26bbc9f9 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -146,9 +146,9 @@ export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onC
- + diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx index b259a728..4a5f23b1 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx @@ -39,7 +39,7 @@ export const Sidebar = ({ className }: { className: string }) => { sidebarStateService.setState({ currentTab: tabs[(index + 1) % tabs.length] as any }) }}>clickme {tab} */} -
+
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 6319c1f0..029e0000 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 @@ -197,11 +197,12 @@ export const VoidCheckBox = ({ label, value, onClick, className }: { label: stri } -export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectBoxRef, options }: { +export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectBoxRef, options, className }: { onChangeSelection: (value: T) => void; onCreateInstance?: ((instance: SelectBox) => void | IDisposable[]); selectBoxRef?: React.MutableRefObject; options: readonly { text: string, value: T }[]; + className?:string; }) => { const accessor = useAccessor() const contextViewProvider = accessor.get('IContextViewService') @@ -209,10 +210,9 @@ 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/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index d0cd41b4..1a3bd734 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -32,6 +32,7 @@ const ModelSelectBox = ({ options, featureName }: { options: ModelOption[], feat let weChangedText = false return { if (weChangedText) return diff --git a/src/vs/workbench/contrib/void/browser/sidebarActions.ts b/src/vs/workbench/contrib/void/browser/sidebarActions.ts index bd1c753f..b2a4df91 100644 --- a/src/vs/workbench/contrib/void/browser/sidebarActions.ts +++ b/src/vs/workbench/contrib/void/browser/sidebarActions.ts @@ -26,13 +26,17 @@ import { VOID_OPEN_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; // ---------- Register commands and keybindings ---------- -const roundRangeToLines = (range: IRange | null | undefined) => { +export const roundRangeToLines = (range: IRange | null | undefined, options: { emptySelectionBehavior: 'null' | 'line' }) => { if (!range) return null // treat as no selection if selection is empty - if (range.endColumn === range.startColumn && range.endLineNumber === range.startLineNumber) - return null + if (range.endColumn === range.startColumn && range.endLineNumber === range.startLineNumber) { + if (options.emptySelectionBehavior === 'null') + return null + else if (options.emptySelectionBehavior === 'line') + return { startLineNumber: range.startLineNumber, startColumn: 1, endLineNumber: range.startLineNumber, endColumn: 1 } + } // IRange is 1-indexed const endLine = range.endColumn === 1 ? range.endLineNumber - 1 : range.endLineNumber // e.g. if the user triple clicks, it selects column=0, line=line -> column=0, line=line+1 @@ -77,10 +81,8 @@ registerAction2(class extends Action2 { stateService.fireFocusChat() const editor = editorService.getActiveCodeEditor() - const selectionRange = roundRangeToLines( - // accessor.get(IEditorService).activeTextEditorControl?.getSelection() - editor?.getSelection() - ) + // accessor.get(IEditorService).activeTextEditorControl?.getSelection() + const selectionRange = roundRangeToLines(editor?.getSelection(), { emptySelectionBehavior: 'null' }) // select whole lines From f19e579ce9b6485ebb8d11775b965fe68017e4dd Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Mon, 6 Jan 2025 01:19:27 -0800 Subject: [PATCH 016/111] extract code works! ignore etc --- .../platform/void/common/voidSettingsTypes.ts | 2 +- .../void/browser/autocompleteService.ts | 4 +- .../browser/helpers/extractCodeFromResult.ts | 18 +-- .../void/browser/inlineDiffsService.ts | 25 +++- .../contrib/void/browser/prompt/prompts.ts | 28 ++-- .../react/src/void-settings-tsx/Settings.tsx | 122 ++++++++++++------ 6 files changed, 136 insertions(+), 63 deletions(-) diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index e4878e6f..3c9b9da0 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -204,7 +204,7 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn } else if (providerName === 'openAICompatible') { return { - title: 'Other', + title: 'OpenAI-Compatible', } } else if (providerName === 'gemini') { diff --git a/src/vs/workbench/contrib/void/browser/autocompleteService.ts b/src/vs/workbench/contrib/void/browser/autocompleteService.ts index 3bd4d955..bbefb748 100644 --- a/src/vs/workbench/contrib/void/browser/autocompleteService.ts +++ b/src/vs/workbench/contrib/void/browser/autocompleteService.ts @@ -17,7 +17,7 @@ import { IEditorService } from '../../../services/editor/common/editorService.js import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { EditorResourceAccessor } from '../../../common/editor.js'; import { IModelService } from '../../../../editor/common/services/model.js'; -import { extractCodeFromResult } from './helpers/extractCodeFromResult.js'; +import { extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; // The extension this was called from is here - https://github.com/voideditor/void/blob/autocomplete/extensions/void/src/extension/extension.ts @@ -652,7 +652,7 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ // newAutocompletion.abortRef = { current: () => { } } newAutocompletion.status = 'finished' // newAutocompletion.promise = undefined - newAutocompletion.insertText = postprocessResult(extractCodeFromResult(fullText)) + newAutocompletion.insertText = postprocessResult(extractCodeFromRegular(fullText)) resolve(newAutocompletion.insertText) diff --git a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts index 2573dae4..6ac12fd1 100644 --- a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts +++ b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ - - -export const extractArtificialFIMCodeFromResult = ({ text, preTag, sufTag, midTag }: { text: string, preTag: string, sufTag: string, midTag: string }) => { +// modelWasTrainedOnFIM should be false here +export const extractCodeFromFIM = ({ text, midTag, modelWasTrainedOnFIM }: { text: string, midTag: string, modelWasTrainedOnFIM: false }) => { /* desired matches ` @@ -39,22 +38,25 @@ export const extractArtificialFIMCodeFromResult = ({ text, preTag, sufTag, midTa [optional ` | `` | ```] */ - const regex = /[\s\S]*?(?:`{1,3}\s*([a-zA-Z_]+[\w]*)?[\s\S]*?)?([\s\S]*?)(?:|`{1,3}|$)/; - + // const regex = /[\s\S]*?(?:`{1,3}\s*([a-zA-Z_]+[\w]*)?[\s\S]*?)?([\s\S]*?)(?:<\/MID>|`{1,3}|$)/; + const regex = new RegExp( + `[\\s\\S]*?(?:\`{1,3}\\s*([a-zA-Z_]+[\\w]*)?[\\s\\S]*?)?<${midTag}>([\\s\\S]*?)(?:|\`{1,3}|$)`, + '' + ); const match = text.match(regex); if (match) { const [_, languageName, codeBetweenMidTags] = match; - return [languageName, codeBetweenMidTags] + return [languageName, codeBetweenMidTags] as const } else { - return [undefined, extractCodeFromResult(text)] + return [undefined, extractCodeFromRegular(text)] as const } } -export const extractCodeFromResult = (result: string) => { +export const extractCodeFromRegular = (result: string) => { // Match either: // 1. ```language\n``` // 2. `````` diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index a7db6e6c..40f4391d 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -27,7 +27,7 @@ import * as dom from '../../../../base/browser/dom.js'; import { Widget } from '../../../../base/browser/ui/widget.js'; import { URI } from '../../../../base/common/uri.js'; import { IConsistentEditorItemService, IConsistentItemService } from './helperServices/consistentItemService.js'; -import { ctrlKStream_prefixAndSuffix, ctrlKStream_prompt, ctrlKStream_systemMessage, ctrlLStream_prompt, ctrlLStream_systemMessage } from './prompt/prompts.js'; +import { ctrlKStream_prefixAndSuffix, ctrlKStream_prompt, ctrlKStream_systemMessage, ctrlLStream_prompt, ctrlLStream_systemMessage, defaultFimTags } from './prompt/prompts.js'; import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; import { IPosition } from '../../../../editor/common/core/position.js'; @@ -36,6 +36,7 @@ import { QuickEditPropsType } from './quickEditActions.js'; import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js'; import { LLMMessage } from '../../../../platform/void/common/llmMessageTypes.js'; import { IModelContentChangedEvent } from '../../../../editor/common/textModelEvents.js'; +import { extractCodeFromFIM, extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; const configOfBG = (color: Color) => { return { dark: color, light: color, hcDark: color, hcLight: color, } @@ -1043,6 +1044,10 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // this._deleteDiffArea(ctrlKZone) // } + // TODO ctrl+K case should be replaced with an actual check for model.isFIM + const modelWasTrainedOnFIM = featureName === 'Ctrl+K' ? false : false + const modelFimTags = defaultFimTags + const adding: Omit = { type: 'DiffZone', originalCode, @@ -1071,7 +1076,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { } else if (featureName === 'Ctrl+K') { const { prefix, suffix } = ctrlKStream_prefixAndSuffix({ fullFileStr: currentFileStr, startLine, endLine }) - const userContent = ctrlKStream_prompt({ selection: originalCode, userMessage, prefix, suffix }) + const userContent = ctrlKStream_prompt({ selection: originalCode, userMessage, prefix, suffix, modelWasTrainedOnFIM, fimTags: modelFimTags }) console.log('PREFIX:\n', prefix) console.log('SUFFIX:\n', suffix) console.log('USER CONTENT:\n', userContent) @@ -1102,17 +1107,29 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // refresh now in case onText takes a while to get 1st message this._refreshStylesAndDiffsInURI(uri) + + const extractText = (fullText: string) => { + if (featureName === 'Ctrl+K') { + const [_, textSoFar] = extractCodeFromFIM({ text: fullText, midTag: modelFimTags.midTag, modelWasTrainedOnFIM }) + return textSoFar + } + else if (featureName === 'Ctrl+L') { + return extractCodeFromRegular(fullText) + } + throw 1 + } + streamRequestIdRef.current = this._llmMessageService.sendLLMMessage({ featureName, logging: { loggingName: `startApplying - ${featureName}` }, messages, onText: ({ newText, fullText }) => { - this._writeDiffZoneLLMText(diffZone, fullText, latestCurrentFileEnd, latestOriginalFileStart) + this._writeDiffZoneLLMText(diffZone, extractText(fullText), latestCurrentFileEnd, latestOriginalFileStart) this._refreshStylesAndDiffsInURI(uri) }, onFinalMessage: ({ fullText }) => { // at the end, re-write whole thing to make sure no sync errors - this._writeText(uri, fullText, + this._writeText(uri, extractText(fullText), { startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed { shouldRealignDiffAreas: false } ) diff --git a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts index f65bfcbe..f2759744 100644 --- a/src/vs/workbench/contrib/void/browser/prompt/prompts.ts +++ b/src/vs/workbench/contrib/void/browser/prompt/prompts.ts @@ -324,13 +324,25 @@ export const ctrlKStream_prefixAndSuffix = ({ fullFileStr, startLine, endLine }: } -export const ctrlKStream_prompt = ({ selection, prefix, suffix, userMessage }: { selection: string, prefix: string, suffix: string, userMessage: string, }) => { - const modelWasTrainedOnFIM = false + +export type FimTagsType = { + preTag: string, + sufTag: string, + midTag: string +} +export const defaultFimTags: FimTagsType = { + preTag: 'BEFORE', + sufTag: 'AFTER', + midTag: 'SELECTION', +} + +export const ctrlKStream_prompt = ({ selection, prefix, suffix, userMessage, modelWasTrainedOnFIM, fimTags }: { selection: string, prefix: string, suffix: string, userMessage: string, modelWasTrainedOnFIM: boolean, fimTags: FimTagsType }) => { + const { preTag, sufTag, midTag } = fimTags if (modelWasTrainedOnFIM) { - const preTag = 'PRE' - const sufTag = 'SUF' - const midTag = 'MID' + // const preTag = 'PRE' + // const sufTag = 'SUF' + // const midTag = 'MID' return `\ <${preTag}> /* Original Selection: @@ -343,9 +355,9 @@ ${prefix} } // prompt the model artifically on how to do FIM else { - const preTag = 'BEFORE' - const sufTag = 'AFTER' - const midTag = 'SELECTION' + // const preTag = 'BEFORE' + // const sufTag = 'AFTER' + // const midTag = 'SELECTION' return `\ The user is selecting this code as their SELECTION: \`\`\` 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 8239ef88..f8d07f75 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 @@ -9,7 +9,7 @@ import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, Voi import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' import { VoidCheckBox, VoidInputBox, VoidSelectBox, VoidSwitch } from '../util/inputs.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' -import { X, RefreshCw, Loader2, Check } from 'lucide-react' +import { X, RefreshCw, Loader2, Check, MoveRight } from 'lucide-react' import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { @@ -360,6 +360,7 @@ export const VoidProviderSettings = ({ providerNames }: { providerNames: Provide // })} // // } +type TabName = 'models' | 'general' export const VoidFeatureFlagSettings = () => { const accessor = useAccessor() @@ -383,12 +384,85 @@ export const VoidFeatureFlagSettings = () => { } +export const FeaturesTab = () => { + return <> +

Local Providers

+ {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} + {/*

{`Instructions:`}

*/} + {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} +

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

+
+ + + + + + {/* TODO we should create UI for downloading models without user going into terminal */} +
+ + + + + +

Providers

+

{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}

+ {/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} + + + + +

Models

+ + + + + + + +} + + + + + + +const OneClickSwitch = () => { + +} + + +const GeneralTab = () => { + return <> + {/* */} + + {/* keyboard shortcuts */} + +

General Settings

+

{`VS Code's built-in settings.`}

+ +

Keyboard Settings

+

{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}

+ + +

One-click Switch

+ + Transfer your VS Code settings to Void. + +

Theme

+ + +

Rules for AI

+ + + +} + // full settings export const Settings = () => { const isDark = useIsDark() - const [tab, setTab] = useState<'models' | 'features'>('models') + const [tab, setTab] = useState('models') return
@@ -407,9 +481,9 @@ export const Settings = () => { - {/* */} +
{/* separator */} @@ -420,43 +494,11 @@ export const Settings = () => {
-

Local Providers

- {/*

{`Keep your data private by hosting AI locally on your computer.`}

*/} - {/*

{`Instructions:`}

*/} - {/*

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

*/} -

{`Void can access any model that you host locally. We automatically detect your local models by default.`}

-
-

-

-

-

-

- {/* TODO we should create UI for downloading models without user going into terminal */} -
- - - - - -

More Providers

-

{`Void can also access models from Anthropic, OpenAI, OpenRouter, and more.`}

- {/*

{`Access models like ChatGPT and Claude. We recommend using Anthropic or OpenAI as providers, or Groq as a faster alternative.`}

*/} - - - - -

Models

- - - - - - +
-
-

{ setTab('features') }}>Features

- {/* */} +
+
From bb7e69b20bc61694d5e5e9ba8a669aa6a599dabb Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Mon, 6 Jan 2025 01:43:54 -0800 Subject: [PATCH 017/111] small fix for realigning --- src/vs/workbench/contrib/void/browser/inlineDiffsService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index 40f4391d..05b8c3d0 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -823,6 +823,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { const lastDiff = computedDiffs.pop() if (!lastDiff) { + // console.log('!lastDiff') // if the writing is identical so far, display no changes originalCodeStartLine = 1 newCodeEndLine = 1 @@ -842,7 +843,8 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { const newCodeTop = llmText.split('\n').slice(0, (newCodeEndLine - 1) + 1).join('\n') const oldFileBottom = diffZone.originalCode.split('\n').slice((originalCodeStartLine - 1) + 1, Infinity).join('\n') - const newCode = `${newCodeTop}\n${oldFileBottom}` + // oriignalCode[1 + line...Infinity]. Must make sure 1 + line < originalCode.length. This is another way to check: + const newCode = (newCodeTop && oldFileBottom) ? `${newCodeTop}\n${oldFileBottom}` : (oldFileBottom || newCodeTop) this._writeText(uri, newCode, { startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER, }, // 1-indexed @@ -1128,6 +1130,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { this._refreshStylesAndDiffsInURI(uri) }, onFinalMessage: ({ fullText }) => { + // console.log('DONE! FULL TEXT\n', extractText(fullText), diffZone.startLine, diffZone.endLine) // at the end, re-write whole thing to make sure no sync errors this._writeText(uri, extractText(fullText), { startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed From f96d320ce061fff8d9645eca0de0c966c0398fe2 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Mon, 6 Jan 2025 02:02:48 -0800 Subject: [PATCH 018/111] fix tricky reject bug --- .../contrib/void/browser/inlineDiffsService.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index 05b8c3d0..2f85ffcd 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -1298,8 +1298,18 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // B| <-- endLine (we want to delete this whole line) // C else if (diff.type === 'insertion') { - writeText = '' - toRange = { startLineNumber: diff.startLine, startColumn: 1, endLineNumber: diff.endLine + 1, endColumn: 1 } // 1-indexed + // console.log('REJECTING:', diff) + // handle the case where the insertion was a newline at end of diffarea (applying to the next line doesnt work because it doesnt exist, vscode just doesnt delete the correct # of newlines) + if (diff.endLine === diffArea.endLine) { + // delete the line before instead of after + writeText = '' + toRange = { startLineNumber: diff.startLine - 1, startColumn: Number.MAX_SAFE_INTEGER, endLineNumber: diff.endLine, endColumn: 1 } // 1-indexed + } + else { + writeText = '' + toRange = { startLineNumber: diff.startLine, startColumn: 1, endLineNumber: diff.endLine + 1, endColumn: 1 } // 1-indexed + } + } // if it was an edit, just edit the range // (this image applies to writeText and toRange, not newOriginalCode) From a0672f845d8c14d5e8e8224b65c1c6ffb6b05abb Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Mon, 6 Jan 2025 18:38:02 -0800 Subject: [PATCH 019/111] selection ui --- .../browser/react/src/sidebar-tsx/Sidebar.tsx | 15 ++-- .../react/src/sidebar-tsx/SidebarChat.tsx | 88 +++++++++++++------ .../void/browser/react/src/util/inputs.tsx | 8 +- .../src/void-settings-tsx/ModelDropdown.tsx | 4 +- 4 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx index 4a5f23b1..edbedbcc 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx @@ -13,17 +13,18 @@ import { useIsDark, useSidebarState } from '../util/services.js'; // import { SidebarChat } from './SidebarChat.js'; import '../styles.css' -import { SidebarThreadSelector } from './SidebarThreadSelector.js'; import { SidebarChat } from './SidebarChat.js'; import ErrorBoundary from './ErrorBoundary.js'; export const Sidebar = ({ className }: { className: string }) => { const sidebarState = useSidebarState() - const { isHistoryOpen, currentTab: tab } = sidebarState + const { currentTab: tab } = sidebarState - const isDark = useIsDark() - // ${isDark ? 'dark' : ''} - return
+ // const isDark = useIsDark() + return
{ sidebarStateService.setState({ currentTab: tabs[(index + 1) % tabs.length] as any }) }}>clickme {tab} */} -
+ {/*
-
+
*/}
diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index e34209ae..66fb4c99 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -6,7 +6,7 @@ import React, { ButtonHTMLAttributes, FormEvent, FormHTMLAttributes, Fragment, useCallback, useEffect, useRef, useState } from 'react'; -import { useAccessor, useThreadsState } from '../util/services.js'; +import { useAccessor, useSidebarState, useThreadsState } from '../util/services.js'; import { ChatMessage, CodeSelection, CodeStagingSelection, IThreadHistoryService } from '../../../threadHistoryService.js'; import { BlockCode, getLanguageFromFileName } from '../markdown/BlockCode.js'; @@ -24,6 +24,7 @@ import { chat_systemMessage, chat_prompt } from '../../../prompt/prompts.js'; import { ISidebarStateService } from '../../../sidebarStateService.js'; import { ILLMMessageService } from '../../../../../../../platform/void/common/llmMessageService.js'; import { IModelService } from '../../../../../../../editor/common/services/model.js'; +import { SidebarThreadSelector } from './SidebarThreadSelector.js'; const IconX = ({ size, className = '', ...props }: { size: number, className?: string } & React.SVGProps) => { @@ -54,7 +55,7 @@ const IconArrowUp = ({ size, className = '' }: { size: number, className?: strin width={size} height={size} className={className} - viewBox="0 0 32 32" + viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > @@ -62,10 +63,9 @@ const IconArrowUp = ({ size, className = '' }: { size: number, className?: strin fill="black" fillRule="evenodd" clipRule="evenodd" - d="M15.1918 8.90615C15.6381 8.45983 16.3618 8.45983 16.8081 8.90615L21.9509 14.049C22.3972 14.4953 22.3972 15.2189 21.9509 15.6652C21.5046 16.1116 20.781 16.1116 20.3347 15.6652L17.1428 12.4734V22.2857C17.1428 22.9169 16.6311 23.4286 15.9999 23.4286C15.3688 23.4286 14.8571 22.9169 14.8571 22.2857V12.4734L11.6652 15.6652C11.2189 16.1116 10.4953 16.1116 10.049 15.6652C9.60265 15.2189 9.60265 14.4953 10.049 14.049L15.1918 8.90615Z" + d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z" > - ); }; @@ -174,26 +174,27 @@ export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Re return } export const ButtonStop = ({ className, ...props }: ButtonHTMLAttributes) => { return } @@ -269,6 +270,9 @@ export const SelectedFiles = ( // index -> isOpened const [selectionIsOpened, setSelectionIsOpened] = useState<(boolean)[]>(selections?.map(() => false) ?? []) + const accessor = useAccessor() + const commandService = accessor.get('ICommandService') + return ( !!selections && selections.length !== 0 && (
{ const isThisSelectionOpened = !!(selection.selectionStr && selectionIsOpened[i]) + const isThisSelectionAFile = selection.selectionStr === null + + return (
{ - setSelectionIsOpened(s => { - const newS = [...s] - newS[i] = !newS[i] - return newS - }); + // open the file if it is a file + if (isThisSelectionAFile) { + commandService.executeCommand('vscode.open', selection.fileURI, { + preview: true, + // preserveFocus: false, + }); + } else { + // open the selection if it is a text-selection + setSelectionIsOpened(s => { + const newS = [...s] + newS[i] = !newS[i] + return newS + }); + } }} > - + {/* file name */} {getBasename(selection.fileURI.fsPath)} {/* selection range */} - {selection.selectionStr !== null ? ` (${selection.range.startLineNumber}-${selection.range.endLineNumber})` : ''} + {!isThisSelectionAFile ? ` (${selection.range.startLineNumber}-${selection.range.endLineNumber})` : ''} {/* X button */} @@ -378,15 +396,22 @@ const ChatBubble = ({ chatMessage, isLoading }: { } return
- {chatbubbleContents} - {isLoading && } +
+ {chatbubbleContents} + {isLoading && } +
} @@ -411,6 +436,8 @@ export const SidebarChat = () => { return () => disposables.forEach(d => d.dispose()) }, [sidebarStateService, inputBoxRef]) + const { currentTab, isHistoryOpen } = useSidebarState() + // threads state const threadsState = useThreadsState() const threadsStateService = accessor.get('IThreadHistoryService') @@ -433,6 +460,7 @@ export const SidebarChat = () => { const [sidebarRef, sidebarDimensions] = useResizeObserver() const [formRef, formDimensions] = useResizeObserver() + const [historyRef, historyDimensions] = useResizeObserver() // const [formHeight, setFormHeight] = useState(0) // TODO should use resize observer instead // const [sidebarHeight, setSidebarHeight] = useState(0) @@ -551,6 +579,14 @@ export const SidebarChat = () => { ref={sidebarRef} className={`w-full h-full`} > + {/* thread selector */} +
+ +
+ + {/* previous messages + current stream */} { overflow-x-hidden overflow-y-auto `} - style={{ maxHeight: sidebarDimensions.height - formDimensions.height - 30 }} + style={{ maxHeight: sidebarDimensions.height - historyDimensions.height - formDimensions.height - 30 }} // the height of the previousMessages is determined by all other heights > {/* previous messages */} {previousMessages.map((message, i) => )} @@ -566,12 +602,6 @@ export const SidebarChat = () => { {/* message stream */} - {/* {_test_messages.map((_, i) =>
div {i}
)} -
{`totalHeight: ${sidebarHeight - formHeight - 30}`}
-
{`sidebarHeight: ${sidebarHeight}`}
-
{`formHeight: ${formHeight}`}
- */} -
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 029e0000..c1bfdb06 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 @@ -306,9 +306,9 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan initValue = normalizeIndentation(initValue) - return
+ return
{ return instantiationService.createInstance( CodeEditorWidget, @@ -321,8 +321,8 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan alwaysConsumeMouseWheel: false, vertical: 'hidden', horizontal: 'hidden', - verticalScrollbarSize: 0, - horizontalScrollbarSize: 0, + verticalScrollbarSize: 8, + horizontalScrollbarSize: 8, }, scrollBeyondLastLine: false, diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 1a3bd734..9a77c73c 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -75,10 +75,10 @@ const MemoizedModelSelectBox = ({ featureName }: { featureName: FeatureName }) = const DummySelectBox = () => { const accessor = useAccessor() - const comandService = accessor.get('ICommandService') + const commandService = accessor.get('ICommandService') const openSettings = () => { - comandService.executeCommand(VOID_OPEN_SETTINGS_ACTION_ID); + commandService.executeCommand(VOID_OPEN_SETTINGS_ACTION_ID); }; return
Date: Mon, 6 Jan 2025 19:15:41 -0800 Subject: [PATCH 020/111] scrollbars --- .../contrib/void/browser/react/src/util/inputs.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 c1bfdb06..d1a5dab6 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 @@ -12,6 +12,7 @@ import { Checkbox } from '../../../../../../../base/browser/ui/toggle/toggle.js' import { CodeEditorWidget } from '../../../../../../../editor/browser/widget/codeEditor/codeEditorWidget.js' import { useAccessor } from './services.js'; +import { ScrollableElement } from '../../../../../../../base/browser/ui/scrollbar/scrollableElement.js'; // type guard @@ -202,7 +203,7 @@ export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectB onCreateInstance?: ((instance: SelectBox) => void | IDisposable[]); selectBoxRef?: React.MutableRefObject; options: readonly { text: string, value: T }[]; - className?:string; + className?: string; }) => { const accessor = useAccessor() const contextViewProvider = accessor.get('IContextViewService') @@ -319,8 +320,8 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan scrollbar: { alwaysConsumeMouseWheel: false, - vertical: 'hidden', - horizontal: 'hidden', + // vertical: 'hidden', + // horizontal: 'hidden', verticalScrollbarSize: 8, horizontalScrollbarSize: 8, }, From 5293095eb8a94a408776425080f41646989da190 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Mon, 6 Jan 2025 23:11:52 -0800 Subject: [PATCH 021/111] custom scrollbar --- .../contrib/void/browser/media/void.css | 33 ++++++++++ .../react/src/sidebar-tsx/SidebarChat.tsx | 62 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/src/vs/workbench/contrib/void/browser/media/void.css b/src/vs/workbench/contrib/void/browser/media/void.css index c6358adc..0ec9730b 100644 --- a/src/vs/workbench/contrib/void/browser/media/void.css +++ b/src/vs/workbench/contrib/void/browser/media/void.css @@ -71,3 +71,36 @@ color: #3b82f6; cursor: pointer; } + + + + +.void-scrollable-element *::-webkit-scrollbar { + width: 14px !important; + height: 14px !important; +} + +.void-scrollable-element *::-webkit-scrollbar-track { + background: transparent !important; +} + +.void-scrollable-element *::-webkit-scrollbar-thumb { + background-color: transparent !important; + border-radius: 0px !important; +} + +.void-scrollable-element.show-scrollbar *::-webkit-scrollbar-thumb { + background-color: var(--vscode-scrollbarSlider-background) !important; +} + +.void-scrollable-element *::-webkit-scrollbar-thumb:hover { + background-color: var(--vscode-scrollbarSlider-hoverBackground) !important; +} + +.void-scrollable-element *::-webkit-scrollbar-thumb:active { + background-color: var(--vscode-scrollbarSlider-activeBackground) !important; +} + +.void-scrollable-element *::-webkit-scrollbar-corner { + background-color: transparent !important; +} diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 66fb4c99..c7a514e1 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -417,6 +417,63 @@ const ChatBubble = ({ chatMessage, isLoading }: { +const useScrollFade = (ref: React.MutableRefObject) => { + useEffect(() => { + if (!ref.current) return; + + let fadeTimeout: NodeJS.Timeout | null = null; + const parent = ref.current; + const scrollElement = parent.querySelector('[class*="void-overflow-"]'); + if (!scrollElement) return; + + const onMouseEnter = () => { + parent.classList.add('show-scrollbar'); + }; + + const onMouseLeave = () => { + if (fadeTimeout) { + clearTimeout(fadeTimeout); + } + fadeTimeout = setTimeout(() => { + parent.classList.remove('show-scrollbar'); + }, 1000); + }; + + scrollElement.addEventListener('mouseenter', onMouseEnter); + scrollElement.addEventListener('mouseleave', onMouseLeave); + + return () => { + scrollElement.removeEventListener('mouseenter', onMouseEnter); + scrollElement.removeEventListener('mouseleave', onMouseLeave); + if (fadeTimeout) { + clearTimeout(fadeTimeout); + } + }; + }, [ref]); +}; + + +const Test = ({ children, className = "", }: { children: React.ReactNode; className?: string; maxHeight?: string; maxWidth?: string; }) => { + + + const ref = useRef(null) + + useScrollFade(ref) + + return ( +
+
+ {children} +
+
+ ); +}; + + export const SidebarChat = () => { const inputBoxRef: React.MutableRefObject = useRef(null); @@ -579,6 +636,11 @@ export const SidebarChat = () => { ref={sidebarRef} className={`w-full h-full`} > + + aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa + aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa + aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa + {/* thread selector */}
Date: Tue, 7 Jan 2025 00:33:27 -0800 Subject: [PATCH 022/111] scrollbar styles recursive --- .../contrib/void/browser/media/void.css | 66 +++++++++++- .../react/src/sidebar-tsx/SidebarChat.tsx | 66 +----------- .../react/src/util/useScrollbarStyles.tsx | 101 ++++++++++++++++++ 3 files changed, 166 insertions(+), 67 deletions(-) create mode 100644 src/vs/workbench/contrib/void/browser/react/src/util/useScrollbarStyles.tsx diff --git a/src/vs/workbench/contrib/void/browser/media/void.css b/src/vs/workbench/contrib/void/browser/media/void.css index 0ec9730b..41177002 100644 --- a/src/vs/workbench/contrib/void/browser/media/void.css +++ b/src/vs/workbench/contrib/void/browser/media/void.css @@ -75,32 +75,90 @@ + +.void-scrollable-element::-webkit-scrollbar, .void-scrollable-element *::-webkit-scrollbar { width: 14px !important; height: 14px !important; } +.void-scrollable-element::-webkit-scrollbar-track, .void-scrollable-element *::-webkit-scrollbar-track { background: transparent !important; } +.void-scrollable-element::-webkit-scrollbar-thumb, .void-scrollable-element *::-webkit-scrollbar-thumb { background-color: transparent !important; border-radius: 0px !important; } -.void-scrollable-element.show-scrollbar *::-webkit-scrollbar-thumb { - background-color: var(--vscode-scrollbarSlider-background) !important; -} - +.void-scrollable-element::-webkit-scrollbar-thumb:hover, .void-scrollable-element *::-webkit-scrollbar-thumb:hover { background-color: var(--vscode-scrollbarSlider-hoverBackground) !important; } +.void-scrollable-element::-webkit-scrollbar-thumb:active, .void-scrollable-element *::-webkit-scrollbar-thumb:active { background-color: var(--vscode-scrollbarSlider-activeBackground) !important; } +.void-scrollable-element::-webkit-scrollbar-corner, .void-scrollable-element *::-webkit-scrollbar-corner { background-color: transparent !important; } + +.void-scrollable-element.show-scrollbar-0::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-0 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 0%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-1::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-1 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 10%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-2::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-2 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 20%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-3::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-3 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 30%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-4::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-4 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 40%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-5::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-5 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 50%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-6::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-6 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 60%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-7::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-7 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 70%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-8::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-8 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 80%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-9::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-9 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 90%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-10::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-10 *::-webkit-scrollbar-thumb { + background-color: var(--vscode-scrollbarSlider-background) !important; +} diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index c7a514e1..e1fc9fc4 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -25,6 +25,7 @@ import { ISidebarStateService } from '../../../sidebarStateService.js'; import { ILLMMessageService } from '../../../../../../../platform/void/common/llmMessageService.js'; import { IModelService } from '../../../../../../../editor/common/services/model.js'; import { SidebarThreadSelector } from './SidebarThreadSelector.js'; +import { useScrollbarStyles } from '../util/useScrollbarStyles.js'; const IconX = ({ size, className = '', ...props }: { size: number, className?: string } & React.SVGProps) => { @@ -416,64 +417,6 @@ const ChatBubble = ({ chatMessage, isLoading }: { } - -const useScrollFade = (ref: React.MutableRefObject) => { - useEffect(() => { - if (!ref.current) return; - - let fadeTimeout: NodeJS.Timeout | null = null; - const parent = ref.current; - const scrollElement = parent.querySelector('[class*="void-overflow-"]'); - if (!scrollElement) return; - - const onMouseEnter = () => { - parent.classList.add('show-scrollbar'); - }; - - const onMouseLeave = () => { - if (fadeTimeout) { - clearTimeout(fadeTimeout); - } - fadeTimeout = setTimeout(() => { - parent.classList.remove('show-scrollbar'); - }, 1000); - }; - - scrollElement.addEventListener('mouseenter', onMouseEnter); - scrollElement.addEventListener('mouseleave', onMouseLeave); - - return () => { - scrollElement.removeEventListener('mouseenter', onMouseEnter); - scrollElement.removeEventListener('mouseleave', onMouseLeave); - if (fadeTimeout) { - clearTimeout(fadeTimeout); - } - }; - }, [ref]); -}; - - -const Test = ({ children, className = "", }: { children: React.ReactNode; className?: string; maxHeight?: string; maxWidth?: string; }) => { - - - const ref = useRef(null) - - useScrollFade(ref) - - return ( -
-
- {children} -
-
- ); -}; - - export const SidebarChat = () => { const inputBoxRef: React.MutableRefObject = useRef(null); @@ -519,6 +462,8 @@ export const SidebarChat = () => { const [formRef, formDimensions] = useResizeObserver() const [historyRef, historyDimensions] = useResizeObserver() + useScrollbarStyles(sidebarRef) + // const [formHeight, setFormHeight] = useState(0) // TODO should use resize observer instead // const [sidebarHeight, setSidebarHeight] = useState(0) const onChangeText = useCallback((newStr: string) => { setInstructions(newStr) }, [setInstructions]) @@ -636,11 +581,6 @@ export const SidebarChat = () => { ref={sidebarRef} className={`w-full h-full`} > - - aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa - aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa - aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa - {/* thread selector */}
) => { + + useEffect(() => { + if (!containerRef.current) return; + + // Create selector for specific overflow classes + const overflowSelector = [ + '[class*="overflow-auto"]', + '[class*="overflow-x-auto"]', + '[class*="overflow-y-auto"]' + ].join(','); + + // Get all matching elements within the container, including the container itself + const scrollElements = [ + ...(containerRef.current.matches(overflowSelector) ? [containerRef.current] : []), + ...Array.from(containerRef.current.querySelectorAll(overflowSelector)) + ]; + + // Apply styles and listeners to each scroll element + scrollElements.forEach(element => { + // Add the scrollable class directly to the overflow element + element.classList.add('void-scrollable-element'); + + let fadeTimeout: NodeJS.Timeout | null = null; + let fadeInterval: NodeJS.Timeout | null = null; + + const fadeIn = () => { + if (fadeInterval) clearInterval(fadeInterval); + + let step = 0; + fadeInterval = setInterval(() => { + if (step <= 10) { + element.classList.remove(`show-scrollbar-${step - 1}`); + element.classList.add(`show-scrollbar-${step}`); + step++; + } else { + clearInterval(fadeInterval!); + } + }, 10); + }; + + const fadeOut = () => { + if (fadeInterval) clearInterval(fadeInterval); + + let step = 10; + fadeInterval = setInterval(() => { + if (step >= 0) { + element.classList.remove(`show-scrollbar-${step + 1}`); + element.classList.add(`show-scrollbar-${step}`); + step--; + } else { + clearInterval(fadeInterval!); + } + }, 60); + }; + + const onMouseEnter = () => { + if (fadeTimeout) clearTimeout(fadeTimeout); + if (fadeInterval) clearInterval(fadeInterval); + fadeIn(); + }; + + const onMouseLeave = () => { + if (fadeTimeout) clearTimeout(fadeTimeout); + fadeTimeout = setTimeout(() => { + fadeOut(); + }, 10); + }; + + element.addEventListener('mouseenter', onMouseEnter); + element.addEventListener('mouseleave', onMouseLeave); + + // Store cleanup function + const cleanup = () => { + element.removeEventListener('mouseenter', onMouseEnter); + element.removeEventListener('mouseleave', onMouseLeave); + if (fadeTimeout) clearTimeout(fadeTimeout); + if (fadeInterval) clearInterval(fadeInterval); + element.classList.remove('void-scrollable-element'); + // Remove any remaining show-scrollbar classes + for (let i = 0; i <= 10; i++) { + element.classList.remove(`show-scrollbar-${i}`); + } + }; + + // Store the cleanup function on the element for later use + (element as any).__scrollbarCleanup = cleanup; + }); + + return () => { + // Clean up all scroll elements + scrollElements.forEach(element => { + if ((element as any).__scrollbarCleanup) { + (element as any).__scrollbarCleanup(); + } + }); + }; + }, [containerRef]); +}; From a53f92432b318a55b8697a8759382384704b23cb Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Tue, 7 Jan 2025 19:45:41 -0800 Subject: [PATCH 023/111] keybinding for ctrl+L and ctrl+K shows accurately even if user changes it --- .../contrib/void/browser/helpers/getCmdKey.ts | 20 ------------------- .../src/quick-edit-tsx/QuickEditChat.tsx | 10 +++++++--- .../react/src/sidebar-tsx/SidebarChat.tsx | 6 ++++-- .../void/browser/react/src/util/services.tsx | 2 ++ 4 files changed, 13 insertions(+), 25 deletions(-) delete mode 100644 src/vs/workbench/contrib/void/browser/helpers/getCmdKey.ts diff --git a/src/vs/workbench/contrib/void/browser/helpers/getCmdKey.ts b/src/vs/workbench/contrib/void/browser/helpers/getCmdKey.ts deleted file mode 100644 index fe520e42..00000000 --- a/src/vs/workbench/contrib/void/browser/helpers/getCmdKey.ts +++ /dev/null @@ -1,20 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Glass Devtools, Inc. All rights reserved. - * Void Editor additions licensed under the AGPL 3.0 License. - *--------------------------------------------------------------------------------------------*/ - -import { isMacintosh } from '../../../../../base/common/platform.js'; - -// import { OperatingSystem, OS } from '../../../../base/common/platform.js'; -// OS === OperatingSystem.Macintosh -export function getCmdKey(): string { - if (isMacintosh) { - return '⌘'; - } else { - return 'Ctrl'; - } -} - - - - diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 26bbc9f9..4d67a861 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -7,9 +7,8 @@ import React, { FormEvent, useCallback, useEffect, useRef, useState } from 'reac import { useSettingsState, useSidebarState, useThreadsState, useQuickEditState, useAccessor } from '../util/services.js'; import { OnError } from '../../../../../../../platform/void/common/llmMessageTypes.js'; import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'; -import { getCmdKey } from '../../../helpers/getCmdKey.js'; import { VoidInputBox } from '../util/inputs.js'; -import { QuickEditPropsType } from '../../../quickEditActions.js'; +import { QuickEditPropsType, VOID_CTRL_K_ACTION_ID } from '../../../quickEditActions.js'; import { ButtonStop, ButtonSubmit } from '../sidebar-tsx/SidebarChat.js'; import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js'; import { X } from 'lucide-react'; @@ -72,6 +71,7 @@ export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onC inlineDiffsService.removeCtrlKZone({ diffareaid }) }, [inlineDiffsService, diffareaid]) + // sync init value const alreadySetRef = useRef(false) useEffect(() => { @@ -81,6 +81,10 @@ export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onC inputBoxRef.current.value = instructions }, [initText, instructions]) + const keybindingString = accessor.get('IKeybindingService').lookupKeybinding(VOID_CTRL_K_ACTION_ID)?.getLabel() + + + return
{/* text input */} { inputBoxRef.current = instance; diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index e1fc9fc4..329724d6 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -16,7 +16,6 @@ import { EndOfLinePreference } from '../../../../../../../editor/common/model.js import { IDisposable } from '../../../../../../../base/common/lifecycle.js'; import { ErrorDisplay } from './ErrorDisplay.js'; import { OnError, ServiceSendLLMMessageParams } from '../../../../../../../platform/void/common/llmMessageTypes.js'; -import { getCmdKey } from '../../../helpers/getCmdKey.js' import { HistoryInputBox, InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'; import { VoidInputBox } from '../util/inputs.js'; import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js'; @@ -26,6 +25,7 @@ import { ILLMMessageService } from '../../../../../../../platform/void/common/ll import { IModelService } from '../../../../../../../editor/common/services/model.js'; import { SidebarThreadSelector } from './SidebarThreadSelector.js'; import { useScrollbarStyles } from '../util/useScrollbarStyles.js'; +import { VOID_CTRL_L_ACTION_ID } from '../../../sidebarActions.js'; const IconX = ({ size, className = '', ...props }: { size: number, className?: string } & React.SVGProps) => { @@ -577,6 +577,8 @@ export const SidebarChat = () => { // const [_test_messages, _set_test_messages] = useState([]) + const keybindingString = accessor.get('IKeybindingService').lookupKeybinding(VOID_CTRL_L_ACTION_ID)?.getLabel() + return
{ {/* text input */} { ILanguageConfigurationService: accessor.get(ILanguageConfigurationService), ILanguageDetectionService: accessor.get(ILanguageDetectionService), ILanguageFeaturesService: accessor.get(ILanguageFeaturesService), + IKeybindingService: accessor.get(IKeybindingService), } as const return reactAccessor From af244938b80934917551afd3cc5f74098bb12ddb Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Tue, 7 Jan 2025 20:39:20 -0800 Subject: [PATCH 024/111] refactor blockcode --- .../browser/react/src/markdown/BlockCode.tsx | 12 ++++------- .../react/src/markdown/ChatMarkdownRender.tsx | 2 +- .../react/src/sidebar-tsx/SidebarChat.tsx | 2 +- .../void/browser/react/src/util/inputs.tsx | 20 +++++++++++++------ 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx index f77bc2b4..66c8e1e5 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ReactNode } from "react" -import { VoidCodeEditor } from '../util/inputs.js'; +import { VoidCodeEditor, VoidCodeEditorProps } from '../util/inputs.js'; const extensionMap: { [key: string]: string } = { @@ -63,10 +63,9 @@ export function getLanguageFromFileName(fileName: string): string { return extensionMap[ext] || 'plaintext'; } -export const BlockCode = ({ text, buttonsOnHover, language }: { text: string, buttonsOnHover?: ReactNode, language?: string }) => { +export const BlockCode = ({ buttonsOnHover, ...codeEditorProps }: { buttonsOnHover?: React.ReactNode } & VoidCodeEditorProps) => { - - const isSingleLine = !text.includes('\n') + const isSingleLine = !codeEditorProps.initValue.includes('\n') return (<>
@@ -76,10 +75,7 @@ export const BlockCode = ({ text, buttonsOnHover, language }: { text: string, bu
)} - +
) diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx index e89cb665..3b214b92 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx @@ -76,7 +76,7 @@ const RenderToken = ({ token, nested = false }: { token: Token | string, nested? if (t.type === "code") { return } /> diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 329724d6..894850f4 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -362,7 +362,7 @@ export const SelectedFiles = ( {/* selection text */} {isThisSelectionOpened &&
- +
}
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 d1a5dab6..bc7c538c 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 @@ -294,9 +294,12 @@ const normalizeIndentation = (code: string): string => { } -export const VoidCodeEditor = ({ initValue, language }: { initValue: string, language: string | undefined }) => { +export type VoidCodeEditorProps = { initValue: string, language?: string, maxHeight?: number, hideScrollbars?: boolean } +export const VoidCodeEditor = ({ initValue, language, maxHeight, hideScrollbars }: VoidCodeEditorProps) => { - const MAX_HEIGHT = Infinity; + // apply default settings + const MAX_HEIGHT = maxHeight ?? Infinity; + const HIDE_SCROLLBARS = hideScrollbars ?? false; const divRef = useRef(null) @@ -320,10 +323,15 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan scrollbar: { alwaysConsumeMouseWheel: false, - // vertical: 'hidden', - // horizontal: 'hidden', - verticalScrollbarSize: 8, - horizontalScrollbarSize: 8, + ...HIDE_SCROLLBARS ? { + vertical: 'hidden', + horizontal: 'hidden', + verticalScrollbarSize: 0, + horizontalScrollbarSize: 0, + } : { + verticalScrollbarSize: 8, + horizontalScrollbarSize: 8, + }, }, scrollBeyondLastLine: false, From f13c30ae0d8600131f0778b4b2d9f975af7cb590 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Tue, 7 Jan 2025 21:02:21 -0800 Subject: [PATCH 025/111] refactor blockcode --- .../void/browser/react/src/markdown/BlockCode.tsx | 1 - .../void/browser/react/src/sidebar-tsx/SidebarChat.tsx | 9 +++++++-- .../contrib/void/browser/react/src/util/inputs.tsx | 10 +++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx index 66c8e1e5..22888e83 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx @@ -74,7 +74,6 @@ export const BlockCode = ({ buttonsOnHover, ...codeEditorProps }: { buttonsOnHov
{buttonsOnHover}
)} -
diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 894850f4..ce269b12 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -17,7 +17,7 @@ import { IDisposable } from '../../../../../../../base/common/lifecycle.js'; import { ErrorDisplay } from './ErrorDisplay.js'; import { OnError, ServiceSendLLMMessageParams } from '../../../../../../../platform/void/common/llmMessageTypes.js'; import { HistoryInputBox, InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'; -import { VoidInputBox } from '../util/inputs.js'; +import { VoidCodeEditorProps, VoidInputBox } from '../util/inputs.js'; import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js'; import { chat_systemMessage, chat_prompt } from '../../../prompt/prompts.js'; import { ISidebarStateService } from '../../../sidebarStateService.js'; @@ -362,7 +362,12 @@ export const SelectedFiles = ( {/* selection text */} {isThisSelectionOpened &&
- +
}
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 bc7c538c..5b7c6d31 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 @@ -294,12 +294,12 @@ const normalizeIndentation = (code: string): string => { } -export type VoidCodeEditorProps = { initValue: string, language?: string, maxHeight?: number, hideScrollbars?: boolean } -export const VoidCodeEditor = ({ initValue, language, maxHeight, hideScrollbars }: VoidCodeEditorProps) => { +export type VoidCodeEditorProps = { initValue: string, language?: string, maxHeight?: number, showScrollbars?: boolean } +export const VoidCodeEditor = ({ initValue, language, maxHeight, showScrollbars }: VoidCodeEditorProps) => { - // apply default settings + // default settings const MAX_HEIGHT = maxHeight ?? Infinity; - const HIDE_SCROLLBARS = hideScrollbars ?? false; + const SHOW_SCROLLBARS = showScrollbars ?? false; const divRef = useRef(null) @@ -323,7 +323,7 @@ export const VoidCodeEditor = ({ initValue, language, maxHeight, hideScrollbars scrollbar: { alwaysConsumeMouseWheel: false, - ...HIDE_SCROLLBARS ? { + ...!SHOW_SCROLLBARS ? { vertical: 'hidden', horizontal: 'hidden', verticalScrollbarSize: 0, From 8ae4700bb25ff2a3578fbdf7a11b25ec0338ca0e Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Tue, 7 Jan 2025 22:28:14 -0800 Subject: [PATCH 026/111] fix to annoying out of order import problem --- .../workbench/browser/parts/editor/editorGroupWatermark.ts | 3 +-- src/vs/workbench/contrib/void/browser/actionIDs.ts | 6 ++++++ src/vs/workbench/contrib/void/browser/quickEditActions.ts | 2 +- .../void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx | 3 ++- .../void/browser/react/src/sidebar-tsx/SidebarChat.tsx | 2 +- src/vs/workbench/contrib/void/browser/sidebarActions.ts | 2 +- 6 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 src/vs/workbench/contrib/void/browser/actionIDs.ts diff --git a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts index c2c62d65..158e6072 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts @@ -18,14 +18,13 @@ import { isRecentFolder, IWorkspacesService } from '../../../../platform/workspa 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 { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../contrib/void/browser/voidSettingsPane.js'; +import { VOID_CTRL_K_ACTION_ID, VOID_CTRL_L_ACTION_ID } from '../../../contrib/void/browser/actionIDs.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.')); diff --git a/src/vs/workbench/contrib/void/browser/actionIDs.ts b/src/vs/workbench/contrib/void/browser/actionIDs.ts new file mode 100644 index 00000000..b237ecf8 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/actionIDs.ts @@ -0,0 +1,6 @@ +// Normally you'd want to put these exports in the files that register them, but if you do that you'll get an import order error if you import them in certain cases. +// (importing them runs the whole file to get the ID, causing an import error). I guess it's best practice to separate out IDs, pretty annoying... + +export const VOID_CTRL_L_ACTION_ID = 'void.ctrlLAction' + +export const VOID_CTRL_K_ACTION_ID = 'void.ctrlKAction' diff --git a/src/vs/workbench/contrib/void/browser/quickEditActions.ts b/src/vs/workbench/contrib/void/browser/quickEditActions.ts index 285e21d2..6a492a80 100644 --- a/src/vs/workbench/contrib/void/browser/quickEditActions.ts +++ b/src/vs/workbench/contrib/void/browser/quickEditActions.ts @@ -12,6 +12,7 @@ import { ICodeEditorService } from '../../../../editor/browser/services/codeEdit import { IInlineDiffsService } from './inlineDiffsService.js'; import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js'; import { roundRangeToLines } from './sidebarActions.js'; +import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js'; export type QuickEditPropsType = { @@ -31,7 +32,6 @@ export type QuickEdit = { } -export const VOID_CTRL_K_ACTION_ID = 'void.ctrlKAction' registerAction2(class extends Action2 { constructor( ) { diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 4d67a861..7efbe265 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -8,10 +8,11 @@ import { useSettingsState, useSidebarState, useThreadsState, useQuickEditState, import { OnError } from '../../../../../../../platform/void/common/llmMessageTypes.js'; import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'; import { VoidInputBox } from '../util/inputs.js'; -import { QuickEditPropsType, VOID_CTRL_K_ACTION_ID } from '../../../quickEditActions.js'; +import { QuickEditPropsType } from '../../../quickEditActions.js'; import { ButtonStop, ButtonSubmit } from '../sidebar-tsx/SidebarChat.js'; import { ModelDropdown } from '../void-settings-tsx/ModelDropdown.js'; import { X } from 'lucide-react'; +import { VOID_CTRL_K_ACTION_ID } from '../../../actionIDs.js'; export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onChangeHeight, initText }: QuickEditPropsType) => { diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index ce269b12..280103a5 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -25,7 +25,7 @@ import { ILLMMessageService } from '../../../../../../../platform/void/common/ll import { IModelService } from '../../../../../../../editor/common/services/model.js'; import { SidebarThreadSelector } from './SidebarThreadSelector.js'; import { useScrollbarStyles } from '../util/useScrollbarStyles.js'; -import { VOID_CTRL_L_ACTION_ID } from '../../../sidebarActions.js'; +import { VOID_CTRL_L_ACTION_ID } from '../../../actionIDs.js'; const IconX = ({ size, className = '', ...props }: { size: number, className?: string } & React.SVGProps) => { diff --git a/src/vs/workbench/contrib/void/browser/sidebarActions.ts b/src/vs/workbench/contrib/void/browser/sidebarActions.ts index b2a4df91..24d83084 100644 --- a/src/vs/workbench/contrib/void/browser/sidebarActions.ts +++ b/src/vs/workbench/contrib/void/browser/sidebarActions.ts @@ -21,6 +21,7 @@ import { IMetricsService } from '../../../../platform/void/common/metricsService import { ISidebarStateService } from './sidebarStateService.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { VOID_OPEN_SETTINGS_ACTION_ID } from './voidSettingsPane.js'; +import { VOID_CTRL_L_ACTION_ID } from './actionIDs.js'; // ---------- Register commands and keybindings ---------- @@ -60,7 +61,6 @@ 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_ACTION_ID, title: 'Void: Show Sidebar', keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyL, weight: KeybindingWeight.BuiltinExtension } }); From 9e852355d9db08262ad7806f6f4e29fbcf19ec9d Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Tue, 7 Jan 2025 22:35:32 -0800 Subject: [PATCH 027/111] add important tags to build files --- .../darwin/product-build-darwin-universal.yml | 5 +++++ build/darwin/create-universal-app.ts | 2 ++ build/darwin/sign.ts | 6 +++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin-universal.yml b/build/azure-pipelines/darwin/product-build-darwin-universal.yml index f8c10a03..549e4107 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-universal.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-universal.yml @@ -1,3 +1,5 @@ +# Void - this looks like the relevant file for us (product-build-darwin.yml is independent and maybe just used for testing) + steps: - task: NodeTool@0 inputs: @@ -59,6 +61,8 @@ steps: - script: node build/azure-pipelines/distro/mixin-quality displayName: Mixin distro quality + + ## Void - IMPORTANT - script: | set -e unzip $(Pipeline.Workspace)/unsigned_vscode_client_darwin_x64_archive/VSCode-darwin-x64.zip -d $(agent.builddirectory)/VSCode-darwin-x64 @@ -66,6 +70,7 @@ steps: DEBUG=* node build/darwin/create-universal-app.js $(agent.builddirectory) displayName: Create Universal App + ## Void - IMPORTANT - script: | set -e security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain diff --git a/build/darwin/create-universal-app.ts b/build/darwin/create-universal-app.ts index 94b8a23b..e732bd69 100644 --- a/build/darwin/create-universal-app.ts +++ b/build/darwin/create-universal-app.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// Void explanation - product-build-darwin-universal.yml runs this (create-universal-app.ts), then sign.ts + import * as path from 'path'; import * as fs from 'fs'; import * as minimatch from 'minimatch'; diff --git a/build/darwin/sign.ts b/build/darwin/sign.ts index 5b3413b7..9e605801 100644 --- a/build/darwin/sign.ts +++ b/build/darwin/sign.ts @@ -92,21 +92,21 @@ async function main(buildDir?: string): Promise { '-insert', 'NSAppleEventsUsageDescription', '-string', - 'An application in Visual Studio Code wants to use AppleScript.', + 'An application in Void wants to use AppleScript.', `${infoPlistPath}` ]); await spawn('plutil', [ '-replace', 'NSMicrophoneUsageDescription', '-string', - 'An application in Visual Studio Code wants to use the Microphone.', + 'An application in Void wants to use the Microphone.', `${infoPlistPath}` ]); await spawn('plutil', [ '-replace', 'NSCameraUsageDescription', '-string', - 'An application in Visual Studio Code wants to use the Camera.', + 'An application in Void wants to use the Camera.', `${infoPlistPath}` ]); } From 910ed7faa90c50b758e6be68bee3a9b5a5a5fd5e Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Tue, 7 Jan 2025 22:48:32 -0800 Subject: [PATCH 028/111] fix scrollbar bug --- .../contrib/void/browser/react/src/util/inputs.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 5b7c6d31..fb501900 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 @@ -322,12 +322,14 @@ export const VoidCodeEditor = ({ initValue, language, maxHeight, showScrollbars wordWrap: 'off', scrollbar: { + ignoreHorizontalScrollbarInContentHeight: true, alwaysConsumeMouseWheel: false, ...!SHOW_SCROLLBARS ? { vertical: 'hidden', - horizontal: 'hidden', verticalScrollbarSize: 0, - horizontalScrollbarSize: 0, + // horizontal: 'hidden', + // horizontalScrollbarSize: 0, + } : { verticalScrollbarSize: 8, horizontalScrollbarSize: 8, From ce634eadaa84b11069026af238bf6ee1775075a4 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 00:14:57 -0800 Subject: [PATCH 029/111] better styles --- .../react/src/sidebar-tsx/SidebarChat.tsx | 2 +- .../void/browser/react/src/util/inputs.tsx | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 280103a5..fb2096b9 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -366,7 +366,7 @@ export const SelectedFiles = ( initValue={selection.selectionStr!} language={getLanguageFromFileName(selection.fileURI.path)} maxHeight={100} - showScrollbars={false} + showScrollbars={true} />
} 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 fb501900..0d895d67 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 @@ -322,17 +322,19 @@ export const VoidCodeEditor = ({ initValue, language, maxHeight, showScrollbars wordWrap: 'off', scrollbar: { - ignoreHorizontalScrollbarInContentHeight: true, alwaysConsumeMouseWheel: false, - ...!SHOW_SCROLLBARS ? { + ...SHOW_SCROLLBARS ? { + vertical: 'auto', + verticalScrollbarSize: 8, + horizontal: 'auto', + horizontalScrollbarSize: 8, + } : { vertical: 'hidden', verticalScrollbarSize: 0, - // horizontal: 'hidden', - // horizontalScrollbarSize: 0, - - } : { - verticalScrollbarSize: 8, + horizontal: 'auto', horizontalScrollbarSize: 8, + ignoreHorizontalScrollbarInContentHeight: true, + }, }, scrollBeyondLastLine: false, From da247c6ed499940cd12602441f3db2ac94db1101 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 01:46:54 -0800 Subject: [PATCH 030/111] color --- .../react/src/quick-edit-tsx/QuickEditChat.tsx | 7 ++++++- .../src/sidebar-tsx/SidebarThreadSelector.tsx | 17 +++++++---------- .../src/void-settings-tsx/ModelDropdown.tsx | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 7efbe265..74941e1e 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -130,7 +130,12 @@ export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onC {/* input */}
+ @@[&_textarea]:!void-bg-transparent + @@[&_textarea]:!void-outline-none + @@[&_textarea]:!void-text-vscode-input-fg + @@[&_div.monaco-inputbox]:!void-outline-none + `} + > {/* text input */} { return <>Error: Threads not found. const pastThread = allThreads[threadId] - let btnStringArr: string[] = [] + let firstMsg:string|null = null + let secondMsg:string|null = null const firstMsgIdx = allThreads[threadId].messages.findIndex(msg => msg.role !== 'system' && !!msg.displayContent) ?? '' if (firstMsgIdx !== -1) - btnStringArr.push(truncate(allThreads[threadId].messages[firstMsgIdx].displayContent ?? '')) + firstMsg = truncate(allThreads[threadId].messages[firstMsgIdx].displayContent ?? '') else - btnStringArr.push('""') + firstMsg = '""' const secondMsgIdx = allThreads[threadId].messages.findIndex((msg, i) => msg.role !== 'system' && !!msg.displayContent && i > firstMsgIdx) ?? '' if (secondMsgIdx !== -1) - btnStringArr.push(truncate(allThreads[threadId].messages[secondMsgIdx].displayContent ?? '')) + secondMsg = truncate(allThreads[threadId].messages[secondMsgIdx].displayContent ?? '') - const numMessagesRemaining = allThreads[threadId].messages.filter((msg, i) => msg.role !== 'system' && !!msg.displayContent && i > secondMsgIdx).length - if (numMessagesRemaining > 0) - btnStringArr.push(numMessagesRemaining + '') - - const btnString = btnStringArr.join(' / ') + const numMessages = allThreads[threadId].messages.filter((msg, i) => msg.role !== 'system').length return ( ) })} diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 9a77c73c..c42c8334 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -32,7 +32,7 @@ const ModelSelectBox = ({ options, featureName }: { options: ModelOption[], feat let weChangedText = false return { if (weChangedText) return From 3621bb63f426138e1324567a87b7e6ceb7ea0058 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 02:58:27 -0800 Subject: [PATCH 031/111] wrap --- .../contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index fb2096b9..78ffcdea 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -411,7 +411,7 @@ const ChatBubble = ({ chatMessage, isLoading }: {
From b5dff4cf0f4431f20f0c28fc0609cee6a371464d Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 03:04:19 -0800 Subject: [PATCH 032/111] selection bug fix --- .../browser/react/src/sidebar-tsx/SidebarChat.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 78ffcdea..3e3f274f 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -284,8 +284,6 @@ export const SelectedFiles = ( const isThisSelectionOpened = !!(selection.selectionStr && selectionIsOpened[i]) const isThisSelectionAFile = selection.selectionStr === null - - return (
{ - e.stopPropagation(); + e.stopPropagation(); // don't open/close selection if (type !== 'staging') return; setStaging([...selections.slice(0, i), ...selections.slice(i + 1)]) setSelectionIsOpened(o => [...o.slice(0, i), ...o.slice(i + 1)]) @@ -361,7 +359,12 @@ export const SelectedFiles = (
{/* selection text */} {isThisSelectionOpened && -
+
{ + e.stopPropagation(); // don't focus input box + }} + > Date: Wed, 8 Jan 2025 16:30:36 -0800 Subject: [PATCH 033/111] minor comment --- build/gulpfile.vscode.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index d9aa780d..4d90766e 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -341,6 +341,8 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op this.emit('data', file); })); + + // Void - this is important, creates the product.json in .app let productJsonContents; const productJsonStream = gulp.src(['product.json'], { base: '.' }) .pipe(json({ commit, date: readISODate('out-build'), checksums, version })) From c4e4701dc3488ee0e0e6f0b94b5fe7257e8b4209 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Wed, 8 Jan 2025 17:12:39 -0800 Subject: [PATCH 034/111] placeholder --- .../void/browser/react/src/void-settings-tsx/Settings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f8d07f75..95b13787 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 @@ -452,7 +452,7 @@ const GeneralTab = () => {

Rules for AI

- + {/* placeholder: "Do not add ;'s. Do not change or delete spacing, formatting, or comments. Respond to queries in French when applicable. " */} } From f2f9b6cccae7a5fc881d8d3121d4fbccf10cefba Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 17:38:51 -0800 Subject: [PATCH 035/111] context fits in inputbox --- .../void/browser/react/src/sidebar-tsx/SidebarChat.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 3e3f274f..220d4197 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -170,7 +170,7 @@ const useResizeObserver = () => { type ButtonProps = ButtonHTMLAttributes -const DEFAULT_BUTTON_SIZE = 20; +const DEFAULT_BUTTON_SIZE = 22; export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Required>) => { return } @@ -628,6 +628,7 @@ export const SidebarChat = () => { transition-all duration-200 rounded-md bg-vscode-input-bg + max-h-[60vh] overflow-y-auto border border-vscode-commandcenter-inactive-border focus-within:border-vscode-commandcenter-active-border hover:border-vscode-commandcenter-active-border `} onKeyDown={(e) => { From 20e1b287f8344eb205ad08daa25de160d3427b9d Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Wed, 8 Jan 2025 19:32:19 -0800 Subject: [PATCH 036/111] scrollbar settings --- .../react/src/void-settings-tsx/Settings.tsx | 8 +++-- .../contrib/void/browser/voidSettingsPane.ts | 34 +++++++++---------- 2 files changed, 22 insertions(+), 20 deletions(-) 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 95b13787..af6edb50 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 @@ -11,6 +11,7 @@ import { VoidCheckBox, VoidInputBox, VoidSelectBox, VoidSwitch } from '../util/i import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' import { X, RefreshCw, Loader2, Check, MoveRight } from 'lucide-react' import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' +import { useScrollbarStyles } from '../util/useScrollbarStyles.js' const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { @@ -464,8 +465,11 @@ export const Settings = () => { const [tab, setTab] = useState('models') - return
-
+ const containerRef = useRef(null) + useScrollbarStyles(containerRef) + + return
+
diff --git a/src/vs/workbench/contrib/void/browser/voidSettingsPane.ts b/src/vs/workbench/contrib/void/browser/voidSettingsPane.ts index 51803ce2..684a7567 100644 --- a/src/vs/workbench/contrib/void/browser/voidSettingsPane.ts +++ b/src/vs/workbench/contrib/void/browser/voidSettingsPane.ts @@ -26,7 +26,6 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke import { mountVoidSettings } from './react/out/void-settings-tsx/index.js' import { Codicon } from '../../../../base/common/codicons.js'; import { IDisposable } from '../../../../base/common/lifecycle.js'; -import { DomScrollableElement } from '../../../../base/browser/ui/scrollbar/scrollableElement.js'; // refer to preferences.contribution.ts keybindings editor @@ -63,7 +62,7 @@ class VoidSettingsInput extends EditorInput { class VoidSettingsPane extends EditorPane { static readonly ID = 'workbench.test.myCustomPane'; - private _scrollbar: DomScrollableElement | undefined; + // private _scrollbar: DomScrollableElement | undefined; constructor( group: IEditorGroup, @@ -79,32 +78,31 @@ class VoidSettingsPane extends EditorPane { parent.style.height = '100%'; parent.style.width = '100%'; - const scrollableContent = document.createElement('div'); - scrollableContent.style.height = '100%'; - scrollableContent.style.width = '100%'; + const settingsElt = document.createElement('div'); + settingsElt.style.height = '100%'; + settingsElt.style.width = '100%'; - this._scrollbar = this._register(new DomScrollableElement(scrollableContent, {})); - parent.appendChild(this._scrollbar.getDomNode()); - this._scrollbar.scanDomNode(); + parent.appendChild(settingsElt); + + // this._scrollbar = this._register(new DomScrollableElement(scrollableContent, {})); + // parent.appendChild(this._scrollbar.getDomNode()); + // this._scrollbar.scanDomNode(); // Mount React into the scrollable content this.instantiationService.invokeFunction(accessor => { - const disposables: IDisposable[] | undefined = mountVoidSettings(scrollableContent, accessor); + const disposables: IDisposable[] | undefined = mountVoidSettings(settingsElt, accessor); - setTimeout(() => { // this is a complete hack and I don't really understand how scrollbar works here - this._scrollbar?.scanDomNode(); - }, 1000) + // setTimeout(() => { // this is a complete hack and I don't really understand how scrollbar works here + // this._scrollbar?.scanDomNode(); + // }, 1000) disposables?.forEach(d => this._register(d)); }); } layout(dimension: Dimension): void { - if (!this._scrollbar) return; - - this._scrollbar.getDomNode().style.height = `${dimension.height}px`; - this._scrollbar.getDomNode().style.width = `${dimension.width}px`; - this._scrollbar.scanDomNode(); - + // if (!settingsElt) return + // settingsElt.style.height = `${dimension.height}px`; + // settingsElt.style.width = `${dimension.width}px`; } From a08e6078f2487c59584f845f4909e332bec0ed5b Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Wed, 8 Jan 2025 19:32:41 -0800 Subject: [PATCH 037/111] reject diffarea and cleanup --- .../void/browser/inlineDiffsService.ts | 103 +++++++++++++----- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index 2f85ffcd..751b0fd5 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -917,16 +917,11 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { const uri = editor.getModel()?.uri if (!uri) return - // check if there's overlap with any other ctrlKZones and if so, focus them - for (const diffareaid of this.diffAreasOfURI[uri.fsPath]) { - const diffArea = this.diffAreaOfId[diffareaid] - if (!diffArea) continue - if (diffArea.type !== 'CtrlKZone') continue - const noOverlap = diffArea.startLine > endLine || diffArea.endLine < startLine - if (!noOverlap) { - setTimeout(() => diffArea._mountInfo?.inputBoxRef.current?.focus(), 0) - return - } + // check if there's overlap with any other ctrlKZone and if so, focus it + const overlappingCtrlKZone = this._findOverlappingDiffArea({ startLine, endLine, uri, filter: (diffArea) => diffArea.type === 'CtrlKZone' }) + if (overlappingCtrlKZone) { + setTimeout(() => (overlappingCtrlKZone as CtrlKZone)._mountInfo?.inputBoxRef.current?.focus(), 0) + return } const { onFinishEdit } = this._addToHistory(uri) @@ -947,6 +942,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { return ctrlKZone.diffareaid } + // _remove means delete and also add to history public removeCtrlKZone({ diffareaid }: { diffareaid: number }) { const ctrlKZone = this.diffAreaOfId[diffareaid] if (!ctrlKZone) return @@ -969,6 +965,19 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { + private _findOverlappingDiffArea({ startLine, endLine, uri, filter }: { startLine: number, endLine: number, uri: URI, filter?: (diffArea: DiffArea) => boolean }): DiffArea | null { + // check if there's overlap with any other diffAreas and return early if there is + for (const diffareaid of this.diffAreasOfURI[uri.fsPath]) { + const diffArea = this.diffAreaOfId[diffareaid] + if (!diffArea) continue + if (!filter?.(diffArea)) continue + const noOverlap = diffArea.startLine > endLine || diffArea.endLine < startLine + if (!noOverlap) { + return diffArea + } + } + return null + } private _initializeStartApplying(opts: StartApplyingOpts): DiffZone | undefined { @@ -986,7 +995,8 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { if (!uri_) return uri = uri_ - // __TODO__ reject all diffs in the diff area + // reject all diffs on this URI, adding to history + this.removeDiffAreas({ uri, behavior: 'reject' }) // in ctrl+L the start and end lines are the full document const numLines = this._getNumLines(uri) @@ -995,15 +1005,10 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { endLine = numLines // check if there's overlap with any other diffAreas and return early if there is - for (const diffareaid of this.diffAreasOfURI[uri.fsPath]) { - const da2 = this.diffAreaOfId[diffareaid] - if (!da2) continue - const noOverlap = da2.startLine > endLine || da2.endLine < startLine - if (!noOverlap) { - // TODO add a message here that says this to the user too - console.error('Not diffing because found overlap:', this.diffAreasOfURI[uri.fsPath], startLine, endLine) - return - } + if (this._findOverlappingDiffArea({ startLine, endLine, uri })) { + // TODO add a message here that says this to the user too + console.error('Not diffing because found overlap:', this.diffAreasOfURI[uri.fsPath], startLine, endLine) + return } userMessage = opts.userMessage @@ -1039,14 +1044,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { const { onFinishEdit } = this._addToHistory(uri) - // // for Ctrl+K, delete the current ctrlKZone, swapping it out for a diffZone - // if (featureName === 'Ctrl+K') { - // const { diffareaid } = opts - // const ctrlKZone = this.diffAreaOfId[diffareaid] - // this._deleteDiffArea(ctrlKZone) - // } - - // TODO ctrl+K case should be replaced with an actual check for model.isFIM + // __TODO__ ctrl+K should use Ollama's FIM method. Also, modelWasTrainedOnFIM should not be a thing const modelWasTrainedOnFIM = featureName === 'Ctrl+K' ? false : false const modelFimTags = defaultFimTags @@ -1187,6 +1185,55 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { + // public removeDiffZone(diffZone: DiffZone, behavior: 'reject' | 'accept') { + // const uri = diffZone._URI + // const { onFinishEdit } = this._addToHistory(uri) + + // if (behavior === 'reject') this._revertAndDeleteDiffZone(diffZone) + // else if (behavior === 'accept') this._deleteDiffZone(diffZone) + + // this._refreshStylesAndDiffsInURI(uri) + // onFinishEdit() + // } + + private _revertAndDeleteDiffZone(diffZone: DiffZone) { + const uri = diffZone._URI + + const writeText = diffZone.originalCode + const toRange: IRange = { startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER } + this._writeText(uri, writeText, toRange, { shouldRealignDiffAreas: true }) + + this._deleteDiffZone(diffZone) + } + + + // remove a batch of diffareas all at once (and handle accept/reject of their diffs) + public removeDiffAreas({ uri, behavior }: { uri: URI, behavior: 'reject' | 'accept' }) { + + const diffareaids = this.diffAreasOfURI[uri.fsPath] + if (diffareaids.size === 0) return // do nothing + + const { onFinishEdit } = this._addToHistory(uri) + + for (const diffareaid of diffareaids) { + const diffArea = this.diffAreaOfId[diffareaid] + if (!diffArea) continue + + if (diffArea.type == 'DiffZone') { + if (behavior === 'reject') this._revertAndDeleteDiffZone(diffArea) + else if (behavior === 'accept') this._deleteDiffZone(diffArea) + } + else if (diffArea.type === 'CtrlKZone') { + this._deleteCtrlKZone(diffArea) + } + } + + this._refreshStylesAndDiffsInURI(uri) + onFinishEdit() + } + + + // called on void.acceptDiff public async acceptDiff({ diffid }: { diffid: number }) { From ec659036926c162fbbb4413fc196c4ec19fd45b1 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Wed, 8 Jan 2025 21:07:54 -0800 Subject: [PATCH 038/111] misc --- .../void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 74941e1e..953c9f13 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -104,10 +104,8 @@ export const QuickEditChat = ({ diffareaid, onGetInputBox, onUserUpdateText, onC } }} onSubmit={(e) => { - if (isDisabled) { - // __TODO__ show disabled + if (isDisabled) return - } console.log('submit!') onSubmit(e) }} From 865c34f2822909dfdd0912bac9ae74430ab4a2f1 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 22:06:58 -0800 Subject: [PATCH 039/111] new model dropdown draft --- .../void/common/voidSettingsService.ts | 8 +- .../react/src/sidebar-tsx/SidebarChat.tsx | 2 +- .../void/browser/react/src/util/inputs.tsx | 103 +++++++++++++++++- .../src/void-settings-tsx/ModelDropdown.tsx | 70 +++++++----- .../react/src/void-settings-tsx/Settings.tsx | 4 +- 5 files changed, 149 insertions(+), 38 deletions(-) diff --git a/src/vs/platform/void/common/voidSettingsService.ts b/src/vs/platform/void/common/voidSettingsService.ts index 895d3f6b..34a4ce80 100644 --- a/src/vs/platform/void/common/voidSettingsService.ts +++ b/src/vs/platform/void/common/voidSettingsService.ts @@ -29,7 +29,7 @@ type SetModelSelectionOfFeatureFn = ( type SetFeatureFlagFn = (flagName: FeatureFlagName, newVal: boolean) => void; -export type ModelOption = { text: string, value: ModelSelection } +export type ModelOption = { name: string, selection: ModelSelection } @@ -69,7 +69,7 @@ let _computeModelOptions = (settingsOfProvider: SettingsOfProvider) => { if (!providerConfig._enabled) continue // if disabled, don't display model options for (const { modelName, isHidden } of providerConfig.models) { if (isHidden) continue - modelOptions.push({ text: `${modelName} (${providerName})`, value: { providerName, modelName } }) + modelOptions.push({ name: `${modelName} (${providerName})`, selection: { providerName, modelName } }) } } return modelOptions @@ -169,11 +169,11 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService { for (const featureName of featureNames) { const currentSelection = newModelSelectionOfFeature[featureName] - const selnIdx = currentSelection === null ? -1 : newModelsList.findIndex(m => modelSelectionsEqual(m.value, currentSelection)) + const selnIdx = currentSelection === null ? -1 : newModelsList.findIndex(m => modelSelectionsEqual(m.selection, currentSelection)) if (selnIdx === -1) { if (newModelsList.length !== 0) - this.setModelSelectionOfFeature(featureName, newModelsList[0].value, { doNotApplyEffects: true }) + this.setModelSelectionOfFeature(featureName, newModelsList[0].selection, { doNotApplyEffects: true }) else this.setModelSelectionOfFeature(featureName, null, { doNotApplyEffects: true }) } diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 220d4197..31c9bafe 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -628,7 +628,7 @@ export const SidebarChat = () => { transition-all duration-200 rounded-md bg-vscode-input-bg - max-h-[60vh] overflow-y-auto + max-h-[80vh] overflow-y-auto border border-vscode-commandcenter-inactive-border focus-within:border-vscode-commandcenter-active-border hover:border-vscode-commandcenter-active-border `} onKeyDown={(e) => { 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 0d895d67..09df6ef8 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 @@ -3,7 +3,7 @@ * Void Editor additions licensed under the AGPL 3.0 License. *--------------------------------------------------------------------------------------------*/ -import React, { useCallback, useEffect, useRef } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { IInputBoxStyles, InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'; import { defaultCheckboxStyles, defaultInputBoxStyles, defaultSelectBoxStyles } from '../../../../../../../platform/theme/browser/defaultStyles.js'; import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'; @@ -13,6 +13,7 @@ import { Checkbox } from '../../../../../../../base/browser/ui/toggle/toggle.js' import { CodeEditorWidget } from '../../../../../../../editor/browser/widget/codeEditor/codeEditorWidget.js' import { useAccessor } from './services.js'; import { ScrollableElement } from '../../../../../../../base/browser/ui/scrollbar/scrollableElement.js'; +import { ModelOption } from '../../../../../../../platform/void/common/voidSettingsService.js'; // type guard @@ -198,7 +199,95 @@ export const VoidCheckBox = ({ label, value, onClick, className }: { label: stri } -export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectBoxRef, options, className }: { +export const VoidCustomSelectBox = ({ options, selectedOption, onChangeOption, getOptionName, getOptionsEqual }: { options: T[], selectedOption?: T, onChangeOption: (newValue: T) => void, getOptionName: (option: T) => string, getOptionsEqual: (a: T, b: T) => boolean }) => { + + const [isOpen, setIsOpen] = useState(false); + const dropdownRef = useRef(null); + + if (!selectedOption) { + selectedOption = options[0] + } + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + + return ( +
+ {/* Select Button */} + + + {/* Dropdown Menu */} + {isOpen && ( +
+ {options.map((option) => { + + const thisOptionIsSelected = getOptionsEqual(option, selectedOption) + const optionName = getOptionName(option) + + return ( +
{ + onChangeOption(option); + setIsOpen(false); + }} + > +
+ {thisOptionIsSelected && ( + + + + )} +
+ {optionName} +
+ ) + })} +
+ )} +
+ ); +}; + + + +export const _VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectBoxRef, options, className }: { onChangeSelection: (value: T) => void; onCreateInstance?: ((instance: SelectBox) => void | IDisposable[]); selectBoxRef?: React.MutableRefObject; @@ -211,9 +300,13 @@ export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectB let containerRef = useRef(null); return { containerRef.current = container @@ -222,7 +315,7 @@ export const VoidSelectBox = ({ onChangeSelection, onCreateInstance, selectB options.map(opt => ({ text: opt.text })), defaultIndex, contextViewProvider, - defaultSelectBoxStyles + defaultSelectBoxStyles, ] as const; }, [containerRef, options, contextViewProvider])} diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index c42c8334..709e9e1a 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -6,7 +6,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { FeatureName, featureNames, ModelSelection, modelSelectionsEqual, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js' import { useSettingsState, useRefreshModelState, useAccessor } from '../util/services.js' -import { VoidSelectBox } from '../util/inputs.js' +import { _VoidSelectBox, VoidCustomSelectBox } from '../util/inputs.js' import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js' import { IconWarning } from '../sidebar-tsx/SidebarChat.js' import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js' @@ -17,43 +17,61 @@ import { ModelOption } from '../../../../../../../platform/void/common/voidSetti const optionsEqual = (m1: ModelOption[], m2: ModelOption[]) => { if (m1.length !== m2.length) return false for (let i = 0; i < m1.length; i++) { - if (!modelSelectionsEqual(m1[i].value, m2[i].value)) return false + if (!modelSelectionsEqual(m1[i].selection, m2[i].selection)) return false } return true } - - const ModelSelectBox = ({ options, featureName }: { options: ModelOption[], featureName: FeatureName }) => { const accessor = useAccessor() - const voidSettingsService = accessor.get('IVoidSettingsService') - let weChangedText = false + const selection = voidSettingsService.state.modelSelectionOfFeature[featureName] + const selectedOption = selection ? voidSettingsService.state._modelOptions.find(v => modelSelectionsEqual(v.selection, selection)) : options[0] - return { + voidSettingsService.setModelSelectionOfFeature(featureName, newOption.selection) + }, [voidSettingsService, featureName]) + + return { - if (weChangedText) return - voidSettingsService.setModelSelectionOfFeature(featureName, newVal) - }, [voidSettingsService, featureName])} - // we are responsible for setting the initial state here. always sync instance when state changes. - onCreateInstance={useCallback((instance: SelectBox) => { - const syncInstance = () => { - const modelsListRef = voidSettingsService.state._modelOptions // as a ref - const settingsAtProvider = voidSettingsService.state.modelSelectionOfFeature[featureName] - const selectionIdx = settingsAtProvider === null ? -1 : modelsListRef.findIndex(v => modelSelectionsEqual(v.value, settingsAtProvider)) - weChangedText = true - instance.select(selectionIdx === -1 ? 0 : selectionIdx) - weChangedText = false - } - syncInstance() - const disposable = voidSettingsService.onDidChangeState(syncInstance) - return [disposable] - }, [voidSettingsService, featureName])} + selectedOption={selectedOption} + onChangeOption={onChangeOption} + getOptionName={(option) => option.name} + getOptionsEqual={(a, b) => optionsEqual([a], [b])} + /> } +// const ModelSelectBox = ({ options, featureName }: { options: ModelOption[], featureName: FeatureName }) => { +// const accessor = useAccessor() + +// const voidSettingsService = accessor.get('IVoidSettingsService') + +// let weChangedText = false + +// return { +// if (weChangedText) return +// voidSettingsService.setModelSelectionOfFeature(featureName, newVal) +// }, [voidSettingsService, featureName])} +// // we are responsible for setting the initial state here. always sync instance when state changes. +// onCreateInstance={useCallback((instance: SelectBox) => { +// const syncInstance = () => { +// const modelsListRef = voidSettingsService.state._modelOptions // as a ref +// const settingsAtProvider = voidSettingsService.state.modelSelectionOfFeature[featureName] +// const selectionIdx = settingsAtProvider === null ? -1 : modelsListRef.findIndex(v => modelSelectionsEqual(v.value, settingsAtProvider)) +// weChangedText = true +// instance.select(selectionIdx === -1 ? 0 : selectionIdx) +// weChangedText = false +// } +// syncInstance() +// const disposable = voidSettingsService.onDidChangeState(syncInstance) +// return [disposable] +// }, [voidSettingsService, featureName])} +// /> +// } const MemoizedModelSelectBox = ({ featureName }: { featureName: FeatureName }) => { const settingsState = useSettingsState() 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 af6edb50..627d7cc7 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 @@ -7,7 +7,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js' import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, featureFlagNames, displayInfoOfFeatureFlag, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, defaultProviderSettings, nonlocalProviderNames, localProviderNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' -import { VoidCheckBox, VoidInputBox, VoidSelectBox, VoidSwitch } from '../util/inputs.js' +import { VoidCheckBox, VoidInputBox, _VoidSelectBox, VoidSwitch } from '../util/inputs.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' import { X, RefreshCw, Loader2, Check, MoveRight } from 'lucide-react' import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' @@ -98,7 +98,7 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => { {/* provider */}
- { providerNameRef.current = providerOptions[0].value }, [providerOptions])} // initialize state onChangeSelection={useCallback((providerName: ProviderName) => { providerNameRef.current = providerName }, [])} options={providerOptions} From e4953057ef25e692c58e00e5236e908590ee4260 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 8 Jan 2025 22:20:18 -0800 Subject: [PATCH 040/111] color improvements --- .../void/browser/react/src/util/inputs.tsx | 57 +++++++++++++------ 1 file changed, 41 insertions(+), 16 deletions(-) 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 09df6ef8..982469e9 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 @@ -199,13 +199,25 @@ export const VoidCheckBox = ({ label, value, onClick, className }: { label: stri } -export const VoidCustomSelectBox = ({ options, selectedOption, onChangeOption, getOptionName, getOptionsEqual }: { options: T[], selectedOption?: T, onChangeOption: (newValue: T) => void, getOptionName: (option: T) => string, getOptionsEqual: (a: T, b: T) => boolean }) => { - +export const VoidCustomSelectBox = ({ + options, + selectedOption, + onChangeOption, + getOptionName, + getOptionsEqual +}: { + options: T[], + selectedOption?: T, + onChangeOption: (newValue: T) => void, + getOptionName: (option: T) => string, + getOptionsEqual: (a: T, b: T) => boolean +}) => { const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); + const buttonRef = useRef(null); if (!selectedOption) { - selectedOption = options[0] + selectedOption = options[0]; } useEffect(() => { @@ -218,18 +230,27 @@ export const VoidCustomSelectBox = ({ options, selectedOption, on return () => document.removeEventListener('mousedown', handleClickOutside); }, []); + // Calculate dropdown position + const getDropdownPosition = () => { + if (!buttonRef.current) return { top: 0, left: 0 }; + const rect = buttonRef.current.getBoundingClientRect(); + return { + top: rect.bottom + window.scrollY, + left: rect.left + window.scrollX, + minWidth: rect.width // Ensure dropdown is at least as wide as the button + }; + }; return ( -
+
{/* Select Button */} + useEffect(() => { + if (isOpen) { + updatePosition(); + window.addEventListener('scroll', updatePosition, true); + window.addEventListener('resize', updatePosition); - {/* Dropdown Menu */} - {isOpen && ( -
- {options.map((option) => { - const thisOptionIsSelected = getOptionsEqual(option, selectedOption); - const optionName = getOptionName(option); + return () => { + window.removeEventListener('scroll', updatePosition, true); + window.removeEventListener('resize', updatePosition); + }; + } + }, [isOpen]); - return ( -
{ - onChangeOption(option); - setIsOpen(false); - }} - > -
- {thisOptionIsSelected && ( - - - - )} -
- {optionName} -
- ); - })} -
- )} -
- ); + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (containerRef.current && !containerRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + }; + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + } + }, [isOpen]); + + return ( +
+ {/* Select Button */} + + + {/* Dropdown Menu */} + {isOpen && ( +
+ {options.map((option) => { + const thisOptionIsSelected = getOptionsEqual(option, selectedOption); + const optionName = getOptionName(option); + + return ( +
{ + onChangeOption(option); + setIsOpen(false); + }} + > +
+ {thisOptionIsSelected && ( + + + + )} +
+ {optionName} +
+ ); + })} +
+ )} +
+ ); }; diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 709e9e1a..99428771 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -39,7 +39,7 @@ const ModelSelectBox = ({ options, featureName }: { options: ModelOption[], feat onChangeOption={onChangeOption} getOptionName={(option) => option.name} getOptionsEqual={(a, b) => optionsEqual([a], [b])} - + className={`text-xs text-void-fg-3 px-1`} /> } // const ModelSelectBox = ({ options, featureName }: { options: ModelOption[], featureName: FeatureName }) => { 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 627d7cc7..692296f1 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 @@ -7,7 +7,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js' import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, featureFlagNames, displayInfoOfFeatureFlag, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, defaultProviderSettings, nonlocalProviderNames, localProviderNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' -import { VoidCheckBox, VoidInputBox, _VoidSelectBox, VoidSwitch } from '../util/inputs.js' +import { VoidCheckBox, VoidInputBox, _VoidSelectBox, VoidSwitch, VoidCustomSelectBox } from '../util/inputs.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' import { X, RefreshCw, Loader2, Check, MoveRight } from 'lucide-react' import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' @@ -85,28 +85,37 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => { const settingsState = useSettingsState() - const providerNameRef = useRef(null) + // const providerNameRef = useRef(null) + const [providerName, setProviderName] = useState(null) + const modelNameRef = useRef(null) const [errorString, setErrorString] = useState('') - const providerOptions = useMemo(() => providerNames.map(providerName => ({ text: displayInfoOfProviderName(providerName).title, value: providerName })), [providerNames]) - return <>
{/* provider */} -
- <_VoidSelectBox + setProviderName(pn)} + getOptionName={(pn) => pn ? displayInfoOfProviderName(pn).title : '(null)'} + getOptionsEqual={(a, b) => a === b} + className={`max-w-40 w-full border border-void-border-2 bg-void-bg-1 text-void-fg-3 text-root + py-[4px] px-[6px] + `} + arrowTouchesText={false} + /> + {/* <_VoidSelectBox onCreateInstance={useCallback(() => { providerNameRef.current = providerOptions[0].value }, [providerOptions])} // initialize state onChangeSelection={useCallback((providerName: ProviderName) => { providerNameRef.current = providerName }, [])} options={providerOptions} - /> -
+ /> */} {/* model */} -
+
{ modelNameRef.current = modelName }, [])} @@ -119,7 +128,6 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => { + return ( +
+ {/* Select Button */} + - {/* Dropdown Menu */} - {isOpen && ( -
- {options.map((option) => { - const thisOptionIsSelected = getOptionsEqual(option, selectedOption); - const optionName = getOptionName(option); + {/* Dropdown Menu */} + {isOpen && ( +
+ {options.map((option) => { + const thisOptionIsSelected = getOptionsEqual(option, selectedOption); + const optionName = getOptionName(option); - return ( -
{ - onChangeOption(option); - setIsOpen(false); - }} - > -
- {thisOptionIsSelected && ( - - - - )} -
- {optionName} -
- ); - })} -
- )} -
- ); + return ( +
{ + onChangeOption(option); + setIsOpen(false); + }} + > +
+ {thisOptionIsSelected && ( + + + + )} +
+ {optionName} +
+ ); + })} +
+ )} +
+ ); }; From 07d87c8bf009c846d983bc6acbe28bf3d267e429 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Thu, 9 Jan 2025 01:56:36 -0800 Subject: [PATCH 043/111] styles --- .../void/browser/react/src/void-settings-tsx/Settings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 692296f1..54c99f2c 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 @@ -210,7 +210,7 @@ export const ModelDump = () => { > {/* left part is width:full */}
- {isNewProviderName ? displayInfoOfProviderName(providerName).title : ''} + {isNewProviderName ? displayInfoOfProviderName(providerName).title : ''} {modelName} {/* {`${modelName} (${providerName})`} */}
From e132c87792897a418f11cbe7bb55378be722e899 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Thu, 9 Jan 2025 02:15:52 -0800 Subject: [PATCH 044/111] generalize for @andrew --- .../src/void-settings-tsx/ModelDropdown.tsx | 17 ++++++++--------- .../void/browser/react/tailwind.config.js | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 99428771..5ee372c8 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -90,7 +90,7 @@ const MemoizedModelSelectBox = ({ featureName }: { featureName: FeatureName }) = } -const DummySelectBox = () => { +const WarningBox = ({ text, className }: { text: string, className?: string }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') @@ -101,22 +101,21 @@ const DummySelectBox = () => { return
- Provider required + {text}
// return { export const ModelDropdown = ({ featureName }: { featureName: FeatureName }) => { const settingsState = useSettingsState() return <> - {settingsState._modelOptions.length === 0 ? : } + {settingsState._modelOptions.length === 0 ? : } } diff --git a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js index 364f66a7..e99703ba 100644 --- a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js +++ b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js @@ -34,7 +34,7 @@ module.exports = { "void-fg-1": "var(--vscode-editor-foreground)", "void-fg-2": "var(--vscode-input-foreground)", "void-fg-3": "var(--vscode-input-placeholderForeground)", - "void-warning": "var(--vscode-charts-orange)", + "void-warning": "var(--vscode-charts-yellow)", "void-border-1": "var(--vscode-commandCenter-activeBorder)", "void-border-2": "var(--vscode-commandCenter-border)", From 037f9f38e57d4342e5340cc5738d8500f17f8164 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 9 Jan 2025 02:13:06 -0800 Subject: [PATCH 045/111] one click switch --- .../parts/editor/editorGroupWatermark.ts | 82 +++++----- .../contrib/void/browser/media/void.css | 4 + .../void/browser/react/src/util/inputs.tsx | 7 + .../void/browser/react/src/util/services.tsx | 8 +- .../react/src/void-settings-tsx/Settings.tsx | 153 +++++++++++++----- 5 files changed, 174 insertions(+), 80 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts index 158e6072..787632ae 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts @@ -167,17 +167,17 @@ export class EditorGroupWatermark extends Disposable { // .filter(entry => !!this.keybindingService.lookupKeybinding(entry.id)); this.clear(); - const box = append(this.shortcuts, $('.watermark-box')); - const boxBelow = append(this.shortcuts, $('')) - boxBelow.style.display = 'flex' - boxBelow.style.flex = 'row' - boxBelow.style.justifyContent = 'center' + const voidIconBox = append(this.shortcuts, $('.watermark-box')); + const recentsBox = append(this.shortcuts, $('div')); + recentsBox.style.display = 'flex' + recentsBox.style.flex = 'row' + recentsBox.style.justifyContent = 'center' const update = async () => { - clearNode(box); - clearNode(boxBelow); + clearNode(voidIconBox); + clearNode(recentsBox); this.currentDisposables.forEach(label => label.dispose()); this.currentDisposables.clear(); @@ -187,13 +187,14 @@ export class EditorGroupWatermark extends Disposable { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { // Open a folder - const button = h('button') - button.root.classList.add('void-watermark-button') - button.root.style.display = 'block' - button.root.style.marginLeft = 'auto' - button.root.style.marginRight = 'auto' - button.root.textContent = 'Open a folder' - button.root.onclick = () => { + const openFolderButton = h('button') + openFolderButton.root.classList.add('void-watermark-button') + openFolderButton.root.style.display = 'block' + openFolderButton.root.style.marginLeft = 'auto' + openFolderButton.root.style.marginRight = 'auto' + openFolderButton.root.style.marginBottom = '16px' + openFolderButton.root.textContent = 'Open a folder' + openFolderButton.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); @@ -201,7 +202,7 @@ export class EditorGroupWatermark extends Disposable { // this.commandService.executeCommand(isMacintosh ? 'workbench.action.files.openFileFolder' : 'workbench.action.files.openFolder'); // } } - box.appendChild(button.root); + voidIconBox.appendChild(openFolderButton.root); // Recents @@ -211,13 +212,8 @@ export class EditorGroupWatermark extends Disposable { if (recentlyOpened.length !== 0) { - const span = $('div') - span.textContent = 'Recent' - span.style.fontWeight = '500' - box.append(span) - - box.append( - ...recentlyOpened.map(w => { + voidIconBox.append( + ...recentlyOpened.map((w, i) => { let fullPath: string; let windowOpenable: IWindowOpenable; @@ -234,14 +230,13 @@ export class EditorGroupWatermark extends Disposable { const { name, parentPath } = splitRecentLabel(fullPath); - const li = $('li'); - const link = $('span'); - link.classList.add('void-link') + const linkSpan = $('span'); + linkSpan.classList.add('void-link') + linkSpan.style.display = 'flex' + linkSpan.style.gap = '4px' + linkSpan.style.padding = '8px' - 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 => { + linkSpan.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 @@ -249,29 +244,30 @@ export class EditorGroupWatermark extends Disposable { e.preventDefault(); e.stopPropagation(); }); - li.appendChild(link); - const span = $('span'); - span.style.paddingLeft = '4px'; - span.classList.add('path'); - span.classList.add('detail'); - span.innerText = parentPath; - span.title = fullPath; - li.appendChild(span); + const nameSpan = $('span'); + nameSpan.innerText = name; + nameSpan.title = fullPath; + linkSpan.appendChild(nameSpan); - return li + const dirSpan = $('span'); + dirSpan.style.paddingLeft = '4px'; + dirSpan.innerText = parentPath; + dirSpan.title = fullPath; + + linkSpan.appendChild(dirSpan); + + return linkSpan }).filter(v => !!v) ) } - - } else { // show them Void keybindings const keys = this.keybindingService.lookupKeybinding(VOID_CTRL_L_ACTION_ID); - const dl = append(box, $('dl')); + const dl = append(voidIconBox, $('dl')); const dt = append(dl, $('dt')); dt.textContent = 'Chat' const dd = append(dl, $('dd')); @@ -282,7 +278,7 @@ export class EditorGroupWatermark extends Disposable { const keys2 = this.keybindingService.lookupKeybinding(VOID_CTRL_K_ACTION_ID); - const dl2 = append(box, $('dl')); + const dl2 = append(voidIconBox, $('dl')); const dt2 = append(dl2, $('dt')); dt2.textContent = 'Quick Edit' const dd2 = append(dl2, $('dd')); @@ -292,7 +288,7 @@ export class EditorGroupWatermark extends Disposable { this.currentDisposables.add(label2); const keys3 = this.keybindingService.lookupKeybinding('workbench.action.openGlobalKeybindings'); - const button3 = append(boxBelow, $('button')); + const button3 = append(recentsBox, $('button')); button3.textContent = 'Void Settings' button3.style.display = 'block' button3.style.marginLeft = 'auto' diff --git a/src/vs/workbench/contrib/void/browser/media/void.css b/src/vs/workbench/contrib/void/browser/media/void.css index 41177002..f3a1d4b8 100644 --- a/src/vs/workbench/contrib/void/browser/media/void.css +++ b/src/vs/workbench/contrib/void/browser/media/void.css @@ -70,6 +70,10 @@ .void-link { color: #3b82f6; cursor: pointer; + transition: all 0.2s ease; +} +.void-link:hover { + opacity: 80%; } 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 15d3c48c..5fecb79b 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 @@ -567,6 +567,13 @@ export const VoidCodeEditor = ({ initValue, language, maxHeight, showScrollbars } +export const VoidButton = ({ children, onClick }: { children: React.ReactNode; onClick: () => void }) => { + return +} + // export const VoidScrollableElt = ({ options, children }: { options: ScrollableElementCreationOptions, children: React.ReactNode }) => { // const instanceRef = useRef(null); // const [childrenPortal, setChildrenPortal] = useState(null) diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx index c083216a..edf0d820 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx @@ -41,7 +41,9 @@ import { ILanguageConfigurationService } from '../../../../../../../editor/commo import { ILanguageFeaturesService } from '../../../../../../../editor/common/services/languageFeatures.js' import { ILanguageDetectionService } from '../../../../../../services/languageDetection/common/languageDetectionWorkerService.js' import { IKeybindingService } from '../../../../../../../platform/keybinding/common/keybinding.js' - +import { IEnvironmentService } from '../../../../../../../platform/environment/common/environment.js' +import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js' +import { IPathService } from '../../../../../../../workbench/services/path/common/pathService.js' // normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes @@ -176,6 +178,10 @@ const getReactAccessor = (accessor: ServicesAccessor) => { ILanguageFeaturesService: accessor.get(ILanguageFeaturesService), IKeybindingService: accessor.get(IKeybindingService), + IEnvironmentService: accessor.get(IEnvironmentService), + IConfigurationService: accessor.get(IConfigurationService), + IPathService: accessor.get(IPathService), + } as const return reactAccessor } 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 54c99f2c..21986a0f 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 @@ -7,11 +7,14 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js' import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, featureFlagNames, displayInfoOfFeatureFlag, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, defaultProviderSettings, nonlocalProviderNames, localProviderNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' -import { VoidCheckBox, VoidInputBox, _VoidSelectBox, VoidSwitch, VoidCustomSelectBox } from '../util/inputs.js' +import { VoidButton, VoidCheckBox, VoidCustomSelectBox, VoidInputBox, VoidSwitch } from '../util/inputs.js' import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js' import { X, RefreshCw, Loader2, Check, MoveRight } from 'lucide-react' import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' import { useScrollbarStyles } from '../util/useScrollbarStyles.js' +import { isWindows, isLinux, isMacintosh } from '../../../../../../../base/common/platform.js' +import { URI } from '../../../../../../../base/common/uri.js' +import { env } from '../../../../../../../base/common/process.js' const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { @@ -115,7 +118,7 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => { /> */} {/* model */} -
+
{ modelNameRef.current = modelName }, [])} @@ -125,36 +128,33 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => { {/* button */}
- + }} + >Add model
{!errorString ? null :
{errorString}
} - -
@@ -167,10 +167,7 @@ const AddModelMenuFull = () => { return
{open ? { setOpen(false) }} /> - : + : setOpen(true)}>Add Model }
} @@ -432,11 +429,94 @@ export const FeaturesTab = () => { +// https://github.com/VSCodium/vscodium/blob/master/docs/index.md#migrating-from-visual-studio-code-to-vscodium +// https://code.visualstudio.com/docs/editor/extension-marketplace#_where-are-extensions-installed +type TransferFilesInfo = { from: URI, to: URI }[] +const transferTheseFilesOfOS = (os: 'mac' | 'windows' | 'linux' | null): TransferFilesInfo => { + if (os === null) + throw new Error(`One-click switch is not possible in this environment.`) + if (os === 'mac') { + const homeDir = env['HOME'] + if (!homeDir) throw new Error(`$HOME not found`) + return [{ + from: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, 'Library', 'Application Support', 'Code', 'User', 'settings.json'), + to: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, 'Library', 'Application Support', 'Void', 'User', 'settings.json'), + }, { + from: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, 'Library', 'Application Support', 'Code', 'User', 'keybindings.json'), + to: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, 'Library', 'Application Support', 'Void', 'User', 'keybindings.json'), + }, { + from: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.vscode', 'extensions'), + to: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.void-editor', 'extensions'), + }] + } + if (os === 'linux') { + const homeDir = env['HOME'] + if (!homeDir) throw new Error(`variable for $HOME location not found`) + return [{ + from: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.config', 'Code', 'User', 'settings.json'), + to: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.config', 'Void', 'User', 'settings.json'), + }, { + from: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.config', 'Code', 'User', 'keybindings.json'), + to: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.config', 'Void', 'User', 'keybindings.json'), + }, { + from: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.vscode', 'extensions'), + to: URI.joinPath(URI.from({ scheme: 'file' }), homeDir, '.void-editor', 'extensions'), + }] + } + if (os === 'windows') { + const appdata = env['APPDATA'] + if (!appdata) throw new Error(`variable for %APPDATA% location not found`) + const userprofile = env['USERPROFILE'] + if (!userprofile) throw new Error(`variable for %USERPROFILE% location not found`) + + return [{ + from: URI.joinPath(URI.from({ scheme: 'file' }), appdata, 'Code', 'User', 'settings.json'), + to: URI.joinPath(URI.from({ scheme: 'file' }), appdata, 'Void', 'User', 'settings.json'), + }, { + from: URI.joinPath(URI.from({ scheme: 'file' }), appdata, 'Code', 'User', 'keybindings.json'), + to: URI.joinPath(URI.from({ scheme: 'file' }), appdata, 'Void', 'User', 'keybindings.json'), + }, { + from: URI.joinPath(URI.from({ scheme: 'file' }), userprofile, '.vscode', 'extensions'), + to: URI.joinPath(URI.from({ scheme: 'file' }), userprofile, '.void-editor', 'extensions'), + }] + } + + throw new Error(`os '${os}' not recognized`) +} + +const os = null//isWindows ? 'windows' : isMacintosh ? 'mac' : isLinux ? 'linux' : null +let transferTheseFiles: TransferFilesInfo = [] +let transferError: string | null = null + +try { transferTheseFiles = transferTheseFilesOfOS(os) } +catch (e) { transferError = e + '' } const OneClickSwitch = () => { + const accessor = useAccessor() + const fileService = accessor.get('IFileService') + if (transferTheseFiles.length === 0) + return <> +
One-click transfer not available.
+
{transferError}
+ + + const onClick = async () => { + for (let { from, to } of transferTheseFiles) { + console.log('transferring', from, to) + // not sure if this can fail, just wrapping it with try/catch for now + try { await fileService.copy(from, to, true) } + catch (e) { console.error('Void Transfer Error:', e) } + } + } + + return <> + + Transfer Settings + + } @@ -446,21 +526,22 @@ const GeneralTab = () => { {/* keyboard shortcuts */} -

General Settings

+

General Settings

{`VS Code's built-in settings.`}

-

Keyboard Settings

+

Keyboard Settings

{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}

-

One-click Switch

- - Transfer your VS Code settings to Void. - -

Theme

+

One-click Switch

+

{`Transfer your VS Code settings into Void.`}

+ -

Rules for AI

+

Theme

+ + +

Rules for AI

{/* placeholder: "Do not add ;'s. Do not change or delete spacing, formatting, or comments. Respond to queries in French when applicable. " */} From 4968452003ef1b39670be56c6eae559be737a3c3 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 9 Jan 2025 02:22:54 -0800 Subject: [PATCH 046/111] proper warning --- .../browser/react/src/void-settings-tsx/ModelDropdown.tsx | 2 +- .../void/browser/react/src/void-settings-tsx/Settings.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 5ee372c8..91191694 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -90,7 +90,7 @@ const MemoizedModelSelectBox = ({ featureName }: { featureName: FeatureName }) = } -const WarningBox = ({ text, className }: { text: string, className?: string }) => { +export const WarningBox = ({ text, className }: { text: string, className?: string }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') 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 21986a0f..8333bc5e 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 @@ -15,6 +15,7 @@ import { useScrollbarStyles } from '../util/useScrollbarStyles.js' import { isWindows, isLinux, isMacintosh } from '../../../../../../../base/common/platform.js' import { URI } from '../../../../../../../base/common/uri.js' import { env } from '../../../../../../../base/common/process.js' +import { WarningBox } from './ModelDropdown.js' const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { @@ -486,7 +487,7 @@ const transferTheseFilesOfOS = (os: 'mac' | 'windows' | 'linux' | null): Transfe throw new Error(`os '${os}' not recognized`) } -const os = null//isWindows ? 'windows' : isMacintosh ? 'mac' : isLinux ? 'linux' : null +const os = isWindows ? 'windows' : isMacintosh ? 'mac' : isLinux ? 'linux' : null let transferTheseFiles: TransferFilesInfo = [] let transferError: string | null = null @@ -499,8 +500,7 @@ const OneClickSwitch = () => { if (transferTheseFiles.length === 0) return <> -
One-click transfer not available.
-
{transferError}
+ const onClick = async () => { From 7bb09932491b82985883c7c312d207d0aa11ef79 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 9 Jan 2025 02:48:48 -0800 Subject: [PATCH 047/111] transfer button feedback --- .../void/browser/react/src/util/inputs.tsx | 4 +-- .../react/src/void-settings-tsx/Settings.tsx | 29 ++++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) 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 5fecb79b..583fef54 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 @@ -567,8 +567,8 @@ export const VoidCodeEditor = ({ initValue, language, maxHeight, showScrollbars } -export const VoidButton = ({ children, onClick }: { children: React.ReactNode; onClick: () => void }) => { - return 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 8333bc5e..e196f4e6 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 @@ -498,24 +498,45 @@ const OneClickSwitch = () => { const accessor = useAccessor() const fileService = accessor.get('IFileService') + const [state, setState] = useState<{ type: 'done' | 'loading' | 'justfinished' } | { type: 'justerrored', error: string }>({ type: 'done' }) + if (transferTheseFiles.length === 0) return <> - + + + const onClick = async () => { + + if (state.type !== 'done') return + + setState({ type: 'loading' }) + + let errAcc = '' for (let { from, to } of transferTheseFiles) { console.log('transferring', from, to) // not sure if this can fail, just wrapping it with try/catch for now try { await fileService.copy(from, to, true) } - catch (e) { console.error('Void Transfer Error:', e) } + catch (e) { errAcc += e + '\n' } } + const hadError = !!errAcc + if (hadError) setState({ type: 'justerrored', error: errAcc }) + else setState({ type: 'justfinished' }) + + setTimeout(() => { setState({ type: 'done' }); }, hadError ? 5000 : 3000) } return <> - - Transfer Settings + + {state.type === 'done' ? 'Transfer my Settings' + : state.type === 'loading' ? 'Transferring...' + : state.type === 'justfinished' ? 'Success!' + : state.type === 'justerrored' ? `There was Error` + : null + } + {state.type === 'justerrored' && state.error} } From 446dede5e47d014fba4a31d1097e84be6b13f55b Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 9 Jan 2025 02:52:18 -0800 Subject: [PATCH 048/111] refreshes ollama only --- src/vs/platform/void/common/refreshModelService.ts | 4 ++-- src/vs/platform/void/common/voidSettingsTypes.ts | 2 +- .../void/browser/react/src/void-settings-tsx/Settings.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/void/common/refreshModelService.ts b/src/vs/platform/void/common/refreshModelService.ts index 8804013c..4794da86 100644 --- a/src/vs/platform/void/common/refreshModelService.ts +++ b/src/vs/platform/void/common/refreshModelService.ts @@ -36,7 +36,7 @@ export type RefreshModelStateOfProvider = Record !(localProviderNames as string[]).includes(name)) // all non-local names type CustomSettingName = UnionOfKeys 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 e196f4e6..ad92dea5 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 @@ -555,7 +555,7 @@ const GeneralTab = () => {

One-click Switch

-

{`Transfer your VS Code settings into Void.`}

+

{`Transfer your settings from VS Code into Void.`}

From 924c9536978dfb3506752ecf6d672ff35b7604ca Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Thu, 9 Jan 2025 03:21:20 -0800 Subject: [PATCH 049/111] setttings minwidth --- .../void/browser/react/src/util/inputs.tsx | 67 ++++++++++++++----- .../src/void-settings-tsx/ModelDropdown.tsx | 1 + .../react/src/void-settings-tsx/Settings.tsx | 8 +-- 3 files changed, 57 insertions(+), 19 deletions(-) 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 583fef54..76ca7871 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 @@ -208,6 +208,8 @@ export const VoidCustomSelectBox = ({ getOptionsEqual, className, arrowTouchesText = true, + matchInputWidth = false, + gap = 0, }: { options: T[]; selectedOption?: T; @@ -216,32 +218,54 @@ export const VoidCustomSelectBox = ({ getOptionsEqual: (a: T, b: T) => boolean; className?: string; arrowTouchesText?: boolean; + matchInputWidth?: boolean; + gap?: number; }) => { const [isOpen, setIsOpen] = useState(false); - const [position, setPosition] = useState({ top: 0, left: 0 }); + const [readyToShow, setReadyToShow] = useState(false); + const [position, setPosition] = useState({ top: 0, left: 0, width: 0 }); const containerRef = useRef(null); const buttonRef = useRef(null); + const measureRef = useRef(null); if (!selectedOption) { selectedOption = options[0]; } - const updatePosition = () => { - if (!buttonRef.current) return; + const updatePosition = useCallback(() => { + if (!buttonRef.current || !containerRef.current || !measureRef.current) return; const rect = buttonRef.current.getBoundingClientRect(); + const containerWidth = containerRef.current.offsetWidth; const viewportHeight = window.innerHeight; const spaceBelow = viewportHeight - rect.bottom; - const spaceNeeded = options.length * 28; // Approximate height per option + const spaceNeeded = options.length * 28; const showAbove = spaceBelow < spaceNeeded && rect.top > spaceBelow; + // Calculate the menu width + let menuWidth = matchInputWidth ? containerWidth : rect.width; + + // If not matchInputWidth, calculate content width from measurement div + if (!matchInputWidth) { + const contentWidth = measureRef.current.offsetWidth; + menuWidth = Math.max(rect.width, contentWidth); + } + + // Calculate exact positions without any additional offsets + const topPosition = showAbove + ? rect.top - spaceNeeded // Align exactly to top when showing above + : rect.bottom + gap; // Add gap only when showing below + setPosition({ - top: showAbove ? rect.top - 4 - spaceNeeded : rect.bottom + 4, + top: topPosition, left: rect.left, + width: menuWidth, }); - }; + setReadyToShow(true); + }, [gap, matchInputWidth, options.length]); useEffect(() => { if (isOpen) { + setReadyToShow(false); updatePosition(); window.addEventListener('scroll', updatePosition, true); window.addEventListener('resize', updatePosition); @@ -250,8 +274,10 @@ export const VoidCustomSelectBox = ({ window.removeEventListener('scroll', updatePosition, true); window.removeEventListener('resize', updatePosition); }; + } else { + setReadyToShow(false); } - }, [isOpen]); + }, [isOpen, updatePosition]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -271,15 +297,26 @@ export const VoidCustomSelectBox = ({ ref={containerRef} className={`inline-block ${className}`} > + {/* Hidden measurement div */} +