234 lines
7.0 KiB
TypeScript
234 lines
7.0 KiB
TypeScript
import {
|
|
ConfigurationTarget,
|
|
InputBoxValidationSeverity,
|
|
ProgressLocation,
|
|
Uri,
|
|
workspace,
|
|
window,
|
|
env,
|
|
commands,
|
|
} from "vscode";
|
|
import { strict as assert } from "assert";
|
|
import { agent } from "./agent";
|
|
import { notifications } from "./notifications";
|
|
|
|
const configTarget = ConfigurationTarget.Global;
|
|
|
|
type Command = {
|
|
command: string;
|
|
callback: (...args: any[]) => any;
|
|
thisArg?: any;
|
|
};
|
|
|
|
const toggleEnabled: Command = {
|
|
command: "tabby.toggleEnabled",
|
|
callback: () => {
|
|
const configuration = workspace.getConfiguration("tabby");
|
|
const enabled = configuration.get("codeCompletion", true);
|
|
console.debug(`Toggle Enabled: ${enabled} -> ${!enabled}.`);
|
|
configuration.update("codeCompletion", !enabled, configTarget, false);
|
|
},
|
|
};
|
|
|
|
const setApiEndpoint: Command = {
|
|
command: "tabby.setApiEndpoint",
|
|
callback: () => {
|
|
const configuration = workspace.getConfiguration("tabby");
|
|
window
|
|
.showInputBox({
|
|
prompt: "Enter the URL of your Tabby Server",
|
|
value: configuration.get("api.endpoint", ""),
|
|
validateInput: (input: string) => {
|
|
try {
|
|
let url = new URL(input);
|
|
assert(url.protocol == "http:" || url.protocol == "https:");
|
|
} catch (_) {
|
|
return {
|
|
message: "Please enter a validate http or https URL.",
|
|
severity: InputBoxValidationSeverity.Error,
|
|
};
|
|
}
|
|
return null;
|
|
},
|
|
})
|
|
.then((url) => {
|
|
if (url) {
|
|
console.debug("Set Tabby Server URL: ", url);
|
|
configuration.update("api.endpoint", url, configTarget, false);
|
|
}
|
|
});
|
|
},
|
|
};
|
|
|
|
const openSettings: Command = {
|
|
command: "tabby.openSettings",
|
|
callback: () => {
|
|
commands.executeCommand("workbench.action.openSettings", "@ext:TabbyML.vscode-tabby");
|
|
},
|
|
};
|
|
|
|
const openTabbyAgentSettings: Command = {
|
|
command: "tabby.openTabbyAgentSettings",
|
|
callback: () => {
|
|
if (env.appHost !== "desktop") {
|
|
window.showWarningMessage("Tabby Agent config file is not supported on web.", { modal: true });
|
|
return;
|
|
}
|
|
const agentUserConfig = Uri.joinPath(Uri.file(require("os").homedir()), ".tabby-client", "agent", "config.toml");
|
|
workspace.fs.stat(agentUserConfig).then(
|
|
() => {
|
|
workspace.openTextDocument(agentUserConfig).then((document) => {
|
|
window.showTextDocument(document);
|
|
});
|
|
},
|
|
() => {
|
|
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 = {
|
|
command: "tabby.gettingStarted",
|
|
callback: () => {
|
|
commands.executeCommand("workbench.action.openWalkthrough", "TabbyML.vscode-tabby#gettingStarted");
|
|
},
|
|
};
|
|
|
|
const emitEvent: Command = {
|
|
command: "tabby.emitEvent",
|
|
callback: (event) => {
|
|
console.debug("Emit Event: ", event);
|
|
agent().postEvent(event);
|
|
},
|
|
};
|
|
|
|
const openAuthPage: Command = {
|
|
command: "tabby.openAuthPage",
|
|
callback: (callbacks?: { onAuthStart?: () => void; onAuthEnd?: () => void }) => {
|
|
window.withProgress(
|
|
{
|
|
location: ProgressLocation.Notification,
|
|
title: "Tabby Server Authorization",
|
|
cancellable: true,
|
|
},
|
|
async (progress, token) => {
|
|
const abortController = new AbortController();
|
|
token.onCancellationRequested(() => {
|
|
abortController.abort();
|
|
});
|
|
const signal = abortController.signal;
|
|
try {
|
|
callbacks?.onAuthStart?.();
|
|
progress.report({ message: "Generating authorization url..." });
|
|
let authUrl = await agent().requestAuthUrl({ signal });
|
|
if (authUrl) {
|
|
env.openExternal(Uri.parse(authUrl.authUrl));
|
|
progress.report({ message: "Waiting for authorization from browser..." });
|
|
await agent().waitForAuthToken(authUrl.code, { signal });
|
|
assert(agent().getStatus() === "ready");
|
|
notifications.showInformationAuthSuccess();
|
|
} else if (agent().getStatus() === "ready") {
|
|
notifications.showInformationWhenStartAuthButAlreadyAuthorized();
|
|
} else {
|
|
notifications.showInformationWhenAuthFailed();
|
|
}
|
|
} catch (error: any) {
|
|
if (error.name === "AbortError") {
|
|
return;
|
|
}
|
|
console.debug("Error auth", { error });
|
|
notifications.showInformationWhenAuthFailed();
|
|
} finally {
|
|
callbacks?.onAuthEnd?.();
|
|
}
|
|
},
|
|
);
|
|
},
|
|
};
|
|
|
|
const statusBarItemClicked: Command = {
|
|
command: "tabby.statusBarItemClicked",
|
|
callback: (status) => {
|
|
switch (status) {
|
|
case "loading":
|
|
notifications.showInformationWhenLoading();
|
|
break;
|
|
case "ready":
|
|
notifications.showInformationWhenReady();
|
|
break;
|
|
case "disconnected":
|
|
notifications.showInformationWhenDisconnected();
|
|
break;
|
|
case "unauthorized":
|
|
notifications.showInformationStartAuth();
|
|
break;
|
|
case "issuesExist":
|
|
switch (agent().getIssues()[0]?.name) {
|
|
case "slowCompletionResponseTime":
|
|
notifications.showInformationWhenSlowCompletionResponseTime();
|
|
break;
|
|
case "highCompletionTimeoutRate":
|
|
notifications.showInformationWhenHighCompletionTimeoutRate();
|
|
break;
|
|
}
|
|
break;
|
|
case "disabled":
|
|
const enabled = workspace.getConfiguration("tabby").get("codeCompletion", true);
|
|
const inlineSuggestEnabled = workspace.getConfiguration("editor").get("inlineSuggest.enabled", true);
|
|
if (enabled && !inlineSuggestEnabled) {
|
|
notifications.showInformationWhenInlineSuggestDisabled();
|
|
} else {
|
|
notifications.showInformationWhenDisabled();
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
};
|
|
|
|
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 = () =>
|
|
[
|
|
toggleEnabled,
|
|
setApiEndpoint,
|
|
openSettings,
|
|
openTabbyAgentSettings,
|
|
openKeybindings,
|
|
gettingStarted,
|
|
emitEvent,
|
|
openAuthPage,
|
|
statusBarItemClicked,
|
|
acceptInlineCompletion,
|
|
acceptInlineCompletionNextWord,
|
|
acceptInlineCompletionNextLine,
|
|
].map((command) => commands.registerCommand(command.command, command.callback, command.thisArg));
|