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