diff --git a/src/cmd_line/commands/marks.ts b/src/cmd_line/commands/marks.ts index e4abcfe2da4..4dcd7e41c6f 100644 --- a/src/cmd_line/commands/marks.ts +++ b/src/cmd_line/commands/marks.ts @@ -2,11 +2,13 @@ import { QuickPickItem, window } from 'vscode'; // eslint-disable-next-line id-denylist import { Parser, alt, noneOf, optWhitespace, regexp, seq, string, whitespace } from 'parsimmon'; +import { Position } from 'vscode'; import { Cursor } from '../../common/motion/cursor'; import { ErrorCode, VimError } from '../../error'; import { IMark } from '../../history/historyTracker'; import { VimState } from '../../state/vimState'; import { ExCommand } from '../../vimscript/exCommand'; +import { LineRange } from '../../vimscript/lineRange'; class MarkQuickPickItem implements QuickPickItem { mark: IMark; @@ -133,3 +135,32 @@ export class DeleteMarksCommand extends ExCommand { vimState.historyTracker.removeMarks(marks); } } + +export class MarkCommand extends ExCommand { + public static readonly argParser: Parser = seq( + optWhitespace, + regexp(/[a-zA-Z'`<>[\].]/).desc('mark name'), + optWhitespace, + ).map(([, markName]) => new MarkCommand(markName)); + + private markName: string; + constructor(markName: string) { + super(); + this.markName = markName; + } + + async execute(vimState: VimState): Promise { + const position = vimState.cursorStopPosition; + vimState.historyTracker.addMark(vimState.document, position, this.markName); + } + + override async executeWithRange(vimState: VimState, range: LineRange): Promise { + /** + * When a range is specified, the mark is set at the last line of the range. + * For example, :1,5mark a will set mark 'a' at line 5. + */ + const { end } = range.resolve(vimState); + const position = new Position(end, 0); + vimState.historyTracker.addMark(vimState.document, position, this.markName); + } +} diff --git a/src/vimscript/exCommandParser.ts b/src/vimscript/exCommandParser.ts index be721ffab45..55160b1bde3 100644 --- a/src/vimscript/exCommandParser.ts +++ b/src/vimscript/exCommandParser.ts @@ -16,7 +16,7 @@ import { GotoLineCommand } from '../cmd_line/commands/gotoLine'; import { HistoryCommand } from '../cmd_line/commands/history'; import { ClearJumpsCommand, JumpsCommand } from '../cmd_line/commands/jumps'; import { CenterCommand, LeftCommand, RightCommand } from '../cmd_line/commands/leftRightCenter'; -import { DeleteMarksCommand, MarksCommand } from '../cmd_line/commands/marks'; +import { DeleteMarksCommand, MarksCommand, MarkCommand } from '../cmd_line/commands/marks'; import { ExploreCommand } from '../cmd_line/commands/explore'; import { MoveCommand } from '../cmd_line/commands/move'; import { NohlCommand } from '../cmd_line/commands/nohl'; @@ -351,7 +351,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und [['lvimgrepa', 'dd'], undefined], [['lw', 'indow'], succeed(new VsCodeCommand('workbench.action.focusCommentsPanel'))], [['m', 'ove'], MoveCommand.argParser], - [['ma', 'rk'], undefined], + [['ma', 'rk'], MarkCommand.argParser], [['mak', 'e'], undefined], [['map', ''], undefined], [['mapc', 'lear'], undefined], diff --git a/test/vimscript/exCommandParse.test.ts b/test/vimscript/exCommandParse.test.ts index 18721b4fc6d..0b9fcfbd34b 100644 --- a/test/vimscript/exCommandParse.test.ts +++ b/test/vimscript/exCommandParse.test.ts @@ -10,7 +10,7 @@ import { GotoLineCommand } from '../../src/cmd_line/commands/gotoLine'; import { HistoryCommand, HistoryCommandType } from '../../src/cmd_line/commands/history'; import { LeftCommand, RightCommand } from '../../src/cmd_line/commands/leftRightCenter'; import { LetCommand } from '../../src/cmd_line/commands/let'; -import { DeleteMarksCommand, MarksCommand } from '../../src/cmd_line/commands/marks'; +import { DeleteMarksCommand, MarksCommand, MarkCommand } from '../../src/cmd_line/commands/marks'; import { PutExCommand } from '../../src/cmd_line/commands/put'; import { QuitCommand } from '../../src/cmd_line/commands/quit'; import { ReadCommand } from '../../src/cmd_line/commands/read'; @@ -382,6 +382,11 @@ suite('Ex command parsing', () => { exParseTest(':marks 0 1', new MarksCommand(['0', '1'])); }); + suite(':mark', () => { + exParseTest(':mark a', new MarkCommand('a')); + exParseTest(':mark `', new MarkCommand('`')); + }); + suite(':p[rint]', () => { // TODO });