diff --git a/src/Types.ts b/src/Types.ts index 444c6e35ce..473e80c11b 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -98,6 +98,15 @@ export interface SubpieceModifier { export interface MatchingPairSymbolModifier { type: "matchingPairSymbol"; } +export interface LineNumberModifierPosition { + lineNumber: number; + isRelative: boolean; +} +export interface LineNumberModifier { + type: "lineNumber"; + anchor: LineNumberModifierPosition; + active: LineNumberModifierPosition; +} export interface IdentityModifier { type: "identity"; } @@ -109,11 +118,12 @@ export interface TailModifier { } export type Modifier = + | IdentityModifier | SurroundingPairModifier | ContainingScopeModifier | SubpieceModifier | MatchingPairSymbolModifier - | IdentityModifier + | LineNumberModifier | HeadModifier | TailModifier; diff --git a/src/extension.ts b/src/extension.ts index 1e28f5dea4..4147a6dfde 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -215,10 +215,38 @@ export async function activate(context: vscode.ExtensionContext) { addDecorationsDebounced(); + function checkForEditsOutsideViewport(event: vscode.TextDocumentChangeEvent) { + const editor = vscode.window.activeTextEditor; + if (editor == null || editor.document !== event.document) { + return; + } + const { start, end } = editor.visibleRanges[0]; + const ranges = []; + for (const edit of event.contentChanges) { + if ( + edit.range.end.isBeforeOrEqual(start) || + edit.range.start.isAfterOrEqual(end) + ) { + ranges.push(edit.range); + } + } + if (ranges.length > 0) { + ranges.sort((a, b) => a.start.line - b.start.line); + const linesText = ranges + .map((range) => `${range.start.line + 1}-${range.end.line + 1}`) + .join(", "); + vscode.window.showWarningMessage( + `Modification outside of viewport at lines: ${linesText}` + ); + } + } + function handleEdit(edit: vscode.TextDocumentChangeEvent) { graph.navigationMap.updateTokenRanges(edit); addDecorationsDebounced(); + + checkForEditsOutsideViewport(edit); } const recomputeDecorationStyles = async () => { diff --git a/src/processTargets.ts b/src/processTargets.ts index 48cf57662a..65da641791 100644 --- a/src/processTargets.ts +++ b/src/processTargets.ts @@ -14,6 +14,7 @@ import { Target, TypedSelection, Modifier, + LineNumberModifierPosition, } from "./Types"; import { performInsideOutsideAdjustment } from "./performInsideOutsideAdjustment"; import { SUBWORD_MATCHER } from "./constants"; @@ -370,6 +371,27 @@ function transformSelection( ]; } + case "lineNumber": { + const getLine = (linePosition: LineNumberModifierPosition) => + linePosition.isRelative + ? selection.editor.selection.active.line + linePosition.lineNumber + : linePosition.lineNumber; + return [ + { + selection: update(selection, { + selection: () => + new Selection( + getLine(modifier.anchor), + 0, + getLine(modifier.active), + 0 + ), + }), + context: {}, + }, + ]; + } + case "matchingPairSymbol": case "surroundingPair": throw new Error("Not implemented");