ui-config.el Thu, Oct 30, 2025

;;; 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