fix(tui): guarded hyperlinks before settings init
Return plain text from hyperlink helpers until Settings.init() has completed so image paste placeholders cannot crash early editor renders. Fixes #3064
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed image paste placeholders falling through to terminal hyperlink settings before `Settings.init()`, so early editor rendering falls back to plain text instead of crashing. ([#3064](https://github.com/can1357/oh-my-pi/issues/3064))
|
||||
|
||||
## [16.1.3] - 2026-06-19
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
import * as url from "node:url";
|
||||
import { TERMINAL } from "@oh-my-pi/pi-tui";
|
||||
import { settings } from "../config/settings";
|
||||
import { isSettingsInitialized, settings } from "../config/settings";
|
||||
import {
|
||||
LocalProtocolHandler,
|
||||
memoryRootsFromRegistry,
|
||||
@@ -45,8 +45,10 @@ function buildFileUri(filePath: string, opts?: { line?: number; col?: number }):
|
||||
* - `"off"`: never
|
||||
* - `"auto"`: when `process.stdout.isTTY`, `NO_COLOR` is unset, and the detected terminal reports hyperlink support
|
||||
* - `"always"`: unconditionally (useful for viewers that support OSC 8 without advertising it)
|
||||
* Before settings initialization, returns false so early render paths stay plain text.
|
||||
*/
|
||||
export function isHyperlinkEnabled(): boolean {
|
||||
if (!isSettingsInitialized()) return false;
|
||||
const mode = settings.get("tui.hyperlinks");
|
||||
if (mode === "off") return false;
|
||||
if (mode === "always") return true;
|
||||
@@ -104,10 +106,11 @@ export function urlHyperlink(url: string, displayText: string): string {
|
||||
* Wrap `displayText` in an OSC 8 hyperlink pointing at an HTTP(S) URL,
|
||||
* bypassing terminal capability auto-detection. Used for auth prompts where
|
||||
* an inert "click" label blocks login on terminals whose capabilities are
|
||||
* not advertised. Still returns plain text when the user has explicitly
|
||||
* opted out via `tui.hyperlinks=off`.
|
||||
* not advertised. Still returns plain text before settings initialization or
|
||||
* when the user has explicitly opted out via `tui.hyperlinks=off`.
|
||||
*/
|
||||
export function urlHyperlinkAlways(url: string, displayText: string): string {
|
||||
if (!isSettingsInitialized()) return displayText;
|
||||
if (settings.get("tui.hyperlinks") === "off") return displayText;
|
||||
const normalized = url.match(/^www\./i) ? `https://${url}` : url;
|
||||
try {
|
||||
|
||||
@@ -60,6 +60,17 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("isHyperlinkEnabled", () => {
|
||||
it("falls back to plain text before Settings.init", async () => {
|
||||
resetSettingsForTest();
|
||||
try {
|
||||
expect(isHyperlinkEnabled()).toBe(false);
|
||||
expect(fileHyperlink(path.resolve("/Users/foo/bar.ts"), "bar.ts")).toBe("bar.ts");
|
||||
expect(urlHyperlinkAlways("https://example.com/path", "example")).toBe("example");
|
||||
} finally {
|
||||
await Settings.init({ inMemory: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('returns false when mode is "off"', () => {
|
||||
setHyperlinkMode("off");
|
||||
expect(isHyperlinkEnabled()).toBe(false);
|
||||
|
||||
Reference in New Issue
Block a user