๐
codeViewer.ts
TypeScript ยท 2,847 bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* CodeViewer โ Renders syntax-highlighted source files
* with line-by-line blame annotations and diff overlays.
*/
import { SyntaxHighlighter } from "@.git/syntax";
import { BlameService } from "@.git/blame";
import { type FileContent, LineBlame, DiffHunk } from "@.git/types";
export interface CodeViewerProps {
filePath: string;
content: FileContent;
blameInfo?: LineBlame[];
diffHunks?: DiffHunk[];
onLineClick?: (line: number) => void;
}
export class CodeViewer {
private highlighter: SyntaxHighlighter;
private blameService: BlameService;
private _props: CodeViewerProps;
private _container: HTMLElement;
// Line 21: constructor
constructor(container: HTMLElement, props: CodeViewerProps) {
this._container = container;
this._props = props;
this.highlighter = new SyntaxHighlighter({
theme: "dark",
languages: ["typescript", "javascript", "css", "html"],
});
this.blameService = new BlameService();
}
// Line 38: Render the code with syntax highlighting
async render(): Promise<void> {
const lines = this._props.content.split("\n");
const lang = this.detectLanguage(this._props.filePath);
// Apply syntax highlighting
const highlighted = await this.highlighter.highlight(lines, lang);
// Fetch blame annotations if available
let blames: LineBlame[] = this._props.blameInfo || [];
if (blames.length === 0) {
blames = await this.blameService.annotate(this._props.filePath);
}
// Render to DOM
this._renderLines(highlighted, blames);
this._bindEvents();
}
// Line 57: Build DOM nodes for each line
private _renderLines(
lines: string[],
blames: LineBlame[]
): void {
const fragment = document.createDocumentFragment();
lines.forEach((html, index) => {
const blame = blames[index] || null;
const lineEl = document.createElement("div");
lineEl.className = "code-line" + (blame ? ` blame:${blame.hash}` : "");
lineEl.innerHTML = `<span class="line-num">${index + 1}</span> ${html}`;
fragment.appendChild(lineEl);
});
this._container.innerHTML = "";
this._container.appendChild(fragment);
}
// Line 75: Attach click handlers for blame tooltips
private _bindEvents(): void {
this._container.addEventListener("click", (e) => {
const target = (e.target as HTMLElement).closest(".code-line");
if (target) this._props.onLineClick?.call(undefined, Number(target.dataset.line));
});
}
// Detect file language from extension
private detectLanguage(path: string): string {
return path.split(".").pop() || "text";
}
}
Blame
Commits
Branches
JL
2 hours ago
Commit History