Skip to content

Commit

Permalink
hl code
Browse files Browse the repository at this point in the history
  • Loading branch information
TwIStOy committed Dec 10, 2023
1 parent ce8d109 commit 6cd1deb
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 11 deletions.
133 changes: 133 additions & 0 deletions src/core/format/rendered-node/codeblock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { info } from "@core/utils/logger";
import { PangoMarkupGenerator } from ".";
import { isNil } from "@core/vim";

type MarkerKind = "start" | "end";

interface HighlightMarkerStart {
kind: "start";
capture: string;
offset: number;
}

interface HighlightMarkerEnd {
kind: "end";
offset: number;
}

type HighlightMarker = HighlightMarkerStart | HighlightMarkerEnd;

export function highlightContent(
pango: PangoMarkupGenerator,
content: string,
language: string
) {
let parser = vim.treesitter.get_string_parser(content, language);
let highlights = vim.treesitter.query.get(language, "highlights");
let root = parser.parse(true)[0].root();
let markers: HighlightMarker[] = [];
for (let [id, node, _metadata] of highlights.iter_captures(root, content)) {
let capture = highlights.captures.get(id);
let [_startLine, _startCol, startByte, _endLine, _endCol, endByte] =
node.range(true);
let text = content.slice(startByte, endByte);
info("capture: %s, type: %s, text: %s", capture, node.type(), text);
markers.push({
kind: "start",
capture,
offset: startByte,
});
markers.push({
kind: "end",
offset: endByte,
});
}
markers = markers.sort((a, b) => a.offset - b.offset);
let m = 0;
pango.addLines('<span allow_breaks="false"><tt>');
for (let i = 0; i < content.length; i++) {
while (m < markers.length && markers[m].offset <= i) {
let marker = markers[m];
if (marker.kind === "start") {
pango.addLines(intoOpenTag(marker.capture));
} else {
pango.addLines("</span>");
}
m++;
}
pango.addLines(content[i]);
}
pango.addLines("</tt></span>");
}

function intoOpenTag(capture: string): string {
let parts = capture.split(".");

let properties = new LuaTable();

while (parts.length > 0) {
let name = `@${parts.join(".")}`;
let hl = vim.api.nvim_get_hl(0, {
name,
link: true,
});
while (hl.has("link")) {
let linkName = hl.get("link")!;
hl = vim.api.nvim_get_hl(0, {
name: linkName,
link: true,
});
}
if (!properties.has("foreground") && hl.has("guifg")) {
let fg = hl.get("guifg")!;
if (!isNil(fg) && fg !== "") {
properties.set("foreground", string.format("#%06x", fg));
}
}
if (!properties.has("foreground") && hl.has("fg")) {
let fg = hl.get("fg")!;
if (!isNil(fg) && fg !== "") {
properties.set("foreground", string.format("#%06x", fg));
}
}
if (!properties.has("background") && hl.has("bg")) {
let bg = hl.get("bg")!;
if (!isNil(bg) && bg !== "") {
properties.set("background", string.format("#%06x", bg));
}
}
if (!properties.has("background") && hl.has("guibg")) {
let bg = hl.get("guibg")!;
if (!isNil(bg) && bg !== "") {
properties.set("background", string.format("#%06x", bg));
}
}
if (!properties.has("underline") && hl.has("underline")) {
let underline = hl.get("underline")!;
if (!isNil(underline) && underline === true) {
properties.set("underline", "single");
}
}
if (!properties.has("underline") && hl.has("undercurl")) {
let undercurl = hl.get("undercurl")!;
if (!isNil(undercurl) && undercurl === true) {
properties.set("underline", "error");
}
}
if (!properties.has("underline_color") && hl.has("sp")) {
let sp = hl.get("sp")!;
if (!isNil(sp) && sp !== "") {
properties.set("underline_color", string.format("#%06x", sp));
}
}

parts.pop();
}

let result = "<span";
for (let [key, value] of properties) {
result += ` ${key}="${value}"`;
}
result += ">";
return result;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { info } from "@core/utils/logger";
import { isNil } from "@core/vim";
import { ifNil, isNil } from "@core/vim";
import * as lgi from "lgi";
import { highlightContent } from "./codeblock";

function escapeMarkup(str: string): string {
return lgi.GLib.markup_escape_text(str, -1);
Expand Down Expand Up @@ -54,9 +55,28 @@ export class PangoMarkupGenerator {
// clean empty tags
result = result
.map((line) => line.replaceAll("<span></span>", "").trim())
.filter((line) => line.length > 0);
.filter((line) => line.length > 0)
.map((line) => this._addCommonTag(line));
return result;
}

private _addCommonTag(p: string) {
let normal = vim.api.nvim_get_hl(0, {
name: "Normal",
});
info("normal, %s", normal);
let foreground = ifNil(normal.get("guifg"), normal.get("fg"));
let background = ifNil(normal.get("guibg"), normal.get("bg"));
let openTag = "<span";
if (!isNil(foreground)) {
openTag += ` foreground="#${string.format("%06x", foreground)}"`;
}
if (!isNil(background)) {
openTag += ` background="#${string.format("%06x", background)}"`;
}
openTag += ">";
return `${openTag}${p}</span>`;
}
}

export abstract class RenderedNode {
Expand Down Expand Up @@ -168,6 +188,16 @@ export class CodeBlockNode extends SimpleWrapperNode {
startNewParagraph(): boolean {
return true;
}

intoPangoMarkup(pango: PangoMarkupGenerator): void {
let content = this.content as string;
let language = this.params as string | null;
if (language !== null) {
highlightContent(pango, content, language);
} else {
super.intoPangoMarkup(pango);
}
}
}

export class SpanNode extends SimpleWrapperNode {
Expand Down
16 changes: 8 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mountRightClickMenu } from "@conf/ui/right-click";
import { Image } from "@core/components/image/image";
import { Command } from "@core/model";
import { VimBuffer, hideCursor } from "@core/vim";
import { VimBuffer, hideCursor, ifNil } from "@core/vim";
import { Padding } from "@glib/widgets/_utils";
import { Container } from "@glib/widgets/container";
import { Text } from "@glib/widgets/text/text";
Expand Down Expand Up @@ -61,19 +61,19 @@ export function test() {
info("paragraph: %s", p);
}

let hl_normal = vim.api.nvim_get_hl(0, {
name: "Normal",
});
let background = ifNil(hl_normal.get("guibg"), hl_normal.get("bg"));

let root = Container({
// color: "#1e2030",
color: "white",
color: background,
border: { width: 4, color: "black", radius: 20 },
height: "expand",
width: "expand",
padding: Padding.all(10),
child: Column({
children: [
Spacing(),
...paragraphs.map((m) => Markup(m)),
Spacing(),
],
children: [Spacing(), ...paragraphs.map((m) => Markup(m)), Spacing()],
}),
});
try {
Expand Down
4 changes: 3 additions & 1 deletion src/types/vim/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ declare namespace vim {
export function nvim_win_set_buf(window: number, buffer: number): void;

export function nvim_win_get_buf(window: number): number;

export function nvim_win_get_width(window: number): number;

export function nvim_exec_autocmds(
Expand Down Expand Up @@ -252,5 +252,7 @@ declare namespace vim {
create?: boolean;
}
): LuaTable;

export function nvim_get_namespaces(): LuaTable<string, number>;
}
}
24 changes: 24 additions & 0 deletions src/types/vim/treesitter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,20 @@ declare interface TSHighlighter {
bufnr: number;
}

declare interface TSMetadata {}

declare interface TSQuery {
iter_captures(
node: TSNode,
source?: number | string,
start?: number,
stop?: number
): LuaIterable<LuaMultiReturn<[number, TSNode, TSMetadata]>>;

captures: LuaTable<number, string>;

}

declare namespace vim {
export namespace treesitter {
export const highlighter: TSHighlighter;
Expand All @@ -283,5 +297,15 @@ declare namespace vim {
metadata: LuaTable;
}
): string;

export namespace query {
/**
* Returns the runtime query `{query_name}` for `{lang}`
*
* @param lang Language to use for the query.
* @param query_name Name of the query.
*/
export function get(lang: string, query_name: string): TSQuery;
}
}
}

0 comments on commit 6cd1deb

Please sign in to comment.