mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-08-16 15:50:35 +03:00
Substitute marks (#744)
* add synonym for '<,'> * support Marks in substitute * support ; and update roadmap
This commit is contained in:
parent
bf2a1ec2c4
commit
1b69c8bb96
18
ROADMAP.md
18
ROADMAP.md
@ -485,20 +485,20 @@ Status | Command | Description
|
||||
:arrow_down: | :!{command} | execute {command} with a shell
|
||||
:arrow_down: | K | lookup keyword under the cursor with 'keywordprg' program (default: "man")
|
||||
|
||||
## Ex rangs
|
||||
## Ex ranges
|
||||
|
||||
Status | Command | Description
|
||||
---|--------|-------|------------------------------
|
||||
Status | Command | Description | Note
|
||||
---|--------|-------|------------|------------------
|
||||
:white_check_mark: | , | separates two line numbers|
|
||||
| ; | idem, set cursor to the first line number before interpreting the second one
|
||||
:white_check_mark: :star: :warning: | ; | idem, set cursor to the first line number before interpreting the second one | The cursor movement is not included.
|
||||
:white_check_mark: | {number} | an absolute line number
|
||||
:white_check_mark: | . | the current line
|
||||
:white_check_mark: | $ | the last line in the file
|
||||
:white_check_mark: | % | equal to 1,$ (the entire file)
|
||||
| * | equal to '<,'> (visual area)
|
||||
| 't | position of mark t
|
||||
| /{pattern}[/] | the next line where {pattern} matches
|
||||
| ?{pattern}[?] | the previous line where {pattern} matches
|
||||
:white_check_mark: | * | equal to '<,'> (visual area)
|
||||
:white_check_mark: | 't | position of mark t
|
||||
:arrow_down: | /{pattern}[/] | the next line where {pattern} matches
|
||||
:arrow_down: | ?{pattern}[?] | the previous line where {pattern} matches
|
||||
:white_check_mark: | +[num] | add [num] to the preceding line number (default: 1)
|
||||
:white_check_mark: | -[num] | subtract [num] from the preceding line number (default: 1)
|
||||
|
||||
@ -528,7 +528,7 @@ Status | Command | Description | Note
|
||||
:white_check_mark: | {count}<C-PageDown>, {count}gt | Same as above
|
||||
:white_check_mark: | :tabp[revious] :1234: | Go to the previous tab page. Wraps around from the first one to the last one.
|
||||
:white_check_mark: | :tabN[ext] :1234: | Same as above
|
||||
| {count}<C-PageUp>, {count}gT | Same as above
|
||||
:white_check_mark: | {count}<C-PageUp>, {count}gT | Same as above
|
||||
:white_check_mark: | :tabfir[st] | Go to the first tab page.
|
||||
:white_check_mark: | :tabl[ast] | Go to the last tab page.
|
||||
:white_check_mark: | :tabe[dit] {file} | Open a new tab page with an empty window, after the current tab page
|
||||
|
@ -99,8 +99,8 @@ export class SubstituteCommand extends node.CommandBase {
|
||||
startLine = new vscode.Position(0, 0);
|
||||
endLine = new vscode.Position(TextEditor.getLineCount() - 1, 0);
|
||||
} else {
|
||||
startLine = range.lineRefToPosition(vscode.window.activeTextEditor, range.left);
|
||||
endLine = range.lineRefToPosition(vscode.window.activeTextEditor, range.right);
|
||||
startLine = range.lineRefToPosition(vscode.window.activeTextEditor, range.left, modeHandler);
|
||||
endLine = range.lineRefToPosition(vscode.window.activeTextEditor, range.right, modeHandler);
|
||||
}
|
||||
|
||||
if (this._arguments.count && this._arguments.count >= 0) {
|
||||
|
@ -36,6 +36,7 @@ module LexerFunctions {
|
||||
var c = state.next();
|
||||
switch (c) {
|
||||
case ",":
|
||||
case ";":
|
||||
tokens.push(emitToken(TokenType.Comma, state)!);
|
||||
continue;
|
||||
case "%":
|
||||
@ -68,6 +69,12 @@ module LexerFunctions {
|
||||
case "-":
|
||||
tokens.push(emitToken(TokenType.Minus, state)!);
|
||||
continue;
|
||||
case "*":
|
||||
state.emit();
|
||||
tokens.push(new Token(TokenType.SelectionFirstLine, '<')!);
|
||||
tokens.push(new Token(TokenType.Comma, ',')!);
|
||||
tokens.push(new Token(TokenType.SelectionLastLine, '>')!);
|
||||
continue;
|
||||
case "'":
|
||||
return lexMark;
|
||||
default:
|
||||
@ -80,24 +87,29 @@ module LexerFunctions {
|
||||
|
||||
function lexMark(state: Scanner, tokens: Token[]): ILexFunction | null {
|
||||
// The first token has already been lexed.
|
||||
while (true) {
|
||||
if (state.isAtEof) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var c = state.next();
|
||||
switch (c) {
|
||||
case '<':
|
||||
tokens.push(emitToken(TokenType.SelectionFirstLine, state)!);
|
||||
break;
|
||||
case '>':
|
||||
tokens.push(emitToken(TokenType.SelectionLastLine, state)!);
|
||||
break;
|
||||
default:
|
||||
state.backup();
|
||||
return lexRange;
|
||||
}
|
||||
if (state.isAtEof) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var c = state.next();
|
||||
switch (c) {
|
||||
case '<':
|
||||
tokens.push(emitToken(TokenType.SelectionFirstLine, state) !);
|
||||
break;
|
||||
case '>':
|
||||
tokens.push(emitToken(TokenType.SelectionLastLine, state) !);
|
||||
break;
|
||||
default:
|
||||
if (/[a-zA-Z]/.test(c)) {
|
||||
state.emit();
|
||||
tokens.push(new Token(TokenType.Mark, c) !);
|
||||
} else {
|
||||
state.backup();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return lexRange;
|
||||
}
|
||||
|
||||
function lexLineRef(state : Scanner, tokens: Token[]): ILexFunction | null {
|
||||
|
@ -43,16 +43,16 @@ export class LineRange {
|
||||
return this.left.toString() + this.separator.content + this.right.toString();
|
||||
}
|
||||
|
||||
execute(document : vscode.TextEditor) : void {
|
||||
execute(document : vscode.TextEditor, modeHandler: ModeHandler) : void {
|
||||
if (this.isEmpty) {
|
||||
return;
|
||||
}
|
||||
var lineRef = this.right.length === 0 ? this.left : this.right;
|
||||
var pos = this.lineRefToPosition(document, lineRef);
|
||||
var pos = this.lineRefToPosition(document, lineRef, modeHandler);
|
||||
document.selection = new vscode.Selection(pos, pos);
|
||||
}
|
||||
|
||||
lineRefToPosition(doc : vscode.TextEditor, toks : token.Token[]) : vscode.Position {
|
||||
lineRefToPosition(doc : vscode.TextEditor, toks : token.Token[], modeHandler: ModeHandler) : vscode.Position {
|
||||
var first = toks[0];
|
||||
switch (first.type) {
|
||||
case token.TokenType.Dollar:
|
||||
@ -71,6 +71,8 @@ export class LineRange {
|
||||
case token.TokenType.SelectionLastLine:
|
||||
let end = doc.selection.start.isAfter(doc.selection.end) ? doc.selection.start : doc.selection.end;
|
||||
return new vscode.Position(end.line, 0);
|
||||
case token.TokenType.Mark:
|
||||
return modeHandler.vimState.historyTracker.getMark(first.content).position;
|
||||
default:
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
@ -95,7 +97,7 @@ export class CommandLine {
|
||||
|
||||
async execute(document : vscode.TextEditor, modeHandler : ModeHandler) : Promise<void> {
|
||||
if (!this.command) {
|
||||
this.range.execute(document);
|
||||
this.range.execute(document, modeHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ function parseLineRange(state: ParserState, commandLine: node.CommandLine): IPar
|
||||
case token.TokenType.LineNumber:
|
||||
case token.TokenType.SelectionFirstLine:
|
||||
case token.TokenType.SelectionLastLine:
|
||||
case token.TokenType.Mark:
|
||||
commandLine.range.addToken(tok);
|
||||
continue;
|
||||
case token.TokenType.CommandName:
|
||||
|
@ -22,7 +22,8 @@ export enum TokenType {
|
||||
*
|
||||
*/
|
||||
SelectionFirstLine,
|
||||
SelectionLastLine
|
||||
SelectionLastLine,
|
||||
Mark
|
||||
}
|
||||
|
||||
export class Token {
|
||||
|
@ -71,4 +71,15 @@ suite("Basic substitute", () => {
|
||||
"db"
|
||||
]);
|
||||
});
|
||||
|
||||
test("Substitute support marks", async () => {
|
||||
await modeHandler.handleMultipleKeyEvents(['i', 'a', 'b', 'c', '<Esc>', 'y', 'y', '2', 'p', 'g', 'g', 'm', 'a', 'j', 'm', 'b']);
|
||||
await runCmdLine("'a,'bs/a/d/g", modeHandler);
|
||||
|
||||
assertEqualLines([
|
||||
"dbc",
|
||||
"dbc",
|
||||
"abc"
|
||||
]);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user