mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
more progress (still broken) + fix weird _useThread() + rm initStreamingDiffZoneId
This commit is contained in:
parent
b005b1e95a
commit
86dfc5521d
8 changed files with 150 additions and 81 deletions
|
|
@ -162,9 +162,12 @@ export interface IChatThreadService {
|
|||
isFocusingMessage(): boolean;
|
||||
setFocusedMessageIdx(messageIdx: number | undefined): void;
|
||||
|
||||
// _useFocusedStagingState(messageIdx?: number | undefined): readonly [StagingInfo, (stagingInfo: StagingInfo) => void];
|
||||
_useCurrentThreadState(): readonly [ThreadType['state'], (newState: Partial<ThreadType['state']>) => void];
|
||||
_useCurrentMessageState(messageIdx: number): readonly [UserMessageState, (newState: Partial<UserMessageState>) => void];
|
||||
// exposed getters/setters
|
||||
getCurrentMessageState: (messageIdx: number) => UserMessageState
|
||||
setCurrentMessageState: (messageIdx: number, newState: Partial<UserMessageState>) => void
|
||||
getCurrentThreadStagingSelections: () => StagingSelectionItem[]
|
||||
setCurrentThreadStagingSelections: (stagingSelections: StagingSelectionItem[]) => void
|
||||
|
||||
|
||||
// call to edit a message
|
||||
editUserMessageAndStreamResponse({ userMessage, chatMode, messageIdx }: { userMessage: string, chatMode: ChatMode, messageIdx: number }): Promise<void>;
|
||||
|
|
@ -622,33 +625,27 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
|
||||
}
|
||||
|
||||
getCurrentThreadStagingSelections = () => {
|
||||
return this.getCurrentThread().state.stagingSelections
|
||||
}
|
||||
|
||||
setCurrentThreadStagingSelections = (stagingSelections: StagingSelectionItem[]) => {
|
||||
this._setCurrentThreadState({ stagingSelections })
|
||||
}
|
||||
|
||||
// gets `staging` and `setStaging` of the currently focused element, given the index of the currently selected message (or undefined if no message is selected)
|
||||
|
||||
_useCurrentMessageState(messageIdx: number) {
|
||||
|
||||
const thread = this.getCurrentThread()
|
||||
const messages = thread.messages
|
||||
const currMessage = messages[messageIdx]
|
||||
|
||||
if (currMessage.role !== 'user') {
|
||||
return [defaultMessageState, (s: any) => { }] as const
|
||||
}
|
||||
|
||||
const state = currMessage.state
|
||||
const setState = (newState: Partial<UserMessageState>) => this._setCurrentMessageState(newState, messageIdx)
|
||||
|
||||
return [state, setState] as const
|
||||
|
||||
getCurrentMessageState(messageIdx: number): UserMessageState {
|
||||
const currMessage = this.getCurrentThread()?.messages?.[messageIdx]
|
||||
if (!currMessage || currMessage.role !== 'user') return defaultMessageState
|
||||
return currMessage.state
|
||||
}
|
||||
setCurrentMessageState(messageIdx: number, newState: Partial<UserMessageState>) {
|
||||
const currMessage = this.getCurrentThread()?.messages?.[messageIdx]
|
||||
if (!currMessage || currMessage.role !== 'user') return
|
||||
this._setCurrentMessageState(newState, messageIdx)
|
||||
}
|
||||
|
||||
_useCurrentThreadState() {
|
||||
const thread = this.getCurrentThread()
|
||||
|
||||
const state = thread.state
|
||||
const setState = this._setCurrentThreadState.bind(this)
|
||||
|
||||
return [state, setState] as const
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,10 +248,17 @@ type StreamLocationMutable = { line: number, col: number, addedSplitYet: boolean
|
|||
|
||||
export interface IEditCodeService {
|
||||
readonly _serviceBrand: undefined;
|
||||
startApplying(opts: StartApplyingOpts): number | void;
|
||||
interruptStreaming(diffareaid: number): void;
|
||||
startApplying(opts: StartApplyingOpts): URI | null;
|
||||
|
||||
addCtrlKZone(opts: AddCtrlKOpts): number | undefined;
|
||||
removeCtrlKZone(opts: { diffareaid: number }): void;
|
||||
|
||||
isDiffZoneStreaming(opts: { diffareaid: number }): boolean;
|
||||
isCtrlKZoneStreaming(opts: { diffareaid: number }): boolean;
|
||||
|
||||
interruptDiffZoneStreaming(opts: { diffareaid: number }): void;
|
||||
interruptCtrlKStreaming(opts: { diffareaid: number }): void;
|
||||
|
||||
// testDiffs(): void;
|
||||
}
|
||||
|
||||
|
|
@ -274,6 +281,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
private readonly _onDidAddOrDeleteDiffZones = new Emitter<{ uri: URI }>();
|
||||
|
||||
|
||||
|
||||
constructor(
|
||||
// @IHistoryService private readonly _historyService: IHistoryService, // history service is the history of pressing alt left/right
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
|
|
@ -309,7 +317,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
// when a stream starts or ends
|
||||
let removeAcceptRejectAllUI: (() => void) | null = null
|
||||
const onChangeUriState = () => {
|
||||
const changeUriState = () => {
|
||||
const uri = model.uri
|
||||
const diffZones = [...this.diffAreasOfURI[uri.fsPath].values()]
|
||||
.map(diffareaid => this.diffAreaOfId[diffareaid])
|
||||
|
|
@ -322,8 +330,8 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
removeAcceptRejectAllUI = null
|
||||
}
|
||||
}
|
||||
this._register(this._onDidAddOrDeleteDiffZones.event(({ uri: uri_ }) => { if (uri_.fsPath === model.uri.fsPath) onChangeUriState() }))
|
||||
this._register(this._onDidChangeStreaming.event(({ uri: uri_ }) => { if (uri_.fsPath === model.uri.fsPath) onChangeUriState() }))
|
||||
this._register(this._onDidAddOrDeleteDiffZones.event(({ uri: uri_ }) => { if (uri_.fsPath === model.uri.fsPath) changeUriState() }))
|
||||
this._register(this._onDidChangeStreaming.event(({ uri: uri_ }) => { if (uri_.fsPath === model.uri.fsPath) changeUriState() }))
|
||||
}
|
||||
// initialize all existing models + initialize when a new model mounts
|
||||
for (let model of this._modelService.getModels()) { initializeModel(model) }
|
||||
|
|
@ -526,7 +534,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
mountCtrlK(domNode, accessor, {
|
||||
|
||||
diffareaid: ctrlKZone.diffareaid,
|
||||
initStreamingDiffZoneId: ctrlKZone._linkedStreamingDiffZone,
|
||||
|
||||
textAreaRef: (r) => {
|
||||
textAreaRef.current = r
|
||||
|
|
@ -1198,19 +1205,15 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
|
||||
public startApplying(opts: StartApplyingOpts) {
|
||||
|
||||
if (opts.type === 'rewrite') {
|
||||
const addedDiffZone = this._initializeWriteoverStream(opts)
|
||||
return addedDiffZone?.diffareaid
|
||||
const addedDiffArea = this._initializeWriteoverStream(opts)
|
||||
return addedDiffArea?._URI ?? null
|
||||
}
|
||||
|
||||
else if (opts.type === 'searchReplace') {
|
||||
const addedDiffZone = this._initializeSearchAndReplaceStream(opts)
|
||||
return addedDiffZone?.diffareaid
|
||||
const addedDiffArea = this._initializeSearchAndReplaceStream(opts)
|
||||
return addedDiffArea?._URI ?? null
|
||||
}
|
||||
|
||||
return undefined
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1708,18 +1711,46 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
this._undoRedoService.undo(uri)
|
||||
}
|
||||
|
||||
// call this outside undo/redo (it calls undo). this is only for aborting a diffzone stream
|
||||
interruptStreaming(diffareaid: number) {
|
||||
const diffArea = this.diffAreaOfId[diffareaid]
|
||||
|
||||
if (!diffArea) return
|
||||
if (diffArea.type !== 'DiffZone') return
|
||||
if (!diffArea._streamState.isStreaming) return
|
||||
|
||||
this._stopIfStreaming(diffArea)
|
||||
this._undoHistory(diffArea._URI)
|
||||
|
||||
|
||||
isCtrlKZoneStreaming({ diffareaid }: { diffareaid: number }) {
|
||||
const ctrlKZone = this.diffAreaOfId[diffareaid]
|
||||
if (!ctrlKZone) return false
|
||||
if (ctrlKZone.type !== 'CtrlKZone') return false
|
||||
return !!ctrlKZone._linkedStreamingDiffZone
|
||||
}
|
||||
|
||||
isDiffZoneStreaming({ diffareaid }: { diffareaid: number }) {
|
||||
const diffZone = this.diffAreaOfId[diffareaid]
|
||||
if (diffZone?.type !== 'DiffZone') return false
|
||||
return diffZone._streamState.isStreaming
|
||||
}
|
||||
|
||||
|
||||
// call this outside undo/redo (it calls undo). this is only for aborting a diffzone stream
|
||||
interruptDiffZoneStreaming({ diffareaid }: { diffareaid: number }) {
|
||||
const diffZone = this.diffAreaOfId[diffareaid]
|
||||
if (diffZone?.type !== 'DiffZone') return
|
||||
if (!diffZone._streamState.isStreaming) return
|
||||
|
||||
this._stopIfStreaming(diffZone)
|
||||
this._undoHistory(diffZone._URI)
|
||||
}
|
||||
|
||||
interruptCtrlKStreaming({ diffareaid }: { diffareaid: number }) {
|
||||
const ctrlKZone = this.diffAreaOfId[diffareaid]
|
||||
if (ctrlKZone?.type !== 'CtrlKZone') return
|
||||
if (!ctrlKZone._linkedStreamingDiffZone) return
|
||||
|
||||
const linkedStreamingDiffZone = this.diffAreaOfId[ctrlKZone._linkedStreamingDiffZone]
|
||||
if (!linkedStreamingDiffZone) return
|
||||
if (linkedStreamingDiffZone.type !== 'DiffZone') return
|
||||
|
||||
this.interruptDiffZoneStreaming({ diffareaid: linkedStreamingDiffZone.diffareaid })
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import { IMetricsService } from '../common/metricsService.js';
|
|||
|
||||
export type QuickEditPropsType = {
|
||||
diffareaid: number,
|
||||
initStreamingDiffZoneId: number | null,
|
||||
textAreaRef: (ref: HTMLTextAreaElement | null) => void;
|
||||
onChangeHeight: (height: number) => void;
|
||||
onChangeText: (text: string) => void;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { useAccessor } from '../util/services.js'
|
||||
import { useAccessor, useIsURIStreaming } from '../util/services.js'
|
||||
import { useRefState } from '../util/helpers.js'
|
||||
import { isFeatureNameDisabled } from '../../../../common/voidSettingsTypes.js'
|
||||
|
||||
enum CopyButtonText {
|
||||
Idle = 'Copy',
|
||||
|
|
@ -50,7 +52,15 @@ const ApplyButton = ({ codeStr, codeBoxId }: { codeStr: string, codeBoxId: strin
|
|||
const metricsService = accessor.get('IMetricsService')
|
||||
|
||||
|
||||
const onApply = useCallback(() => {
|
||||
const [currStreamingDiffZoneRef, setCurrentlyStreamingDiffZone] = useRefState<number | null>(initStreamingDiffZoneId)
|
||||
const isStreaming = currStreamingDiffZoneRef.current !== null
|
||||
const isDisabled = !!isFeatureNameDisabled('Ctrl+K', settingsState)
|
||||
|
||||
useIsDiffZoneStreaming(isDiffAreaStreaming)
|
||||
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
|
||||
const diffareaid = editCodeService.startApplying({
|
||||
from: 'ClickApply',
|
||||
type: 'searchReplace',
|
||||
|
|
@ -60,7 +70,31 @@ const ApplyButton = ({ codeStr, codeBoxId }: { codeStr: string, codeBoxId: strin
|
|||
metricsService.capture('Apply Code', { length: codeStr.length }) // capture the length only
|
||||
|
||||
|
||||
}, [metricsService, editCodeService, codeStr])
|
||||
|
||||
if (isDisabled) return
|
||||
if (currStreamingDiffZoneRef.current !== null) return
|
||||
textAreaFnsRef.current?.disable()
|
||||
|
||||
const id = editCodeService.startApplying({
|
||||
from: 'QuickEdit',
|
||||
type: 'rewrite',
|
||||
diffareaid: diffareaid,
|
||||
})
|
||||
setCurrentlyStreamingDiffZone(id ?? null)
|
||||
}, [currStreamingDiffZoneRef, setCurrentlyStreamingDiffZone, isDisabled, editCodeService, diffareaid])
|
||||
|
||||
const onInterrupt = useCallback(() => {
|
||||
if (currStreamingDiffZoneRef.current === null) return
|
||||
editCodeService.interruptStreaming(currStreamingDiffZoneRef.current)
|
||||
setCurrentlyStreamingDiffZone(null)
|
||||
textAreaFnsRef.current?.enable()
|
||||
}, [currStreamingDiffZoneRef, setCurrentlyStreamingDiffZone, editCodeService])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const isSingleLine = !codeStr.includes('\n')
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import React, { FormEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSettingsState, useSidebarState, useChatThreadsState, useQuickEditState, useAccessor } from '../util/services.js';
|
||||
import { useSettingsState, useSidebarState, useChatThreadsState, useQuickEditState, useAccessor, useIsCtrlKZoneStreaming } from '../util/services.js';
|
||||
import { TextAreaFns, VoidInputBox2 } from '../util/inputs.js';
|
||||
import { QuickEditPropsType } from '../../../quickEditActions.js';
|
||||
import { ButtonStop, ButtonSubmit, IconX, VoidChatArea } from '../sidebar-tsx/SidebarChat.js';
|
||||
|
|
@ -16,7 +16,6 @@ import { isFeatureNameDisabled } from '../../../../../../../workbench/contrib/vo
|
|||
|
||||
export const QuickEditChat = ({
|
||||
diffareaid,
|
||||
initStreamingDiffZoneId,
|
||||
onChangeHeight,
|
||||
onChangeText: onChangeText_,
|
||||
textAreaRef: textAreaRef_,
|
||||
|
|
@ -49,28 +48,25 @@ export const QuickEditChat = ({
|
|||
const [instructionsAreEmpty, setInstructionsAreEmpty] = useState(!(initText ?? '')) // the user's instructions
|
||||
const isDisabled = instructionsAreEmpty || !!isFeatureNameDisabled('Ctrl+K', settingsState)
|
||||
|
||||
const [currStreamingDiffZoneRef, setCurrentlyStreamingDiffZone] = useRefState<number | null>(initStreamingDiffZoneId)
|
||||
const isStreaming = currStreamingDiffZoneRef.current !== null
|
||||
const isStreamingRefState = useIsCtrlKZoneStreaming(diffareaid)
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
if (isDisabled) return
|
||||
if (currStreamingDiffZoneRef.current !== null) return
|
||||
if (isStreamingRefState.current) return
|
||||
textAreaFnsRef.current?.disable()
|
||||
|
||||
const id = editCodeService.startApplying({
|
||||
editCodeService.startApplying({
|
||||
from: 'QuickEdit',
|
||||
type:'rewrite',
|
||||
diffareaid: diffareaid,
|
||||
type: 'rewrite',
|
||||
diffareaid,
|
||||
})
|
||||
setCurrentlyStreamingDiffZone(id ?? null)
|
||||
}, [currStreamingDiffZoneRef, setCurrentlyStreamingDiffZone, isDisabled, editCodeService, diffareaid])
|
||||
}, [isStreamingRefState, isDisabled, editCodeService, diffareaid])
|
||||
|
||||
const onInterrupt = useCallback(() => {
|
||||
if (currStreamingDiffZoneRef.current === null) return
|
||||
editCodeService.interruptStreaming(currStreamingDiffZoneRef.current)
|
||||
setCurrentlyStreamingDiffZone(null)
|
||||
if (!isStreamingRefState.current ) return
|
||||
editCodeService.interruptCtrlKStreaming({ diffareaid })
|
||||
textAreaFnsRef.current?.enable()
|
||||
}, [currStreamingDiffZoneRef, setCurrentlyStreamingDiffZone, editCodeService])
|
||||
}, [isStreamingRefState, editCodeService])
|
||||
|
||||
|
||||
const onX = useCallback(() => {
|
||||
|
|
@ -89,7 +85,7 @@ export const QuickEditChat = ({
|
|||
onSubmit={onSubmit}
|
||||
onAbort={onInterrupt}
|
||||
onClose={onX}
|
||||
isStreaming={isStreaming}
|
||||
isStreaming={isStreamingRefState.current}
|
||||
isDisabled={isDisabled}
|
||||
featureName="Ctrl+K"
|
||||
className="py-2 w-full"
|
||||
|
|
|
|||
|
|
@ -557,11 +557,11 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx }: { chatMessage: ChatM
|
|||
let setStagingSelections = (s: StagingSelectionItem[]) => { }
|
||||
|
||||
if (messageIdx !== undefined) {
|
||||
const [_state, _setState] = chatThreadsService._useCurrentMessageState(messageIdx)
|
||||
const _state = chatThreadsService.getCurrentMessageState(messageIdx)
|
||||
isBeingEdited = _state.isBeingEdited
|
||||
setIsBeingEdited = (v) => _setState({ isBeingEdited: v })
|
||||
stagingSelections = _state.stagingSelections
|
||||
setStagingSelections = (s) => { _setState({ stagingSelections: s }) }
|
||||
setIsBeingEdited = (v) => chatThreadsService.setCurrentMessageState(messageIdx, { isBeingEdited: v })
|
||||
setStagingSelections = (s) => chatThreadsService.setCurrentMessageState(messageIdx, { stagingSelections: s })
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -780,9 +780,8 @@ export const SidebarChat = () => {
|
|||
const currentThread = chatThreadsService.getCurrentThread()
|
||||
const previousMessages = currentThread?.messages ?? []
|
||||
|
||||
const [_state, _setState] = chatThreadsService._useCurrentThreadState()
|
||||
const selections = _state.stagingSelections
|
||||
const setSelections = (s: StagingSelectionItem[]) => { _setState({ stagingSelections: s }) }
|
||||
const selections = chatThreadsService.getCurrentThread().state.stagingSelections
|
||||
const setSelections = (s: StagingSelectionItem[]) => { chatThreadsService.setCurrentThreadStagingSelections(s) }
|
||||
|
||||
// stream state
|
||||
const currThreadStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId)
|
||||
|
|
@ -818,7 +817,7 @@ export const SidebarChat = () => {
|
|||
textAreaFnsRef.current?.setValue('')
|
||||
textAreaRef.current?.focus() // focus input after submit
|
||||
|
||||
}, [chatThreadsService, isDisabled, isStreaming, textAreaRef, textAreaFnsRef, selections, setSelections])
|
||||
}, [chatThreadsService, isDisabled, isStreaming, textAreaRef, textAreaFnsRef, setSelections])
|
||||
|
||||
const onAbort = () => {
|
||||
const threadId = currentThread.id
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import { IEnvironmentService } from '../../../../../../../platform/environment/c
|
|||
import { IConfigurationService } from '../../../../../../../platform/configuration/common/configuration.js'
|
||||
import { IPathService } from '../../../../../../../workbench/services/path/common/pathService.js'
|
||||
import { IMetricsService } from '../../../../../../../workbench/contrib/void/common/metricsService.js'
|
||||
import { URI } from '../../../../../../../base/common/uri.js'
|
||||
|
||||
|
||||
|
||||
|
|
@ -353,3 +354,17 @@ export const useIsDark = () => {
|
|||
return isDark
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export const useIsCtrlKZoneStreaming = (diffareaid: number) => {
|
||||
|
||||
return { current: true }
|
||||
|
||||
}
|
||||
|
||||
|
||||
export const useIsDiffZoneStreaming = (uri: URI) => {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,13 +141,11 @@ registerAction2(class extends Action2 {
|
|||
let setSelections = (s: StagingSelectionItem[]) => { }
|
||||
|
||||
if (focusedMessageIdx === undefined) {
|
||||
const [state, setState] = chatThreadService._useCurrentThreadState()
|
||||
selections = state.stagingSelections
|
||||
setSelections = (s) => setState({ stagingSelections: s })
|
||||
selections = chatThreadService.getCurrentThreadStagingSelections()
|
||||
setSelections = (s: StagingSelectionItem[]) => chatThreadService.setCurrentThreadStagingSelections(s)
|
||||
} else {
|
||||
const [state, setState] = chatThreadService._useCurrentMessageState(focusedMessageIdx)
|
||||
selections = state.stagingSelections
|
||||
setSelections = (s) => setState({ stagingSelections: s })
|
||||
selections = chatThreadService.getCurrentMessageState(focusedMessageIdx).stagingSelections
|
||||
setSelections = (s) => chatThreadService.setCurrentMessageState(focusedMessageIdx, { stagingSelections: s })
|
||||
}
|
||||
|
||||
// if matches with existing selection, overwrite (since text may change)
|
||||
|
|
|
|||
Loading…
Reference in a new issue