From 13a7da62687de69c30eba35e98e62d0fe17487b3 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 21 Sep 2024 10:42:43 -0400 Subject: [PATCH] Add support for loading custom themes (#53) --- README.md | 15 +++++++++++++++ src/getConfig.ts | 4 +--- src/getGitConfig.test.ts | 6 +++++- src/getGitConfig.ts | 11 +++++++++++ src/previewTheme.ts | 20 ++++++++++++++------ src/themes.ts | 17 +++++++---------- 6 files changed, 53 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 787aa67..0963aeb 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,17 @@ git config split-diffs.theme-name monochrome-light ![Screenshot of Monochrome Light theme](screenshots/monochrome-light.png?raw=true) +## Custom Themes + +Default themes are loaded from the `git-split-diffs` bundle. To load a custom theme, set `theme-directory` in git config and create a `{theme-name}.json` file in that directory with the theme's definition. You can use one of the existing themes in [themes/](https://github.com/banga/git-split-diffs/tree/main/themes) as a starting point. + +``` +git config split-diffs.theme-directory +git config split-diffs.theme-name +``` + +This will use `/path/to/theme/name.json` as the theme. + ## Performance Tested by measuring the time it took to pipe the output `git log -p` to `/dev/null` via `git-split-diffs` with the default theme: @@ -191,6 +202,10 @@ See [#narrow-terminals](#narrow-terminals) Text coloring is implemented using Chalk which supports [various levels of color](https://github.com/chalk/chalk#supportscolor). If Chalk is producing fewer colors than your terminal supports, try overriding Chalk's detection using a variation of the `--color` flag, e.g. `--color=16m` for true color. See Chalk's documentation or [this useful gist on terminal support](https://gist.github.com/XVilka/8346728) if issues persist. +### Want to remove background colors from a theme? + +See [#custom-themes](#custom-themes) for instructions on customizing themes. Removing `backgroundColor` should usually work. + ## Acknowledgements - [diff-so-fancy](https://github.com/so-fancy/diff-so-fancy) for showing what's possible diff --git a/src/getConfig.ts b/src/getConfig.ts index b2b1efe..b63b5c6 100644 --- a/src/getConfig.ts +++ b/src/getConfig.ts @@ -8,8 +8,6 @@ export type Config = Theme & { HIGHLIGHT_LINE_CHANGES: boolean; }; -export const DEFAULT_THEME_NAME = 'dark'; - export const CONFIG_DEFAULTS: Omit = { MIN_LINE_WIDTH: 80, WRAP_LINES: true, @@ -17,7 +15,7 @@ export const CONFIG_DEFAULTS: Omit = { }; export function getConfig(gitConfig: GitConfig): Config { - const theme = loadTheme(gitConfig.THEME_NAME ?? DEFAULT_THEME_NAME); + const theme = loadTheme(gitConfig.THEME_DIRECTORY, gitConfig.THEME_NAME); return { ...CONFIG_DEFAULTS, diff --git a/src/getGitConfig.test.ts b/src/getGitConfig.test.ts index cd165c4..559a9f8 100644 --- a/src/getGitConfig.test.ts +++ b/src/getGitConfig.test.ts @@ -1,6 +1,7 @@ -import { DEFAULT_THEME_NAME } from './getConfig'; import { DEFAULT_MIN_LINE_WIDTH, + DEFAULT_THEME_DIRECTORY, + DEFAULT_THEME_NAME, GitConfig, getGitConfig, } from './getGitConfig'; @@ -10,6 +11,7 @@ const DEFAULT_CONFIG: GitConfig = { HIGHLIGHT_LINE_CHANGES: true, MIN_LINE_WIDTH: DEFAULT_MIN_LINE_WIDTH, THEME_NAME: DEFAULT_THEME_NAME, + THEME_DIRECTORY: DEFAULT_THEME_DIRECTORY, }; describe('getGitConfig', () => { @@ -24,6 +26,7 @@ split-diffs.wrap-lines=false split-diffs.highlight-line-changes=false split-diffs.min-line-width=40 split-diffs.theme-name=arctic +split-diffs.theme-directory=/tmp split-diffs.syntax-highlighting-theme=dark-plus `) ).toEqual({ @@ -31,6 +34,7 @@ split-diffs.syntax-highlighting-theme=dark-plus HIGHLIGHT_LINE_CHANGES: false, MIN_LINE_WIDTH: 40, THEME_NAME: 'arctic', + THEME_DIRECTORY: '/tmp', SYNTAX_HIGHLIGHTING_THEME: 'dark-plus', }); }); diff --git a/src/getGitConfig.ts b/src/getGitConfig.ts index 5854b47..5c0107c 100644 --- a/src/getGitConfig.ts +++ b/src/getGitConfig.ts @@ -1,12 +1,21 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; + export type GitConfig = { MIN_LINE_WIDTH: number; WRAP_LINES: boolean; HIGHLIGHT_LINE_CHANGES: boolean; + THEME_DIRECTORY: string; THEME_NAME: string; SYNTAX_HIGHLIGHTING_THEME?: string; }; export const DEFAULT_MIN_LINE_WIDTH = 80; +export const DEFAULT_THEME_DIRECTORY = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..', + 'themes' +); export const DEFAULT_THEME_NAME = 'dark'; const GIT_CONFIG_KEY_PREFIX = 'split-diffs'; @@ -44,6 +53,8 @@ export function getGitConfig(configString: string): GitConfig { MIN_LINE_WIDTH: minLineWidth, WRAP_LINES: rawConfig['wrap-lines'] !== 'false', HIGHLIGHT_LINE_CHANGES: rawConfig['highlight-line-changes'] !== 'false', + THEME_DIRECTORY: + rawConfig['theme-directory'] ?? DEFAULT_THEME_DIRECTORY, THEME_NAME: rawConfig['theme-name'] ?? DEFAULT_THEME_NAME, SYNTAX_HIGHLIGHTING_THEME: rawConfig['syntax-highlighting-theme'], }; diff --git a/src/previewTheme.ts b/src/previewTheme.ts index d20f553..298099f 100644 --- a/src/previewTheme.ts +++ b/src/previewTheme.ts @@ -6,6 +6,7 @@ import { Config } from './getConfig'; import { getContextForConfig } from './context'; import { loadTheme } from './themes'; import { transformContentsStreaming } from './transformContentsStreaming'; +import { DEFAULT_THEME_DIRECTORY } from './getGitConfig'; const CONFIG = { MIN_LINE_WIDTH: 40, @@ -13,8 +14,12 @@ const CONFIG = { HIGHLIGHT_LINE_CHANGES: true, }; -async function previewTheme(themeName: string, content: string) { - const theme = loadTheme(themeName); +async function previewTheme( + themeDirectory: string, + themeName: string, + content: string +) { + const theme = loadTheme(themeDirectory, themeName); const { rows, columns } = terminalSize(); const config: Config = { @@ -41,19 +46,22 @@ async function previewTheme(themeName: string, content: string) { } function main() { - if (process.argv.length !== 4) { - console.error(`Usage: ${process.argv[1]} `); + if (process.argv.length < 4) { + console.error( + `Usage: ${process.argv[1]} [theme directory]` + ); process.exit(1); } - const [, , sha, themeName] = process.argv; + const [, , sha, themeName, themeDirectory = DEFAULT_THEME_DIRECTORY] = + process.argv; const content = execSync(`git show ${sha}`).toString(); // Clear screen process.stdout.write('\x1bc'); - previewTheme(themeName, content); + previewTheme(themeDirectory, themeName, content); } main(); diff --git a/src/themes.ts b/src/themes.ts index afc592f..ed8ff83 100644 --- a/src/themes.ts +++ b/src/themes.ts @@ -1,14 +1,8 @@ import * as assert from 'assert'; import * as path from 'path'; import * as fs from 'fs'; -import { fileURLToPath } from 'url'; import * as shiki from 'shiki'; -const THEMES_DIR = path.resolve( - path.dirname(fileURLToPath(import.meta.url)), - '..', - 'themes' -); /** * Colors are always specified as hex strings */ @@ -165,14 +159,17 @@ export function parseColorDefinition(definition: ColorDefinition): ThemeColor { }; } -function loadThemeDefinition(themeName: string): ThemeDefinition { +function loadThemeDefinition( + themesDir: string, + themeName: string +): ThemeDefinition { return JSON.parse( - fs.readFileSync(path.join(THEMES_DIR, `${themeName}.json`)).toString() + fs.readFileSync(path.join(themesDir, `${themeName}.json`)).toString() ) as ThemeDefinition; } -export function loadTheme(themeName: string): Theme { - const themeDefinition = loadThemeDefinition(themeName); +export function loadTheme(themesDir: string, themeName: string): Theme { + const themeDefinition = loadThemeDefinition(themesDir, themeName); const theme: Partial = { SYNTAX_HIGHLIGHTING_THEME: themeDefinition.SYNTAX_HIGHLIGHTING_THEME,