;;; syd-ui.el -*- lexical-binding: t; -*- (require 'syd-prelude) (defvar syd-fixed-pitch-font (font-spec :family "VictorMono Nerd Font" :size 13) "Default fixed-pitch (monospace) font.") (defvar syd-variable-pitch-font (font-spec :family "IBM Plex Serif" :size 15) "Default variable-pitch font.") (defvar syd-alt-fixed-pitch-font (font-spec :family "JuliaMono" :size 16) "A monospace font secondary to `syd-fixed-pitch-font'.") (defface syd-alt-fixed-pitch `((t (:inherit fixed-pitch :font ,syd-alt-fixed-pitch-font))) "TODO") (defface syd-apl `((t (:inherit syd-alt-fixed-pitch))) "Face for APL code") ;; Beautiful theme in dark and light. (use-package kanagawa-themes :config (load-theme 'kanagawa-wave t)) (defun syd-init-fonts-h () "Loads `syd-fixed-pitch-font' and `syd-variable-pitch-font'." (dolist (map `((default . ,syd-fixed-pitch-font) (fixed-pitch . ,syd-fixed-pitch-font) (variable-pitch . ,syd-variable-pitch-font))) (pcase-let ((`(,face . ,font) map)) (set-face-attribute face nil :width 'normal :weight 'normal :slant 'normal :font font)))) (defun syd-configure-default-frame-h () "Customise the default frame, primarily by adding to `default-frame-alist'." ;; Maximise the frame. ;; (add-to-list 'default-frame-alist '(fullscreen . maximized)) ;; Disable the titlebar and borders (decorations). (add-to-list 'default-frame-alist '(undecorated . t))) (let ((hook (if (daemonp) 'server-after-make-frame-hook 'after-init-hook))) (add-hook hook #'syd-init-fonts-h) (add-hook hook #'syd-configure-default-frame-h)) ;; Use JuliaMono as a fallback for some glyphs that VictorMono does not cover. (dolist (char-range '((#x0250 . #x02af) ; IPA extensions (#x2200 . #x22FF))) ; Mathematical operators (set-fontset-font "fontset-default" char-range "JuliaMono")) (use-package emacs ;; Display (relative) line numbers only in prog-mode derivatives. :hook ((prog-mode-hook . display-line-numbers-mode) ;; (on-init-ui-hook . syd-configure-default-frame-h) ;; (on-init-ui-hook . syd-init-fonts-h) ) :custom ((display-line-numbers-type 'relative) ;; Always ask "y/n"; never "yes/no". (use-short-answers t) ;; Scroll compilation buffer to follow output. (compilation-scroll-output t) ;; Allow `fit-window-to-buffer' to make horizontal adjustments. (fit-window-to-buffer-horizontally t) ;; I don't like that `grep' asks me to save unsaved files. It makes ;; me think it's about to kill my buffers. (grep-save-buffers nil) ;; The default value is `ask', meaning that Emacs will ask for ;; confirmation any time you follow a symlink to a file under version ;; control. The documentation claims this is "dangerous, and ;; probably not what you want;" I personally don't see it, and it's ;; usually what I want. (vc-follow-symlinks t) ;; Log native-compiler warnings, but don't display the ;; buffer. Most of the warnings are "`X' is not known to ;; be defined" which are typically nothing worth concerning. (native-comp-async-report-warnings-errors 'silent) ;; Don't recenter the view unless >10 lines are scrolled off-screen ;; in a single movement. (scroll-conservatively 10) ;; In modes making use of `recenter-top-bottom' (e.g. Comint, ;; Eshell), this will make the command behave more like a plain old ;; `clear` invocation. (recenter-positions '(top))) :config ;; Disable the menu bar, scroll bar, and tool bar. (menu-bar-mode -1) (scroll-bar-mode -1) (tool-bar-mode -1)) (defun syd-init-kill-process-buffer-on-exit () (defun syd-comint--kill-buffer-sentinel (process _output) "Process sentinel to auto kill associated buffer once PROCESS dies." ;; Note that `process-exit-status' returns zero when the process has not yet ;; died. (unless (and process (zerop (process-exit-status process))) (let ((buffer (process-buffer process))) (with-current-buffer buffer (goto-char (point-max)) (insert (format "\n[Process exited with exit status %d]" (process-exit-status process)))) (kill-buffer (process-buffer process))))) (defun syd-comint--add-kill-on-exit-sentinel () "Replace current process sentinel with a new sentinel composed of the current one and `syd-comint--kill-buffer-sentinel'." (let* ((process (get-buffer-process (current-buffer))) (original-sentinel (process-sentinel process)) (sentinel-list (-remove #'null (list original-sentinel #'syd-comint--kill-buffer-sentinel))) (combined-sentinel (lambda (process line) (--each sentinel-list (funcall it process line))))) (setf (process-sentinel process) combined-sentinel))) (defvar syd-comint--kill-on-exit-h-has-run nil "Whether or not `syd-comint--kill-on-exit-h' has run or not. We need this buffer-local var to prevent the hook from running several times, as can happen for example when calling `shell'.") (defun syd-comint--async-funcall (fn &optional buffer args delay) "Run FUNCTION with ARGS in the buffer after a short DELAY." (run-at-time (or delay 0.2) nil `(lambda () (with-current-buffer ,buffer ,(cons fn args))))) (syd-add-hook 'comint-mode-hook (defun syd-comint--kill-on-exit-h () (unless syd-comint--kill-on-exit-h-has-run (setq-local syd-comint--kill-on-exit-h-has-run t) (syd-comint--async-funcall #'syd-comint--add-kill-on-exit-sentinel (current-buffer)))))) (with-eval-after-load 'comint (require 'syd-kanagawa) (custom-theme-set-faces 'user ;; Default prompt face is very ugly. Give it a more subtle look. `(comint-highlight-prompt ((t :foreground ,(syd-kanagawa-get 'old-white) :background unspecified :weight bold)))) (general-def :keymaps 'comint-mode-map :states '(normal insert) "C-k" #'comint-previous-input "C-j" #'comint-next-input "C-s" #'consult-history) (general-def :keymaps 'comint-mode-map :states 'insert "C-d" #'comint-delchar-or-maybe-eof)) (syd-add-hook 'on-init-ui-hook (defun syd-init-ui-hacks () (set-popup-rule! "*Backtrace*" :size #'doom-popup-shrink-to-fit) (set-popup-rule! "*Messages*" :ttl nil :quit t) (syd-init-kill-process-buffer-on-exit) ;; Required for :quit t to do anything. (evil-set-initial-state 'messages-buffer-mode 'motion) (evil-set-initial-state 'debugger-mode 'normal) (set-popup-rule! shell-command-buffer-name-async :slot -2 :modeline nil :ttl nil))) (provide 'syd-ui)