;;; ui-config.el --- UI configuration -*- lexical-binding: t -*-
;;; Commentary:
;; Visual and interface settings
;;; Code:
;; Custom cleanup function instead of midnight mode
;; run manually like (dws/cleanup-buffers 4)
(defcustom dws/cleanup-buffer-excludes
'("\\*scratch\\*"
"\\*Messages\\*"
"\\.org$"
"TAGS$"
"\\*compilation\\*"
"\\*grep\\*"
"\\*Backtrace\\*")
"Regexps of buffer names to exclude from cleanup."
:type '(repeat regexp)
:group 'convenience)
(defun dws/cleanup-buffers (hours)
"Kill stale buffers not visible and unmodified, older than HOURS."
(interactive "Kill buffers not seen in the last N hours: ")
(let* ((now (float-time))
(age-threshold (* hours 3600))
(killed '()))
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (and buffer-display-time ; only process if buffer was ever displayed
(not (get-buffer-window buf t)) ; not visible
(not (buffer-modified-p buf)) ; not dirty
(buffer-file-name buf) ; file buffer
(not (string-prefix-p " " (buffer-name buf))) ; not internal
(> (- now (float-time buffer-display-time)) age-threshold)
(not (seq-some (lambda (re) (string-match-p re (buffer-name buf)))
dws/cleanup-buffer-excludes)))
(push (buffer-name buf) killed)
(kill-buffer buf))))
(if killed
(message "Killed %d stale buffer%s (>%dh): %s"
(length killed)
(if (= 1 (length killed)) "" "s")
hours
(string-join (reverse killed) ", "))
(message "No stale buffers older than %d hours." hours))))
;; run every couple of hours
(run-with-idle-timer (* 120 60) t (lambda () (dws/cleanup-buffers 5)))
;; Window system specific configuration
(when window-system
(server-start)
(menu-bar-mode 1)
(bind-key "C-x C-c" 'kill-buffer)
(bind-key "H-n" 'make-frame)
(bind-key "H-w" 'delete-frame)
(bind-key "H-o" 'other-frame)
(bind-key "H-m" 'lower-frame)
(bind-key "H-h" 'lower-frame))
;; ;; Font configuration
;; (when (member "Source Code Variable" (font-family-list))
;; (set-face-attribute 'default nil
;; :font "Source Code Pro:pixelsize=14:weight=regular:antialias=1")))
;; Old way to load the theme - doesn't like starting as a daemon
;; (use-package nord-theme
;; :ensure t
;; :config
;; (load-theme 'nord t))
;; new way to load the theme.
(use-package nord-theme
:ensure t
:demand t ; Ensure the package code is available in the daemon
:init
(defun my-nord-theme-setup (frame)
"Load Nord theme only when a frame is created."
;; The with-selected-frame ensures the load-theme command
;; is executed in the context of the new client/frame.
(with-selected-frame frame
;; This check prevents the theme from being loaded multiple times
;; if you open several windows, but still loads it if it's the first time.
(unless (member 'nord custom-enabled-themes)
(load-theme 'nord t)
;; Also make sure true-color is set for this frame
(setq x-term-true-color t))))
;; Add the function to the hook that runs when a frame is created
(add-hook 'after-make-frame-functions #'my-nord-theme-setup))
;; (use-package solarized-theme
;; :ensure t
;; :config
;; ;; Optional: tweak options *before* loading the theme
;; (setq solarized-scale-org-headlines nil ;; e.g. disable headline scaling
;; solarized-use-less-bold t
;; solarized-distinct-fringe-background t)
;; ;; Load Zenburn-inspired variant
;; (load-theme 'solarized-zenburn t))
;; for the function/class hints
(which-function-mode 1)
(use-package doom-modeline
:ensure t
:defer 8
:init
(doom-modeline-mode 1)
;; buffer path style
(setq doom-modeline-buffer-file-name-style 'relative-from-project)
:config
(setq doom-modeline-enable-current-function t)
(setq doom-modeline-enable-word-count nil)
(setq doom-modeline-major-mode-icon t) ; keep mode icon
(setq doom-modeline-buffer-encoding nil) ; optional
(setq doom-modeline-minor-modes nil) ; optional
(setq doom-modeline-continuous-word-count-modes nil)
(setq doom-modeline-buffer-file-name-style 'relative-from-project)
(setq doom-modeline-gnus nil
doom-modeline-irc nil))
(use-package vertico
:ensure t
:init
(vertico-mode)
:config
(setq vertico-cycle t
vertico-count 12))
(use-package orderless
:ensure t
:defer 10
:custom
(completion-styles '(orderless basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
(use-package marginalia
:ensure t
:defer 10
:init
(marginalia-mode))
(use-package consult
:ensure t
:defer 1
:bind (;; Modified from your previous ivy bindings
("C-s" . consult-line) ; replaces swiper
("M-y" . consult-yank-pop)
("M-b" . consult-buffer)))
;; Mac-specific configuration
(when (eq system-type 'darwin)
(setq mac-option-key-is-meta t
mac-command-modifier 'hyper
mac-option-modifier 'meta)
;; Clipboard integration
(defun isolate-kill-ring()
"Isolate Emacs kill ring from OS X system pasteboard."
(interactive)
(setq interprogram-cut-function nil)
(setq interprogram-paste-function nil))
(defun pasteboard-copy()
"Copy region to OS X system pasteboard."
(interactive)
(shell-command-on-region
(region-beginning) (region-end) "pbcopy"))
(defun pasteboard-paste()
"Paste from OS X system pasteboard via `pbpaste' to point."
(interactive)
(shell-command-on-region
(point) (if mark-active (mark) (point)) "pbpaste" nil t))
(defun pasteboard-cut()
"Cut region and put on OS X system pasteboard."
(interactive)
(pasteboard-copy)
(delete-region (region-beginning) (region-end)))
(isolate-kill-ring)
(bind-key "H-c" 'pasteboard-copy)
(bind-key "H-v" 'pasteboard-paste)
(bind-key "H-x" 'pasteboard-cut))
;; Linux-specific configuration
(when (eq system-type 'linux)
(setq x-alt-keysym 'meta))
;; Which-key configuration
(use-package which-key
:ensure t
:defer 10
:config
(which-key-mode))
(use-package tramp
:config
(add-to-list 'tramp-remote-path "~/bin")
(add-to-list 'tramp-remote-path "~/python/bin")
(add-to-list 'tramp-remote-path "/usr/local/go/bin/")
(add-to-list 'tramp-remote-path 'tramp-own-remote-path))
;; Window management functions
(defun dws/rotate-windows ()
"Rotate your windows."
(interactive)
(cond ((not (> (count-windows)1))
(message "You can't rotate a single window!"))
(t
(setq i 1)
(let ((numWindows (count-windows)))
(while (< i numWindows)
(let* ((w1 (elt (window-list) i))
(w2 (elt (window-list) (+ (% i numWindows) 1)))
(b1 (window-buffer w1))
(b2 (window-buffer w2))
(s1 (window-start w1))
(s2 (window-start w2)))
(set-window-buffer w1 b2)
(set-window-buffer w2 b1)
(set-window-start w1 s2)
(set-window-start w2 s1)
(setq i (1+ i))))))))
(provide 'ui-config)
;;; ui-config.el ends here