diff --git a/package.json b/package.json index 6d08bb8f55..9e88238fa7 100644 --- a/package.json +++ b/package.json @@ -282,7 +282,8 @@ "winston": "^3.8.1", "winston-console-format": "^1.0.8", "winston-transport-browserconsole": "^1.0.5", - "ws": "^8.8.1" + "ws": "^8.8.1", + "xterm-link-provider": "^1.3.1" }, "devDependencies": { "@async-fn/jest": "1.6.4", diff --git a/src/renderer/components/dock/terminal/create-terminal.injectable.ts b/src/renderer/components/dock/terminal/create-terminal.injectable.ts index a4df656247..878d88f091 100644 --- a/src/renderer/components/dock/terminal/create-terminal.injectable.ts +++ b/src/renderer/components/dock/terminal/create-terminal.injectable.ts @@ -11,6 +11,8 @@ import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable" import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable"; import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable"; import themeStoreInjectable from "../../../themes/store.injectable"; +import isMacInjectable from "../../../../common/vars/is-mac.injectable"; +import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable"; export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal; @@ -22,6 +24,8 @@ const createTerminalInjectable = getInjectable({ terminalConfig: di.inject(terminalConfigInjectable), terminalCopyOnSelect: di.inject(terminalCopyOnSelectInjectable), themeStore: di.inject(themeStoreInjectable), + isMac: di.inject(isMacInjectable), + openLinkInBrowser: di.inject(openLinkInBrowserInjectable), }; return (tabId, api) => new Terminal(dependencies, { tabId, api }); diff --git a/src/renderer/components/dock/terminal/terminal.ts b/src/renderer/components/dock/terminal/terminal.ts index 1415a643dd..cf89a572c1 100644 --- a/src/renderer/components/dock/terminal/terminal.ts +++ b/src/renderer/components/dock/terminal/terminal.ts @@ -12,19 +12,22 @@ import type { TabId } from "../dock/store"; import type { TerminalApi } from "../../../api/terminal-api"; import type { ThemeStore } from "../../../themes/store"; import { disposer } from "../../../utils"; -import { isMac } from "../../../../common/vars"; import { once } from "lodash"; import { clipboard } from "electron"; import logger from "../../../../common/logger"; import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; import assert from "assert"; import { TerminalChannels } from "../../../../common/terminal/channels"; +import { LinkProvider } from "xterm-link-provider"; +import type { OpenLinkInBrowser } from "../../../../common/utils/open-link-in-browser.injectable"; export interface TerminalDependencies { readonly spawningPool: HTMLElement; readonly terminalConfig: IComputedValue; readonly terminalCopyOnSelect: IComputedValue; readonly themeStore: ThemeStore; + readonly isMac: boolean; + openLinkInBrowser: OpenLinkInBrowser; } export interface TerminalArguments { @@ -93,7 +96,6 @@ export class Terminal { this.xterm.loadAddon(this.fitAddon); this.xterm.open(this.dependencies.spawningPool); - this.xterm.registerLinkMatcher(/https?:\/\/[^\s]+/i, this.onClickLink); this.xterm.attachCustomKeyEventHandler(this.keyHandler); this.xterm.onSelectionChange(this.onSelectionChange); @@ -108,7 +110,16 @@ export class Terminal { this.api.on("data", this.onApiData); window.addEventListener("resize", this.onResize); + const linkProvider = new LinkProvider( + this.xterm, + /https?:\/\/[^\s]+/i, + (event, link) => this.dependencies.openLinkInBrowser(link), + undefined, + 0, + ); + this.disposer.push( + this.xterm.registerLinkProvider(linkProvider), reaction(() => this.theme, colors => this.xterm.setOption("theme", colors), { fireImmediately: true, }), @@ -169,10 +180,6 @@ export class Terminal { this.viewport.scrollTop = this.scrollPos; // restore last scroll position }; - onClickLink = (evt: MouseEvent, link: string) => { - window.open(link, "_blank"); - }; - onContextMenu = () => { if ( // don't paste if user hasn't turned on the feature @@ -229,7 +236,7 @@ export class Terminal { } //Ctrl+K: clear the entire buffer, making the prompt line the new first line on mac os - if (isMac && metaKey) { + if (this.dependencies.isMac && metaKey) { switch (code) { case "KeyK": this.onClear(); diff --git a/yarn.lock b/yarn.lock index 4b79090cd6..87109d013e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13699,7 +13699,14 @@ xterm-addon-fit@^0.5.0: resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596" integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ== -xterm@^4.19.0: +xterm-link-provider@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/xterm-link-provider/-/xterm-link-provider-1.3.1.tgz#69727223220dfa8758056ad6b2b5394a8454b9cb" + integrity sha512-uOlaIeUED6kJeL2nIIf5YwreO0obMhsC0RWypEUmWkz7SAQewzgwdWFjQ2He7NGcT93c4KUf8bRgAu8cV9bAYA== + dependencies: + xterm "^4.6.0" + +xterm@^4.19.0, xterm@^4.6.0: version "4.19.0" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==