From 00cfb98cca94fbebe6295a5a829c66e442e630f5 Mon Sep 17 00:00:00 2001 From: Patryk Rozanski Date: Wed, 5 Aug 2026 11:24:35 +0200 Subject: [PATCH] Add Emacs and Doom emacs theme plugin --- README.md | 22 +-- install.sh | 1 + tests/run.sh | 52 +++++ theme-set.d/30-emacs.sh | 424 ++++++++++++++++++++++++++++++++++++++++ uninstall.sh | 6 + 5 files changed, 494 insertions(+), 11 deletions(-) create mode 100755 theme-set.d/30-emacs.sh diff --git a/README.md b/README.md index 4dc6c6a..16b4854 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Inline themes in `config.kdl` are hot-reloaded by Zellij. If the active Omarchy **Browsers:** Firefox, Qutebrowser, Zen Browser -**Editors and writing:** Cursor, Obsidian Terminal plugin, Typora, VS Code, Windsurf, Zed +**Editors and writing:** Cursor, Obsidian Terminal plugin, Typora, VS Code, Windsurf, Zed, Emacs / Doom Emacs **Desktop and UI:** Discord clients using Vencord-compatible themes, optional Discord System24 theme, GTK apps, Hermes, nwg-dock-hyprland, Omarchy branding, Qt6 apps using qt6ct, SwayNC, Vicinae @@ -120,17 +120,17 @@ thpm update thpm remove ``` -| Command | What it does | -| --- | --- | -| `thpm list` | Show enabled and disabled plugins | -| `thpm enable ` | Enable a plugin | -| `thpm disable ` | Disable a plugin | -| `thpm doctor [name]` | Diagnose thpm setup and plugin theming issues | -| `thpm run` | Ask Omarchy to fire the `theme-set` hook now | +| Command | What it does | +| --------------------- | --------------------------------------------------------- | +| `thpm list` | Show enabled and disabled plugins | +| `thpm enable ` | Enable a plugin | +| `thpm disable ` | Disable a plugin | +| `thpm doctor [name]` | Diagnose thpm setup and plugin theming issues | +| `thpm run` | Ask Omarchy to fire the `theme-set` hook now | | `thpm install skills` | Install a bundled agent skill, currently for Codex/OpenAI | -| `thpm open` | Open the plugin directory | -| `thpm update` | Re-run the installer | -| `thpm remove` | Uninstall `thpm` | +| `thpm open` | Open the plugin directory | +| `thpm update` | Re-run the installer | +| `thpm remove` | Uninstall `thpm` | `thpm list` and `thpm help` may show a cached notice when a newer commit is available. They do not update files automatically; run `thpm update` to install updates. diff --git a/install.sh b/install.sh index 1b64167..ec2b131 100755 --- a/install.sh +++ b/install.sh @@ -47,6 +47,7 @@ bundled_plugins=( 30-cursor.sh 30-vscode.sh 30-windsurf.sh + 30-emacs.sh 35-obsidian-terminal.sh 40-cava.sh 40-firefox.sh diff --git a/tests/run.sh b/tests/run.sh index dfff560..6fa22fa 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -1898,6 +1898,54 @@ EOF assert_eq "#101112" "$(jq -r '.terminalOptions.theme.background' "$data_file")" "obsidian terminal plugin direct run loads theme env" } +test_emacs_plugin_skips_when_missing() { + local home_dir="$TMP_ROOT/emacs-missing-home" + local stub_bin="$TMP_ROOT/stub-bin" + local output + + mkdir -p "$stub_bin" + cp "$(command -v bash)" "$stub_bin/" + cp "$(command -v env)" "$stub_bin/" + write_colors_fixture "$home_dir" + + output="$(PATH="$stub_bin" XDG_CONFIG_HOME="$home_dir/.config" THPM_THEME_ENV="$ROOT_DIR/lib/theme-env.sh" HOME="$home_dir" "$ROOT_DIR/theme-set.d/30-emacs.sh")" + + assert_contains "$output" "Emacs not found" "emacs plugin skips cleanly when emacs is missing" +} + +test_emacs_plugin_generates_standard_emacs_theme() { + local home_dir="$TMP_ROOT/emacs-standard-home" + local emacs_dir="$home_dir/.config/emacs" + + write_colors_fixture "$home_dir" + mkdir -p "$emacs_dir" + + XDG_CONFIG_HOME="$home_dir/.config" THPM_THEME_ENV="$ROOT_DIR/lib/theme-env.sh" HOME="$home_dir" "$ROOT_DIR/theme-set.d/30-emacs.sh" >/dev/null + + assert_file_exists "$emacs_dir/omarchy-colors.el" "emacs plugin generates omarchy-colors.el" + assert_file_exists "$emacs_dir/themes/omarchy-theme.el" "emacs plugin generates omarchy-theme.el" + assert_file_exists "$emacs_dir/omarchy.el" "emacs plugin generates omarchy.el" + assert_contains "$(cat "$emacs_dir/omarchy-colors.el")" 'omarchy-color-bg "#101112"' "emacs plugin omarchy-colors.el uses primary background" + assert_contains "$(cat "$emacs_dir/themes/omarchy-theme.el")" "deftheme omarchy" "omarchy-theme.el defines omarchy theme" + assert_contains "$(cat "$emacs_dir/omarchy.el")" "omarchy-apply-theme" "omarchy.el defines omarchy-apply-theme" +} + +test_emacs_plugin_generates_doom_emacs_theme() { + local home_dir="$TMP_ROOT/emacs-doom-home" + local doom_dir="$home_dir/.config/doom" + + write_colors_fixture "$home_dir" + mkdir -p "$doom_dir" + + XDG_CONFIG_HOME="$home_dir/.config" THPM_THEME_ENV="$ROOT_DIR/lib/theme-env.sh" HOME="$home_dir" "$ROOT_DIR/theme-set.d/30-emacs.sh" >/dev/null + + assert_file_exists "$doom_dir/omarchy-colors.el" "emacs plugin generates omarchy-colors.el for Doom Emacs" + assert_file_exists "$doom_dir/themes/omarchy-theme.el" "emacs plugin generates omarchy-theme.el for Doom Emacs" + assert_file_exists "$doom_dir/omarchy.el" "emacs plugin generates omarchy.el for Doom Emacs" + assert_contains "$(cat "$doom_dir/themes/omarchy-theme.el")" "doom-modeline" "omarchy-theme.el includes Doom modeline faces" + assert_contains "$(cat "$doom_dir/omarchy.el")" "doom-theme" "omarchy.el includes Doom Emacs support" +} + test_foot_plugin_respects_disable_flag() { local home_dir="$TMP_ROOT/foot-disabled-home" local hook_dir="$home_dir/.config/omarchy/hooks/theme-set.d" @@ -3236,6 +3284,7 @@ print_coverage_summary() { "$ROOT_DIR/theme-set.d/25-swaync.sh" "$ROOT_DIR/theme-set.d/26-foot-live-colors.sh" "$ROOT_DIR/theme-set.d/35-obsidian-terminal.sh" + "$ROOT_DIR/theme-set.d/30-emacs.sh" "$ROOT_DIR/theme-set.d/30-vscode.sh" "$ROOT_DIR/theme-set.d/40-cava.sh" "$ROOT_DIR/theme-set.d/40-qutebrowser.sh" @@ -3525,6 +3574,9 @@ main() { test_fish_plugin_writes_shell_colors test_obsidian_terminal_plugin_discovers_registered_vault test_obsidian_terminal_plugin_direct_run_loads_theme_env + test_emacs_plugin_skips_when_missing + test_emacs_plugin_generates_standard_emacs_theme + test_emacs_plugin_generates_doom_emacs_theme test_foot_plugin_respects_disable_flag test_foot_plugin_logs_missing_theme_file test_foot_plugin_reads_theme_and_logs_no_ttys diff --git a/theme-set.d/30-emacs.sh b/theme-set.d/30-emacs.sh new file mode 100755 index 0000000..0b72cdc --- /dev/null +++ b/theme-set.d/30-emacs.sh @@ -0,0 +1,424 @@ +#!/usr/bin/env bash +source "${THPM_THEME_ENV:-$HOME/.local/share/thpm/lib/theme-env.sh}" + +# Emacs & Doom Emacs theme and font synchronization plugin for Omarchy. + +has_emacs_cmd=0 +command -v emacs >/dev/null 2>&1 && has_emacs_cmd=1 + +emacs_dirs=() +doom_dirs=() + +for dir in "$HOME/.config/emacs" "$HOME/.emacs.d"; do + if [[ -d "$dir" ]]; then + emacs_dirs+=("$dir") + fi +done + +for dir in "$HOME/.config/doom" "$HOME/.doom.d"; do + if [[ -d "$dir" ]]; then + doom_dirs+=("$dir") + fi +done + +if [[ $has_emacs_cmd -eq 0 && ${#emacs_dirs[@]} -eq 0 && ${#doom_dirs[@]} -eq 0 ]]; then + skipped "Emacs" +fi + +if [[ -z "${primary_background:-}" || -z "${primary_foreground:-}" ]]; then + if declare -F skipped >/dev/null 2>&1; then + skipped "Emacs theme colors" + fi + exit 0 +fi + +target_dirs=() +if [[ ${#emacs_dirs[@]} -gt 0 ]]; then + for dir in "${emacs_dirs[@]}"; do + target_dirs+=("$dir") + done +fi + +if [[ ${#doom_dirs[@]} -gt 0 ]]; then + for dir in "${doom_dirs[@]}"; do + target_dirs+=("$dir") + done +fi + +if [[ ${#target_dirs[@]} -eq 0 ]]; then + target_dirs+=("${XDG_CONFIG_HOME:-$HOME/.config}/emacs") +fi + +accent_color="${normal_blue:-$primary_foreground}" +cursor_col="${cursor_color:-$primary_foreground}" +sel_fg="${selection_foreground:-$primary_background}" +sel_bg="${selection_background:-$normal_blue}" + +light_mode="nil" +if [[ -f "${THPM_LIGHT_MODE_FILE:-}" ]] || [[ "${mode:-}" == "light" ]]; then + light_mode="t" +fi + +for target_dir in "${target_dirs[@]}"; do + mkdir -p "$target_dir/themes" + + cat > "$target_dir/omarchy-colors.el" < "$target_dir/themes/omarchy-theme.el" <<'EOF' +;;; omarchy-theme.el --- Omarchy theme synced from system colors -*- lexical-binding: t -*- + +(deftheme omarchy "Omarchy theme synced from system colors.") + +(require 'omarchy-colors nil t) + +(let* ((light (if (boundp 'omarchy-is-light) omarchy-is-light + (or (file-exists-p "~/.local/state/omarchy/current/theme/light.mode") + (file-exists-p "~/.config/omarchy/current/theme/light.mode")))) + (highlight-bg (if light omarchy-color-bright-white omarchy-color-bright-black)) + (mode-line-inactive-bg (if light omarchy-color-bright-white omarchy-color-black)) + (line-number-fg (if light omarchy-color-bright-black omarchy-color-blue)) + (variable-name-fg (if light omarchy-color-black omarchy-color-bright-white)) + (completions-first-fg (if light omarchy-color-black omarchy-color-bright-white)) + (comment-attrs (if light + `(:foreground ,omarchy-color-bright-black) + `(:foreground ,omarchy-color-bright-blue :slant italic)))) + (custom-theme-set-faces + 'omarchy + + ;; Core faces + `(default ((t (:foreground ,omarchy-color-fg :background ,omarchy-color-bg)))) + `(cursor ((t (:background ,omarchy-color-cursor)))) + `(region ((t (:foreground ,omarchy-color-sel-fg :background ,omarchy-color-sel-bg)))) + `(highlight ((t (:background ,highlight-bg)))) + `(fringe ((t (:background ,omarchy-color-bg)))) + `(vertical-border ((t (:foreground ,omarchy-color-bright-black)))) + + ;; Mode line (Standard Emacs) + `(mode-line ((t (:foreground ,omarchy-color-bg :background ,omarchy-color-accent :box nil)))) + `(mode-line-inactive ((t (:foreground ,omarchy-color-bright-black :background ,mode-line-inactive-bg :box nil)))) + `(mode-line-buffer-id ((t (:weight bold)))) + + ;; Doom Modeline & Doom Themes support + `(doom-modeline-bar ((t (:background ,omarchy-color-accent)))) + `(doom-modeline-inactive-bar ((t (:background ,omarchy-color-bright-black)))) + `(doom-modeline-panel ((t (:foreground ,omarchy-color-bg :background ,omarchy-color-accent)))) + `(doom-modeline-buffer-file ((t (:foreground ,omarchy-color-fg :weight bold)))) + `(doom-modeline-buffer-path ((t (:foreground ,omarchy-color-blue :weight bold)))) + `(doom-modeline-buffer-project-root ((t (:foreground ,omarchy-color-green)))) + `(doom-modeline-buffer-modified ((t (:foreground ,omarchy-color-yellow :weight bold)))) + `(doom-modeline-buffer-major-mode ((t (:foreground ,omarchy-color-magenta :weight bold)))) + `(doom-modeline-info ((t (:foreground ,omarchy-color-green)))) + `(doom-modeline-warning ((t (:foreground ,omarchy-color-yellow)))) + `(doom-modeline-urgent ((t (:foreground ,omarchy-color-red)))) + `(doom-themes-visual-bell ((t (:background ,omarchy-color-red)))) + + ;; Line numbers + `(line-number ((t (:foreground ,line-number-fg :background ,omarchy-color-bg)))) + `(line-number-current-line ((t (:foreground ,omarchy-color-accent :background ,omarchy-color-bg :weight bold)))) + + ;; Minibuffer / prompts / vertico / selectrum / ivy + `(minibuffer-prompt ((t (:foreground ,omarchy-color-accent :weight bold)))) + `(vertico-current ((t (:foreground ,omarchy-color-sel-fg :background ,omarchy-color-sel-bg :weight bold)))) + `(selectrum-current-match ((t (:foreground ,omarchy-color-sel-fg :background ,omarchy-color-sel-bg :weight bold)))) + `(ivy-current-match ((t (:foreground ,omarchy-color-sel-fg :background ,omarchy-color-sel-bg :weight bold)))) + + ;; Search + `(isearch ((t (:foreground ,omarchy-color-bg :background ,omarchy-color-yellow)))) + `(lazy-highlight ((t (:foreground ,omarchy-color-bg :background ,omarchy-color-bright-yellow)))) + + ;; Font lock (syntax highlighting) + `(font-lock-keyword-face ((t (:foreground ,omarchy-color-magenta)))) + `(font-lock-function-name-face ((t (:foreground ,omarchy-color-blue)))) + `(font-lock-function-call-face ((t (:foreground ,omarchy-color-blue)))) + `(font-lock-variable-name-face ((t (:foreground ,variable-name-fg)))) + `(font-lock-string-face ((t (:foreground ,omarchy-color-green)))) + `(font-lock-comment-face ((t ,comment-attrs))) + `(font-lock-comment-delimiter-face ((t ,comment-attrs))) + `(font-lock-type-face ((t (:foreground ,omarchy-color-yellow)))) + `(font-lock-constant-face ((t (:foreground ,omarchy-color-white)))) + `(font-lock-builtin-face ((t (:foreground ,omarchy-color-cyan)))) + `(font-lock-preprocessor-face ((t (:foreground ,omarchy-color-red)))) + `(font-lock-warning-face ((t (:foreground ,omarchy-color-red :weight bold)))) + `(font-lock-doc-face ((t (:foreground ,omarchy-color-bright-green)))) + `(font-lock-number-face ((t (:foreground ,omarchy-color-white)))) + `(font-lock-negation-char-face ((t (:foreground ,omarchy-color-red)))) + `(font-lock-operator-face ((t (:foreground ,omarchy-color-cyan)))) + + ;; Parentheses + `(show-paren-match ((t (:foreground ,omarchy-color-bg :background ,omarchy-color-accent :weight bold)))) + `(show-paren-mismatch ((t (:foreground ,omarchy-color-bg :background ,omarchy-color-red :weight bold)))) + + ;; Completion + `(completions-common-part ((t (:foreground ,omarchy-color-accent)))) + `(completions-first-difference ((t (:foreground ,completions-first-fg :weight bold)))) + + ;; Links + `(link ((t (:foreground ,omarchy-color-cyan :underline t)))) + `(link-visited ((t (:foreground ,omarchy-color-magenta :underline t)))) + + ;; Errors / warnings + `(error ((t (:foreground ,omarchy-color-red :weight bold)))) + `(warning ((t (:foreground ,omarchy-color-yellow :weight bold)))) + `(success ((t (:foreground ,omarchy-color-green :weight bold)))) + + ;; Org mode + `(org-level-1 ((t (:foreground ,omarchy-color-blue :weight bold :height 1.1)))) + `(org-level-2 ((t (:foreground ,omarchy-color-magenta :weight bold)))) + `(org-level-3 ((t (:foreground ,omarchy-color-cyan :weight bold)))) + `(org-level-4 ((t (:foreground ,omarchy-color-yellow)))) + `(org-code ((t (:foreground ,omarchy-color-green)))) + `(org-verbatim ((t (:foreground ,omarchy-color-white)))) + `(org-link ((t (:foreground ,omarchy-color-cyan :underline t)))) + `(org-done ((t (:foreground ,omarchy-color-green :weight bold)))) + `(org-todo ((t (:foreground ,omarchy-color-red :weight bold)))) + + ;; Treemacs + `(treemacs-directory-face ((t (:foreground ,omarchy-color-blue)))) + `(treemacs-file-face ((t (:foreground ,omarchy-color-fg)))) + `(treemacs-git-modified-face ((t (:foreground ,omarchy-color-yellow)))) + + ;; Diff / ediff + `(diff-added ((t (:foreground ,omarchy-color-green :background unspecified)))) + `(diff-removed ((t (:foreground ,omarchy-color-red :background unspecified)))) + `(diff-header ((t (:foreground ,omarchy-color-cyan :weight bold)))) + `(diff-file-header ((t (:foreground ,omarchy-color-blue :weight bold)))))) + +(provide-theme 'omarchy) +;;; omarchy-theme.el ends here +EOF + + cat > "$target_dir/omarchy.el" <<'EOF' +;;; omarchy.el --- Omarchy Emacs & Doom Emacs integration -*- lexical-binding: t -*- + +(require 'subr-x) +(require 'cl-lib) + +;; Add theme directories to custom-theme-load-path (do not add user-emacs-directory to load-path) +(let ((cfg-dir (or (bound-and-true-p doom-user-dir) + (bound-and-true-p user-emacs-directory) + (file-name-directory (or load-file-name buffer-file-name "~/.config/emacs/omarchy.el"))))) + (when (and cfg-dir (file-directory-p cfg-dir)) + (let ((themes-dir (expand-file-name "themes" cfg-dir))) + (when (file-directory-p themes-dir) + (add-to-list 'custom-theme-load-path themes-dir))))) + +(dolist (d '("~/.config/emacs/themes" "~/.emacs.d/themes" "~/.config/doom/themes" "~/.doom.d/themes")) + (let ((expanded (expand-file-name d))) + (when (file-directory-p expanded) + (add-to-list 'custom-theme-load-path expanded)))) + +(defun omarchy-light-theme-p () + "Return non-nil if the current Omarchy theme is a light theme." + (or (bound-and-true-p omarchy-is-light) + (file-exists-p "~/.local/state/omarchy/current/theme/light.mode") + (file-exists-p "~/.config/omarchy/current/theme/light.mode"))) + +(defun omarchy-apply-theme () + "Load Omarchy colors and apply them as an Emacs / Doom Emacs theme." + (interactive) + (let* ((cfg-dir (or (bound-and-true-p doom-user-dir) + (bound-and-true-p user-emacs-directory) + "~/.config/emacs")) + (colors-file (or (locate-file "omarchy-colors.el" custom-theme-load-path '(".el")) + (expand-file-name "omarchy-colors.el" cfg-dir) + (expand-file-name "omarchy-colors.el" "~/.emacs.d")))) + (when (and colors-file (file-exists-p colors-file)) + (load-file colors-file))) + (dolist (theme '(omarchy omarchy-dark omarchy-light)) + (disable-theme theme) + (put theme 'theme-settings nil) + (setq custom-known-themes (delq theme custom-known-themes))) + (let ((theme-file (locate-file "omarchy-theme" custom-theme-load-path '(".el")))) + (when theme-file + (load-file theme-file))) + (enable-theme 'omarchy) + (when (boundp 'doom-theme) + (setq doom-theme 'omarchy)) + (when (fboundp 'doom-modeline-refresh-bars) + (ignore-errors (doom-modeline-refresh-bars)))) + +(defun omarchy--match-in-file (file regex &optional group) + (let ((path (expand-file-name file))) + (when (file-readable-p path) + (with-temp-buffer + (insert-file-contents path) + (goto-char (point-min)) + (when (re-search-forward regex nil t) + (match-string (or group 1))))))) + +(defun omarchy--current-terminal () + (let* ((dirs '("~/.local/share/applications" "/usr/share/applications" "/usr/local/share/applications")) + (installed (lambda (entry) + (and (stringp entry) (not (string-empty-p entry)) + (cl-some (lambda (d) (file-exists-p (expand-file-name entry d))) dirs)))) + (list-file (expand-file-name "~/.config/xdg-terminals.list")) + (entries (when (file-readable-p list-file) + (with-temp-buffer + (insert-file-contents list-file) + (mapcar (lambda (l) (string-trim (replace-regexp-in-string "#.*" "" l))) + (split-string (buffer-string) "\n"))))) + (entry (or (cl-find-if installed entries) + (cl-find-if installed '("com.mitchellh.ghostty.desktop" "kitty.desktop" "Alacritty.desktop"))))) + (when entry + (cond + ((string-match-p "[Aa]lacritty" entry) 'alacritty) + ((string-match-p "kitty" entry) 'kitty) + ((string-match-p "ghostty" entry) 'ghostty))))) + +(defun omarchy--terminal-font-size () + (pcase (omarchy--current-terminal) + ('alacritty + (let ((file (expand-file-name "~/.config/alacritty/alacritty.toml"))) + (when (file-readable-p file) + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (when (re-search-forward "^\\[font\\][ \t]*$" nil t) + (let ((bound (or (save-excursion (when (re-search-forward "^\\[" nil t) (match-beginning 0))) (point-max)))) + (when (re-search-forward "^size[ \t]*=[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)" bound t) + (match-string 1)))))))) + ('kitty (omarchy--match-in-file "~/.config/kitty/kitty.conf" "^font_size[ \t]+\\([0-9]+\\(?:\\.[0-9]+\\)?\\)")) + ('ghostty (omarchy--match-in-file "~/.config/ghostty/config" "^font-size[ \t]*=[ \t]*\\([0-9]+\\(?:\\.[0-9]+\\)?\\)")))) + +(defun omarchy--terminal-font-family () + (pcase (omarchy--current-terminal) + ('alacritty + (let ((file (expand-file-name "~/.config/alacritty/alacritty.toml"))) + (when (file-readable-p file) + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (when (re-search-forward "^\\[font\\][ \t]*$" nil t) + (let ((bound (or (save-excursion (when (re-search-forward "^\\[" nil t) (match-beginning 0))) (point-max)))) + (when (re-search-forward "family[ \t]*=[ \t]*[\"']\\([^\"']+\\)[\"']" bound t) + (match-string 1)))))))) + ('kitty (omarchy--match-in-file "~/.config/kitty/kitty.conf" "^font_family[ \t]+\\(.+?\\)[ \t]*$")) + ('ghostty (omarchy--match-in-file "~/.config/ghostty/config" "^font-family[ \t]*=[ \t]*[\"']?\\([^\"'\n]+?\\)[\"']?[ \t]*$" )) + ('foot (omarchy--match-in-file "~/.config/foot/foot.ini" "^font[ \t]*=[ \t]*\\([^:\n]+\\)")))) + +(defun omarchy-current-font () + (or (let ((fam (omarchy--terminal-font-family))) + (and fam (setq fam (string-trim fam)) (not (string-empty-p fam)) fam)) + (and (executable-find "omarchy-font-current") + (let ((f (string-trim (shell-command-to-string "omarchy-font-current")))) + (and (not (string-empty-p f)) f))) + (omarchy--match-in-file "~/.config/waybar/style.css" "font-family:[ \t]*[\"']?\\([^;\"'\n]+\\)") + "")) + +(defun omarchy-current-font-size () + (let ((size (omarchy--terminal-font-size))) + (round (* (if size (string-to-number size) 12.0) 10)))) + +(defun omarchy-apply-font () + "Set default font for standard Emacs & Doom Emacs." + (let ((font (omarchy-current-font)) + (pt (/ (omarchy-current-font-size) 10.0))) + (when (and font (not (string-empty-p font))) + (let ((spec + (if (featurep 'pgtk) + (format "%s:pixelsize=%d" font (max 1 (round (* pt (/ 96.0 72.0))))) + (let ((s (string-to-number + (string-trim + (shell-command-to-string + "hyprctl monitors 2>/dev/null | grep -oP 'scale:\\s*\\K[0-9]+\\.?[0-9]*' | head -1"))))) + (format "%s-%g" font (* pt (if (or (zerop s) (< s 1)) 1.0 s))))))) + (set-face-attribute 'default nil :font spec) + (dolist (frame (frame-list)) + (when (display-graphic-p frame) + (set-frame-font spec nil (list frame)))) + (setf (alist-get 'font default-frame-alist) spec) + (when (boundp 'doom-font) + (setq doom-font (font-spec :family font :size pt))))))) + +(unless (boundp 'doom-version) + (menu-bar-mode -1) + (tool-bar-mode -1) + (scroll-bar-mode -1) + (set-frame-parameter nil 'internal-border-width 8) + (add-to-list 'default-frame-alist '(internal-border-width . 8))) + +(omarchy-apply-theme) +(omarchy-apply-font) + +(provide 'omarchy) +;;; omarchy.el ends here +EOF + + # Cleanly load omarchy without adding user-emacs-directory to load-path + if [[ "$target_dir" == *doom* ]]; then + config_file="$target_dir/config.el" + if [[ ! -f "$config_file" ]]; then + cat > "$config_file" <<'EOF' +;;; config.el --- Doom Emacs configuration -*- lexical-binding: t -*- + +;; Load Omarchy theme and font integration +(let ((omarchy-file (expand-file-name "omarchy.el" (or (bound-and-true-p doom-user-dir) "~/.config/doom")))) + (when (file-exists-p omarchy-file) + (load omarchy-file nil t))) +EOF + elif ! grep -Fq "omarchy" "$config_file"; then + sed -i '/add-to-list '\''load-path dir/d' "$config_file" 2>/dev/null || true + printf '\n;; Load Omarchy integration\n(let ((omarchy-file (expand-file-name "omarchy.el" (or (bound-and-true-p doom-user-dir) "~/.config/doom"))))\n (when (file-exists-p omarchy-file)\n (load omarchy-file nil t)))\n' >> "$config_file" + fi + else + init_file="$target_dir/init.el" + cat > "$init_file" <<'EOF' +;;; init.el --- Emacs initialisation -*- lexical-binding: t -*- + +;; Load Omarchy theme and font integration +(let ((omarchy-file (expand-file-name "omarchy.el" (or (bound-and-true-p user-emacs-directory) "~/.config/emacs")))) + (when (file-exists-p omarchy-file) + (load omarchy-file nil t))) + +;; Add your personal customizations below this line +EOF + fi + +done + +if command -v emacsclient >/dev/null 2>&1 && emacsclient --eval t >/dev/null 2>&1; then + emacsclient --no-wait --eval \ + "(progn + (dolist (dir '(\"~/.config/emacs\" \"~/.emacs.d\" \"~/.config/doom\" \"~/.doom.d\")) + (let ((f (expand-file-name \"omarchy.el\" (expand-file-name dir)))) + (when (file-exists-p f) (load-file f)))) + (when (fboundp 'omarchy-apply-theme) (omarchy-apply-theme)) + (when (fboundp 'omarchy-apply-font) (omarchy-apply-font)))" >/dev/null 2>&1 || true + success "Emacs theme updated!" +else + require_restart "emacs" "Emacs" + success "Emacs theme files generated!" +fi diff --git a/uninstall.sh b/uninstall.sh index 616364f..9c92e9a 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -57,6 +57,7 @@ bundled_plugins=( 25-swaync.sh 26-foot-live-colors.sh 30-cursor.sh + 30-emacs.sh 30-vscode.sh 30-windsurf.sh 35-obsidian-terminal.sh @@ -120,6 +121,11 @@ fi # Remove Hermes theme rm -f "$HOME/.config/Hermes/omarchy-theme.json" +# Remove Emacs / Doom Emacs generated theme files +for dir in "$HOME/.config/emacs" "$HOME/.emacs.d" "$HOME/.config/doom" "$HOME/.doom.d"; do + rm -f "$dir/omarchy-colors.el" "$dir/themes/omarchy-colors.el" +done + # Remove Vicinae theme if command -v vicinae >/dev/null 2>&1; then vicinae theme set vicinae-dark > /dev/null 2>&1 || true