From 51c84df5a51666e3bc0ba73f38a7653d598b2546 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Sun, 30 Mar 2025 23:50:39 -0700 Subject: [PATCH] better helperwidget positioning --- .../void/browser/voidSelectionHelperWidget.ts | 81 +++++++++++++++---- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/voidSelectionHelperWidget.ts b/src/vs/workbench/contrib/void/browser/voidSelectionHelperWidget.ts index b3cd5ead..e3cd2d41 100644 --- a/src/vs/workbench/contrib/void/browser/voidSelectionHelperWidget.ts +++ b/src/vs/workbench/contrib/void/browser/voidSelectionHelperWidget.ts @@ -14,10 +14,12 @@ import * as dom from '../../../../base/browser/dom.js'; import { mountVoidSelectionHelper } from './react/out/void-editor-widgets-tsx/index.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { IVoidSettingsService } from '../common/voidSettingsService.js'; +import { EditorOption } from '../../../../editor/common/config/editorOptions.js'; +import { getLengthOfTextPx } from './editCodeService.js'; const minDistanceFromRightPx = 400; -const minDistanceFromLeftPx = 60; +const minLeftPx = 60; export type VoidSelectionHelperProps = { @@ -156,34 +158,81 @@ export class SelectionHelperContribution extends Disposable implements IEditorCo const model = this._editor.getModel()!; + // get the longest length of the nearest neighbors of the target + const { tabSize: numSpacesInTab } = model.getFormattingOptions(); + const spaceWidth = this._editor.getOption(EditorOption.fontInfo).spaceWidth; + const tabWidth = numSpacesInTab * spaceWidth; + const numLinesModel = model.getLineCount() + + // Calculate right edge of visible editor area + const editorWidthPx = this._editor.getLayoutInfo().width; + const maxLeftPx = editorWidthPx - minDistanceFromRightPx + + // returns the position where the box should go on the targetLine + const getBoxPosition = (targetLine: number): { top: number, left: number } => { + + const targetPosition = this._editor.getScrolledVisiblePosition({ lineNumber: targetLine, column: 1 }) ?? { left: 0, top: 0 }; + + const { top: targetTop, left: targetLeft } = targetPosition + + let targetWidth = 0; + for (let i = targetLine; i <= targetLine + 1; i++) { + + // if not in range, continue + if (!(i >= 1) || !(i <= numLinesModel)) continue; + + const content = model.getLineContent(i); + const currWidth = getLengthOfTextPx({ + tabWidth, + spaceWidth, + content + }) + + targetWidth = Math.max(targetWidth, currWidth); + } + + return { + top: targetTop, + left: targetLeft + targetWidth, + }; + + } + + // Calculate the middle line of the selection const startLine = selection.startLineNumber; const endLine = selection.endLineNumber; - const middleLineNumber = Math.floor(startLine + (endLine - startLine) / 2); + // const middleLine = Math.floor(startLine + (endLine - startLine) / 2); + const targetLine = endLine - startLine + 1 <= 2 ? startLine : startLine + 2; - // Get the content of the middle line - const lineContent = model.getLineContent(middleLineNumber); + let boxPos = getBoxPosition(targetLine); - // Find the position at the end of the middle line - const endOfLinePos = this._editor.getScrolledVisiblePosition({ - lineNumber: middleLineNumber, - column: lineContent.length + 1 // +1 because columns are 1-based - }); + // if the position of the box is too far to the right, keep searching for a good position + let attempt = 0; + const maxAttempts = 3; + outerLoop: while (boxPos.left > maxLeftPx && attempt < maxAttempts) { + attempt++ - if (!endOfLinePos) { - this._hideHelper(); - return; + const linesToTry = [targetLine - attempt, targetLine + attempt] + for (const line of linesToTry) { + boxPos = getBoxPosition(line); + if (boxPos.left <= maxLeftPx) { + break outerLoop; + } + } + } + if (boxPos.left > maxLeftPx) { // if still not found, make it the line before + boxPos = getBoxPosition(targetLine - 1) } - // Calculate right edge of visible editor area - const editorWidth = this._editor.getLayoutInfo().width; // Position the helper element at the end of the middle line but ensure it's visible - const xPosition = Math.max(Math.min(endOfLinePos.left, editorWidth - minDistanceFromRightPx), minDistanceFromLeftPx); + const xPosition = Math.max(Math.min(boxPos.left, maxLeftPx), minLeftPx); + const yPosition = boxPos.top; // Update the React component position this._rootHTML.style.left = `${xPosition}px`; - this._rootHTML.style.top = `${endOfLinePos.top}px`; + this._rootHTML.style.top = `${yPosition}px`; this._rootHTML.style.display = 'flex'; // Show the container this._isVisible = true;