Initial commit

main
idylls 2 years ago
parent 9299b974c6
commit 42874f26b4
Signed by: idylls
GPG Key ID: 8A7167CBC2CC9F0F

2
.gitignore vendored

@ -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;