From e894be803b66e3ca931e8962e25ec5c4db563eb6 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Thu, 20 Mar 2025 22:10:45 -0700 Subject: [PATCH] command bar draft --- .../void-command-bar-tsx/VoidCommandBar.tsx | 37 ++++++++---- .../void/browser/voidCommandBarService.ts | 58 ++++++++++++++----- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx index f8e85334..9864110e 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx @@ -7,18 +7,12 @@ import { useAccessor, useCommandBarState, useIsDark } from '../util/services.js'; import '../styles.css' -import { useCallback, useEffect, useState } from 'react'; -import { URI } from '../../../../../../../base/common/uri.js'; -import { ICodeEditor } from '../../../../../../../editor/browser/editorBrowser.js'; +import { useCallback, useEffect, useState, useRef } from 'react'; import { ScrollType } from '../../../../../../../editor/common/editorCommon.js'; import { acceptAllBg, acceptBorder, buttonFontSize, buttonTextColor, rejectAllBg, rejectBorder } from '../../../../common/helpers/colors.js'; +import { VoidCommandBarProps } from '../../../voidCommandBarService.js'; -export type VoidCommandBarProps = { - uri: URI | null; - editor: ICodeEditor; -} - -export const VoidCommandBarMain = ({ uri, editor }: VoidCommandBarProps) => { +export const VoidCommandBarMain = ({ uri, editor, onChangeHeight }: VoidCommandBarProps) => { const isDark = useIsDark() if (uri?.scheme !== 'file') return null // don't show in editors that we made, they must be files @@ -26,7 +20,7 @@ export const VoidCommandBarMain = ({ uri, editor }: VoidCommandBarProps) => { return
- +
} @@ -38,9 +32,11 @@ const stepIdx = (currIdx: number | null, len: number, step: -1 | 1) => { return ((currIdx ?? 0) + step + len) % len // for some reason, small negatives are kept negative. just add len to offset } +const DummyContainer = ()=>{ +} -const VoidCommandBar = ({ uri, editor }: { uri: URI | null, editor: ICodeEditor }) => { +const VoidCommandBar = ({ uri, editor, onChangeHeight }: VoidCommandBarProps) => { const accessor = useAccessor() const editCodeService = accessor.get('IEditCodeService') const editorService = accessor.get('ICodeEditorService') @@ -50,6 +46,23 @@ const VoidCommandBar = ({ uri, editor }: { uri: URI | null, editor: ICodeEditor const voidModelService = accessor.get('IVoidModelService') const { state: commandBarState, sortedURIs: sortedCommandBarURIs } = useCommandBarState() + // Add a reference to the container for resize observer + const sizerRef = useRef(null) + + // Add the resize observer effect + useEffect(() => { + const inputContainer = sizerRef.current + if (!inputContainer) return; + // only observing 1 element + let resizeObserver: ResizeObserver | undefined + resizeObserver = new ResizeObserver((entries) => { + const height = entries[0].borderBoxSize[0].blockSize + onChangeHeight(height) + }) + resizeObserver.observe(inputContainer); + return () => { resizeObserver?.disconnect(); }; + }, [onChangeHeight]); + // changes if the user clicks left/right or if the user goes on a uri with changes const [currUriIdx, setUriIdx] = useState(null) @@ -263,7 +276,7 @@ const VoidCommandBar = ({ uri, editor }: { uri: URI | null, editor: ICodeEditor - return
+ return
{currUriHasChanges && <>
{acceptAllButton} diff --git a/src/vs/workbench/contrib/void/browser/voidCommandBarService.ts b/src/vs/workbench/contrib/void/browser/voidCommandBarService.ts index 4b3b8645..28392bd5 100644 --- a/src/vs/workbench/contrib/void/browser/voidCommandBarService.ts +++ b/src/vs/workbench/contrib/void/browser/voidCommandBarService.ts @@ -17,6 +17,7 @@ import { InstantiationType, registerSingleton } from '../../../../platform/insta import { IEditCodeService } from './editCodeServiceInterface.js'; import { ITextModel } from '../../../../editor/common/model.js'; import { IModelService } from '../../../../editor/common/services/model.js'; +import { generateUuid } from '../../../../base/common/uuid.js'; @@ -112,6 +113,8 @@ export class VoidCommandBarService extends Disposable implements IVoidCommandBar const onCodeEditorAdd = (editor: ICodeEditor) => { const id = editor.getId(); disposablesOfEditorId[id] = []; + + // mount the command bar const d1 = this._instantiationService.createInstance(AcceptRejectAllFloatingWidget, { editor }); disposablesOfEditorId[id].push(d1); const d2 = editor.onDidChangeModel((e) => { if (e?.newModelUrl?.scheme === 'file') updateActiveURI() }) @@ -346,6 +349,12 @@ registerSingleton(IVoidCommandBarService, VoidCommandBarService, InstantiationTy // registerWorkbenchContribution2(VoidCommandBarService.ID, VoidCommandBarService, WorkbenchPhase.BlockRestore); +export type VoidCommandBarProps = { + uri: URI | null; + editor: ICodeEditor; + onChangeHeight: (height: number) => void; +} + @@ -354,14 +363,15 @@ class AcceptRejectAllFloatingWidget extends Widget implements IOverlayWidget { private readonly editor: ICodeEditor; private readonly ID: string; + _height = 0 + constructor({ editor }: { editor: ICodeEditor, }, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); - this.ID = editor.getId() + '-voidfloatingwidget'; + this.ID = generateUuid(); this.editor = editor; - // Create container div const { root } = dom.h('div@root'); @@ -370,30 +380,50 @@ class AcceptRejectAllFloatingWidget extends Widget implements IOverlayWidget { root.style.padding = '4px'; root.style.alignItems = 'center'; root.style.pointerEvents = 'none'; - // Mount command bar using mountVoidCommandBar + // this.editor.getDomNode()?.appendChild(root) + + const onChangeHeight = (height: number) => { + if (height === 0) return; + + this._height = height + // editor.layoutOverlayWidget(this) + // stupid hack because layoutOverlayWidget doesn't work + editor.removeOverlayWidget(this) + editor.addOverlayWidget(this) + } + + // alternative to mount VoidCommandBar without the stupid widget + // editor.getLayoutInfo() + // this._register( + // editor.onDidLayoutChange(e => { + // // e.height + // // e.width + // }) + // ) + + + + + this._domNode = root; + editor.addOverlayWidget(this); + this.instantiationService.invokeFunction(accessor => { - type Props = { uri: URI | null, editor: ICodeEditor } const uri = editor.getModel()?.uri || null - const res = mountVoidCommandBar(root, accessor, { uri, editor } satisfies Props) + + const res = mountVoidCommandBar(root, accessor, { uri, editor, onChangeHeight } satisfies VoidCommandBarProps) if (!res) return - const dispose = res.dispose - const rerender: (o: Props) => void = res.rerender - - this._register(toDisposable(() => dispose?.())) + this._register(toDisposable(() => res.dispose?.())) this._register(editor.onDidChangeModel((model) => { const uri = model.newModelUrl - rerender({ uri, editor }) + res.rerender({ uri, editor, onChangeHeight }) })) }); - this._domNode = root; - // Mount the widget - editor.addOverlayWidget(this); } @@ -407,7 +437,7 @@ class AcceptRejectAllFloatingWidget extends Widget implements IOverlayWidget { public getPosition() { return { - preference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER, + preference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER } }