diff --git a/ROADMAP.md b/ROADMAP.md index d73d0852..7d726651 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,9 +12,9 @@ ## Roadmap -These are the big Vim features, put generally in the order in which we plan to implement them. +These are the big Vim features, put generally in the order in which we plan to implement them. -Status | Command +Status | Command ---|-------- :white_check_mark: | Normal Mode :white_check_mark: | Insert Mode @@ -23,16 +23,16 @@ Status | Command :white_check_mark: | Number Prefixes :white_check_mark: | . Operator :warning: | Searching with / and ? -:white_check_mark: | Correct Undo/Redo +:white_check_mark: | Correct Undo/Redo :warning: | Command Remapping :warning: | Marks :warning: | Text Objects | Visual Block Mode | Macros -:warning: | Buffer/Window/Tab +:warning: | Buffer/Window/Tab -Now follows an exhaustive list of every known Vim command that we could find. +Now follows an exhaustive list of every known Vim command that we could find. ## Left-right motions @@ -243,9 +243,9 @@ Status | Command | Description Status | Command | Description ---|--------|------------------------------ -:white_check_mark: | v | start highlighting characters -:white_check_mark: | V | start highlighting linewise - | CTRL-V | start highlighting blockwise +:white_check_mark: | v | start highlighting characters +:white_check_mark: | V | start highlighting linewise + | CTRL-V | start highlighting blockwise | o | exchange cursor position with start of highlighting | gv | start highlighting on previous visual area :white_check_mark: | v | highlight characters or stop highlighting @@ -297,7 +297,7 @@ Status | Command | Description :arrow_down: | :so[urce]! {file} | read Vim commands from {file} :arrow_down: | :sl[eep] [sec] | don't do anything for [sec] seconds :arrow_down: | :1234: gs | goto Sleep for N seconds - + ## Marks and motions @@ -359,8 +359,8 @@ Status | Command | Description | CTRL-D | delete one shiftwidth of indent in front of the current line | 0 CTRL-D | delete all indent in the current line | ^ CTRL-D | delete all indent in the current line, restore indent in next line - - + + ## Scrolling @@ -397,17 +397,23 @@ Status | Command | Description | :vne[w] | Create a new window vertically and start editing an empty file in it. -## Tabs +## Tabs Status | Command | Description ---|--------|------------------------------ -:warning: | :1234: :tabe[dit] | Open a new tab page with an empty window, after the current tab page -:warning: | :1234: :tabnew | Open a new tab page with an empty window, after the current tab page -:warning: | :tabc[lose][!] :1234: | Close current tab page. -:warning: | :tabo[nly][!] | Close all other tab pages. -:white_check_mark: | :tabn[ext] :1234: | Go to tab page {count}. The first tab page has number one. +:white_check_mark: | :tabn[ext] :1234: | Go to next tab page or tab page {count}. The first tab page has number one. + | {count}, {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}, {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. -:x: | :tabls | List the tab pages and the windows they contain. -:x: | :tabm[ove] [N] | Move the current tab page to after tab page N. +:warning: | :tabe[dit] {file} | Open a new tab page with an empty window, after the current tab page + | :[count]tabe[dit], :[count]tabnew | Same as above +:warning: | :tabnew {file} | Open a new tab page with an empty window, after the current tab page + | :[count]tab {cmd} | Execute {cmd} and when it opens a new window open a new tab page instead. +:warning: | :tabc[lose][!] :1234: | Close current tab page or close tab page {count}. +:warning: | :tabo[nly][!] | Close all other tab pages. +:white_check_mark: | :tabm[ove] [N] | Move the current tab page to after tab page N. +:x: | :tabs | List the tab pages and the windows they contain. + | :tabd[o] {cmd} | Execute {cmd} in each tab page. diff --git a/src/cmd_line/commands/tab.ts b/src/cmd_line/commands/tab.ts index 115968a6..a6acd8b4 100644 --- a/src/cmd_line/commands/tab.ts +++ b/src/cmd_line/commands/tab.ts @@ -10,12 +10,13 @@ export enum Tab { Last, New, Close, - Only + Only, + Move } export interface ITabCommandArguments extends node.ICommandArgs { tab: Tab; - count: number; + count?: number; } // @@ -45,25 +46,56 @@ export class TabCommand extends node.CommandBase { execute() : void { switch (this._arguments.tab) { case Tab.Next: - this.executeCommandWithCount(this._arguments.count, "workbench.action.nextEditor"); + if (this._arguments.count /** not undefined or 0 */) { + vscode.commands.executeCommand("workbench.action.openEditorAtIndex1"); + this.executeCommandWithCount(this._arguments.count! - 1, "workbench.action.nextEditor"); + } else { + this.executeCommandWithCount(1, "workbench.action.nextEditor"); + } break; case Tab.Previous: - this.executeCommandWithCount(this._arguments.count, "workbench.action.previousEditor"); + if (this._arguments.count !== undefined && this._arguments.count <= 0) { + break; + } + + this.executeCommandWithCount(this._arguments.count || 1, "workbench.action.previousEditor"); break; case Tab.First: - this.executeCommandWithCount(this._arguments.count, "workbench.action.openEditorAtIndex1"); + this.executeCommandWithCount(1, "workbench.action.openEditorAtIndex1"); break; case Tab.Last: - this.executeCommandWithCount(this._arguments.count, "workbench.action.openLastEditorInGroup"); + this.executeCommandWithCount(1, "workbench.action.openLastEditorInGroup"); break; case Tab.New: - this.executeCommandWithCount(this._arguments.count, "workbench.action.files.newUntitledFile"); + this.executeCommandWithCount(1, "workbench.action.files.newUntitledFile"); break; case Tab.Close: - this.executeCommandWithCount(this._arguments.count, "workbench.action.closeActiveEditor"); + // Navigate the correct position + if (this._arguments.count === undefined) { + vscode.commands.executeCommand("workbench.action.closeActiveEditor"); + break; + } + + if (this._arguments.count === 0) { + // Wrong paramter + break; + } + + // TODO: Close Page {count}. Page count is one-based. break; case Tab.Only: - this.executeCommandWithCount(this._arguments.count, "workbench.action.closeOtherEditors"); + this.executeCommandWithCount(1, "workbench.action.closeOtherEditors"); + break; + case Tab.Move: + if (this._arguments.count !== undefined) { + if (this._arguments.count === 0) { + vscode.commands.executeCommand("activeEditorMove", { to: "first" }); + } else { + vscode.commands.executeCommand("activeEditorMove", { to: "position", amount: this._arguments.count); + } + } else { + vscode.commands.executeCommand("activeEditorMove", { to: "last" }); + } break; default: diff --git a/src/cmd_line/subparser.ts b/src/cmd_line/subparser.ts index ea2e34d7..237eab67 100644 --- a/src/cmd_line/subparser.ts +++ b/src/cmd_line/subparser.ts @@ -23,6 +23,8 @@ export const commandParsers = { tabp: tabCmd.parseTabPCommandArgs, tabprevious: tabCmd.parseTabPCommandArgs, + tabN: tabCmd.parseTabPCommandArgs, + tabNext: tabCmd.parseTabPCommandArgs, tabfirst: tabCmd.parseTabFirstCommandArgs, tabfir: tabCmd.parseTabFirstCommandArgs, @@ -40,6 +42,8 @@ export const commandParsers = { tabo: tabCmd.parseTabOnlyCommandArgs, tabonly: tabCmd.parseTabOnlyCommandArgs, + tabm: tabCmd.parseTabMovementCommandArgs, + e: fileCmd.parseEditFileCommandArgs, s: parseSubstituteCommandArgs, diff --git a/src/cmd_line/subparsers/tab.ts b/src/cmd_line/subparsers/tab.ts index 3972a56e..e4369cc9 100644 --- a/src/cmd_line/subparsers/tab.ts +++ b/src/cmd_line/subparsers/tab.ts @@ -3,22 +3,22 @@ import * as node from "../commands/tab"; import {Scanner} from '../scanner'; -function parseCount(args: string): number { +function parseCount(args: string): number | undefined { if (!args) { - return 1; + return undefined; } let scanner = new Scanner(args); scanner.skipWhiteSpace(); if (scanner.isAtEof) { - return 1; + return undefined; } let c = scanner.next(); let count = Number.parseInt(c); - if (Number.isInteger(count) && count > 0 ) { + if (Number.isInteger(count) && count >= 0 ) { if (count > 999) { count = 999; } @@ -29,6 +29,10 @@ function parseCount(args: string): number { } } +/** + * :tabn[ext] Go to the next tab page. + * :tabn[ext] {count} Go to tab page {count}. + */ export function parseTabNCommandArgs(args : string) : node.TabCommand { return new node.TabCommand({ tab: node.Tab.Next, @@ -36,6 +40,10 @@ export function parseTabNCommandArgs(args : string) : node.TabCommand { }); } +/** + * :tabp[revious] Go to the previous tab page. Wraps around from the first one to the last one. + * :tabp[revious] {count} Go {count} tab pages back. + */ export function parseTabPCommandArgs(args : string) : node.TabCommand { return new node.TabCommand({ tab: node.Tab.Previous, @@ -43,41 +51,55 @@ export function parseTabPCommandArgs(args : string) : node.TabCommand { }); } +/** + * :tabfir[st] Go to the first tab page. + */ export function parseTabFirstCommandArgs(args : string) : node.TabCommand { return new node.TabCommand({ - tab: node.Tab.First, - count: 1 + tab: node.Tab.First }); } +/** + * :tabl[ast] Go to the last tab page. + */ export function parseTabLastCommandArgs(args : string) : node.TabCommand { return new node.TabCommand({ - tab: node.Tab.Last, - count: 1 + tab: node.Tab.Last }); } +/** + * :tabe[dit] + * :tabnew Open a new tab page with an empty window, after the current tab page. + */ export function parseTabNewCommandArgs(args: string) : node.TabCommand { - // New Tab command should support `count` - // And the new created Tab's position depends on `count` - // For now VS Code only allows open tab next to current Tab - // So `count == 0` is not possible. But we can workaround this once we can move tabs through API. + // TODO: Tab New takes parameter file name. return new node.TabCommand({ - tab: node.Tab.New, - count: 1 + tab: node.Tab.New }); } +/** + * :tabc[lose][!] Close current tab page. + * :tabc[lose][!] {count}. Close tab page {count}. + */ export function parseTabCloseCommandArgs(args: string) : node.TabCommand { return new node.TabCommand({ tab: node.Tab.Close, - count: 1 + count: parseCount(args) }); } export function parseTabOnlyCommandArgs(args: string) : node.TabCommand { return new node.TabCommand({ - tab: node.Tab.Only, - count: 1 + tab: node.Tab.Only + }); +} + +export function parseTabMovementCommandArgs(args: string) : node.TabCommand { + return new node.TabCommand({ + tab: node.Tab.Move, + count: parseCount(args) }); } \ No newline at end of file