Initial commit
parent
9299b974c6
commit
42874f26b4
@ -0,0 +1,2 @@
|
|||||||
|
build/*
|
||||||
|
build
|
@ -0,0 +1,13 @@
|
|||||||
|
import * as everwild from "./schemes/everwild.ts";
|
||||||
|
import * as emacs from "./programs/emacs.ts";
|
||||||
|
import * as kitty from "./programs/kitty.ts";
|
||||||
|
|
||||||
|
const build = async () => {
|
||||||
|
console.info("Building...");
|
||||||
|
await emacs.writeTheme(everwild.emacsDark, "build/emacs/everwild-dark.el");
|
||||||
|
await kitty.writeConf(everwild.kittyDark, "build/kitty/everwild-dark.conf");
|
||||||
|
|
||||||
|
console.info("Done");
|
||||||
|
};
|
||||||
|
|
||||||
|
await build();
|
@ -0,0 +1,118 @@
|
|||||||
|
import { Face, Color, } from "../util/colors.ts"
|
||||||
|
import { Syntax } from "../util/syntax.ts";
|
||||||
|
import { ensureDir } from "../util/fs.ts";
|
||||||
|
|
||||||
|
export interface Theme {
|
||||||
|
name: string,
|
||||||
|
faces: Faces,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ts = (s: string) => `tree-sitter-hl-face:${s}`;
|
||||||
|
const fl = (s: string) => `font-lock-${s}-face`;
|
||||||
|
const syntaxToFaceName: Record<keyof Syntax, string> = {
|
||||||
|
attribute: ts("attribute"),
|
||||||
|
argumentType: ts("type.argument"),
|
||||||
|
builtinConstant: ts("constant.builtin"),
|
||||||
|
builtinFunction: ts("function.builtin"),
|
||||||
|
builtinType: ts("type.builtin"),
|
||||||
|
builtinVariable: ts("variable.builtin"),
|
||||||
|
comment: fl("comment"),
|
||||||
|
constant: fl("constant"),
|
||||||
|
constructor_: ts("constructor"),
|
||||||
|
documentaton: fl("doc"),
|
||||||
|
embedded: ts("embedded"),
|
||||||
|
escape: ts("escape"),
|
||||||
|
function: fl("function-name"),
|
||||||
|
functionCall: ts("function.call"),
|
||||||
|
keyword: fl("keyword"),
|
||||||
|
label: ts("label"),
|
||||||
|
macro: ts("macro"),
|
||||||
|
method: ts("method"),
|
||||||
|
methodCall: ts("method.call"),
|
||||||
|
number: ts("number"),
|
||||||
|
operator: ts("operator"),
|
||||||
|
parameter: ts("parameter"),
|
||||||
|
property: ts("property"),
|
||||||
|
propertyDefinition: ts("property.definition"),
|
||||||
|
punctuation: ts("punctuation"),
|
||||||
|
punctuationBracket: ts("punctuation.bracket"),
|
||||||
|
punctuationSpecial: ts("punctuation.special"),
|
||||||
|
punctuationDelimiter: ts("punctuation.delimiter"),
|
||||||
|
specialFunction: ts("function.special"),
|
||||||
|
specialString: ts("string.special"),
|
||||||
|
specialVariable: ts("variable.special"),
|
||||||
|
string: fl("string"),
|
||||||
|
super: ts("super"),
|
||||||
|
tag: ts("tag"),
|
||||||
|
type: fl("type"),
|
||||||
|
typeParameter: ts("type.parameter"),
|
||||||
|
variable: fl("variable-name"),
|
||||||
|
};
|
||||||
|
export const createTheme = (
|
||||||
|
name: string,
|
||||||
|
fi: FacesInput,
|
||||||
|
s: Partial<Syntax>,
|
||||||
|
) => {
|
||||||
|
const faces = Object.entries(syntaxToFaceName).reduce((faces, [sn, fn]) => {
|
||||||
|
const sn_ = sn as keyof Syntax;
|
||||||
|
const c = s[sn_];
|
||||||
|
if (!c) {
|
||||||
|
faces[fn] = fi.default;
|
||||||
|
return faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
faces[fn] = c;
|
||||||
|
return faces;
|
||||||
|
}, {} as Record<string, Face>);
|
||||||
|
Object.assign(faces, fi);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
faces,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Faces = Record<string, Face>;
|
||||||
|
export type FacesInput = Faces & {
|
||||||
|
default: Face,
|
||||||
|
};
|
||||||
|
|
||||||
|
const themeToString = (theme: Theme) => {
|
||||||
|
let s = `
|
||||||
|
(deftheme ${theme.name} "${theme.name}")
|
||||||
|
(custom-theme-set-faces
|
||||||
|
'${theme.name}
|
||||||
|
`;
|
||||||
|
for (const [name, face] of Object.entries(theme.faces)) {
|
||||||
|
s += ` \`(${name} ((t (`;
|
||||||
|
s += faceToString(face);
|
||||||
|
s += `))))\n`;
|
||||||
|
}
|
||||||
|
s += `)\n`;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const faceToString = (face: Face) => {
|
||||||
|
const t = (name: string, v: string) => `:${name} ${v} `;
|
||||||
|
const y = <T>(f: (v: T) => string) => {
|
||||||
|
return (n: string, v: T | null) => {
|
||||||
|
return v ? t(n, f(v)) : '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const c = y((v: Color) => `"${v}"`);
|
||||||
|
|
||||||
|
let o = '';
|
||||||
|
o += c("background", face.bg);
|
||||||
|
o += c("foreground", face.fg);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeTheme = async (theme: Theme, path: string) => {
|
||||||
|
await ensureDir(path);
|
||||||
|
|
||||||
|
const s = themeToString(theme);
|
||||||
|
|
||||||
|
return Deno.writeTextFile(path, s);
|
||||||
|
};
|
@ -0,0 +1,60 @@
|
|||||||
|
import { Color } from "../util/colors.ts";
|
||||||
|
import { ensureDir } from "../util/fs.ts";
|
||||||
|
|
||||||
|
export interface ColorPair {
|
||||||
|
regular: Color,
|
||||||
|
bright: Color,
|
||||||
|
}
|
||||||
|
export const pair = (regular: Color, bright: Color) => ({ regular, bright });
|
||||||
|
export interface Colors {
|
||||||
|
black: ColorPair,
|
||||||
|
red: ColorPair,
|
||||||
|
green: ColorPair,
|
||||||
|
yellow: ColorPair,
|
||||||
|
blue: ColorPair,
|
||||||
|
magenta: ColorPair,
|
||||||
|
cyan: ColorPair,
|
||||||
|
white: ColorPair,
|
||||||
|
}
|
||||||
|
export interface Conf {
|
||||||
|
foreground: Color,
|
||||||
|
background: Color,
|
||||||
|
selectionForeground: Color,
|
||||||
|
selectionBackground: Color,
|
||||||
|
cursor: Color,
|
||||||
|
cursorTextColor: Color | "background",
|
||||||
|
colors: Colors,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const writeConf = async (r: Conf, path: string) => {
|
||||||
|
await ensureDir(path);
|
||||||
|
|
||||||
|
let s = '';
|
||||||
|
const l = (n: string, v: string) => `${n} ${v}\n`;
|
||||||
|
const c = (c: Color) => c;
|
||||||
|
|
||||||
|
s += l('foreground', c(r.foreground));
|
||||||
|
s += l('background', c(r.background));
|
||||||
|
s += l('selection_foreground', c(r.selectionForeground));
|
||||||
|
s += l('selection_background', c(r.selectionBackground));
|
||||||
|
s += l('cursor', c(r.foreground));
|
||||||
|
s += l('cursor_text_color', 'background');
|
||||||
|
s += l('color0', r.colors.black.regular);
|
||||||
|
s += l('color8', r.colors.black.bright);
|
||||||
|
s += l('color1', r.colors.red.regular);
|
||||||
|
s += l('color9', r.colors.red.bright);
|
||||||
|
s += l('color2', r.colors.green.regular);
|
||||||
|
s += l('color10', r.colors.green.bright);
|
||||||
|
s += l('color3', r.colors.yellow.regular);
|
||||||
|
s += l('color11', r.colors.yellow.bright);
|
||||||
|
s += l('color4', r.colors.blue.regular);
|
||||||
|
s += l('color12', r.colors.blue.bright);
|
||||||
|
s += l('color5', r.colors.magenta.regular);
|
||||||
|
s += l('color13', r.colors.magenta.bright);
|
||||||
|
s += l('color6', r.colors.cyan.regular);
|
||||||
|
s += l('color14', r.colors.cyan.bright);
|
||||||
|
s += l('color7', r.colors.white.regular);
|
||||||
|
s += l('color15', r.colors.white.bright);
|
||||||
|
|
||||||
|
return Deno.writeTextFile(path, s);
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
import { defaultSyntax } from "../util/syntax.ts";
|
||||||
|
import { color, fg, fgBg } from "../util/colors.ts";
|
||||||
|
import { resolve, ref } from "../util/ouro.ts";
|
||||||
|
|
||||||
|
import { createTheme } from "../programs/emacs.ts";
|
||||||
|
import { pair, Conf } from "../programs/kitty.ts";
|
||||||
|
|
||||||
|
|
||||||
|
// This is a comment
|
||||||
|
export const palette = {
|
||||||
|
gray: {
|
||||||
|
0: color("#262726"),
|
||||||
|
10: color("#EAEBEA"),
|
||||||
|
},
|
||||||
|
green: {
|
||||||
|
3: color("#214521"),
|
||||||
|
4: color("#285328"),
|
||||||
|
6: color("#356E35"),
|
||||||
|
8: color("#91CA91"),
|
||||||
|
10: color("#C0E1C0"),
|
||||||
|
},
|
||||||
|
yellow: {
|
||||||
|
8: color("#D4BF88"),
|
||||||
|
},
|
||||||
|
blue: {
|
||||||
|
7: color("#9EBEE6"),
|
||||||
|
10: color("#9EBEE6"),
|
||||||
|
},
|
||||||
|
cyan: {
|
||||||
|
7: color("#7CDFC5"),
|
||||||
|
10: color("#D0F4EA"),
|
||||||
|
},
|
||||||
|
orange: {
|
||||||
|
7: color("#DFA77C"),
|
||||||
|
},
|
||||||
|
pink: {
|
||||||
|
9: color("#E7B6C3"),
|
||||||
|
},
|
||||||
|
purple: {
|
||||||
|
8: color("#D4B6E7"),
|
||||||
|
10: color("#E4D0F0"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const p = palette;
|
||||||
|
|
||||||
|
export const emacsDark = createTheme(
|
||||||
|
"everwild-dark",
|
||||||
|
resolve({
|
||||||
|
default: fgBg(p.gray[10], p.gray[0]),
|
||||||
|
"mode-line": fgBg(p.gray[10], p.green[4]),
|
||||||
|
region: ref("mode-line"),
|
||||||
|
"vertico-current": ref("region"),
|
||||||
|
"corfu-current": ref("region"),
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
...defaultSyntax,
|
||||||
|
comment: fg(p.cyan[7]),
|
||||||
|
type: fg(p.blue[7]),
|
||||||
|
function: fg(p.green[8]),
|
||||||
|
constant: fg(p.purple[8]),
|
||||||
|
string: fg(p.yellow[8]),
|
||||||
|
variable: fg(p.orange[7]),
|
||||||
|
keyword: fg(p.pink[9]),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const kittyDark: Conf = resolve({
|
||||||
|
background: p.gray[0],
|
||||||
|
foreground: p.gray[10],
|
||||||
|
selectionBackground: p.green[4],
|
||||||
|
selectionForeground: ref("foreground"),
|
||||||
|
cursor: ref("foreground"),
|
||||||
|
cursorTextColor: "background",
|
||||||
|
colors: {
|
||||||
|
white: pair(p.gray[10], color("#FFFFFF")),
|
||||||
|
black: pair(color("#000000"), p.gray[0]),
|
||||||
|
blue: pair(p.blue[7], p.blue[10]),
|
||||||
|
cyan: pair(p.cyan[7], p.cyan[10]),
|
||||||
|
green: pair(p.green[8], p.green[10]),
|
||||||
|
magenta: pair(p.purple[8], p.purple[10]),
|
||||||
|
red: pair(p.pink[9], p.pink[9]),
|
||||||
|
yellow: pair(p.yellow[8], p.yellow[8]),
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
|
"noEmit": true,
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
"noImplicitOverride": true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
export type Color = string & { readonly __color: unique symbol };
|
||||||
|
export const color = (hex: string) => hex as Color;
|
||||||
|
|
||||||
|
export interface Face {
|
||||||
|
fg: Color | null,
|
||||||
|
bg: Color | null,
|
||||||
|
}
|
||||||
|
export const createFace = (
|
||||||
|
fg: Face["fg"],
|
||||||
|
bg: Face["bg"],
|
||||||
|
): Face => ({ fg, bg });
|
||||||
|
export const fgBg = createFace;
|
||||||
|
export const fg = (fg: Face["fg"]) => createFace(fg, null);
|
@ -0,0 +1,12 @@
|
|||||||
|
const dirname = (path: string) => path.split("/").slice(0, -1).join("/");
|
||||||
|
|
||||||
|
export const ensureDir = async (path: string) => {
|
||||||
|
const dir = dirname(path);
|
||||||
|
try {
|
||||||
|
await Deno.mkdir(dir, { recursive: true });
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof Deno.errors.AlreadyExists)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
export type Ref<T> = { __ref: keyof T };
|
||||||
|
export const ref = <T>(k: keyof T) => ({ __ref: k });
|
||||||
|
const isRef = <T>(t: unknown): t is Ref<T> =>
|
||||||
|
t !== null && typeof t === "object" && "__ref" in t;
|
||||||
|
|
||||||
|
export type Ouro<T> = {
|
||||||
|
[K in keyof T]: T[K] | Ref<T>
|
||||||
|
};
|
||||||
|
|
||||||
|
type Follow<T, K extends keyof T> =
|
||||||
|
T[K] extends Ref<T>
|
||||||
|
? Follow<T, T[K]["__ref"]>
|
||||||
|
: T[K];
|
||||||
|
|
||||||
|
export type Boros<T> = {
|
||||||
|
[K in keyof T]: Follow<T, K>
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resolve = <T>(obj: Ouro<T>): Boros<T> => {
|
||||||
|
const newObj = {} as Partial<Boros<T>>;
|
||||||
|
const keysToProcess = new Set(Object.keys(obj) as (keyof typeof obj)[]);
|
||||||
|
while (true) {
|
||||||
|
if (keysToProcess.size === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keysToAssign = new Set<keyof T>();
|
||||||
|
|
||||||
|
let k = [...keysToProcess][0];
|
||||||
|
while (true) {
|
||||||
|
if (keysToAssign.has(k)) {
|
||||||
|
throw new Error("Infinite loop detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
keysToProcess.delete(k);
|
||||||
|
keysToAssign.add(k);
|
||||||
|
|
||||||
|
const v = newObj[k] ?? obj[k];
|
||||||
|
if (!isRef<T>(v)) {
|
||||||
|
for (const k of keysToAssign) {
|
||||||
|
newObj[k] = v as Boros<T>[typeof k];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
k = v.__ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newObj as Boros<T>;
|
||||||
|
};
|
@ -0,0 +1,91 @@
|
|||||||
|
import { Face } from "./colors.ts";
|
||||||
|
import { resolve, ref, Ouro } from "./ouro.ts";
|
||||||
|
|
||||||
|
export type Syn = Face | null;
|
||||||
|
|
||||||
|
export type BasicSyntax = {
|
||||||
|
comment: Syn,
|
||||||
|
documentaton: Syn,
|
||||||
|
string: Syn,
|
||||||
|
keyword: Syn,
|
||||||
|
operator: Syn,
|
||||||
|
constant: Syn,
|
||||||
|
function: Syn,
|
||||||
|
variable: Syn,
|
||||||
|
punctuation: Syn,
|
||||||
|
type: Syn,
|
||||||
|
label: Syn,
|
||||||
|
};
|
||||||
|
export const defaultBasicSyntax = {
|
||||||
|
comment: null,
|
||||||
|
documentaton: null,
|
||||||
|
string: null,
|
||||||
|
keyword: null,
|
||||||
|
operator: null,
|
||||||
|
constant: null,
|
||||||
|
function: null,
|
||||||
|
variable: null,
|
||||||
|
punctuation: null,
|
||||||
|
type: null,
|
||||||
|
label: null,
|
||||||
|
} as Ouro<BasicSyntax>;
|
||||||
|
|
||||||
|
export interface ExtendedSyntax {
|
||||||
|
tag: Syn,
|
||||||
|
number: Syn,
|
||||||
|
method: Syn,
|
||||||
|
methodCall: Syn,
|
||||||
|
functionCall: Syn,
|
||||||
|
property: Syn,
|
||||||
|
attribute: Syn,
|
||||||
|
constructor_: Syn,
|
||||||
|
punctuationSpecial: Syn,
|
||||||
|
punctuationBracket: Syn,
|
||||||
|
punctuationDelimiter: Syn,
|
||||||
|
super: Syn,
|
||||||
|
builtinType: Syn,
|
||||||
|
argumentType: Syn,
|
||||||
|
specialString: Syn,
|
||||||
|
macro: Syn,
|
||||||
|
typeParameter: Syn,
|
||||||
|
specialFunction: Syn,
|
||||||
|
specialVariable: Syn,
|
||||||
|
builtinConstant: Syn,
|
||||||
|
builtinFunction: Syn,
|
||||||
|
builtinVariable: Syn,
|
||||||
|
parameter: Syn,
|
||||||
|
propertyDefinition: Syn,
|
||||||
|
escape: Syn,
|
||||||
|
embedded: Syn,
|
||||||
|
}
|
||||||
|
export const defaultSyntax: Ouro<Syntax> = {
|
||||||
|
...defaultBasicSyntax,
|
||||||
|
tag: null,
|
||||||
|
number: ref("constant"),
|
||||||
|
functionCall: ref("function"),
|
||||||
|
method: ref("function"),
|
||||||
|
methodCall: ref("method"),
|
||||||
|
property: ref("variable"),
|
||||||
|
attribute: ref("property"),
|
||||||
|
constructor_: ref("type"),
|
||||||
|
punctuationSpecial: ref("punctuation"),
|
||||||
|
punctuationBracket: ref("punctuation"),
|
||||||
|
punctuationDelimiter: ref("punctuation"),
|
||||||
|
super: ref("keyword"),
|
||||||
|
builtinType: ref("type"),
|
||||||
|
builtinConstant: ref("constant"),
|
||||||
|
builtinFunction: ref("function"),
|
||||||
|
builtinVariable: ref("variable"),
|
||||||
|
argumentType: ref("type"),
|
||||||
|
embedded: null,
|
||||||
|
escape: null,
|
||||||
|
macro: ref("function"),
|
||||||
|
parameter: ref("variable"),
|
||||||
|
propertyDefinition: ref("variable"),
|
||||||
|
specialFunction: ref("function"),
|
||||||
|
specialString: ref("string"),
|
||||||
|
specialVariable: ref("variable"),
|
||||||
|
typeParameter: ref("type"),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Syntax = BasicSyntax & ExtendedSyntax;
|
Reference in New Issue