mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(coding-agent): defer uncommon syntax grammars
This commit is contained in:
parent
39d869f02a
commit
cec3a91c02
6 changed files with 162 additions and 21 deletions
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
### Changed
|
||||
|
||||
- Changed syntax highlighting to initialize only twenty common languages eagerly and defer the remaining grammars until after the initial TUI render, reducing CLI startup time.
|
||||
- Changed the Node.js CLI and RPC entrypoints to load a bundled runtime, reducing startup filesystem reads while keeping the public library and legacy module paths on the modular runtime for normal dependency identity.
|
||||
- Changed session sharing to render clickable terminal links and Radius shares to display only the artifact's canonical URL.
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ import { openBrowser } from "../../utils/open-browser.ts";
|
|||
import { getCwdRelativePath } from "../../utils/paths.ts";
|
||||
import { getPiUserAgent } from "../../utils/pi-user-agent.ts";
|
||||
import { killTrackedDetachedChildren } from "../../utils/shell.ts";
|
||||
import { loadAllHighlightLanguages } from "../../utils/syntax-highlight.ts";
|
||||
import { ensureTool, type ToolStatus } from "../../utils/tools-manager.ts";
|
||||
import { checkForNewPiVersion, type LatestPiRelease } from "../../utils/version-check.ts";
|
||||
import { ArminComponent } from "./components/armin.ts";
|
||||
|
|
@ -1051,6 +1052,14 @@ export class InteractiveMode {
|
|||
|
||||
// Initialize available provider count for footer display
|
||||
await this.updateAvailableProviderCount();
|
||||
|
||||
// Flush the completed startup state before loading the remaining syntax grammars.
|
||||
this.ui.renderNow();
|
||||
void loadAllHighlightLanguages().then(() => {
|
||||
if (!this.isInitialized) return;
|
||||
this.ui.invalidate();
|
||||
this.ui.requestRender();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
declare module "highlight.js/lib/index.js" {
|
||||
interface HighlightResult {
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface HighlightOptions {
|
||||
language: string;
|
||||
ignoreIllegals?: boolean;
|
||||
}
|
||||
|
||||
interface HighlightJs {
|
||||
highlight(code: string, options: HighlightOptions): HighlightResult;
|
||||
highlightAuto(code: string, languageSubset?: string[]): HighlightResult;
|
||||
getLanguage(name: string): unknown;
|
||||
}
|
||||
|
||||
const hljs: HighlightJs;
|
||||
export default hljs;
|
||||
}
|
||||
36
packages/coding-agent/src/utils/highlight-js.d.ts
vendored
Normal file
36
packages/coding-agent/src/utils/highlight-js.d.ts
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
interface HighlightJsResult {
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface HighlightJsOptions {
|
||||
language: string;
|
||||
ignoreIllegals?: boolean;
|
||||
}
|
||||
|
||||
interface HighlightJsLanguageDefinition {
|
||||
readonly name?: string;
|
||||
}
|
||||
|
||||
type HighlightJsLanguageFactory = (hljs: HighlightJsApi) => HighlightJsLanguageDefinition;
|
||||
|
||||
interface HighlightJsApi {
|
||||
highlight(code: string, options: HighlightJsOptions): HighlightJsResult;
|
||||
highlightAuto(code: string, languageSubset?: string[]): HighlightJsResult;
|
||||
getLanguage(name: string): HighlightJsLanguageDefinition | undefined;
|
||||
registerLanguage(name: string, language: HighlightJsLanguageFactory): void;
|
||||
}
|
||||
|
||||
declare module "highlight.js/lib/core.js" {
|
||||
const hljs: HighlightJsApi;
|
||||
export default hljs;
|
||||
}
|
||||
|
||||
declare module "highlight.js/lib/index.js" {
|
||||
const hljs: HighlightJsApi;
|
||||
export default hljs;
|
||||
}
|
||||
|
||||
declare module "highlight.js/lib/languages/*.js" {
|
||||
const language: HighlightJsLanguageFactory;
|
||||
export default language;
|
||||
}
|
||||
|
|
@ -1,6 +1,83 @@
|
|||
import hljs from "highlight.js/lib/index.js";
|
||||
import { createRequire } from "node:module";
|
||||
import hljs from "highlight.js/lib/core.js";
|
||||
import bash from "highlight.js/lib/languages/bash.js";
|
||||
import c from "highlight.js/lib/languages/c.js";
|
||||
import cpp from "highlight.js/lib/languages/cpp.js";
|
||||
import csharp from "highlight.js/lib/languages/csharp.js";
|
||||
import dart from "highlight.js/lib/languages/dart.js";
|
||||
import go from "highlight.js/lib/languages/go.js";
|
||||
import groovy from "highlight.js/lib/languages/groovy.js";
|
||||
import java from "highlight.js/lib/languages/java.js";
|
||||
import javascript from "highlight.js/lib/languages/javascript.js";
|
||||
import kotlin from "highlight.js/lib/languages/kotlin.js";
|
||||
import lua from "highlight.js/lib/languages/lua.js";
|
||||
import nix from "highlight.js/lib/languages/nix.js";
|
||||
import perl from "highlight.js/lib/languages/perl.js";
|
||||
import php from "highlight.js/lib/languages/php.js";
|
||||
import python from "highlight.js/lib/languages/python.js";
|
||||
import ruby from "highlight.js/lib/languages/ruby.js";
|
||||
import rust from "highlight.js/lib/languages/rust.js";
|
||||
import scala from "highlight.js/lib/languages/scala.js";
|
||||
import swift from "highlight.js/lib/languages/swift.js";
|
||||
import typescript from "highlight.js/lib/languages/typescript.js";
|
||||
import { decodeHtmlEntityAt } from "./html.ts";
|
||||
|
||||
const moduleRequire = createRequire(import.meta.url);
|
||||
declare const PI_BUNDLED_NODE: boolean;
|
||||
declare const Bun: unknown;
|
||||
declare const require: (specifier: string) => unknown;
|
||||
|
||||
const eagerLanguages = {
|
||||
python,
|
||||
java,
|
||||
go,
|
||||
javascript,
|
||||
cpp,
|
||||
typescript,
|
||||
php,
|
||||
ruby,
|
||||
c,
|
||||
csharp,
|
||||
nix,
|
||||
bash,
|
||||
rust,
|
||||
scala,
|
||||
kotlin,
|
||||
swift,
|
||||
dart,
|
||||
groovy,
|
||||
perl,
|
||||
lua,
|
||||
};
|
||||
|
||||
for (const [name, language] of Object.entries(eagerLanguages)) {
|
||||
hljs.registerLanguage(name, language);
|
||||
}
|
||||
|
||||
let allLanguagesPromise: Promise<void> | undefined;
|
||||
|
||||
export function loadAllHighlightLanguages(): Promise<void> {
|
||||
if (!allLanguagesPromise) {
|
||||
allLanguagesPromise = new Promise((resolve) => {
|
||||
setImmediate(() => {
|
||||
try {
|
||||
// Static require lets esbuild and Bun include this deferred module in
|
||||
// standalone bundles. Source and unbundled Node runtimes need createRequire.
|
||||
if ((typeof PI_BUNDLED_NODE !== "undefined" && PI_BUNDLED_NODE) || typeof Bun !== "undefined") {
|
||||
require("highlight.js/lib/index.js");
|
||||
} else {
|
||||
moduleRequire("highlight.js/lib/index.js");
|
||||
}
|
||||
} catch {
|
||||
// Eager languages and plaintext fallback remain available.
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
return allLanguagesPromise;
|
||||
}
|
||||
|
||||
export type HighlightFormatter = (text: string) => string;
|
||||
export type HighlightTheme = Partial<Record<string, HighlightFormatter>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,46 @@
|
|||
import { resetCapabilitiesCache, setCapabilities } from "@earendil-works/pi-tui";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { highlightCode, initTheme } from "../src/modes/interactive/theme/theme.ts";
|
||||
import { highlight, renderHighlightedHtml, supportsLanguage } from "../src/utils/syntax-highlight.ts";
|
||||
import {
|
||||
highlight,
|
||||
loadAllHighlightLanguages,
|
||||
renderHighlightedHtml,
|
||||
supportsLanguage,
|
||||
} from "../src/utils/syntax-highlight.ts";
|
||||
|
||||
const eagerLanguages = [
|
||||
"python",
|
||||
"java",
|
||||
"go",
|
||||
"javascript",
|
||||
"cpp",
|
||||
"typescript",
|
||||
"php",
|
||||
"ruby",
|
||||
"c",
|
||||
"csharp",
|
||||
"nix",
|
||||
"bash",
|
||||
"rust",
|
||||
"scala",
|
||||
"kotlin",
|
||||
"swift",
|
||||
"dart",
|
||||
"groovy",
|
||||
"perl",
|
||||
"lua",
|
||||
];
|
||||
const eagerLanguagesLoadedAtStartup = eagerLanguages.every(supportsLanguage);
|
||||
const uncommonLanguageLoadedAtStartup = supportsLanguage("ada");
|
||||
|
||||
describe("syntax highlight renderer", () => {
|
||||
it("loads the twenty most common languages at startup and defers the rest", async () => {
|
||||
expect(eagerLanguagesLoadedAtStartup).toBe(true);
|
||||
expect(uncommonLanguageLoadedAtStartup).toBe(false);
|
||||
await loadAllHighlightLanguages();
|
||||
expect(supportsLanguage("ada")).toBe(true);
|
||||
});
|
||||
|
||||
it("renders highlighted spans with the provided theme", () => {
|
||||
const rendered = renderHighlightedHtml('<span class="hljs-keyword">const</span> value', {
|
||||
keyword: (text) => `[keyword:${text}]`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue