feat(vscode): add keybindings for accepting inline completions. (#297)
* feat(vscode): add keybindings for accepting inline completions. * fix: set vscode keybinding profile to tabby-style. * fix: update vscode keybindings documentation. * docs: update vscode keybindings documentation.sweep/improve-logging-information
parent
be5fe0d737
commit
1878644778
|
|
@ -14,6 +14,5 @@
|
||||||
"no-throw-literal": "warn",
|
"no-throw-literal": "warn",
|
||||||
"semi": "off"
|
"semi": "off"
|
||||||
},
|
},
|
||||||
"ignorePatterns": ["out", "dist", "**/*.d.ts"],
|
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
|
||||||
"extends": ["prettier"]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@
|
||||||
"name": "Run Extension",
|
"name": "Run Extension",
|
||||||
"type": "extensionHost",
|
"type": "extensionHost",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"args": [
|
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--disable-extensions"],
|
||||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
|
||||||
"--disable-extensions"
|
|
||||||
],
|
|
||||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||||
"preLaunchTask": "${defaultBuildTask}"
|
"preLaunchTask": "${defaultBuildTask}"
|
||||||
},
|
},
|
||||||
|
|
@ -29,6 +26,6 @@
|
||||||
],
|
],
|
||||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||||
"preLaunchTask": "${defaultBuildTask}"
|
"preLaunchTask": "${defaultBuildTask}"
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
||||||
.vscode-test/**
|
.vscode-test/**
|
||||||
.vscode-test-web/**
|
.vscode-test-web/**
|
||||||
out/**
|
out/**
|
||||||
node_modules/**
|
**/node_modules/**
|
||||||
src/**
|
src/**
|
||||||
.gitignore
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
.prettierrc.json
|
||||||
|
tsup.config.ts
|
||||||
.yarnrc
|
.yarnrc
|
||||||
webpack.config.js
|
|
||||||
**/tsconfig.json
|
**/tsconfig.json
|
||||||
**/.eslintrc.json
|
**/.eslintrc.json
|
||||||
**/*.map
|
**/*.map
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,20 @@
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
Tabby will show inline suggestions when you stop typing. You can press the `Tab` key to accept the current suggestion.
|
Tabby will show inline suggestions when you stop typing.
|
||||||
|
You can accept press `Tab` to accept by line, `Ctrl +Tab` key to accept full suggestion, or `Ctrl + RightArrow` to accept single word.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## More Actions
|
## Cycling Through Choices
|
||||||
|
|
||||||
Hover over the inline suggestion text to see the toolbar providing more actions.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Cycling Through Choices
|
|
||||||
|
|
||||||
When multiple choices are available, you can cycle through them by pressing `Alt + [` and `Alt + ]`.
|
When multiple choices are available, you can cycle through them by pressing `Alt + [` and `Alt + ]`.
|
||||||
|
|
||||||
### Partially Accept by Word or by Line
|
## Keybindings
|
||||||
|
|
||||||
If you want to partially accept a code suggestion, you can accept it by word or by line. Press `Ctrl + RightArrow` to accept next word. Click `...` button on the toolbar, and you will find the option to accept the suggestion by line.
|
You can select a keybinding profile in the [settings](command:tabby.openSettings), or customize your own [keybindings](command:tabby.openKeybindings).
|
||||||
|
|
||||||
|
| | Accept Full Completion | Accept Next Word | Accept Next Line |
|
||||||
|
| -------------: | :--------------------: | :---------------: | :--------------: |
|
||||||
|
| _tabby-style_ | Ctrl + Tab | Ctrl + RightArrow | Tab |
|
||||||
|
| _vscode-style_ | Tab | Ctrl + RightArrow | - |
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ Choose your preferred way to host your Tabby server, either through Tabby Cloud
|
||||||
## Tabby Cloud
|
## Tabby Cloud
|
||||||
|
|
||||||
You can get a Tabby Cloud account [here](https://app.tabbyml.com). Once you create or join a workspace, you will receive a URL for your Tabby server endpoint.
|
You can get a Tabby Cloud account [here](https://app.tabbyml.com). Once you create or join a workspace, you will receive a URL for your Tabby server endpoint.
|
||||||
*Note*: Tabby Cloud is currently in beta. Join our [Slack community](https://join.slack.com/t/tabbycommunity/shared_invite/zt-1xeiddizp-bciR2RtFTaJ37RBxr8VxpA) and ask in Tabby Cloud channel to get a beta invite.
|
**Note**: Tabby Cloud is currently in beta. Join our [Slack community](https://join.slack.com/t/tabbycommunity/shared_invite/zt-1xeiddizp-bciR2RtFTaJ37RBxr8VxpA) and ask in Tabby Cloud channel to get a beta invite.
|
||||||
|
|
||||||
## Self-Hosting
|
## Self-Hosting
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:08f9f6cfa67831df25e5274878c9d6e64d193a89b8c3e267c3baea68b21ca043
|
|
||||||
size 156320
|
|
||||||
|
|
@ -121,24 +121,61 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Enable Tabby code completion or not."
|
"description": "Enable Tabby code completion or not."
|
||||||
},
|
},
|
||||||
|
"tabby.keybindings": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"tabby-style",
|
||||||
|
"vscode-style"
|
||||||
|
],
|
||||||
|
"default": "tabby-style",
|
||||||
|
"markdownDescription": "Select keybinding profile to accept current inline completion. \n | | Accept Full Completion | Accept Next Word | Accept Next Line | \n |---:|:--:|:--:|:--:| \n | _tabby-style_ | Ctrl + Tab | Ctrl + RightArrow | Tab | \n | _vscode-style_ | Tab | Ctrl + RightArrow | - | \n "
|
||||||
|
},
|
||||||
"tabby.usage.anonymousUsageTracking": {
|
"tabby.usage.anonymousUsageTracking": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Disable anonymous usage tracking."
|
"description": "Disable anonymous usage tracking."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"keybindings": [
|
||||||
|
{
|
||||||
|
"command": "tabby.inlineCompletion.accept",
|
||||||
|
"key": "tab",
|
||||||
|
"when": "config.tabby.codeCompletion && config.tabby.keybindings === 'vscode-style' && inlineSuggestionVisible && !editorReadonly && !editorTabMovesFocus && inlineSuggestionHasIndentationLessThanTabSize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "tabby.inlineCompletion.acceptNextWord",
|
||||||
|
"key": "ctrl+right",
|
||||||
|
"when": "config.tabby.codeCompletion && config.tabby.keybindings === 'vscode-style' && inlineSuggestionVisible && !editorReadonly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "tabby.inlineCompletion.accept",
|
||||||
|
"key": "ctrl+tab",
|
||||||
|
"when": "config.tabby.codeCompletion && config.tabby.keybindings === 'tabby-style' && inlineSuggestionVisible && !editorReadonly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "tabby.inlineCompletion.acceptNextWord",
|
||||||
|
"key": "ctrl+right",
|
||||||
|
"when": "config.tabby.codeCompletion && config.tabby.keybindings === 'tabby-style' && inlineSuggestionVisible && !editorReadonly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "tabby.inlineCompletion.acceptNextLine",
|
||||||
|
"key": "tab",
|
||||||
|
"when": "config.tabby.codeCompletion && config.tabby.keybindings === 'tabby-style' && inlineSuggestionVisible && !editorReadonly && !editorTabMovesFocus"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"prebuild": "cd ../tabby-agent && yarn build",
|
||||||
"build": "tsup --minify --treeshake smallest",
|
"build": "tsup --minify --treeshake smallest",
|
||||||
"watch": "tsup --sourcemap --watch ./ --ignore-watch ./dist --watch ../tabby-agent/dist",
|
"watch": "tsup --sourcemap --watch ./ --ignore-watch ./dist --watch ../tabby-agent/dist",
|
||||||
"dev": "code --extensionDevelopmentPath=$PWD --disable-extensions && yarn watch",
|
"dev": "code --extensionDevelopmentPath=$PWD --disable-extensions && yarn watch",
|
||||||
"dev:browser": "vscode-test-web --extensionDevelopmentPath=$PWD --browserType=chromium --port=3000 && yarn watch",
|
"dev:browser": "vscode-test-web --extensionDevelopmentPath=$PWD --browserType=chromium --port=3000 && yarn watch",
|
||||||
"lint": "eslint . --fix",
|
"lint": "prettier --write .",
|
||||||
"vscode:prepackage": "yarn build",
|
"vscode:prepackage": "yarn build",
|
||||||
"vscode:package": "vsce package",
|
"vscode:package": "vsce package --no-dependencies",
|
||||||
"vscode:prepublish": "yarn build",
|
"vscode:prepublish": "yarn build",
|
||||||
"vscode:publish": "vsce publish"
|
"vscode:publish": "vsce publish --no-dependencies"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/glob": "^7.2.0",
|
"@types/glob": "^7.2.0",
|
||||||
|
|
@ -153,7 +190,6 @@
|
||||||
"assert": "^2.0.0",
|
"assert": "^2.0.0",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.20.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"tsup": "^7.1.0",
|
"tsup": "^7.1.0",
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export class TabbyCompletionProvider implements InlineCompletionItemProvider {
|
||||||
|
|
||||||
private hasSuffixParen(document: TextDocument, position: Position) {
|
private hasSuffixParen(document: TextDocument, position: Position) {
|
||||||
const suffix = document.getText(
|
const suffix = document.getText(
|
||||||
new Range(position.line, position.character, position.line, position.character + 1)
|
new Range(position.line, position.character, position.line, position.character + 1),
|
||||||
);
|
);
|
||||||
return ")]}".indexOf(suffix) > -1;
|
return ")]}".indexOf(suffix) > -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,18 @@ const openTabbyAgentSettings: Command = {
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
window.showWarningMessage("Tabby Agent config file not found.", { modal: true });
|
window.showWarningMessage("Tabby Agent config file not found.", { modal: true });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openKeybindings: Command = {
|
||||||
|
command: "tabby.openKeybindings",
|
||||||
|
callback: () => {
|
||||||
|
commands.executeCommand("workbench.action.openGlobalKeybindings", "tabby.inlineCompletion");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const gettingStarted: Command = {
|
const gettingStarted: Command = {
|
||||||
command: "tabby.gettingStarted",
|
command: "tabby.gettingStarted",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
|
|
@ -138,13 +145,15 @@ const openAuthPage: Command = {
|
||||||
notifications.showInformationWhenAuthFailed();
|
notifications.showInformationWhenAuthFailed();
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.isCancelled) return;
|
if (error.isCancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.debug("Error auth", { error });
|
console.debug("Error auth", { error });
|
||||||
notifications.showInformationWhenAuthFailed();
|
notifications.showInformationWhenAuthFailed();
|
||||||
} finally {
|
} finally {
|
||||||
callbacks?.onAuthEnd?.();
|
callbacks?.onAuthEnd?.();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -172,14 +181,41 @@ const statusBarItemClicked: Command = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const acceptInlineCompletion: Command = {
|
||||||
|
command: "tabby.inlineCompletion.accept",
|
||||||
|
callback: () => {
|
||||||
|
commands.executeCommand("editor.action.inlineSuggest.commit");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const acceptInlineCompletionNextWord: Command = {
|
||||||
|
command: "tabby.inlineCompletion.acceptNextWord",
|
||||||
|
callback: () => {
|
||||||
|
// FIXME: sent event when partially accept?
|
||||||
|
commands.executeCommand("editor.action.inlineSuggest.acceptNextWord");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const acceptInlineCompletionNextLine: Command = {
|
||||||
|
command: "tabby.inlineCompletion.acceptNextLine",
|
||||||
|
callback: () => {
|
||||||
|
// FIXME: sent event when partially accept?
|
||||||
|
commands.executeCommand("editor.action.inlineSuggest.acceptNextLine");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const tabbyCommands = () =>
|
export const tabbyCommands = () =>
|
||||||
[
|
[
|
||||||
toggleEnabled,
|
toggleEnabled,
|
||||||
setApiEndpoint,
|
setApiEndpoint,
|
||||||
openSettings,
|
openSettings,
|
||||||
openTabbyAgentSettings,
|
openTabbyAgentSettings,
|
||||||
|
openKeybindings,
|
||||||
gettingStarted,
|
gettingStarted,
|
||||||
emitEvent,
|
emitEvent,
|
||||||
openAuthPage,
|
openAuthPage,
|
||||||
statusBarItemClicked,
|
statusBarItemClicked,
|
||||||
|
acceptInlineCompletion,
|
||||||
|
acceptInlineCompletionNextWord,
|
||||||
|
acceptInlineCompletionNextLine,
|
||||||
].map((command) => commands.registerCommand(command.command, command.callback, command.thisArg));
|
].map((command) => commands.registerCommand(command.command, command.callback, command.thisArg));
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,7 @@ export async function activate(context: ExtensionContext) {
|
||||||
console.debug("Activating Tabby extension", new Date());
|
console.debug("Activating Tabby extension", new Date());
|
||||||
await createAgentInstance(context);
|
await createAgentInstance(context);
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
languages.registerInlineCompletionItemProvider(
|
languages.registerInlineCompletionItemProvider({ pattern: "**" }, new TabbyCompletionProvider()),
|
||||||
{ pattern: "**" },
|
|
||||||
new TabbyCompletionProvider()
|
|
||||||
),
|
|
||||||
tabbyStatusBarItem(),
|
tabbyStatusBarItem(),
|
||||||
...tabbyCommands(),
|
...tabbyCommands(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ function showInformationStartAuth(callbacks?: { onAuthStart?: () => void; onAuth
|
||||||
.showWarningMessage(
|
.showWarningMessage(
|
||||||
"Tabby Server requires authorization. Continue to open authorization page in your browser.",
|
"Tabby Server requires authorization. Continue to open authorization page in your browser.",
|
||||||
"Continue",
|
"Continue",
|
||||||
"Settings"
|
"Settings",
|
||||||
)
|
)
|
||||||
.then((selection) => {
|
.then((selection) => {
|
||||||
switch (selection) {
|
switch (selection) {
|
||||||
|
|
|
||||||
|
|
@ -1481,11 +1481,6 @@ escape-string-regexp@^1.0.5:
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||||
|
|
||||||
eslint-config-prettier@^8.8.0:
|
|
||||||
version "8.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348"
|
|
||||||
integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==
|
|
||||||
|
|
||||||
eslint-scope@^5.1.1:
|
eslint-scope@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue