Skip to content

Commit

Permalink
Add terminal highlighting (fix #28)
Browse files Browse the repository at this point in the history
  • Loading branch information
pomber committed Jul 25, 2023
1 parent 89402fb commit 8ceee96
Show file tree
Hide file tree
Showing 18 changed files with 375 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/moody-trainers-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@code-hike/lighter": patch
---

Add terminal highlighting
2 changes: 1 addition & 1 deletion lib/dist/browser.esm.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/dist/index.cjs.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/dist/index.esm.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/dist/worker.esm.mjs

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,8 @@
},
"repository": "https://github.com/code-hike/lighter",
"homepage": "https://lighter.codehike.org",
"funding": "https://github.com/code-hike/lighter?sponsor=1"
"funding": "https://github.com/code-hike/lighter?sponsor=1",
"dependencies": {
"ansi-sequence-parser": "^1.1.0"
}
}
10 changes: 7 additions & 3 deletions lib/src/highlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import onig from "./wasm";

let registry: Registry | null = null;

function isGramarless(lang: LanguageAlias) {
return lang == "text" || lang == "terminal";
}

export function preloadGrammars(languages: LanguageAlias[]) {
// initialize the registry the first time
if (!registry) {
Expand All @@ -29,7 +33,7 @@ export function preloadGrammars(languages: LanguageAlias[]) {
}

const promises = languages
.filter((alias) => alias != "text")
.filter((alias) => !isGramarless(alias))
.map((alias) => {
const langData = aliasToLangData(alias);
if (!langData) {
Expand All @@ -45,9 +49,9 @@ export function getGrammar(alias: LanguageAlias): {
langId: string;
grammar: IGrammar | null;
} {
if (alias == "text") {
if (isGramarless(alias)) {
return {
langId: "text",
langId: alias,
grammar: null,
};
}
Expand Down
21 changes: 13 additions & 8 deletions lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
Tokens,
Token,
} from "./annotations";
import { getTerminalStyle, highlightTerminal } from "./terminal";

type Config = { scopes?: boolean };
type AnnotatedConfig = { annotations: Annotation[] } & Config;
Expand Down Expand Up @@ -140,28 +141,32 @@ export function highlightSync(
const lines =
langId == "text"
? highlightText(theCode)
: langId == "terminal"
? highlightTerminal(theCode, theme)
: config?.scopes
? highlightTokensWithScopes(theCode, grammar, theme)
: highlightTokens(theCode, grammar, theme);

const style =
langId == "terminal"
? getTerminalStyle(theme)
: {
color: theme.foreground,
background: theme.background,
};

if (isAnnotatedConfig(config)) {
const annotations = config?.annotations || [];
return {
lines: applyAnnotations(lines, annotations),
lang: langId,
style: {
color: theme.foreground,
background: theme.background,
},
style,
};
} else {
return {
lines: lines,
lang: langId,
style: {
color: theme.foreground,
background: theme.background,
},
style,
};
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/src/language-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export const LANG_NAMES = [
"system-verilog",
"tasl",
"tcl",
"terminal",
"tex",
"text",
"toml",
Expand Down
80 changes: 80 additions & 0 deletions lib/src/terminal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { FinalTheme } from "./theme";
import { Token } from "./annotations";
import { Color, createAnsiSequenceParser } from "ansi-sequence-parser";
import { getColor } from "./theme-colors";

export function highlightTerminal(code: string, theme: FinalTheme): Token[][] {
const parser = createAnsiSequenceParser();
const lines = code
.split(/\r?\n|\r/g)
.map((line) => highlightLine(parser, line, theme));

return lines;
}

function highlightLine(
parser: ReturnType<typeof createAnsiSequenceParser>,
line: string,
theme: FinalTheme
) {
const ansiLine = parser.parse(line);
const tokens = ansiLine.map(
({ value, foreground, background, decorations }) => {
const color = getAnsiColor(foreground, theme);
const style = {};
if (color) {
style["color"] = color;
}
const backgroundColor = getAnsiColor(background, theme);
if (backgroundColor) {
style["background"] = backgroundColor;
}
if (decorations.has("bold")) {
style["fontWeight"] = "bold";
}
if (decorations.has("italic")) {
style["fontStyle"] = "italic";
}
if (decorations.has("underline")) {
style["textDecoration"] = "underline";
}
if (decorations.has("strikethrough")) {
style["textDecoration"] = "line-through";
}
if (decorations.has("reverse")) {
style["color"] = backgroundColor;
style["background"] = color;
}
if (decorations.has("dim")) {
style["opacity"] = 0.5;
}

return {
content: value,
style,
};
}
);
return tokens;
}

function getAnsiColor(color: Color | null, theme: FinalTheme) {
if (!color) return undefined;
if (color.type === "named") {
// capitalize name
const name = color.name[0].toUpperCase() + color.name.slice(1);
return getColor(theme, "terminal.ansi" + name);
}
if (color.type === "rgb") {
const [r, g, b] = color.rgb;
return `rgb(${r}, ${g}, ${b})`;
}
return undefined;
}

export function getTerminalStyle(theme: FinalTheme) {
return {
color: getColor(theme, "terminal.foreground"),
background: getColor(theme, "terminal.background"),
};
}
84 changes: 84 additions & 0 deletions lib/src/theme-colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,88 @@ const defaults = {
dark: [transparent, "editor.background", 0.9],
light: [transparent, "editor.background", 0.9],
},

// terminal colors
"terminal.background": "editor.background",
"terminal.foreground": "editor.foreground",
"terminal.ansiBlack": {
dark: "#000000",
light: "#000000",
hc: "#000000",
},
"terminal.ansiRed": {
dark: "#cd3131",
light: "#cd3131",
hc: "#cd0000",
},
"terminal.ansiGreen": {
dark: "#0DBC79",
light: "#00BC00",
hc: "#00cd00",
},
"terminal.ansiYellow": {
dark: "#e5e510",
light: "#949800",
hc: "#cdcd00",
},
"terminal.ansiBlue": {
dark: "#2472c8",
light: "#0451a5",
hc: "#0000ee",
},
"terminal.ansiMagenta": {
dark: "#bc3fbc",
light: "#bc05bc",
hc: "#cd00cd",
},
"terminal.ansiCyan": {
dark: "#11a8cd",
light: "#0598bc",
hc: "#00cdcd",
},
"terminal.ansiWhite": {
dark: "#e5e5e5",
light: "#555555",
hc: "#e5e5e5",
},
"terminal.ansiBrightBlack": {
dark: "#666666",
light: "#666666",
hc: "#7f7f7f",
},
"terminal.ansiBrightRed": {
dark: "#f14c4c",
light: "#cd3131",
hc: "#ff0000",
},
"terminal.ansiBrightGreen": {
dark: "#23d18b",
light: "#14CE14",
hc: "#00ff00",
},
"terminal.ansiBrightYellow": {
dark: "#f5f543",
light: "#b5ba00",
hc: "#ffff00",
},
"terminal.ansiBrightBlue": {
dark: "#3b8eea",
light: "#0451a5",
hc: "#5c5cff",
},
"terminal.ansiBrightMagenta": {
dark: "#d670d6",
light: "#bc05bc",
hc: "#ff00ff",
},
"terminal.ansiBrightCyan": {
dark: "#29b8db",
light: "#0598bc",
hc: "#00ffff",
},
"terminal.ansiBrightWhite": {
dark: "#e5e5e5",
light: "#a5a5a5",
hc: "#ffffff",
},
};
36 changes: 36 additions & 0 deletions lib/test/__snapshots__/browser.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,42 @@ exports[`highlight js 1`] = `
}
`;

exports[`highlight terminal 1`] = `
{
"lang": "terminal",
"lines": [
[
{
"content": "Foo",
"style": {},
},
],
],
"style": {
"background": "#0d1117",
"color": "#c9d1d9",
},
}
`;

exports[`highlight terminal ansi codes 1`] = `
{
"lang": "terminal",
"lines": [
[
{
"content": "Foo",
"style": {},
},
],
],
"style": {
"background": "#0d1117",
"color": "#c9d1d9",
},
}
`;

exports[`highlight text 1`] = `
{
"lang": "text",
Expand Down
36 changes: 36 additions & 0 deletions lib/test/__snapshots__/cjs.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,42 @@ exports[`highlight js 1`] = `
}
`;

exports[`highlight terminal 1`] = `
{
"lang": "terminal",
"lines": [
[
{
"content": "Foo",
"style": {},
},
],
],
"style": {
"background": "#0d1117",
"color": "#c9d1d9",
},
}
`;

exports[`highlight terminal ansi codes 1`] = `
{
"lang": "terminal",
"lines": [
[
{
"content": "Foo",
"style": {},
},
],
],
"style": {
"background": "#0d1117",
"color": "#c9d1d9",
},
}
`;

exports[`highlight text 1`] = `
{
"lang": "text",
Expand Down
Loading

1 comment on commit 8ceee96

@vercel
Copy link

@vercel vercel bot commented on 8ceee96 Jul 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

lighter – ./

lighter-codehike.vercel.app
lighter.codehike.org
lighter-git-main-codehike.vercel.app

Please sign in to comment.