Skip to content

Commit

Permalink
feat(compiler): add verbose errors for wrong user config (#288)
Browse files Browse the repository at this point in the history
  • Loading branch information
nekowinston authored Jan 10, 2024
1 parent 712e80b commit 8162693
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 55 deletions.
8 changes: 2 additions & 6 deletions packages/catppuccin-vsc/src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,12 @@ export const compileTheme = (
isLatte: flavor === "latte",
};

const flavourName = `Catppuccin ${flavorData.name}`;

const theme = {
name: flavourName,
return {
name: `Catppuccin ${flavorData.name}`,
type: context.isLatte ? "light" : "dark",
colors: getUiColors(context),
semanticHighlighting: true,
semanticTokenColors: getSemanticTokens(context),
tokenColors: getTokenColors(context),
};

return theme;
};
113 changes: 67 additions & 46 deletions packages/catppuccin-vsc/src/theme/ui/customNames.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,79 @@
import { CatppuccinPalette, ThemeContext } from "@/types";
import type { ThemeContext, ColorName } from "@/types";
import { opacity } from "@/theme/utils";
import { flavors } from "@catppuccin/palette";

type CustomNamedColors = Record<string, string>;

const ctpColors = new Set(Object.keys(flavors.mocha.colors));

class CustomUIColorError extends Error {
constructor(key: string, value: string, message = "") {
super(
`Invalid value: "${value}" for key "${key}" in "catppuccin.customUIColors".\n${message}`,
);
this.name = "CustomUIColorError";
}
}

/**
* @throws if the value is not a valid 'colorName' or 'colorName opacityValue'
* @returns a tuple of [colorName, opacityValue]
*/
const parseCustomUiColor = (k: string, v: string): [string, number] => {
const entry = v.split(" ");
if (entry.length > 2) {
throw new CustomUIColorError(
k,
v,
'Too many arguments, expected "colorName" or "colorName opacityValue".',
);
}
let opacityValue = 1;
if (entry.length == 2) {
opacityValue = Number(entry[1]);
if (Number.isNaN(opacityValue)) {
throw new CustomUIColorError(k, v, "Opacity value is not a number.");
}
if (opacityValue < 0 || opacityValue > 1) {
throw new CustomUIColorError(
k,
v,
"Opacity value is not between 0 and 1.",
);
}
}
return [entry[0], opacityValue];
};
const hexColorRegex = /^#([\dA-Fa-f]{3,4}){1,2}$/;

const customNamedColors = (context: ThemeContext): CustomNamedColors => {
const { flavor, palette, options } = context;
const accent = palette[options.accent];

return {
...Object.entries({
// collect the options, overwrite the "all" config with the current palette config
...options.customUIColors.all,
...options.customUIColors[flavor],
})
.map(([k, v]) => {
// deal with accents
if (v.startsWith("accent")) {
const entry = v.split(" ");
return entry.length === 1
? {
[k]: accent,
}
: {
[k]: opacity(accent, Number(entry[1])),
};
}

// allow custom hex colors
if (v.startsWith("#")) {
return {
[k]: v,
};
}

//check if the entry is a "color opacity" mapping
const entry = v.split(" ");
v =
entry.length === 1
? // resolve to the palette color
palette[v as keyof CatppuccinPalette]
: // call the opacity function
opacity(
palette[entry[0] as keyof CatppuccinPalette],
Number(entry[1]),
);

return {
[k]: v,
};
})
// TODO: rework this to get rid of the reduce
// eslint-disable-next-line unicorn/no-array-reduce
.reduce((previous, current) => ({ ...previous, ...current }), {}),
const customUIColors = {
...options.customUIColors.all,
...options.customUIColors[flavor],
};

for (const [k, v] of Object.entries(customUIColors)) {
// don't change custom hex colors
if (hexColorRegex.test(v)) continue;

const [parsedColor, opacityValue] = parseCustomUiColor(k, v);

let color: string;
if (parsedColor === "accent") {
color = accent;
} else if (ctpColors.has(parsedColor)) {
color = palette[parsedColor as ColorName];
} else {
throw new CustomUIColorError(k, v, "Invalid color name.");
}

customUIColors[k] = opacity(color, opacityValue);
}

return customUIColors;
};

export default customNamedColors;
1 change: 1 addition & 0 deletions packages/catppuccin-vsc/src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type * from "@catppuccin/vsc-typegen/types/gitlens";

export type CatppuccinAccent = AccentName;
export type CatppuccinFlavor = FlavorName;
export { type ColorName } from "@catppuccin/palette";
export type CatppuccinWorkbenchMode = "default" | "flat" | "minimal";
export type CatppuccinBracketMode =
| "rainbow"
Expand Down
12 changes: 9 additions & 3 deletions packages/catppuccin-vsc/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,15 @@ export const updateThemes = async (
return writeThemeFile(paths[flavor], theme);
});

Promise.all(promises).then(() => {
promptToReload(trigger);
});
Promise.all(promises)
.then(() => {
promptToReload(trigger);
})
.catch((error) => {
window.showErrorMessage(
"Failed to save re-compiled theme: \n" + error.message,
);
});
};

export const syncToIconPack = () => {
Expand Down

0 comments on commit 8162693

Please sign in to comment.