diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 63109c91..00000000 --- a/.eslintrc +++ /dev/null @@ -1,24 +0,0 @@ -{ - "env": { - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended", - "plugin:storybook/recommended" - ], - "overrides": [], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "project": ["tsconfig.json", "stories/tsconfig.json"], - "sourceType": "module" - }, - "plugins": ["@typescript-eslint", "prettier"], - "rules": { - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-explicit-any": "off" - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..84bc8a7b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,35 @@ +const { error } = require("node:console"); + +/** @type {import('eslint').Linter.Config} */ +module.exports = { + env: { + es2021: true, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "plugin:storybook/recommended", + ], + overrides: [], + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: "latest", + project: ["tsconfig.json", "stories/tsconfig.json"], + sourceType: "module", + }, + plugins: ["@typescript-eslint", "prettier"], + rules: { + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "no-restricted-imports": [ + "error", + { paths: require("node:module").builtinModules }, + ], + "no-restricted-modules": [ + "error", + { paths: require("node:module").builtinModules }, + ], + }, +}; diff --git a/package.json b/package.json index 50b25cee..27bbc1e6 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "workspace" ], "activationEvents": [ - "*" + "onStartupFinished" ], "capabilities": { "untrustedWorkspaces": { @@ -168,7 +168,7 @@ "@storybook/react": "^7.4.0", "@storybook/react-vite": "^7.4.0", "@types/node": "^18.17.12", - "@types/vscode": "^1.70.0", + "@types/vscode": "~1.70.0", "@typescript-eslint/eslint-plugin": "^6.5.0", "@typescript-eslint/parser": "^6.5.0", "@vscode/vsce": "^2.21.0", diff --git a/src/browser.ts b/src/browser.ts index 7e57c116..5bb7fc3a 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,14 +1,18 @@ -import { workspace, ConfigurationChangeEvent, window } from "vscode"; +import { + workspace, + ConfigurationChangeEvent, + window, + ExtensionContext, +} from "vscode"; -export const activate = () => { - // regenerate the theme files when the config changes - workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { - if (event.affectsConfiguration("catppuccin")) { - window.showInformationMessage( - "VSCode Web doesn't support advanced Catppuccin options at the moment.", - ); - } - }); +export const activate = (ctx: ExtensionContext) => { + ctx.subscriptions.push( + workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { + if (event.affectsConfiguration("catppuccin")) { + window.showErrorMessage( + "VSCode Web doesn't support advanced Catppuccin options at the moment.", + ); + } + }), + ); }; - -export const deactivate = () => {}; diff --git a/src/helpers.ts b/src/helpers.ts deleted file mode 100644 index d93e0c98..00000000 --- a/src/helpers.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { join } from "path"; -import { ThemePaths } from "./types"; - -export const getThemePaths = (): ThemePaths => { - const themes = ["latte", "frappe", "macchiato", "mocha"]; - const paths: ThemePaths = { - latte: "", - frappe: "", - macchiato: "", - mocha: "", - }; - themes.map( - (theme) => - (paths[theme] = join(__dirname, "..", "themes", `${theme}.json`)), - ); - return paths; -}; diff --git a/src/hooks/.eslintrc b/src/hooks/.eslintrc new file mode 100644 index 00000000..701d4cbd --- /dev/null +++ b/src/hooks/.eslintrc @@ -0,0 +1,6 @@ +{ + "rules": { + "no-restricted-imports": "off", + "no-restricted-modules": "off" + } +} diff --git a/src/hooks/generateThemes.ts b/src/hooks/generateThemes.ts index 27cc7a90..dce733b1 100644 --- a/src/hooks/generateThemes.ts +++ b/src/hooks/generateThemes.ts @@ -1,18 +1,20 @@ -import * as fs from "fs"; -import path = require("path"); +import * as fs from "fs/promises"; +import * as path from "path"; import { variants } from "@catppuccin/palette"; -import { getThemePaths } from "../helpers"; import { compileTheme, defaultOptions } from "../theme"; -import { CatppuccinFlavour } from "../types"; +import type { CatppuccinFlavour } from "../types"; -const paths = getThemePaths(); +const themeDir = path.join(__dirname, "../../themes"); const flavours = Object.keys(variants) as CatppuccinFlavour[]; flavours.map((flavour) => { const theme = compileTheme(flavour, defaultOptions); // ignore error if directory exists - fs.mkdir(path.dirname(paths[flavour]), () => { - fs.writeFileSync(paths[flavour], JSON.stringify(theme, null, 2)); + fs.mkdir(themeDir, { recursive: true }).then(() => { + fs.writeFile( + path.join(themeDir, `${flavour}.json`), + JSON.stringify(theme, null, 2), + ); }); }); diff --git a/src/main.ts b/src/main.ts index 465c4187..d4e13a49 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,24 @@ -import { workspace, ConfigurationChangeEvent, extensions } from "vscode"; -import { getThemePaths } from "./helpers"; +import { + ConfigurationChangeEvent, + ExtensionContext, + Uri, + extensions, + workspace, +} from "vscode"; import utils, { UpdateTrigger } from "./utils"; +import type { ThemePaths } from "./types"; -export const activate = () => { - const paths = getThemePaths(); +export const activate = async (ctx: ExtensionContext) => { + const base = ctx.extensionUri; + const paths: ThemePaths = { + latte: Uri.joinPath(base, "themes", "latte.json"), + frappe: Uri.joinPath(base, "themes", "frappe.json"), + macchiato: Uri.joinPath(base, "themes", "macchiato.json"), + mocha: Uri.joinPath(base, "themes", "mocha.json"), + }; // regenerate on a fresh install if non-default config is set - if (utils.isFreshInstall() && !utils.isDefaultConfig()) { + if ((await utils.isFreshInstall(ctx)) && !utils.isDefaultConfig()) { utils.updateThemes( utils.getConfiguration(), paths, @@ -14,35 +26,39 @@ export const activate = () => { ); } - // regenerate the theme files when the config changes - workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { - if ( - event.affectsConfiguration("workbench.colorTheme") && - extensions.getExtension("catppuccin.catppuccin-vsc-icons") - ) { - const theme = workspace + ctx.subscriptions.push( + // regenerate the theme files when the config changes + workspace.onDidChangeConfiguration((event) => handler(event, paths)), + ); +}; + +const handler = (event: ConfigurationChangeEvent, paths: ThemePaths) => { + const id = "catppuccin.catppuccin-vsc-icons"; + const iconsInstalled = extensions.getExtension(id).isActive; + const iconsAffected = event.affectsConfiguration("workbench.colorTheme"); + + if (iconsInstalled && iconsAffected) { + const theme = workspace + .getConfiguration("workbench") + .get("colorTheme"); + const ctp_themes = { + "Catppuccin Latte": "catppuccin-latte", + "Catppuccin Frappé": "catppuccin-frappe", + "Catppuccin Macchiato": "catppuccin-macchiato", + "Catppuccin Mocha": "catppuccin-mocha", + }; + if (Object.keys(ctp_themes).includes(theme)) { + workspace .getConfiguration("workbench") - .get("colorTheme"); - const ctp_themes = { - "Catppuccin Latte": "catppuccin-latte", - "Catppuccin Frappé": "catppuccin-frappe", - "Catppuccin Macchiato": "catppuccin-macchiato", - "Catppuccin Mocha": "catppuccin-mocha", - }; - if (Object.keys(ctp_themes).includes(theme)) { - workspace - .getConfiguration("workbench") - .update("iconTheme", ctp_themes[theme], true); - } + .update("iconTheme", ctp_themes[theme], true); } - if (event.affectsConfiguration("catppuccin")) { - utils.updateThemes( - utils.getConfiguration(), - paths, - UpdateTrigger.CONFIG_CHANGE, - ); - } - }); -}; + } -export const deactivate = () => {}; + if (event.affectsConfiguration("catppuccin")) { + utils.updateThemes( + utils.getConfiguration(), + paths, + UpdateTrigger.CONFIG_CHANGE, + ); + } +}; diff --git a/src/theme/extensions/error-lens.ts b/src/theme/extensions/error-lens.ts index eb50a117..08ed3200 100644 --- a/src/theme/extensions/error-lens.ts +++ b/src/theme/extensions/error-lens.ts @@ -1,4 +1,4 @@ -import { ThemeContext } from "../../types"; +import type { ThemeContext } from "../../types"; import { opacity } from "../utils"; export default function colors(context: ThemeContext) { diff --git a/src/theme/extensions/index.ts b/src/theme/extensions/index.ts index 504324aa..4ddec528 100644 --- a/src/theme/extensions/index.ts +++ b/src/theme/extensions/index.ts @@ -1,4 +1,4 @@ -import { ThemeContext } from "../../types"; +import type { ThemeContext } from "../../types"; import errorLens from "./error-lens"; export default function (context: ThemeContext) { diff --git a/src/types/index.d.ts b/src/types/index.d.ts index acc59cb2..13b036e5 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,8 +1,12 @@ +import { labels, variants } from "@catppuccin/palette"; + +import type { Uri } from "vscode"; + export type * from "./textmate-colors"; export type * from "./workbench-colors"; export type * from "./token-styling"; -export type CatppuccinFlavour = "latte" | "frappe" | "macchiato" | "mocha"; +export type CatppuccinFlavour = keyof typeof variants; export type CatppuccinAccent = | "rosewater" | "flamingo" @@ -25,35 +29,11 @@ export type CatppuccinBracketMode = | "monochromatic" | "neovim"; -export interface CatppuccinPalette { +export type CatppuccinPalette = { name: CatppuccinFlavour; - rosewater: string; - flamingo: string; - pink: string; - mauve: string; - red: string; - maroon: string; - peach: string; - yellow: string; - green: string; - teal: string; - sky: string; - sapphire: string; - blue: string; - lavender: string; - text: string; - subtext1: string; - subtext0: string; - overlay2: string; - overlay1: string; - overlay0: string; - surface2: string; - surface1: string; - surface0: string; - base: string; - mantle: string; - crust: string; -} +} & { + [k in keyof typeof labels]: string; +}; export type ColorOverrides = { all?: Partial; @@ -84,10 +64,10 @@ export type ThemeOptions = { }; export type ThemePaths = { - latte: string; - frappe: string; - macchiato: string; - mocha: string; + latte: Uri; + frappe: Uri; + macchiato: Uri; + mocha: Uri; }; export type ThemeContext = { diff --git a/src/utils.ts b/src/utils.ts index 39cb7aa2..e73dd350 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,8 +1,14 @@ import { variants } from "@catppuccin/palette"; -import * as fs from "fs"; import { compileTheme, defaultOptions } from "./theme"; -import { commands, workspace, window } from "vscode"; import { + commands, + workspace, + window, + Uri, + FilePermission, + ExtensionContext, +} from "vscode"; +import type { CatppuccinAccent, CatppuccinFlavour, ColorOverrides, @@ -12,7 +18,6 @@ import { CatppuccinWorkbenchMode, CatppuccinBracketMode, } from "./types"; -import { join } from "path"; // the reason why an update has been triggered, and a reload is needed export enum UpdateTrigger { @@ -21,7 +26,7 @@ export enum UpdateTrigger { } class Utils { - private promptToReload(trigger: UpdateTrigger) { + private promptToReload = (trigger: UpdateTrigger) => { const msg = `Catppuccin: ${trigger} - Reload required.`; const action = "Reload window"; window.showInformationMessage(msg, action).then((selectedAction) => { @@ -29,32 +34,54 @@ class Utils { commands.executeCommand("workbench.action.reloadWindow"); } }); - } - private writeThemeFile(path: string, data: any) { - return fs.writeFile(path, JSON.stringify(data, null, 2), (err) => { - if (err) { - window.showErrorMessage(err.message); - } - }); - } - isFreshInstall(): boolean { + }; + private writeThemeFile = async (uri: Uri, data: any): Promise => { + return workspace.fs + .writeFile(uri, Buffer.from(JSON.stringify(data, null, 2))) + .then( + () => {}, + (err) => { + window.showErrorMessage(err.message); + }, + ); + }; + private fileExists = async (uri: Uri): Promise => { + return workspace.fs.stat(uri).then( + () => true, + () => false, + ); + }; + isMutable = async (uri: Uri): Promise => { + return workspace.fs.stat(uri).then( + (stat) => stat.permissions !== FilePermission.Readonly, + (err) => err, + ); + }; + isFreshInstall = async ( + ctx: ExtensionContext, + ): Promise => { console.log("Checking if catppuccin is installed for the first time."); - const flagPath = join(__dirname, "..", "themes", ".flag"); - if (fs.existsSync(flagPath)) { + const flagUri = Uri.file(ctx.asAbsolutePath("themes/.flag")); + if (await this.fileExists(flagUri)) { console.log("Catppuccin has been installed before."); return false; } else { console.log("Catppuccin is installed for the first time!"); - fs.writeFileSync(flagPath, ""); - return true; + return workspace.fs.writeFile(flagUri, Buffer.from("")).then( + () => true, + () => "error", + ); } - } - isDefaultConfig(): boolean { + }; + isDefaultConfig = (): boolean => { console.log("Checking if catppuccin is using default config."); - const state = this.getConfiguration() === defaultOptions; + const state = + JSON.stringify(this.getConfiguration()) === + JSON.stringify(defaultOptions); console.log(`Catppuccin is using ${state ? "default" : "custom"} config.`); + return state; - } + }; getConfiguration = (): ThemeOptions => { const conf = workspace.getConfiguration("catppuccin"); return { diff --git a/tsup.config.ts b/tsup.config.ts index 2e8b0b7c..96a7c98b 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,11 +1,9 @@ import { defineConfig } from "tsup"; -const debug = !!process.env.DEBUG; export default defineConfig({ entry: ["src/browser.ts", "src/main.ts"], - minify: !debug, - sourcemap: debug, external: ["vscode"], + sourcemap: true, target: "node16", clean: true, }); diff --git a/yarn.lock b/yarn.lock index 8de9e88c..e112d1ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4038,10 +4038,10 @@ __metadata: languageName: node linkType: hard -"@types/vscode@npm:^1.70.0": - version: 1.77.0 - resolution: "@types/vscode@npm:1.77.0" - checksum: 169dbced32d3f84aad6a41f0d099343ff2a2a86005e309e48192db500cd846423e0e5848f20a6c1aab71329915423255dd9a083974d6f3eb4bb085c278435b98 +"@types/vscode@npm:~1.70.0": + version: 1.70.0 + resolution: "@types/vscode@npm:1.70.0" + checksum: fda7b48d93a8c2164abb393224572e201a995518a223c6d1fb130e66baf5878235901a078ee31f8f12f89854935ca431a9b78c335abc78672b4e25e5b9d32584 languageName: node linkType: hard @@ -5049,7 +5049,7 @@ __metadata: "@storybook/react": ^7.4.0 "@storybook/react-vite": ^7.4.0 "@types/node": ^18.17.12 - "@types/vscode": ^1.70.0 + "@types/vscode": ~1.70.0 "@typescript-eslint/eslint-plugin": ^6.5.0 "@typescript-eslint/parser": ^6.5.0 "@vscode/vsce": ^2.21.0