;; -*- lexical-binding: t; -*- (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 ;; To disable collection of benchmark data after init is done. (add-hook 'after-init-hook 'benchmark-init/deactivate)) (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)))) (defun my/clean-prog-file (&optional buffer) "Fixes whitespace etc in BUFFER or current buffer." (unless buffer (setq buffer (current-buffer))) (with-current-buffer buffer (indent-region (point-min) (point-max)) (untabify (point-min) (point-max)) (delete-trailing-whitespace))) (defvar my/prog-cleanup-excluded-modes '(makefile-gmake-mode makefile-mode makefile-imake-mode makefile-makepp-mode makefile-bsdmake-mode makefile-automake-mode)) (defun my/prog-buffer-setup () "Do setup in for mode buffers." (superword-mode 1) (modify-syntax-entry ?_ "w") (hs-minor-mode 1) (display-fill-column-indicator-mode 1) (add-hook 'before-save-hook (lambda () (unless (elm major-mode my/prog-cleanup-excluded-modes) (my/clean-prog-file))))) (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 inside the new pair, with prefix arg do the same backwards, pushing the mark. Does the same of ARG number sexps if given" (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 sole 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)))) (defun my/open-window-by-buffer (buffer) "Move focus to an extant window by the buffer it contains." (interactive "bBuffer: ") (let ((win (get-buffer-window buffer t))) (if win (select-window win) (switch-to-buffer buffer)))) (defun my/shorten-path (path) "Shortens each directory in PATH except for the last directory to its first character." (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 () "Try to switch the buffer contents of the current window and the next in the cyclic ordering. Don't involve 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) "Rebind the keys starting with C-x [number] to M-[number] in the given keymap or in 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) (use-package server ; allow emacsclient :demand t :config (unless (server-running-p) (server-start))) (use-package proced ; process editor :commands (proced) :config ;; always auto update proced (setq-default proced-auto-update-flag t) (setq-default proced-auto-update-interval 1)) (use-package orderless ; ordering (minibuffer) completions :demand t :custom ;; (orderless-skip-highlighting t) (completion-styles '(orderless basic)) (orderless-matching-styles '(orderless-prefixes orderless-initialism 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 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 corfu-terminal ; make corfu work on terminals :demand t :custom (corfu-terminal-disable-on-gui t) :config (corfu-terminal-mode 1)) ;; TODO debug / test (use-package tempel :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 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)) (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) :custom (completion-at-point-functions (list (cape-capf-super 'cape-dabbrev 'cape-dict 'tempel-complete))) ;; :hook ;; (after-change-major-mode . (lambda () ;; (setq-local completion-at-point-functions ;; (apply 'cape-wrap-super ;; (append ;; '(tempel-complete tags-completion-at-point-function cape-dabbrev cape-dict) ;; completion-at-point-functions))))) ) (use-package tempel-collection :after tempel :demand t) (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)) (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 magit) (use-package free-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 recentf :config (recentf-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-S-w" . consult-buffer) ("C-S-y" . consult-yank-from-kill-ring) ("M-g M-g" . consult-goto-line) ("M-i" . consult-imenu-multi) ("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 hl-line ; make it easier to find your point ;; TODO this doesn't work with buffers created after enabled :bind ("M-s h SPC" . global-hl-line-mode)) (use-package visible-mark ; make the mark visible ;; TODO make the attr list display dependent :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))) (use-package balanced-windows ; auto rebalance windows :bind ("C-x w b" . balanced-windows-mode)) (use-package eshell ; emacs shell :demand t :config (use-package esh-help) (require 'em-hist) (require 'em-term) (setup-esh-help-eldoc) ;; (keymap-set eshell-hist-mode-map "C-p" 'eshell-previous-input) ;; (keymap-set eshell-hist-mode-map "C-n" 'eshell-next-input) ;; (keymap-set eshell-hist-mode-map "C-c C-n" 'next-line) ;; (keymap-set eshell-hist-mode-map "C-c C-p" 'previous-line) :bind (:map eshell-mode-map ("C-l" . eshell/clear)) :hook (eshell-mode . eldoc-mode)) (use-package vterm) (use-package shelldon :demand t :config ;; (setf shell-command-switch "-ic") (setf enable-recursive-minibuffers t) ;; command codes -> ansi colors in emacs (add-hook 'shelldon-mode-hook 'ansi-color-for-comint-mode-on) (add-to-list 'comint-output-filter-functions 'ansi-color-process-output) (autoload 'ansi-color-for-comint-mode-on "ansi-color" nil t) (add-to-list 'display-buffer-alist '("*shelldon:" (display-buffer-reuse-window display-buffer-in-previous-window display-buffer-in-side-window display-buffer-pop-up-window) (side . right) (slot . 0) (window-width . 80))) :bind ("M-&" . 'shelldon) ("M-*" . 'shelldon-loop)) (use-package eat ; terminal override to make eshell behave better :demand t :config (eat-eshell-mode) (eat-eshell-visual-command-mode)) (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)) (use-package bash-completion :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 pass ; password integration :demand t :init ;; (pinentry-start) (use-package password-store) (use-package auth-source-pass :init (auth-source-pass-enable)) :custom (pass-suppress-confirmations t) (epg-pinentry-mode 'loopback) :config (push '("\\*Password-Store\\*" display-buffer-in-side-window (side . right)) display-buffer-alist)) (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 lsp-mode ;; :commands (lsp) ;; :init ;; (use-package lsp-haskell) ;; :custom ;; (lsp-completion-provider :none) ;; :config ;; (defun corfu-lsp-setup () ;; (setq-local completion-styles '(orderless) ;; completion-category-defaults nil)) ;; (add-hook 'lsp-completion-mode-hook #'corfu-lsp-setup)) (use-package pyvenv) (use-package sideline ; put warnings on the side of the same line :init (use-package sideline-flycheck) (use-package sideline-flymake) (use-package sideline-lsp) :custom (sideline-backends-right '(sideline-flycheck sideline-flymake sideline-lsp))) (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 ; 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-set-column) ;; ^ never gonna use but whatever ) (use-package imenu ; jump to items in the current buffer :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 ediff :custom (ediff-window-setup-function 'ediff-setup-windows-plain)) (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) (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))) (progn ; hs (keymap-set my/fold-map (kbd "t") 'hs-toggle-hiding) (keymap-set my/fold-map (kbd "l") 'hs-hide-level)) (add-hook 'prog-mode-hook 'my/prog-buffer-setup) (use-package eglot :demand t ) (use-package eglot-tempel :demand t :config (eglot-tempel-mode 1)) (use-package haskell-mode :custom (haskell-tags-on-save t) (haskell-process-type 'cabal-repl) :hook (haskell-mode . interactive-haskell-mode)) (use-package opam-switch-mode :config (opam-switch-set-switch "default")) (use-package tuareg :after opam-switch-mode) (use-package ocp-indent :after tuareg :hook (tuareg-mode . ocp-setup-indent)) (use-package merlin :after tuareg :hook (tuareg-mode . merlin-mode) :custom (merlin-command 'opam)) (use-package racket-mode) (use-package rustic :custom (rustic-lsp-setup-p nil)) (use-package compile :custom (compilation-always-kill t) (compilation-scroll-output t) :bind ("M-M" . 'recompile) :config ;; Allow compilation buffer to be dedicated across frames (push '("\\*compilation\\*" . (nil (reusable-frames . t))) display-buffer-alist)) ;; (use-package evil ;; :demand nil ;; :custom ;; (evil-want-keybinding nil) ;; (evil-want-integration t) ;; :config ;; (use-package evil-collection ;; :config (evil-collection-init)) ;; (use-package evil-easymotion ;; :config (evilem-default-keybindings "SPC")) ;; (use-package evil-surround ;; :config (global-evil-surround-mode 1)) ;; (use-package evil-snipe ;; :custom (evil-snipe-scope 'buffer) ;; :config ;; (evil-snipe-mode 1) ;; (evil-snipe-override-mode 1) ;; :bind ;; (:map evil-snipe-local-mode-map ;; ("z" . 'evil-snipe-s) ;; ("Z" . 'evil-snipe-S))) ;; (use-package treemacs-evil) ;; :hook ;; (eshell-mode-hook . (lambda () (evil-local-mode -1))) ;; (vterm-mode-hook . (lambda () (evil-local-mode -1))) ;; :bind ;; (:map evil-insert-state-map ;; ("C-d" . 'delete-char) ;; ("C-e" . 'move-end-of-line) ;; ("C-a" . 'move-beginning-of-line) ;; ("C-t" . 'transpose-chars)) ;; (:map evil-normal-state-map ;; ("M-." . 'xref-find-definitions) ;; ("M-Z" . 'suspend-frame) ;; ("C-t" . 'transpose-chars)) ;; (:map evil-motion-state-map ;; ("TAB" . 'indent-for-tab-command))) (use-package exwm ; emacs x window manager :demand t :config (require 'exwm-randr) (require 'exwm-xim) (require 'exwm-systemtray) (require 'exwm-manage) (add-to-list 'exwm-manage-configurations '((equal exwm-class-name "Slack") managed t)) (use-package exwm-modeline) ;;(exwm-xim-mode 1) (defun my/exwm-auto-workspace-montior () "Autopopulate exwm-randr-workspace-monitor-plist and attempt to have a workspace on each monitor. Try to keep up with xrandr changes." (let ((buf (generate-new-buffer "*xrandr-output*")) (out-plist nil)) (call-process-shell-command "xrandr --listmonitors -q" nil buf nil) (with-current-buffer buf (keep-lines "[^[:word:]]connected" (point-min) (point-max) nil) (let ((num-monitors (count-lines (point-min) (point-max))) (i 0)) (setq exwm-workspace-number num-monitors) (goto-char (point-min)) (while (< i num-monitors) (move-beginning-of-line 1) (push-mark) (search-forward-regexp " ") (backward-char) (push (buffer-substring (mark) (point)) out-plist) (push i out-plist) (setq i (+ i 1)) (pop-mark) (next-line)))) (kill-buffer buf) (setq exwm-randr-workspace-monitor-plist out-plist)) (while (> exwm-workspace-number (length exwm-workspace--list)) (exwm-workspace-add))) (add-hook 'exwm-randr-screen-change-hook #'my/exwm-auto-workspace-montior) (defun my/exwm-set-buffer-name () (if exwm-title (let* ((shortened-title (replace-regexp-in-string " - Mozilla Firefox" "" exwm-title)) (class-and-title (concat exwm-class-name "<" shortened-title ">"))) (setq-local exwm-title class-and-title) (exwm-workspace-rename-buffer exwm-title)))) (defun my/exwm-other-workspace (arg) "Focus other monitor's workspace." (interactive "p") ;; based on other-frame (let ((filter-f (function (lambda (f) (and (exwm-workspace--active-p f) (not (eq (selected-frame) f)))))) (sframe (selected-frame)) (frame (selected-frame))) (while (> arg 0) (setq frame (next-frame frame)) (while (and (not (eq frame sframe)) (not (eq (frame-visible-p frame) t)) (funcall filter-f frame)) (setq frame (next-frame frame))) (setq arg (1- arg))) (while (< arg 0) (setq frame (previous-frame frame)) (while (and (not (eq frame sframe)) (not (eq (frame-visible-p frame) t)) (filter-f frame)) (setq frame (previous-frame frame))) (setq arg (1+ arg))) (exwm-workspace-switch frame))) (defun my/dmenu (command) (interactive (list (read-shell-command "$ "))) (start-process-shell-command command nil command)) (defun my/browser () (interactive) (start-process-shell-command "glide" nil "glide")) (defun my/eshell (&optional arg) (interactive "P") (if (eq major-mode 'eshell-mode) ;; switch back (switch-to-prev-buffer) (eshell arg))) (defun my/brightnessdown () (interactive) (start-process "" nil "brightnessdown")) (defun my/brightnessup () (interactive) (start-process "" nil "brightnessup")) (defun my/mute () (interactive) (start-process "" nil "pactl" "set-sink-mute" "@DEFAULT_SINK@" "toggle")) (defun my/voldown () (interactive) (start-process "" nil "pactl" "set-sink-volume" "@DEFAULT_SINK@" "-5%")) (defun my/volup () (interactive) (start-process "" nil "pactl" "set-sink-volume" "@DEFAULT_SINK@" "+5%")) (exwm-randr-mode) (exwm-systemtray-mode) (push ?\C-\\ exwm-input-prefix-keys) ;;C-\ to switch input method (push ?\C-u exwm-input-prefix-keys) ;; send C-u to all windows too (push ?\M-L exwm-input-prefix-keys) (when (equal window-system 'x) (exwm-enable)) (when (s-equals? (getenv "INSIDE_EXWM") "1") (display-time-mode 1) (display-battery-mode 1) (ednc-mode 1)) :hook (exwm-update-class . my/exwm-set-buffer-name) (exwm-update-title . my/exwm-set-buffer-name) :custom (exwm-replace nil) (exwm-title-length 50) (exwm-workspace-show-all-buffers t) (exwm-layout-show-all-buffers t) (exwm-modeline-randr t) (exwm-modeline-short nil) (exwm-modeline-urgent t) (exwm-manage-force-tiling t) (exwm-input-global-keys `( ([?\M-r] . exwm-reset) ;; Bind "s-w" to window switcher ([?\M-W] . consult-buffer) ([?\M-o] . other-window) ([?\M-O] . my/exwm-other-workspace) ([?\M-D] . my/dmenu) ([?\M-E] . my/browser) ([M-return] . my/eshell) ([?\M-K] . kill-current-buffer) ,@(mapcar (lambda (n) (let* ((from (concat "C-x " (format "%d" n))) (to (concat "M-" (format "%d" n))) (bind (keymap-lookup global-map from))) (cons (kbd to) bind))) (number-sequence 0 9)) ([XF86MonBrightnessDown] . my/brightnessdown) ([XF86MonBrightnessUp] . my/brightnessup) ([XF86AudioMute] . my/mute) ([XF86AudioLowerVolume] . my/voldown) ([XF86AudioRaiseVolume] . my/volup))) (exwm-input-simulation-keys '(;; movement ([?\C-b] . [left]) ([?\M-b] . [C-left]) ([?\C-f] . [right]) ([?\M-f] . [C-right]) ([?\C-p] . [up]) ([?\C-n] . [down]) ([?\C-a] . [home]) ([?\C-e] . [end]) ([?\M-v] . [prior]) ([?\C-v] . [next]) ;; edit, copy, paste ([?\C-d] . [delete]) ([?\C-k] . [S-end delete]) ([M-backspace] . [C-backspace]) ([?\M-w] . [?\C-c]) ([?\C-y] . [?\C-v]) ([?\C-s] . [?\C-f]))) (exwm-input-move-event 'M-down-mouse-1) :bind (:map exwm-mode-map ("C-q" . 'exwm-input-send-next-key) ("M-!" . 'shell-command))) (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" "#emacs-social" "#linux" "#archlinux" "#haskell" "#invidious" "#duskos"))) (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)) (progn ; indent code when pasting (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)) (use-package minions :demand t :config (minions-mode 1) :custom (minions-prominent-modes '(persp-mode auto-fill-mode eldoc-mode eglot-mode lsp-mode))) (progn ; default modeline config additions (setq-default global-mode-string '("" (: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))))) (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) ;; start additional async shell commands in new buffers without asking (setq async-shell-command-buffer 'new-buffer)) (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)))) (electric-pair-mode 1) ;; (setq x-super-keysym 'meta) (global-set-key (kbd "C-x C-C") 'save-buffers-kill-terminal) (global-set-key (kbd "C-x C-c") 'my/close-or-kill) (global-set-key (kbd "M-w") 'copy-region-as-kill) ; make copying not flash cursor (global-set-key (kbd "C-x -") 'my/swap-other-window-buffer) (global-set-key (kbd "M-(") 'my/wrap-region-paren) (global-set-key (kbd "M-z") 'my/zap-whitespace) (global-set-key (kbd "C-M-z") 'my/wrap-sexp) (global-set-key (kbd "M-o") 'other-window) (global-set-key (kbd "M-c") 'calc) (global-set-key (kbd "M-U") 'scroll-lock-mode) (global-set-key (kbd "M-Q") 'auto-fill-mode) (global-set-key (kbd "M-A") 'beginning-of-line-text) (global-set-key (kbd "C-c r") 'raise-sexp) (global-set-key (kbd "M-\"") 'my/activate-mark) (global-set-key (kbd "C-x w o") 'my/toggle-window-other-reachability) (advice-add 'mode-line-window-control :around (lambda (f) (concat (funcall f) (if (window-parameter nil 'no-other-window) "o" ""))) '(:name "other-window-indicator")) ;; this stuff is conditionally activated by exwm ;; (use-package single-header ;; :ensure nil ;; :demand t ;; :init ;; (use-package ednc ; notifications, required for single-header ;; ) ;; :config ;; (single-header-mode 1) ;; :bind ;; ("M-L d" . 'single-header-dismiss) ;; ("M-L t" . 'single-header-mode) ;; ;; (keymap-global-set "M-L d" 'single-header-dismiss) ;; ;; (keymap-global-set "M-L t" 'single-header-mode) ;; ) (use-package time :demand t :config ;; (display-time-mode 1) :custom (display-time-day-and-date t) (display-time-24hr-format t)) (use-package battery :demand t :config ;; (display-battery-mode 1) ) (use-package ednc :demand t :config ;; (when (eq window-system 'x) ;; (ednc-mode 1)) ) (use-package mu4e :ensure nil :demand t :init ;; assumed Maildir layout ;; ~/Maildir/Account0/{Inbox,Sent,Trash} ;; ~/Maildir/Account1/{Inbox,Sent,Trash} ;; where Account0 is context name (defun my/make-mu4e-context (context-name full-name mail-address signature) "Return a mu4e context named CONTEXT-NAME with :match-func matching folder name CONTEXT-NAME in Maildir. The context's `user-mail-address', `user-full-name' and `mu4e-compose-signature' is set to MAIL-ADDRESS FULL-NAME and SIGNATURE respectively. Special folders are set to context specific folders." (let ((dir-name (concat "/" context-name))) (make-mu4e-context :name context-name ;; we match based on the maildir of the message ;; this matches maildir /Arkham and its sub-directories :match-func `(lambda (msg) (when msg (string-match-p ,(concat "^" dir-name) (mu4e-message-field msg :maildir)))) :vars `((user-mail-address . ,mail-address) (user-full-name . ,full-name) (mu4e-sent-folder . ,(concat dir-name "/sent")) (mu4e-drafts-folder . ,(concat dir-name "/drafts")) (mu4e-trash-folder . ,(concat dir-name "/trash")) (mu4e-refile-folder . ,(concat dir-name "/archive")) (mu4e-compose-signature . ,signature))))) :custom (mu4e-change-filenames-when-moving t) (mu4e-get-mail-command "mbsync --all") :config ;;Fixing duplicate UID errors when using mbsync and mu4e (setq mu4e-contexts `(,(my/make-mu4e-context "thomasmulmer02" "Thomas Ulmer" "thomasmulmer02@gmail.com" "Thanks, Thomas Ulmer"))) (require 'smtpmail) (setq message-send-mail-function 'smtpmail-send-it) (setq smtpmail-default-smtp-server "smtp.gmail.com" smtpmail-smtp-server "smtp.gmail.com" smtpmail-smtp-service 587 starttls-use-gnutls t smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil)) smtp-auth-credentials (expand-file-name "~/.authinfo.gpg"))) ;; ---------------------------------------------------------------------- ;; theme stuff (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) (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. ) (put 'set-goal-column 'disabled nil)