Implement a few simple ex commands

- `:p[rint]` and friends (arguments still unsupported)
- `:te[rminal]`
- `:asc[ii]`
This commit is contained in:
Jason Fields 2021-10-16 02:17:34 -04:00
parent 3d37bb4898
commit 71d9c1670f
14 changed files with 100 additions and 17 deletions

View File

@ -2956,7 +2956,7 @@ class DecrementNumberStaircaseAction extends IncrementDecrementNumberAction {
}
@RegisterAction
class CommandUnicodeName extends BaseCommand {
export class CommandUnicodeName extends BaseCommand {
modes = [Mode.Normal];
keys = ['g', 'a'];
override runsOnceForEveryCursor() {

View File

@ -0,0 +1,9 @@
import { CommandUnicodeName } from '../../actions/commands/actions';
import { VimState } from '../../state/vimState';
import { ExCommand } from '../../vimscript/exCommand';
export class AsciiCommand extends ExCommand {
async execute(vimState: VimState): Promise<void> {
await new CommandUnicodeName().exec(vimState.cursorStopPosition, vimState);
}
}

View File

@ -67,7 +67,7 @@ export class CopyCommand extends ExCommand {
}
public override async executeWithRange(vimState: VimState, range: LineRange): Promise<void> {
const { start, end } = range.resolve(vimState)!;
const { start, end } = range.resolve(vimState);
this.copyLines(vimState, start, end);
}
}

View File

@ -94,7 +94,7 @@ export class DeleteRangeCommand extends ExCommand {
* Ex. if two lines are VisualLine highlighted, :<,>d3 will :d3
* from the end of the selected lines.
*/
const { start, end } = range.resolve(vimState)!;
const { start, end } = range.resolve(vimState);
if (this.arguments.count) {
vimState.cursorStartPosition = new Position(end, 0);
await this.execute(vimState);

View File

@ -9,7 +9,7 @@ export class GotoLineCommand extends ExCommand {
public override async executeWithRange(vimState: VimState, range: LineRange): Promise<void> {
vimState.cursorStartPosition = vimState.cursorStopPosition = vimState.cursorStopPosition
.with({ line: range.resolve(vimState)!.end })
.with({ line: range.resolve(vimState).end })
.obeyStartOfLine(vimState.document);
}
}

View File

@ -0,0 +1,54 @@
import { Parser, succeed } from 'parsimmon';
import { VimState } from '../../state/vimState';
import { StatusBar } from '../../statusBar';
import { ExCommand } from '../../vimscript/exCommand';
import { Address, LineRange } from '../../vimscript/lineRange';
type PrintArgs = {
printNumbers: boolean;
printText: boolean;
};
// TODO: `:l[ist]` is more than an alias
// TODO: `:z`
export class PrintCommand extends ExCommand {
// TODO: Print {count} and [flags]
public static readonly argParser = (args: {
printNumbers: boolean;
printText: boolean;
}): Parser<PrintCommand> => succeed(new PrintCommand(args));
private args: PrintArgs;
constructor(args: PrintArgs) {
super();
this.args = args;
}
async execute(vimState: VimState): Promise<void> {
// TODO: Wrong default for `:=`
this.executeWithRange(vimState, new LineRange(new Address({ type: 'current_line' })));
}
override async executeWithRange(vimState: VimState, range: LineRange): Promise<void> {
const { end } = range.resolve(vimState);
// For now, we just print the last line.
// TODO: Create a dynamic document if there's more than one line?
const line = vimState.document.lineAt(end);
let output: string;
if (this.args.printNumbers) {
if (this.args.printText) {
output = `${line.lineNumber + 1} ${line.text}`;
} else {
output = `${line.lineNumber + 1}`;
}
} else {
if (this.args.printText) {
output = `${line.text}`;
} else {
output = '';
}
}
StatusBar.setText(vimState, output);
}
}

View File

@ -57,7 +57,7 @@ export class PutExCommand extends ExCommand {
}
override async executeWithRange(vimState: VimState, range: LineRange): Promise<void> {
const { end } = range.resolve(vimState)!;
const { end } = range.resolve(vimState);
await this.doPut(vimState, new Position(end, 0).getLineEnd());
}
}

View File

@ -95,7 +95,7 @@ export class SortCommand extends ExCommand {
}
override async executeWithRange(vimState: VimState, range: LineRange): Promise<void> {
const { start, end } = range.resolve(vimState)!;
const { start, end } = range.resolve(vimState);
await this.sortLines(vimState, start, end);
}

View File

@ -412,7 +412,7 @@ export class SubstituteCommand extends ExCommand {
}
override async executeWithRange(vimState: VimState, range: LineRange): Promise<void> {
let { start, end } = range.resolve(vimState)!;
let { start, end } = range.resolve(vimState);
if (this.arguments.count && this.arguments.count >= 0) {
start = end;

View File

@ -0,0 +1,12 @@
import { Parser, succeed } from 'parsimmon';
import * as vscode from 'vscode';
import { VimState } from '../../state/vimState';
import { ExCommand } from '../../vimscript/exCommand';
export class TerminalCommand extends ExCommand {
public static readonly argParser: Parser<TerminalCommand> = succeed(new TerminalCommand());
async execute(vimState: VimState): Promise<void> {
await vscode.commands.executeCommand('workbench.action.createTerminalEditor');
}
}

View File

@ -68,7 +68,7 @@ export class YankCommand extends ExCommand {
* Ex. if two lines are VisualLine highlighted, :<,>y3 will :y3
* from the end of the selected lines.
*/
const { start, end } = range.resolve(vimState)!;
const { start, end } = range.resolve(vimState);
if (this.arguments.count) {
vimState.cursorStartPosition = new Position(end, 0);
await this.execute(vimState);

View File

@ -1,4 +1,5 @@
import { all, alt, optWhitespace, Parser, regexp, seq, string, succeed } from 'parsimmon';
import { AsciiCommand } from '../cmd_line/commands/ascii';
import { BangCommand } from '../cmd_line/commands/bang';
import { BufferDeleteCommand } from '../cmd_line/commands/bufferDelete';
import { CloseCommand } from '../cmd_line/commands/close';
@ -14,6 +15,7 @@ import { ClearJumpsCommand, JumpsCommand } from '../cmd_line/commands/jumps';
import { DeleteMarksCommand, MarksCommand } from '../cmd_line/commands/marks';
import { NohlCommand } from '../cmd_line/commands/nohl';
import { OnlyCommand } from '../cmd_line/commands/only';
import { PrintCommand } from '../cmd_line/commands/print';
import { PutExCommand } from '../cmd_line/commands/put';
import { QuitCommand } from '../cmd_line/commands/quit';
import { ReadCommand } from '../cmd_line/commands/read';
@ -24,6 +26,7 @@ import { SmileCommand } from '../cmd_line/commands/smile';
import { SortCommand } from '../cmd_line/commands/sort';
import { SubstituteCommand } from '../cmd_line/commands/substitute';
import { TabCommand } from '../cmd_line/commands/tab';
import { TerminalCommand } from '../cmd_line/commands/terminal';
import { UndoCommand } from '../cmd_line/commands/undo';
import { VsCodeCommand } from '../cmd_line/commands/vscode';
import { WallCommand } from '../cmd_line/commands/wall';
@ -50,11 +53,12 @@ type ArgParser = Parser<ExCommand>;
export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | undefined]> = [
[['', ''], succeed(new GotoLineCommand())],
[['!', ''], BangCommand.argParser],
[['#', ''], undefined],
[['#', ''], PrintCommand.argParser({ printNumbers: true, printText: true })],
// TODO: Ignore #! (shebang)
[['&', ''], undefined],
[['*', ''], undefined],
[['<', ''], undefined],
[['=', ''], undefined],
[['=', ''], PrintCommand.argParser({ printNumbers: true, printText: false })],
[['>', ''], undefined],
[['@', ''], undefined],
[['@@', ''], undefined],
@ -74,7 +78,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und
[['argg', 'lobal'], undefined],
[['argl', 'ocal'], undefined],
[['argu', 'ment'], undefined],
[['as', 'cii'], undefined],
[['as', 'cii'], succeed(new AsciiCommand())],
[['au', 'tocmd'], undefined],
[['aug', 'roup'], undefined],
[['aun', 'menu'], undefined],
@ -267,7 +271,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und
[['keepa', 'lt'], undefined],
[['keepj', 'umps'], undefined],
[['keepp', 'atterns'], undefined],
[['l', 'ist'], undefined],
[['l', 'ist'], PrintCommand.argParser({ printNumbers: false, printText: true })],
[['lN', 'ext'], undefined],
[['lNf', 'ile'], undefined],
[['la', 'st'], undefined],
@ -359,7 +363,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und
[['noreme', 'nu'], undefined],
[['norm', 'al'], undefined],
[['nos', 'wapfile'], undefined],
[['nu', 'mber'], undefined],
[['nu', 'mber'], PrintCommand.argParser({ printNumbers: true, printText: true })],
[['nun', 'map'], undefined],
[['nunme', 'nu'], undefined],
[['ol', 'dfiles'], undefined],
@ -373,7 +377,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und
[['ou', 'nmap'], undefined],
[['ounme', 'nu'], undefined],
[['ow', 'nsyntax'], undefined],
[['p', 'rint'], undefined],
[['p', 'rint'], PrintCommand.argParser({ printNumbers: false, printText: true })],
[['pa', 'ckadd'], undefined],
[['packl', 'oadall'], undefined],
[['pc', 'lose'], undefined],
@ -522,7 +526,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und
[['tags', ''], undefined],
[['tc', 'd'], undefined],
[['tch', 'dir'], undefined],
[['te', 'rminal'], undefined],
[['te', 'rminal'], TerminalCommand.argParser],
[['tf', 'irst'], undefined],
[['th', 'row'], undefined],
[['tj', 'ump'], undefined],

View File

@ -292,7 +292,7 @@ export class LineRange {
return new LineRange(start);
});
public resolve(vimState: VimState): { start: number; end: number } | undefined {
public resolve(vimState: VimState): { start: number; end: number } {
// TODO: *,4 is not a valid range
const end = this.end ?? this.start;
@ -329,7 +329,7 @@ export class LineRange {
}
public resolveToRange(vimState: VimState): Range {
const { start, end } = this.resolve(vimState)!;
const { start, end } = this.resolve(vimState);
return new Range(new Position(start, 0), new Position(end, 0).getLineEnd());
}

View File

@ -219,6 +219,10 @@ suite('Ex command parsing', () => {
exParseTest(':marks 0 1', new MarksCommand(['0', '1']));
});
suite(':p[rint]', () => {
// TODO
});
suite(':pu[t]', () => {
exParseTest(':put', new PutExCommand({ bang: false, register: undefined }));
exParseTest(':put!', new PutExCommand({ bang: true, register: undefined }));