Files
dotfiles/rider-palette/.config/rider-palette/generate.py

240 lines
8.7 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import json
from pathlib import Path
from textwrap import dedent
ROOT = Path(__file__).resolve().parent
PALETTE_FILE = ROOT / "palette.json"
def load_palette() -> dict[str, str]:
data = json.loads(PALETTE_FILE.read_text())
return data["colors"]
def hex_no_hash(value: str) -> str:
return value.lstrip("#")
def camel_from_snake(name: str) -> str:
head, *tail = name.split("_")
return head + "".join(part.capitalize() for part in tail)
def write(path: Path, content: str) -> None:
path.write_text(content.rstrip() + "\n")
def render_palette_sh(colors: dict[str, str]) -> str:
lines = [
"# Generated from palette.json by generate.py. Do not edit directly.",
"",
]
for name, value in colors.items():
lines.append(f'export RIDER_{name.upper()}="{value}"')
return "\n".join(lines)
def render_palette_css(colors: dict[str, str]) -> str:
lines = [
"/* Generated from palette.json by generate.py. Do not edit directly. */",
":root {",
]
for name, value in colors.items():
lines.append(f" --rider-{name.replace('_', '-')}: {value};")
lines.append("}")
lines.append("")
for name, value in colors.items():
lines.append(f"@define-color rider-{name.replace('_', '-')} {value};")
return "\n".join(lines)
def render_palette_hypr(colors: dict[str, str]) -> str:
lines = [
"# Generated from palette.json by generate.py. Do not edit directly.",
"# Usage:",
"# source = ~/.config/rider-palette/palette.hyprland.conf",
"",
]
for name, value in colors.items():
lines.append(f"${name} = rgb({hex_no_hash(value)})")
lines.append(f"${camel_from_snake(name)}Alpha = {hex_no_hash(value)}")
return "\n".join(lines)
def render_palette_rasi(colors: dict[str, str]) -> str:
lines = [
"/* Generated from palette.json by generate.py. Do not edit directly. */",
"* {",
]
for name, value in colors.items():
lines.append(f" rider-{name.replace('_', '-')}: {value};")
lines.append("}")
return "\n".join(lines)
def render_tmux_conf(colors: dict[str, str]) -> str:
return dedent(
f"""
# Generated from palette.json by generate.py. Do not edit directly.
# Source this near the end of ~/.tmux.conf, after plugin/theme setup.
set -g status-style "bg={colors['bg']},fg={colors['fg_bright']}"
set -g status-left-style "bg={colors['bg']},fg={colors['fg_bright']}"
set -g status-right-style "bg={colors['bg']},fg={colors['fg_bright']}"
set -g message-style "bg={colors['cursor_line']},fg={colors['fg_bright']}"
set -g message-command-style "bg={colors['cursor_line']},fg={colors['fg_bright']}"
set -g mode-style "bg={colors['selection']},fg={colors['fg_bright']}"
set -g pane-border-style "fg={colors['border']}"
set -g pane-active-border-style "fg={colors['keyword']}"
set -g clock-mode-colour "{colors['keyword']}"
set -g window-status-style "bg={colors['bg']},fg={colors['fg_gutter']}"
set -g window-status-current-style "bg={colors['cursor_line']},fg={colors['fg_bright']}"
set -g window-status-current-format "#[fg={colors['func']},bg={colors['cursor_line']},bold] #I #W "
set -g window-status-format "#[fg={colors['fg_gutter']},bg={colors['bg']}] #I #W "
"""
).strip()
def render_bash_prompt() -> str:
return dedent(
"""
# Generated from palette.json by generate.py. Do not edit directly.
# Rider-colored bash prompt using the shared palette.
# shellcheck shell=bash
if [ -r "$HOME/.config/rider-palette/palette.sh" ]; then
. "$HOME/.config/rider-palette/palette.sh"
fi
rider_fg() {
local hex="${1#\\#}"
printf '\\[\\033[38;2;%d;%d;%dm\\]' "$((16#${hex:0:2}))" "$((16#${hex:2:2}))" "$((16#${hex:4:2}))"
}
RIDER_RESET='\\[\\033[0m\\]'
__rider_git_branch() {
command -v git >/dev/null 2>&1 || return 0
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
local branch
branch="$(git symbolic-ref --quiet --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)" || return 0
[ -n "$branch" ] || return 0
printf ' %sgit:%s%s' "$(rider_fg "$RIDER_FUNC")" "$branch" "$RIDER_RESET"
}
__rider_set_bash_prompt() {
PS1="${debian_chroot:+($debian_chroot)}$(rider_fg "$RIDER_FG_BRIGHT")\\u@\\h${RIDER_RESET}$(rider_fg "$RIDER_BORDER"):$(rider_fg "$RIDER_KEYWORD")\\w${RIDER_RESET}$(__rider_git_branch)$(rider_fg "$RIDER_BORDER") \\\\$ ${RIDER_RESET}"
}
PROMPT_COMMAND=__rider_set_bash_prompt
"""
).strip()
def render_p10k_zsh() -> str:
return dedent(
"""
# Generated from palette.json by generate.py. Do not edit directly.
# Rider-colored Powerlevel10k overrides using the shared palette.
[[ -r "$HOME/.config/rider-palette/palette.sh" ]] && source "$HOME/.config/rider-palette/palette.sh"
typeset -g POWERLEVEL9K_BACKGROUND="$RIDER_BG"
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX="%F{$RIDER_BORDER}╭─%f"
typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_PREFIX="%F{$RIDER_BORDER}├─%f"
typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX="%F{$RIDER_BORDER}╰─%f"
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_SUFFIX="%F{$RIDER_BORDER}─╮%f"
typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_SUFFIX="%F{$RIDER_BORDER}─┤%f"
typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_SUFFIX="%F{$RIDER_BORDER}─╯%f"
typeset -g POWERLEVEL9K_LEFT_SUBSEGMENT_SEPARATOR="%F{$RIDER_BORDER}\\uE0B1%f"
typeset -g POWERLEVEL9K_RIGHT_SUBSEGMENT_SEPARATOR="%F{$RIDER_BORDER}\\uE0B3%f"
typeset -g POWERLEVEL9K_OS_ICON_FOREGROUND="$RIDER_FG_BRIGHT"
typeset -g POWERLEVEL9K_DIR_FOREGROUND="$RIDER_KEYWORD"
typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND="$RIDER_TYPE"
typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND="$RIDER_FUNC"
typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_COLOR="$RIDER_FUNC"
typeset -g POWERLEVEL9K_VCS_LOADING_VISUAL_IDENTIFIER_COLOR="$RIDER_BORDER"
typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND="$RIDER_FUNC"
typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND="$RIDER_FIELD"
typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND="$RIDER_NUMBER"
typeset -g POWERLEVEL9K_STATUS_OK_FOREGROUND="$RIDER_FUNC"
typeset -g POWERLEVEL9K_STATUS_OK_PIPE_FOREGROUND="$RIDER_FUNC"
typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND="$RIDER_ERROR"
typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_FOREGROUND="$RIDER_ERROR"
typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_FOREGROUND="$RIDER_ERROR"
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND="$RIDER_STRING"
typeset -g POWERLEVEL9K_TIME_FOREGROUND="$RIDER_FIELD"
typeset -g POWERLEVEL9K_DOTNET_VERSION_FOREGROUND="$RIDER_TYPE"
typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND="$RIDER_FG_BRIGHT"
"""
).strip()
def render_readme() -> str:
return dedent(
"""
# Rider Palette Reuse
`palette.json` is the single source of truth for your shared Rider palette.
Regenerate all derived files with:
```bash
python3 ~/.config/rider-palette/generate.py
```
Generated outputs:
- `palette.sh`: shell env vars for prompts and scripts
- `palette.css`: CSS variables for Waybar and Wofi
- `palette.hyprland.conf`: Hyprlang variables for Hyprland and Hyprlock
- `palette.rasi`: Rasi variables for Rofi
- `tmux.conf`: tmux status and pane colors
- `bash-prompt.sh`: bash prompt using the shared palette
- `p10k.zsh`: Powerlevel10k overrides using the shared palette
This package is meant to be stowed from the dotfiles repo so that
`~/.config/rider-palette/*` becomes available to the rest of the system.
"""
).strip()
def main() -> None:
colors = load_palette()
outputs = {
ROOT / "palette.sh": render_palette_sh(colors),
ROOT / "palette.css": render_palette_css(colors),
ROOT / "palette.hyprland.conf": render_palette_hypr(colors),
ROOT / "palette.rasi": render_palette_rasi(colors),
ROOT / "tmux.conf": render_tmux_conf(colors),
ROOT / "bash-prompt.sh": render_bash_prompt(),
ROOT / "p10k.zsh": render_p10k_zsh(),
ROOT / "README.md": render_readme(),
}
for path, content in outputs.items():
write(path, content)
if __name__ == "__main__":
main()