;;; init.el --- tmu init file -*- lexical-binding: t; -*- ;;; Commentary: ;;; This file is organized with ;;; ;;; Stuff that needs to be at the start (package init, some fast ;;; startup stuff, etc) ;;; then my custom functions and variables ;;; then builtin customization ;;; then external packages ;;; then other files that contain config I don't need all the time ;;; then things Emacs sets programtically. ;;; Code: ;;; Init header: (progn ; performance stuff: ;; delay initial gc until after loading init if possible (setq gc-cons-threshold most-positive-fixnum) (add-hook 'emacs-startup-hook (lambda () (setq gc-cons-threshold (expt 2 23))))) (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (push "~/.emacs.d/site-lisp/" load-path) (package-initialize) (require 'use-package-ensure) (setq use-package-always-ensure t) (use-package benchmark-init :config (add-hook 'after-init-hook 'benchmark-init/deactivate)) ;;; Custom definitions, with prefix "my/" (defvar surround-keys '("(" "{" "[" "$" "\"" "'")) (defun my/wrap-pair () "Ensure the region is active and then \"insert-pair\"." (interactive) (activate-mark) (insert-pair)) (eval `(define-keymap :full nil :name "Surround" :prefix 'surround-prefix ,@(mapcan (lambda (key) (list key ''my/wrap-pair)) surround-keys ))) (defun my/toggle-frame-transparency () "Toggle transparency." (interactive) (let ((alpha-transparency 90)) (if (eq alpha-transparency (frame-parameter nil 'alpha-background)) (set-frame-parameter nil 'alpha-background 100) (set-frame-parameter nil 'alpha-background alpha-transparency)))) (defvar my/prog-cleanup-excluded-modes '(makefile-gmake-mode makefile-mode makefile-imake-mode makefile-makepp-mode makefile-bsdmake-mode makefile-automake-mode fundamental-mode) "Major modes for which \"my/clean-prog-file\" should not be run before save.") (defvar my/prog-cleanup-want-tabs-modes '(makefile-gmake-mode makefile-mode makefile-imake-mode makefile-makepp-mode makefile-bsdmake-mode makefile-automake-mode) "Major modes that need tabs instead of spaces. \"my/clean-prog-file\" should convert spaces to tabs instead of tabs to spaces.") (defvar my/prog-cleanup-indent-max-lines 500 "Skip reindenting the buffer if it is longer than this many lines. Nil for no limit.") (defun my/clean-prog-file (&optional buffer) "Perform whitespace cleanup and some normalization on `buffer'. Defaults to the current BUFFER. Converts tabs to spaces unless the major mode is in `my/prog-cleanup-want-tabs-modes', otherwise do the reverse. Delete trailing whitespace." (unless buffer (setq buffer (current-buffer))) (with-current-buffer buffer (cond ((and (functionp 'clang-format-buffer) ; safety valve for undef'd (derived-mode-p '(c-mode c++-mode))) (clang-format-buffer)) (t (when (and my/prog-cleanup-indent-max-lines (< (car (buffer-line-statistics buffer)) my/prog-cleanup-indent-max-lines)) (indent-region (point-min) (point-max))))) (if (member major-mode my/prog-cleanup-want-tabs-modes) (tabify (point-min) (point-max)) (untabify (point-min) (point-max))) (delete-trailing-whitespace))) (defun my/prog-buffer-setup () "Do setup in for code buffers." (superword-mode 1) (modify-syntax-entry ?_ "w") (hs-minor-mode 1) (display-fill-column-indicator-mode 1) (smerge-mode 1) (when (derived-mode-p '(c-mode c++-mode)) (c-guess)) (add-hook 'before-save-hook (lambda () (unless (member major-mode my/prog-cleanup-excluded-modes) (my/clean-prog-file))))) (add-hook 'prog-mode-hook 'my/prog-buffer-setup) (defun my/wrap-region-paren () "Wraps the region in parens. Similar to pressing ( with the region active." (interactive) (let ((beg (region-beginning)) (end (region-end))) (save-excursion (goto-char beg) (insert "(") (goto-char (+ end 1)) (insert ")")))) (defun my/zap-whitespace () "Zaps (deletes) the whitespace around the point in both directions." (interactive) (push-mark) (skip-chars-backward " \t\n") (push-mark) (skip-chars-forward " \t\n") (delete-region (mark) (point)) (pop-mark) (goto-char (mark)) (pop-mark)) (defun my/wrap-sexp (&optional arg) "Wraps the following sexp in a pair of parens. Places point inside the new pair, pushing the mark before the new pair. With prefix ARG do ARG number sexps if given, including backwards." (interactive "p") (message "%s" arg) (if arg (progn (push-mark) (insert-pair arg ?\( ?\))) (insert-pair 1 ?\( ?\)))) (defun my/close-or-kill () "If this is the only frame, kill Emacs. Otherwise close the frame." (interactive) (save-buffers-kill-terminal)) (defun my/toggle-window-other-reachability () "Toggle whether this window can be selected by `other-window'." (interactive) (let* ((win (get-buffer-window (current-buffer))) (current (window-parameter win 'no-other-window))) (set-window-parameter win 'no-other-window (not current)) (force-mode-line-update))) ;; small hack to make other window reachability visible like window dedication (advice-add 'mode-line-window-control :around (lambda (f) (concat (funcall f) (if (window-parameter nil 'no-other-window) "o" ""))) '(:name "other-window-indicator")) ;; TODO find a bind for this (defun my/open-window-by-buffer (buffer) "Move focus to an extant window by the buffer it contains. If no such window exists, switch to BUFFER in the current window." (interactive "bBuffer: ") (let ((win (get-buffer-window buffer t))) (if win (select-window win) (switch-to-buffer buffer)))) (defun my/shorten-path (path) "Shorten string PATH. Initialize all but the last path component." (let* ((components (split-string path "/")) (last-component (-last (lambda (s) (not (string-empty-p s))) components)) (shortened-components (mapcar (lambda (comp) (if (or (string-equal comp last-component) (string-empty-p comp)) comp (substring comp 0 1))) components))) (mapconcat 'identity shortened-components "/"))) (defun my/swap-other-window-buffer () "Exchange buffer contents with the next window. Tries to switch the buffer contents of the current window and the next in the cyclic ordering. Doesn't consider windows that are dedicated." (interactive) (let* ((cw (get-mru-window nil nil nil t)) (cb (window-buffer cw)) (ow (next-window)) (ob (window-buffer ow))) (unless (window-dedicated-p cw) (while (window-dedicated-p ow) (setq ow (next-window ow) ob (window-buffer ow))) (unless (eq cw ow) (progn (with-selected-window ow (switch-to-buffer cb)) (with-selected-window cw (switch-to-buffer ob))))))) (defun my/activate-mark () "Activate the region a la `C-SPC C-SPC', but don't move the point. Useful in combination with `query-replace' for acting on the region." (interactive) (if (region-active-p) (deactivate-mark) (activate-mark))) (defun my/c-x-n-to-m-n (&optional keymap) "Copy bindings from C-x [n] to M-[n] in KEYMAP, defaulting to the global keymap." (unless keymap (setq keymap global-map)) (mapc (lambda (n) (let* ((from (concat "C-x " (format "%d" n))) (to (concat "M-" (format "%d" n))) (bind (keymap-lookup keymap from))) (keymap-set keymap to bind))) '(0 1 2 3 4 5 6 7 8 9))) (my/c-x-n-to-m-n) (defun my/keymap-keys (map) "Return a list of all key sequences in a keymap MAP recursively." (mapcan (lambda (c) (let ((ks (car c)) (km (cdr c)) (acc nil)) (map-keymap (lambda (key bind) (let ((kss (vconcat ks (vector key)))) (when (commandp bind) (push kss acc)))) km) acc)) (accessible-keymaps map))) (defun my/eshell (&optional arg) "Create a new eshell or switch to an existing one. With ARG, make a new shell. If the current buffer is an eshell, switch back to the previous selected buffer." (interactive "P") (if (eq major-mode 'eshell-mode) (switch-to-prev-buffer) (eshell arg))) (defun my/vc-on-root (&optional arg) "Open a vc dir buffer at the project root. With ARG, open a Dired buffer instead." (interactive "P") (let ((dir (project-root (project-current t)))) (if arg (dired dir) (vc-dir dir)))) (defun my/kill-buffer (&optional arg) "Kill the current buffer. With ARG kill the window as well." (interactive "P") (if arg (kill-buffer-and-window) (kill-buffer))) (defvar my/layout-pair (cons nil nil) "Cons pair of window configurations.") (add-hook 'after-init-hook (lambda () (setq my/layout-pair (cons (current-window-configuration) (current-window-configuration))))) (defun my/layout-swap (&optional arg) "Swap between the two saved window configurations. With ARG, don't save the current layout." (interactive "P") (let ((left (car my/layout-pair)) (right (cdr my/layout-pair))) (unless arg (setq left (current-window-configuration))) (set-window-configuration right t t) (setq my/layout-pair (cons right left)))) (progn ; my global keybinds (define-minor-mode my/keys-mode "Minor mode collecting global keybinds" :global t :keymap (make-sparse-keymap)) ;; The keymaps in `emulation-mode-map-alists' take precedence over ;; `minor-mode-map-alist' (add-to-list 'emulation-mode-map-alists '((my/keys-mode . my/keys-keymap))) (keymap-set my/keys-mode-map "C-x C-C" 'save-buffers-kill-terminal) (keymap-set my/keys-mode-map "C-x C-c" 'my/close-or-kill) (keymap-set my/keys-mode-map "C-x -" 'my/swap-other-window-buffer) (keymap-set my/keys-mode-map "C-x w o" 'my/toggle-window-other-reachability) (keymap-set my/keys-mode-map "M-w" 'copy-region-as-kill) ; make copying not flash cursor (keymap-set my/keys-mode-map "M-(" 'my/wrap-region-paren) (keymap-set my/keys-mode-map "M-z" 'my/zap-whitespace) (keymap-set my/keys-mode-map "C-M-z" 'my/wrap-sexp) (keymap-set my/keys-mode-map "M-o" 'other-window) (keymap-set my/keys-mode-map "M-RET" 'my/eshell) (keymap-set my/keys-mode-map "M-C" 'calc) (keymap-set my/keys-mode-map "M-K" 'my/kill-buffer) (keymap-set my/keys-mode-map "M-D" 'my/vc-on-root) (keymap-set my/keys-mode-map "M-U" 'scroll-lock-mode) (keymap-set my/keys-mode-map "M-Q" 'auto-fill-mode) (keymap-set my/keys-mode-map "M-A" 'beginning-of-line-text) (keymap-set my/keys-mode-map "M-R" 'my/layout-swap) (keymap-set my/keys-mode-map "M-W" 'switch-to-buffer) (keymap-set my/keys-mode-map "M-N" 'man) (keymap-set my/keys-mode-map "C-c R" 'raise-sexp) (keymap-set my/keys-mode-map "C-c r" 'delete-pair) (keymap-set my/keys-mode-map "M-S" 'surround-prefix) (keymap-set my/keys-mode-map "M-\"" 'my/activate-mark) (my/keys-mode 1)) (progn ; mode for log files (define-derived-mode generic-log-mode fundamental-mode "Log" "Major mode for following log files." (setq-local auto-revert-verbose nil) (auto-revert-tail-mode 1)) (add-to-list 'auto-mode-alist '("\\.log\\'" . generic-log-mode))) ;;; Builtin config: (use-package server ; allow emacsclient :demand t :config (unless (server-running-p) (server-start))) (use-package proced ; process editor :commands (proced) :config (setq-default proced-auto-update-flag t) (setq-default proced-auto-update-interval 1)) (use-package dabbrev ; dynamic abbreviations :demand t :config (add-to-list 'dabbrev-ignored-buffer-modes 'exwm-mode) (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode) (add-to-list 'dabbrev-ignored-buffer-modes 'tags-table-mode) (add-to-list 'dabbrev-ignored-buffer-modes 'doc-view-mode)) (progn ; dired directory editor (require 'dired) (defun dired-do-find-marked-files () (interactive) (seq-do 'find-file (dired-get-marked-files))) (define-key dired-mode-map (kbd "C-o") 'dired-display-file) (define-key dired-mode-map (kbd "F") 'dired-do-find-marked-files)) (use-package ibuffer ; give a nice list of buffers with extra info :commands (ibuffer) :custom (ibuffer-formats '((mark modified read-only " " (name 50 50 :left :elide) ; was originally 18 " " (size 9 -1 :right) " " (mode 16 16 :left :elide) " " filename-and-process) (mark " " (name 16 -1) " " filename))) :bind ("C-x C-b" . ibuffer)) (progn ; isearch search in buffer ;; swap basic and regex binds (keymap-set global-map "C-s" 'isearch-forward-regexp) (keymap-set global-map "C-r" 'isearch-backward-regexp) (keymap-set global-map "C-M-s" 'isearch-forward) (keymap-set global-map "C-M-r" 'isearch-backward)) (use-package eshell ; emacs shell :demand t :config (use-package esh-help) (require 'em-hist) (require 'em-term) (setup-esh-help-eldoc) :bind (:map eshell-mode-map ("C-l" . eshell/clear)) ; todo make smarter with centering :hook (eshell-mode . eldoc-mode)) (use-package ediff ; emacs interactive diff :custom (ediff-window-setup-function 'ediff-setup-windows-plain)) (progn ; comint, doesn't play with use-package (require 'comint) (setq-default comint-scroll-to-bottom-on-input t) (setq-default comint-scroll-to-bottom-on-output t) (add-to-list 'comint-output-filter-functions #'comint-truncate-buffer) (add-to-list 'comint-output-filter-functions #'ansi-color-process-output)) (use-package tramp ; remote access for files :demand t :custom (tramp-allow-unsafe-temporary-files t)) (use-package asm-mode ; asm comments and tags generation :demand t :custom (asm-comment-char ?#) ; prefer # over ; for asm comments :init (defun add-asm-label-tag-generation-hook () (add-hook 'after-save-hook (lambda () (shell-command "find . -iregex '.*\\.[sS]' -exec etags -l none -r '/\\([a-zA-Z0-9\\-_]+\\):/\1/' {} +")) 0 t)) :hook (asm-mode . 'add-asm-label-tag-generation-hook)) (use-package compile ; compliation buffers and easy bind :custom (compilation-always-kill t) (compilation-scroll-output t) :bind (:map my/keys-mode-map ("M-M" . 'recompile)) :config ;; Allow compilation buffer to be dedicated across frames (add-to-list 'display-buffer-alist '("\\*compilation\\*" (nil (reusable-frames . t)))) (add-hook 'compilation-filter-hook #'ansi-color-compilation-filter)) (use-package man ; view manuals in emacs :custom (Man-switches "-a")) (use-package imenu ; jump to items in the current buffer :bind ("M-i" . imenu) :custom (imenu-auto-rescan t) (imenu-flatten t)) (use-package xref ; jump to syntactic elements in project ;; (add-hook 'xref-backend-functions 'gxref-xref-backend) :bind ("M-I" . xref-find-definitions)) (use-package time ; time if I want it in the modeline etc :custom (display-time-day-and-date t) (display-time-24hr-format t)) (use-package battery ; battery in modeline etc ) (progn ; viper, anchient vi emulation (setq-default viper-want-ctl-h-help t) (setq-default viper-inhibit-startup-message 't) (setq-default viper-expert-level 5) (setq-default viper-is-in-minibuffer nil) (setq-default viper-vi-style-in-minibuffer nil) (setq-default viper-enable-minibuffer-faces nil) (setq-default viper-syntax-preference 'emacs) (setq-default viper-ex-style-motion nil) (setq-default viper-auto-indent t) (setq-default viper-buffer-search-char ?g) (setq viper-mode nil) (require 'viper) (define-key viper-vi-global-user-map (kbd "C-y") 'yank) (define-key viper-vi-global-user-map (kbd "C-e") 'end-of-line) (define-key viper-vi-global-user-map (kbd "C-f") 'forward-char) (define-key viper-vi-global-user-map (kbd "C-b") 'backward-char) (define-key viper-vi-global-user-map (kbd "C-u") 'universal-argument) (define-key viper-insert-global-user-map (kbd "C-u") 'universal-argument) (define-key viper-insert-global-user-map (kbd "C-d") 'delete-char) (define-key viper-insert-global-user-map (kbd "C-m") #'(lambda () (interactive) (if completion-in-region-mode (corfu-insert) (viper-autoindent))))) (progn ; indent code when pasting (require 'dash) (defvar yank-indent-modes '(prog-mode LaTeX-mode TeX-mode) "Modes in which to indent regions that are yanked (or yank-popped).") (defun yank-indent-func (&optional arg) (let* ((parents (derived-mode-all-parents major-mode)) (helper (lambda (acc v) (or acc (member v yank-indent-modes)))) (included (-reduce helper parents))) (when (and (not arg) included) (indent-region (region-beginning) (region-end))))) (advice-add 'yank :after 'yank-indent-func) (advice-add 'yank-pop :after 'yank-indent-func)) (progn ; better commenting binds (global-set-key (kbd "C-x C-;") 'comment-or-uncomment-region) (global-set-key (kbd "C-x ;") 'comment-line) (global-set-key (kbd "C-x :") 'comment-or-uncomment-region) ;; ^ duped for terminal w/o C-; ) (progn ; default modeline config additions (let ((dir '("" (:eval (let ((str (concat (format " [%s] " (my/shorten-path default-directory))))) (add-face-text-property 0 (length str) '(:weight bold :foreground "green2") t str) str))))) (push dir global-mode-string))) (progn ; comfy scratch buffer (require 'iimage) (setq inhibit-startup-screen t) (setq initial-scratch-message (concat (propertize ";; " 'invisible t) " ;; scratch for lisp evaluation and unsaved text ")) (add-hook 'emacs-startup-hook (lambda () (with-current-buffer "*scratch*" (emacs-lock-mode 'kill) (iimage-mode 1))))) (progn ; confirm fewer things (setq kill-buffer-query-functions (delq 'process-kill-buffer-query-function kill-buffer-query-functions)) (setq confirm-kill-processes nil) (setq async-shell-command-buffer 'new-buffer) (setq vc-follow-symlinks t)) ;; misc vars (setq delete-pair-blink-delay 0 enable-recursive-minibuffers t frame-resize-pixelwise t) (electric-pair-mode 1) (vc-auto-revert-mode 1) ;;; External packages: (use-package orderless ; ordering (minibuffer) completions :demand t :custom (orderless-skip-highlighting t) (completion-styles '(orderless basic partial-completion emacs22)) (completion-category-defaults nil) (completion-category-overrides nil) (completion-ignore-case t) (read-file-name-completion-ignore-case t) (read-buffer-completion-ignore-case t) (orderless-smart-case nil) (orderless-matching-styles '(orderless-prefixes orderless-literal orderless-regexp))) (use-package vertico ; better minibuffer complete :demand t :custom (vertico-cycle t) :config ;; (vertico-flat-mode) (vertico-mode 1)) (use-package posframe ; child frames inside normal frames ) (use-package vertico-posframe ; use posframes to display minibuffer :after vertico :demand t :custom (vertico-posframe-poshandler #'posframe-poshandler-frame-bottom-center) (vertico-posframe-size-function (lambda (buffer) (let ((w (frame-width))) (list :height (buffer-local-value 'vertico-posframe-height buffer) :min-height (or (buffer-local-value 'vertico-posframe-min-height buffer) (let ((height (+ vertico-count 1))) (min height (or (buffer-local-value 'vertico-posframe-height buffer) height)))) :width w :min-width w)))) :config (vertico-posframe-mode 1)) (use-package marginalia ; more info in minibuffer menus :demand t :custom (marginalia-max-relative-age 0) (marginalia-align 'right) :bind (:map minibuffer-local-map ("M-A" . 'marginalia-cycle)) :config (marginalia-mode)) (use-package embark ; more actions from minibuffer :demand t :bind (("C-." . embark-act) ("C-," . embark-dwim) ("C-h B" . embark-bindings)) :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) (use-package corfu ; in buffer completion :demand t :custom (corfu-cycle t) (corfu-quit-no-match t) :bind (("M-/" . completion-at-point)) :init (defun my/corfu-commit-single () "Complete without asking if there is only one candidate." (when (and (corfu--popup-visible-p) (= (length corfu--candidates) 1)) (corfu-accept))) :hook (corfu-post-command . my/corfu-commit-single) :config (global-corfu-mode 1)) (use-package tempel ; templates :demand t :custom (tempel-path "~/.emacs.d/templates/*.eld") :bind (("M-+" . tempel-complete)) :config (keymap-set tempel-map " " #'tempel-next) (keymap-set tempel-map " " #'tempel-previous)) (use-package tempel-collection ; other people's templates :after tempel :demand t) (use-package cape ; extend completion frameworks :demand t :bind ("C-c p" . cape-prefix-map) :config (advice-add 'pcomplete-completions-at-point :around 'cape-wrap-silent) ;; (advice-add 'pcomplete-completions-at-point :around 'cape-wrap-purify) (defvar my/completion-at-point-functions-always-include (list 'tags-completion-at-point-function 'cape-dabbrev 'cape-dict 'tempel-complete)) ;; local settings should include t to also include global settings (setq completion-at-point-functions my/completion-at-point-functions-always-include)) (use-package ibuffer-vc ; group buffers by vcs directory :after ibuffer :demand t :hook (ibuffer . (lambda () (ibuffer-vc-set-filter-groups-by-vc-root) (unless (eq ibuffer-sorting-mode 'alphabetic) (ibuffer-do-sort-by-alphabetic))))) (use-package free-keys ; display a list of unbound keys ) (use-package which-key ; show list of next keys after prefix & delay :demand t :config (which-key-mode 1)) (use-package winum ; binds for switching to windows by number :demand t :config (winum-mode 1)) ;; (use-package savehist ; preserve minibuffer history across sessions ;; :demand t ;; :init ;; (savehist-mode)) ;; (use-package consult ; more encompassing buffer switch and searching ;; :demand t ;; :custom ;; (consult-preview-excluded-buffers t) ;; (consult-narrow-key ",") ;; :bind ;; ("C-x b" . consult-buffer) ;; ("M-W" . consult-buffer) ;; ("C-S-y" . consult-yank-from-kill-ring) ;; ("M-g M-g" . consult-goto-line) ;; ("C-S-s" . consult-line-multi) ;; ("M-s g" . consult-grep) ;; ("M-s G" . grep) ;; ("M-s f" . consult-find) ;; ;; move some standard binds ;; ("M-s s" . consult-line)) ;; (use-package embark-consult ;; :after embark consult) (use-package hl-todo ; highlight certain keywords :hook (prog-mode . hl-todo-mode)) (use-package visible-mark ; make the mark visible :demand t :custom-face (visible-mark-active ((t . (:foreground "black" :background "deep pink" :box (:line-width (-1 . -1) :color "deep pink" :style nil))))) :custom (visible-mark-max 1) :config (global-visible-mark-mode 1)) (use-package avy ; goto location by char pair and jump list :bind (("C-'" . avy-goto-char-2) ("M-G" . avy-goto-char-2)) :custom (avy-all-windows nil) (avy-all-windows-alt 'all-frames)) (use-package balanced-windows ; auto rebalance windows :bind ("C-x w b" . balanced-windows-mode)) (use-package eat ; terminal emu + make eshell behave better :demand t :custom (eat-enable-auto-line-mode t) :config (eat-eshell-mode) (eat-eshell-visual-command-mode) (let* ((desired-global-binds (my/keymap-keys my/keys-mode-map)) (desired-prefixes (mapcar (lambda (ks) (let ((k1 (elt ks 0)) (meta-mask ?\M-\0)) (if (numberp k1) (if (equal ?\e k1) (vector k1 (elt ks 1)) (let ((k-no-m (logand k1 (lognot meta-mask))) (k-has-m (not (zerop (logand k1 meta-mask))))) (if k-has-m (vector ?\e k-no-m) (vector k1)))) (vector k1)))) desired-global-binds))) (mapc (lambda (ks) (add-to-list 'eat-semi-char-non-bound-keys ks) (add-to-list 'eat-eshell-semi-char-non-bound-keys ks)) desired-prefixes) (eat-update-semi-char-mode-map) (eat-eshell-update-semi-char-mode-map))) (use-package bash-completion ; allow bash completion in eshell mostly :demand t :config (add-hook 'shell-dynamic-complete-functions 'bash-completion-dynamic-complete) :hook (eshell-mode . (lambda () (add-hook 'completion-at-point-functions 'bash-completion-capf-nonexclusive nil t)))) (use-package pinentry ; allow some passwords to be entered with emacs ) (use-package password-store ; gnu pass integration :demand t) (use-package auth-source-pass ; allow pass to act as auth within emacs :init (auth-source-pass-enable)) (use-package pass ; nice interface for gnu pass :demand t :after password-store auth-source-pass :custom (pass-suppress-confirmations t) (epg-pinentry-mode 'loopback) :config (add-to-list 'display-buffer-alist '("\\*Password-Store\\*" display-buffer-in-side-window (side . right)))) (use-package pyvenv ; respect python environments ) ;; (use-package sideline ; put warnings on the side of the same line ;; :init ;; (use-package sideline-flycheck) ;; (use-package sideline-flymake) ;; :custom ;; (sideline-backends-right '(sideline-flycheck sideline-flymake))) ;; (use-package flycheck ;; :config ;; ;; flymake stuff to be less annoying ;; ;; (face-spec-set 'flycheck-note '((t :underline nil))) ;; ;; (face-spec-set 'flycheck-info '((t :underline nil))) ;; ;; (face-spec-set 'flycheck-warning '((t :underline nil))) ;; ;; (face-spec-set 'flycheck-error '((t :underline nil))) ;; :hook ;; (prog-mode . flycheck-mode)) (progn ; collected folding binds, hs + fold this (define-prefix-command 'my/fold-map) (global-set-key (kbd "M-F") 'my/fold-map) (define-keymap :full nil :parent nil :suppress nil :keymap nil :name "my/fold-map" :prefix 'my/fold-map) (progn ; hideshow folding (keymap-set my/fold-map "t" 'hs-toggle-hiding) (keymap-set my/fold-map "l" 'hs-hide-level) (keymap-set my/fold-map "C-t" 'hs-hide-all) (keymap-set my/fold-map "C-a" 'hs-show-all)) (use-package fold-this ; fold arbitrary region :init (defun my/fold-this-fold-forward (&optional arg) "Fold forward ARG number of sexps, defaulting to one." (interactive "p") (push-mark) (forward-sexp arg) (fold-this (mark) (point)) (pop-mark)) (defun my/fold-this-fold-backward (&optional arg) "Fold backward ARG number of sexps, defaulting to one." (interactive "p") (push-mark) (backward-sexp arg) (fold-this (point) (mark)) (pop-mark)) :bind (:map my/fold-map ("c" . fold-this) ("e" . fold-this-unfold-at-point) ("f" . my/fold-this-fold-forward) ("b" . my/fold-this-fold-backward)))) (use-package clang-format ; let clang do c formatting ) (use-package rust-mode ; rust lang syntax ) (use-package haskell-mode ; haskell + cabal integrations :custom (haskell-tags-on-save t) (haskell-process-type 'cabal-repl) (haskell-process-auto-import-loaded-modules t) :hook (haskell-mode . interactive-haskell-mode)) (use-package opam-switch-mode ; make emacs mode respect switch :config (when (and (file-exists-p "~/.opam") (executable-find "opam")) (opam-switch-set-switch "default"))) (use-package tuareg ; ocaml mode :after opam-switch-mode) (use-package ocp-indent ; indentation for ocaml :after tuareg :hook (tuareg-mode . ocp-setup-indent)) (use-package merlin ; ocaml completion :after tuareg :hook (tuareg-mode . merlin-mode) :custom (merlin-command 'opam)) (use-package racket-mode ; basic racket integration ) (use-package sdcv ; dictionary, requires sdcv install :demand t :config (define-prefix-command 'dict-map) (define-keymap :full nil :parent nil :suppress nil :keymap nil :name "dict-map" :prefix 'dict-map (kbd "w") 'sdcv-search-input (kbd "c") (lambda () (interactive) (activate-input-method 'pyim) (sdcv-search-input (read-from-minibuffer "Chinese Word: " nil nil nil nil nil t)) (activate-input-method nil))) :bind (:map text-mode-map ("M-l" . 'dict-map))) (use-package erc ; irc client :init (defun my/start-erc () "Start erc and autojoin various channels" (interactive) (erc :server "irc.libera.chat" :port 6667)) :custom (erc-modules '(services autojoin button completion fill imenu irccontrols list match menu move-to-prompt netsplit networks readonly ring stamp track)) (erc-nick "tccq") (erc-use-auth-source-for-nickserv-password t) (erc-autojoin-channels-alist '(("libera.chat" "#emacs" "#haskell" "#duskos" "#ocaml"))) (erc-hide-list '("JOIN" "PART" "QUIT")) (erc-current-nick-highlight-type 'nick) (erc-keywords nil) (erc-track-exclude-types '("JOIN" "PART" "QUIT" "NICK" "MODE")) (erc-track-use-faces t) (erc-track-faces-priority-list '(erc-current-nick-face erc-keyword-face)) (erc-track-priority-faces-only 'all)) (use-package minions ; show less on the modeline :demand t :config (minions-mode 1) :custom (minions-prominent-modes '(persp-mode auto-fill-mode eldoc-mode eglot-mode lsp-mode))) (use-package ispell ; spellchecker :demand t :custom (ispell-personal-dictionary "/home/tmu/.aspell.en.pws") :config (defun ispell-mode (&optional arg) "Make some old packages work with modern ispell." (interactive) (ispell-minor-mode arg)) (advice-add 'ispell-mode :before 'debug) (setq-default text-mode-hook (cons 'ispell-minor-mode (remove 'ispell-mode text-mode-hook)))) ;;; Optional files for occasional loading: ;; if you want exwm, include from ~/.emacs.d/site-lisp/my-exwm.el ;; if you want mail, include from ~/.emacs.d/site-lisp/my-mail.el ;; if you want eglot, include from ~/.emacs.d/site-lisp/my-eglot.el ;;; Theming: (require 'tmu-custom-theme) (push "~/.emacs.d/site-lisp/" custom-theme-load-path) (load-theme 'tmu-custom t) ;;; Things emacs sets programatically: ;; ---------------------------------------------------------------------- (put 'dired-find-alternate-file 'disabled nil) (put 'upcase-region 'disabled nil) (put 'downcase-region 'disabled nil) (put 'list-timers 'disabled nil) (put 'narrow-to-region 'disabled nil) (put 'set-goal-column 'disabled nil) (custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(comment-style 'extra-line) '(connection-local-criteria-alist '(((:application eshell :protocol "ssh" :user "tmu" :machine "cnoserver") autogenerated-connection-local-profile/\(:application\ eshell\ :protocol\ \"ssh\"\ :user\ \"tmu\"\ :machine\ \"cnoserver\"\)) ((:application vc-git :protocol "ssh" :user "tmu" :machine "cnoserver") autogenerated-connection-local-profile/\(:application\ vc-git\ :protocol\ \"ssh\"\ :user\ \"tmu\"\ :machine\ \"cnoserver\"\)) ((:application vc-git) vc-git-connection-default-profile) ((:application tramp :protocol "kubernetes") tramp-kubernetes-connection-local-default-profile) ((:application tramp :protocol "flatpak") tramp-container-connection-local-default-flatpak-profile tramp-flatpak-connection-local-default-profile) ((:application tramp) tramp-connection-local-default-system-profile tramp-connection-local-default-shell-profile) ((:application eshell) eshell-connection-default-profile))) '(connection-local-profile-alist '((autogenerated-connection-local-profile/\(:application\ eshell\ :protocol\ \"ssh\"\ :user\ \"tmu\"\ :machine\ \"cnoserver\"\) (eshell-path-env-list "/bin" "/usr/bin" "/sbin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin")) (autogenerated-connection-local-profile/\(:application\ vc-git\ :protocol\ \"ssh\"\ :user\ \"tmu\"\ :machine\ \"cnoserver\"\) (vc-git--program-version . "2.48.1")) (vc-git-connection-default-profile (vc-git--program-version)) (tramp-flatpak-connection-local-default-profile (tramp-remote-path "/app/bin" tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin" "/local/bin" "/local/freeware/bin" "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin" "/opt/bin" "/opt/sbin" "/opt/local/bin")) (tramp-kubernetes-connection-local-default-profile (tramp-config-check . tramp-kubernetes--current-context-data) (tramp-extra-expand-args 97 (tramp-kubernetes--container (car tramp-current-connection)) 104 (tramp-kubernetes--pod (car tramp-current-connection)) 120 (tramp-kubernetes--context-namespace (car tramp-current-connection)))) (tramp-container-connection-local-default-flatpak-profile (tramp-remote-path "/app/bin" tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin" "/local/bin" "/local/freeware/bin" "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin" "/opt/bin" "/opt/sbin" "/opt/local/bin")) (tramp-connection-local-darwin-ps-profile (tramp-process-attributes-ps-args "-acxww" "-o" "pid,uid,user,gid,comm=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "-o" "state=abcde" "-o" "ppid,pgid,sess,tty,tpgid,minflt,majflt,time,pri,nice,vsz,rss,etime,pcpu,pmem,args") (tramp-process-attributes-ps-format (pid . number) (euid . number) (user . string) (egid . number) (comm . 52) (state . 5) (ppid . number) (pgrp . number) (sess . number) (ttname . string) (tpgid . number) (minflt . number) (majflt . number) (time . tramp-ps-time) (pri . number) (nice . number) (vsize . number) (rss . number) (etime . tramp-ps-time) (pcpu . number) (pmem . number) (args))) (tramp-connection-local-busybox-ps-profile (tramp-process-attributes-ps-args "-o" "pid,user,group,comm=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "-o" "stat=abcde" "-o" "ppid,pgid,tty,time,nice,etime,args") (tramp-process-attributes-ps-format (pid . number) (user . string) (group . string) (comm . 52) (state . 5) (ppid . number) (pgrp . number) (ttname . string) (time . tramp-ps-time) (nice . number) (etime . tramp-ps-time) (args))) (tramp-connection-local-bsd-ps-profile (tramp-process-attributes-ps-args "-acxww" "-o" "pid,euid,user,egid,egroup,comm=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "-o" "state,ppid,pgid,sid,tty,tpgid,minflt,majflt,time,pri,nice,vsz,rss,etimes,pcpu,pmem,args") (tramp-process-attributes-ps-format (pid . number) (euid . number) (user . string) (egid . number) (group . string) (comm . 52) (state . string) (ppid . number) (pgrp . number) (sess . number) (ttname . string) (tpgid . number) (minflt . number) (majflt . number) (time . tramp-ps-time) (pri . number) (nice . number) (vsize . number) (rss . number) (etime . number) (pcpu . number) (pmem . number) (args))) (tramp-connection-local-default-shell-profile (shell-file-name . "/bin/sh") (shell-command-switch . "-c")) (tramp-connection-local-default-system-profile (path-separator . ":") (null-device . "/dev/null")) (eshell-connection-default-profile (eshell-path-env-list)))) '(custom-safe-themes '("aee99e2118e960b53016623dc2345d88227d1236d28c6c34858e1d55575cf7c3" "6f5e3fd2b4245ffe660da69ea5c13ab392337e94776dfb23cc1d8d0f80e3baa2" "1b8c2fd98bf6777d8b95f8cf98fdaede88feee3419ec3e5008f94b56618ac6ca" "0cc5046b7981609166c28b64f6185fa5f73bcb00d21e037f304794c6aaa1f340" "9f2e4e8b2ddbfdd392eedbc123649d94654278dee5a53b899557224416413d35" "6dafb31ade9ff07229faaf05c41c2ae475c44731362b792f65f3930b1a2c9cfd" "dc77e008092a5a4aa6b6ed8e4826bebf8f2fb930a8de073bf7f458efd884cca8" "d1ff3e66028f9c527298580d2a64f9e3280f07f9e94d4dada72b67ef15069441" "3d4e3644e237a95683daa73e397c4c0d1ae06bbaaf8040104232591a28bc1315" "12a07bc38295e4b06a8965db261f51ea7ea61fbf91b3ef41298bbb549d1d9403" default)) '(ede-project-directories '("/home/tmu/Desktop/eway/sway" "/home/tmu/Desktop/eway/cage" "/home/tmu/Desktop/eway/wlroots" "/home/tmu/Desktop/eway/comp" "/home/tmu/Desktop/eway")) '(eglot-events-buffer-config '(:size 0 :format full)) '(fortune-dir "/usr/share/fortune/") '(gdb-non-stop-setting nil) '(helm-minibuffer-history-key "M-p") '(menu-bar-mode nil) '(package-selected-packages nil) '(pyim-assistant-scheme 'cangjie) '(safe-local-variable-values '((LEXICAL-binding . t))) '(scroll-bar-mode nil) '(tags-revert-without-query t) '(tool-bar-mode nil) '(transient-mark-mode nil) '(whitespace-style '(face trailing tabs lines-tail missing-newline-at-eof indentation space-after-tab space-before-tab tab-mark) t)) (custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. )