model selection is accurate now, and lots of files moved to be more accurate

This commit is contained in:
Andrew Pareles 2024-12-15 20:43:08 -08:00
parent a42ff2d59a
commit 8b25f80e9b
28 changed files with 462 additions and 438 deletions

View file

@ -10,6 +10,7 @@
"jsdoc",
"header",
"local"
// "react" // Void
],
"rules": {
"constructor-super": "warn",

View file

@ -5,8 +5,8 @@
// llmMessage
import '../common/llmMessageService.js'
// voidConfig
import '../common/voidConfigService.js'
// voidSettings
import '../common/voidSettingsService.js'
// refreshModel
import '../common/refreshModelService.js'

View file

@ -11,7 +11,7 @@ import { generateUuid } from '../../../base/common/uuid.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
import { Event } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { IVoidConfigStateService } from './voidConfigService.js';
import { IVoidSettingsService } from './voidSettingsService.js';
// import { INotificationService } from '../../notification/common/notification.js';
// calls channel to implement features
@ -42,7 +42,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
constructor(
@IMainProcessService private readonly mainProcessService: IMainProcessService, // used as a renderer (only usable on client side)
@IVoidConfigStateService private readonly voidConfigStateService: IVoidConfigStateService,
@IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService,
// @INotificationService private readonly notificationService: INotificationService,
) {
super()
@ -79,7 +79,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
const { featureName } = proxyParams
// end early if no provider
const modelSelection = this.voidConfigStateService.state.modelSelectionOfFeature[featureName]
const modelSelection = this.voidSettingsService.state.modelSelectionOfFeature[featureName]
if (modelSelection === null) {
onError({ message: 'Please add a Provider in Settings!', fullError: null })
return null
@ -92,7 +92,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
this.onFinalMessageHooks_llm[requestId_] = onFinalMessage
this.onErrorHooks_llm[requestId_] = onError
const { settingsOfProvider } = this.voidConfigStateService.state
const { settingsOfProvider } = this.voidSettingsService.state
// params will be stripped of all its functions over the IPC channel
this.channel.call('sendLLMMessage', {
@ -116,7 +116,7 @@ export class LLMMessageService extends Disposable implements ILLMMessageService
ollamaList = (params: ServiceOllamaListParams) => {
const { onSuccess, onError, ...proxyParams } = params
const { settingsOfProvider } = this.voidConfigStateService.state
const { settingsOfProvider } = this.voidSettingsService.state
// add state for request id
const requestId_ = generateUuid();

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IRange } from '../../../editor/common/core/range'
import { ProviderName, SettingsOfProvider } from './voidConfigTypes'
import { ProviderName, SettingsOfProvider } from './voidSettingsTypes.js'
export type OnText = (p: { newText: string, fullText: string }) => void

View file

@ -5,7 +5,7 @@
import { createDecorator } from '../../instantiation/common/instantiation.js';
import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
import { IVoidConfigStateService } from './voidConfigService.js';
import { IVoidSettingsService } from './voidSettingsService.js';
import { ILLMMessageService } from './llmMessageService.js';
import { Emitter, Event } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
@ -38,7 +38,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
readonly onDidChangeState: Event<void> = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes
constructor(
@IVoidConfigStateService private readonly voidConfigStateService: IVoidConfigStateService,
@IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService,
@ILLMMessageService private readonly llmMessageService: ILLMMessageService,
) {
super()
@ -46,11 +46,11 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
// on mount, refresh ollama models
this.refreshOllamaModels()
// every time ollama.enabled changes, refresh ollama models
let relevantVals = () => [this.voidConfigStateService.state.settingsOfProvider.ollama.enabled, this.voidConfigStateService.state.settingsOfProvider.ollama.endpoint]
// every time ollama.enabled changes, refresh ollama models, like useEffect
let relevantVals = () => [this.voidSettingsService.state.settingsOfProvider.ollama.enabled, this.voidSettingsService.state.settingsOfProvider.ollama.endpoint]
let prevVals = relevantVals()
this._register(
this.voidConfigStateService.onDidChangeState(() => { // we might want to debounce this
this.voidSettingsService.onDidChangeState(() => { // we might want to debounce this
const newVals = relevantVals()
if (!eq(prevVals, newVals)) {
this.refreshOllamaModels()
@ -75,7 +75,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
this._cancelTimeout()
// if ollama is disabled, obivously done
if (this.voidConfigStateService.state.settingsOfProvider.ollama.enabled !== 'true') {
if (this.voidSettingsService.state.settingsOfProvider.ollama.enabled !== 'true') {
this._setState('done')
return
}
@ -85,7 +85,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
this.llmMessageService.ollamaList({
onSuccess: ({ models }) => {
this.voidConfigStateService.setSettingOfProvider('ollama', 'models', models.map(model => model.name))
this.voidSettingsService.setSettingOfProvider('ollama', 'models', models.map(model => model.name))
this._setState('done')
},
onError: ({ error }) => {

View file

@ -1,137 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Glass Devtools, Inc. All rights reserved.
* Void Editor additions licensed under the AGPL 3.0 License.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { deepClone } from '../../../base/common/objects.js';
import { IEncryptionService } from '../../encryption/common/encryptionService.js';
import { registerSingleton, InstantiationType } from '../../instantiation/common/extensions.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
import { IStorageService, StorageScope, StorageTarget } from '../../storage/common/storage.js';
import { defaultVoidProviderState, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName } from './voidConfigTypes.js';
const STORAGE_KEY = 'void.voidConfigStateII'
type SetSettingOfProviderFn = <S extends SettingName>(
providerName: ProviderName,
settingName: S,
newVal: SettingsOfProvider[ProviderName][S extends keyof SettingsOfProvider[ProviderName] ? S : never],
) => Promise<void>;
type SetModelSelectionOfFeature = <K extends FeatureName>(
featureName: K,
newVal: ModelSelectionOfFeature[K],
) => Promise<void>;
type VoidConfigState = {
readonly settingsOfProvider: SettingsOfProvider; // optionsOfProvider
readonly modelSelectionOfFeature: ModelSelectionOfFeature; // stateOfFeature
}
export interface IVoidConfigStateService {
readonly _serviceBrand: undefined;
readonly state: VoidConfigState;
onDidChangeState: Event<void>;
setSettingOfProvider: SetSettingOfProviderFn;
setModelSelectionOfFeature: SetModelSelectionOfFeature;
}
const defaultState = () => {
const d: VoidConfigState = {
settingsOfProvider: deepClone(defaultVoidProviderState),
modelSelectionOfFeature: { 'Ctrl+L': null, 'Ctrl+K': null, 'Autocomplete': null }
}
return d
}
export const IVoidConfigStateService = createDecorator<IVoidConfigStateService>('VoidConfigStateService');
class VoidConfigService extends Disposable implements IVoidConfigStateService {
_serviceBrand: undefined;
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes
state: VoidConfigState;
constructor(
@IStorageService private readonly _storageService: IStorageService,
@IEncryptionService private readonly _encryptionService: IEncryptionService,
// could have used this, but it's clearer the way it is (+ slightly different eg StorageTarget.USER)
// @ISecretStorageService private readonly _secretStorageService: ISecretStorageService,
) {
super()
// at the start, we haven't read the partial config yet, but we need to set state to something
this.state = defaultState()
// read and update the actual state immediately
this._readVoidConfigState().then(voidConfigState => {
this._setState(voidConfigState)
})
}
private async _readVoidConfigState(): Promise<VoidConfigState> {
const encryptedPartialConfig = this._storageService.get(STORAGE_KEY, StorageScope.APPLICATION)
if (!encryptedPartialConfig)
return defaultState()
const voidConfigStateStr = await this._encryptionService.decrypt(encryptedPartialConfig)
return JSON.parse(voidConfigStateStr)
}
private async _storeVoidConfigState(voidConfigState: VoidConfigState) {
const encryptedVoidConfigStr = await this._encryptionService.encrypt(JSON.stringify(voidConfigState))
this._storageService.store(STORAGE_KEY, encryptedVoidConfigStr, StorageScope.APPLICATION, StorageTarget.USER);
}
setSettingOfProvider: SetSettingOfProviderFn = async (providerName, settingName, newVal) => {
const newState: VoidConfigState = {
...this.state,
settingsOfProvider: {
...this.state.settingsOfProvider,
[providerName]: {
...this.state.settingsOfProvider[providerName],
[settingName]: newVal,
}
},
}
// console.log('NEW STATE I', JSON.stringify(newState, null, 2))
await this._storeVoidConfigState(newState)
this._setState(newState)
}
setModelSelectionOfFeature: SetModelSelectionOfFeature = async (featureName, newVal) => {
const newState: VoidConfigState = {
...this.state,
modelSelectionOfFeature: {
...this.state.modelSelectionOfFeature,
[featureName]: newVal
}
}
// console.log('NEW STATE II', JSON.stringify(newState, null, 2))
await this._storeVoidConfigState(newState)
this._setState(newState)
}
// internal function to update state, should be called every time state changes
private async _setState(voidConfigState: VoidConfigState) {
this.state = voidConfigState
this._onDidChangeState.fire()
}
}
registerSingleton(IVoidConfigStateService, VoidConfigService, InstantiationType.Eager);

View file

@ -0,0 +1,191 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Glass Devtools, Inc. All rights reserved.
* Void Editor additions licensed under the AGPL 3.0 License.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { deepClone } from '../../../base/common/objects.js';
import { IEncryptionService } from '../../encryption/common/encryptionService.js';
import { registerSingleton, InstantiationType } from '../../instantiation/common/extensions.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
import { IStorageService, StorageScope, StorageTarget } from '../../storage/common/storage.js';
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames } from './voidSettingsTypes.js';
const STORAGE_KEY = 'void.voidConfigStateIV'
type SetSettingOfProviderFn = <S extends SettingName>(
providerName: ProviderName,
settingName: S,
newVal: SettingsOfProvider[ProviderName][S extends keyof SettingsOfProvider[ProviderName] ? S : never],
) => Promise<void>;
type SetModelSelectionOfFeature = <K extends FeatureName>(
featureName: K,
newVal: ModelSelectionOfFeature[K],
options?: { doNotApplyEffects?: true }
) => Promise<void>;
type ModelOption = { text: string, value: ModelSelection }
export type VoidSettingsState = {
readonly settingsOfProvider: SettingsOfProvider; // optionsOfProvider
readonly modelSelectionOfFeature: ModelSelectionOfFeature; // stateOfFeature
readonly _modelsList: ModelOption[] // computed based on the two above items
}
export interface IVoidSettingsService {
readonly _serviceBrand: undefined;
readonly state: VoidSettingsState;
onDidChangeState: Event<void>;
setSettingOfProvider: SetSettingOfProviderFn;
setModelSelectionOfFeature: SetModelSelectionOfFeature;
}
let _computeModelsList = (settingsOfProvider: SettingsOfProvider) => {
let modelsList: ModelOption[] = []
for (const providerName of providerNames) {
const providerConfig = settingsOfProvider[providerName]
if (providerConfig.enabled !== 'true') continue
providerConfig.models?.forEach(modelName => {
modelsList.push({ text: `${modelName} (${providerName})`, value: { providerName, modelName } })
})
}
return modelsList
}
const defaultState = () => {
const d: VoidSettingsState = {
settingsOfProvider: deepClone(defaultSettingsOfProvider),
modelSelectionOfFeature: { 'Ctrl+L': null, 'Ctrl+K': null, 'Autocomplete': null },
_modelsList: _computeModelsList(defaultSettingsOfProvider),
}
return d
}
export const IVoidSettingsService = createDecorator<IVoidSettingsService>('VoidSettingsService');
class VoidSettingsService extends Disposable implements IVoidSettingsService {
_serviceBrand: undefined;
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes
state: VoidSettingsState;
constructor(
@IStorageService private readonly _storageService: IStorageService,
@IEncryptionService private readonly _encryptionService: IEncryptionService,
// could have used this, but it's clearer the way it is (+ slightly different eg StorageTarget.USER)
// @ISecretStorageService private readonly _secretStorageService: ISecretStorageService,
) {
super()
// at the start, we haven't read the partial config yet, but we need to set state to something
this.state = defaultState()
// read and update the actual state immediately
this._readState().then(s => {
this.state = s
this._onDidChangeState.fire()
})
}
private async _readState(): Promise<VoidSettingsState> {
const encryptedState = this._storageService.get(STORAGE_KEY, StorageScope.APPLICATION)
if (!encryptedState)
return defaultState()
const stateStr = await this._encryptionService.decrypt(encryptedState)
return JSON.parse(stateStr)
}
private async _storeState() {
const state = this.state
const encryptedState = await this._encryptionService.encrypt(JSON.stringify(state))
this._storageService.store(STORAGE_KEY, encryptedState, StorageScope.APPLICATION, StorageTarget.USER);
}
setSettingOfProvider: SetSettingOfProviderFn = async (providerName, settingName, newVal) => {
const newModelSelectionOfFeature = this.state.modelSelectionOfFeature
const newSettingsOfProvider = {
...this.state.settingsOfProvider,
[providerName]: {
...this.state.settingsOfProvider[providerName],
[settingName]: newVal,
}
}
// if changed models or enabled a provider, recompute models list
const modelsListChanged = settingName === 'models' || settingName === 'enabled'
const newModelsList = modelsListChanged ? _computeModelsList(newSettingsOfProvider) : this.state._modelsList
const newState: VoidSettingsState = {
modelSelectionOfFeature: newModelSelectionOfFeature,
settingsOfProvider: newSettingsOfProvider,
_modelsList: newModelsList,
}
// this must go above this.setanythingelse()
this.state = newState
// if the user-selected model is no longer in the list, update the selection for each feature that needs it to something relevant (the 0th model available, or null)
if (modelsListChanged) {
for (const featureName of featureNames) {
const currentSelection = newModelSelectionOfFeature[featureName]
const selnIdx = currentSelection === null ? -1 : newModelsList.findIndex(m => modelSelectionsEqual(m.value, currentSelection))
if (selnIdx === -1) {
if (newModelsList.length !== 0)
this.setModelSelectionOfFeature(featureName, newModelsList[0].value, { doNotApplyEffects: true })
else
this.setModelSelectionOfFeature(featureName, null, { doNotApplyEffects: true })
}
}
}
await this._storeState()
this._onDidChangeState.fire()
}
setModelSelectionOfFeature: SetModelSelectionOfFeature = async (featureName, newVal, options) => {
const newState: VoidSettingsState = {
...this.state,
modelSelectionOfFeature: {
...this.state.modelSelectionOfFeature,
[featureName]: newVal
}
}
this.state = newState
if (options?.doNotApplyEffects)
return
console.log('NEW STATE II', JSON.stringify(newState, null, 2))
await this._storeState()
this._onDidChangeState.fire()
}
}
registerSingleton(IVoidSettingsService, VoidSettingsService, InstantiationType.Eager);

View file

@ -76,12 +76,12 @@ export const anthropicMaxPossibleTokens = (modelName: string) => {
}
export const dummyModelData = {
anthropic: ['claude 3.5'],
openAI: ['gpt 4o'],
ollama: ['llama 3.2', 'codestral'],
openRouter: ['qwen 2.5'],
}
// export const dummyModelData = {
// anthropic: ['claude 3.5'],
// openAI: ['gpt 4o'],
// ollama: ['llama 3.2', 'codestral'],
// openRouter: ['qwen 2.5'],
// }
@ -234,7 +234,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
// used when waiting and for a type reference
export const defaultVoidProviderState: SettingsOfProvider = {
export const defaultSettingsOfProvider: SettingsOfProvider = {
anthropic: {
...voidProviderDefaults.anthropic,
...voidInitModelOptions.anthropic,
@ -273,21 +273,17 @@ export const defaultVoidProviderState: SettingsOfProvider = {
}
export type ModelSelection = { providerName: ProviderName, modelName: string }
export const modelSelectionsEqual = (m1: ModelSelection, m2: ModelSelection) => {
return m1.modelName === m2.modelName && m1.providerName === m2.providerName
}
// this is a state
export type ModelSelectionOfFeature = {
'Ctrl+L': {
providerName: ProviderName,
modelName: string,
} | null,
'Ctrl+K': {
providerName: ProviderName,
modelName: string,
} | null,
'Autocomplete': {
providerName: ProviderName,
modelName: string,
} | null,
'Ctrl+L': ModelSelection | null,
'Ctrl+K': ModelSelection | null,
'Autocomplete': ModelSelection | null,
}
export type FeatureName = keyof ModelSelectionOfFeature
export const featureNames = ['Ctrl+L', 'Ctrl+K', 'Autocomplete'] as const

View file

@ -5,7 +5,7 @@
import Anthropic from '@anthropic-ai/sdk';
import { _InternalSendLLMMessageFnType } from '../../common/llmMessageTypes.js';
import { anthropicMaxPossibleTokens } from '../../common/voidConfigTypes.js';
import { anthropicMaxPossibleTokens } from '../../common/voidSettingsTypes.js';
// Anthropic
type LLMMessageAnthropic = {

View file

@ -1 +0,0 @@
void-imports/

View file

@ -3,7 +3,7 @@
* Void Editor additions licensed under the AGPL 3.0 License.
*--------------------------------------------------------------------------------------------*/
import { diffLines } from './react/out/diff/index.js'
import { diffLines } from '../react/out/diff/index.js'
export type ComputedDiff = {
type: 'edit';

View file

@ -3,7 +3,7 @@
* Void Editor additions licensed under the AGPL 3.0 License.
*--------------------------------------------------------------------------------------------*/
import { isMacintosh } from '../../../../base/common/platform.js';
import { isMacintosh } from '../../../../../base/common/platform.js';
// import { OperatingSystem, OS } from '../../../../base/common/platform.js';
// OS === OperatingSystem.Macintosh

View file

@ -0,0 +1,51 @@
import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';
import { IModelService } from '../../../../../editor/common/services/model.js';
import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';
import { IContextViewService, IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js';
import { IFileService } from '../../../../../platform/files/common/files.js';
import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
import { IThemeService } from '../../../../../platform/theme/common/themeService.js';
import { ILLMMessageService } from '../../../../../platform/void/common/llmMessageService.js';
import { IRefreshModelService } from '../../../../../platform/void/common/refreshModelService.js';
import { IVoidSettingsService } from '../../../../../platform/void/common/voidSettingsService.js';
import { IInlineDiffsService } from '../inlineDiffsService.js';
import { ISidebarStateService } from '../sidebarStateService.js';
import { IThreadHistoryService } from '../threadHistoryService.js';
export type ReactServicesType = {
sidebarStateService: ISidebarStateService;
settingsStateService: IVoidSettingsService;
threadsStateService: IThreadHistoryService;
fileService: IFileService;
modelService: IModelService;
inlineDiffService: IInlineDiffsService;
llmMessageService: ILLMMessageService;
clipboardService: IClipboardService;
refreshModelService: IRefreshModelService;
themeService: IThemeService,
hoverService: IHoverService,
contextViewService: IContextViewService;
contextMenuService: IContextMenuService;
}
export const getReactServices = (accessor: ServicesAccessor): ReactServicesType => {
return {
settingsStateService: accessor.get(IVoidSettingsService),
sidebarStateService: accessor.get(ISidebarStateService),
threadsStateService: accessor.get(IThreadHistoryService),
fileService: accessor.get(IFileService),
modelService: accessor.get(IModelService),
inlineDiffService: accessor.get(IInlineDiffsService),
llmMessageService: accessor.get(ILLMMessageService),
clipboardService: accessor.get(IClipboardService),
themeService: accessor.get(IThemeService),
hoverService: accessor.get(IHoverService),
refreshModelService: accessor.get(IRefreshModelService),
contextViewService: accessor.get(IContextViewService),
contextMenuService: accessor.get(IContextMenuService),
}
}

View file

@ -11,9 +11,8 @@ import { ICodeEditor, IOverlayWidget, IViewZone } from '../../../../editor/brows
// import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
// import { throttle } from '../../../../base/common/decorators.js';
// import { IVoidConfigStateService } from './registerConfig.js';
import { writeFileWithDiffInstructions } from './prompt/systemPrompts.js';
import { ComputedDiff, findDiffs } from './findDiffs.js';
import { ComputedDiff, findDiffs } from './helpers/findDiffs.js';
import { EndOfLinePreference, ITextModel } from '../../../../editor/common/model.js';
import { IRange } from '../../../../editor/common/core/range.js';
import { registerColor } from '../../../../platform/theme/common/colorUtils.js';
@ -144,7 +143,6 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
constructor(
// @IHistoryService private readonly _historyService: IHistoryService, // history service is the history of pressing alt left/right
// @IVoidConfigStateService private readonly _voidConfigStateService: IVoidConfigStateService,
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@IModelService private readonly _modelService: IModelService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService, // undoRedo service is the history of pressing ctrl+z

View file

@ -3,7 +3,7 @@
* Void Editor additions licensed under the AGPL 3.0 License.
*--------------------------------------------------------------------------------------------*/
import { CodeSelection } from '../registerThreads.js';
import { CodeSelection } from '../threadHistoryService.js';
export const stringifySelections = (selections: CodeSelection[]) => {

View file

@ -6,10 +6,10 @@
import React, { FormEvent, Fragment, useCallback, useEffect, useRef, useState } from 'react';
import { useConfigState, useService, useSidebarState, useThreadsState } from '../util/services.js';
import { useSettingsState, useService, useSidebarState, useThreadsState } from '../util/services.js';
import { generateDiffInstructions } from '../../../prompt/systemPrompts.js';
import { userInstructionsStr } from '../../../prompt/stringifySelections.js';
import { ChatMessage, CodeSelection, CodeStagingSelection } from '../../../registerThreads.js';
import { ChatMessage, CodeSelection, CodeStagingSelection } from '../../../threadHistoryService.js';
import { BlockCode } from '../markdown/BlockCode.js';
import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js';
@ -19,7 +19,7 @@ import { EndOfLinePreference } from '../../../../../../../editor/common/model.js
import { IDisposable } from '../../../../../../../base/common/lifecycle.js';
import { ErrorDisplay } from './ErrorDisplay.js';
import { OnError, ServiceSendLLMMessageParams } from '../../../../../../../platform/void/common/llmMessageTypes.js';
import { getCmdKey } from '../../../getCmdKey.js'
import { getCmdKey } from '../../../helpers/getCmdKey.js'
import { HistoryInputBox, InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
import { VoidInputBox } from './inputs.js';
import { ModelSelectionOfFeature } from '../void-settings-tsx/ModelSelectionSettings.js';
@ -277,9 +277,6 @@ export const SidebarChat = () => {
return () => disposables.forEach(d => d.dispose())
}, [sidebarStateService, inputBoxRef])
// config state
const voidConfigState = useConfigState()
// threads state
const threadsState = useThreadsState()
const threadsStateService = useService('threadsStateService')

View file

@ -6,7 +6,7 @@
import React, { useEffect, useState } from 'react';
import * as ReactDOM from 'react-dom/client'
import { _registerServices } from './services.js';
import { ReactServicesType } from '../../../reactServices.js';
import { ReactServicesType } from '../../../helpers/reactServicesHelper.js';
export const mountFnGenerator = (Component: React.FC) => (rootElement: HTMLElement, services: ReactServicesType) => {

View file

@ -4,35 +4,38 @@
*--------------------------------------------------------------------------------------------*/
import { useState, useEffect } from 'react'
import { VoidSidebarState } from '../../../registerSidebar.js'
import { ThreadsState } from '../../../registerThreads.js'
import { SettingsOfProvider } from '../../../../../../../platform/void/common/voidConfigTypes.js'
import { ThreadsState } from '../../../threadHistoryService.js'
import { SettingsOfProvider } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
import { RefreshModelState } from '../../../../../../../platform/void/common/refreshModelService.js'
import { IDisposable } from '../../../../../../../base/common/lifecycle.js'
import { ReactServicesType } from '../../../reactServices.js'
import { ReactServicesType } from '../../../helpers/reactServicesHelper.js'
import { VoidSidebarState } from '../../../sidebarStateService.js'
import { VoidSettingsState } from '../../../../../../../platform/void/common/voidSettingsService.js'
// normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes
let services: ReactServicesType
// even if React hasn't mounted yet, these variables are always updated to the latest state:
// even if React hasn't mounted yet, the variables are always updated to the latest state.
// React listens by adding a setState function to these listeners.
let sidebarState: VoidSidebarState
let threadsState: ThreadsState
let settingsOfProvider: SettingsOfProvider
let refreshModelState: RefreshModelState
// React listens by adding a setState function to these:
const sidebarStateListeners: Set<(s: VoidSidebarState) => void> = new Set()
let threadsState: ThreadsState
const threadsStateListeners: Set<(s: ThreadsState) => void> = new Set()
const settingsOfProviderListeners: Set<(s: SettingsOfProvider) => void> = new Set()
let settingsState: VoidSettingsState
const settingsStateListeners: Set<(s: VoidSettingsState) => void> = new Set()
let refreshModelState: RefreshModelState
const refreshModelStateListeners: Set<(s: RefreshModelState) => void> = new Set()
// must call this before you can use any of the hooks below
// this should only be called ONCE! this is the only place you don't need to dispose onDidChange. If you use state.onDidChange anywhere else, make sure to dispose it!
let wasCalled = false
export const _registerServices = (services_: ReactServicesType) => {
const disposables: IDisposable[] = []
@ -41,7 +44,7 @@ export const _registerServices = (services_: ReactServicesType) => {
wasCalled = true
services = services_
const { sidebarStateService, configStateService, threadsStateService, refreshModelService } = services
const { sidebarStateService, settingsStateService, threadsStateService, refreshModelService } = services
sidebarState = sidebarStateService.state
disposables.push(
@ -59,11 +62,11 @@ export const _registerServices = (services_: ReactServicesType) => {
})
)
settingsOfProvider = configStateService.state.settingsOfProvider
settingsState = settingsStateService.state
disposables.push(
configStateService.onDidChangeState(() => {
settingsOfProvider = configStateService.state.settingsOfProvider
settingsOfProviderListeners.forEach(l => l(settingsOfProvider))
settingsStateService.onDidChangeState(() => {
settingsState = settingsStateService.state
settingsStateListeners.forEach(l => l(settingsState))
})
)
@ -99,12 +102,12 @@ export const useSidebarState = () => {
return s
}
export const useConfigState = () => {
const [s, ss] = useState(settingsOfProvider)
export const useSettingsState = () => {
const [s, ss] = useState(settingsState)
useEffect(() => {
ss(settingsOfProvider)
settingsOfProviderListeners.add(ss)
return () => { settingsOfProviderListeners.delete(ss) }
ss(settingsState)
settingsStateListeners.add(ss)
return () => { settingsStateListeners.delete(ss) }
}, [ss])
return s
}

View file

@ -4,66 +4,44 @@
*--------------------------------------------------------------------------------------------*/
import { useCallback, useEffect, useRef, useState } from 'react'
import { FeatureName, featureNames, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidConfigTypes.js'
import { dummyModelData } from '../../../../../../../platform/void/common/voidConfigTypes.js'
import { useConfigState, useRefreshModelState, useService } from '../util/services.js'
import { FeatureName, featureNames, ModelSelection, modelSelectionsEqual, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
import { useSettingsState, useRefreshModelState, useService } from '../util/services.js'
import { VoidSelectBox } from '../sidebar-tsx/inputs.js'
import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js'
export const ModelSelectionOfFeature = ({ featureName }: { featureName: FeatureName }) => {
const voidConfigService = useService('configStateService')
const voidConfigState = useConfigState()
const modelOptions: { text: string, value: [string, string] }[] = []
for (const providerName of providerNames) {
const providerConfig = voidConfigState[providerName]
if (providerConfig.enabled !== 'true') continue
providerConfig.models?.forEach(model => {
modelOptions.push({ text: `${model} (${providerName})`, value: [providerName, model] })
})
}
const isDummy = modelOptions.length === 0
if (isDummy) {
for (const [providerName, models] of Object.entries(dummyModelData)) {
for (let model of models) {
modelOptions.push({ text: `${model} (${providerName})`, value: ['dummy', 'dummy'] })
}
}
}
const voidSettingsService = useService('settingsStateService')
const settingsState = useSettingsState()
let weChangedText = false
return <>
<h2>{featureName}</h2>
{
<VoidSelectBox
options={modelOptions}
onChangeSelection={useCallback((newVal: [string, string]) => {
if (isDummy) return // don't set state to the dummy value
options={settingsState._modelsList}
onChangeSelection={useCallback((newVal: ModelSelection) => {
if (weChangedText) return
voidConfigService.setModelSelectionOfFeature(featureName, { providerName: newVal[0] as ProviderName, modelName: newVal[1] })
}, [voidConfigService, featureName, isDummy])}
voidSettingsService.setModelSelectionOfFeature(featureName, newVal)
}, [voidSettingsService, featureName])}
// we are responsible for setting the initial state here. always sync instance when state changes.
onCreateInstance={useCallback((instance: SelectBox) => {
const syncInstance = () => {
const settingsAtProvider = voidConfigService.state.modelSelectionOfFeature[featureName]
const index = modelOptions.findIndex(v => v.value[0] === settingsAtProvider?.providerName && v.value[1] === settingsAtProvider?.modelName)
if (index !== -1) {
const modelsListRef = voidSettingsService.state._modelsList // as a ref
const settingsAtProvider = voidSettingsService.state.modelSelectionOfFeature[featureName]
const selectionIdx = settingsAtProvider === null ? -1 : modelsListRef.findIndex(v => modelSelectionsEqual(v.value, settingsAtProvider))
if (selectionIdx !== -1) {
weChangedText = true
instance.select(index)
instance.select(selectionIdx)
weChangedText = false
}
}
syncInstance()
const disposable = voidConfigService.onDidChangeState(syncInstance)
const disposable = voidSettingsService.onDidChangeState(syncInstance)
return [disposable]
}, [voidConfigService, modelOptions, featureName])}
}, [voidSettingsService, featureName])}
/>}
</>

View file

@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
import { titleOfProviderName, displayInfoOfSettingName, ProviderName, providerNames, featureNames, SettingsOfProvider, SettingName, defaultVoidProviderState } from '../../../../../../../platform/void/common/voidConfigTypes.js'
import { titleOfProviderName, displayInfoOfSettingName, ProviderName, providerNames, featureNames, SettingsOfProvider, SettingName, defaultSettingsOfProvider } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
import { VoidInputBox } from '../sidebar-tsx/inputs.js'
import { useConfigState, useService } from '../util/services.js'
import { useSettingsState, useService } from '../util/services.js'
import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
@ -14,41 +14,34 @@ import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
const Setting = ({ providerName, settingName }: { providerName: ProviderName, settingName: SettingName }) => {
const { title, type, placeholder } = displayInfoOfSettingName(providerName, settingName)
const voidConfigService = useService('configStateService')
const voidSettingsService = useService('settingsStateService')
let weChangedText = false
let weChangedTextRef = false
return <><ErrorBoundary>
<label>{title}</label>
<VoidInputBox
placeholder={placeholder}
onChangeText={useCallback((newVal) => {
if (weChangedText) return
voidConfigService.setSettingOfProvider(providerName, settingName, newVal)
// if we just disabeld this provider, we should unselect all models that use it
if (settingName === 'enabled' && newVal !== 'true') {
for (let featureName of featureNames) {
if (voidConfigService.state.modelSelectionOfFeature[featureName]?.providerName === providerName)
voidConfigService.setModelSelectionOfFeature(featureName, null)
}
}
}, [voidConfigService, providerName, settingName])}
if (weChangedTextRef) return
voidSettingsService.setSettingOfProvider(providerName, settingName, newVal)
}, [voidSettingsService, providerName, settingName])}
// we are responsible for setting the initial value. always sync the instance whenever there's a change to state.
onCreateInstance={useCallback((instance: InputBox) => {
const syncInstance = () => {
const settingsAtProvider = voidConfigService.state.settingsOfProvider[providerName];
const settingsAtProvider = voidSettingsService.state.settingsOfProvider[providerName];
const stateVal = settingsAtProvider[settingName as keyof typeof settingsAtProvider]
weChangedText = true
// console.log('SYNCING TO', providerName, settingName, stateVal)
weChangedTextRef = true
instance.value = stateVal as string
weChangedText = false
weChangedTextRef = false
}
syncInstance()
const disposable = voidConfigService.onDidChangeState(syncInstance)
const disposable = voidSettingsService.onDidChangeState(syncInstance)
return [disposable]
}, [voidConfigService, providerName, settingName])}
}, [voidSettingsService, providerName, settingName])}
multiline={false}
/>
</ErrorBoundary></>
@ -57,8 +50,8 @@ const Setting = ({ providerName, settingName }: { providerName: ProviderName, se
const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) => {
const voidConfigState = useConfigState()
const { models, ...others } = voidConfigState[providerName]
const voidSettingsState = useSettingsState()
const { models, ...others } = voidSettingsState.settingsOfProvider[providerName]
return <>
<h1 className='text-xl'>{titleOfProviderName(providerName)}</h1>
@ -77,7 +70,5 @@ export const VoidProviderSettings = () => {
{providerNames.map(providerName =>
<SettingsForProvider key={providerName} providerName={providerName} />
)}
</>
}

View file

@ -1,51 +0,0 @@
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
import { IModelService } from '../../../../editor/common/services/model.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
import { IContextViewService, IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
import { IFileService } from '../../../../platform/files/common/files.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js';
import { IRefreshModelService } from '../../../../platform/void/common/refreshModelService.js';
import { IVoidConfigStateService } from '../../../../platform/void/common/voidConfigService.js';
import { IInlineDiffsService } from './registerInlineDiffs.js';
import { IVoidSidebarStateService } from './registerSidebar.js';
import { IThreadHistoryService } from './registerThreads.js';
export type ReactServicesType = {
sidebarStateService: IVoidSidebarStateService;
configStateService: IVoidConfigStateService;
threadsStateService: IThreadHistoryService;
fileService: IFileService;
modelService: IModelService;
inlineDiffService: IInlineDiffsService;
llmMessageService: ILLMMessageService;
clipboardService: IClipboardService;
refreshModelService: IRefreshModelService;
themeService: IThemeService,
hoverService: IHoverService,
contextViewService: IContextViewService;
contextMenuService: IContextMenuService;
}
export const getReactServices = (accessor: ServicesAccessor): ReactServicesType => {
return {
configStateService: accessor.get(IVoidConfigStateService),
sidebarStateService: accessor.get(IVoidSidebarStateService),
threadsStateService: accessor.get(IThreadHistoryService),
fileService: accessor.get(IFileService),
modelService: accessor.get(IModelService),
inlineDiffService: accessor.get(IInlineDiffsService),
llmMessageService: accessor.get(ILLMMessageService),
clipboardService: accessor.get(IClipboardService),
themeService: accessor.get(IThemeService),
hoverService: accessor.get(IHoverService),
refreshModelService: accessor.get(IRefreshModelService),
contextViewService: accessor.get(IContextViewService),
contextMenuService: accessor.get(IContextMenuService),
}
}

View file

@ -11,16 +11,16 @@ import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { CodeStagingSelection, IThreadHistoryService } from './registerThreads.js';
import { CodeStagingSelection, IThreadHistoryService } from './threadHistoryService.js';
// import { IEditorService } from '../../../services/editor/common/editorService.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { IRange } from '../../../../editor/common/core/range.js';
import { ITextModel } from '../../../../editor/common/model.js';
import { IVoidSidebarStateService, VOID_VIEW_ID } from './registerSidebar.js';
import { VOID_VIEW_ID } from './sidebarViewPane.js';
import { IMetricsService } from '../../../../platform/void/common/metricsService.js';
// import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
import { ISidebarStateService } from './sidebarStateService.js';
// ---------- Register commands and keybindings ----------
@ -61,7 +61,7 @@ registerAction2(class extends Action2 {
if (!model)
return
const stateService = accessor.get(IVoidSidebarStateService)
const stateService = accessor.get(ISidebarStateService)
const metricsService = accessor.get(IMetricsService)
metricsService.capture('Chat Navigation', { type: 'Ctrl+L' })
@ -126,7 +126,7 @@ registerAction2(class extends Action2 {
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const stateService = accessor.get(IVoidSidebarStateService)
const stateService = accessor.get(ISidebarStateService)
const metricsService = accessor.get(IMetricsService)
metricsService.capture('Chat Navigation', { type: 'New Chat' })
@ -149,7 +149,7 @@ registerAction2(class extends Action2 {
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const stateService = accessor.get(IVoidSidebarStateService)
const stateService = accessor.get(ISidebarStateService)
const metricsService = accessor.get(IMetricsService)
metricsService.capture('Chat Navigation', { type: 'History' })
@ -159,7 +159,6 @@ registerAction2(class extends Action2 {
}
})
// // Settings (API config) menu button
// registerAction2(class extends Action2 {
// constructor() {
// super({

View file

@ -0,0 +1,84 @@
import { Emitter, Event } from '../../../../base/common/event.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { IViewsService } from '../../../services/views/common/viewsService.js';
import { VOID_VIEW_CONTAINER_ID, VOID_VIEW_ID } from './sidebarViewPane.js';
// service that manages sidebar's state
export type VoidSidebarState = {
isHistoryOpen: boolean;
currentTab: 'chat';
}
export interface ISidebarStateService {
readonly _serviceBrand: undefined;
readonly state: VoidSidebarState; // readonly to the user
setState(newState: Partial<VoidSidebarState>): void;
onDidChangeState: Event<void>;
onDidFocusChat: Event<void>;
onDidBlurChat: Event<void>;
fireFocusChat(): void;
fireBlurChat(): void;
openSidebarView(): void;
}
export const ISidebarStateService = createDecorator<ISidebarStateService>('voidSidebarStateService');
class VoidSidebarStateService extends Disposable implements ISidebarStateService {
_serviceBrand: undefined;
static readonly ID = 'voidSidebarStateService';
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
private readonly _onFocusChat = new Emitter<void>();
readonly onDidFocusChat: Event<void> = this._onFocusChat.event;
private readonly _onBlurChat = new Emitter<void>();
readonly onDidBlurChat: Event<void> = this._onBlurChat.event;
// state
state: VoidSidebarState
constructor(
@IViewsService private readonly _viewsService: IViewsService,
) {
super()
// initial state
this.state = { isHistoryOpen: false, currentTab: 'chat', }
}
setState(newState: Partial<VoidSidebarState>) {
// make sure view is open if the tab changes
if ('currentTab' in newState) {
this.openSidebarView()
}
this.state = { ...this.state, ...newState }
this._onDidChangeState.fire()
}
fireFocusChat() {
this._onFocusChat.fire()
}
fireBlurChat() {
this._onBlurChat.fire()
}
openSidebarView() {
this._viewsService.openViewContainer(VOID_VIEW_CONTAINER_ID);
this._viewsService.openView(VOID_VIEW_ID);
}
}
registerSingleton(ISidebarStateService, VoidSidebarStateService, InstantiationType.Eager);

View file

@ -24,9 +24,8 @@ import { SyncDescriptor } from '../../../../platform/instantiation/common/descri
import { IViewPaneOptions, ViewPane } from '../../../browser/parts/views/viewPane.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
import { Emitter, Event } from '../../../../base/common/event.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { IDisposable } from '../../../../base/common/lifecycle.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
@ -37,18 +36,11 @@ import { IHoverService } from '../../../../platform/hover/browser/hover.js';
import { mountSidebar } from './react/out/sidebar-tsx/index.js';
import { IViewsService } from '../../../services/views/common/viewsService.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { getReactServices } from './reactServices.js';
import { getReactServices } from './helpers/reactServicesHelper.js';
// compare against search.contribution.ts and debug.contribution.ts, scm.contribution.ts (source control)
export type VoidSidebarState = {
isHistoryOpen: boolean;
currentTab: 'chat';
}
// ---------- Define viewpane ----------
class VoidSidebarViewPane extends ViewPane {
@ -132,77 +124,3 @@ viewsRegistry.registerViews([{
// },
}], viewContainer);
// ---------- Register service that manages sidebar's state ----------
export interface IVoidSidebarStateService {
readonly _serviceBrand: undefined;
readonly state: VoidSidebarState; // readonly to the user
setState(newState: Partial<VoidSidebarState>): void;
onDidChangeState: Event<void>;
onDidFocusChat: Event<void>;
onDidBlurChat: Event<void>;
fireFocusChat(): void;
fireBlurChat(): void;
openSidebarView(): void;
}
export const IVoidSidebarStateService = createDecorator<IVoidSidebarStateService>('voidSidebarStateService');
class VoidSidebarStateService extends Disposable implements IVoidSidebarStateService {
_serviceBrand: undefined;
static readonly ID = 'voidSidebarStateService';
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
private readonly _onFocusChat = new Emitter<void>();
readonly onDidFocusChat: Event<void> = this._onFocusChat.event;
private readonly _onBlurChat = new Emitter<void>();
readonly onDidBlurChat: Event<void> = this._onBlurChat.event;
// state
state: VoidSidebarState
constructor(
@IViewsService private readonly _viewsService: IViewsService,
) {
super()
// initial state
this.state = { isHistoryOpen: false, currentTab: 'chat', }
}
setState(newState: Partial<VoidSidebarState>) {
// make sure view is open if the tab changes
if ('currentTab' in newState) {
this.openSidebarView()
}
this.state = { ...this.state, ...newState }
this._onDidChangeState.fire()
}
fireFocusChat() {
this._onFocusChat.fire()
}
fireBlurChat() {
this._onBlurChat.fire()
}
openSidebarView() {
this._viewsService.openViewContainer(VOID_VIEW_CONTAINER_ID);
this._viewsService.openView(VOID_VIEW_ID);
}
}
registerSingleton(IVoidSidebarStateService, VoidSidebarStateService, InstantiationType.Eager);

View file

@ -10,7 +10,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../platfo
import { URI } from '../../../../base/common/uri.js';
import { Emitter, Event } from '../../../../base/common/event.js';
import { IAutocompleteService } from './registerAutocomplete.js';
import { IAutocompleteService } from './autocompleteService.js';
import { IRange } from '../../../../editor/common/core/range.js';
export type CodeSelection = {
@ -80,7 +80,7 @@ const newThreadObject = () => {
}
}
const THREAD_STORAGE_KEY = 'void.threadsHistory'
const THREAD_STORAGE_KEY = 'void.threadHistory'
export interface IThreadHistoryService {
readonly _serviceBrand: undefined;

View file

@ -3,23 +3,23 @@
* Void Editor additions licensed under the AGPL 3.0 License.
*--------------------------------------------------------------------------------------------*/
// register keybinds
import './registerActions.js'
// register inline diffs
import './registerInlineDiffs.js'
import './inlineDiffsService.js'
// register Sidebar chat
import './registerSidebar.js'
// register Sidebar pane, state, actions (keybinds, menus)
import './sidebarActions.js'
import './sidebarViewPane.js'
import './sidebarStateService.js'
// register Thread History
import './registerThreads.js'
import './threadHistoryService.js'
// register Autocomplete
import './registerAutocomplete.js'
import './autocompleteService.js'
// register css
import './media/void.css'
// settings pane
import './voidSettingsEditorPane.js'
import './voidSettingsPane.js'

View file

@ -15,10 +15,8 @@ import { IStorageService } from '../../../../platform/storage/common/storage.js'
import { Dimension } from '../../../../base/browser/dom.js';
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
import { URI } from '../../../../base/common/uri.js';
@ -26,12 +24,13 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke
import { mountVoidSettings } from './react/out/void-settings-tsx/index.js'
import { getReactServices } from './reactServices.js';
import { getReactServices } from './helpers/reactServicesHelper.js';
import { Codicon } from '../../../../base/common/codicons.js';
// refer to preferences.contribution.ts keybindings editor
export class VoidEditorInput extends EditorInput {
class VoidEditorInput extends EditorInput {
static readonly ID: string = 'workbench.input.void.settings';
@ -93,17 +92,25 @@ Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane
);
// Register the action
// Register the gear
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.openVoidEditor',
title: 'Open Void Settings',
keybinding: {
when: ContextKeyExpr.true(),
primary: KeyMod.CtrlCmd | KeyCode.KeyE,
weight: KeybindingWeight.WorkbenchContrib
}
id: 'workbench.action.openVoidSettings',
title: nls.localize2('voidSettings', "Void: Settings"),
f1: true,
icon: Codicon.gear,
menu: [
{
id: MenuId.LayoutControlMenuSubmenu,
group: 'z_end',
},
{
id: MenuId.LayoutControlMenu,
when: ContextKeyExpr.equals('config.workbench.layoutControl.type', 'both'),
group: 'z_end'
}
]
});
}
async run(accessor: ServicesAccessor): Promise<void> {
@ -112,5 +119,4 @@ registerAction2(class extends Action2 {
const input = instantiationService.createInstance(VoidEditorInput);
await editorService.openEditor(input);
}
});
})