Add WebGL acceleration and link handling to terminal (#205)

This PR adds back WebGL acceleration (enabled by default) for XTerm. It
also adds back link handling and adds a new option (disabled by default)
to open all links internally as a new web block.

---------

Co-authored-by: sawka <mike.sawka@gmail.com>
This commit is contained in:
Evan Simkowitz
2024-08-07 14:27:16 -07:00
committed by GitHub
co-authored by sawka
parent 3c8bac6bf9
commit 7b87b7d7b9
9 changed files with 110 additions and 10 deletions
+15
View File
@@ -435,6 +435,20 @@ function isDev() {
return cachedIsDev;
}
async function openLink(uri: string) {
if (globalStore.get(atoms.settingsConfigAtom)?.web?.openlinksinternally) {
const blockDef: BlockDef = {
meta: {
view: "web",
url: uri,
},
};
await createBlock(blockDef);
} else {
getApi().openExternal(uri);
}
}
export {
PLATFORM,
WOS,
@@ -451,6 +465,7 @@ export {
initGlobal,
initWS,
isDev,
openLink,
sendWSCommand,
setBlockFocus,
setPlatform,
@@ -425,7 +425,7 @@ function TableBody({
{
label: "Open Preview in New Block",
click: async () => {
const blockDef = {
const blockDef: BlockDef = {
meta: {
view: "preview",
file: path,
+2 -2
View File
@@ -9,14 +9,13 @@ import * as keyutil from "@/util/keyutil";
import clsx from "clsx";
import { produce } from "immer";
import * as jotai from "jotai";
import "public/xterm.css";
import * as React from "react";
import { TermStickers } from "./termsticker";
import { TermThemeUpdater } from "./termtheme";
import { computeTheme } from "./termutil";
import { TermWrap } from "./termwrap";
import "public/xterm.css";
const keyMap = {
Enter: "\r",
Backspace: "\x7f",
@@ -248,6 +247,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
},
{
keydownHandler: handleTerminalKeydown,
useWebGl: !termSettings?.disablewebgl,
}
);
(window as any).term = termWrap;
+53 -3
View File
@@ -2,15 +2,36 @@
// SPDX-License-Identifier: Apache-2.0
import { WshServer } from "@/app/store/wshserver";
import { PLATFORM, fetchWaveFile, getFileSubject, sendWSCommand } from "@/store/global";
import { PLATFORM, fetchWaveFile, getFileSubject, openLink, sendWSCommand } from "@/store/global";
import * as services from "@/store/services";
import { base64ToArray } from "@/util/util";
import { base64ToArray, fireAndForget } from "@/util/util";
import { SerializeAddon } from "@xterm/addon-serialize";
import { WebLinksAddon } from "@xterm/addon-web-links";
import { WebglAddon } from "@xterm/addon-webgl";
import * as TermTypes from "@xterm/xterm";
import { Terminal } from "@xterm/xterm";
import { debounce } from "throttle-debounce";
import { FitAddon } from "./fitaddon";
// detect webgl support
function detectWebGLSupport(): boolean {
try {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("webgl");
return !!ctx;
} catch (e) {
return false;
}
}
const WebGLSupported = detectWebGLSupport();
let loggedWebGL = false;
type TermWrapOptions = {
keydownHandler?: (e: KeyboardEvent) => void;
useWebGl?: boolean;
};
export class TermWrap {
blockId: string;
ptyOffset: number;
@@ -30,7 +51,7 @@ export class TermWrap {
blockId: string,
connectElem: HTMLDivElement,
options: TermTypes.ITerminalOptions & TermTypes.ITerminalInitOnlyOptions,
waveOptions: { keydownHandler?: (e: KeyboardEvent) => void }
waveOptions: TermWrapOptions
) {
this.blockId = blockId;
this.ptyOffset = 0;
@@ -41,6 +62,35 @@ export class TermWrap {
this.serializeAddon = new SerializeAddon();
this.terminal.loadAddon(this.fitAddon);
this.terminal.loadAddon(this.serializeAddon);
this.terminal.loadAddon(
new WebLinksAddon((e, uri) => {
e.preventDefault();
switch (PLATFORM) {
case "darwin":
if (e.metaKey) {
fireAndForget(() => openLink(uri));
}
break;
default:
if (e.ctrlKey) {
fireAndForget(() => openLink(uri));
}
break;
}
})
);
if (WebGLSupported && waveOptions.useWebGl) {
const webglAddon = new WebglAddon();
webglAddon.onContextLoss(() => {
webglAddon.dispose();
});
this.terminal.loadAddon(webglAddon);
if (!loggedWebGL) {
console.log("loaded webgl!");
loggedWebGL = true;
}
}
this.connectElem = connectElem;
this.mainFileSubject = null;
this.loaded = false;
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { getApi } from "@/app/store/global";
import { openLink } from "@/app/store/global";
import { WOS, globalStore } from "@/store/global";
import * as services from "@/store/services";
import clsx from "clsx";
@@ -336,7 +336,7 @@ const WebView = memo(({ parentRef, model }: WebViewProps) => {
webview.addEventListener("new-window", (e: any) => {
e.preventDefault();
const newUrl = e.detail.url;
getApi().openExternal(newUrl);
openLink(newUrl);
});
// Suppress errors