From 8456f979ba023e2e9cf52b622f47f2fb5bca0cc3 Mon Sep 17 00:00:00 2001 From: mp Date: Sun, 22 Dec 2024 02:07:26 -0800 Subject: [PATCH 1/8] warning icon --- .../react/src/sidebar-tsx/SidebarChat.tsx | 23 ++++++++------- .../src/void-settings-tsx/ModelDropdown.tsx | 27 +++++++++++++---- .../void/browser/react/tailwind.config.js | 29 ++++++++++--------- 3 files changed, 50 insertions(+), 29 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 d3c1ce8b..90df4a53 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 @@ -94,45 +94,46 @@ export const IconWarning = ({ size, className = '' }: { size: number, className? stroke="currentColor" fill="currentColor" strokeWidth="0" - viewBox="0 0 24 24" + viewBox="0 0 16 16" width={size} height={size} xmlns="http://www.w3.org/2000/svg" > - {/* Warning triangle */} - - - {/* Exclamation mark */} - - + ); }; type ButtonProps = ButtonHTMLAttributes +const DEFAULT_BUTTON_SIZE = 20; export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Required>) => { + return } export const ButtonStop = ({ className, ...props }: ButtonHTMLAttributes) => { 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 2ec2db72..26961573 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 @@ -9,7 +9,7 @@ import { useSettingsState, useRefreshModelState, useAccessor } from '../util/ser import { VoidSelectBox } from '../util/inputs.js' import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js' import { IconWarning } from '../sidebar-tsx/SidebarChat.js' - +import { OPEN_VOID_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js' const ModelSelectBox = ({ featureName }: { featureName: FeatureName }) => { const accessor = useAccessor() @@ -44,12 +44,29 @@ const ModelSelectBox = ({ featureName }: { featureName: FeatureName }) => { const DummySelectBox = () => { - return
+ const accessor = useAccessor() + const comandService = accessor.get('ICommandService') + + const openSettings = () => { + comandService.executeCommand(OPEN_VOID_SETTINGS_ACTION_ID); + }; + + return
- Add a model + Model required
// return Date: Sun, 22 Dec 2024 02:10:13 -0800 Subject: [PATCH 2/8] warning icon --- .../browser/react/src/void-settings-tsx/ModelDropdown.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 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 26961573..20f46435 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 @@ -9,7 +9,7 @@ import { useSettingsState, useRefreshModelState, useAccessor } from '../util/ser import { VoidSelectBox } from '../util/inputs.js' import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js' import { IconWarning } from '../sidebar-tsx/SidebarChat.js' -import { OPEN_VOID_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js' +import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js' const ModelSelectBox = ({ featureName }: { featureName: FeatureName }) => { const accessor = useAccessor() @@ -48,7 +48,7 @@ const DummySelectBox = () => { const comandService = accessor.get('ICommandService') const openSettings = () => { - comandService.executeCommand(OPEN_VOID_SETTINGS_ACTION_ID); + comandService.executeCommand(VOID_OPEN_SETTINGS_ACTION_ID); }; return
{ flex-nowrap text-ellipsis text-vscode-charts-yellow hover:brightness-110 transition-all duration-200 - min-w-[120px] cursor-pointer `} onClick={openSettings} From e7af8d944871424bfd540b25c78a01aef15d3040 Mon Sep 17 00:00:00 2001 From: mp Date: Sun, 22 Dec 2024 21:28:09 -0800 Subject: [PATCH 3/8] selection style --- .../react/src/sidebar-tsx/SidebarChat.tsx | 69 ++++++++++++++----- .../void/browser/react/src/util/inputs.tsx | 7 +- .../src/void-settings-tsx/ModelDropdown.tsx | 2 +- .../react/src/void-settings-tsx/Settings.tsx | 2 +- .../void/browser/react/tailwind.config.js | 12 ++-- 5 files changed, 66 insertions(+), 26 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 90df4a53..7bb432ee 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 @@ -26,7 +26,7 @@ import { ILLMMessageService } from '../../../../../../../platform/void/common/ll import { IModelService } from '../../../../../../../editor/common/services/model.js'; -const IconX = ({ size, className = '' }: { size: number, className?: string }) => { +const IconX = ({ size, className = '', ...props }: { size: number, className?: string } & React.SVGProps) => { return ( {selections.map((selection, i) => { @@ -225,13 +226,14 @@ export const SelectedFiles = ( {/* selection summary */}
{ setSelectionIsOpened(s => { const newS = [...s] @@ -240,18 +242,37 @@ export const SelectedFiles = ( }); }} > - + {/* file name */} {getBasename(selection.fileURI.fsPath)} {/* selection range */} {selection.selectionStr !== null ? ` (${selection.range.startLineNumber}-${selection.range.endLineNumber})` : ''} - {/* type of selection */} - {selection.selectionStr !== null ? 'Selection' : 'File'} - {/* X button */} - {type === 'staging' && // hoveredIdx === i + {type === 'staging' && + { + e.stopPropagation(); + if (type !== 'staging') return; + setStaging([...selections.slice(0, i), ...selections.slice(i + 1)]) + setSelectionIsOpened(o => [...o.slice(0, i), ...o.slice(i + 1)]) + }} + > + + + } + + {/* type of selection */} + {/* {selection.selectionStr !== null ? 'Selection' : 'File'} */} + {/* X button */} + {/* {type === 'staging' && // hoveredIdx === i { e.stopPropagation(); @@ -262,11 +283,12 @@ export const SelectedFiles = ( > - } + } */} +
{/* selection text */} {showSelectionText && -
+
} @@ -483,7 +505,7 @@ export const SidebarChat = () => { {/* input box */}
0 ? 'absolute bottom-0' : ''}`} + className={`right-0 left-0 m-2 z-[999] overflow-hidden ${previousMessages.length > 0 ? 'absolute bottom-0' : ''}`} >
{ if (ref) { setFormHeight(ref.clientHeight); } }} @@ -539,7 +561,13 @@ export const SidebarChat = () => { // .split(' ') // .map(style => `@@[&_div.monaco-inputbox]:!void-${style}`) // .join(' '); - `@@[&_textarea]:!void-bg-transparent @@[&_textarea]:!void-outline-none @@[&_textarea]:!void-text-vscode-input-fg @@[&_textarea]:!void-min-h-[81px] @@[&_textarea]:!void-max-h-[500px] @@[&_div.monaco-inputbox]:!void-border-none @@[&_div.monaco-inputbox]:!void-outline-none` + `@@[&_textarea]:!void-bg-transparent + @@[&_textarea]:!void-outline-none + @@[&_textarea]:!void-text-vscode-input-fg + @@[&_textarea]:!void-min-h-[81px] + @@[&_textarea]:!void-max-h-[500px] + @@[&_div.monaco-inputbox]:!void-border-none + @@[&_div.monaco-inputbox]:!void-outline-none` } > @@ -557,7 +585,10 @@ export const SidebarChat = () => { className='flex flex-row justify-between items-end gap-1' > {/* submit options */} -
+
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 260f8c75..4eccb09f 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 @@ -299,7 +299,7 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan return
instantiationService.createInstance( CodeEditorWidget, @@ -312,6 +312,8 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan alwaysConsumeMouseWheel: false, vertical: 'auto', horizontal: 'auto', + // verticalScrollbarSize: 3, + // horizontalScrollbarSize: 3, }, scrollBeyondLastLine: false, @@ -335,6 +337,9 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan hideCursorInOverviewRuler: true, overviewRulerBorder: false, glyphMargin: false, + stickyScroll: { + enabled: false + }, }, { isSimpleWidget: true, 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 20f46435..a1554d14 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 @@ -56,7 +56,7 @@ const DummySelectBox = () => { flex items-center flex-nowrap text-ellipsis text-vscode-charts-yellow - hover:brightness-110 transition-all duration-200 + hover:brightness-90 transition-all duration-200 cursor-pointer `} onClick={openSettings} 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 f1d95780..583e6f56 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 @@ -220,7 +220,7 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider return
{ if (weChangedTextRef) return voidSettingsService.setSettingOfProvider(providerName, settingName, newVal) 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 48b72252..972d9b18 100644 --- a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js +++ b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js @@ -107,12 +107,16 @@ module.exports = { "editor-bg": "var(--vscode-editor-background)", "editor-fg": "var(--vscode-editor-foreground)", - // editor widget colors - "editorwidget-fg": "var(--vscode-editorWidget-foreground)", - "editorwidget-bg": "var(--vscode-editorWidget-background)", - "editorwidget-border": "var(--vscode-editorWidget-border)", + // other + "editorwidget-bg": "var(--vscode-editorWidget-background)", + "toolbar-hover-bg": "var(--vscode-toolbar-hoverBackground)", + "toolbar-foreground": "var(--vscode-editorActionList-foreground)", + + "editorwidget-fg": "var(--vscode-editorWidget-foreground)", + "editorwidget-border": "var(--vscode-editorWidget-border)", + "charts-orange": "var(--vscode-charts-orange)", "charts-yellow": "var(--vscode-charts-yellow)", }, From 70c7d0261ccb709bbd270ac0f03f42905fc6fd64 Mon Sep 17 00:00:00 2001 From: mp Date: Sun, 22 Dec 2024 21:41:37 -0800 Subject: [PATCH 4/8] correct bg --- .../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 7bb432ee..269b6351 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 @@ -288,7 +288,7 @@ export const SelectedFiles = (
{/* selection text */} {showSelectionText && -
+
} From 806ec939e53739a0f7020e129d3e4c88ad73fb17 Mon Sep 17 00:00:00 2001 From: mp Date: Mon, 23 Dec 2024 02:34:23 -0800 Subject: [PATCH 5/8] ux for providers --- .../void/common/refreshModelService.ts | 8 +- .../void/common/voidSettingsService.ts | 4 +- .../platform/void/common/voidSettingsTypes.ts | 18 +-- .../react/src/sidebar-tsx/SidebarChat.tsx | 2 +- .../void/browser/react/src/util/inputs.tsx | 4 +- .../react/src/void-settings-tsx/Settings.tsx | 120 ++++++++++++------ 6 files changed, 102 insertions(+), 54 deletions(-) diff --git a/src/vs/platform/void/common/refreshModelService.ts b/src/vs/platform/void/common/refreshModelService.ts index 123a12c7..3859a82a 100644 --- a/src/vs/platform/void/common/refreshModelService.ts +++ b/src/vs/platform/void/common/refreshModelService.ts @@ -32,8 +32,8 @@ export type RefreshModelStateOfProvider = Record { let modelOptions: ModelOption[] = [] for (const providerName of providerNames) { const providerConfig = settingsOfProvider[providerName] - if (!providerConfig.enabled) continue // if disabled, don't display model options + 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 } }) @@ -151,7 +151,7 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService { const newFeatureFlags = this.state.featureFlagSettings // if changed models or enabled a provider, recompute models list - const modelsListChanged = settingName === 'models' || settingName === 'enabled' + const modelsListChanged = settingName === 'models' || settingName === '_enabled' const newModelsList = modelsListChanged ? _computeModelOptions(newSettingsOfProvider) : this.state._modelOptions const newState: VoidSettingsState = { diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index 1b1b2ff7..22cbdcc2 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -137,7 +137,7 @@ export const customSettingNamesOfProvider = (providerName: ProviderName) => { type CommonProviderSettings = { - enabled: boolean | undefined, // undefined initially + _enabled: boolean | undefined, // undefined initially, computed when user types in all fields models: VoidModelInfo[], } @@ -240,7 +240,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName undefined, } } - else if (settingName === 'enabled') { + else if (settingName === '_enabled') { return { title: '(never)', placeholder: '(never)', @@ -293,13 +293,13 @@ export const voidInitModelOptions = { // used when waiting and for a type reference export const defaultSettingsOfProvider: SettingsOfProvider = { anthropic: { - enabled: undefined, + _enabled: undefined, ...defaultCustomSettings, ...defaultProviderSettings.anthropic, ...voidInitModelOptions.anthropic, }, openAI: { - enabled: undefined, + _enabled: undefined, ...defaultCustomSettings, ...defaultProviderSettings.openAI, ...voidInitModelOptions.openAI, @@ -308,31 +308,31 @@ export const defaultSettingsOfProvider: SettingsOfProvider = { ...defaultCustomSettings, ...defaultProviderSettings.gemini, ...voidInitModelOptions.gemini, - enabled: undefined, + _enabled: undefined, }, groq: { ...defaultCustomSettings, ...defaultProviderSettings.groq, ...voidInitModelOptions.groq, - enabled: undefined, + _enabled: undefined, }, ollama: { ...defaultCustomSettings, ...defaultProviderSettings.ollama, ...voidInitModelOptions.ollama, - enabled: undefined, + _enabled: undefined, }, openRouter: { ...defaultCustomSettings, ...defaultProviderSettings.openRouter, ...voidInitModelOptions.openRouter, - enabled: undefined, + _enabled: undefined, }, openAICompatible: { ...defaultCustomSettings, ...defaultProviderSettings.openAICompatible, ...voidInitModelOptions.openAICompatible, - enabled: undefined, + _enabled: undefined, }, } 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 269b6351..363c3630 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 @@ -134,7 +134,7 @@ export const ButtonStop = ({ className, ...props }: ButtonHTMLAttributes - + } 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 4eccb09f..31710236 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 @@ -312,8 +312,8 @@ export const VoidCodeEditor = ({ initValue, language }: { initValue: string, lan alwaysConsumeMouseWheel: false, vertical: 'auto', horizontal: 'auto', - // verticalScrollbarSize: 3, - // horizontalScrollbarSize: 3, + verticalScrollbarSize: 0, + horizontalScrollbarSize: 0, }, scrollBeyondLastLine: false, 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 583e6f56..11411198 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 @@ -1,12 +1,23 @@ 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 } from '../../../../../../../platform/void/common/voidSettingsTypes.js' +import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, featureFlagNames, displayInfoOfFeatureFlag, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, defaultProviderSettings } from '../../../../../../../platform/void/common/voidSettingsTypes.js' 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 { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' +const SubtleButton = ({ onClick, text, icon, disabled }: { onClick: () => void, text: string, icon: React.ReactNode, disabled: boolean }) => { + + return
+ + + {text} + +
+} // models @@ -34,14 +45,12 @@ const RefreshModelButton = ({ providerName }: { providerName: RefreshableProvide const isRefreshing = state === 'refreshing' const { title: providerTitle } = displayInfoOfProviderName(providerName) - return
- - { - justFinished ? `${providerTitle} Models are up-to-date!` : `Refresh Models List for ${providerTitle}.` - } -
+ return { refreshModelService.refreshModels(providerName) }} + text={justFinished ? `${providerTitle} Models are up-to-date!` : `Refresh Models List for ${providerTitle}.`} + icon={isRefreshing ? : (justFinished ? : )} + disabled={isRefreshing || justFinished} + /> } const RefreshableModels = () => { @@ -49,7 +58,7 @@ const RefreshableModels = () => { const buttons = refreshableProviderNames.map(providerName => { - if (!settingsState.settingsOfProvider[providerName].enabled) return null + if (!settingsState.settingsOfProvider[providerName]._enabled) return null return }) @@ -162,7 +171,7 @@ export const ModelDump = () => { for (let providerName of providerNames) { const providerSettings = settingsState.settingsOfProvider[providerName] // if (!providerSettings.enabled) continue - modelDump.push(...providerSettings.models.map(model => ({ ...model, providerName, providerEnabled: !!providerSettings.enabled }))) + modelDump.push(...providerSettings.models.map(model => ({ ...model, providerName, providerEnabled: !!providerSettings._enabled }))) } // sort by hidden @@ -231,10 +240,27 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider const syncInstance = () => { const settingsAtProvider = voidSettingsService.state.settingsOfProvider[providerName]; const stateVal = settingsAtProvider[settingName as SettingName] + // console.log('SYNCING TO', providerName, settingName, stateVal) weChangedTextRef = true instance.value = stateVal as string weChangedTextRef = false + + const isEverySettingPresent = Object.keys(defaultProviderSettings[providerName]).every(key => { + return !!settingsAtProvider[key as keyof typeof settingsAtProvider] + }) + + const shouldEnable = isEverySettingPresent && !settingsAtProvider._enabled // enable if all settings are present and not already enabled + const shouldDisable = !isEverySettingPresent && settingsAtProvider._enabled + + if (shouldEnable) { + voidSettingsService.setSettingOfProvider(providerName, '_enabled', true) + } + + if (shouldDisable) { + voidSettingsService.setSettingOfProvider(providerName, '_enabled', false) + } + } syncInstance() const disposable = voidSettingsService.onDidChangeState(syncInstance) @@ -251,21 +277,22 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider } const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) => { - const voidSettingsState = useSettingsState() - const accessor = useAccessor() - const voidSettingsService = accessor.get('IVoidSettingsService') + // const voidSettingsState = useSettingsState() + // const accessor = useAccessor() + // const voidSettingsService = accessor.get('IVoidSettingsService') - const { enabled } = voidSettingsState.settingsOfProvider[providerName] + // const { enabled } = voidSettingsState.settingsOfProvider[providerName] const settingNames = customSettingNamesOfProvider(providerName) const { title: providerTitle } = displayInfoOfProviderName(providerName) return
+

{providerTitle}

{/* enable provider switch */} - { @@ -273,7 +300,7 @@ const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) = voidSettingsService.setSettingOfProvider(providerName, 'enabled', !enabledRef) }, [voidSettingsService, providerName])} size='sm+' - /> + /> */}
@@ -282,7 +309,7 @@ const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) = return })}
-
+
} @@ -294,29 +321,49 @@ export const VoidProviderSettings = () => { } +// export const VoidFeatureFlagSettings = () => { +// const accessor = useAccessor() +// const voidSettingsService = accessor.get('IVoidSettingsService') +// const voidSettingsState = useSettingsState() + +// return <> +// {featureFlagNames.map((flagName) => { +// const value = voidSettingsState.featureFlagSettings[flagName] +// const { description } = displayInfoOfFeatureFlag(flagName) +// return
+//
+// { voidSettingsService.setFeatureFlag(flagName, !value) }} +// /> +//

{description}

+//
+//
+// })} +// +// } export const VoidFeatureFlagSettings = () => { + + const accessor = useAccessor() const voidSettingsService = accessor.get('IVoidSettingsService') const voidSettingsState = useSettingsState() - return <> - {featureFlagNames.map((flagName) => { - const value = voidSettingsState.featureFlagSettings[flagName] - const { description } = displayInfoOfFeatureFlag(flagName) - return
-
- { voidSettingsService.setFeatureFlag(flagName, !value) }} - /> -

{description}

-
-
- })} - + return featureFlagNames.map((flagName) => { + + const enabled = voidSettingsState.featureFlagSettings[flagName] + const { description } = displayInfoOfFeatureFlag(flagName) + + return { voidSettingsService.setFeatureFlag(flagName, !enabled) }} + text={description} + icon={enabled ? : } + disabled={false} + /> + }) } @@ -359,20 +406,21 @@ export const Settings = () => {

Providers

+

Models

+ -

{ setTab('features') }}>Features

- + {/* */}
From 8f9c2f0630a96ef610dc6c15e9549ba15a85935f Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Sun, 22 Dec 2024 23:52:21 -0800 Subject: [PATCH 6/8] misc --- .../inlineDiffService/inlineDiffService.ts | 2 + .../helperServices/abstractAreaService.ts | 186 ++++ .../helperServices/abstractAreaService2.ts | 185 ++++ .../inlineDiffsServiceBackup.ts | 996 ++++++++++++++++++ .../helperServices/zoneStyleService.ts | 186 ++++ .../void/browser/inlineDiffsService.ts | 13 +- 6 files changed, 1559 insertions(+), 9 deletions(-) create mode 100644 src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService.ts create mode 100644 src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService2.ts create mode 100644 src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts create mode 100644 src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts diff --git a/src/vs/editor/browser/services/inlineDiffService/inlineDiffService.ts b/src/vs/editor/browser/services/inlineDiffService/inlineDiffService.ts index 7c2d1324..56637a06 100644 --- a/src/vs/editor/browser/services/inlineDiffService/inlineDiffService.ts +++ b/src/vs/editor/browser/services/inlineDiffService/inlineDiffService.ts @@ -6,6 +6,8 @@ import { ICodeEditor, IViewZone } from '../../editorBrowser.js'; import { IRange } from '../../../common/core/range.js'; import { EditorOption } from '../../../common/config/editorOptions.js'; + +// THIS FILE IS OLD!!! export interface IInlineDiffService { readonly _serviceBrand: undefined; addDiff(editor: ICodeEditor, originalText: string, modifiedRange: IRange): void; diff --git a/src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService.ts b/src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService.ts new file mode 100644 index 00000000..f06bbee4 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService.ts @@ -0,0 +1,186 @@ +// import { Disposable } from '../../../../../base/common/lifecycle.js'; +// import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; +// import { IModelService } from '../../../../../editor/common/services/model.js'; +// import { ITextModel, EndOfLinePreference } from '../../../../../editor/common/model.js'; +// import { ICodeEditor } from '../../../../../editor/browser/editorBrowser.js'; +// import { URI } from '../../../../../base/common/uri.js'; +// import { IRange } from '../../../../../editor/common/core/range.js'; + + +// // DiffArea +// export interface BaseArea { +// areaId: number; +// uri: URI; +// startLine: number; +// endLine: number; +// } + + +// export abstract class AbstractAreaService extends Disposable { + +// protected _areasOfURI: Record> = {}; +// protected _areaOfId: Record = {}; +// protected _areaIdPool = 0; // for generating unique IDs + +// protected _removeStylesFnsOfURI: Record void>> = {}; + +// private _weAreWriting = false; + +// constructor( +// protected readonly _editorService: ICodeEditorService, +// protected readonly _modelService: IModelService, +// ) { +// super(); + + +// const initializeModel = (model: ITextModel) => { +// const fsPath = model.uri.fsPath; +// if (!this._areasOfURI[fsPath]) { +// this._areasOfURI[fsPath] = new Set(); +// } +// if (!this._removeStylesFnsOfURI[fsPath]) { +// this._removeStylesFnsOfURI[fsPath] = new Set(); +// } + +// // when the user types, realign diff areas and re-render them +// this._register( +// model.onDidChangeContent(e => { +// const uri = model.uri +// // it's as if we just called _write, now all we need to do is realign and refresh +// if (this._weAreWriting) return; +// for (const change of e.changes) this._realignAreasInURI(uri, change.text, change.range); +// this._renderAreaInEditor(uri); +// }) +// ); +// } + +// const initializeEditor = (editor: ICodeEditor) => { +// this._register(editor.onDidChangeModel(e => { +// if (e.oldModelUrl) this._renderAreaInEditor(e.oldModelUrl); +// if (e.newModelUrl) this._renderAreaInEditor(e.newModelUrl); +// })); +// const uri = editor.getModel()?.uri; +// if (uri) this._renderAreaInEditor(uri); +// } + +// // initialize all current models + listen for new models to appear +// for (const model of this._modelService.getModels()) initializeModel(model); +// this._register(this._modelService.onModelAdded(model => initializeModel(model))); + +// // initialize all current editors + listen for new editors to appear +// for (const editor of this._editorService.listCodeEditors()) initializeEditor(editor); +// this._register(this._editorService.onCodeEditorAdd(editor => initializeEditor(editor))); +// } + + +// //-------------------------------------- +// // Realignment + refresh +// //-------------------------------------- + +// // changes the start/line locations of all DiffAreas on the page (adjust their start/end based on the change) based on the change that was recently made +// private _realignAreasInURI(uri: URI, text: string, recentChange: { startLineNumber: number; endLineNumber: number }) { + +// const model = this._getModel(uri) +// if (!model) return + +// // compute net number of newlines lines that were added/removed +// const startLine = recentChange.startLineNumber +// const endLine = recentChange.endLineNumber +// const changeRangeHeight = endLine - startLine + 1 + +// const newTextHeight = (text.match(/\n/g) || []).length + 1 // number of newlines is number of \n's + 1, e.g. "ab\ncd" + +// const deltaNewlines = newTextHeight - changeRangeHeight + +// // compute overlap with each diffArea and shrink/elongate each diffArea accordingly +// for (const diffareaid of this._areasOfURI[model.uri.fsPath] || []) { +// const diffArea = this._areaOfId[diffareaid] + +// // if the diffArea is above the range, it is not affected +// if (diffArea.endLine < startLine) { +// console.log('A') +// continue +// } + +// // console.log('Changing DiffArea:', diffArea.startLine, diffArea.endLine) + +// // if the diffArea fully contains the change, elongate it by the delta amount of newlines +// if (startLine >= diffArea.startLine && endLine <= diffArea.endLine) { +// diffArea.endLine += deltaNewlines +// } +// // if the change fully contains the diffArea, make the diffArea have the same range as the change +// else if (diffArea.startLine > startLine && diffArea.endLine < endLine) { + +// diffArea.startLine = startLine +// diffArea.endLine = startLine + newTextHeight +// console.log('B', diffArea.startLine, diffArea.endLine) +// } +// // if the change contains only the diffArea's top +// else if (diffArea.startLine > startLine) { +// // TODO fill in this case +// console.log('C', diffArea.startLine, diffArea.endLine) +// } +// // if the change contains only the diffArea's bottom +// else if (diffArea.endLine < endLine) { +// const numOverlappingLines = diffArea.endLine - startLine + 1 +// diffArea.endLine += newTextHeight - numOverlappingLines // TODO double check this +// console.log('D', diffArea.startLine, diffArea.endLine) +// } +// // if a diffArea is below the last character of the change, shift the diffArea up/down by the delta amount of newlines +// else if (diffArea.startLine > endLine) { +// diffArea.startLine += deltaNewlines +// diffArea.endLine += deltaNewlines +// console.log('E', diffArea.startLine, diffArea.endLine) +// } + +// // console.log('To:', diffArea.startLine, diffArea.endLine) +// } + +// } + +// //-------------------------------------- +// // Reading + Writing the text +// //-------------------------------------- + +// protected _readURI(uri: URI): string | null { +// const m = this._modelService.getModel(uri); +// if (!m || m.isDisposed()) { +// return null; +// } +// return m.getValue(EndOfLinePreference.LF); +// } + +// protected _getModel(uri: URI): ITextModel | null { +// const m = this._modelService.getModel(uri); +// return (m && !m.isDisposed()) ? m : null; +// } + + +// protected _writeText(uri: URI, text: string, range: IRange) { +// const model = this._getModel(uri); +// if (!model) return; + +// const finalRange = { +// startLineNumber: range.startLineNumber, +// startColumn: range.startColumn ?? 1, +// endLineNumber: range.endLineNumber, +// endColumn: range.endColumn ?? Number.MAX_SAFE_INTEGER +// }; + +// this._weAreWriting = true; +// model.applyEdits([{ range: finalRange, text }]); +// this._weAreWriting = false; +// } + +// //-------------------------------------- +// // Abstract: how to render an area +// //-------------------------------------- +// /** +// * Subclasses override this to define how an area gets +// * painted in a particular editor: decorations, zones, widgets, etc. +// * +// * Return an array of functions that will remove those +// * decorations/zones when needed. +// */ +// protected abstract _renderAreaInEditor(editor: ICodeEditor, area: A): Array<() => void>; +// } diff --git a/src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService2.ts b/src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService2.ts new file mode 100644 index 00000000..9e4a0416 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/helperServices/abstractAreaService2.ts @@ -0,0 +1,185 @@ +// import { Disposable } from '../../../../../base/common/lifecycle.js'; +// import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; +// import { IModelService } from '../../../../../editor/common/services/model.js'; +// import { ITextModel, EndOfLinePreference } from '../../../../../editor/common/model.js'; +// import { ICodeEditor } from '../../../../../editor/browser/editorBrowser.js'; +// import { URI } from '../../../../../base/common/uri.js'; +// import { IRange } from '../../../../../editor/common/core/range.js'; + + +// // DiffArea +// export interface BaseArea { +// areaId: number; +// uri: URI; +// startLine: number; +// endLine: number; +// } + + +// export abstract class AbstractAreaService extends Disposable { + +// protected _areasOfURI: Record> = {}; +// protected _areaOfId: Record = {}; + +// protected _removeStylesFnsOfURI: Record void>> = {}; + +// private _weAreWriting = false; + +// constructor( +// protected readonly _editorService: ICodeEditorService, +// protected readonly _modelService: IModelService, +// ) { +// super(); + + +// const initializeModel = (model: ITextModel) => { +// const fsPath = model.uri.fsPath; +// if (!this._areasOfURI[fsPath]) { +// this._areasOfURI[fsPath] = new Set(); +// } +// if (!this._removeStylesFnsOfURI[fsPath]) { +// this._removeStylesFnsOfURI[fsPath] = new Set(); +// } + +// // when the user types, realign diff areas and re-render them +// this._register( +// model.onDidChangeContent(e => { +// const uri = model.uri +// // it's as if we just called _write, now all we need to do is realign and refresh +// if (this._weAreWriting) return; +// for (const change of e.changes) this._realignAreasInURI(uri, change.text, change.range); +// this._renderAreaInEditor(uri); +// }) +// ); +// } + +// const initializeEditor = (editor: ICodeEditor) => { +// this._register(editor.onDidChangeModel(e => { +// if (e.oldModelUrl) this._renderAreaInEditor(e.oldModelUrl); +// if (e.newModelUrl) this._renderAreaInEditor(e.newModelUrl); +// })); +// const uri = editor.getModel()?.uri; +// if (uri) this._renderAreaInEditor(uri); +// } + +// // initialize all current models + listen for new models to appear +// for (const model of this._modelService.getModels()) initializeModel(model); +// this._register(this._modelService.onModelAdded(model => initializeModel(model))); + +// // initialize all current editors + listen for new editors to appear +// for (const editor of this._editorService.listCodeEditors()) initializeEditor(editor); +// this._register(this._editorService.onCodeEditorAdd(editor => initializeEditor(editor))); +// } + + +// //-------------------------------------- +// // Realignment + refresh +// //-------------------------------------- + +// // changes the start/line locations of all DiffAreas on the page (adjust their start/end based on the change) based on the change that was recently made +// private _realignAreasInURI(uri: URI, text: string, recentChange: { startLineNumber: number; endLineNumber: number }) { + +// const model = this._getModel(uri) +// if (!model) return + +// // compute net number of newlines lines that were added/removed +// const startLine = recentChange.startLineNumber +// const endLine = recentChange.endLineNumber +// const changeRangeHeight = endLine - startLine + 1 + +// const newTextHeight = (text.match(/\n/g) || []).length + 1 // number of newlines is number of \n's + 1, e.g. "ab\ncd" + +// const deltaNewlines = newTextHeight - changeRangeHeight + +// // compute overlap with each diffArea and shrink/elongate each diffArea accordingly +// for (const diffareaid of this._areasOfURI[model.uri.fsPath] || []) { +// const diffArea = this._areaOfId[diffareaid] + +// // if the diffArea is above the range, it is not affected +// if (diffArea.endLine < startLine) { +// console.log('A') +// continue +// } + +// // console.log('Changing DiffArea:', diffArea.startLine, diffArea.endLine) + +// // if the diffArea fully contains the change, elongate it by the delta amount of newlines +// if (startLine >= diffArea.startLine && endLine <= diffArea.endLine) { +// diffArea.endLine += deltaNewlines +// } +// // if the change fully contains the diffArea, make the diffArea have the same range as the change +// else if (diffArea.startLine > startLine && diffArea.endLine < endLine) { + +// diffArea.startLine = startLine +// diffArea.endLine = startLine + newTextHeight +// console.log('B', diffArea.startLine, diffArea.endLine) +// } +// // if the change contains only the diffArea's top +// else if (diffArea.startLine > startLine) { +// // TODO fill in this case +// console.log('C', diffArea.startLine, diffArea.endLine) +// } +// // if the change contains only the diffArea's bottom +// else if (diffArea.endLine < endLine) { +// const numOverlappingLines = diffArea.endLine - startLine + 1 +// diffArea.endLine += newTextHeight - numOverlappingLines // TODO double check this +// console.log('D', diffArea.startLine, diffArea.endLine) +// } +// // if a diffArea is below the last character of the change, shift the diffArea up/down by the delta amount of newlines +// else if (diffArea.startLine > endLine) { +// diffArea.startLine += deltaNewlines +// diffArea.endLine += deltaNewlines +// console.log('E', diffArea.startLine, diffArea.endLine) +// } + +// // console.log('To:', diffArea.startLine, diffArea.endLine) +// } + +// } + +// //-------------------------------------- +// // Reading + Writing the text +// //-------------------------------------- + +// protected _readURI(uri: URI): string | null { +// const m = this._modelService.getModel(uri); +// if (!m || m.isDisposed()) { +// return null; +// } +// return m.getValue(EndOfLinePreference.LF); +// } + +// protected _getModel(uri: URI): ITextModel | null { +// const m = this._modelService.getModel(uri); +// return (m && !m.isDisposed()) ? m : null; +// } + + +// protected _writeText(uri: URI, text: string, range: IRange) { +// const model = this._getModel(uri); +// if (!model) return; + +// const finalRange = { +// startLineNumber: range.startLineNumber, +// startColumn: range.startColumn ?? 1, +// endLineNumber: range.endLineNumber, +// endColumn: range.endColumn ?? Number.MAX_SAFE_INTEGER +// }; + +// this._weAreWriting = true; +// model.applyEdits([{ range: finalRange, text }]); +// this._weAreWriting = false; +// } + +// //-------------------------------------- +// // Abstract: how to render an area +// //-------------------------------------- +// /** +// * Subclasses override this to define how an area gets +// * painted in a particular editor: decorations, zones, widgets, etc. +// * +// * Return an array of functions that will remove those +// * decorations/zones when needed. +// */ +// protected abstract _renderAreaInEditor(editor: ICodeEditor, area: A): Array<() => void>; +// } diff --git a/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts b/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts new file mode 100644 index 00000000..169f7d50 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts @@ -0,0 +1,996 @@ +// /*--------------------------------------------------------------------------------------------- +// * Copyright (c) Glass Devtools, Inc. All rights reserved. +// * Void Editor additions licensed under the AGPL 3.0 License. +// *--------------------------------------------------------------------------------------------*/ + +// import { Disposable } from '../../../../base/common/lifecycle.js'; +// import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; +// import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; +// import { ICodeEditor, IOverlayWidget, IViewZone } from '../../../../editor/browser/editorBrowser.js'; + +// // import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js'; +// import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; +// // import { throttle } from '../../../../base/common/decorators.js'; +// import { inlineDiff_systemMessage } from './prompt/prompts.js'; +// import { ComputedDiff, findDiffs } from './helpers/findDiffs.js'; +// import { EndOfLinePreference, IModelDecorationOptions, ITextModel } from '../../../../editor/common/model.js'; +// import { IRange } from '../../../../editor/common/core/range.js'; +// import { registerColor } from '../../../../platform/theme/common/colorUtils.js'; +// import { Color, RGBA } from '../../../../base/common/color.js'; +// import { IModelService } from '../../../../editor/common/services/model.js'; +// import { IUndoRedoElement, IUndoRedoService, UndoRedoElementType } from '../../../../platform/undoRedo/common/undoRedo.js'; +// import { LineSource, renderLines, RenderOptions } from '../../../../editor/browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; +// import { LineTokens } from '../../../../editor/common/tokens/lineTokens.js'; +// import { ILanguageService } from '../../../../editor/common/languages/language.js'; +// // import { IModelService } from '../../../../editor/common/services/model.js'; + +// import * as dom from '../../../../base/browser/dom.js'; +// import { Widget } from '../../../../base/browser/ui/widget.js'; +// import { URI } from '../../../../base/common/uri.js'; +// import { LLMFeatureSelection, ServiceSendLLMMessageParams } from '../../../../platform/void/common/llmMessageTypes.js'; +// import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; + + +// const configOfBG = (color: Color) => { +// return { dark: color, light: color, hcDark: color, hcLight: color, } +// } +// // gets converted to --vscode-void-greenBG, see void.css +// const greenBG = new Color(new RGBA(155, 185, 85, .3)); // default is RGBA(155, 185, 85, .2) +// registerColor('void.greenBG', configOfBG(greenBG), '', true); + +// const redBG = new Color(new RGBA(255, 0, 0, .3)); // default is RGBA(255, 0, 0, .2) +// registerColor('void.redBG', configOfBG(redBG), '', true); + +// const sweepBG = new Color(new RGBA(100, 100, 100, .2)); +// registerColor('void.sweepBG', configOfBG(sweepBG), '', true); + +// const highlightBG = new Color(new RGBA(100, 100, 100, .1)); +// registerColor('void.highlightBG', configOfBG(highlightBG), '', true); + +// const sweepIdxBG = new Color(new RGBA(100, 100, 100, .5)); +// registerColor('void.sweepIdxBG', configOfBG(sweepIdxBG), '', true); + + +// export type Diff = { +// diffid: number; +// diffareaid: number; // the diff area this diff belongs to, "computed" +// } & ComputedDiff + + +// // _ means anything we don't include if we clone it +// // DiffArea.originalStartLine is the line in originalCode (not the file) +// type DiffArea = { +// diffareaid: number; +// originalCode: string; +// startLine: number; +// endLine: number; +// shouldHighlight: boolean; // should visually highlight this DiffArea + +// _URI: URI; // typically we get the URI from model +// _diffOfId: Record; // diffid -> diff in this DiffArea + +// } & ({ +// _sweepState: { +// isStreaming: true; +// line: number; +// } | { +// isStreaming: false; +// line: null; +// }; +// }) + +// const diffAreaSnapshotKeys = [ +// 'diffareaid', +// 'originalCode', +// 'startLine', +// 'endLine', +// 'shouldHighlight', +// ] as const satisfies (keyof DiffArea)[] + +// type DiffAreaSnapshot = Pick + + + +// type HistorySnapshot = { +// snapshottedDiffAreaOfId: Record; +// entireFileCode: string; +// } & +// ({ +// type: 'Ctrl+K'; +// ctrlKText: string; +// } | { +// type: 'Ctrl+L'; +// }) + + + +// export interface IInlineDiffsService { +// readonly _serviceBrand: undefined; +// startStreaming(params: LLMFeatureSelection, str: string): void; +// } + +// export const IInlineDiffsService = createDecorator('inlineDiffAreasService'); + +// class InlineDiffsService extends Disposable implements IInlineDiffsService { +// _serviceBrand: undefined; + + +// // URI <--> model +// removeStylesFnsOfURI: Record> = {} // functions that remove the styles of this uri +// diffAreasOfURI: Record> = {} + +// diffAreaOfId: Record = {}; +// diffOfId: Record = {}; // redundant with diffArea._diffs + +// _diffareaidPool = 0 // each diffarea has an id +// _diffidPool = 0 // each diff has an id + +// constructor( +// // @IHistoryService private readonly _historyService: IHistoryService, // history service is the history of pressing alt left/right +// @ICodeEditorService private readonly _editorService: ICodeEditorService, +// @IModelService private readonly _modelService: IModelService, +// @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, // undoRedo service is the history of pressing ctrl+z +// @ILanguageService private readonly _langService: ILanguageService, +// @ILLMMessageService private readonly _llmMessageService: ILLMMessageService, +// ) { +// super(); + +// // this function initializes data structures and listens for changes +// const initializeModel = (model: ITextModel) => { +// if (!(model.uri.fsPath in this.diffAreasOfURI)) { +// this.diffAreasOfURI[model.uri.fsPath] = new Set(); +// } +// if (!(model.uri.fsPath in this.removeStylesFnsOfURI)) { +// this.removeStylesFnsOfURI[model.uri.fsPath] = new Set(); +// } + +// // when the user types, realign diff areas and re-render them +// this._register( +// model.onDidChangeContent(e => { +// // it's as if we just called _write, now all we need to do is realign and refresh +// if (this._weAreWriting) return +// const uri = model.uri +// // realign +// for (const change of e.changes) { this._realignAllDiffAreasLines(uri, change.text, change.range) } +// // refresh +// this._refreshDiffsInURI(uri) +// }) +// ) +// } +// // initialize all existing models +// for (let model of this._modelService.getModels()) { initializeModel(model) } +// // initialize whenever a new model mounts +// this._register(this._modelService.onModelAdded(model => initializeModel(model))); + + + +// // this function adds listeners to refresh styles when editor changes tab +// let initializeEditor = (editor: ICodeEditor) => { +// const uri = editor.getModel()?.uri ?? null +// if (uri) this._refreshDiffsInURI(uri) + +// // called when the user switches tabs (typically there's only 1 editor on the screen, it switches between models, make sure you understand this) +// this._register(editor.onDidChangeModel((e) => { +// if (e.oldModelUrl) this._refreshDiffsInURI(e.oldModelUrl) +// if (e.newModelUrl) this._refreshDiffsInURI(e.newModelUrl) +// })) +// } +// // add listeners for all existing editors +// for (let editor of this._editorService.listCodeEditors()) { initializeEditor(editor) } +// // add listeners when an editor is created +// this._register(this._editorService.onCodeEditorAdd(editor => { console.log('ADD EDITOR'); initializeEditor(editor) })) +// this._register(this._editorService.onCodeEditorRemove(editor => { console.log('REMOVE EDITOR'); initializeEditor(editor) })) + +// } + + + + +// // highlight the region +// private _addLineDecoration = (model: ITextModel | null, startLine: number, endLine: number, className: string, options?: Partial) => { +// if (model === null) return +// const id = model.changeDecorations(accessor => accessor.addDecoration( +// { startLineNumber: startLine, startColumn: 1, endLineNumber: endLine, endColumn: Number.MAX_SAFE_INTEGER }, +// { +// className: className, +// description: className, +// isWholeLine: true, +// ...options +// })) +// const disposeHighlight = () => { +// if (id) model.changeDecorations(accessor => accessor.removeDecoration(id)) +// } +// return disposeHighlight +// } + + + +// private _addDiffAreaStylesToURI = (uri: URI) => { +// const model = this._getModel(uri) + +// for (const diffareaid of this.diffAreasOfURI[uri.fsPath]) { +// const diffArea = this.diffAreaOfId[diffareaid] +// // add sweep styles to the diffArea +// if (diffArea._sweepState.isStreaming) { +// // sweepLine ... sweepLine +// const fn1 = this._addLineDecoration(model, diffArea._sweepState.line, diffArea._sweepState.line, 'void-sweepIdxBG') +// // sweepLine+1 ... endLine +// const fn2 = this._addLineDecoration(model, diffArea._sweepState.line + 1, diffArea.endLine, 'void-sweepBG') +// this.removeStylesFnsOfURI[uri.fsPath].add(() => { fn1?.(); fn2?.(); }) +// } +// // highlight the diffArea +// if (diffArea.shouldHighlight) { +// const fn = this._addLineDecoration(model, diffArea.startLine, diffArea.endLine, 'void-highlightBG') +// this.removeStylesFnsOfURI[uri.fsPath].add(() => fn?.()); +// } +// } +// } + + +// private _addDiffStylesToEditor = (editor: ICodeEditor, diff: Diff) => { +// const { type, diffid } = diff + +// const disposeInThisEditorFns: (() => void)[] = [] + +// // green decoration and minimap decoration +// if (type !== 'deletion') { +// const fn = this._addLineDecoration(editor.getModel(), diff.startLine, diff.endLine, 'void-greenBG', { +// minimap: { color: { id: 'minimapGutter.addedBackground' }, position: 2 }, +// overviewRuler: { color: { id: 'editorOverviewRuler.addedForeground' }, position: 7 } +// }) +// disposeInThisEditorFns.push(() => { fn?.() }) +// } + + +// // red in a view zone +// if (type !== 'insertion') { +// editor.changeViewZones(accessor => { + +// const domNode = document.createElement('div'); +// domNode.className = 'void-redBG' + +// const renderOptions = RenderOptions.fromEditor(editor); +// // applyFontInfo(domNode, renderOptions.fontInfo) + +// // Compute view-lines based on redText +// const redText = diff.originalCode +// const lines = redText.split('\n'); +// const lineTokens = lines.map(line => LineTokens.createFromTextAndMetadata([{ text: line, metadata: 0 }], this._langService.languageIdCodec)); +// const source = new LineSource(lineTokens, lines.map(() => null), false, false) +// const result = renderLines(source, renderOptions, [], domNode); + +// const viewZone: IViewZone = { +// // afterLineNumber: computedDiff.startLine - 1, +// afterLineNumber: type === 'edit' ? diff.endLine : diff.startLine - 1, +// heightInLines: result.heightInLines, +// minWidthInPx: result.minWidthInPx, +// domNode: domNode, +// marginDomNode: document.createElement('div'), // displayed to left +// suppressMouseDown: true, +// }; + +// const zoneId = accessor.addZone(viewZone) +// disposeInThisEditorFns.push(() => { editor.changeViewZones(accessor => { if (zoneId) accessor.removeZone(zoneId) }) }) + +// }); +// } + + +// // Accept | Reject widget +// const buttonsWidget = new AcceptRejectWidget({ +// editor, +// onAccept: () => { this.acceptDiff({ diffid }) }, +// onReject: () => { this.rejectDiff({ diffid }) }, +// diffid: diffid.toString(), +// startLine: diff.startLine, +// }) +// disposeInThisEditorFns.push(() => { buttonsWidget.dispose() }) + +// const disposeInEditor = () => { disposeInThisEditorFns.forEach(f => f()) } +// return disposeInEditor; + +// } + + + +// private _getModel(uri: URI) { +// const model = this._modelService.getModel(uri) +// if (!model || model.isDisposed()) { +// return null +// } +// return model +// } +// private _readURI(uri: URI): string | null { +// return this._getModel(uri)?.getValue(EndOfLinePreference.LF) ?? null +// } +// private _getNumLines(uri: URI): number | null { +// return this._getModel(uri)?.getLineCount() ?? null +// } + + +// _weAreWriting = false +// private _writeText(uri: URI, text: string, range: IRange) { +// const model = this._getModel(uri) +// if (!model) return + +// this._weAreWriting = true +// model.applyEdits([{ range, text }]) // applies edits without adding them to undo/redo stack +// this._weAreWriting = false + +// this._realignAllDiffAreasLines(uri, text, range) +// } + + + + +// private _addToHistory(uri: URI) { + +// const getCurrentSnapshot = (): HistorySnapshot => { +// const diffAreaOfId = this.diffAreaOfId + +// const snapshottedDiffAreaOfId: Record = {} +// for (const diffareaid in diffAreaOfId) { +// const diffArea = diffAreaOfId[diffareaid] +// snapshottedDiffAreaOfId[diffareaid] = structuredClone( // a structured clone must be on a JSON object +// Object.fromEntries(diffAreaSnapshotKeys.map(key => [key, diffArea[key]])) +// ) as DiffAreaSnapshot +// } +// return { +// snapshottedDiffAreaOfId, +// entireFileCode: this._readURI(uri) ?? '', // the whole file's code +// type: 'Ctrl+L', +// } +// } + +// const restoreDiffAreas = (snapshot: HistorySnapshot) => { +// const { snapshottedDiffAreaOfId, entireFileCode: entireModelCode } = structuredClone(snapshot) // don't want to destroy the snapshot + +// // delete all current decorations (diffs, sweep styles) so we don't have any unwanted leftover decorations +// this._clearAllDiffsAndStyles(uri) + +// // restore diffAreaOfId and diffAreasOfModelId +// this.diffAreaOfId = {} +// this.diffAreasOfURI[uri.fsPath].clear() +// for (const diffareaid in snapshottedDiffAreaOfId) { +// this.diffAreaOfId[diffareaid] = { +// ...snapshottedDiffAreaOfId[diffareaid], +// _diffOfId: {}, +// _URI: uri, +// _sweepState: { +// isStreaming: false, +// line: null, +// }, +// } +// this.diffAreasOfURI[uri.fsPath].add(diffareaid) +// } + +// // restore file content +// const numLines = this._getNumLines(uri) +// if (numLines === null) return +// this._writeText(uri, entireModelCode, { startColumn: 1, startLineNumber: 1, endLineNumber: numLines, endColumn: Number.MAX_SAFE_INTEGER }) + +// // restore all the decorations +// this._refreshDiffsInURI(uri) +// } + +// const beforeSnapshot: HistorySnapshot = getCurrentSnapshot() +// let afterSnapshot: HistorySnapshot | null = null + +// const elt: IUndoRedoElement = { +// type: UndoRedoElementType.Resource, +// resource: uri, +// label: 'Void Changes', +// code: 'undoredo.inlineDiffs', +// undo: () => { restoreDiffAreas(beforeSnapshot) }, +// redo: () => { if (afterSnapshot) restoreDiffAreas(afterSnapshot) } +// } +// this._undoRedoService.pushElement(elt) + +// const onFinishEdit = () => { afterSnapshot = getCurrentSnapshot() } +// return { onFinishEdit } +// } + + +// // delete diffOfId and diffArea._diffOfId +// private _deleteDiff(diff: Diff) { +// const diffArea = this.diffAreaOfId[diff.diffareaid] +// delete diffArea._diffOfId[diff.diffid] +// delete this.diffOfId[diff.diffid] +// } + +// private _deleteDiffs(diffArea: DiffArea) { +// for (const diffid in diffArea._diffOfId) { +// const diff = diffArea._diffOfId[diffid] +// this._deleteDiff(diff) +// } +// } + +// private _clearAllDiffsAndStyles(uri: URI) { +// for (let diffareaid of this.diffAreasOfURI[uri.fsPath]) { +// const diffArea = this.diffAreaOfId[diffareaid] +// this._deleteDiffs(diffArea) +// } +// for (const removeStyleFn of this.removeStylesFnsOfURI[uri.fsPath]) { +// removeStyleFn() +// } +// this.removeStylesFnsOfURI[uri.fsPath].clear() +// } + + + +// // delete all diffs, update diffAreaOfId, update diffAreasOfModelId +// private _deleteDiffArea(diffArea: DiffArea) { +// this._deleteDiffs(diffArea) +// delete this.diffAreaOfId[diffArea.diffareaid] +// this.diffAreasOfURI[diffArea._URI.fsPath].delete(diffArea.diffareaid.toString()) +// } + + + + + +// // changes the start/line locations of all DiffAreas on the page (adjust their start/end based on the change) based on the change that was recently made +// private _realignAllDiffAreasLines(uri: URI, text: string, recentChange: { startLineNumber: number; endLineNumber: number }) { + +// const model = this._getModel(uri) +// if (!model) return + +// // compute net number of newlines lines that were added/removed +// const startLine = recentChange.startLineNumber +// const endLine = recentChange.endLineNumber +// const changeRangeHeight = endLine - startLine + 1 + +// const newTextHeight = (text.match(/\n/g) || []).length + 1 // number of newlines is number of \n's + 1, e.g. "ab\ncd" + +// const deltaNewlines = newTextHeight - changeRangeHeight + +// // compute overlap with each diffArea and shrink/elongate each diffArea accordingly +// for (const diffareaid of this.diffAreasOfURI[model.uri.fsPath] || []) { +// const diffArea = this.diffAreaOfId[diffareaid] + +// // if the diffArea is above the range, it is not affected +// if (diffArea.endLine < startLine) { +// console.log('A') +// continue +// } + +// // console.log('Changing DiffArea:', diffArea.startLine, diffArea.endLine) + +// // if the diffArea fully contains the change, elongate it by the delta amount of newlines +// if (startLine >= diffArea.startLine && endLine <= diffArea.endLine) { +// diffArea.endLine += deltaNewlines +// } +// // if the change fully contains the diffArea, make the diffArea have the same range as the change +// else if (diffArea.startLine > startLine && diffArea.endLine < endLine) { + +// diffArea.startLine = startLine +// diffArea.endLine = startLine + newTextHeight +// console.log('B', diffArea.startLine, diffArea.endLine) +// } +// // if the change contains only the diffArea's top +// else if (diffArea.startLine > startLine) { +// // TODO fill in this case +// console.log('C', diffArea.startLine, diffArea.endLine) +// } +// // if the change contains only the diffArea's bottom +// else if (diffArea.endLine < endLine) { +// const numOverlappingLines = diffArea.endLine - startLine + 1 +// diffArea.endLine += newTextHeight - numOverlappingLines // TODO double check this +// console.log('D', diffArea.startLine, diffArea.endLine) +// } +// // if a diffArea is below the last character of the change, shift the diffArea up/down by the delta amount of newlines +// else if (diffArea.startLine > endLine) { +// diffArea.startLine += deltaNewlines +// diffArea.endLine += deltaNewlines +// console.log('E', diffArea.startLine, diffArea.endLine) +// } + +// // console.log('To:', diffArea.startLine, diffArea.endLine) +// } + +// } + + +// private _refreshDiffsInURI(uri: URI) { +// const content = this._readURI(uri) +// if (content === null) return + +// // 1. clear Diffs and styles +// this._clearAllDiffsAndStyles(uri) + +// // 2. recompute all diffs on each editor with this URI +// const editors = this._editorService.listCodeEditors().filter(editor => editor.getModel()?.uri.fsPath === uri.fsPath) +// const fullFileText = this._readURI(uri) ?? '' + + +// // go thru all diffareas in this URI, creating diffs and adding styles to it +// for (let diffareaid of this.diffAreasOfURI[uri.fsPath]) { +// const diffArea = this.diffAreaOfId[diffareaid] + +// const newDiffAreaCode = fullFileText.split('\n').slice((diffArea.startLine - 1), (diffArea.endLine - 1) + 1).join('\n') +// const computedDiffs = findDiffs(diffArea.originalCode, newDiffAreaCode) + +// for (let computedDiff of computedDiffs) { +// const diffid = this._diffidPool++ + +// // create a Diff of it +// const newDiff: Diff = { +// ...computedDiff, +// diffid: diffid, +// diffareaid: diffArea.diffareaid, +// } + +// for (let editor of editors) { +// const fn = this._addDiffStylesToEditor(editor, newDiff) +// this.removeStylesFnsOfURI[uri.fsPath].add(() => fn()) +// } + +// this.diffOfId[diffid] = newDiff +// diffArea._diffOfId[diffid] = newDiff +// } + +// // update styles on this DiffArea +// this._addDiffAreaStylesToURI(uri) +// } + + +// } + + +// // @throttle(100) +// private _writeDiffAreaLLMText(diffArea: DiffArea, newCodeSoFar: string) { + +// // ----------- 1. Write the new code to the document ----------- +// // figure out where to highlight based on where the AI is in the stream right now, use the last diff to figure that out +// const uri = diffArea._URI +// const computedDiffs = findDiffs(diffArea.originalCode, newCodeSoFar) + +// // if not streaming, just write the new code +// if (!diffArea._sweepState.isStreaming) { +// this._writeText(uri, newCodeSoFar, +// { startLineNumber: diffArea.startLine, startColumn: 1, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, } // 1-indexed +// ) +// } +// // if streaming, use diffs to figure out where to write new code +// else { +// // these are two different coordinate systems - new and old line number +// let newFileEndLine: number // get new[0...newStoppingPoint] with line=newStoppingPoint highlighted +// let oldFileStartLine: number // get original[oldStartingPoint...] + +// const lastDiff = computedDiffs.pop() + +// if (!lastDiff) { +// // if the writing is identical so far, display no changes +// newFileEndLine = 1 +// oldFileStartLine = 1 +// } +// else { +// if (lastDiff.type === 'insertion') { +// newFileEndLine = lastDiff.endLine +// oldFileStartLine = lastDiff.originalStartLine +// } +// else if (lastDiff.type === 'deletion') { +// newFileEndLine = lastDiff.startLine +// oldFileStartLine = lastDiff.originalStartLine +// } +// else if (lastDiff.type === 'edit') { +// newFileEndLine = lastDiff.endLine +// oldFileStartLine = lastDiff.originalStartLine +// } +// else { +// throw new Error(`Void: diff.type not recognized on: ${lastDiff}`) +// } +// } + +// diffArea._sweepState.line = newFileEndLine + +// // lines are 1-indexed +// const newFileTop = newCodeSoFar.split('\n').slice(0, (newFileEndLine - 1)).join('\n') +// const oldFileBottom = diffArea.originalCode.split('\n').slice((oldFileStartLine - 1), Infinity).join('\n') + +// const newCode = `${newFileTop}\n${oldFileBottom}` + +// this._writeText(uri, newCode, +// { startLineNumber: diffArea.startLine, startColumn: 1, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, } // 1-indexed +// ) + +// } + +// return computedDiffs + +// } + + + + +// private async _initializeStream(opts: LLMFeatureSelection, diffRepr: string, uri: URI,) { + +// // diff area begin and end line +// const numLines = this._getNumLines(uri) +// if (numLines === null) return + +// const beginLine = 1 +// const 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 < beginLine +// 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], beginLine, endLine) +// return +// } +// } + +// const currentFileStr = this._readURI(uri) +// if (currentFileStr === null) return +// const originalCode = currentFileStr.split('\n').slice((beginLine - 1), (endLine - 1) + 1).join('\n') + +// // add to history +// const { onFinishEdit } = this._addToHistory(uri) + +// // create a diffArea for the stream +// const diffareaid = this._diffareaidPool++ + +// // in ctrl+L the start and end lines are the full document +// const diffArea: DiffArea = { +// diffareaid: diffareaid, +// // originalStartLine: beginLine, +// // originalEndLine: endLine, +// originalCode: originalCode, +// startLine: beginLine, +// endLine: endLine, // starts out the same as the current file +// shouldHighlight: false, +// _URI: uri, +// _sweepState: { +// isStreaming: true, +// line: 1, +// }, +// _diffOfId: {}, // added later +// } + +// console.log('adding uri.fspath', uri.fsPath, diffArea.diffareaid.toString()) +// this.diffAreasOfURI[uri.fsPath].add(diffArea.diffareaid.toString()) +// this.diffAreaOfId[diffArea.diffareaid] = diffArea + +// // actually call the LLM +// const promptContent = `\ +// ORIGINAL_CODE +// \`\`\` +// ${originalCode} +// \`\`\` + +// DIFF +// \`\`\` +// ${diffRepr} +// \`\`\` + +// INSTRUCTIONS +// Please finish writing the new file by applying the diff to the original file. Return ONLY the completion of the file, without any explanation. +// ` + + +// await new Promise((resolve, reject) => { + +// let streamRequestId: string | null = null + +// const object: ServiceSendLLMMessageParams = { +// logging: { loggingName: 'streamChunk' }, +// messages: [ +// { role: 'system', content: inlineDiff_systemMessage, }, +// // TODO include more context too +// { role: 'user', content: promptContent, } +// ], +// onText: ({ newText, fullText }) => { +// this._writeDiffAreaLLMText(diffArea, fullText) +// this._refreshDiffsInURI(uri) +// }, +// onFinalMessage: ({ fullText }) => { +// this._writeText(uri, fullText, +// { startLineNumber: diffArea.startLine, startColumn: 1, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed +// ) +// diffArea._sweepState = { isStreaming: false, line: null } +// this._refreshDiffsInURI(uri) +// resolve(); +// }, +// onError: (e: any) => { +// console.error('Error rewriting file with diff', e); +// // TODO indicate there was an error +// if (streamRequestId) +// this._llmMessageService.abort(streamRequestId) + +// diffArea._sweepState = { isStreaming: false, line: null } +// resolve(); +// }, +// ...opts +// } + +// streamRequestId = this._llmMessageService.sendLLMMessage(object) +// }) + +// onFinishEdit() + +// } + + + + + + +// async startStreaming(opts: LLMFeatureSelection, userMessage: string) { + +// const editor = this._editorService.getActiveCodeEditor() +// if (!editor) return + +// const uri = editor.getModel()?.uri +// if (!uri) return + +// // TODO reject all diffs in the diff area + +// // TODO deselect user's cursor + +// this._initializeStream(opts, userMessage, uri) +// } + + +// interruptStreaming() { +// // TODO add abort +// } + + + +// addDiffArea({ uri, startLine, endLine, originalCode }: { uri: URI, startLine: number, endLine: number, originalCode: string }) { +// const diffareaid = this._diffareaidPool++ + +// const diffArea: DiffArea = { +// diffareaid: diffareaid, +// originalCode, +// startLine, +// endLine, +// shouldHighlight: true, +// _URI: uri, +// _sweepState: { +// isStreaming: false, +// line: null, +// }, +// _diffOfId: {}, +// } + +// this.diffAreasOfURI[uri.fsPath].add(diffArea.diffareaid.toString()) +// this.diffAreaOfId[diffArea.diffareaid] = diffArea + +// this._refreshDiffsInURI(uri) +// } + + + + + +// // called on void.acceptDiff +// public async acceptDiff({ diffid }: { diffid: number }) { + +// const diff = this.diffOfId[diffid] +// if (!diff) return + +// const { diffareaid } = diff +// const diffArea = this.diffAreaOfId[diffareaid] +// if (!diffArea) return + +// const uri = diffArea._URI + +// // add to history +// const { onFinishEdit } = this._addToHistory(uri) + +// const originalLines = diffArea.originalCode.split('\n') +// let newOriginalCode: string + +// if (diff.type === 'deletion') { +// newOriginalCode = [ +// ...originalLines.slice(0, (diff.originalStartLine - 1)), // everything before startLine +// // <-- deletion has nothing here +// ...originalLines.slice((diff.originalEndLine - 1) + 1, Infinity) // everything after endLine +// ].join('\n') +// } +// else if (diff.type === 'insertion') { +// newOriginalCode = [ +// ...originalLines.slice(0, (diff.originalStartLine - 1)), // everything before startLine +// diff.code, // code +// ...originalLines.slice((diff.originalStartLine - 1), Infinity) // startLine (inclusive) and on (no +1) +// ].join('\n') +// } +// else if (diff.type === 'edit') { +// newOriginalCode = [ +// ...originalLines.slice(0, (diff.originalStartLine - 1)), // everything before startLine +// diff.code, // code +// ...originalLines.slice((diff.originalEndLine - 1) + 1, Infinity) // everything after endLine +// ].join('\n') +// } +// else { +// throw new Error(`Void error: ${diff}.type not recognized`) +// } + +// // console.log('DIFF', diff) +// // console.log('DIFFAREA', diffArea) +// // console.log('ORIGINAL', diffArea.originalCode) +// // console.log('new original Code', newOriginalCode) + +// // update code now accepted as original +// diffArea.originalCode = newOriginalCode + +// // delete the diff +// this._deleteDiff(diff) + +// // diffArea should be removed if it has no more diffs in it +// if (Object.keys(diffArea._diffOfId).length === 0) { +// this._deleteDiffArea(diffArea) +// } + +// this._refreshDiffsInURI(uri) + +// onFinishEdit() + +// } + + + +// // called on void.rejectDiff +// public async rejectDiff({ diffid }: { diffid: number }) { + +// const diff = this.diffOfId[diffid] +// if (!diff) return + +// const { diffareaid } = diff +// const diffArea = this.diffAreaOfId[diffareaid] +// if (!diffArea) return + +// const uri = diffArea._URI + +// // add to history +// const { onFinishEdit } = this._addToHistory(uri) + +// let writeText: string +// let toRange: IRange + +// // if it was a deletion, need to re-insert +// // (this image applies to writeText and toRange, not newOriginalCode) +// // A +// // |B <-- deleted here, diff.startLine == diff.endLine +// // C +// if (diff.type === 'deletion') { +// writeText = diff.originalCode + '\n' +// toRange = { startLineNumber: diff.startLine, startColumn: 1, endLineNumber: diff.startLine, endColumn: 1 } +// } +// // if it was an insertion, need to delete all the lines +// // (this image applies to writeText and toRange, not newOriginalCode) +// // |A <-- startLine +// // 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 +// } +// // if it was an edit, just edit the range +// // (this image applies to writeText and toRange, not newOriginalCode) +// // |A <-- startLine +// // B| <-- endLine (just swap out these lines for the originalCode) +// // C +// else if (diff.type === 'edit') { +// writeText = diff.originalCode +// toRange = { startLineNumber: diff.startLine, startColumn: 1, endLineNumber: diff.endLine, endColumn: Number.MAX_SAFE_INTEGER } // 1-indexed +// } +// else { +// throw new Error(`Void error: ${diff}.type not recognized`) +// } + +// // update the file +// this._writeText(uri, writeText, toRange) + +// // originalCode does not change! + +// // delete the diff +// this._deleteDiff(diff) + +// // diffArea should be removed if it has no more diffs in it +// if (Object.keys(diffArea._diffOfId).length === 0) { +// this._deleteDiffArea(diffArea) +// } + +// this._refreshDiffsInURI(uri) + +// onFinishEdit() + +// } + +// } + +// registerSingleton(IInlineDiffsService, InlineDiffsService, InstantiationType.Eager); + + + + +// class AcceptRejectWidget extends Widget implements IOverlayWidget { + +// public getId() { return this.ID } +// public getDomNode() { return this._domNode; } +// public getPosition() { return null } + +// private readonly _domNode: HTMLElement; +// private readonly editor +// private readonly ID +// private readonly startLine + +// constructor({ editor, onAccept, onReject, diffid, startLine }: { editor: ICodeEditor; onAccept: () => void; onReject: () => void; diffid: string, startLine: number }) { +// super() + +// this.ID = editor.getModel()?.uri.fsPath + diffid; +// this.editor = editor; +// this.startLine = startLine; + +// // Create container div with buttons +// const { acceptButton, rejectButton, buttons } = dom.h('div@buttons', [ +// dom.h('button@acceptButton', []), +// dom.h('button@rejectButton', []) +// ]); + +// // Style the container +// buttons.style.display = 'flex'; +// buttons.style.position = 'absolute'; +// buttons.style.gap = '4px'; +// buttons.style.padding = '4px'; +// buttons.style.zIndex = '1000'; + + +// // Style accept button +// acceptButton.onclick = onAccept; +// acceptButton.textContent = 'Accept'; +// acceptButton.style.backgroundColor = '#28a745'; +// acceptButton.style.color = 'white'; +// acceptButton.style.border = 'none'; +// acceptButton.style.padding = '4px 8px'; +// acceptButton.style.borderRadius = '3px'; +// acceptButton.style.cursor = 'pointer'; + +// // Style reject button +// rejectButton.onclick = onReject; +// rejectButton.textContent = 'Reject'; +// rejectButton.style.backgroundColor = '#dc3545'; +// rejectButton.style.color = 'white'; +// rejectButton.style.border = 'none'; +// rejectButton.style.padding = '4px 8px'; +// rejectButton.style.borderRadius = '3px'; +// rejectButton.style.cursor = 'pointer'; + +// this._domNode = buttons; + +// const updateTop = () => { +// const topPx = editor.getTopForLineNumber(this.startLine) - editor.getScrollTop() +// this._domNode.style.top = `${topPx}px` +// } +// const updateLeft = () => { +// const leftPx = 0//editor.getScrollLeft() - editor.getScrollWidth() +// this._domNode.style.left = `${leftPx}px` +// } + +// updateTop() +// updateLeft() + +// this._register(editor.onDidScrollChange(e => { updateTop() })) +// this._register(editor.onDidChangeModelContent(e => { updateTop() })) +// this._register(editor.onDidLayoutChange(e => { updateTop(); updateLeft() })) + +// // mount this widget + +// editor.addOverlayWidget(this); +// // console.log('created elt', this._domNode) +// } + +// public override dispose(): void { +// this.editor.removeOverlayWidget(this) +// super.dispose() +// } + +// } + + diff --git a/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts b/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts new file mode 100644 index 00000000..8ccf1374 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts @@ -0,0 +1,186 @@ +import { Disposable, IDisposable } from '../../../../../base/common/lifecycle.js'; +import { URI } from '../../../../../base/common/uri.js'; +import { generateUuid } from '../../../../../base/common/uuid.js'; +import { ICodeEditor, IViewZone } from '../../../../../editor/browser/editorBrowser.js'; +import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js'; +import { InstantiationType, registerSingleton } from '../../../../../platform/instantiation/common/extensions.js'; +import { createDecorator } from '../../../../../platform/instantiation/common/instantiation.js'; + + +// lets you add a zone to a Model (aka URI), instead of just to a single editor + + +export interface IZoneStyleService { + readonly _serviceBrand: undefined; + addConsistentZoneToURI(uri: URI, iZoneFn: (editor: ICodeEditor) => IViewZone, iOther?: (editor: ICodeEditor) => (() => void)): string; + removeConsistentZoneFromURI(consistentZoneId: string): void; +} + +export const IZoneStyleService = createDecorator('zoneStyleService'); + +export class ZoneStyleService extends Disposable { + + readonly _serviceBrand: undefined + + // the zones that are attached to each URI, completely independent from current state of editors + private readonly consistentZoneIdsOfURI: Record | undefined> = {} + private readonly infoOfConsistentZoneId: Record IViewZone, + iOther?: (editor: ICodeEditor) => (() => void), + uri: URI + }> = {} + + // current state of zones on each editor, and the fns to call to remove them. A zone is the actual zone plus whatever iOther you put on it. + private readonly zoneIdsOfEditorId: Record | undefined> = {} + private readonly removeFnOfZoneId: Record void> = {} + private readonly consistentZoneIdOfZoneId: Record = {} + + // current state on each consistent zone + + // listener disposables + private readonly disposablesOfEditorId: Record | undefined> = {} + + constructor( + @ICodeEditorService private readonly _editorService: ICodeEditorService, + ) { + super() + + const addTabSwitchListeners = (editor: ICodeEditor) => { + const editorId = editor.getId() + + const d = editor.onDidChangeModel(e => { + const newURI = e.newModelUrl + // clear all the zones off of this editor + for (const zoneId of this.zoneIdsOfEditorId[editorId] ?? []) + this._removeZoneIdFromEditor(editor, zoneId) + + // add all the zones it should have, judging by the new URI + if (newURI) + for (const consistentZoneId of this.consistentZoneIdsOfURI[newURI.fsPath] ?? []) + this._putZoneOnEditor(editor, consistentZoneId) + }) + + if (!(editorId in this.disposablesOfEditorId)) + this.disposablesOfEditorId[editorId] = new Set() + this.disposablesOfEditorId[editorId]!.add(d) + } + + // initialize current editors + const initialEditors = this._editorService.listCodeEditors() + for (let editor of initialEditors) + addTabSwitchListeners(editor) + + // initialize any new editors - add tab switch listeners and add all zones it should have + this._register(this._editorService.onCodeEditorAdd(editor => { + addTabSwitchListeners(editor) + + const uri = editor.getModel()?.uri + if (uri) + for (const consistentZoneId of this.consistentZoneIdsOfURI[uri.fsPath] ?? []) + this._putZoneOnEditor(editor, consistentZoneId) + })) + + // when an editor is deleted, remove its zones and call any disposables it has + this._register(this._editorService.onCodeEditorRemove(editor => { + const editorId = editor.getId() + + for (const zoneId of this.zoneIdsOfEditorId[editorId] ?? []) + this._removeZoneIdFromEditor(editor, zoneId) + + for (const d of this.disposablesOfEditorId[editorId] ?? []) { + d.dispose() + this.disposablesOfEditorId[editorId]?.delete(d) + } + + })) + + } + + + _putZoneOnEditor(editor: ICodeEditor, consistentZoneId: string) { + const { iZoneFn, iOther } = this.infoOfConsistentZoneId[consistentZoneId] + + const iZone = iZoneFn(editor) + + const editorId = editor.getId() + + editor.changeViewZones(accessor => { + // add zone + other + const zoneId = accessor.addZone(iZone) + const rmFn = iOther?.(editor) + + if (!(editorId in this.zoneIdsOfEditorId)) + this.zoneIdsOfEditorId[editorId] = new Set() + this.zoneIdsOfEditorId[editorId]!.add(zoneId) + + this.consistentZoneIdOfZoneId[zoneId] = consistentZoneId + + // fn that describes how to remove zone + other + this.removeFnOfZoneId[zoneId] = () => { + editor.changeViewZones(accessor => accessor.removeZone(zoneId)) + rmFn?.() + } + }) + } + + + _removeZoneIdFromEditor(editor: ICodeEditor, zoneId: string) { + + this.removeFnOfZoneId[zoneId]?.() + delete this.removeFnOfZoneId[zoneId] + + + const editorId = editor.getId() + if (editorId in this.zoneIdsOfEditorId) { + this.zoneIdsOfEditorId[editorId]?.delete(zoneId) + } + + if (zoneId in this.consistentZoneIdOfZoneId) + delete this.consistentZoneIdOfZoneId[zoneId] + } + + + addConsistentZoneToURI(uri: URI, iZoneFn: (editor: ICodeEditor) => IViewZone, iOther?: (editor: ICodeEditor) => (() => void)) { + const consistentZoneId = generateUuid() + this.infoOfConsistentZoneId[consistentZoneId] = { iZoneFn, iOther, uri } + + if (!(uri.fsPath in this.consistentZoneIdsOfURI)) + this.consistentZoneIdsOfURI[uri.fsPath] = new Set() + this.consistentZoneIdsOfURI[uri.fsPath]!.add(consistentZoneId) + + const editors = this._editorService.listCodeEditors().filter(editor => editor.getModel()?.uri.fsPath === uri.fsPath) + for (const editor of editors) + this._putZoneOnEditor(editor, consistentZoneId) + + return consistentZoneId + } + + + removeConsistentZoneFromURI(consistentZoneId: string) { + + if (!(consistentZoneId in this.infoOfConsistentZoneId)) + return + + const { uri } = this.infoOfConsistentZoneId[consistentZoneId] + const editors = this._editorService.listCodeEditors().filter(e => e.getModel()?.uri.fsPath === uri.fsPath) + + for (const editor of editors) { + for (const zoneId of this.zoneIdsOfEditorId[editor.getId()] ?? []) { + if (this.consistentZoneIdOfZoneId[zoneId] === consistentZoneId) + this._removeZoneIdFromEditor(editor, zoneId) + } + } + + // clear + this.consistentZoneIdsOfURI[uri.fsPath]?.delete(consistentZoneId) + delete this.infoOfConsistentZoneId[consistentZoneId] + + } + + + +} + +registerSingleton(IZoneStyleService, ZoneStyleService, InstantiationType.Eager); + + diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index 50a51301..cc6277e4 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -150,20 +150,16 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // it's as if we just called _write, now all we need to do is realign and refresh if (this._weAreWriting) return const uri = model.uri - // realign for (const change of e.changes) { this._realignAllDiffAreasLines(uri, change.text, change.range) } - // refresh this._refreshDiffsInURI(uri) }) ) } - // initialize all existing models + // initialize all existing models + initialize when a new model mounts for (let model of this._modelService.getModels()) { initializeModel(model) } - // initialize whenever a new model mounts this._register(this._modelService.onModelAdded(model => initializeModel(model))); - // this function adds listeners to refresh styles when editor changes tab let initializeEditor = (editor: ICodeEditor) => { const uri = editor.getModel()?.uri ?? null @@ -175,17 +171,16 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { if (e.newModelUrl) this._refreshDiffsInURI(e.newModelUrl) })) } - // add listeners for all existing editors + // add listeners for all existing editors + listen for editor being added for (let editor of this._editorService.listCodeEditors()) { initializeEditor(editor) } - // add listeners when an editor is created - this._register(this._editorService.onCodeEditorAdd(editor => { console.log('ADD EDITOR'); initializeEditor(editor) })) - this._register(this._editorService.onCodeEditorRemove(editor => { console.log('REMOVE EDITOR'); initializeEditor(editor) })) + this._register(this._editorService.onCodeEditorAdd(editor => { initializeEditor(editor) })) } + // highlight the region private _addLineDecoration = (model: ITextModel | null, startLine: number, endLine: number, className: string, options?: Partial) => { if (model === null) return From ffb0549c7c037489c296d992b45092b6cc07dee9 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Mon, 23 Dec 2024 00:14:54 -0800 Subject: [PATCH 7/8] update zoneStyleService --- .../helperServices/zoneStyleService.ts | 102 ++++++++---------- 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts b/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts index 8ccf1374..b57b7d8a 100644 --- a/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts +++ b/src/vs/workbench/contrib/void/browser/helperServices/zoneStyleService.ts @@ -25,72 +25,71 @@ export class ZoneStyleService extends Disposable { // the zones that are attached to each URI, completely independent from current state of editors private readonly consistentZoneIdsOfURI: Record | undefined> = {} private readonly infoOfConsistentZoneId: Record IViewZone, iOther?: (editor: ICodeEditor) => (() => void), - uri: URI }> = {} + // listener disposables + private readonly disposablesOfEditorId: Record | undefined> = {} + // current state of zones on each editor, and the fns to call to remove them. A zone is the actual zone plus whatever iOther you put on it. private readonly zoneIdsOfEditorId: Record | undefined> = {} private readonly removeFnOfZoneId: Record void> = {} private readonly consistentZoneIdOfZoneId: Record = {} - // current state on each consistent zone - - // listener disposables - private readonly disposablesOfEditorId: Record | undefined> = {} constructor( @ICodeEditorService private readonly _editorService: ICodeEditorService, ) { super() - const addTabSwitchListeners = (editor: ICodeEditor) => { + + const removeZonesFromEditor = (editor: ICodeEditor) => { const editorId = editor.getId() - - const d = editor.onDidChangeModel(e => { - const newURI = e.newModelUrl - // clear all the zones off of this editor - for (const zoneId of this.zoneIdsOfEditorId[editorId] ?? []) - this._removeZoneIdFromEditor(editor, zoneId) - - // add all the zones it should have, judging by the new URI - if (newURI) - for (const consistentZoneId of this.consistentZoneIdsOfURI[newURI.fsPath] ?? []) - this._putZoneOnEditor(editor, consistentZoneId) - }) - - if (!(editorId in this.disposablesOfEditorId)) - this.disposablesOfEditorId[editorId] = new Set() - this.disposablesOfEditorId[editorId]!.add(d) + for (const zoneId of this.zoneIdsOfEditorId[editorId] ?? []) + this._removeZoneIdFromEditor(editor, zoneId) } - // initialize current editors - const initialEditors = this._editorService.listCodeEditors() - for (let editor of initialEditors) - addTabSwitchListeners(editor) + // put zones on the editor, based on the consistentZones for that URI + const putZonesOnEditor = (editor: ICodeEditor, uri: URI | null) => { + if (!uri) return + for (const consistentZoneId of this.consistentZoneIdsOfURI[uri.fsPath] ?? []) + this._putZoneOnEditor(editor, consistentZoneId) + } - // initialize any new editors - add tab switch listeners and add all zones it should have - this._register(this._editorService.onCodeEditorAdd(editor => { - addTabSwitchListeners(editor) - const uri = editor.getModel()?.uri - if (uri) - for (const consistentZoneId of this.consistentZoneIdsOfURI[uri.fsPath] ?? []) - this._putZoneOnEditor(editor, consistentZoneId) - })) + + const addTabSwitchListeners = (editor: ICodeEditor) => { + const editorId = editor.getId() + if (!(editorId in this.disposablesOfEditorId)) + this.disposablesOfEditorId[editorId] = new Set() + + this.disposablesOfEditorId[editorId]!.add( + editor.onDidChangeModel(e => { + removeZonesFromEditor(editor) + putZonesOnEditor(editor, e.newModelUrl) + }) + ) + } + + const initializeEditor = (editor: ICodeEditor) => { + addTabSwitchListeners(editor) + putZonesOnEditor(editor, editor.getModel()?.uri ?? null) + } + + // initialize current editors + any new editors + for (let editor of this._editorService.listCodeEditors()) initializeEditor(editor) + this._register(this._editorService.onCodeEditorAdd(editor => { initializeEditor(editor) })) // when an editor is deleted, remove its zones and call any disposables it has this._register(this._editorService.onCodeEditorRemove(editor => { const editorId = editor.getId() - for (const zoneId of this.zoneIdsOfEditorId[editorId] ?? []) - this._removeZoneIdFromEditor(editor, zoneId) - - for (const d of this.disposablesOfEditorId[editorId] ?? []) { + removeZonesFromEditor(editor) + for (const d of this.disposablesOfEditorId[editorId] ?? []) d.dispose() - this.disposablesOfEditorId[editorId]?.delete(d) - } + delete this.disposablesOfEditorId[editorId] })) @@ -100,43 +99,36 @@ export class ZoneStyleService extends Disposable { _putZoneOnEditor(editor: ICodeEditor, consistentZoneId: string) { const { iZoneFn, iOther } = this.infoOfConsistentZoneId[consistentZoneId] - const iZone = iZoneFn(editor) - - const editorId = editor.getId() - editor.changeViewZones(accessor => { // add zone + other - const zoneId = accessor.addZone(iZone) + const zoneId = accessor.addZone(iZoneFn(editor)) const rmFn = iOther?.(editor) + const editorId = editor.getId() if (!(editorId in this.zoneIdsOfEditorId)) this.zoneIdsOfEditorId[editorId] = new Set() this.zoneIdsOfEditorId[editorId]!.add(zoneId) - this.consistentZoneIdOfZoneId[zoneId] = consistentZoneId - // fn that describes how to remove zone + other this.removeFnOfZoneId[zoneId] = () => { editor.changeViewZones(accessor => accessor.removeZone(zoneId)) rmFn?.() } + + this.consistentZoneIdOfZoneId[zoneId] = consistentZoneId }) } _removeZoneIdFromEditor(editor: ICodeEditor, zoneId: string) { + const editorId = editor.getId() + this.zoneIdsOfEditorId[editorId]?.delete(zoneId) + this.removeFnOfZoneId[zoneId]?.() delete this.removeFnOfZoneId[zoneId] - - const editorId = editor.getId() - if (editorId in this.zoneIdsOfEditorId) { - this.zoneIdsOfEditorId[editorId]?.delete(zoneId) - } - - if (zoneId in this.consistentZoneIdOfZoneId) - delete this.consistentZoneIdOfZoneId[zoneId] + delete this.consistentZoneIdOfZoneId[zoneId] } From ee8b98ff74fb437368dd0e44087e52a696484d41 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Mon, 23 Dec 2024 00:16:37 -0800 Subject: [PATCH 8/8] minor changes --- .../inlineDiffsServiceBackup.ts | 99 ++++++++++--------- .../void/browser/inlineDiffsService.ts | 13 ++- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts b/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts index 169f7d50..e870c9b5 100644 --- a/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts +++ b/src/vs/workbench/contrib/void/browser/helperServices/inlineDiffsServiceBackup.ts @@ -29,6 +29,7 @@ // import { URI } from '../../../../base/common/uri.js'; // import { LLMFeatureSelection, ServiceSendLLMMessageParams } from '../../../../platform/void/common/llmMessageTypes.js'; // import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js'; +// import { IZoneStyleService } from './helperServices/zoneStyleService.js'; // const configOfBG = (color: Color) => { @@ -132,6 +133,7 @@ // @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, // undoRedo service is the history of pressing ctrl+z // @ILanguageService private readonly _langService: ILanguageService, // @ILLMMessageService private readonly _llmMessageService: ILLMMessageService, +// @IZoneStyleService private readonly _zoneStyleService: IZoneStyleService, // ) { // super(); @@ -150,20 +152,16 @@ // // it's as if we just called _write, now all we need to do is realign and refresh // if (this._weAreWriting) return // const uri = model.uri -// // realign // for (const change of e.changes) { this._realignAllDiffAreasLines(uri, change.text, change.range) } -// // refresh // this._refreshDiffsInURI(uri) // }) // ) // } -// // initialize all existing models +// // initialize all existing models + initialize when a new model mounts // for (let model of this._modelService.getModels()) { initializeModel(model) } -// // initialize whenever a new model mounts // this._register(this._modelService.onModelAdded(model => initializeModel(model))); - // // this function adds listeners to refresh styles when editor changes tab // let initializeEditor = (editor: ICodeEditor) => { // const uri = editor.getModel()?.uri ?? null @@ -175,11 +173,9 @@ // if (e.newModelUrl) this._refreshDiffsInURI(e.newModelUrl) // })) // } -// // add listeners for all existing editors +// // add listeners for all existing editors + listen for editor being added // for (let editor of this._editorService.listCodeEditors()) { initializeEditor(editor) } -// // add listeners when an editor is created -// this._register(this._editorService.onCodeEditorAdd(editor => { console.log('ADD EDITOR'); initializeEditor(editor) })) -// this._register(this._editorService.onCodeEditorRemove(editor => { console.log('REMOVE EDITOR'); initializeEditor(editor) })) +// this._register(this._editorService.onCodeEditorAdd(editor => { initializeEditor(editor) })) // } @@ -227,14 +223,16 @@ // } -// private _addDiffStylesToEditor = (editor: ICodeEditor, diff: Diff) => { +// private _addDiffStylesToURI = (uri: URI, diff: Diff) => { // const { type, diffid } = diff // const disposeInThisEditorFns: (() => void)[] = [] +// const model = this._modelService.getModel(uri) + // // green decoration and minimap decoration // if (type !== 'deletion') { -// const fn = this._addLineDecoration(editor.getModel(), diff.startLine, diff.endLine, 'void-greenBG', { +// const fn = this._addLineDecoration(model, diff.startLine, diff.endLine, 'void-greenBG', { // minimap: { color: { id: 'minimapGutter.addedBackground' }, position: 2 }, // overviewRuler: { color: { id: 'editorOverviewRuler.addedForeground' }, position: 7 } // }) @@ -244,47 +242,55 @@ // // red in a view zone // if (type !== 'insertion') { -// editor.changeViewZones(accessor => { +// const consistentZoneId = this._zoneStyleService.addConsistentZoneToURI( -// const domNode = document.createElement('div'); -// domNode.className = 'void-redBG' +// uri, -// const renderOptions = RenderOptions.fromEditor(editor); -// // applyFontInfo(domNode, renderOptions.fontInfo) +// (editor) => { +// const domNode = document.createElement('div'); +// domNode.className = 'void-redBG' -// // Compute view-lines based on redText -// const redText = diff.originalCode -// const lines = redText.split('\n'); -// const lineTokens = lines.map(line => LineTokens.createFromTextAndMetadata([{ text: line, metadata: 0 }], this._langService.languageIdCodec)); -// const source = new LineSource(lineTokens, lines.map(() => null), false, false) -// const result = renderLines(source, renderOptions, [], domNode); +// const renderOptions = RenderOptions.fromEditor(editor); +// // applyFontInfo(domNode, renderOptions.fontInfo) -// const viewZone: IViewZone = { -// // afterLineNumber: computedDiff.startLine - 1, -// afterLineNumber: type === 'edit' ? diff.endLine : diff.startLine - 1, -// heightInLines: result.heightInLines, -// minWidthInPx: result.minWidthInPx, -// domNode: domNode, -// marginDomNode: document.createElement('div'), // displayed to left -// suppressMouseDown: true, -// }; +// // Compute view-lines based on redText +// const redText = diff.originalCode +// const lines = redText.split('\n'); +// const lineTokens = lines.map(line => LineTokens.createFromTextAndMetadata([{ text: line, metadata: 0 }], this._langService.languageIdCodec)); +// const source = new LineSource(lineTokens, lines.map(() => null), false, false) +// const result = renderLines(source, renderOptions, [], domNode); + +// const viewZone: IViewZone = { +// // afterLineNumber: computedDiff.startLine - 1, +// afterLineNumber: type === 'edit' ? diff.endLine : diff.startLine - 1, +// heightInLines: result.heightInLines, +// minWidthInPx: result.minWidthInPx, +// domNode: domNode, +// marginDomNode: document.createElement('div'), // displayed to left +// suppressMouseDown: true, +// }; +// return viewZone +// }, + +// (editor) => { +// // Accept | Reject widget +// const buttonsWidget = new AcceptRejectWidget({ +// editor, +// onAccept: () => { this.acceptDiff({ diffid }) }, +// onReject: () => { this.rejectDiff({ diffid }) }, +// diffid: diffid.toString(), +// startLine: diff.startLine, +// }) +// return () => buttonsWidget.dispose() +// } +// ) + +// disposeInThisEditorFns.push(() => { this._zoneStyleService.removeConsistentZoneFromURI(consistentZoneId) }) -// const zoneId = accessor.addZone(viewZone) -// disposeInThisEditorFns.push(() => { editor.changeViewZones(accessor => { if (zoneId) accessor.removeZone(zoneId) }) }) -// }); // } -// // Accept | Reject widget -// const buttonsWidget = new AcceptRejectWidget({ -// editor, -// onAccept: () => { this.acceptDiff({ diffid }) }, -// onReject: () => { this.rejectDiff({ diffid }) }, -// diffid: diffid.toString(), -// startLine: diff.startLine, -// }) -// disposeInThisEditorFns.push(() => { buttonsWidget.dispose() }) // const disposeInEditor = () => { disposeInThisEditorFns.forEach(f => f()) } // return disposeInEditor; @@ -499,7 +505,6 @@ // this._clearAllDiffsAndStyles(uri) // // 2. recompute all diffs on each editor with this URI -// const editors = this._editorService.listCodeEditors().filter(editor => editor.getModel()?.uri.fsPath === uri.fsPath) // const fullFileText = this._readURI(uri) ?? '' @@ -520,10 +525,8 @@ // diffareaid: diffArea.diffareaid, // } -// for (let editor of editors) { -// const fn = this._addDiffStylesToEditor(editor, newDiff) -// this.removeStylesFnsOfURI[uri.fsPath].add(() => fn()) -// } +// const fn = this._addDiffStylesToURI(uri, newDiff) +// this.removeStylesFnsOfURI[uri.fsPath].add(fn) // this.diffOfId[diffid] = newDiff // diffArea._diffOfId[diffid] = newDiff diff --git a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts index cc6277e4..50a51301 100644 --- a/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts +++ b/src/vs/workbench/contrib/void/browser/inlineDiffsService.ts @@ -150,16 +150,20 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { // it's as if we just called _write, now all we need to do is realign and refresh if (this._weAreWriting) return const uri = model.uri + // realign for (const change of e.changes) { this._realignAllDiffAreasLines(uri, change.text, change.range) } + // refresh this._refreshDiffsInURI(uri) }) ) } - // initialize all existing models + initialize when a new model mounts + // initialize all existing models for (let model of this._modelService.getModels()) { initializeModel(model) } + // initialize whenever a new model mounts this._register(this._modelService.onModelAdded(model => initializeModel(model))); + // this function adds listeners to refresh styles when editor changes tab let initializeEditor = (editor: ICodeEditor) => { const uri = editor.getModel()?.uri ?? null @@ -171,16 +175,17 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService { if (e.newModelUrl) this._refreshDiffsInURI(e.newModelUrl) })) } - // add listeners for all existing editors + listen for editor being added + // add listeners for all existing editors for (let editor of this._editorService.listCodeEditors()) { initializeEditor(editor) } - this._register(this._editorService.onCodeEditorAdd(editor => { initializeEditor(editor) })) + // add listeners when an editor is created + this._register(this._editorService.onCodeEditorAdd(editor => { console.log('ADD EDITOR'); initializeEditor(editor) })) + this._register(this._editorService.onCodeEditorRemove(editor => { console.log('REMOVE EDITOR'); initializeEditor(editor) })) } - // highlight the region private _addLineDecoration = (model: ITextModel | null, startLine: number, endLine: number, className: string, options?: Partial) => { if (model === null) return