mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-06-13 07:10:26 +08:00
Switches all samples to use eslint 9 with flat configs. I've tried to migrate existing settings as much as possible. However our eslint configs were also inconsistent so I've tried to align these too
436 lines
12 KiB
TypeScript
436 lines
12 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { Position, TextDocument, window } from 'vscode';
|
|
import { Words, WordCharacters } from './words';
|
|
import { Command, AbstractCommandDescriptor } from './common';
|
|
|
|
export class MotionState {
|
|
|
|
public anchor: Position | null;
|
|
public cursorDesiredCharacter: number;
|
|
public wordCharacterClass: WordCharacters | null;
|
|
|
|
constructor() {
|
|
this.cursorDesiredCharacter = -1;
|
|
this.wordCharacterClass = null;
|
|
this.anchor = null;
|
|
}
|
|
|
|
}
|
|
|
|
export abstract class Motion {
|
|
public abstract run(doc: TextDocument, pos: Position, state: MotionState): Position;
|
|
|
|
public repeat(hasRepeatCount: boolean, count: number): Motion {
|
|
if (!hasRepeatCount) {
|
|
return this;
|
|
}
|
|
return new RepeatingMotion(this, count);
|
|
}
|
|
}
|
|
|
|
class RepeatingMotion extends Motion {
|
|
|
|
private _actual: Motion;
|
|
private _repeatCount: number;
|
|
|
|
constructor(actual: Motion, repeatCount: number) {
|
|
super();
|
|
this._actual = actual;
|
|
this._repeatCount = repeatCount;
|
|
}
|
|
|
|
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
for (let cnt = 0; cnt < this._repeatCount; cnt++) {
|
|
pos = this._actual.run(doc, pos, state);
|
|
}
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
class NextCharacterMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, _state: MotionState): Position {
|
|
if (pos.character === doc.lineAt(pos.line).text.length) {
|
|
// on last character
|
|
return ((pos.line + 1 < doc.lineCount) ? new Position(pos.line + 1, 0) : pos);
|
|
}
|
|
|
|
return new Position(pos.line, pos.character + 1);
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
class LeftMotion extends Motion {
|
|
public run(_doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
const line = pos.line;
|
|
|
|
if (pos.character > 0) {
|
|
state.cursorDesiredCharacter = pos.character - 1;
|
|
return new Position(line, state.cursorDesiredCharacter);
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
class DownMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
let line = pos.line;
|
|
|
|
state.cursorDesiredCharacter = (state.cursorDesiredCharacter === -1 ? pos.character : state.cursorDesiredCharacter);
|
|
|
|
if (line < doc.lineCount - 1) {
|
|
line++;
|
|
return new Position(line, Math.min(state.cursorDesiredCharacter, doc.lineAt(line).text.length));
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
class UpMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
let line = pos.line;
|
|
|
|
state.cursorDesiredCharacter = (state.cursorDesiredCharacter === -1 ? pos.character : state.cursorDesiredCharacter);
|
|
|
|
if (line > 0) {
|
|
line--;
|
|
return new Position(line, Math.min(state.cursorDesiredCharacter, doc.lineAt(line).text.length));
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
class RightMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
const line = pos.line;
|
|
const maxCharacter = doc.lineAt(line).text.length;
|
|
|
|
if (pos.character < maxCharacter) {
|
|
state.cursorDesiredCharacter = pos.character + 1;
|
|
return new Position(line, state.cursorDesiredCharacter);
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
class EndOfLineMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, _state: MotionState): Position {
|
|
return new Position(pos.line, doc.lineAt(pos.line).text.length);
|
|
}
|
|
}
|
|
|
|
class StartOfLineMotion extends Motion {
|
|
public run(_doc: TextDocument, pos: Position, _state: MotionState): Position {
|
|
return new Position(pos.line, 0);
|
|
}
|
|
}
|
|
|
|
class NextWordStartMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
const lineContent = doc.lineAt(pos.line).text;
|
|
|
|
if (pos.character >= lineContent.length - 1) {
|
|
// cursor at end of line
|
|
return ((pos.line + 1 < doc.lineCount) ? new Position(pos.line + 1, 0) : pos);
|
|
}
|
|
|
|
const nextWord = Words.findNextWord(doc, pos, state.wordCharacterClass);
|
|
|
|
if (!nextWord) {
|
|
// return end of the line
|
|
return Motions.EndOfLine.run(doc, pos, state);
|
|
}
|
|
|
|
if (nextWord.start <= pos.character && pos.character < nextWord.end) {
|
|
// Sitting on a word
|
|
const nextNextWord = Words.findNextWord(doc, new Position(pos.line, nextWord.end), state.wordCharacterClass);
|
|
if (nextNextWord) {
|
|
// return start of the next next word
|
|
return new Position(pos.line, nextNextWord.start);
|
|
} else {
|
|
// return end of line
|
|
return Motions.EndOfLine.run(doc, pos, state);
|
|
}
|
|
} else {
|
|
// return start of the next word
|
|
return new Position(pos.line, nextWord.start);
|
|
}
|
|
}
|
|
}
|
|
|
|
class NextWordEndMotion extends Motion {
|
|
public run(doc: TextDocument, pos: Position, state: MotionState): Position {
|
|
const lineContent = doc.lineAt(pos.line).text;
|
|
|
|
if (pos.character >= lineContent.length - 1) {
|
|
// no content on this line or cursor at end of line
|
|
return ((pos.line + 1 < doc.lineCount) ? new Position(pos.line + 1, 0) : pos);
|
|
}
|
|
|
|
const nextWord = Words.findNextWord(doc, pos, state.wordCharacterClass);
|
|
|
|
if (!nextWord) {
|
|
// return end of the line
|
|
return Motions.EndOfLine.run(doc, pos, state);
|
|
}
|
|
|
|
// return start of the next word
|
|
return new Position(pos.line, nextWord.end);
|
|
}
|
|
}
|
|
|
|
class GoToLineUndefinedMotion extends Motion {
|
|
public run(_doc: TextDocument, pos: Position, _state: MotionState): Position {
|
|
// does not do anything
|
|
return pos;
|
|
}
|
|
|
|
public repeat(hasRepeatCount: boolean, count: number): Motion {
|
|
if (!hasRepeatCount) {
|
|
return Motions.GoToLastLine;
|
|
}
|
|
return new GoToLineDefinedMotion(count);
|
|
}
|
|
}
|
|
|
|
abstract class GoToLineMotion extends Motion {
|
|
|
|
protected firstNonWhitespaceChar(doc: TextDocument, line: number): number {
|
|
const lineContent = doc.lineAt(line).text;
|
|
let character = 0;
|
|
while (character < lineContent.length) {
|
|
const ch = lineContent.charAt(character);
|
|
if (ch !== ' ' && ch !== '\t') {
|
|
break;
|
|
}
|
|
character++;
|
|
}
|
|
return character;
|
|
}
|
|
|
|
}
|
|
|
|
class GoToFirstLineMotion extends GoToLineMotion {
|
|
public run(doc: TextDocument, _pos: Position, _state: MotionState): Position {
|
|
return new Position(0, this.firstNonWhitespaceChar(doc, 0));
|
|
}
|
|
}
|
|
|
|
class GoToLastLineMotion extends GoToLineMotion {
|
|
public run(doc: TextDocument, _pos: Position, _state: MotionState): Position {
|
|
const lastLine = doc.lineCount - 1;
|
|
return new Position(lastLine, this.firstNonWhitespaceChar(doc, lastLine));
|
|
}
|
|
}
|
|
|
|
class GoToLineDefinedMotion extends GoToLineMotion {
|
|
private _lineNumber: number;
|
|
|
|
constructor(lineNumber: number) {
|
|
super();
|
|
this._lineNumber = lineNumber;
|
|
}
|
|
|
|
public run(doc: TextDocument, _pos: Position, _state: MotionState): Position {
|
|
const line = Math.min(doc.lineCount - 1, Math.max(0, this._lineNumber - 1));
|
|
return new Position(line, this.firstNonWhitespaceChar(doc, line));
|
|
}
|
|
}
|
|
|
|
class CursorMoveCommand extends AbstractCommandDescriptor {
|
|
|
|
constructor(private to: string, private by?: string) {
|
|
super();
|
|
}
|
|
|
|
public createCommand(args?: any): Command {
|
|
const cursorMoveArgs: any = {
|
|
to: this.to,
|
|
by: this.by,
|
|
value: args.repeat || 1,
|
|
select: !!args.isVisual
|
|
};
|
|
return {
|
|
commandId: 'cursorMove',
|
|
args: cursorMoveArgs
|
|
};
|
|
}
|
|
}
|
|
|
|
class EditorScrollCommand extends AbstractCommandDescriptor {
|
|
|
|
constructor(private to: string, private by?: string) {
|
|
super();
|
|
}
|
|
|
|
public createCommand(args?: any): Command {
|
|
const editorScrollArgs: any = {
|
|
to: this.to,
|
|
by: this.by,
|
|
value: args.repeat || 1,
|
|
revealCursor: true
|
|
};
|
|
return {
|
|
commandId: 'editorScroll',
|
|
args: editorScrollArgs
|
|
};
|
|
}
|
|
}
|
|
|
|
class RevealCurrentLineCommand extends AbstractCommandDescriptor {
|
|
|
|
constructor(private at: string) {
|
|
super();
|
|
}
|
|
|
|
public createCommand(_args?: any): Command {
|
|
const lineNumber = window.activeTextEditor.selection.start.line;
|
|
const revealLineArgs: any = {
|
|
lineNumber,
|
|
at: this.at
|
|
};
|
|
return {
|
|
commandId: 'revealLine',
|
|
args: revealLineArgs
|
|
};
|
|
}
|
|
}
|
|
|
|
class MoveActiveEditorCommandByPosition extends AbstractCommandDescriptor {
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
public createCommand(args?: any): Command {
|
|
const moveActiveEditorArgs: any = {
|
|
to: args.repeat === void 0 ? 'last' : 'position',
|
|
value: args.repeat !== void 0 ? args.repeat + 1 : undefined
|
|
};
|
|
return {
|
|
commandId: 'moveActiveEditor',
|
|
args: moveActiveEditorArgs
|
|
};
|
|
}
|
|
}
|
|
|
|
class MoveActiveEditorCommand extends AbstractCommandDescriptor {
|
|
|
|
constructor(private to: string) {
|
|
super();
|
|
}
|
|
|
|
public createCommand(args?: any): Command {
|
|
const moveActiveEditorArgs: any = {
|
|
to: this.to,
|
|
value: args.repeat ? args.repeat : 1
|
|
};
|
|
return {
|
|
commandId: 'moveActiveEditor',
|
|
args: moveActiveEditorArgs
|
|
};
|
|
}
|
|
}
|
|
class FoldCommand extends AbstractCommandDescriptor {
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
public createCommand(args?: any): Command {
|
|
const foldEditorArgs: any = {
|
|
levels: args.repeat ? args.repeat : 1,
|
|
direction: 'up'
|
|
};
|
|
return {
|
|
commandId: 'editor.fold',
|
|
args: foldEditorArgs
|
|
};
|
|
}
|
|
}
|
|
|
|
class UnfoldCommand extends AbstractCommandDescriptor {
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
public createCommand(args?: any): Command {
|
|
const foldEditorArgs: any = {
|
|
levels: args.repeat ? args.repeat : 1,
|
|
direction: 'up'
|
|
};
|
|
return {
|
|
commandId: 'editor.unfold',
|
|
args: foldEditorArgs
|
|
};
|
|
}
|
|
}
|
|
|
|
export const Motions = {
|
|
RightMotion: new RightMotion(),
|
|
|
|
NextCharacter: new NextCharacterMotion(),
|
|
|
|
Left: new CursorMoveCommand('left'),
|
|
Right: new CursorMoveCommand('right'),
|
|
Down: new CursorMoveCommand('down'),
|
|
Up: new CursorMoveCommand('up'),
|
|
|
|
EndOfLine: new EndOfLineMotion(),
|
|
StartOfLine: new StartOfLineMotion(),
|
|
NextWordStart: new NextWordStartMotion(),
|
|
NextWordEnd: new NextWordEndMotion(),
|
|
GoToLine: new GoToLineUndefinedMotion(),
|
|
GoToFirstLine: new GoToFirstLineMotion(),
|
|
GoToLastLine: new GoToLastLineMotion(),
|
|
|
|
CursorScrollLeft: new CursorMoveCommand('left'),
|
|
CursorScrollRight: new CursorMoveCommand('right'),
|
|
CursorScrollLeftByHalfLine: new CursorMoveCommand('left', 'halfLine'),
|
|
CursorScrollRightByHalfLine: new CursorMoveCommand('right', 'halfLine'),
|
|
|
|
WrappedLineUp: new CursorMoveCommand('up', 'wrappedLine'),
|
|
WrappedLineDown: new CursorMoveCommand('down', 'wrappedLine'),
|
|
|
|
WrappedLineStart: new CursorMoveCommand('wrappedLineStart'),
|
|
WrappedLineFirstNonWhiteSpaceCharacter: new CursorMoveCommand('wrappedLineFirstNonWhitespaceCharacter'),
|
|
WrappedLineColumnCenter: new CursorMoveCommand('wrappedLineColumnCenter'),
|
|
WrappedLineEnd: new CursorMoveCommand('wrappedLineEnd'),
|
|
WrappedLineLastNonWhiteSpaceCharacter: new CursorMoveCommand('wrappedLineLastNonWhitespaceCharacter'),
|
|
|
|
ViewPortTop: new CursorMoveCommand('viewPortTop'),
|
|
ViewPortBottom: new CursorMoveCommand('viewPortBottom'),
|
|
ViewPortCenter: new CursorMoveCommand('viewPortCenter'),
|
|
|
|
MoveActiveEditor: new MoveActiveEditorCommandByPosition(),
|
|
MoveActiveEditorLeft: new MoveActiveEditorCommand('left'),
|
|
MoveActiveEditorRight: new MoveActiveEditorCommand('right'),
|
|
MoveActiveEditorFirst: new MoveActiveEditorCommand('first'),
|
|
MoveActiveEditorLast: new MoveActiveEditorCommand('last'),
|
|
MoveActiveEditorCenter: new MoveActiveEditorCommand('center'),
|
|
|
|
ScrollDownByLine: new EditorScrollCommand('down', 'line'),
|
|
ScrollDownByHalfPage: new EditorScrollCommand('down', 'halfPage'),
|
|
ScrollDownByPage: new EditorScrollCommand('down', 'page'),
|
|
ScrollUpByLine: new EditorScrollCommand('up', 'line'),
|
|
ScrollUpByHalfPage: new EditorScrollCommand('up', 'halfPage'),
|
|
ScrollUpByPage: new EditorScrollCommand('up', 'page'),
|
|
|
|
RevealCurrentLineAtTop: new RevealCurrentLineCommand('top'),
|
|
RevealCurrentLineAtCenter: new RevealCurrentLineCommand('center'),
|
|
RevealCurrentLineAtBottom: new RevealCurrentLineCommand('bottom'),
|
|
|
|
FoldUnder: new FoldCommand(),
|
|
UnfoldUnder: new UnfoldCommand()
|
|
};
|