mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
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:
parent
3c8bac6bf9
commit
7b87b7d7b9
@ -435,6 +435,20 @@ function isDev() {
|
|||||||
return cachedIsDev;
|
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 {
|
export {
|
||||||
PLATFORM,
|
PLATFORM,
|
||||||
WOS,
|
WOS,
|
||||||
@ -451,6 +465,7 @@ export {
|
|||||||
initGlobal,
|
initGlobal,
|
||||||
initWS,
|
initWS,
|
||||||
isDev,
|
isDev,
|
||||||
|
openLink,
|
||||||
sendWSCommand,
|
sendWSCommand,
|
||||||
setBlockFocus,
|
setBlockFocus,
|
||||||
setPlatform,
|
setPlatform,
|
||||||
|
@ -425,7 +425,7 @@ function TableBody({
|
|||||||
{
|
{
|
||||||
label: "Open Preview in New Block",
|
label: "Open Preview in New Block",
|
||||||
click: async () => {
|
click: async () => {
|
||||||
const blockDef = {
|
const blockDef: BlockDef = {
|
||||||
meta: {
|
meta: {
|
||||||
view: "preview",
|
view: "preview",
|
||||||
file: path,
|
file: path,
|
||||||
|
@ -9,14 +9,13 @@ import * as keyutil from "@/util/keyutil";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import * as jotai from "jotai";
|
import * as jotai from "jotai";
|
||||||
|
import "public/xterm.css";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { TermStickers } from "./termsticker";
|
import { TermStickers } from "./termsticker";
|
||||||
import { TermThemeUpdater } from "./termtheme";
|
import { TermThemeUpdater } from "./termtheme";
|
||||||
import { computeTheme } from "./termutil";
|
import { computeTheme } from "./termutil";
|
||||||
import { TermWrap } from "./termwrap";
|
import { TermWrap } from "./termwrap";
|
||||||
|
|
||||||
import "public/xterm.css";
|
|
||||||
|
|
||||||
const keyMap = {
|
const keyMap = {
|
||||||
Enter: "\r",
|
Enter: "\r",
|
||||||
Backspace: "\x7f",
|
Backspace: "\x7f",
|
||||||
@ -248,6 +247,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
keydownHandler: handleTerminalKeydown,
|
keydownHandler: handleTerminalKeydown,
|
||||||
|
useWebGl: !termSettings?.disablewebgl,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
(window as any).term = termWrap;
|
(window as any).term = termWrap;
|
||||||
|
@ -2,15 +2,36 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { WshServer } from "@/app/store/wshserver";
|
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 * as services from "@/store/services";
|
||||||
import { base64ToArray } from "@/util/util";
|
import { base64ToArray, fireAndForget } from "@/util/util";
|
||||||
import { SerializeAddon } from "@xterm/addon-serialize";
|
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 * as TermTypes from "@xterm/xterm";
|
||||||
import { Terminal } from "@xterm/xterm";
|
import { Terminal } from "@xterm/xterm";
|
||||||
import { debounce } from "throttle-debounce";
|
import { debounce } from "throttle-debounce";
|
||||||
import { FitAddon } from "./fitaddon";
|
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 {
|
export class TermWrap {
|
||||||
blockId: string;
|
blockId: string;
|
||||||
ptyOffset: number;
|
ptyOffset: number;
|
||||||
@ -30,7 +51,7 @@ export class TermWrap {
|
|||||||
blockId: string,
|
blockId: string,
|
||||||
connectElem: HTMLDivElement,
|
connectElem: HTMLDivElement,
|
||||||
options: TermTypes.ITerminalOptions & TermTypes.ITerminalInitOnlyOptions,
|
options: TermTypes.ITerminalOptions & TermTypes.ITerminalInitOnlyOptions,
|
||||||
waveOptions: { keydownHandler?: (e: KeyboardEvent) => void }
|
waveOptions: TermWrapOptions
|
||||||
) {
|
) {
|
||||||
this.blockId = blockId;
|
this.blockId = blockId;
|
||||||
this.ptyOffset = 0;
|
this.ptyOffset = 0;
|
||||||
@ -41,6 +62,35 @@ export class TermWrap {
|
|||||||
this.serializeAddon = new SerializeAddon();
|
this.serializeAddon = new SerializeAddon();
|
||||||
this.terminal.loadAddon(this.fitAddon);
|
this.terminal.loadAddon(this.fitAddon);
|
||||||
this.terminal.loadAddon(this.serializeAddon);
|
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.connectElem = connectElem;
|
||||||
this.mainFileSubject = null;
|
this.mainFileSubject = null;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// 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 { WOS, globalStore } from "@/store/global";
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@ -336,7 +336,7 @@ const WebView = memo(({ parentRef, model }: WebViewProps) => {
|
|||||||
webview.addEventListener("new-window", (e: any) => {
|
webview.addEventListener("new-window", (e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const newUrl = e.detail.url;
|
const newUrl = e.detail.url;
|
||||||
getApi().openExternal(newUrl);
|
openLink(newUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Suppress errors
|
// Suppress errors
|
||||||
|
7
frontend/types/gotypes.d.ts
vendored
7
frontend/types/gotypes.d.ts
vendored
@ -323,6 +323,7 @@ declare global {
|
|||||||
autoupdate: AutoUpdateOpts;
|
autoupdate: AutoUpdateOpts;
|
||||||
termthemes: {[key: string]: TermThemeType};
|
termthemes: {[key: string]: TermThemeType};
|
||||||
window: WindowSettingsType;
|
window: WindowSettingsType;
|
||||||
|
web: WebConfigType;
|
||||||
defaultmeta?: MetaType;
|
defaultmeta?: MetaType;
|
||||||
presets?: {[key: string]: MetaType};
|
presets?: {[key: string]: MetaType};
|
||||||
};
|
};
|
||||||
@ -398,6 +399,7 @@ declare global {
|
|||||||
type TerminalConfigType = {
|
type TerminalConfigType = {
|
||||||
fontsize?: number;
|
fontsize?: number;
|
||||||
fontfamily?: string;
|
fontfamily?: string;
|
||||||
|
disablewebgl: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// wstore.UIContext
|
// wstore.UIContext
|
||||||
@ -545,6 +547,11 @@ declare global {
|
|||||||
args: any[];
|
args: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wconfig.WebConfigType
|
||||||
|
type WebConfigType = {
|
||||||
|
openlinksinternally: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
// service.WebReturnType
|
// service.WebReturnType
|
||||||
type WebReturnType = {
|
type WebReturnType = {
|
||||||
success?: boolean;
|
success?: boolean;
|
||||||
|
@ -83,6 +83,8 @@
|
|||||||
"@types/color": "^3.0.6",
|
"@types/color": "^3.0.6",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-serialize": "^0.13.0",
|
"@xterm/addon-serialize": "^0.13.0",
|
||||||
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
|
"@xterm/addon-webgl": "^0.18.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
@ -27,6 +27,11 @@ type WidgetsConfigType struct {
|
|||||||
type TerminalConfigType struct {
|
type TerminalConfigType struct {
|
||||||
FontSize int `json:"fontsize,omitempty"`
|
FontSize int `json:"fontsize,omitempty"`
|
||||||
FontFamily string `json:"fontfamily,omitempty"`
|
FontFamily string `json:"fontfamily,omitempty"`
|
||||||
|
DisableWebGl bool `json:"disablewebgl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebConfigType struct {
|
||||||
|
OpenLinksInternally bool `json:"openlinksinternally"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AiConfigType struct {
|
type AiConfigType struct {
|
||||||
@ -99,6 +104,7 @@ type SettingsConfigType struct {
|
|||||||
AutoUpdate *AutoUpdateOpts `json:"autoupdate"`
|
AutoUpdate *AutoUpdateOpts `json:"autoupdate"`
|
||||||
TermThemes TermThemesConfigType `json:"termthemes"`
|
TermThemes TermThemesConfigType `json:"termthemes"`
|
||||||
WindowSettings WindowSettingsType `json:"window"`
|
WindowSettings WindowSettingsType `json:"window"`
|
||||||
|
Web WebConfigType `json:"web"`
|
||||||
|
|
||||||
DefaultMeta *waveobj.MetaMapType `json:"defaultmeta,omitempty"`
|
DefaultMeta *waveobj.MetaMapType `json:"defaultmeta,omitempty"`
|
||||||
Presets map[string]*waveobj.MetaMapType `json:"presets,omitempty"`
|
Presets map[string]*waveobj.MetaMapType `json:"presets,omitempty"`
|
||||||
|
20
yarn.lock
20
yarn.lock
@ -4570,6 +4570,24 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@xterm/addon-web-links@npm:^0.11.0":
|
||||||
|
version: 0.11.0
|
||||||
|
resolution: "@xterm/addon-web-links@npm:0.11.0"
|
||||||
|
peerDependencies:
|
||||||
|
"@xterm/xterm": ^5.0.0
|
||||||
|
checksum: 10c0/9426bed80afa954b0ea97771d041eb44e77a64e560ce8b8ef507a5d3a763979af18ae9f74ed54007bb7e235d0daf035be2a33f90d8edfecb431caf8ba0b0664e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@xterm/addon-webgl@npm:^0.18.0":
|
||||||
|
version: 0.18.0
|
||||||
|
resolution: "@xterm/addon-webgl@npm:0.18.0"
|
||||||
|
peerDependencies:
|
||||||
|
"@xterm/xterm": ^5.0.0
|
||||||
|
checksum: 10c0/682a3f5f128ee09a0cf1b41cbb7b2f925a5e43056e12ba0c523b93a1f5f188045caef9e31f32db933b8a7a1b12d8f9babaddfa11e6f11df0c7b265009103476c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@xterm/xterm@npm:^5.5.0":
|
"@xterm/xterm@npm:^5.5.0":
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
resolution: "@xterm/xterm@npm:5.5.0"
|
resolution: "@xterm/xterm@npm:5.5.0"
|
||||||
@ -12352,6 +12370,8 @@ __metadata:
|
|||||||
"@vitest/coverage-istanbul": "npm:^2.0.5"
|
"@vitest/coverage-istanbul": "npm:^2.0.5"
|
||||||
"@xterm/addon-fit": "npm:^0.10.0"
|
"@xterm/addon-fit": "npm:^0.10.0"
|
||||||
"@xterm/addon-serialize": "npm:^0.13.0"
|
"@xterm/addon-serialize": "npm:^0.13.0"
|
||||||
|
"@xterm/addon-web-links": "npm:^0.11.0"
|
||||||
|
"@xterm/addon-webgl": "npm:^0.18.0"
|
||||||
"@xterm/xterm": "npm:^5.5.0"
|
"@xterm/xterm": "npm:^5.5.0"
|
||||||
base64-js: "npm:^1.5.1"
|
base64-js: "npm:^1.5.1"
|
||||||
clsx: "npm:^2.1.1"
|
clsx: "npm:^2.1.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user