diff --git a/package-lock.json b/package-lock.json
index f8f1be757..186649dac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7186,6 +7186,17 @@
"integrity": "sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==",
"license": "MIT"
},
+ "node_modules/@lezer/cpp": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.5.tgz",
+ "integrity": "sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
"node_modules/@lezer/css": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.1.tgz",
@@ -7197,6 +7208,17 @@
"@lezer/lr": "^1.3.0"
}
},
+ "node_modules/@lezer/go": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz",
+ "integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
"node_modules/@lezer/highlight": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
@@ -7217,6 +7239,17 @@
"@lezer/lr": "^1.0.0"
}
},
+ "node_modules/@lezer/java": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz",
+ "integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
"node_modules/@lezer/javascript": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
@@ -7258,6 +7291,17 @@
"@lezer/highlight": "^1.0.0"
}
},
+ "node_modules/@lezer/php": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.5.tgz",
+ "integrity": "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.1.0"
+ }
+ },
"node_modules/@lezer/python": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz",
@@ -7269,6 +7313,39 @@
"@lezer/lr": "^1.0.0"
}
},
+ "node_modules/@lezer/rust": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz",
+ "integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/xml": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz",
+ "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/yaml": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.4.tgz",
+ "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.4.0"
+ }
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz",
@@ -31462,13 +31539,20 @@
"@gorhom/bottom-sheet": "^5.2.6",
"@gorhom/portal": "^1.0.14",
"@lezer/common": "^1.5.0",
+ "@lezer/cpp": "^1.1.5",
"@lezer/css": "^1.3.0",
+ "@lezer/go": "^1.0.1",
"@lezer/highlight": "^1.2.3",
"@lezer/html": "^1.3.13",
+ "@lezer/java": "^1.1.3",
"@lezer/javascript": "^1.5.4",
"@lezer/json": "^1.0.3",
"@lezer/markdown": "^1.6.2",
+ "@lezer/php": "^1.0.5",
"@lezer/python": "^1.1.18",
+ "@lezer/rust": "^1.0.2",
+ "@lezer/xml": "^1.0.6",
+ "@lezer/yaml": "^1.0.4",
"@react-native-async-storage/async-storage": "2.2.0",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-native/normalize-colors": "^0.81.5",
@@ -31684,13 +31768,20 @@
"@deepgram/sdk": "^3.4.0",
"@getpaseo/relay": "0.1.30",
"@lezer/common": "^1.5.0",
+ "@lezer/cpp": "^1.1.5",
"@lezer/css": "^1.3.0",
+ "@lezer/go": "^1.0.1",
"@lezer/highlight": "^1.2.3",
"@lezer/html": "^1.3.13",
+ "@lezer/java": "^1.1.3",
"@lezer/javascript": "^1.5.4",
"@lezer/json": "^1.0.3",
"@lezer/markdown": "^1.6.2",
+ "@lezer/php": "^1.0.5",
"@lezer/python": "^1.1.18",
+ "@lezer/rust": "^1.0.2",
+ "@lezer/xml": "^1.0.6",
+ "@lezer/yaml": "^1.0.4",
"@modelcontextprotocol/sdk": "^1.20.1",
"@opencode-ai/sdk": "1.2.6",
"@sctg/sentencepiece-js": "^1.1.0",
diff --git a/packages/app/package.json b/packages/app/package.json
index 482d88b30..39c119780 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -38,13 +38,20 @@
"@gorhom/bottom-sheet": "^5.2.6",
"@gorhom/portal": "^1.0.14",
"@lezer/common": "^1.5.0",
+ "@lezer/cpp": "^1.1.5",
"@lezer/css": "^1.3.0",
+ "@lezer/go": "^1.0.1",
"@lezer/highlight": "^1.2.3",
"@lezer/html": "^1.3.13",
+ "@lezer/java": "^1.1.3",
"@lezer/javascript": "^1.5.4",
"@lezer/json": "^1.0.3",
"@lezer/markdown": "^1.6.2",
+ "@lezer/php": "^1.0.5",
"@lezer/python": "^1.1.18",
+ "@lezer/rust": "^1.0.2",
+ "@lezer/xml": "^1.0.6",
+ "@lezer/yaml": "^1.0.4",
"@react-native-async-storage/async-storage": "2.2.0",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-native/normalize-colors": "^0.81.5",
diff --git a/packages/app/src/utils/diff-highlighter.test.ts b/packages/app/src/utils/diff-highlighter.test.ts
index 30fa3a816..10e52cf74 100644
--- a/packages/app/src/utils/diff-highlighter.test.ts
+++ b/packages/app/src/utils/diff-highlighter.test.ts
@@ -59,6 +59,105 @@ index 1234567..0000000
-export { legacy };
`;
+const RUST_DIFF = `diff --git a/lib.rs b/lib.rs
+index 1234567..abcdefg 100644
+--- a/lib.rs
++++ b/lib.rs
+@@ -1,4 +1,4 @@
+ fn main() {
+- let version = 1;
++ let version = 2;
+ println!("Hello, world!");
+ }
+`;
+
+const C_DIFF = `diff --git a/example.c b/example.c
+index 1234567..abcdefg 100644
+--- a/example.c
++++ b/example.c
+@@ -1,4 +1,4 @@
+ int main(void) {
+- int version = 1;
++ int version = 2;
+ return version;
+ }
+`;
+
+const JAVA_DIFF = `diff --git a/Main.java b/Main.java
+index 1234567..abcdefg 100644
+--- a/Main.java
++++ b/Main.java
+@@ -1,5 +1,5 @@
+ public class Main {
+ public static void main(String[] args) {
+- int version = 1;
++ int version = 2;
+ }
+ }
+`;
+
+const OBJECTIVE_C_DIFF = `diff --git a/AppDelegate.m b/AppDelegate.m
+index 1234567..abcdefg 100644
+--- a/AppDelegate.m
++++ b/AppDelegate.m
+@@ -1,4 +1,4 @@
+ int main(void) {
+- int version = 1;
++ int version = 2;
+ return version;
+ }
+`;
+
+const GO_DIFF = `diff --git a/main.go b/main.go
+index 1234567..abcdefg 100644
+--- a/main.go
++++ b/main.go
+@@ -1,7 +1,7 @@
+ package main
+
+ import "fmt"
+
+ func main() {
+- version := 1
++ version := 2
+ fmt.Println(version)
+ }
+`;
+
+const PHP_DIFF = `diff --git a/index.php b/index.php
+index 1234567..abcdefg 100644
+--- a/index.php
++++ b/index.php
+@@ -1,4 +1,4 @@
+
+`;
+
+const YAML_DIFF = `diff --git a/config.yaml b/config.yaml
+index 1234567..abcdefg 100644
+--- a/config.yaml
++++ b/config.yaml
+@@ -1,3 +1,3 @@
+ app: paseo
+-count: 1
++count: 2
+ enabled: true
+`;
+
+const XML_DIFF = `diff --git a/config.xml b/config.xml
+index 1234567..abcdefg 100644
+--- a/config.xml
++++ b/config.xml
+@@ -1,3 +1,3 @@
+
+- 1
++ 2
+
+`;
+
describe("parseDiff", () => {
it("parses a simple diff with one hunk", () => {
const files = parseDiff(SIMPLE_DIFF);
@@ -251,6 +350,124 @@ describe("highlightDiffFile", () => {
expect(highlighted.hunks[0].lines[1].tokens).toBeUndefined();
expect(highlighted.hunks[0].lines[2].tokens).toBeUndefined();
});
+
+ it("adds syntax highlighting tokens to Rust code", () => {
+ const files = parseDiff(RUST_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const fnLine = hunk.lines[1];
+ expect(fnLine.tokens).toBeDefined();
+ expect(fnLine.tokens!.some((t) => t.text === "fn" && t.style === "keyword")).toBe(true);
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to C code", () => {
+ const files = parseDiff(C_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const mainLine = hunk.lines[1];
+ expect(mainLine.tokens).toBeDefined();
+ expect(mainLine.tokens!.length).toBeGreaterThan(0);
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to Java code", () => {
+ const files = parseDiff(JAVA_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const classLine = hunk.lines[1];
+ expect(classLine.tokens).toBeDefined();
+ expect(
+ classLine.tokens!.some((t) => t.text === "public" && t.style === "keyword")
+ ).toBe(true);
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to Objective-C file extensions", () => {
+ const files = parseDiff(OBJECTIVE_C_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to Go code", () => {
+ const files = parseDiff(GO_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to PHP code", () => {
+ const files = parseDiff(PHP_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("$version")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to YAML code", () => {
+ const files = parseDiff(YAML_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("count")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(addedLine!.tokens!.length).toBeGreaterThan(0);
+ });
+
+ it("adds syntax highlighting tokens to XML code", () => {
+ const files = parseDiff(XML_DIFF);
+ const highlighted = highlightDiffFile(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(addedLine!.tokens!.some((t) => t.style === "tag")).toBe(true);
+ });
});
describe("parseAndHighlightDiff", () => {
diff --git a/packages/app/src/utils/syntax-highlighter.ts b/packages/app/src/utils/syntax-highlighter.ts
index e0f38a455..89cae3952 100644
--- a/packages/app/src/utils/syntax-highlighter.ts
+++ b/packages/app/src/utils/syntax-highlighter.ts
@@ -2,9 +2,16 @@ import { highlightTree, tagHighlighter, tags } from "@lezer/highlight";
import { parser as jsParser } from "@lezer/javascript";
import { parser as jsonParser } from "@lezer/json";
import { parser as cssParser } from "@lezer/css";
+import { parser as cppParser } from "@lezer/cpp";
+import { parser as goParser } from "@lezer/go";
import { parser as htmlParser } from "@lezer/html";
+import { parser as javaParser } from "@lezer/java";
import { parser as pythonParser } from "@lezer/python";
import { parser as markdownParser } from "@lezer/markdown";
+import { parser as phpParser } from "@lezer/php";
+import { parser as rustParser } from "@lezer/rust";
+import { parser as xmlParser } from "@lezer/xml";
+import { parser as yamlParser } from "@lezer/yaml";
import { parser as elixirParser } from "lezer-elixir";
import type { Parser } from "@lezer/common";
@@ -17,6 +24,16 @@ const parsersByExtension: Record = {
tsx: jsParser.configure({ dialect: "tsx jsx" }),
mjs: jsParser,
cjs: jsParser,
+ // C / C++ / Objective-C
+ c: cppParser,
+ h: cppParser,
+ cc: cppParser,
+ cpp: cppParser,
+ cxx: cppParser,
+ hpp: cppParser,
+ hxx: cppParser,
+ m: cppParser,
+ mm: cppParser,
// JSON
json: jsonParser,
// CSS
@@ -25,8 +42,21 @@ const parsersByExtension: Record = {
// HTML
html: htmlParser,
htm: htmlParser,
+ // XML
+ xml: xmlParser,
+ // Java
+ java: javaParser,
// Python
py: pythonParser,
+ // Go
+ go: goParser,
+ // PHP
+ php: phpParser,
+ // YAML
+ yaml: yamlParser,
+ yml: yamlParser,
+ // Rust
+ rs: rustParser,
// Elixir
ex: elixirParser,
exs: elixirParser,
diff --git a/packages/server/package.json b/packages/server/package.json
index b93f8a840..5d6c2cd4f 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -66,13 +66,20 @@
"@deepgram/sdk": "^3.4.0",
"@getpaseo/relay": "0.1.30",
"@lezer/common": "^1.5.0",
+ "@lezer/cpp": "^1.1.5",
"@lezer/css": "^1.3.0",
+ "@lezer/go": "^1.0.1",
"@lezer/highlight": "^1.2.3",
"@lezer/html": "^1.3.13",
+ "@lezer/java": "^1.1.3",
"@lezer/javascript": "^1.5.4",
"@lezer/json": "^1.0.3",
"@lezer/markdown": "^1.6.2",
+ "@lezer/php": "^1.0.5",
"@lezer/python": "^1.1.18",
+ "@lezer/rust": "^1.0.2",
+ "@lezer/xml": "^1.0.6",
+ "@lezer/yaml": "^1.0.4",
"@modelcontextprotocol/sdk": "^1.20.1",
"@opencode-ai/sdk": "1.2.6",
"@sctg/sentencepiece-js": "^1.1.0",
diff --git a/packages/server/src/server/utils/diff-highlighter.test.ts b/packages/server/src/server/utils/diff-highlighter.test.ts
index c0b61eeae..fe5ac629e 100644
--- a/packages/server/src/server/utils/diff-highlighter.test.ts
+++ b/packages/server/src/server/utils/diff-highlighter.test.ts
@@ -57,6 +57,105 @@ index 1234567..0000000
-export { legacy };
`;
+const RUST_DIFF = `diff --git a/lib.rs b/lib.rs
+index 1234567..abcdefg 100644
+--- a/lib.rs
++++ b/lib.rs
+@@ -1,4 +1,4 @@
+ fn main() {
+- let version = 1;
++ let version = 2;
+ println!("Hello, world!");
+ }
+`;
+
+const C_DIFF = `diff --git a/example.c b/example.c
+index 1234567..abcdefg 100644
+--- a/example.c
++++ b/example.c
+@@ -1,4 +1,4 @@
+ int main(void) {
+- int version = 1;
++ int version = 2;
+ return version;
+ }
+`;
+
+const JAVA_DIFF = `diff --git a/Main.java b/Main.java
+index 1234567..abcdefg 100644
+--- a/Main.java
++++ b/Main.java
+@@ -1,5 +1,5 @@
+ public class Main {
+ public static void main(String[] args) {
+- int version = 1;
++ int version = 2;
+ }
+ }
+`;
+
+const OBJECTIVE_C_DIFF = `diff --git a/AppDelegate.m b/AppDelegate.m
+index 1234567..abcdefg 100644
+--- a/AppDelegate.m
++++ b/AppDelegate.m
+@@ -1,4 +1,4 @@
+ int main(void) {
+- int version = 1;
++ int version = 2;
+ return version;
+ }
+`;
+
+const GO_DIFF = `diff --git a/main.go b/main.go
+index 1234567..abcdefg 100644
+--- a/main.go
++++ b/main.go
+@@ -1,7 +1,7 @@
+ package main
+
+ import "fmt"
+
+ func main() {
+- version := 1
++ version := 2
+ fmt.Println(version)
+ }
+`;
+
+const PHP_DIFF = `diff --git a/index.php b/index.php
+index 1234567..abcdefg 100644
+--- a/index.php
++++ b/index.php
+@@ -1,4 +1,4 @@
+
+`;
+
+const YAML_DIFF = `diff --git a/config.yaml b/config.yaml
+index 1234567..abcdefg 100644
+--- a/config.yaml
++++ b/config.yaml
+@@ -1,3 +1,3 @@
+ app: paseo
+-count: 1
++count: 2
+ enabled: true
+`;
+
+const XML_DIFF = `diff --git a/config.xml b/config.xml
+index 1234567..abcdefg 100644
+--- a/config.xml
++++ b/config.xml
+@@ -1,3 +1,3 @@
+
+- 1
++ 2
+
+`;
+
describe("parseDiff", () => {
it("parses a simple diff with one hunk", () => {
const files = parseDiff(SIMPLE_DIFF);
@@ -249,4 +348,122 @@ describe("highlightDiffFromHunks", () => {
expect(highlighted.hunks[0].lines[1].tokens).toBeUndefined();
expect(highlighted.hunks[0].lines[2].tokens).toBeUndefined();
});
+
+ it("adds syntax highlighting tokens to Rust code", () => {
+ const files = parseDiff(RUST_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const fnLine = hunk.lines[1];
+ expect(fnLine.tokens).toBeDefined();
+ expect(fnLine.tokens!.some((t) => t.text === "fn" && t.style === "keyword")).toBe(true);
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to C code", () => {
+ const files = parseDiff(C_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const mainLine = hunk.lines[1];
+ expect(mainLine.tokens).toBeDefined();
+ expect(mainLine.tokens!.length).toBeGreaterThan(0);
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to Java code", () => {
+ const files = parseDiff(JAVA_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const classLine = hunk.lines[1];
+ expect(classLine.tokens).toBeDefined();
+ expect(
+ classLine.tokens!.some((t) => t.text === "public" && t.style === "keyword")
+ ).toBe(true);
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to Objective-C file extensions", () => {
+ const files = parseDiff(OBJECTIVE_C_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const hunk = highlighted.hunks[0];
+
+ const addedLine = hunk.lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to Go code", () => {
+ const files = parseDiff(GO_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("version")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to PHP code", () => {
+ const files = parseDiff(PHP_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("$version")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(
+ addedLine!.tokens!.some((t) => t.text === "2" && t.style === "number")
+ ).toBe(true);
+ });
+
+ it("adds syntax highlighting tokens to YAML code", () => {
+ const files = parseDiff(YAML_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("count")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(addedLine!.tokens!.length).toBeGreaterThan(0);
+ });
+
+ it("adds syntax highlighting tokens to XML code", () => {
+ const files = parseDiff(XML_DIFF);
+ const highlighted = highlightDiffFromHunks(files[0]);
+ const addedLine = highlighted.hunks[0].lines.find(
+ (line) => line.type === "add" && line.content.includes("")
+ );
+
+ expect(addedLine?.tokens).toBeDefined();
+ expect(addedLine!.tokens!.some((t) => t.style === "tag")).toBe(true);
+ });
});
diff --git a/packages/server/src/server/utils/syntax-highlighter.ts b/packages/server/src/server/utils/syntax-highlighter.ts
index c86a5a40e..89483ebbb 100644
--- a/packages/server/src/server/utils/syntax-highlighter.ts
+++ b/packages/server/src/server/utils/syntax-highlighter.ts
@@ -2,9 +2,16 @@ import { highlightTree, tagHighlighter, tags } from "@lezer/highlight";
import { parser as jsParser } from "@lezer/javascript";
import { parser as jsonParser } from "@lezer/json";
import { parser as cssParser } from "@lezer/css";
+import { parser as cppParser } from "@lezer/cpp";
+import { parser as goParser } from "@lezer/go";
import { parser as htmlParser } from "@lezer/html";
+import { parser as javaParser } from "@lezer/java";
import { parser as pythonParser } from "@lezer/python";
import { parser as markdownParser } from "@lezer/markdown";
+import { parser as phpParser } from "@lezer/php";
+import { parser as rustParser } from "@lezer/rust";
+import { parser as xmlParser } from "@lezer/xml";
+import { parser as yamlParser } from "@lezer/yaml";
import { parser as elixirParser } from "lezer-elixir";
import type { Parser } from "@lezer/common";
@@ -17,6 +24,16 @@ const parsersByExtension: Record = {
tsx: jsParser.configure({ dialect: "ts jsx" }),
mjs: jsParser,
cjs: jsParser,
+ // C / C++ / Objective-C
+ c: cppParser,
+ h: cppParser,
+ cc: cppParser,
+ cpp: cppParser,
+ cxx: cppParser,
+ hpp: cppParser,
+ hxx: cppParser,
+ m: cppParser,
+ mm: cppParser,
// JSON
json: jsonParser,
// CSS
@@ -25,8 +42,21 @@ const parsersByExtension: Record = {
// HTML
html: htmlParser,
htm: htmlParser,
+ // XML
+ xml: xmlParser,
+ // Java
+ java: javaParser,
// Python
py: pythonParser,
+ // Go
+ go: goParser,
+ // PHP
+ php: phpParser,
+ // YAML
+ yaml: yamlParser,
+ yml: yamlParser,
+ // Rust
+ rs: rustParser,
// Elixir
ex: elixirParser,
exs: elixirParser,