;;; 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")))
(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))
(use-package doom-modeline
:ensure t
:defer 8
:init (doom-modeline-mode 1)
:config
(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