From 2fb1571ce0773494da81d2112e815a8c85311bc6 Mon Sep 17 00:00:00 2001 From: Max Amundsen Date: Sat, 27 Dec 2025 00:45:43 -0500 Subject: [PATCH] emac --- .emacs.d/init.el | 2310 +++++++++++++++--------------- .emacs.d/themes/bedroom-theme.el | 8 +- .emacs.d/themes/focus-theme.el | 140 ++ .emacs.d/themes/jbeans-theme.el | 442 ------ .emacs.d/themes/valigo-theme.el | 152 ++ 5 files changed, 1485 insertions(+), 1567 deletions(-) create mode 100644 .emacs.d/themes/focus-theme.el delete mode 100644 .emacs.d/themes/jbeans-theme.el create mode 100644 .emacs.d/themes/valigo-theme.el diff --git a/.emacs.d/init.el b/.emacs.d/init.el index c248b0d..b3232bc 100755 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -1,1123 +1,1187 @@ -;; Max's init.el -*- lexical-binding: t; -*- - -;;; ============================================================================ -;;; PACKAGE LOADING & LOAD PATHS -;;; ============================================================================ - -(add-to-list 'load-path "~/.emacs.d/lisp/") - -(let ((default-directory "~/.emacs.d/lisp/")) - (normal-top-level-add-subdirs-to-load-path)) - -;; Core libraries -(require 's) -(require 'dash) -(require 'popup) - -;; Completion framework -(require 'ivy) -(require 'counsel) - -;; Language modes -(require 'yaml-mode) -(require 'dockerfile-mode) -(require 'go-mode) -(require 'jai-mode) -(require 'simpc-mode) - -;; Editing enhancements -(require 'stupid-indent-mode) -(require 'multiple-cursors) -(require 'vundo) - -;; Navigation -(require 'dumb-jump) -(require 'eglot) - -;; Search -(require 'xah-find) - -;;; ============================================================================ -;;; MODE ASSOCIATIONS -;;; ============================================================================ - -(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)) -(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode)) -(add-to-list 'auto-mode-alist '("\\.jai\\'" . jai-mode)) -(add-to-list 'auto-mode-alist '("\\.[hc]\\(pp\\)?\\'" . simpc-mode)) - -;;; ============================================================================ -;;; IVY & COMPLETION FRAMEWORK -;;; ============================================================================ - -(ivy-mode 1) -(setq ivy-use-virtual-buffers t) -(setq ivy-count-format "(%d/%d) ") -(setq ivy-wrap t) - -;;; ============================================================================ -;;; XREF, CTAGS & NAVIGATION -;;; ============================================================================ - -;; dumb-jump as fallback for xref -(setq dumb-jump-force-searcher 'grep) -(setq dumb-jump-selector 'ivy) -(setq xref-show-definitions-function #'xref-show-definitions-completing-read) -(setq tags-revert-without-query t) -(add-hook 'xref-backend-functions #'dumb-jump-xref-activate 100) - -;;; ============================================================================ -;;; EGLOT (LSP) CONFIGURATION -;;; ============================================================================ - -;; When eglot is active, xref commands (F12, M-f12) automatically use LSP -;; instead of CTAGS. Eglot registers itself as a higher-priority xref backend. - -(setq eglot-autoshutdown t) ; shutdown server when last buffer is closed -(setq eglot-confirm-server-initiated-edits nil) ; don't ask for confirmation on renames - -;; disable LSP visual indicators but keep diagnostics available -(add-to-list 'eglot-ignored-server-capabilities :documentHighlightProvider) - -;; Go: auto-start eglot (requires gopls: go install golang.org/x/tools/gopls@latest) -(add-hook 'go-mode-hook 'eglot-ensure) - -;; auto-confirm "modified buffer" prompts when jumping from diagnostics -(defun my-auto-confirm-modified-buffer (orig-fun prompt) - "Auto-confirm prompts about modified buffers having wrong location." - (if (string-match-p "has been modified.*wrong location" prompt) - t - (funcall orig-fun prompt))) -(advice-add 'y-or-n-p :around #'my-auto-confirm-modified-buffer) - -(defun my-lsp-find-workspace-symbol () - "Interactively search for symbols in workspace using LSP." - (interactive) - (if (eglot-managed-p) - (let ((server (eglot-current-server)) - (root (project-root (project-current)))) - (ivy-read "Symbol: " - (lambda (input) - (when (and input (>= (length input) 1)) - (condition-case nil - (let* ((resp (jsonrpc-request server :workspace/symbol - `(:query ,input))) - (items (append resp nil))) - (delq nil - (mapcar (lambda (item) - (condition-case nil - (let* ((name (plist-get item :name)) - (loc (plist-get item :location)) - (uri (plist-get loc :uri)) - (range (plist-get loc :range)) - (start (plist-get range :start)) - (line (1+ (plist-get start :line))) - (file (eglot-uri-to-path uri)) - (rel-path (file-relative-name file root))) - (propertize (format "%s %s:%d" name rel-path line) - 'file file - 'line line)) - (error nil))) - items))) - (error nil)))) - :dynamic-collection t - :require-match t - :action (lambda (candidate) - (when (and candidate (get-text-property 0 'file candidate)) - (find-file (get-text-property 0 'file candidate)) - (goto-char (point-min)) - (forward-line (1- (get-text-property 0 'line candidate))))))) - (call-interactively 'xref-find-apropos))) - -;;; ============================================================================ -;;; FLYMAKE & DIAGNOSTICS -;;; ============================================================================ - -;; hide squiggly underlines -(set-face-attribute 'flymake-error nil :underline nil) -(set-face-attribute 'flymake-warning nil :underline nil) -(set-face-attribute 'flymake-note nil :underline nil) - -;; hide fringe indicators -(setq flymake-fringe-indicator-position nil) - -(defun my-flymake-show-project-errors-warnings () - "Show project diagnostics, filtering out notes (only errors and warnings)." - (interactive) - ;; Kill existing diagnostics buffer to force refresh - (when-let ((buf (get-buffer "*Flymake diagnostics*"))) - (kill-buffer buf)) - ;; Refresh flymake on all project buffers - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (and (bound-and-true-p flymake-mode) - (buffer-file-name)) - (flymake-start)))) - (flymake-show-project-diagnostics) - (run-at-time 0.1 nil - (lambda () - (when-let ((buf (get-buffer "*Flymake diagnostics*"))) - (with-current-buffer buf - (let ((inhibit-read-only t)) - (goto-char (point-min)) - (while (not (eobp)) - (if (looking-at ".*\\bnote\\b.*$") - (delete-region (line-beginning-position) (1+ (line-end-position))) - (forward-line 1))))))))) - -;;; ============================================================================ -;;; MULTIPLE CURSORS -;;; ============================================================================ - -(setq mc/always-run-for-all t) -(define-key mc/keymap (kbd "") 'mc/keyboard-quit) -(define-key mc/keymap (kbd "") nil) - -;;; ============================================================================ -;;; INDENTATION SETTINGS -;;; ============================================================================ - -;; default indentation -(setq-default indent-tabs-mode t) -(setq-default tab-width 4) -(setq-default stupid-indent-level 4) -(add-hook 'text-mode-hook 'stupid-indent-mode) -(add-hook 'prog-mode-hook 'stupid-indent-mode) - -;; per-language indentation (indent-tabs-mode: t = tabs, nil = spaces) -(add-hook 'go-mode-hook (lambda () - (setq-local indent-tabs-mode t) - (setq-local tab-width 4) - (setq-local stupid-indent-level 4))) - -(add-hook 'jai-mode-hook (lambda () - (setq-local indent-tabs-mode nil) - (setq-local tab-width 4) - (setq-local stupid-indent-level 4))) - -(add-hook 'simpc-mode-hook (lambda () - (setq-local indent-tabs-mode t) - (setq-local tab-width 4) - (setq-local stupid-indent-level 4))) - -(add-hook 'python-mode-hook (lambda () - (setq-local indent-tabs-mode nil) - (setq-local tab-width 4) - (setq-local stupid-indent-level 4))) - -(add-hook 'js-mode-hook (lambda () - (setq-local indent-tabs-mode nil) - (setq-local tab-width 4) - (setq-local stupid-indent-level 4))) - -(add-hook 'emacs-lisp-mode-hook (lambda () - (setq-local indent-tabs-mode nil) - (setq-local tab-width 2) - (setq-local stupid-indent-level 2))) - -;;; ============================================================================ -;;; GENERAL SETTINGS & UI -;;; ============================================================================ - -;; startup -(setq-default inhibit-startup-screen t) -(setq initial-major-mode 'text-mode) -(setq initial-scratch-message "Just give him some food, water, and a funny hat." ) - -;; frame & window -(add-to-list 'default-frame-alist '(fullscreen . maximized)) -(setq ns-pop-up-frames nil) -(setq use-dialog-box nil) -(setq frame-inhibit-implied-resize t) - -;; UI chrome -(menu-bar-mode -1) -(scroll-bar-mode -1) -(tool-bar-mode -1) -(context-menu-mode -1) -(tooltip-mode -1) -(blink-cursor-mode 0) - -;; editing behavior -(show-paren-mode 1) -(delete-selection-mode 1) -(cua-mode t) -(setq cua-auto-tabify-rectangles nil) -(setq cua-keep-region-after-copy nil) -(transient-mark-mode 1) -(electric-pair-mode -1) -(electric-indent-mode 0) -(global-auto-revert-mode t) -(global-so-long-mode 1) -(global-hl-line-mode -1) - -;; display -(setq-default truncate-lines 1) -(setq column-number-mode t) -(column-number-mode 1) -(global-font-lock-mode 1) - -;; clipboard -(setq-default select-enable-clipboard t) -(setq-default x-select-enable-clipboard t) - -;; misc behavior -(setq-default backward-delete-char-untabify-method nil) -(setq ring-bell-function 'ignore) -(setq-default require-final-newline t) -(setq ediff-split-window-function 'split-window-horizontally) -(setq dired-dnd-protocol-alist nil) -(setq custom-file "~/.emacs.d/custom.el") - -;; mouse - disable right-click context menu -(global-set-key [mouse-3] 'ignore) -(global-set-key [down-mouse-3] 'ignore) -(global-set-key [C-down-mouse-1] 'ignore) -(global-set-key [C-down-mouse-3] 'ignore) - -;; dired: mouse click opens in same window -(add-hook 'dired-mode-hook - (lambda () - (define-key dired-mode-map [mouse-2] 'dired-find-file))) - -;;; ============================================================================ -;;; BOTTOM PANEL / COMPILATION WINDOW -;;; ============================================================================ - -(setq compilation-scroll-output -1) -(setq compilation-save-buffers-predicate 'ignore) - -(defvar my-bottom-panel-buffers '("\\*compilation\\*" "\\*xref\\*" "\\*Flymake diagnostics.*\\*") - "List of buffer name patterns for bottom panel.") - -(defun my-bottom-panel-buffer-p (buf) - "Check if BUF is a bottom panel buffer." - (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) - my-bottom-panel-buffers)) - -(defun my-get-bottom-panel-window () - "Get existing bottom panel window if any." - (seq-find (lambda (w) - (and (window-at-side-p w 'bottom) - (my-bottom-panel-buffer-p (window-buffer w)))) - (window-list))) - -(defun my-display-in-bottom-panel (buffer alist) - "Display BUFFER in bottom panel, reusing existing panel window." - (let ((window (my-get-bottom-panel-window))) - (if window - (progn - (set-window-buffer window buffer) - window) - (let ((new-window (display-buffer-at-bottom buffer alist))) - (when new-window - (with-selected-window new-window - (set-window-parameter new-window 'window-height 0.25))) - new-window)))) - -(add-to-list 'display-buffer-alist - '("\\*compilation\\*" (my-display-in-bottom-panel) (window-height . 0.25))) -(add-to-list 'display-buffer-alist - '("\\*xref\\*" (my-display-in-bottom-panel) (window-height . 0.25))) -(add-to-list 'display-buffer-alist - '("\\*Flymake diagnostics.*\\*" (my-display-in-bottom-panel) (window-height . 0.25))) - -(defun my-bottom-panel-toggle () - "Toggle the bottom panel. Close if visible, open if hidden." - (interactive) - (let ((panel-window (my-get-bottom-panel-window))) - (if panel-window - (delete-window panel-window) - (let ((matching-buffers (seq-filter - (lambda (buf) - (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) - my-bottom-panel-buffers)) - (buffer-list)))) - (if matching-buffers - (my-display-in-bottom-panel (car matching-buffers) '((window-height . 0.25))) - (message "No bottom panel buffers open.")))))) - -;;; ============================================================================ -;;; BACKUP & AUTOSAVE SETTINGS -;;; ============================================================================ - -(setq backup-by-copying t - backup-directory-alist '(("." . "~/.emacs.d/saves/")) - delete-old-versions t - kept-new-versions 6 - kept-old-versions 2 - version-control t) - -(setq auto-save-file-name-transforms - `((".*" "~/.emacs.d/saves/" t))) - -(setq create-lockfiles nil) - -;;; ============================================================================ -;;; PROCESS MANAGEMENT -;;; ============================================================================ - -(defun my-kill-process-tree (pid) - "Kill PID and all its descendant processes." - (let ((children (split-string - (shell-command-to-string - (format "pgrep -P %d 2>/dev/null" pid)) - "\n" t))) - (dolist (child children) - (when (string-match "^[0-9]+$" child) - (my-kill-process-tree (string-to-number child))))) - (ignore-errors (call-process "kill" nil nil nil "-9" (number-to-string pid)))) - -;; Ensure all subprocesses are killed when Emacs exits -(add-hook 'kill-emacs-hook - (lambda () - (dolist (proc (process-list)) - (when (process-live-p proc) - (let ((pid (process-id proc))) - (when pid - (my-kill-process-tree pid))) - (set-process-query-on-exit-flag proc t) - (ignore-errors (delete-process proc)))))) - -;; Kill terminal buffer when process exits -(defun my-term-handle-exit (&optional process-name msg) - "Kill terminal buffer when process exits." - (when (buffer-live-p (current-buffer)) - (kill-buffer (current-buffer)))) - -(advice-add 'term-handle-exit :after #'my-term-handle-exit) - -;;; ============================================================================ -;;; KEYBINDINGS -;;; ============================================================================ - -;; Mac-specific modifier keys -(setq mac-command-modifier 'control) -(setq mac-control-modifier 'command) - -;; isearch settings -(setq isearch-wrap-pause 'no) - -;; --- File & Buffer Operations --- -(global-set-key (kbd "C-s") 'save-buffer) -(global-set-key (kbd "C-n") (lambda () (interactive) (switch-to-buffer (generate-new-buffer "untitled")))) -(global-set-key (kbd "C-p") 'project-find-file) -(global-set-key (kbd "C-3") 'switch-to-buffer) -(global-set-key (kbd "C-4") 'find-file) -(global-set-key (kbd "C-q") 'save-buffers-kill-terminal) -(global-set-key (kbd "M-") 'save-buffers-kill-terminal) - -;; --- Window & Pane Management --- -(global-set-key (kbd "C-w") 'delete-window) -(global-set-key (kbd "C-\\") 'split-window-below) -(global-set-key (kbd "C-|") 'split-window-right) -(global-set-key (kbd "C-o") 'next-multiframe-window) -(global-set-key (kbd "C-1") 'my-select-left-pane) -(global-set-key (kbd "C-2") 'my-select-right-pane) -(global-set-key (kbd "") 'toggle-frame-maximized) - -;; --- Selection & Editing --- -(global-set-key (kbd "C-a") 'mark-whole-buffer) -(global-set-key (kbd "C-l") 'my-select-line) -(global-set-key (kbd "C-/") 'my-toggle-comment) -(global-set-key (kbd "M-j") 'my-duplicate-line) -(global-unset-key (kbd "C-x C-SPC")) -(global-set-key (kbd "C-x C-SPC") 'rectangle-mark-mode) -(global-set-key (kbd "S-") #'my-mouse-start-rectangle) - -;; --- Clipboard & Kill Ring --- -(global-set-key [?\C-z] 'undo) -(global-set-key (kbd "C-y") 'clipboard-yank) -(global-set-key (kbd "M-w") 'clipboard-kill-ring-save) - -;; --- Navigation --- -(global-set-key (kbd "") 'my-smart-home) -(global-set-key (kbd "") 'move-end-of-line) -(global-set-key (kbd "M-p") 'backward-paragraph) -(global-set-key (kbd "M-n") 'forward-paragraph) -(global-set-key [f8] 'goto-line) -(when (eq system-type 'darwin) - (global-set-key (kbd "C-") 'my-smart-home) - (global-set-key (kbd "C-") 'move-end-of-line)) - -;; --- Line Movement --- -(global-set-key (kbd "M-") 'my-move-line-up) -(global-set-key (kbd "M-") 'my-move-line-down) - -;; --- Search & Replace --- -(global-set-key (kbd "C-f") 'my-isearch-forward) -(global-set-key (kbd "C-*") 'search-current-word) -(global-set-key (kbd "C-S-f") 'my-project-find-text) -(global-set-key (kbd "C-S-h") 'my-find-replace) - -;; --- Code Navigation (xref/LSP) --- -(global-set-key (kbd "") 'my-xref-find-definitions-same-pane) -(global-set-key (kbd "C-") 'xref-find-references) -(global-set-key (kbd "C-{") 'xref-go-back) -(global-set-key (kbd "C-}") 'xref-go-forward) -(global-set-key (kbd "") 'xref-go-back) -(global-set-key (kbd "") 'xref-go-forward) -(global-set-key (kbd "C-") 'my-xref-find-definitions-at-click) -(global-set-key (kbd "C-S-") 'my-xref-find-references-at-click) -(global-set-key (kbd "C-t") 'my-lsp-find-workspace-symbol) - -;; --- LSP / Eglot --- -(global-set-key (kbd "") 'eglot-rename) -(global-set-key (kbd "") 'eglot-reconnect) -(global-set-key (kbd "C-S-m") 'my-flymake-show-project-errors-warnings) - -;; --- Compilation & Build --- -(global-set-key (kbd "") 'my-bottom-panel-toggle) -(global-set-key (kbd "") 'my-compile-last) -(global-set-key (kbd "") 'my-compile-custom) - -;; --- External Tools --- -(global-set-key (kbd "") 'my-file-manager-command) -(global-set-key (kbd "") 'my-terminal-emulator-command) - -;; --- Project Management --- -(global-set-key (kbd "") 'project-switch-project) -(global-set-key (kbd "C-S-p") 'counsel-M-x) - -;; --- Bookmarks --- -(global-set-key (kbd "") 'bookmark-jump) -(global-set-key (kbd "") 'bookmark-set) - -;; --- Themes --- -(global-set-key (kbd "") 'my-select-theme) - -;; --- Zoom --- -(global-set-key (kbd "C-=") 'my-global-zoom-in) -(global-set-key (kbd "C--") 'my-global-zoom-out) -(global-set-key (kbd "C-0") 'my-global-zoom-reset) -(global-unset-key (kbd "C-x C-=")) -(global-unset-key (kbd "C-x C--")) -(global-unset-key (kbd "C-x C-0")) -(global-set-key (kbd "C-") 'ignore) -(global-set-key (kbd "C-") 'ignore) - -;; --- Completion (dabbrev) --- -(global-set-key (kbd "C-j") 'dabbrev-expand) - -;; --- Multiple Cursors --- -(global-set-key (kbd "C-d") 'mc/mark-next-like-this-word) -(global-set-key (kbd "C-S-d") 'mc/mark-previous-like-this-word) -(global-set-key (kbd "C-S-a") 'mc/mark-all-like-this) -(global-set-key (kbd "M-") 'ignore) -(global-set-key (kbd "M-") 'mc/add-cursor-on-click) -(global-set-key (kbd "C-M-") (lambda () (interactive) (mc/mark-previous-lines 1))) -(global-set-key (kbd "C-M-") (lambda () (interactive) (mc/mark-next-lines 1))) - -;; --- Word Deletion (without kill ring) --- -(global-set-key (kbd "M-") 'my-backward-delete-word) -(global-set-key (kbd "M-d") 'my-delete-word) -(global-set-key (kbd "M-") 'my-delete-word) -(global-set-key (kbd "C-") 'my-backward-delete-word) - -;; --- Misc --- -(global-set-key (kbd "C-e") 'my-copy-path-with-line) - -;; --- Minibuffer Keybindings --- -(define-key minibuffer-local-filename-completion-map (kbd "C-2") 'my-find-file-right-pane) - -;; --- Isearch Keybindings --- -(define-key isearch-mode-map (kbd "") 'isearch-repeat-forward) -(define-key isearch-mode-map (kbd "S-") 'isearch-repeat-backward) -(define-key isearch-mode-map (kbd "") 'isearch-del-char) -(define-key isearch-mode-map (kbd "C-v") 'isearch-yank-kill) -(define-key isearch-mode-map (kbd "") 'my-isearch-cancel-or-exit) -(define-key isearch-mode-map (kbd "C-g") 'my-isearch-cancel-or-exit) - -;;; ============================================================================ -;;; CUSTOM MINOR MODE (for keybinding overrides) -;;; ============================================================================ - -(defvar my-keys-minor-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "M-p") 'backward-paragraph) - (define-key map (kbd "M-n") 'forward-paragraph) - (define-key map (kbd "C-o") 'next-multiframe-window) - (define-key map (kbd "C-1") 'my-select-left-pane) - (define-key map (kbd "C-2") 'my-select-right-pane) - (define-key map (kbd "C-3") 'switch-to-buffer) - (define-key map (kbd "C-4") 'find-file) - (define-key map (kbd "C-j") 'dabbrev-expand) - (define-key map (kbd "C-d") 'mc/mark-next-like-this-word) - (define-key map (kbd "C-S-d") 'mc/mark-previous-like-this-word) - (define-key map (kbd "C-S-a") 'mc/mark-all-like-this) - map) - "my-keys-minor-mode keymap.") - -(define-minor-mode my-keys-minor-mode - "A minor mode so that my key settings override annoying major modes." - :init-value t - :lighter "") - -;; don't enable override keymap in minibuffer -(defun my-minibuffer-setup-hook () - (my-keys-minor-mode 0)) -(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook) - -(my-keys-minor-mode 1) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Navigation -;;; ============================================================================ - -(defun my-smart-home () - "Move to first non-whitespace char, or beginning of line if already there." - (interactive "^") - (let ((orig-point (point))) - (back-to-indentation) - (when (= orig-point (point)) - (move-beginning-of-line 1)))) - -(defun my-get-top-windows () - "Get windows in the top portion of the frame (not bottom compilation)." - (let ((windows '())) - (walk-windows - (lambda (w) - (when (window-at-side-p w 'top) - (push w windows)))) - (sort windows (lambda (a b) (< (car (window-edges a)) (car (window-edges b))))))) - -(defun my-select-left-pane () - "Select the left pane of the top split." - (interactive) - (let ((top-windows (my-get-top-windows))) - (when top-windows - (select-window (car top-windows))))) - -(defun my-select-right-pane () - "Select the right pane of the top split, creating it if needed." - (interactive) - (let ((top-windows (my-get-top-windows))) - (if (>= (length top-windows) 2) - (select-window (cadr top-windows)) - (when top-windows - (select-window (car top-windows)) - (split-window-right) - (other-window 1))))) - -(defun my-xref-find-definitions-same-pane () - "Find definition and show it in the same pane. -Falls back to dumb-jump if xref fails." - (interactive) - (let ((identifier (thing-at-point 'symbol t))) - (if (null identifier) - (message "No symbol at point") - (condition-case nil - (let ((xrefs (xref-backend-definitions (xref-find-backend) identifier))) - (if xrefs - (xref-find-definitions identifier) - (dumb-jump-go))) - (error (dumb-jump-go)))))) - -(defun my-xref-find-definitions-at-click (event) - "Find definition of the symbol clicked on." - (interactive "e") - (mouse-set-point event) - (my-xref-find-definitions-same-pane)) - -(defun my-xref-find-references-at-click (event) - "Find references of the symbol clicked on." - (interactive "e") - (mouse-set-point event) - (xref-find-references (thing-at-point 'symbol t))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Search & Replace -;;; ============================================================================ - -(defun my-isearch-forward () - "Start isearch, using selected text if region is active." - (interactive) - (if (use-region-p) - (let ((text (buffer-substring-no-properties (region-beginning) (region-end)))) - (deactivate-mark) - (isearch-forward nil 1) - (setq isearch-string text - isearch-message text) - (isearch-update)) - (isearch-forward))) - -(defun my-isearch-cancel-or-exit () - "Cancel isearch if search string is empty, otherwise exit at current position." - (interactive) - (if (string= isearch-string "") - (isearch-cancel) - (isearch-exit))) - -(defun search-current-word () - (interactive) - (let ($p1 $p2) - (if (region-active-p) - (setq $p1 (region-beginning) $p2 (region-end)) - (save-excursion - - (skip-chars-backward "-_A-Za-z0-9") - (setq $p1 (point)) - (right-char) - (skip-chars-forward "-_A-Za-z0-9") - (setq $p2 (point)))) - (setq mark-active nil) - (when (< $p1 (point)) - (goto-char $p1)) - (isearch-mode t) - (isearch-yank-string (buffer-substring-no-properties $p1 $p2)))) - -(defun my-project-find-text () - "Search for literal text in project." - (interactive) - (let* ((initial (when (use-region-p) - (buffer-substring-no-properties (region-beginning) (region-end)))) - (text (read-string "Search in project: " initial))) - (project-find-regexp (regexp-quote text)))) - -(defun my-project-find-word-at-point () - "Search for word under cursor in project." - (interactive) - (let ($p1 $p2 word) - (if (region-active-p) - (setq $p1 (region-beginning) $p2 (region-end)) - (save-excursion - (skip-chars-backward "-_A-Za-z0-9") - (setq $p1 (point)) - (skip-chars-forward "-_A-Za-z0-9") - (setq $p2 (point)))) - (setq word (buffer-substring-no-properties $p1 $p2)) - (when (> (length word) 0) - (project-find-regexp (regexp-quote word))))) - -(defun my-find-replace () - "Find and replace with mode selection: project, file, or selection." - (interactive) - (let* ((mode (completing-read "Replace in: " '("file" "project" "selection") nil t)) - (search (read-string "Find: ")) - (replace (read-string (format "Replace '%s' with: " search)))) - (cond - ((string= mode "project") - (project-query-replace-regexp (regexp-quote search) replace)) - ((string= mode "file") - (save-excursion - (goto-char (point-min)) - (query-replace search replace))) - ((string= mode "selection") - (if (use-region-p) - (query-replace search replace nil (region-beginning) (region-end)) - (message "No region selected.")))))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Line Operations -;;; ============================================================================ - -(defun my-select-line () - "Select the current line. Repeat to select subsequent lines." - (interactive) - (if (and (use-region-p) (eq last-command 'my-select-line)) - (forward-line 1) - (move-beginning-of-line 1) - (set-mark (point)) - (forward-line 1))) - -(defun my-toggle-comment () - "Toggle comment on line or region without moving point." - (interactive) - (let* ((region-active (use-region-p)) - (start (if region-active (region-beginning) (line-beginning-position))) - (end (if region-active (region-end) (line-end-position)))) - (comment-or-uncomment-region start end) - (when region-active - (setq deactivate-mark nil)))) - -(defun my-duplicate-line (arg) - "Duplicate current line, leaving point in lower line." - (interactive "*p") - (setq buffer-undo-list (cons (point) buffer-undo-list)) - (let ((bol (save-excursion (beginning-of-line) (point))) - eol) - (save-excursion - (end-of-line) - (setq eol (point)) - (let ((line (buffer-substring bol eol)) - (buffer-undo-list t) - (count arg)) - (while (> count 0) - (newline) - (insert line) - (setq count (1- count))) - ) - (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list))) - ) - (next-line arg)) - -(defun my-move-line-up () - "Move current line or region up one line." - (interactive) - (if (use-region-p) - (my-move-region-up) - (let ((col (current-column))) - (transpose-lines 1) - (forward-line -2) - (move-to-column col)))) - -(defun my-move-line-down () - "Move current line or region down one line." - (interactive) - (if (use-region-p) - (my-move-region-down) - (let ((col (current-column))) - (forward-line 1) - (transpose-lines 1) - (forward-line -1) - (move-to-column col)))) - -(defun my-move-region-up () - "Move selected region up one line, keeping selection." - (let* ((rbeg (region-beginning)) - (rend (region-end)) - (beg (save-excursion (goto-char rbeg) (line-beginning-position))) - (end (save-excursion (goto-char rend) (if (bolp) (point) (1+ (line-end-position))))) - (offset-from-beg (- rbeg beg)) - (region-len (- rend rbeg)) - (text (delete-and-extract-region beg end))) - (forward-line -1) - (let ((new-beg (point))) - (insert text) - (set-mark (+ new-beg offset-from-beg)) - (goto-char (+ new-beg offset-from-beg region-len)) - (setq deactivate-mark nil)))) - -(defun my-move-region-down () - "Move selected region down one line, keeping selection." - (let* ((rbeg (region-beginning)) - (rend (region-end)) - (beg (save-excursion (goto-char rbeg) (line-beginning-position))) - (end (save-excursion (goto-char rend) (if (bolp) (point) (1+ (line-end-position))))) - (offset-from-beg (- rbeg beg)) - (region-len (- rend rbeg)) - (lines (count-lines beg end)) - (text (delete-and-extract-region beg end))) - (forward-line 1) - (let ((new-beg (point))) - (insert text) - (set-mark (+ new-beg offset-from-beg)) - (goto-char (+ new-beg offset-from-beg region-len)) - (setq deactivate-mark nil)))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Word Deletion -;;; ============================================================================ - -(defun my-delete-word (arg) - "Delete characters forward until encountering the end of a word. -With argument ARG, do this that many times. -Does not copy to kill ring." - (interactive "p") - (delete-region (point) (progn (forward-word arg) (point)))) - -(defun my-backward-delete-word (arg) - "Delete characters backward until encountering the beginning of a word. -With argument ARG, do this that many times. -Does not copy to kill ring." - (interactive "p") - (my-delete-word (- arg))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Compile Commands -;;; ============================================================================ - -(defvar my-project-data-dir "~/.emacs.d/project-data/" "Directory to store per-project data.") - -(defun my-project-data-file (filename) - "Get path to FILENAME for current project in project-data dir." - (let* ((root (project-root (project-current t))) - (hash (md5 root)) - (dir (expand-file-name hash my-project-data-dir))) - (unless (file-exists-p dir) - (make-directory dir t)) - (expand-file-name filename dir))) - -(defun my-compile-get-saved-command () - "Get saved compile command for current project." - (let ((file (my-project-data-file "compile-command"))) - (when (file-exists-p file) - (with-temp-buffer - (insert-file-contents file) - (string-trim (buffer-string)))))) - -(defun my-compile-save-command (cmd) - "Save compile command CMD for current project." - (let ((file (my-project-data-file "compile-command"))) - (with-temp-file file - (insert cmd)))) - -(defun my-compile-custom () - "Run a custom compile command in the project root." - (interactive) - (let* ((default-directory (project-root (project-current t))) - (saved (my-compile-get-saved-command)) - (cmd (read-string "Command: " saved))) - (my-compile-save-command cmd) - (compile cmd))) - -(defun my-compile-last () - "Run last compile command, or prompt for one if none has been run." - (interactive) - (let* ((default-directory (project-root (project-current t))) - (cmd (my-compile-get-saved-command))) - (if cmd - (compile cmd) - (my-compile-custom)))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - CTAGS -;;; ============================================================================ - -(defun my-tags-get-saved () - "Get saved TAGS file path for current project." - (when (project-current) - (let ((file (my-project-data-file "tags-file"))) - (when (file-exists-p file) - (with-temp-buffer - (insert-file-contents file) - (string-trim (buffer-string))))))) - -(defun my-tags-save (tags-path) - "Save TAGS file path for current project." - (when (project-current) - (let ((file (my-project-data-file "tags-file"))) - (with-temp-file file - (insert tags-path))))) - -(defun my-tags-load () - "Load saved TAGS file for current project." - (let ((saved (my-tags-get-saved))) - (when (and saved (file-exists-p saved)) - (visit-tags-table saved t)))) - -(add-hook 'find-file-hook #'my-tags-load) - -(defun ctags-generate () - "Generate TAGS file using ctags in project root or current directory." - (interactive) - (let* ((default-directory (or (and (project-current) - (project-root (project-current))) - default-directory)) - (tags-path (expand-file-name "TAGS" default-directory))) - (message "Generating TAGS in %s..." default-directory) - (shell-command "ctags -e -R --exclude=.git --exclude=log *") - (my-tags-save tags-path) - (visit-tags-table tags-path) - (message "TAGS generated and saved: %s" tags-path))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - File Operations -;;; ============================================================================ - -(defvar my--find-file-right-pane nil) - -(defun my-find-file-right-pane () - "Open file in right pane from find-file minibuffer." - (interactive) - (setq my--find-file-right-pane (expand-file-name (minibuffer-contents))) - (abort-recursive-edit)) - -(defun my-find-file-right-pane-after () - "Actually open the file in right pane." - (when my--find-file-right-pane - (let ((file my--find-file-right-pane)) - (setq my--find-file-right-pane nil) - (when (one-window-p) - (split-window-right)) - (other-window 1) - (find-file file)))) - -(add-hook 'minibuffer-exit-hook 'my-find-file-right-pane-after) - -(defun my-copy-path-with-line () - "Copy the current file path with line number to clipboard." - (interactive) - (if buffer-file-name - (let ((path-with-line (format "%s:%d" buffer-file-name (line-number-at-pos)))) - (kill-new path-with-line) - (message "Copied: %s" path-with-line)) - (message "Buffer has no file."))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Theme Selection -;;; ============================================================================ - -(add-to-list 'custom-theme-load-path "~/.emacs.d/themes/") -(defvar my-current-theme 'bedroom "Currently active theme.") - -(defun my-select-theme () - "Select and load a theme from all available themes." - (interactive) - (let* ((themes (append '("default" "default-dark") (mapcar #'symbol-name (custom-available-themes)))) - (choice (completing-read "Theme: " themes nil t))) - (when my-current-theme - (disable-theme my-current-theme)) - (cond - ((string= choice "default") - (set-foreground-color "black") - (set-background-color "white") - (setq my-current-theme nil)) - ((string= choice "default-dark") - (set-foreground-color "white") - (set-background-color "black") - (setq my-current-theme nil)) - (t - (setq my-current-theme (intern choice)) - (load-theme my-current-theme t))))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Zoom -;;; ============================================================================ - -(defvar my-default-font-height (face-attribute 'default :height)) - -(defun my-global-zoom-in () - (interactive) - (set-face-attribute 'default nil :height (+ (face-attribute 'default :height) 10))) - -(defun my-global-zoom-out () - (interactive) - (set-face-attribute 'default nil :height (- (face-attribute 'default :height) 10))) - -(defun my-global-zoom-reset () - (interactive) - (set-face-attribute 'default nil :height my-default-font-height)) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Buffer Management -;;; ============================================================================ - -(defun kill-other-buffers () - "Kill all buffers except the current one and close other panes." - (interactive) - (let ((current (current-buffer))) - (dolist (buf (buffer-list)) - (unless (eq buf current) - (let ((proc (get-buffer-process buf))) - (when proc - (let ((pid (process-id proc))) - (when pid - (my-kill-process-tree pid))) - (set-process-query-on-exit-flag proc nil))) - (with-current-buffer buf - (set-buffer-modified-p nil)) - (kill-buffer buf)))) - (setq recentf-list nil) - (delete-other-windows)) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Window Management -;;; ============================================================================ - -(defun my-transpose-windows (arg) - "Transpose the buffers shown in two windows." - (interactive "p") - (let ((selector (if (>= arg 0) 'next-window 'previous-window))) - (while (/= arg 0) - (let ((this-win (window-buffer)) - (next-win (window-buffer (funcall selector)))) - (set-window-buffer (selected-window) next-win) - (set-window-buffer (funcall selector) this-win) - (select-window (funcall selector))) - (setq arg (if (plusp arg) (1- arg) (1+ arg)))))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Rectangle Selection -;;; ============================================================================ - -(defun my-mouse-start-rectangle (start-event) - (interactive "e") - (deactivate-mark) - (mouse-set-point start-event) - (rectangle-mark-mode +1) - (let ((drag-event)) - (track-mouse - (while (progn - (setq drag-event (read-event)) - (mouse-movement-p drag-event)) - (mouse-set-point drag-event))))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - External Tools -;;; ============================================================================ - -(defun my-file-manager-command () - (interactive) - (cond ((eq system-type 'windows-nt) - (shell-command "explorer.exe .")) - ((eq system-type 'darwin) - (shell-command "open .")) - ((eq system-type 'gnu/linux) - (shell-command "setsid -f nautilus . >/dev/null 2>&1")))) - -(defun my-terminal-emulator-command () - (interactive) - (cond ((eq system-type 'windows-nt) - (let ((proc (start-process "cmd" nil "cmd.exe" "/C" "start" "cmd.exe"))) - (set-process-query-on-exit-flag proc nil))) - ((eq system-type 'gnu/linux) - (shell-command "setsid -f gnome-terminal . >/dev/null 2>&1")))) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Emacs Config -;;; ============================================================================ - -(defun reload-emacs-config () - "Reload the Emacs configuration file." - (interactive) - (load-file "~/.emacs.d/init.el") - (message "Emacs config reloaded.")) - -(defun edit-emacs-config () - "Open the Emacs configuration file for editing." - (interactive) - (find-file "~/.emacs.d/init.el")) - -;;; ============================================================================ -;;; CUSTOM FUNCTIONS - Misc -;;; ============================================================================ - -(defun my-test () - (interactive) - (message "Hello world!")) - -;;; ============================================================================ -;;; TWEAKS & FIXES -;;; ============================================================================ - -;; fix isearch wrapping behavior -(defadvice isearch-search (after isearch-no-fail activate) - (unless isearch-success - (ad-disable-advice 'isearch-search 'after 'isearch-no-fail) - (ad-activate 'isearch-search) - (isearch-repeat (if isearch-forward 'forward)) - (ad-enable-advice 'isearch-search 'after 'isearch-no-fail) - (ad-activate 'isearch-search))) - -;; go to match beginning after isearch -(add-hook 'isearch-mode-end-hook - #'endless/goto-match-beginning) - -(defun endless/goto-match-beginning () - "Go to the start of current isearch match. -Use in `isearch-mode-end-hook'." - (when (and isearch-forward - (number-or-marker-p isearch-other-end) - (not mark-active) - (not isearch-mode-end-hook-quit)) - (goto-char isearch-other-end))) - -;;; ============================================================================ -;;; APPEARANCE & THEME -;;; ============================================================================ - -;; (set-face-attribute 'default nil :font "Consolas-15") -(load-theme 'bedroom t) - -;;; init.el ends here +;; Max's init.el -*- lexical-binding: t; -*- + +;;; ============================================================================ +;;; PACKAGE LOADING & LOAD PATHS +;;; ============================================================================ + +(add-to-list 'load-path "~/.emacs.d/lisp/") + +(let ((default-directory "~/.emacs.d/lisp/")) + (normal-top-level-add-subdirs-to-load-path)) + +;; Core libraries +(require 's) +(require 'dash) +(require 'popup) + +;; Completion framework +(require 'ivy) +(require 'counsel) + +;; Language modes +(require 'yaml-mode) +(require 'dockerfile-mode) +(require 'go-mode) +(require 'jai-mode) +(require 'simpc-mode) +(require 'web-mode) + +;; Editing enhancements +(require 'stupid-indent-mode) +(require 'multiple-cursors) +(require 'vundo) + +;; Navigation +(require 'dumb-jump) +(require 'eglot) + +;; Search +(require 'xah-find) + +;;; ============================================================================ +;;; MODE ASSOCIATIONS +;;; ============================================================================ + +(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)) +(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode)) +(add-to-list 'auto-mode-alist '("\\.jai\\'" . jai-mode)) +(add-to-list 'auto-mode-alist '("\\.css\\'" . web-mode)) +(add-to-list 'auto-mode-alist '("\\.js\\'" . web-mode)) +(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode)) +(add-to-list 'auto-mode-alist '("\\.\\(as\\(px?\\|cx\\)\\|razor\\|blazor\\|cshtml\\)\\'" . web-mode)) +(add-to-list 'auto-mode-alist '("\\.[hc]\\(pp\\)?\\'" . simpc-mode)) + +;;; ============================================================================ +;;; IVY & COMPLETION FRAMEWORK +;;; ============================================================================ + +(ivy-mode 1) +(setq ivy-use-virtual-buffers t) +(setq ivy-count-format "(%d/%d) ") +(setq ivy-wrap t) + +;;; ============================================================================ +;;; XREF, CTAGS & NAVIGATION +;;; ============================================================================ + +;; dumb-jump as fallback for xref +(setq dumb-jump-force-searcher 'grep) +(setq dumb-jump-selector 'ivy) +(setq xref-show-definitions-function #'xref-show-definitions-completing-read) +(setq tags-revert-without-query t) +(add-hook 'xref-backend-functions #'dumb-jump-xref-activate 100) + +;;; ============================================================================ +;;; EGLOT (LSP) CONFIGURATION +;;; ============================================================================ + +;; When eglot is active, xref commands (F12, M-f12) automatically use LSP +;; instead of CTAGS. Eglot registers itself as a higher-priority xref backend. + +(setq eglot-autoshutdown t) ; shutdown server when last buffer is closed +(setq eglot-confirm-server-initiated-edits nil) ; don't ask for confirmation on renames + +;; disable LSP visual indicators but keep diagnostics available +(add-to-list 'eglot-ignored-server-capabilities :documentHighlightProvider) + +;; Go: auto-start eglot (requires gopls: go install golang.org/x/tools/gopls@latest) +(add-hook 'go-mode-hook 'eglot-ensure) + +;; auto-confirm "modified buffer" prompts when jumping from diagnostics +(defun my-auto-confirm-modified-buffer (orig-fun prompt) + "Auto-confirm prompts about modified buffers having wrong location." + (if (string-match-p "has been modified.*wrong location" prompt) + t + (funcall orig-fun prompt))) +(advice-add 'y-or-n-p :around #'my-auto-confirm-modified-buffer) + +(defun my-lsp-find-workspace-symbol () + "Interactively search for symbols in workspace using LSP." + (interactive) + (if (eglot-managed-p) + (let ((server (eglot-current-server)) + (root (project-root (project-current)))) + (ivy-read "Symbol: " + (lambda (input) + (when (and input (>= (length input) 1)) + (condition-case nil + (let* ((resp (jsonrpc-request server :workspace/symbol + `(:query ,input))) + (items (append resp nil))) + (delq nil + (mapcar (lambda (item) + (condition-case nil + (let* ((name (plist-get item :name)) + (loc (plist-get item :location)) + (uri (plist-get loc :uri)) + (range (plist-get loc :range)) + (start (plist-get range :start)) + (line (1+ (plist-get start :line))) + (file (eglot-uri-to-path uri)) + (rel-path (file-relative-name file root))) + (propertize (format "%s %s:%d" name rel-path line) + 'file file + 'line line)) + (error nil))) + items))) + (error nil)))) + :dynamic-collection t + :require-match t + :action (lambda (candidate) + (when (and candidate (get-text-property 0 'file candidate)) + (find-file (get-text-property 0 'file candidate)) + (goto-char (point-min)) + (forward-line (1- (get-text-property 0 'line candidate))))))) + (call-interactively 'xref-find-apropos))) + +;;; ============================================================================ +;;; FLYMAKE & DIAGNOSTICS +;;; ============================================================================ + +;; hide squiggly underlines +(set-face-attribute 'flymake-error nil :underline nil) +(set-face-attribute 'flymake-warning nil :underline nil) +(set-face-attribute 'flymake-note nil :underline nil) + +;; hide fringe indicators +(setq flymake-fringe-indicator-position nil) + +(defun my-flymake-show-project-errors-warnings () + "Show project diagnostics, filtering out notes (only errors and warnings)." + (interactive) + ;; Kill existing diagnostics buffer to force refresh + (when-let ((buf (get-buffer "*Flymake diagnostics*"))) + (kill-buffer buf)) + ;; Refresh flymake on all project buffers + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (and (bound-and-true-p flymake-mode) + (buffer-file-name)) + (flymake-start)))) + (flymake-show-project-diagnostics) + (run-at-time 0.1 nil + (lambda () + (when-let ((buf (get-buffer "*Flymake diagnostics*"))) + (with-current-buffer buf + (let ((inhibit-read-only t)) + (goto-char (point-min)) + (while (not (eobp)) + (if (looking-at ".*\\bnote\\b.*$") + (delete-region (line-beginning-position) (1+ (line-end-position))) + (forward-line 1))))))))) + +;;; ============================================================================ +;;; MULTIPLE CURSORS +;;; ============================================================================ + +(setq mc/always-run-for-all t) +(setq mc/cycle-looping-behaviour 'continue) +(define-key mc/keymap (kbd "") 'mc/keyboard-quit) +(define-key mc/keymap (kbd "") nil) + +(advice-add 'mc/load-lists :after + (lambda () (add-to-list 'mc/cmds-to-run-once 'my-mc-mark-next-like-this))) + + +;;; ============================================================================ +;;; INDENTATION SETTINGS +;;; ============================================================================ + +;; default indentation +(setq-default indent-tabs-mode t) +(setq-default tab-width 4) +(setq-default stupid-indent-level 4) +(add-hook 'text-mode-hook 'stupid-indent-mode) +(add-hook 'prog-mode-hook 'stupid-indent-mode) + +;; per-language indentation (indent-tabs-mode: t = tabs, nil = spaces) +(add-hook 'go-mode-hook (lambda () + (setq-local indent-tabs-mode t) + (setq-local tab-width 4) + (setq-local stupid-indent-level 4))) + +(add-hook 'jai-mode-hook (lambda () + (setq-local indent-tabs-mode nil) + (setq-local tab-width 4) + (setq-local stupid-indent-level 4))) + +(add-hook 'simpc-mode-hook (lambda () + (setq-local indent-tabs-mode t) + (setq-local tab-width 4) + (setq-local stupid-indent-level 4))) + +(add-hook 'python-mode-hook (lambda () + (setq-local indent-tabs-mode nil) + (setq-local tab-width 4) + (setq-local stupid-indent-level 4))) + +(add-hook 'js-mode-hook (lambda () + (setq-local indent-tabs-mode nil) + (setq-local tab-width 4) + (setq-local stupid-indent-level 4))) + +(add-hook 'emacs-lisp-mode-hook (lambda () + (setq-local indent-tabs-mode nil) + (setq-local tab-width 2) + (setq-local stupid-indent-level 2))) + +;;; ============================================================================ +;;; GENERAL SETTINGS & UI +;;; ============================================================================ + +;; startup +(setq-default inhibit-startup-screen t) +(setq initial-major-mode 'text-mode) +(setq initial-scratch-message "Just give him some food, water, and a funny hat." ) + +;; frame & window +(add-to-list 'default-frame-alist '(fullscreen . maximized)) +(setq ns-pop-up-frames nil) +(setq use-dialog-box nil) +(setq frame-inhibit-implied-resize t) + +;; UI chrome +(menu-bar-mode -1) +(scroll-bar-mode -1) +(tool-bar-mode -1) +(context-menu-mode -1) +(tooltip-mode -1) +(blink-cursor-mode 0) + +;; editing behavior +(show-paren-mode 1) +(delete-selection-mode 1) +(cua-mode t) +(setq cua-auto-tabify-rectangles nil) +(setq cua-keep-region-after-copy nil) +(transient-mark-mode 1) +(electric-pair-mode -1) +(electric-indent-mode 0) +(global-auto-revert-mode t) +(global-so-long-mode 1) +(global-hl-line-mode -1) + +;; display +(setq-default truncate-lines 1) +(setq column-number-mode t) +(column-number-mode 1) +(global-font-lock-mode 1) + +;; clipboard +(setq-default select-enable-clipboard t) +(setq-default x-select-enable-clipboard t) + +;; misc behavior +(setq-default backward-delete-char-untabify-method nil) +(setq ring-bell-function 'ignore) +(setq-default require-final-newline t) +(setq ediff-split-window-function 'split-window-horizontally) +(setq dired-dnd-protocol-alist nil) +(setq custom-file "~/.emacs.d/custom.el") + +;; mouse - disable right-click context menu +(global-set-key [mouse-3] 'ignore) +(global-set-key [down-mouse-3] 'ignore) +(global-set-key [C-down-mouse-1] 'ignore) +(global-set-key [C-down-mouse-3] 'ignore) + +;; dired: mouse click opens in same window +(add-hook 'dired-mode-hook + (lambda () + (define-key dired-mode-map [mouse-2] 'dired-find-file))) + +;;; ============================================================================ +;;; BOTTOM PANEL / COMPILATION WINDOW +;;; ============================================================================ + +(setq compilation-scroll-output -1) +(setq compilation-save-buffers-predicate 'ignore) + +(defvar my-bottom-panel-buffers '("\\*compilation\\*" "\\*xref\\*" "\\*Flymake diagnostics.*\\*") + "List of buffer name patterns for bottom panel.") + +(defun my-bottom-panel-buffer-p (buf) + "Check if BUF is a bottom panel buffer." + (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) + my-bottom-panel-buffers)) + +(defun my-get-bottom-panel-window () + "Get existing bottom panel window if any." + (seq-find (lambda (w) + (and (window-at-side-p w 'bottom) + (my-bottom-panel-buffer-p (window-buffer w)))) + (window-list))) + +(defun my-display-in-bottom-panel (buffer alist) + "Display BUFFER in bottom panel, reusing existing panel window." + (let ((window (my-get-bottom-panel-window))) + (if window + (progn + (set-window-buffer window buffer) + window) + (let ((new-window (display-buffer-at-bottom buffer alist))) + (when new-window + (with-selected-window new-window + (set-window-parameter new-window 'window-height 0.25))) + new-window)))) + +(add-to-list 'display-buffer-alist + '("\\*compilation\\*" (my-display-in-bottom-panel) (window-height . 0.25))) +(add-to-list 'display-buffer-alist + '("\\*xref\\*" (my-display-in-bottom-panel) (window-height . 0.25))) +(add-to-list 'display-buffer-alist + '("\\*Flymake diagnostics.*\\*" (my-display-in-bottom-panel) (window-height . 0.25))) + +(defun my-bottom-panel-toggle () + "Toggle the bottom panel. Close if visible, open if hidden." + (interactive) + (let ((panel-window (my-get-bottom-panel-window))) + (if panel-window + (delete-window panel-window) + (let ((matching-buffers (seq-filter + (lambda (buf) + (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) + my-bottom-panel-buffers)) + (buffer-list)))) + (if matching-buffers + (my-display-in-bottom-panel (car matching-buffers) '((window-height . 0.25))) + (message "No bottom panel buffers open.")))))) + +;;; ============================================================================ +;;; BACKUP & AUTOSAVE SETTINGS +;;; ============================================================================ + +(setq backup-by-copying t + backup-directory-alist '(("." . "~/.emacs.d/saves/")) + delete-old-versions t + kept-new-versions 6 + kept-old-versions 2 + version-control t) + +(setq auto-save-file-name-transforms + `((".*" "~/.emacs.d/saves/" t))) + +(setq create-lockfiles nil) + +;;; ============================================================================ +;;; PROCESS MANAGEMENT +;;; ============================================================================ + +(defun my-kill-process-tree (pid) + "Kill PID and all its descendant processes." + (let ((children (split-string + (shell-command-to-string + (format "pgrep -P %d 2>/dev/null" pid)) + "\n" t))) + (dolist (child children) + (when (string-match "^[0-9]+$" child) + (my-kill-process-tree (string-to-number child))))) + (ignore-errors (call-process "kill" nil nil nil "-9" (number-to-string pid)))) + +;; Ensure all subprocesses are killed when Emacs exits +(add-hook 'kill-emacs-hook + (lambda () + (dolist (proc (process-list)) + (when (process-live-p proc) + (let ((pid (process-id proc))) + (when pid + (my-kill-process-tree pid))) + (set-process-query-on-exit-flag proc t) + (ignore-errors (delete-process proc)))))) + +;; Kill terminal buffer when process exits +(defun my-term-handle-exit (&optional process-name msg) + "Kill terminal buffer when process exits." + (when (buffer-live-p (current-buffer)) + (kill-buffer (current-buffer)))) + +(advice-add 'term-handle-exit :after #'my-term-handle-exit) + +;;; ============================================================================ +;;; KEYBINDINGS +;;; ============================================================================ + +;; Mac-specific modifier keys +(setq mac-command-modifier 'control) +(setq mac-control-modifier 'command) + +;; isearch settings +(setq isearch-wrap-pause 'no) + +;; --- File & Buffer Operations --- +(global-set-key (kbd "C-s") 'save-buffer) +(global-set-key (kbd "C-n") (lambda () (interactive) (switch-to-buffer (generate-new-buffer "untitled")))) +(global-set-key (kbd "C-p") 'project-find-file) +(global-set-key (kbd "C-3") 'switch-to-buffer) +(global-set-key (kbd "C-4") 'find-file) +(global-set-key (kbd "C-q") 'save-buffers-kill-terminal) +(global-set-key (kbd "M-") 'save-buffers-kill-terminal) + +;; --- Window & Pane Management --- +(global-set-key (kbd "C-w") 'delete-window) +(global-set-key (kbd "C-\\") 'split-window-below) +(global-set-key (kbd "C-|") 'split-window-right) +(global-set-key (kbd "C-o") 'next-multiframe-window) +(global-set-key (kbd "C-1") 'my-select-left-pane) +(global-set-key (kbd "C-2") 'my-select-right-pane) +(global-set-key (kbd "") 'toggle-frame-maximized) + +;; --- Selection & Editing --- +(global-set-key (kbd "C-a") 'mark-whole-buffer) +(global-set-key (kbd "C-l") 'my-select-line) +(global-set-key (kbd "C-/") 'my-toggle-comment) +(global-set-key (kbd "M-j") 'my-duplicate-line) +(global-unset-key (kbd "C-x C-SPC")) +(global-set-key (kbd "C-x C-SPC") 'rectangle-mark-mode) +(global-set-key (kbd "S-") #'my-mouse-start-rectangle) + +;; --- Clipboard & Kill Ring --- +(global-set-key [?\C-z] 'undo) +(global-set-key (kbd "C-y") 'clipboard-yank) +(global-set-key (kbd "M-w") 'clipboard-kill-ring-save) + +;; --- Navigation --- +(global-set-key (kbd "") 'my-smart-home) +(global-set-key (kbd "") 'move-end-of-line) +(global-set-key (kbd "M-p") 'backward-paragraph) +(global-set-key (kbd "M-n") 'forward-paragraph) +(global-set-key [f8] 'goto-line) +(when (eq system-type 'darwin) + (global-set-key (kbd "C-") 'my-smart-home) + (global-set-key (kbd "C-") 'move-end-of-line)) + +;; --- Line Movement --- +(global-set-key (kbd "M-") 'my-move-line-up) +(global-set-key (kbd "M-") 'my-move-line-down) + +;; --- Search & Replace --- +(global-set-key (kbd "C-f") 'my-isearch-forward) +(global-set-key (kbd "C-*") 'search-current-word) +(global-set-key (kbd "C-S-f") 'my-project-find-text) +(global-set-key (kbd "C-S-h") 'my-find-replace) + +;; --- Code Navigation (xref/LSP) --- +(global-set-key (kbd "") 'my-xref-find-definitions-same-pane) +(global-set-key (kbd "C-") 'xref-find-references) +(global-set-key (kbd "C-{") 'xref-go-back) +(global-set-key (kbd "C-}") 'xref-go-forward) +(global-set-key (kbd "") 'xref-go-back) +(global-set-key (kbd "") 'xref-go-forward) +(global-set-key (kbd "C-") 'my-xref-find-definitions-at-click) +(global-set-key (kbd "C-S-") 'my-xref-find-references-at-click) +(global-set-key (kbd "C-t") 'my-lsp-find-workspace-symbol) + +;; --- LSP / Eglot --- +(global-set-key (kbd "") 'eglot-rename) +(global-set-key (kbd "") 'eglot-reconnect) +(global-set-key (kbd "C-S-m") 'my-flymake-show-project-errors-warnings) + +;; --- Compilation & Build --- +(global-set-key (kbd "") 'my-bottom-panel-toggle) +(global-set-key (kbd "") 'my-compile-last) +(global-set-key (kbd "") 'my-compile-custom) + +;; --- External Tools --- +(global-set-key (kbd "") 'my-file-manager-command) +(global-set-key (kbd "") 'my-terminal-emulator-command) + +;; --- Project Management --- +(global-set-key (kbd "") 'project-switch-project) +(global-set-key (kbd "C-S-p") 'counsel-M-x) + +;; --- Bookmarks --- +(global-set-key (kbd "") 'bookmark-jump) +(global-set-key (kbd "") 'bookmark-set) + +;; --- Themes --- +(global-set-key (kbd "") 'my-select-theme) + +;; --- Zoom --- +(global-set-key (kbd "C-=") 'my-global-zoom-in) +(global-set-key (kbd "C--") 'my-global-zoom-out) +(global-set-key (kbd "C-0") 'my-global-zoom-reset) +(global-unset-key (kbd "C-x C-=")) +(global-unset-key (kbd "C-x C--")) +(global-unset-key (kbd "C-x C-0")) +(global-set-key (kbd "C-") 'ignore) +(global-set-key (kbd "C-") 'ignore) + +;; --- Completion (dabbrev) --- +(global-set-key (kbd "C-j") 'dabbrev-expand) + +;; --- Multiple Cursors --- +(global-set-key (kbd "C-d") 'my-mc-mark-next-like-this) +(global-set-key (kbd "C-S-d") 'mc/mark-previous-like-this-word) +(global-set-key (kbd "C-S-a") 'mc/mark-all-like-this) +(global-set-key (kbd "M-") 'ignore) +(global-set-key (kbd "M-") 'mc/add-cursor-on-click) +(global-set-key (kbd "C-M-") (lambda () (interactive) (mc/mark-previous-lines 1))) +(global-set-key (kbd "C-M-") (lambda () (interactive) (mc/mark-next-lines 1))) + +;; --- Word Deletion (without kill ring) --- +(global-set-key (kbd "M-") 'my-backward-delete-word) +(global-set-key (kbd "M-d") 'my-delete-word) +(global-set-key (kbd "M-") 'my-delete-word) +(global-set-key (kbd "C-") 'my-backward-delete-word) + +;; --- Misc --- +(global-set-key (kbd "C-e") 'my-copy-path-with-line) +(global-set-key (kbd "C-!") 'my-insert-shell-command-output) +(global-set-key (kbd "C-") 'my-toggle-macro-recording) +(global-set-key (kbd "") 'my-call-macro) + +;; --- Minibuffer Keybindings --- +(define-key minibuffer-local-filename-completion-map (kbd "C-2") 'my-find-file-right-pane) + +;; --- Isearch Keybindings --- +(define-key isearch-mode-map (kbd "") 'isearch-repeat-forward) +(define-key isearch-mode-map (kbd "S-") 'isearch-repeat-backward) +(define-key isearch-mode-map (kbd "") 'isearch-del-char) +(define-key isearch-mode-map (kbd "C-v") 'isearch-yank-kill) +(define-key isearch-mode-map (kbd "") 'my-isearch-cancel-or-exit) +(define-key isearch-mode-map (kbd "C-g") 'my-isearch-cancel-or-exit) + +;;; ============================================================================ +;;; CUSTOM MINOR MODE (for keybinding overrides) +;;; ============================================================================ + +(defvar my-keys-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "M-p") 'backward-paragraph) + (define-key map (kbd "M-n") 'forward-paragraph) + (define-key map (kbd "C-o") 'next-multiframe-window) + (define-key map (kbd "C-1") 'my-select-left-pane) + (define-key map (kbd "C-2") 'my-select-right-pane) + (define-key map (kbd "C-3") 'switch-to-buffer) + (define-key map (kbd "C-4") 'find-file) + (define-key map (kbd "C-j") 'dabbrev-expand) + (define-key map (kbd "C-d") 'my-mc-mark-next-like-this) + (define-key map (kbd "C-S-d") 'mc/mark-previous-like-this-word) + (define-key map (kbd "C-S-a") 'mc/mark-all-like-this) + map) + "my-keys-minor-mode keymap.") + +(define-minor-mode my-keys-minor-mode + "A minor mode so that my key settings override annoying major modes." + :init-value t + :lighter "") + +;; don't enable override keymap in minibuffer +(defun my-minibuffer-setup-hook () + (my-keys-minor-mode 0)) +(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook) + +(my-keys-minor-mode 1) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Navigation +;;; ============================================================================ + +(defun my-smart-home () + "Move to first non-whitespace char, or beginning of line if already there." + (interactive "^") + (let ((orig-point (point))) + (back-to-indentation) + (when (= orig-point (point)) + (move-beginning-of-line 1)))) + +(defun my-get-top-windows () + "Get windows in the top portion of the frame (not bottom compilation)." + (let ((windows '())) + (walk-windows + (lambda (w) + (when (window-at-side-p w 'top) + (push w windows)))) + (sort windows (lambda (a b) (< (car (window-edges a)) (car (window-edges b))))))) + +(defun my-select-left-pane () + "Select the left pane of the top split." + (interactive) + (let ((top-windows (my-get-top-windows))) + (when top-windows + (select-window (car top-windows))))) + +(defun my-select-right-pane () + "Select the right pane of the top split, creating it if needed." + (interactive) + (let ((top-windows (my-get-top-windows))) + (if (>= (length top-windows) 2) + (select-window (cadr top-windows)) + (when top-windows + (select-window (car top-windows)) + (split-window-right) + (other-window 1))))) + +(defun my-xref-find-definitions-same-pane () + "Find definition and show it in the same pane. +Falls back to dumb-jump if xref fails." + (interactive) + (let ((identifier (thing-at-point 'symbol t))) + (if (null identifier) + (message "No symbol at point") + (condition-case nil + (let ((xrefs (xref-backend-definitions (xref-find-backend) identifier))) + (if xrefs + (xref-find-definitions identifier) + (dumb-jump-go))) + (error (dumb-jump-go)))))) + +(defun my-xref-find-definitions-at-click (event) + "Find definition of the symbol clicked on." + (interactive "e") + (mouse-set-point event) + (my-xref-find-definitions-same-pane)) + +(defun my-xref-find-references-at-click (event) + "Find references of the symbol clicked on." + (interactive "e") + (mouse-set-point event) + (xref-find-references (thing-at-point 'symbol t))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Search & Replace +;;; ============================================================================ + +(defun my-isearch-forward () + "Start isearch, using selected text if region is active." + (interactive) + (if (use-region-p) + (let ((text (buffer-substring-no-properties (region-beginning) (region-end)))) + (deactivate-mark) + (isearch-forward nil 1) + (setq isearch-string text + isearch-message text) + (isearch-update)) + (isearch-forward))) + +(defun my-isearch-cancel-or-exit () + "Cancel isearch if search string is empty, otherwise exit at current position." + (interactive) + (if (string= isearch-string "") + (isearch-cancel) + (isearch-exit))) + +(defun search-current-word () + (interactive) + (let ($p1 $p2) + (if (region-active-p) + (setq $p1 (region-beginning) $p2 (region-end)) + (save-excursion + + (skip-chars-backward "-_A-Za-z0-9") + (setq $p1 (point)) + (right-char) + (skip-chars-forward "-_A-Za-z0-9") + (setq $p2 (point)))) + (setq mark-active nil) + (when (< $p1 (point)) + (goto-char $p1)) + (isearch-mode t) + (isearch-yank-string (buffer-substring-no-properties $p1 $p2)))) + +(defun my-project-find-text () + "Search for literal text in project." + (interactive) + (let* ((initial (when (use-region-p) + (buffer-substring-no-properties (region-beginning) (region-end)))) + (text (read-string "Search in project: " initial))) + (project-find-regexp (regexp-quote text)))) + +(defun my-project-find-word-at-point () + "Search for word under cursor in project." + (interactive) + (let ($p1 $p2 word) + (if (region-active-p) + (setq $p1 (region-beginning) $p2 (region-end)) + (save-excursion + (skip-chars-backward "-_A-Za-z0-9") + (setq $p1 (point)) + (skip-chars-forward "-_A-Za-z0-9") + (setq $p2 (point)))) + (setq word (buffer-substring-no-properties $p1 $p2)) + (when (> (length word) 0) + (project-find-regexp (regexp-quote word))))) + +(defun my-find-replace () + "Find and replace with mode selection: project, file, or selection." + (interactive) + (let* ((mode (completing-read "Replace in: " '("file" "project" "selection") nil t)) + (search (read-string "Find: ")) + (replace (read-string (format "Replace '%s' with: " search)))) + (cond + ((string= mode "project") + (project-query-replace-regexp (regexp-quote search) replace)) + ((string= mode "file") + (save-excursion + (goto-char (point-min)) + (query-replace search replace))) + ((string= mode "selection") + (if (use-region-p) + (query-replace search replace nil (region-beginning) (region-end)) + (message "No region selected.")))))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Line Operations +;;; ============================================================================ + +(defun my-select-line () + "Select the current line. Repeat to select subsequent lines." + (interactive) + (if (and (use-region-p) (eq last-command 'my-select-line)) + (forward-line 1) + (move-beginning-of-line 1) + (set-mark (point)) + (forward-line 1))) + +(defun my-toggle-comment () + "Toggle comment on line or region without moving point." + (interactive) + (let* ((region-active (use-region-p)) + (start (if region-active (region-beginning) (line-beginning-position))) + (end (if region-active (region-end) (line-end-position)))) + (comment-or-uncomment-region start end) + (when region-active + (setq deactivate-mark nil)))) + +(defun my-duplicate-line (arg) + "Duplicate current line, leaving point in lower line." + (interactive "*p") + (setq buffer-undo-list (cons (point) buffer-undo-list)) + (let ((bol (save-excursion (beginning-of-line) (point))) + eol) + (save-excursion + (end-of-line) + (setq eol (point)) + (let ((line (buffer-substring bol eol)) + (buffer-undo-list t) + (count arg)) + (while (> count 0) + (newline) + (insert line) + (setq count (1- count))) + ) + (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list))) + ) + (next-line arg)) + +(defun my-move-line-up () + "Move current line or region up one line." + (interactive) + (if (use-region-p) + (my-move-region-up) + (let ((col (current-column))) + (transpose-lines 1) + (forward-line -2) + (move-to-column col)))) + +(defun my-move-line-down () + "Move current line or region down one line." + (interactive) + (if (use-region-p) + (my-move-region-down) + (let ((col (current-column))) + (forward-line 1) + (transpose-lines 1) + (forward-line -1) + (move-to-column col)))) + +(defun my-move-region-up () + "Move selected region up one line, keeping selection." + (let* ((rbeg (region-beginning)) + (rend (region-end)) + (beg (save-excursion (goto-char rbeg) (line-beginning-position))) + (end (save-excursion (goto-char rend) (if (bolp) (point) (1+ (line-end-position))))) + (offset-from-beg (- rbeg beg)) + (region-len (- rend rbeg)) + (text (delete-and-extract-region beg end))) + (forward-line -1) + (let ((new-beg (point))) + (insert text) + (set-mark (+ new-beg offset-from-beg)) + (goto-char (+ new-beg offset-from-beg region-len)) + (setq deactivate-mark nil)))) + +(defun my-move-region-down () + "Move selected region down one line, keeping selection." + (let* ((rbeg (region-beginning)) + (rend (region-end)) + (beg (save-excursion (goto-char rbeg) (line-beginning-position))) + (end (save-excursion (goto-char rend) (if (bolp) (point) (1+ (line-end-position))))) + (offset-from-beg (- rbeg beg)) + (region-len (- rend rbeg)) + (lines (count-lines beg end)) + (text (delete-and-extract-region beg end))) + (forward-line 1) + (let ((new-beg (point))) + (insert text) + (set-mark (+ new-beg offset-from-beg)) + (goto-char (+ new-beg offset-from-beg region-len)) + (setq deactivate-mark nil)))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Word Deletion +;;; ============================================================================ + +(defun my-delete-word (arg) + "Delete characters forward until encountering the end of a word. +With argument ARG, do this that many times. +Does not copy to kill ring." + (interactive "p") + (delete-region (point) (progn (forward-word arg) (point)))) + +(defun my-backward-delete-word (arg) + "Delete characters backward until encountering the beginning of a word. +With argument ARG, do this that many times. +Does not copy to kill ring." + (interactive "p") + (my-delete-word (- arg))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Compile Commands +;;; ============================================================================ + +(defvar my-project-data-dir "~/.emacs.d/project-data/" "Directory to store per-project data.") + +(defun my-project-data-file (filename) + "Get path to FILENAME for current project in project-data dir." + (let* ((root (project-root (project-current t))) + (hash (md5 root)) + (dir (expand-file-name hash my-project-data-dir))) + (unless (file-exists-p dir) + (make-directory dir t)) + (expand-file-name filename dir))) + +(defun my-compile-get-saved-command () + "Get saved compile command for current project." + (let ((file (my-project-data-file "compile-command"))) + (when (file-exists-p file) + (with-temp-buffer + (insert-file-contents file) + (string-trim (buffer-string)))))) + +(defun my-compile-save-command (cmd) + "Save compile command CMD for current project." + (let ((file (my-project-data-file "compile-command"))) + (with-temp-file file + (insert cmd)))) + +(defun my-compile-custom () + "Run a custom compile command in the project root." + (interactive) + (let* ((default-directory (project-root (project-current t))) + (saved (my-compile-get-saved-command)) + (cmd (read-string "Command: " saved))) + (my-compile-save-command cmd) + (compile cmd))) + +(defun my-compile-last () + "Run last compile command, or prompt for one if none has been run." + (interactive) + (let* ((default-directory (project-root (project-current t))) + (cmd (my-compile-get-saved-command))) + (if cmd + (compile cmd) + (my-compile-custom)))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - CTAGS +;;; ============================================================================ + +(defun my-tags-get-saved () + "Get saved TAGS file path for current project." + (when (project-current) + (let ((file (my-project-data-file "tags-file"))) + (when (file-exists-p file) + (with-temp-buffer + (insert-file-contents file) + (string-trim (buffer-string))))))) + +(defun my-tags-save (tags-path) + "Save TAGS file path for current project." + (when (project-current) + (let ((file (my-project-data-file "tags-file"))) + (with-temp-file file + (insert tags-path))))) + +(defun my-tags-load () + "Load saved TAGS file for current project." + (let ((saved (my-tags-get-saved))) + (when (and saved (file-exists-p saved)) + (visit-tags-table saved t)))) + +(add-hook 'find-file-hook #'my-tags-load) + +(defun ctags-generate () + "Generate TAGS file using ctags in project root or current directory." + (interactive) + (let* ((default-directory (or (and (project-current) + (project-root (project-current))) + default-directory)) + (tags-path (expand-file-name "TAGS" default-directory))) + (message "Generating TAGS in %s..." default-directory) + (shell-command "ctags -e -R --exclude=.git --exclude=log *") + (my-tags-save tags-path) + (visit-tags-table tags-path) + (message "TAGS generated and saved: %s" tags-path))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - File Operations +;;; ============================================================================ + +(defvar my--find-file-right-pane nil) + +(defun my-find-file-right-pane () + "Open file in right pane from find-file minibuffer." + (interactive) + (setq my--find-file-right-pane (expand-file-name (minibuffer-contents))) + (abort-recursive-edit)) + +(defun my-find-file-right-pane-after () + "Actually open the file in right pane." + (when my--find-file-right-pane + (let ((file my--find-file-right-pane)) + (setq my--find-file-right-pane nil) + (when (one-window-p) + (split-window-right)) + (other-window 1) + (find-file file)))) + +(add-hook 'minibuffer-exit-hook 'my-find-file-right-pane-after) + +(defun my-copy-path-with-line () + "Copy the current file path with line number to clipboard." + (interactive) + (if buffer-file-name + (let ((path-with-line (format "%s:%d" buffer-file-name (line-number-at-pos)))) + (kill-new path-with-line) + (message "Copied: %s" path-with-line)) + (message "Buffer has no file."))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Theme Selection +;;; ============================================================================ + +(add-to-list 'custom-theme-load-path "~/.emacs.d/themes/") +(defvar my-current-theme 'bedroom "Currently active theme.") + +(defun my-select-theme () + "Select and load a theme from all available themes." + (interactive) + (let* ((themes (append '("default" "default-dark") (mapcar #'symbol-name (custom-available-themes)))) + (choice (completing-read "Theme: " themes nil t))) + (when my-current-theme + (disable-theme my-current-theme)) + (cond + ((string= choice "default") + (set-foreground-color "black") + (set-background-color "white") + (setq my-current-theme nil)) + ((string= choice "default-dark") + (set-foreground-color "white") + (set-background-color "black") + (setq my-current-theme nil)) + (t + (setq my-current-theme (intern choice)) + (load-theme my-current-theme t))))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Zoom +;;; ============================================================================ + +(defvar my-default-font-height (face-attribute 'default :height)) + +(defun my-global-zoom-in () + (interactive) + (set-face-attribute 'default nil :height (+ (face-attribute 'default :height) 10))) + +(defun my-global-zoom-out () + (interactive) + (set-face-attribute 'default nil :height (- (face-attribute 'default :height) 10))) + +(defun my-global-zoom-reset () + (interactive) + (set-face-attribute 'default nil :height my-default-font-height)) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Buffer Management +;;; ============================================================================ + +(defun kill-other-buffers () + "Kill all buffers except the current one and close other panes." + (interactive) + (let ((current (current-buffer))) + (dolist (buf (buffer-list)) + (unless (eq buf current) + (let ((proc (get-buffer-process buf))) + (when proc + (let ((pid (process-id proc))) + (when pid + (my-kill-process-tree pid))) + (set-process-query-on-exit-flag proc nil))) + (with-current-buffer buf + (set-buffer-modified-p nil)) + (kill-buffer buf)))) + (setq recentf-list nil) + (delete-other-windows)) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Window Management +;;; ============================================================================ + +(defun my-transpose-windows (arg) + "Transpose the buffers shown in two windows." + (interactive "p") + (let ((selector (if (>= arg 0) 'next-window 'previous-window))) + (while (/= arg 0) + (let ((this-win (window-buffer)) + (next-win (window-buffer (funcall selector)))) + (set-window-buffer (selected-window) next-win) + (set-window-buffer (funcall selector) this-win) + (select-window (funcall selector))) + (setq arg (if (plusp arg) (1- arg) (1+ arg)))))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Rectangle Selection +;;; ============================================================================ + +(defun my-mouse-start-rectangle (start-event) + (interactive "e") + (deactivate-mark) + (mouse-set-point start-event) + (rectangle-mark-mode +1) + (let ((drag-event)) + (track-mouse + (while (progn + (setq drag-event (read-event)) + (mouse-movement-p drag-event)) + (mouse-set-point drag-event))))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - External Tools +;;; ============================================================================ + +(defun my-file-manager-command () + (interactive) + (cond ((eq system-type 'windows-nt) + (shell-command "explorer.exe .")) + ((eq system-type 'darwin) + (shell-command "open .")) + ((eq system-type 'gnu/linux) + (shell-command "setsid -f nautilus . >/dev/null 2>&1")))) + +(defun my-terminal-emulator-command () + (interactive) + (cond ((eq system-type 'windows-nt) + (let ((proc (start-process "cmd" nil "cmd.exe" "/C" "start" "cmd.exe"))) + (set-process-query-on-exit-flag proc nil))) + ((eq system-type 'gnu/linux) + (shell-command "setsid -f gnome-terminal . >/dev/null 2>&1")))) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Emacs Config +;;; ============================================================================ + +(defun reload-emacs-config () + "Reload the Emacs configuration file." + (interactive) + (load-file "~/.emacs.d/init.el") + (message "Emacs config reloaded.")) + +(defun edit-emacs-config () + "Open the Emacs configuration file for editing." + (interactive) + (find-file "~/.emacs.d/init.el")) + +;;; ============================================================================ +;;; CUSTOM FUNCTIONS - Misc +;;; ============================================================================ + +(defun my-test () + (interactive) + (message "Hello world!")) + +(defun lipsum () + "Insert lorem ipsum placeholder text." + (interactive) + (insert "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")) + +(defun my-mc-mark-next-like-this () + "VSCode-style C-d: first press selects word, subsequent presses add cursors." + (interactive) + (if (use-region-p) + (progn + (mc/mark-next-like-this 1) + (mc/maybe-multiple-cursors-mode)) + (let ((bounds (bounds-of-thing-at-point 'symbol))) + (when bounds + (goto-char (car bounds)) + (set-mark (cdr bounds)) + (activate-mark))))) + +(defun my-insert-shell-command-output () + "Prompt for a shell command and insert its output at point." + (interactive) + (let ((command (read-string "Shell command: "))) + (insert (string-trim-right (shell-command-to-string command))))) + +(defun my-toggle-macro-recording () + "Toggle keyboard macro recording. Start if not recording, stop if recording." + (interactive) + (if defining-kbd-macro + (progn + (kmacro-end-macro nil) + (message "Macro recorded. Press F4 to replay.")) + (kmacro-start-macro nil) + (message "Recording macro... Press C- to stop."))) + +(defun my-call-macro () + "Call last macro. If region is active, run macro N times where N is number of selected lines. +All changes from a multi-line macro execution are undoable as a single operation." + (interactive) + (if (use-region-p) + (let ((lines (count-lines (region-beginning) (region-end))) + (change-group (prepare-change-group))) + (goto-char (region-beginning)) + (deactivate-mark) + (unwind-protect + (progn + (activate-change-group change-group) + (kmacro-call-macro lines)) + (undo-amalgamate-change-group change-group))) + (kmacro-call-macro 1))) + +;;; ============================================================================ +;;; TWEAKS & FIXES +;;; ============================================================================ + +;; fix isearch wrapping behavior +(defadvice isearch-search (after isearch-no-fail activate) + (unless isearch-success + (ad-disable-advice 'isearch-search 'after 'isearch-no-fail) + (ad-activate 'isearch-search) + (isearch-repeat (if isearch-forward 'forward)) + (ad-enable-advice 'isearch-search 'after 'isearch-no-fail) + (ad-activate 'isearch-search))) + +;; go to match beginning after isearch +(add-hook 'isearch-mode-end-hook + #'endless/goto-match-beginning) + +(defun endless/goto-match-beginning () + "Go to the start of current isearch match. +Use in `isearch-mode-end-hook'." + (when (and isearch-forward + (number-or-marker-p isearch-other-end) + (not mark-active) + (not isearch-mode-end-hook-quit)) + (goto-char isearch-other-end))) + +;;; ============================================================================ +;;; APPEARANCE & THEME +;;; ============================================================================ + +;; (set-face-attribute 'default nil :font "Consolas-15") + +(load-theme 'bedroom t) + +;;; init.el ends here diff --git a/.emacs.d/themes/bedroom-theme.el b/.emacs.d/themes/bedroom-theme.el index 3389dc2..53a9fdc 100644 --- a/.emacs.d/themes/bedroom-theme.el +++ b/.emacs.d/themes/bedroom-theme.el @@ -16,9 +16,13 @@ '(region ((t (:background "#15285A")))) '(hl-line ((t (:background "#000000")))) '(highlight ((t (:background "#15285A")))) - '(mode-line ((t (:background "#505050" :foreground "#DADEE5")))) - '(mode-line-inactive ((t (:background "#2A2A2A" :foreground "#888888")))) + '(mode-line ((t (:background "#1E3050" :foreground "#DADEE5")))) + '(mode-line-inactive ((t (:background "#182438" :foreground "#6A7A8A")))) '(vertical-border ((t (:foreground "#505050")))) + '(fringe ((t (:background "#141B2B")))) + '(window-divider ((t (:foreground "#3A4255")))) + '(window-divider-first-pixel ((t (:foreground "#141B2B")))) + '(window-divider-last-pixel ((t (:foreground "#3A4255")))) '(tab-line ((t (:background "#505050" :foreground "#DADEE5")))) '(tab-line-tab ((t (:background "#505050" :foreground "#DADEE5")))) '(tab-line-tab-current ((t (:background "#505050" :foreground "#DADEE5")))) diff --git a/.emacs.d/themes/focus-theme.el b/.emacs.d/themes/focus-theme.el new file mode 100644 index 0000000..ae2c4ea --- /dev/null +++ b/.emacs.d/themes/focus-theme.el @@ -0,0 +1,140 @@ +;;; focus-theme.el --- Focus dark color theme -*- lexical-binding: t; -*- + +;;; Commentary: +;; Default theme from the Focus Editor. +;; +;; https://focus-editor.dev/ +;; https://github.com/focus-editor/focus + +;;; Code: + +(deftheme focus + "Focus dark color theme.") + +(custom-theme-set-faces + 'focus + ;; Basic faces + '(default ((t (:foreground "#BFC9DB" :background "#15212A")))) + '(cursor ((t (:background "#26B2B2")))) + '(region ((t (:background "#1C4449")))) + '(hl-line ((t (:background "#18262F")))) + '(highlight ((t (:background "#1C4449")))) + '(secondary-selection ((t (:background "#1C4449")))) + '(lazy-highlight ((t (:background "#8E772E")))) + '(isearch ((t (:background "#8E772E" :foreground "#FFFFFF")))) + '(isearch-fail ((t (:background "#772222")))) + '(match ((t (:background "#1C4449")))) + + ;; Mode line + '(mode-line ((t (:background "#1C303A" :foreground "#BFC9DB")))) + '(mode-line-inactive ((t (:background "#10191F" :foreground "#87919D")))) + '(mode-line-buffer-id ((t (:foreground "#BFC9DB" :weight bold)))) + + ;; Borders and dividers + '(vertical-border ((t (:foreground "#10191F")))) + '(fringe ((t (:background "#15212A")))) + '(window-divider ((t (:foreground "#1C4449")))) + '(window-divider-first-pixel ((t (:foreground "#15212A")))) + '(window-divider-last-pixel ((t (:foreground "#1C4449")))) + + ;; Tab line + '(tab-line ((t (:background "#1A2831" :foreground "#BFC9DB")))) + '(tab-line-tab ((t (:background "#1A2831" :foreground "#BFC9DB")))) + '(tab-line-tab-current ((t (:background "#21333F" :foreground "#BFC9DB")))) + '(tab-line-tab-inactive ((t (:background "#10191F" :foreground "#87919D")))) + + ;; Line numbers + '(line-number ((t (:foreground "#87919D" :background "#15212A")))) + '(line-number-current-line ((t (:foreground "#BFC9DB" :background "#18262F")))) + + ;; Font lock faces + '(font-lock-builtin-face ((t (:foreground "#E0AD82")))) + '(font-lock-comment-face ((t (:foreground "#87919D")))) + '(font-lock-comment-delimiter-face ((t (:foreground "#87919D")))) + '(font-lock-doc-face ((t (:foreground "#87919D")))) + '(font-lock-string-face ((t (:foreground "#D4BC7D")))) + '(font-lock-keyword-face ((t (:foreground "#E67D74")))) + '(font-lock-function-name-face ((t (:foreground "#D0C5A9")))) + '(font-lock-variable-name-face ((t (:foreground "#BFC9DB")))) + '(font-lock-constant-face ((t (:foreground "#D699B5")))) + '(font-lock-type-face ((t (:foreground "#82AAA3")))) + '(font-lock-warning-face ((t (:foreground "#F8AD34")))) + '(font-lock-negation-char-face ((t (:foreground "#E67D74")))) + '(font-lock-preprocessor-face ((t (:foreground "#E67D74")))) + '(font-lock-regexp-grouping-backslash ((t (:foreground "#E0AD82")))) + '(font-lock-regexp-grouping-construct ((t (:foreground "#E0AD82")))) + + ;; Parenthesis matching + '(show-paren-match ((t (:background "#1C4449" :foreground "#FFFFFF")))) + '(show-paren-mismatch ((t (:background "#772222" :foreground "#FFFFFF")))) + + ;; Minibuffer + '(minibuffer-prompt ((t (:foreground "#26B2B2")))) + + ;; Compilation + '(compilation-info ((t (:foreground "#227722")))) + '(compilation-warning ((t (:foreground "#F8AD34")))) + '(compilation-error ((t (:foreground "#FF0000")))) + '(compilation-mode-line-exit ((t (:foreground "#227722")))) + '(compilation-mode-line-fail ((t (:foreground "#772222")))) + + ;; Flymake + '(flymake-error ((t (:underline (:style wave :color "#772222"))))) + '(flymake-warning ((t (:underline (:style wave :color "#986032"))))) + '(flymake-note ((t (:underline (:style wave :color "#87919D"))))) + + ;; Flyspell + '(flyspell-incorrect ((t (:underline (:style wave :color "#772222"))))) + '(flyspell-duplicate ((t (:underline (:style wave :color "#986032"))))) + + ;; Ivy + '(ivy-current-match ((t (:background "#1C4449" :foreground "#BFC9DB")))) + '(ivy-minibuffer-match-face-1 ((t (:foreground "#599999")))) + '(ivy-minibuffer-match-face-2 ((t (:foreground "#26B2B2" :weight bold)))) + '(ivy-minibuffer-match-face-3 ((t (:foreground "#E0AD82" :weight bold)))) + '(ivy-minibuffer-match-face-4 ((t (:foreground "#D699B5" :weight bold)))) + '(ivy-confirm-face ((t (:foreground "#227722")))) + '(ivy-match-required-face ((t (:foreground "#772222")))) + + ;; Dired + '(dired-directory ((t (:foreground "#82AAA3")))) + '(dired-symlink ((t (:foreground "#26B2B2")))) + '(dired-ignored ((t (:foreground "#87919D")))) + + ;; Diff + '(diff-added ((t (:background "#226022" :foreground "#BFC9DB")))) + '(diff-removed ((t (:background "#772222" :foreground "#BFC9DB")))) + '(diff-changed ((t (:background "#986032" :foreground "#BFC9DB")))) + '(diff-header ((t (:background "#1A2831" :foreground "#BFC9DB")))) + '(diff-file-header ((t (:background "#21333F" :foreground "#BFC9DB")))) + '(diff-hunk-header ((t (:background "#1C4449" :foreground "#BFC9DB")))) + + ;; Ediff + '(ediff-current-diff-A ((t (:background "#772222")))) + '(ediff-current-diff-B ((t (:background "#226022")))) + '(ediff-current-diff-C ((t (:background "#986032")))) + '(ediff-fine-diff-A ((t (:background "#993333")))) + '(ediff-fine-diff-B ((t (:background "#338033")))) + '(ediff-fine-diff-C ((t (:background "#B87842")))) + + ;; Eglot + '(eglot-highlight-symbol-face ((t (:background "#1C4449")))) + + ;; Link + '(link ((t (:foreground "#26B2B2" :underline t)))) + '(link-visited ((t (:foreground "#D699B5" :underline t)))) + + ;; Custom/widget faces + '(custom-group-tag ((t (:foreground "#82AAA3" :weight bold)))) + '(custom-variable-tag ((t (:foreground "#82AAA3" :weight bold)))) + '(widget-field ((t (:background "#21333F" :foreground "#BFC9DB")))) + '(widget-single-line-field ((t (:background "#21333F" :foreground "#BFC9DB")))) + + ;; Error, warning, success + '(error ((t (:foreground "#FF0000")))) + '(warning ((t (:foreground "#F8AD34")))) + '(success ((t (:foreground "#227722"))))) + +(provide-theme 'focus) + +;;; focus-theme.el ends here diff --git a/.emacs.d/themes/jbeans-theme.el b/.emacs.d/themes/jbeans-theme.el deleted file mode 100644 index 56a7b89..0000000 --- a/.emacs.d/themes/jbeans-theme.el +++ /dev/null @@ -1,442 +0,0 @@ -;;; jbeans-theme.el --- Jbeans theme for GNU Emacs 24 (deftheme) - -;; Author: Adam Olsen -;; URL: -;; Version: 1.3 -;; Package-Requires: ((emacs "24")) -;; Based On: ujelly by Mark Tran -;; Package-Version: 20151208.2136 -;; "What do you mean, no one calls you JBeans?! I call you JBeans!" -;; -- Wilbur - -;; Based on ujelly by Mark Tran -;; Orig-URL: http://github.com/marktran/color-theme-ujelly -;; Inspired by jellybeans: http://www.vim.org/scripts/script.php?script_id=2555. - - -;; Copyright (c) 2017 Adam Olsen -;; -;; Permission is hereby granted, free of charge, to any person obtaining a copy -;; of this software and associated documentation files (the "Software"), to deal -;; in the Software without restriction, including without limitation the rights -;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -;; copies of the Software, and to permit persons to whom the Software is -;; furnished to do so, subject to the following conditions: -;; -;; The above copyright notice and this permission notice shall be included in all -;; copies or substantial portions of the Software. -;; -;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -;; SOFTWARE. - -(deftheme jbeans "The jbeans color theme") - -(let ((class '((class color) (min-colors 89))) - ;; GUI TER - (jbeans-fg (if (display-graphic-p) "#cccccc" "#cccccc")) - (jbeans-bg (if (display-graphic-p) "#151515" "#151515")) - (jbeans-grey-0 (if (display-graphic-p) "#151515" "#151515")) - (jbeans-grey-1 (if (display-graphic-p) "#112433" "#112433")) - (jbeans-grey-2 (if (display-graphic-p) "#222222" "#222222")) - (jbeans-grey-3 (if (display-graphic-p) "#333344" "#444455")) - (jbeans-grey-4 (if (display-graphic-p) "#363636" "#363636")) - (jbeans-grey-5 (if (display-graphic-p) "#444444" "#444444")) - (jbeans-grey-6 (if (display-graphic-p) "#7f7f7f" "#7f7f7f")) - (jbeans-grey-7 (if (display-graphic-p) "#888888" "#888888")) - (jbeans-purple-0 (if (display-graphic-p) "#ff73fd" "#ff73fd")) - (jbeans-purple-1 (if (display-graphic-p) "#cd00cd" "#cd00cd")) - (jbeans-purple-2 (if (display-graphic-p) "#a40073" "#a40073")) - (jbeans-purple-3 (if (display-graphic-p) "#540063" "#540063")) - (jbeans-purple-4 (if (display-graphic-p) "#474e90" "#474e90")) - (jbeans-purple-5 (if (display-graphic-p) "#202025" "#202025")) - (jbeans-blue-0 (if (display-graphic-p) "#8197bf" "#8197bf")) - (jbeans-blue-1 (if (display-graphic-p) "#8fbfdc" "#8fbfdc")) - (jbeans-blue-2 (if (display-graphic-p) "#b2e2fe" "#b2e2fe")) - (jbeans-blue-3 (if (display-graphic-p) "#447799" "#447799")) - (jbeans-blue-4 (if (display-graphic-p) "#0b24fb" "#0b24fb")) - (jbeans-blue-5 (if (display-graphic-p) "#2dfffe" "#2dfffe")) - (jbeans-green-0 (if (display-graphic-p) "#ddffdd" "#ddffdd")) - (jbeans-green-1 (if (display-graphic-p) "#b6edb6" "#b6edb6")) - (jbeans-green-2 (if (display-graphic-p) "#448844" "#448844")) - (jbeans-green-3 (if (display-graphic-p) "#556a32" "#556a32")) - (jbeans-green-4 (if (display-graphic-p) "#335533" "#335533")) - (jbeans-green-5 (if (display-graphic-p) "#99ad6a" "#99ad6a")) - (jbeans-green-6 (if (display-graphic-p) "#a8ff60" "#a8ff60")) - (jbeans-green-7 (if (display-graphic-p) "#29fd2f" "#29fd2f")) - (jbeans-yellow-0 (if (display-graphic-p) "#ffffcc" "#ffffcc")) - (jbeans-yellow-1 (if (display-graphic-p) "#ffff00" "#ffff00")) - (jbeans-yellow-2 (if (display-graphic-p) "#eddb87" "#eddb87")) - (jbeans-yellow-3 (if (display-graphic-p) "#fad07a" "#fad07a")) - (jbeans-orange-0 (if (display-graphic-p) "#ffb964" "#ffb964")) - (jbeans-orange-1 (if (display-graphic-p) "#ff8c00" "#ebbd87")) - (jbeans-orange-2 (if (display-graphic-p) "#b78521" "#b78521")) - (jbeans-red-0 (if (display-graphic-p) "#cb8165" "#cb8165")) - (jbeans-red-1 (if (display-graphic-p) "#cf6a4c" "#cf6a4c")) - (jbeans-red-2 (if (display-graphic-p) "#de5577" "#de5577")) - (jbeans-red-3 (if (display-graphic-p) "#fc644d" "#fc644d")) - (jbeans-red-4 (if (display-graphic-p) "#dd0093" "#dd0093")) - (jbeans-red-5 (if (display-graphic-p) "#aa4444" "#aa4444")) - (jbeans-red-6 (if (display-graphic-p) "#8a3b3c" "#8a3b3c")) - (jbeans-red-7 (if (display-graphic-p) "#663333" "#663333")) - (jbeans-red-8 (if (display-graphic-p) "#fc0d1b" "#fc0d1b")) - (jbeans-red-9 (if (display-graphic-p) "#ffdddd" "#ffdddd")) - ) - - (custom-theme-set-variables - 'jbeans - `(linum-format " %3i ")) - - (custom-theme-set-faces - 'jbeans - `(default ((,class (:foreground ,jbeans-fg :background ,jbeans-bg)))) -;;;;; ACE/Avy - `(aw-leading-char-face ((,class (:foreground ,jbeans-red-3 :height 1.2)))) -;;;;; Alchemist - `(alchemist-test--failed-face ((,class (:foreground ,jbeans-red-1)))) - `(alchemist-test--success-face ((,class (:foreground ,jbeans-green-5)))) -;;;;; Company - `(company-preview-common ((,class (:foreground nil :background ,jbeans-purple-4)))) - `(company-scrollbar-bg ((,class (:background ,jbeans-grey-0)))) - `(company-scrollbar-fg ((,class (:background ,jbeans-grey-7)))) - `(company-tooltip ((,class (:background ,jbeans-grey-0 :foreground ,jbeans-fg :weight bold)))) - `(company-tooltip-annotation ((,class (:inherit company-tooltip :foreground ,jbeans-blue-0)))) - `(company-tooltip-common ((,class (:inherit company-tooltip :weight bold :underline nil)))) - `(company-tooltip-common-selection ((,class (:inherit company-tooltip-selection :foreground ,jbeans-fg :underline nil :weight bold)))) - `(company-tooltip-selection ((,class (:background ,jbeans-purple-4)))) -;;;;; Compilation - `(compilation-error ((,class (:foreground ,jbeans-red-1)))) - `(compilation-info ((,class (:foreground ,jbeans-yellow-3)))) - `(compilation-line-number ((,class (:foreground ,jbeans-grey-7)))) - `(compilation-mode-line-exit ((,class (:foreground ,jbeans-green-5)))) - `(compilation-mode-line-fail ((,class (:foreground ,jbeans-red-1)))) - `(compilation-mode-line-run ((,class (:foreground ,jbeans-yellow-3)))) -;;;;; Dired - `(diredp-compressed-file-name ((,class (:foreground ,jbeans-red-7)))) - `(diredp-compressed-file-suffix ((,class (:foreground ,jbeans-fg)))) - `(diredp-date-time ((,class (:foreground ,jbeans-green-5)))) - `(diredp-deletion ((,class (:foreground ,jbeans-red-1 :background ,jbeans-bg)))) - `(diredp-dir-heading ((,class (:foreground ,jbeans-yellow-3 :background ,jbeans-bg)))) - `(diredp-dir-priv ((,class (:foreground ,jbeans-purple-2 :background ,jbeans-bg)))) - `(diredp-exec-priv ((,class (:foreground ,jbeans-orange-2 :background ,jbeans-bg)))) - `(diredp-file-name ((,class (:foreground ,jbeans-green-0)))) - `(diredp-file-suffix ((,class (:foreground ,jbeans-fg)))) - `(diredp-flag-mark ((,class (:foreground ,jbeans-blue-0 :weight bold)))) - `(diredp-flag-mark-line ((,class (:foreground ,jbeans-purple-4 :weight bold)))) - `(diredp-link-priv ((,class (:foreground ,jbeans-fg)))) - `(diredp-number ((,class (:foreground ,jbeans-grey-6)))) - `(diredp-no-priv ((,class (:foreground ,jbeans-fg :background ,jbeans-bg)))) - `(diredp-rare-priv ((,class (:foreground ,jbeans-red-1 :background ,jbeans-bg)))) - `(diredp-read-priv ((,class (:foreground ,jbeans-yellow-3 :background ,jbeans-bg)))) - `(diredp-symlink ((,class (:foreground ,jbeans-blue-0)))) - `(diredp-dir-name ((,class (:foreground ,jbeans-blue-2)))) - `(diredp-write-priv ((,class (:foreground ,jbeans-blue-0 :background ,jbeans-bg)))) -;;;;; Emmet - `(emmet-preview-output ((,class (:background ,jbeans-purple-4)))) -;;;;; Elixir - `(elixir-atom-face ((,class (:foreground ,jbeans-blue-1)))) -;;;;; ERC - `(erc-notice-face ((,class (:foreground ,jbeans-yellow-3)))) - `(erc-prompt-face ((,class (:foreground ,jbeans-fg)))) - `(erc-timestamp-face ((,class (:foreground ,jbeans-blue-0)))) -;;;;;; EShell - `(eshell-prompt ((,class (:foreground ,jbeans-red-1)))) - `(eshell-ls-directory ((,class (:weight normal :foreground ,jbeans-green-6)))) - `(eshell-ls-executable ((,class (:weight normal :foreground ,jbeans-red-1)))) - `(eshell-ls-product ((,class (:foreground ,jbeans-fg)))) - `(eshell-ls-symlink ((,class (:weight normal :foreground ,jbeans-purple-1)))) -;;;;; Evil - `(evil-visual-mark-face ((,class (:weight ultra-bold :box ,jbeans-blue-0 :foreground ,jbeans-green-7)))) -;;;;; FCI Ruler - ;; As of now, this does nothing, because fci-rule-color is not a face yet. - `(fci-rule-color ((,class (:foreground ,jbeans-grey-4 :background ,jbeans-grey-4)))) - `(fill-column-indicator ((,class (:foreground ,jbeans-grey-3 :background ,jbeans-bg)))) -;;;;; Fonts - `(font-lock-builtin-face ((,class (:foreground ,jbeans-blue-1)))) - `(font-lock-comment-face ((,class (:slant italic :foreground ,jbeans-grey-7)))) - `(font-lock-constant-face ((,class (:foreground ,jbeans-blue-3)))) - `(font-lock-doc-face ((,class (:foreground ,jbeans-green-5)))) - `(font-lock-function-name-face ((,class (:foreground ,jbeans-yellow-3)))) - `(font-lock-keyword-face ((,class (:foreground ,jbeans-blue-0)))) - `(font-lock-preprocessor-face ((,class (:foreground ,jbeans-fg)))) - `(font-lock-string-face ((,class (:foreground ,jbeans-green-5)))) - `(font-lock-type-face ((,class (:foreground ,jbeans-orange-0)))) - `(font-lock-variable-name-face ((,class (:foreground ,jbeans-red-1)))) - `(font-lock-warning-face ((,class (:foreground ,jbeans-red-4)))) - `(font-lock-regexp-grouping-construct ((,class (:foreground ,jbeans-yellow-3 :bold t)))) - `(font-lock-regexp-grouping-backslash ((,class (:foreground ,jbeans-red-1 :bold t)))) -;;;;; Fringe - `(fringe ((,class (:foreground ,jbeans-fg :background ,jbeans-bg)))) -;;;;; Header - `(header-line ((,class (:foreground ,jbeans-fg)))) -;;;;; Helm - `(helm-visible-mark ((,class (:background ,jbeans-green-4 :foreground ,jbeans-bg)))) - `(helm-buffer-file ((,class (:foreground ,jbeans-fg)))) - `(helm-buffer-directory ((,class (:foreground ,jbeans-blue-0)))) - `(helm-buffer-process ((,class (:foreground ,jbeans-yellow-3)))) - `(helm-buffer-size ((,class (:foreground ,jbeans-fg)))) - `(helm-candidate-number ((,class (:foreground ,jbeans-fg :background ,jbeans-bg)))) - `(helm-grep-lineno ((,class (:foreground ,jbeans-fg)))) - `(helm-grep-finish ((,class (:foreground ,jbeans-blue-2)))) - `(helm-match ((,class (:foreground ,jbeans-red-4 :background ,jbeans-bg)))) - `(helm-moccur-buffer ((,class (:foreground ,jbeans-yellow-3)))) - `(helm-selection ((,class (:background ,jbeans-grey-3)))) - `(helm-source-header ((,class (:foreground ,jbeans-yellow-3 :background ,jbeans-grey-0)))) - `(helm-swoop-target-line-face ((,class (:foreground ,jbeans-fg :background ,jbeans-grey-4)))) - `(helm-swoop-target-word-face ((,class (:foreground ,jbeans-red-4)))) - `(helm-ff-file ((,class (:foreground ,jbeans-fg)))) - `(helm-ff-directory ((,class (:foreground ,jbeans-blue-2)))) - `(helm-ff-executable ((,class (:foreground ,jbeans-green-5)))) -;;;;; Highlight - `(highlight ((,class (:background ,jbeans-grey-3)))) - `(hl-line ((,class (:background ,jbeans-purple-5)))) -;;;;; iSearch - `(isearch ((,class (:foreground ,jbeans-fg :background ,jbeans-red-4)))) - `(isearch-fail ((,class (:background ,jbeans-red-4)))) -;;;;; Ido - `(ido-first-match ((,class (:foreground ,jbeans-yellow-3)))) - `(ido-only-match ((,class (:foreground ,jbeans-green-5)))) - `(ido-subdir ((,class (:foreground ,jbeans-fg)))) - `(ido-virtual ((,class (:foreground - ,jbeans-blue-0)))) -;;;;; Ivy - `(ivy-current-match ((,class (:background ,jbeans-grey-3)))) - `(ivy-minibuffer-match-face-1 ((,class (:foreground ,jbeans-yellow-3)))) - `(ivy-minibuffer-match-face-2 ((,class (:foreground ,jbeans-orange-0)))) - `(ivy-minibuffer-match-face-3 ((,class (:foreground ,jbeans-blue-1)))) - `(ivy-minibuffer-match-face-4 ((,class (:foreground ,jbeans-purple-1)))) - `(ivy-subdir ((,class (:foreground ,jbeans-green-4)))) - `(ivy-modified-buffer ((,class (:foreground ,jbeans-red-2)))) -;;;;; Jabber - `(jabber-activity-personal-face ((,class (:foreground ,jbeans-green-6 :weight bold)))) - `(jabber-activity-face ((,class (:foreground ,jbeans-red-3 :weight bold)))) - `(jabber-roster-user-online ((,class (:foreground ,jbeans-blue-0)))) - `(jabber-roster-user-dnd ((,class (:foreground ,jbeans-red-3)))) - `(jabber-chat-prompt-system ((,class (:foreground ,jbeans-green-6)))) - `(jabber-chat-prompt-local ((,class (:foreground ,jbeans-blue-0)))) - `(jabber-chat-prompt-foreign ((,class (:foreground ,jbeans-green-2)))) -;;;;; Lazy highlight - `(lazy-highlight ((,class (:foreground ,jbeans-red-4 :background nil)))) -;;;;; Linum - `(linum ((,class (:foreground ,jbeans-grey-5 :background ,jbeans-grey-2)))) -;;;;; Display line numbers - `(line-number ((,class (:foreground ,jbeans-grey-5 :background ,jbeans-grey-2)))) -;;;;; Ediff - `(ediff-even-diff-A ((,class (:background ,jbeans-grey-2 :foreground ,jbeans-fg)))) - `(ediff-even-diff-B ((,class (:background ,jbeans-grey-3 :foreground ,jbeans-fg)))) - `(ediff-even-diff-C ((,class (:background ,jbeans-grey-3 :foreground ,jbeans-fg)))) - `(ediff-odd-diff-A ((,class (:background ,jbeans-grey-2 :foreground ,jbeans-fg)))) - `(ediff-odd-diff-B ((,class (:background ,jbeans-grey-3 :foreground ,jbeans-fg)))) - `(ediff-odd-diff-C ((,class (:background ,jbeans-grey-5 :foreground ,jbeans-fg)))) - `(powerline-active1 ((,class (:inherit mode-line :background ,jbeans-bg)))) - `(powerline-active2 ((,class (:inherit mode-line :background ,jbeans-grey-3)))) - `(powerline-inactive1 ((,class (:inherit mode-line :background ,jbeans-bg)))) - `(powerline-inactive2 ((,class (:inherit mode-line :background ,jbeans-grey-2)))) -;;;;; flycheck - `(flycheck-error ((((supports :underline (:style wave))) - (:underline (:style wave :color ,jbeans-red-4) :inherit unspecified)) - (,class (:underline (:style line :color ,jbeans-red-4))))) - `(flycheck-warning ((((supports :underline (:style wave))) - (:underline (:style wave :color ,jbeans-yellow-3) :inherit unspecified)) - (,class (:underline (:style line :color ,jbeans-yellow-3))))) - `(flycheck-info ((((supports :underline (:style wave))) - (:underline (:style wave :color ,jbeans-blue-5) :inherit unspecified)) - (,class (:underline (:style line :color ,jbeans-blue-5))))) - `(flycheck-fringe-error ((,class (:foreground ,jbeans-red-4 :weight bold)))) - `(flycheck-fringe-warning ((,class (:foreground ,jbeans-yellow-3 :weight bold)))) - `(flycheck-fringe-info ((,class (:foreground ,jbeans-blue-5 :weight bold)))) -;;;;; flyspell - `(flyspell-duplicate ((((supports :underline (:style wave))) - (:underline (:style wave :color ,jbeans-orange-1) :inherit unspecified)) - (,class (:underline (:style line :color ,jbeans-orange-1))))) - `(flyspell-incorrect ((((supports :underline (:style wave))) - (:underline (:style wave :color ,jbeans-red-8) :inherit unspecified)) - (,class (:underline (:style line :color ,jbeans-red-8))))) -;;;;; Git - `(git-commit-comment-file ((,class (:background ,jbeans-bg :foreground ,jbeans-fg)))) - `(git-commit-summary ((,class (:background ,jbeans-bg :foreground ,jbeans-blue-0)))) - `(git-commit-comment-heading ((,class (:foreground ,jbeans-yellow-3)))) -;;;;; Git-gutter - `(git-gutter-fr+-modified ((,class (:foreground ,jbeans-blue-3 :background ,jbeans-bg)))) - `(git-gutter-fr+-added ((,class (:foreground ,jbeans-green-2 :background ,jbeans-bg)))) - `(git-gutter-fr+-deleted ((,class (:foreground - ,jbeans-red-5 :background ,jbeans-bg)))) -;;;;; Highlighting - `(hi-yellow ((,class (:box ,jbeans-yellow-1 :foreground ,jbeans-yellow-1 :background, jbeans-grey-4)))) -;;;;; Magit - `(magit-blame-heading ((,class (:background ,jbeans-grey-2 :box ,jbeans-purple-4 :weight bold :foreground ,jbeans-fg)))) - `(magit-blame-date ((,class (:background ,jbeans-grey-0 :box ,jbeans-green-3 :weight bold :foreground ,jbeans-green-5)))) - `(magit-blame-name ((,class (:background ,jbeans-grey-0 :box ,jbeans-green-3 :weight bold :foreground ,jbeans-red-0)))) - `(magit-blame-hash ((,class (:background ,jbeans-grey-0 :box ,jbeans-green-3 :weight bold :foreground ,jbeans-blue-3)))) - `(magit-bisect-bad ((,class (:foreground ,jbeans-red-6)))) - `(magit-bisect-good ((,class (:foreground ,jbeans-green-3)))) - `(magit-bisect-skip ((,class (:foreground ,jbeans-orange-2)))) - `(magit-blame-summary ((,class (:inherit magit-blame-heading)))) - `(magit-branch-current ((,class (:inherit magit-branch-local :box 1)))) - `(magit-branch-local ((,class (:foreground ,jbeans-blue-2)))) - `(magit-branch-remote ((,class (:foreground ,jbeans-green-5)))) - `(magit-cherry-equivalent ((,class (:foreground ,jbeans-purple-1)))) - `(magit-cherry-unmatched ((,class (:foreground ,jbeans-blue-5)))) - `(magit-diff-added ((,class (:background ,jbeans-green-4 :foreground ,jbeans-green-0)))) - `(magit-diff-added-highlight ((,class (:background ,jbeans-green-4 :foreground ,jbeans-green-0)))) - `(magit-diff-base ((,class (:background ,jbeans-green-3 :foreground ,jbeans-yellow-0)))) - `(magit-diff-base-highlight ((,class (:background ,jbeans-green-3 :foreground ,jbeans-yellow-0)))) - `(magit-diff-conflict-heading ((,class (:inherit magit-diff-hunk-heading)))) - `(magit-diff-context ((,class (:background ,jbeans-bg :foreground ,jbeans-fg)))) - `(magit-diff-context-highlight ((,class (:background ,jbeans-bg :foreground ,jbeans-fg)))) - `(magit-diff-file-heading ((,class (:foreground ,jbeans-blue-0 :weight bold)))) - `(magit-diff-file-heading-highlight ((,class (:foreground ,jbeans-blue-0 :weight normal)))) - `(magit-diff-file-heading-selection ((,class (:background ,jbeans-bg :foreground ,jbeans-fg)))) - `(magit-diff-hunk-heading ((,class (:background ,jbeans-grey-3 :box ,jbeans-grey-3 :foreground ,jbeans-fg :weight bold)))) - `(magit-diff-hunk-heading-highlight ((,class (:background ,jbeans-grey-3 :box ,jbeans-grey-7 :weight bold :foreground ,jbeans-fg)))) - `(magit-diff-hunk-heading-selection ((,class (:inherit magit-diff-hunk-heading-highlight :foreground ,jbeans-red-0)))) - `(magit-diff-lines-boundary ((,class (:inherit magit-diff-lines-heading)))) - `(magit-diff-lines-heading ((,class (:inherit magit-diff-hunk-heading-highlight :background ,jbeans-red-6 :foreground ,jbeans-fg)))) - `(magit-diff-our ((,class (:inherit magit-diff-removed)))) - `(magit-diff-our-highlight ((,class (:inherit magit-diff-removed-highlight)))) - `(magit-diff-removed ((,class (:background ,jbeans-red-7 :foreground ,jbeans-red-9)))) - `(magit-diff-removed-highlight ((,class (:background ,jbeans-red-7 :foreground ,jbeans-red-9)))) - `(magit-diff-their ((,class (:inherit magit-diff-added)))) - `(magit-diff-their-highlight ((,class (:inherit magit-diff-added-highlight)))) - `(magit-diff-whitespace-warning ((,class (:inherit trailing-whitespace)))) - `(magit-diffstat-added ((,class (:foreground ,jbeans-green-2)))) - `(magit-diffstat-removed ((,class (:foreground ,jbeans-red-5)))) - `(magit-dimmed ((,class (:background ,jbeans-bg :foreground ,jbeans-grey-6)))) - `(magit-filename ((,class (:foreground ,jbeans-orange-2 :weight normal)))) - `(magit-hash ((,class (:foreground ,jbeans-grey-5)))) - `(magit-head ((,class (:inherit magit-branch-local)))) - `(magit-header-line ((,class (:inherit magit-section-heading)))) - `(magit-log-author ((,class (:foreground ,jbeans-blue-0)))) - `(magit-log-date ((,class (:foreground ,jbeans-green-5)))) - `(magit-log-graph ((,class (:foreground ,jbeans-fg)))) - `(magit-popup-argument ((,class (:inherit font-lock-warning-face)))) - `(magit-popup-disabled-argument ((,class (:inherit shadow)))) - `(magit-popup-heading ((,class (:inherit font-lock-keyword-face)))) - `(magit-popup-key ((,class (:inherit font-lock-builtin-face)))) - `(magit-popup-option-value ((,class (:inherit font-lock-string-face)))) - `(magit-process-ng ((,class (:inherit magit-section-heading :foreground ,jbeans-red-8)))) - `(magit-process-ok ((,class (:inherit magit-section-heading :foreground ,jbeans-green-7)))) - `(magit-reflog-amend ((,class (:foreground ,jbeans-purple-1)))) - `(magit-reflog-checkout ((,class (:foreground ,jbeans-blue-5)))) - `(magit-reflog-cherry-pick ((,class (:foreground ,jbeans-green-7)))) - `(magit-reflog-commit ((,class (:foreground ,jbeans-green-7)))) - `(magit-reflog-merge ((,class (:foreground ,jbeans-green-7)))) - `(magit-reflog-other ((,class (:foreground ,jbeans-blue-5)))) - `(magit-reflog-rebase ((,class (:foreground ,jbeans-purple-1)))) - `(magit-reflog-remote ((,class (:foreground ,jbeans-blue-5)))) - `(magit-reflog-reset ((,class (:foreground ,jbeans-red-8)))) - `(magit-refname ((,class (:background ,jbeans-bg :foreground ,jbeans-fg)))) - `(magit-refname-stash ((,class (:inherit magit-refname)))) - `(magit-refname-wip ((,class (:inherit magit-refname)))) - `(magit-section-heading ((,class (:background ,jbeans-bg :foreground ,jbeans-yellow-3)))) - `(magit-section-highlight ((,class (:background ,jbeans-bg)))) - `(magit-section-secondary-heading ((,class (:background ,jbeans-bg :weight bold)))) - `(magit-sequence-done ((,class (:inherit magit-hash)))) - `(magit-sequence-drop ((,class (:foreground ,jbeans-red-5)))) - `(magit-sequence-head ((,class (:foreground ,jbeans-blue-2)))) - `(magit-sequence-onto ((,class (:inherit magit-sequence-done)))) - `(magit-sequence-part ((,class (:foreground ,jbeans-yellow-2)))) - `(magit-sequence-pick ((,class (:inherit default)))) - `(magit-sequence-stop ((,class (:foreground ,jbeans-green-1)))) - `(magit-signature-bad ((,class (:foreground ,jbeans-red-8)))) - `(magit-signature-good ((,class (:foreground ,jbeans-green-7)))) - `(magit-signature-untrusted ((,class (:foreground ,jbeans-blue-5)))) - `(magit-tag ((,class (:foreground ,jbeans-yellow-2)))) -;;;;; Match - `(match ((,class (:background ,jbeans-red-4)))) -;;;;; Minibuffer - `(minibuffer-prompt ((,class (:foreground ,jbeans-yellow-3)))) -;;;;; Modeline - `(mode-line ((,class (:foreground ,jbeans-fg :background ,jbeans-grey-3)))) - `(mode-line-inactive ((,class (:foreground ,jbeans-grey-6 :background ,jbeans-grey-2)))) -;;;;; NeoTree - `(neo-dir-link-face ((,class (:foreground ,jbeans-blue-0)))) - `(neo-file-link-face ((,class (:foreground ,jbeans-fg)))) -;;;;; Org - `(org-checkbox ((,class (:foreground ,jbeans-green-5)))) - `(org-date ((,class (:foreground ,jbeans-blue-0)))) - `(org-document-title ((,class (:foreground ,jbeans-red-9)))) - `(org-done ((,class (:foreground ,jbeans-green-2)))) - `(org-level-1 ((,class (:foreground ,jbeans-orange-0 :weight bold)))) - `(org-level-2 ((,class (:foreground ,jbeans-green-5 :weight bold)))) - `(org-level-3 ((,class (:foreground ,jbeans-red-0)))) - `(org-link ((,class (:foreground ,jbeans-blue-1)))) - `(org-special-keyword ((,class (:foreground ,jbeans-blue-0)))) - `(org-table ((,class (:foreground ,jbeans-orange-0)))) - `(org-todo ((,class (:foreground ,jbeans-red-1)))) -;;;;; Region - `(region ((,class (:background ,jbeans-grey-3)))) -;;;;; SHM - `(shm-current-face ((,class (:background ,jbeans-grey-4)))) - `(shm-quarantine-face ((,class (:background ,jbeans-red-4)))) -;;;;; Smerge - `(smerge-markers ((,class (:foreground ,jbeans-yellow-3 :background ,jbeans-grey-0)))) - `(smerge-refined-change ((,class (:foreground ,jbeans-green-5)))) -;;;;; SmartParens - `(sp-pair-overlay-face ((((class color) (min-colors 89)) (:background ,jbeans-grey-2)))) - `(sp-show-pair-match-face ((((class color) (min-colors 89)) (:background ,jbeans-grey-5)))) -;;;;; Spaceline - `(spaceline-evil-normal ((,class (:foreground ,jbeans-bg :background ,jbeans-orange-2)))) - `(spaceline-evil-motion ((,class (:foreground ,jbeans-bg :background ,jbeans-purple-2)))) - `(spaceline-evil-insert ((,class (:foreground ,jbeans-bg :background ,jbeans-green-2)))) - `(spaceline-evil-visual ((,class (:foreground ,jbeans-bg :background ,jbeans-grey-5)))) - `(spaceline-evil-replace ((,class (:foreground ,jbeans-bg :background ,jbeans-red-1)))) - `(spaceline-evil-emacs ((,class (:foreground ,jbeans-bg :background ,jbeans-blue-5)))) -;;;;; Spacemacs - `(spacemacs-normal-face ((,class (:foreground ,jbeans-bg :background ,jbeans-orange-2)))) - `(spacemacs-motion-face ((,class (:foreground ,jbeans-bg :background ,jbeans-purple-2)))) - `(spacemacs-insert-face ((,class (:foreground ,jbeans-bg :background ,jbeans-green-2)))) - `(spacemacs-visual-face ((,class (:foreground ,jbeans-bg :background ,jbeans-grey-5)))) - `(spacemacs-lisp-face ((,class (:foreground ,jbeans-bg :background ,jbeans-purple-1)))) - `(spacemacs-replace-face ((,class (:foreground ,jbeans-bg :background ,jbeans-red-1)))) - `(spacemacs-iedit-face ((,class (:foreground ,jbeans-bg :background ,jbeans-red-8)))) - `(spacemacs-iedit-insert-face ((,class (:foreground ,jbeans-bg :background ,jbeans-red-8)))) - `(spacemacs-evilified-face ((,class (:foreground ,jbeans-bg :background ,jbeans-green-3)))) - `(spacemacs-emacs-face ((,class (:foreground ,jbeans-bg :background ,jbeans-blue-5)))) -;;;;; TabBar - `(tabbar-default ((,class (:inherit variable-pitch :background ,jbeans-bg :foreground ,jbeans-fg :height 0.8)))) - `(tabbar-modified ((,class (:inherit tabbar-default :foreground ,jbeans-green-5 :box (:line-width 1 :color ,jbeans-grey-5 style: released-button))))) - `(tabbar-selected ((,class (:inherit tabbar-default :foreground ,jbeans-blue-0 :box (:line-width 1 :color ,jbeans-fg style: released-button))))) - `(tabbar-unselected ((,class (:inherit tabbar-default :box (:line-width 1 :color ,jbeans-grey-6 style: released-button))))) -;;;;; Term - `(term-color-black ((,class (:foreground ,jbeans-bg :background ,jbeans-bg)))) - `(term-color-red ((,class (:foreground ,jbeans-red-2 :background ,jbeans-red-3)))) - `(term-color-green ((,class (:foreground ,jbeans-green-2 :background ,jbeans-green-3)))) - `(term-color-yellow ((,class (:foreground ,jbeans-yellow-3 :background ,jbeans-yellow-2)))) - `(term-color-blue ((,class (:foreground ,jbeans-blue-0 :background ,jbeans-blue-1)))) - `(term-color-magenta ((,class (:foreground ,jbeans-purple-0 :background ,jbeans-purple-3)))) - `(term-color-white ((,class (:foreground ,jbeans-fg :background ,jbeans-fg)))) - `(term-default-fg-color ((,class (:inherit term-color-white)))) - `(term-default-bg-color ((,class (:inherit term-color-black)))) -;;;;; Whitespace - `(trailing-whitespace ((,class (:background ,jbeans-red-4)))) -;;;;; Vertical border - `(vertical-border ((,class (:foreground ,jbeans-grey-3)))) -;;;;; Web Mode - `(web-mode-builtin-face ((,class (:foreground ,jbeans-blue-1)))) - `(web-mode-html-attr-name-face ((,class (:foreground ,jbeans-blue-0)))) - `(web-mode-html-tag-face ((,class (:foreground ,jbeans-orange-0)))) - `(web-mode-symbol-face ((,class (:foreground ,jbeans-blue-3)))) - `(web-mode-function-name-face ((,class (:foreground ,jbeans-orange-0)))) - `(web-mode-block-control-face ((,class (:foreground ,jbeans-red-1)))) - `(web-mode-variable-name-face ((,class (:foreground ,jbeans-blue-2)))) -;;;;; More Whitespace - `(whitespace-trailing ((,class (:background ,jbeans-red-4)))))) - -;;;###autoload -(when load-file-name - (add-to-list 'custom-theme-load-path - (file-name-as-directory (file-name-directory load-file-name)))) - -(provide-theme 'jbeans) - -;; Local Variables: -;; no-byte-compile: t -;; indent-tabs-mode: nil -;; eval: (when (require 'rainbow-mode nil t) (rainbow-mode 1)) -;; End: -;;; jbeans-theme.el ends here diff --git a/.emacs.d/themes/valigo-theme.el b/.emacs.d/themes/valigo-theme.el new file mode 100644 index 0000000..e08b16c --- /dev/null +++ b/.emacs.d/themes/valigo-theme.el @@ -0,0 +1,152 @@ +;;; valigo-theme.el --- Dark purple-grey theme with gold accents -*- lexical-binding: t; -*- + +;;; Commentary: +;; Based on ef-dream theme with customizations from valignatev/dotemacs. +;; A dark theme with warm gold accents and muted purple-grey tones. + +;;; Code: + +(deftheme valigo + "Dark purple-grey theme with gold accents.") + +(custom-theme-set-faces + 'valigo + ;; Basic faces + '(default ((t (:foreground "#efd5c5" :background "#131015")))) + '(cursor ((t (:background "#f3c09a")))) + '(region ((t (:background "#544a50")))) + '(hl-line ((t (:background "#232224")))) + '(highlight ((t (:background "#503240")))) + '(secondary-selection ((t (:background "#412f4f")))) + '(lazy-highlight ((t (:background "#8f665f")))) + '(isearch ((t (:background "#957856" :foreground "#efd5c5")))) + '(isearch-fail ((t (:background "#5a3142")))) + '(match ((t (:background "#503240")))) + + ;; Mode line + '(mode-line ((t (:background "#472b00" :foreground "#f2ddcf")))) + '(mode-line-inactive ((t (:background "#2a272c" :foreground "#8f8886")))) + '(mode-line-buffer-id ((t (:foreground "#f2ddcf" :weight bold)))) + + ;; Borders and dividers + '(vertical-border ((t (:foreground "#635850")))) + '(fringe ((t (:background "#131015")))) + '(window-divider ((t (:foreground "#635850")))) + '(window-divider-first-pixel ((t (:foreground "#131015")))) + '(window-divider-last-pixel ((t (:foreground "#635850")))) + '(border ((t (:foreground "#635850")))) + + ;; Tab line + '(tab-line ((t (:background "#322f34" :foreground "#efd5c5")))) + '(tab-line-tab ((t (:background "#322f34" :foreground "#efd5c5")))) + '(tab-line-tab-current ((t (:background "#3b393e" :foreground "#efd5c5")))) + '(tab-line-tab-inactive ((t (:background "#2a272c" :foreground "#8f8886")))) + + ;; Line numbers + '(line-number ((t (:foreground "#8f8886" :background "#131015")))) + '(line-number-current-line ((t (:foreground "#efd5c5" :background "#232224")))) + + ;; Font lock faces + '(font-lock-builtin-face ((t (:foreground "#b0a0cf")))) + '(font-lock-comment-face ((t (:foreground "#8f8886")))) + '(font-lock-comment-delimiter-face ((t (:foreground "#8f8886")))) + '(font-lock-doc-face ((t (:foreground "#8f8886")))) + '(font-lock-string-face ((t (:foreground "#c0b24f")))) + '(font-lock-keyword-face ((t (:foreground "#ff9f0a")))) + '(font-lock-function-name-face ((t (:foreground "#ffaacf")))) + '(font-lock-variable-name-face ((t (:foreground "#efd5c5")))) + '(font-lock-constant-face ((t (:foreground "#d0b0ff")))) + '(font-lock-type-face ((t (:foreground "#6fb3c0")))) + '(font-lock-warning-face ((t (:foreground "#ff6f6f")))) + '(font-lock-negation-char-face ((t (:foreground "#ff7a5f")))) + '(font-lock-preprocessor-face ((t (:foreground "#ff9f0a")))) + '(font-lock-regexp-grouping-backslash ((t (:foreground "#deb07a")))) + '(font-lock-regexp-grouping-construct ((t (:foreground "#deb07a")))) + + ;; Parenthesis matching + '(show-paren-match ((t (:background "#885566" :foreground "#efd5c5")))) + '(show-paren-mismatch ((t (:background "#a02f50" :foreground "#efd5c5")))) + + ;; Minibuffer + '(minibuffer-prompt ((t (:foreground "#ff9f0a")))) + + ;; Compilation + '(compilation-info ((t (:foreground "#51b04f")))) + '(compilation-warning ((t (:foreground "#d09950")))) + '(compilation-error ((t (:foreground "#ff6f6f")))) + '(compilation-mode-line-exit ((t (:foreground "#51b04f")))) + '(compilation-mode-line-fail ((t (:foreground "#ff6f6f")))) + + ;; Flymake + '(flymake-error ((t (:underline (:style wave :color "#ff6f6f"))))) + '(flymake-warning ((t (:underline (:style wave :color "#d09950"))))) + '(flymake-note ((t (:underline (:style wave :color "#8f8886"))))) + + ;; Flyspell + '(flyspell-incorrect ((t (:underline (:style wave :color "#ff6f6f"))))) + '(flyspell-duplicate ((t (:underline (:style wave :color "#d09950"))))) + + ;; Ivy + '(ivy-current-match ((t (:background "#503240" :foreground "#efd5c5")))) + '(ivy-minibuffer-match-face-1 ((t (:foreground "#8fcfd0")))) + '(ivy-minibuffer-match-face-2 ((t (:foreground "#ff9f0a" :weight bold)))) + '(ivy-minibuffer-match-face-3 ((t (:foreground "#ffaacf" :weight bold)))) + '(ivy-minibuffer-match-face-4 ((t (:foreground "#d0b0ff" :weight bold)))) + '(ivy-confirm-face ((t (:foreground "#51b04f")))) + '(ivy-match-required-face ((t (:foreground "#ff6f6f")))) + + ;; Dired + '(dired-directory ((t (:foreground "#57b0ff")))) + '(dired-symlink ((t (:foreground "#6fb3c0")))) + '(dired-ignored ((t (:foreground "#8f8886")))) + + ;; Diff + '(diff-added ((t (:background "#304a4f" :foreground "#efd5c5")))) + '(diff-removed ((t (:background "#5a3142" :foreground "#efd5c5")))) + '(diff-changed ((t (:background "#51512f" :foreground "#efd5c5")))) + '(diff-header ((t (:background "#322f34" :foreground "#efd5c5")))) + '(diff-file-header ((t (:background "#3b393e" :foreground "#efd5c5")))) + '(diff-hunk-header ((t (:background "#412f4f" :foreground "#efd5c5")))) + '(diff-refine-added ((t (:background "#2f6767")))) + '(diff-refine-removed ((t (:background "#782a4a")))) + '(diff-refine-changed ((t (:background "#64651f")))) + + ;; Ediff + '(ediff-current-diff-A ((t (:background "#5a3142")))) + '(ediff-current-diff-B ((t (:background "#304a4f")))) + '(ediff-current-diff-C ((t (:background "#51512f")))) + '(ediff-fine-diff-A ((t (:background "#782a4a")))) + '(ediff-fine-diff-B ((t (:background "#2f6767")))) + '(ediff-fine-diff-C ((t (:background "#64651f")))) + + ;; Eglot + '(eglot-highlight-symbol-face ((t (:background "#412f4f")))) + + ;; Link + '(link ((t (:foreground "#57b0ff" :underline t)))) + '(link-visited ((t (:foreground "#d0b0ff" :underline t)))) + + ;; Custom/widget faces + '(custom-group-tag ((t (:foreground "#6fb3c0" :weight bold)))) + '(custom-variable-tag ((t (:foreground "#6fb3c0" :weight bold)))) + '(widget-field ((t (:background "#3b393e" :foreground "#efd5c5")))) + '(widget-single-line-field ((t (:background "#3b393e" :foreground "#efd5c5")))) + + ;; Error, warning, success + '(error ((t (:foreground "#ff6f6f")))) + '(warning ((t (:foreground "#d09950")))) + '(success ((t (:foreground "#51b04f")))) + + ;; Org mode + '(org-level-1 ((t (:foreground "#ff9f0a")))) + '(org-level-2 ((t (:foreground "#ffaacf")))) + '(org-level-3 ((t (:foreground "#6fb3c0")))) + '(org-level-4 ((t (:foreground "#d0b0ff")))) + '(org-level-5 ((t (:foreground "#c0b24f")))) + '(org-level-6 ((t (:foreground "#51b04f")))) + '(org-level-7 ((t (:foreground "#57b0ff")))) + '(org-level-8 ((t (:foreground "#8fcfd0"))))) + +(provide-theme 'valigo) + +;;; valigo-theme.el ends here