Skip to content

Commit

Permalink
fix(chat-panel&vscode): fix keyboard event handling. (#3219)
Browse files Browse the repository at this point in the history
* fix(chat-panel&vscode): fix keyboard event handling.

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
icycodes and autofix-ci[bot] authored Sep 29, 2024
1 parent 28ecaa8 commit 8f54ef8
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 178 deletions.
2 changes: 1 addition & 1 deletion clients/tabby-chat-panel/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "tabby-chat-panel",
"type": "module",
"version": "0.1.0",
"version": "0.2.0",
"keywords": [],
"sideEffects": false,
"exports": {
Expand Down
20 changes: 7 additions & 13 deletions clients/tabby-chat-panel/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,16 @@ export interface FetcherOptions {

export interface InitRequest {
fetcherOptions: FetcherOptions
focusKey?: FocusKeybinding
// Workaround for vscode webview issue:
// shortcut (cmd+a, cmd+c, cmd+v, cmd+x) not work in nested iframe in vscode webview
// see https://github.com/microsoft/vscode/issues/129178
useMacOSKeyboardEventHandler?: boolean
}

export interface OnLoadedParams {
apiVersion: string
}

export interface FocusKeybinding {
key: string
ctrlKey: boolean
metaKey: boolean
shiftKey: boolean
altKey: boolean
}

export interface ErrorMessage {
title?: string
content: string
Expand Down Expand Up @@ -72,7 +67,7 @@ export interface ClientApi {
// On user copy content to clipboard.
onCopy: (content: string) => void

focusOnEditor: () => void
onKeyboardEvent: (type: 'keydown' | 'keyup' | 'keypress', event: KeyboardEventInit) => void
}

export interface ChatMessage {
Expand All @@ -97,12 +92,13 @@ export function createClient(target: HTMLIFrameElement, api: ClientApi): ServerA
onApplyInEditor: api.onApplyInEditor,
onLoaded: api.onLoaded,
onCopy: api.onCopy,
onKeyboardEvent: api.onKeyboardEvent,
},
})
}

export function createServer(api: ServerApi): ClientApi {
const clientApi: ClientApi = createThreadFromInsideIframe({
return createThreadFromInsideIframe({
expose: {
init: api.init,
sendMessage: api.sendMessage,
Expand All @@ -112,6 +108,4 @@ export function createServer(api: ServerApi): ClientApi {
updateTheme: api.updateTheme,
},
})

return clientApi
}
4 changes: 4 additions & 0 deletions clients/vscode/assets/chat-panel.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
html,
body {
background: transparent;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
html,
body,
Expand Down
10 changes: 8 additions & 2 deletions clients/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,19 +411,25 @@
"key": "ctrl+l",
"mac": "cmd+l",
"when": "!editorHasSelection && editorTextFocus && tabby.chatEnabled"
},
{
"command": "workbench.action.focusActiveEditorGroup",
"key": "ctrl+l",
"mac": "cmd+l",
"when": "!editorFocus && focusedView == 'tabby.chatView'"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "chatView",
"id": "tabbyChatView",
"title": "Tabby",
"icon": "assets/chat.svg"
}
]
},
"views": {
"chatView": [
"tabbyChatView": [
{
"type": "webview",
"id": "tabby.chatView",
Expand Down
51 changes: 13 additions & 38 deletions clients/vscode/src/chat/WebviewHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,25 @@ import {
ViewColumn,
WorkspaceFolder,
TextDocument,
commands,
Webview,
ColorThemeKind,
} from "vscode";
import type { ServerApi, ChatMessage, Context, NavigateOpts, FocusKeybinding, OnLoadedParams } from "tabby-chat-panel";
import type { ServerApi, ChatMessage, Context, NavigateOpts, OnLoadedParams } from "tabby-chat-panel";
import { TABBY_CHAT_PANEL_API_VERSION } from "tabby-chat-panel";
import hashObject from "object-hash";
import * as semver from "semver";
import type { ServerInfo } from "tabby-agent";
import type { AgentFeature as Agent } from "../lsp/AgentFeature";
import { GitProvider } from "../git/GitProvider";
import { getLogger } from "../logger";
import { contributes } from "../../package.json";
import { parseKeybinding, readUserKeybindingsConfig } from "../util/KeybindingParser";
import { createClient } from "./chatPanel";
import { isBrowser } from "../env";

export class WebviewHelper {
webview?: Webview;
client?: ServerApi;
private pendingMessages: ChatMessage[] = [];
private pendingRelevantContexts: Context[] = [];
private isChatPageDisplayed = false;
// FIXME: this check is not compatible with the environment of a browser in macOS
private isMac: boolean = env.appHost === "desktop" && process.platform === "darwin";

constructor(
private readonly context: ExtensionContext,
Expand Down Expand Up @@ -283,15 +278,11 @@ export class WebviewHelper {
}
window.addEventListener("message", (event) => {
if (!chatIframe) return
if (event.data) {
if (event.data.action === 'sync-theme') {
syncTheme();
return;
}
if (event.data.data) {
chatIframe.contentWindow.postMessage(event.data.data[0], "*");
if (event.data.action === 'postMessageToChatPanel') {
chatIframe.contentWindow.postMessage(event.data.message, "*");
} else if (event.data.action === 'dispatchKeyboardEvent') {
window.dispatchEvent(new KeyboardEvent(event.data.type, event.data.event));
} else {
vscode.postMessage(event.data);
}
Expand All @@ -318,19 +309,6 @@ export class WebviewHelper {
}
}

public async getFocusKeybinding(): Promise<FocusKeybinding | undefined> {
const focusCommand = "tabby.chatView.focus";
const defaultFocusKey = contributes.keybindings.find((cmd) => cmd.command === focusCommand);
const defaultKeybinding = defaultFocusKey
? parseKeybinding(this.isMac && defaultFocusKey.mac ? defaultFocusKey.mac : defaultFocusKey.key)
: undefined;

const allKeybindings = await readUserKeybindingsConfig();
const userShortcut = allKeybindings?.find((keybinding) => keybinding.command === focusCommand);

return userShortcut ? parseKeybinding(userShortcut.key) : defaultKeybinding;
}

public displayDisconnectedPage() {
if (this.webview) {
this.isChatPageDisplayed = false;
Expand Down Expand Up @@ -396,14 +374,14 @@ export class WebviewHelper {
if (serverInfo.config.token) {
this.client?.cleanError();

const focusKeybinding = await this.getFocusKeybinding();
getLogger().info("focus key binding: ", focusKeybinding);

const isMac = isBrowser
? navigator.userAgent.toLowerCase().includes("mac")
: process.platform.toLowerCase().includes("darwin");
this.client?.init({
fetcherOptions: {
authorization: serverInfo.config.token,
},
focusKey: focusKeybinding,
useMacOSKeyboardEventHandler: isMac,
});
}
}
Expand Down Expand Up @@ -578,12 +556,9 @@ export class WebviewHelper {
onCopy: (content) => {
env.clipboard.writeText(content);
},
focusOnEditor: () => {
const editor = window.activeTextEditor;
if (editor) {
getLogger().info("Focus back to active editor");
commands.executeCommand("workbench.action.focusFirstEditorGroup");
}
onKeyboardEvent: (type: string, event: KeyboardEventInit) => {
this.logger.debug(`Dispatching keyboard event: ${type} ${JSON.stringify(event)}`);
this.webview?.postMessage({ action: "dispatchKeyboardEvent", type, event });
},
});
}
Expand Down
13 changes: 5 additions & 8 deletions clients/vscode/src/chat/chatPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ export function createThreadFromWebview<Self = Record<string, never>, Target = R
) {
return createThread(
{
send(...args) {
webview.postMessage({ data: args });
send(message) {
webview.postMessage({ action: "postMessageToChatPanel", message });
},
listen(listen, { signal }) {
const { dispose } = webview.onDidReceiveMessage((data) => {
listen(data);
});

listen(listener, { signal }) {
const { dispose } = webview.onDidReceiveMessage(listener);
signal?.addEventListener("abort", () => {
dispose();
});
Expand All @@ -34,7 +31,7 @@ export function createClient(webview: Webview, api: ClientApi): ServerApi {
onApplyInEditor: api.onApplyInEditor,
onCopy: api.onCopy,
onLoaded: api.onLoaded,
focusOnEditor: api.focusOnEditor,
onKeyboardEvent: api.onKeyboardEvent,
},
});
}
2 changes: 2 additions & 0 deletions clients/vscode/src/chat/dom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@

// FIXME: This is required by `@quilted/threads` and `tabby-chat-panel`
declare type HTMLIFrameElement = unknown;

declare type KeyboardEventInit = unknown;
1 change: 1 addition & 0 deletions clients/vscode/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isBrowser = !!process.env["IS_BROWSER"];
2 changes: 1 addition & 1 deletion clients/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import { ChatPanelViewProvider } from "./chat/ChatPanelViewProvider";
import { Commands } from "./Commands";
import { Status } from "tabby-agent";
import { CodeActions } from "./CodeActions";
import { isBrowser } from "./env";

const isBrowser = !!process.env["IS_BROWSER"];
const logger = getLogger();
let client: Client | undefined = undefined;

Expand Down
90 changes: 0 additions & 90 deletions clients/vscode/src/util/KeybindingParser.ts

This file was deleted.

Loading

0 comments on commit 8f54ef8

Please sign in to comment.