Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/web/src/components/ThreadTerminalDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
} from "~/terminal/ghostty/surface";
import { type GhosttyColor, type GhosttyTheme } from "~/terminal/ghostty/core";
import { useOpenInPreferredEditor } from "../editorPreferences";
import { isTerminalLinkActivation, resolvePathLinkTarget } from "../terminal-links";
import { isTerminalLinkActivation, isTerminalUrl, resolvePathLinkTarget } from "../terminal-links";
import {
isDiffToggleShortcut,
isTerminalClearShortcut,
Expand Down Expand Up @@ -749,7 +749,7 @@ export function TerminalViewport({
if (!isTerminalLinkActivation(event)) return;
const latestTerminal = terminalRef.current;
if (!latestTerminal) return;
if (/^https?:\/\//u.test(text)) {
if (isTerminalUrl(text)) {
if (!localApi) {
writeSystemMessage(latestTerminal, "Opening links is unavailable in this browser.");
return;
Expand Down
19 changes: 19 additions & 0 deletions apps/web/src/terminal-links.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
collectWrappedTerminalLinkLine,
extractTerminalLinks,
isTerminalLinkActivation,
isTerminalUrl,
resolvePathLinkTarget,
resolveWrappedTerminalLinkRange,
wrappedTerminalLinkRangeIntersectsBufferLine,
Expand Down Expand Up @@ -37,6 +38,24 @@ describe("extractTerminalLinks", () => {
]);
});

it("classifies uppercase schemes as URLs at activation time too", () => {
expect(isTerminalUrl("HTTPS://example.com/docs")).toBe(true);
expect(isTerminalUrl("Http://example.com")).toBe(true);
expect(isTerminalUrl("src/components/main.ts")).toBe(false);
expect(isTerminalUrl("httpsdocs/readme.md")).toBe(false);
});

it("finds URLs regardless of scheme casing", () => {
expect(extractTerminalLinks("open HTTPS://example.com/docs")).toEqual([
{
kind: "url",
text: "HTTPS://example.com/docs",
start: 5,
end: 29,
},
]);
});

it("trims trailing punctuation from links", () => {
const line = "(https://example.com/docs), ./src/main.ts:12.";
expect(extractTerminalLinks(line)).toEqual([
Expand Down
8 changes: 6 additions & 2 deletions apps/web/src/terminal-links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface WrappedTerminalLinkLine {
segments: ReadonlyArray<WrappedTerminalLinkLineSegment>;
}

const URL_PATTERN = /https?:\/\/[^\s"'`<>]+/g;
const URL_PATTERN = /https?:\/\/[^\s"'`<>]+/giu;
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Comment thread
flamboh marked this conversation as resolved.
Outdated
const FILE_PATH_PATTERN =
/(?:~\/|\.{1,2}\/|\/|[A-Za-z]:[\\/]|\\\\)[^\s"'`<>]+|[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)+(?::\d+){0,2}/g;
const TRAILING_PUNCTUATION_PATTERN = /[.,;!?]+$/;
Expand Down Expand Up @@ -80,7 +80,7 @@ function collectMatches(

const trimmed = trimClosingDelimiters(raw);
if (trimmed.length === 0) continue;
if (kind === "path" && /^https?:\/\//i.test(trimmed)) continue;
if (kind === "path" && isTerminalUrl(trimmed)) continue;

const candidate: TerminalLinkMatch = {
kind,
Expand Down Expand Up @@ -172,6 +172,10 @@ export function extractTerminalLinks(line: string): TerminalLinkMatch[] {
return [...urlMatches, ...pathMatches].toSorted((a, b) => a.start - b.start);
}

export function isTerminalUrl(value: string): boolean {
return /^https?:\/\//iu.test(value);
}

export function collectWrappedTerminalLinkLine(
bufferLineNumber: number,
getLine: (bufferLineIndex: number) => TerminalBufferLineLike | null | undefined,
Expand Down
8 changes: 0 additions & 8 deletions apps/web/src/terminal/ghostty/surface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
resolveTerminalMouseTrackingState,
shouldBlinkTerminalCursor,
shouldReportTerminalMouse,
shouldShowTerminalLinkHover,
terminalGridCellAt,
Comment thread
flamboh marked this conversation as resolved.
Outdated
terminalScrollbarGeometry,
terminalScrollbarOffsetAtPointer,
Expand Down Expand Up @@ -438,13 +437,6 @@ describe("application mouse reporting", () => {
motionData: "\u001b[<35;8;4M",
});
});

it("only shows link hover during mouse tracking when the link modifier is held", () => {
expect(shouldShowTerminalLinkHover(false, false)).toBe(true);
expect(shouldShowTerminalLinkHover(false, true)).toBe(true);
expect(shouldShowTerminalLinkHover(true, false)).toBe(false);
expect(shouldShowTerminalLinkHover(true, true)).toBe(true);
});
});

describe("terminal font resolution", () => {
Expand Down
12 changes: 1 addition & 11 deletions apps/web/src/terminal/ghostty/surface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,13 +483,6 @@ export function isTerminalLinkPointerGesture(
: event.ctrlKey && !event.metaKey;
}

export function shouldShowTerminalLinkHover(
mouseTracking: boolean,
linkModifierActive: boolean,
): boolean {
return !mouseTracking || linkModifierActive;
}

export function ghosttyMouseButton(button: number): number | null {
switch (button) {
case 0:
Expand Down Expand Up @@ -1409,10 +1402,7 @@ export class GhosttyTerminalSurface {

private refreshHoveredLink(): void {
const pointer = this.hoverPointer;
const link =
pointer && shouldShowTerminalLinkHover(this.core.isMouseTracking(), this.linkModifierActive)
? this.linkAt(pointer.x, pointer.y)
: null;
const link = pointer && this.linkModifierActive ? this.linkAt(pointer.x, pointer.y) : null;
this.setHoveredLink(link);
}

Expand Down
Loading