better helperwidget positioning

This commit is contained in:
Mathew Pareles 2025-03-30 23:50:39 -07:00
parent 77c031abc5
commit 51c84df5a5

View file

@ -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;