mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-19 07:42:52 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
457ddad8cc | ||
|
|
bb5c1ffbbc |
@@ -0,0 +1,88 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { highlightCode } from "@getpaseo/highlight";
|
||||
import { buildNativeSourceLines } from "./native-lines";
|
||||
|
||||
const records = Array.from({ length: 900 }, (_, i) => ({
|
||||
t: `comment number ${i} with some text`,
|
||||
l: i % 7,
|
||||
r: i % 3,
|
||||
u: `user${i}`,
|
||||
}));
|
||||
|
||||
describe("native source lines", () => {
|
||||
it("opens the reported single-line JSON without thousands of native text spans", () => {
|
||||
const content = JSON.stringify(records);
|
||||
expect(new TextEncoder().encode(content)).toHaveLength(60981);
|
||||
expect(highlightCode(content, "one-line-repro.json")[0]).toHaveLength(14401);
|
||||
const lines = buildNativeSourceLines({
|
||||
content,
|
||||
filename: "one-line-repro.json",
|
||||
presentation: "highlighted",
|
||||
});
|
||||
expect(lines).toEqual([{ number: 1, tokens: [{ text: content, style: null }] }]);
|
||||
});
|
||||
|
||||
it("keeps the pretty-printed control highlighted and preserves its line numbers", () => {
|
||||
const content = JSON.stringify(records, null, 2);
|
||||
const lines = buildNativeSourceLines({
|
||||
content,
|
||||
filename: "pretty-repro.json",
|
||||
presentation: "highlighted",
|
||||
});
|
||||
expect(lines).toHaveLength(5402);
|
||||
expect(lines.map((line) => line.tokens)).toEqual(highlightCode(content, "pretty-repro.json"));
|
||||
expect(lines.at(-1)?.number).toBe(5402);
|
||||
expect(lines.flatMap((line) => line.tokens).some((token) => token.style !== null)).toBe(true);
|
||||
expect(lines.map(lineText).join("\n")).toBe(content);
|
||||
});
|
||||
it("falls back only for dense rows, without changing text or line numbering", () => {
|
||||
const dense = `${JSON.stringify(Array.from({ length: 25 }, (_, i) => i))} `;
|
||||
const content = `${dense}\n{"ok":true}\n`;
|
||||
const original = highlightCode(content, "data.json");
|
||||
expect(original[0]).toHaveLength(52);
|
||||
const lines = buildNativeSourceLines({
|
||||
content,
|
||||
filename: "data.json",
|
||||
presentation: "highlighted",
|
||||
});
|
||||
expect(lines).toEqual([
|
||||
{ number: 1, tokens: [{ text: dense, style: null }] },
|
||||
{ number: 2, tokens: original[1] },
|
||||
{ number: 3, tokens: original[2] },
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps a row at the span budget highlighted", () => {
|
||||
const content = JSON.stringify(Array.from({ length: 25 }, (_, i) => i));
|
||||
const original = highlightCode(content, "data.json");
|
||||
expect(original[0]).toHaveLength(51);
|
||||
expect(
|
||||
buildNativeSourceLines({ content, filename: "data.json", presentation: "highlighted" }),
|
||||
).toEqual([{ number: 1, tokens: original[0] }]);
|
||||
});
|
||||
|
||||
it("keeps ordinary TypeScript statements within the span budget highlighted", () => {
|
||||
const content =
|
||||
'const values = [{ id: 0, name: "item0" }, { id: 1, name: "item1" }, { id: 2, name: "item2" }];';
|
||||
const original = highlightCode(content, "ordinary.ts");
|
||||
expect(original[0]).toHaveLength(50);
|
||||
expect(
|
||||
buildNativeSourceLines({ content, filename: "ordinary.ts", presentation: "highlighted" }),
|
||||
).toEqual([{ number: 1, tokens: original[0] }]);
|
||||
});
|
||||
|
||||
it("keeps the plain tier and unknown languages lossless", () => {
|
||||
for (const presentation of ["highlighted", "plain"] as const) {
|
||||
const content = "hello\r\n\nworld\n";
|
||||
expect(buildNativeSourceLines({ content, filename: "data.unknown", presentation })).toEqual(
|
||||
content
|
||||
.split("\n")
|
||||
.map((text, index) => ({ number: index + 1, tokens: [{ text, style: null }] })),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function lineText(line: { tokens: { text: string }[] }): string {
|
||||
return line.tokens.map((token) => token.text).join("");
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { highlightCode, type HighlightToken } from "@getpaseo/highlight";
|
||||
|
||||
// Android has 256 span-priority slots (indices 0–255). Each colored source
|
||||
// token produces five operations: color, size, font family, line height and
|
||||
// tag. 51 tokens use 255 operations; the 52nd exceeds the priority limit.
|
||||
const MAX_HIGHLIGHTED_TOKENS_PER_LINE = 51;
|
||||
|
||||
export interface SourceLine {
|
||||
number: number;
|
||||
tokens: HighlightToken[];
|
||||
}
|
||||
|
||||
export function buildNativeSourceLines(input: {
|
||||
content: string;
|
||||
filename: string;
|
||||
presentation: "highlighted" | "plain";
|
||||
}): SourceLine[] {
|
||||
const lines =
|
||||
input.presentation === "highlighted"
|
||||
? highlightCode(input.content, input.filename)
|
||||
: input.content.split("\n").map((text) => [{ text, style: null }]);
|
||||
return lines.map((tokens, index) => ({
|
||||
number: index + 1,
|
||||
tokens:
|
||||
tokens.length <= MAX_HIGHLIGHTED_TOKENS_PER_LINE
|
||||
? tokens
|
||||
: [{ text: tokens.map((token) => token.text).join(""), style: null }],
|
||||
}));
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { FlatList, Text, View, type ListRenderItem } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { highlightCode, type HighlightToken } from "@getpaseo/highlight";
|
||||
import { buildNativeSourceLines, type SourceLine } from "./native-lines";
|
||||
import { syntaxTokenStyleFor } from "@/styles/syntax-token-styles";
|
||||
import type { WorkspaceFileLocation } from "@/workspace/file-open";
|
||||
import type { EditorVisualTheme } from "../editor/extensions.web";
|
||||
@@ -17,11 +17,6 @@ interface FileSourceViewProps {
|
||||
tooLargeMessage: string;
|
||||
}
|
||||
|
||||
interface SourceLine {
|
||||
number: number;
|
||||
tokens: HighlightToken[];
|
||||
}
|
||||
|
||||
export function FileSourceView({
|
||||
content,
|
||||
filename,
|
||||
@@ -59,16 +54,10 @@ function VirtualizedSource({
|
||||
presentation: "highlighted" | "plain";
|
||||
}) {
|
||||
const listRef = useRef<FlatList<SourceLine>>(null);
|
||||
const lines = useMemo(() => {
|
||||
if (presentation === "highlighted")
|
||||
return highlightCode(content, filename).map((tokens, index) => ({
|
||||
number: index + 1,
|
||||
tokens,
|
||||
}));
|
||||
return content
|
||||
.split("\n")
|
||||
.map((text, index) => ({ number: index + 1, tokens: [{ text, style: null }] }));
|
||||
}, [content, filename, presentation]);
|
||||
const lines = useMemo(
|
||||
() => buildNativeSourceLines({ content, filename, presentation }),
|
||||
[content, filename, presentation],
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!location.lineStart) return;
|
||||
listRef.current?.scrollToIndex({
|
||||
|
||||
Reference in New Issue
Block a user