commit e0ad4ea6276b48b8fa795d1375a507d31148e8cc Author: Charlie Root Date: Fri Sep 6 11:42:11 2024 +0200 working system diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6260081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +/auto-save-list +/eln-cache +/elpa* +/transient +/tldr +/games +/eshell +custom-el* +.uptimes.el +.session +recentf +projectile-bookmarks.eld +org-clock-save.el + diff --git a/.mc-lists.el b/.mc-lists.el new file mode 100644 index 0000000..11bff02 --- /dev/null +++ b/.mc-lists.el @@ -0,0 +1,13 @@ +;; This file is automatically generated by the multiple-cursors extension. +;; It keeps track of your preferences for running commands with multiple cursors. + +(setq mc/cmds-to-run-for-all + '( + evil-insert-line + )) + +(setq mc/cmds-to-run-once + '( + evil-backward-char + evil-insert + )) diff --git a/custom.el b/custom.el new file mode 100644 index 0000000..0edd870 --- /dev/null +++ b/custom.el @@ -0,0 +1,12 @@ +(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. + '(safe-local-variable-values '((lexical-bindings . 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. + ) diff --git a/early-init.el b/early-init.el new file mode 100644 index 0000000..0526d08 --- /dev/null +++ b/early-init.el @@ -0,0 +1,3 @@ +(setq package-enable-at-startup nil) + +(provide 'early-init) diff --git a/init.el b/init.el new file mode 100644 index 0000000..bfb0122 --- /dev/null +++ b/init.el @@ -0,0 +1,101 @@ +;; init.el --- Load the full configuration -*- lexical-binding: t -*- +;;; Commentary: + + +;; This file bootstraps the configuration, which is divided into +;; a number of other files. + +;;; Code: + + +(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory)) + +;; Adjust garbage collection threshold for early startup (see use of gcmh below) +(setq gc-cons-threshold (* 128 1024 1024)) +(defvar cache-dir "~/.local/cache") + +;; Process performance tuning + +(setq read-process-output-max (* 4 1024 1024)) +(setq process-adaptive-read-buffering nil) + + + + + +(setq custom-file (locate-user-emacs-file "custom.el")) + +;; Initialize elpa +(require 'init-elpa) + +;; And some exec paths +(require 'init-exec-path) + +;; General performance tuning +(when (require-package 'gcmh) + (setq gcmh-high-cons-threshold (* 128 1024 1024)) + (add-hook 'after-init-hook (lambda () + (gcmh-mode) + (diminish 'gcmh-mode)))) + +(setq jit-lock-defer-time 0) + +(require-package 'diminish) +;; Packages +(require 'init-meow) + +(require 'init-gui-frames) +(require 'init-dired) +(require 'init-themes) +(require 'init-look) +(require 'init-isearch) +(require 'init-uniquify) +;; (require 'init-flymake) +;;(require 'init-flycheck) +(require 'init-recentf) +(require 'init-minibuffer) +(require 'init-ibuffer) +;;(require 'init-eglot) +(require 'init-corfu) +;;(require 'init-company) +(require 'init-whitespace) +(require 'init-editing-utils) +(require 'init-paredit) +(require 'init-lisp) +(require 'init-spelling) +(require 'init-folding) +(require 'init-modeline) +(require 'init-terminal) +(require 'init-org) +(require 'init-git) + +(require 'init-vc) + +(require 'init-projectile) +;;(require 'init-general) + +(require-package 'sudo-edit) +(require-package 'gnuplot) +(maybe-require-package 'tldr) +(maybe-require-package 'dotenv-mode) + + + +(require 'init-direnv) +(when (and (require 'treesit nil t) + (fboundp 'treesit-available-p) + (treesit-available-p)) + (require 'init-treesitter)) + + +(require 'init-locales) + +(require 'init-local nil t) + +(provide 'init) + +;; Local Variables: +;; coding: utf-8 +;; no-byte-compile: t +;; End: +;;; init.el ends here diff --git a/lisp/#init-meow.el# b/lisp/#init-meow.el# new file mode 100644 index 0000000..4f7b154 --- /dev/null +++ b/lisp/#init-meow.el# @@ -0,0 +1,118 @@ +(when (maybe-require-package 'meow) +(defun meow-setup () + (setq meow-cheatsheet-physical-layout meow-cheatsheet-physical-layout-iso) + (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwertz) + + (meow-thing-register 'angle + '(pair (";") (":")) + '(pair (";") (":"))) + + (setq meow-char-thing-table + '((?f . round) + (?d . square) + (?s . curly) + (?a . angle) + (?r . string) + (?v . paragraph) + (?c . line) + (?x . buffer))) + + (meow-leader-define-key + ;; Use SPC (0-9) for digit arguments. + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument) + '("-" . meow-keypad-describe-key) + '("_" . meow-cheatsheet)) + + (meow-normal-define-key + ;; expansion + '("0" . meow-expand-0) + '("1" . meow-expand-1) + '("2" . meow-expand-2) + '("3" . meow-expand-3) + '("4" . meow-expand-4) + '("5" . meow-expand-5) + '("6" . meow-expand-6) + '("7" . meow-expand-7) + '("8" . meow-expand-8) + '("9" . meow-expand-9) + '("ä" . meow-reverse) + + ;; movement + '("i" . meow-prev) + '("k" . meow-next) + '("j" . meow-left) + '("l" . meow-right) + + '("z" . meow-search) + '("-" . meow-visit) + + ;; expansion + '("I" . meow-prev-expand) + '("K" . meow-next-expand) + '("J" . meow-left-expand) + '("L" . meow-right-expand) + + '("u" . meow-back-word) + '("U" . meow-back-symbol) + '("o" . meow-next-word) + '("O" . meow-next-symbol) + + '("a" . meow-mark-word) + '("A" . meow-mark-symbol) + '("s" . meow-line) + '("S" . meow-goto-line) + '("w" . meow-block) + '("q" . meow-join) + '("g" . meow-grab) + '("G" . meow-pop-grab) + '("m" . meow-swap-grab) + '("M" . meow-sync-grab) + '("p" . meow-cancel-selection) + '("P" . meow-pop-selection) + + '("x" . meow-till) + '("y" . meow-find) + + '("," . meow-beginning-of-thing) + '("." . meow-end-of-thing) + '(";" . meow-inner-of-thing) + '(":" . meow-bounds-of-thing) + + ;; editing + '("d" . meow-kill) + '("f" . meow-change) + '("t" . meow-delete) + '("c" . meow-save) + '("v" . meow-yank) + '("V" . meow-yank-pop) + + '("e" . meow-insert) + '("E" . meow-open-above) + '("r" . meow-append) + '("R" . meow-open-below) + + '("h" . undo-only) + '("H" . undo-redo) + + '("b" . open-line) + '("B" . split-line) + + '("ü" . indent-rigidly-left-to-tab-stop) + '("+" . indent-rigidly-right-to-tab-stop) + + ;; ignore escape + '("" . ignore))) + +(meow-setup) +(meow-global-mode 1)) + +(provide 'init-meow) diff --git a/lisp/init-company.el b/lisp/init-company.el new file mode 100644 index 0000000..c818eb8 --- /dev/null +++ b/lisp/init-company.el @@ -0,0 +1,15 @@ +;;; init-company.el --- Companyy autocompletion +;;; Commentary: +;;; Code: +(when (maybe-require-package 'company) + ;;(diminish 'company-mode) + (add-hook 'after-init-hook 'global-company-mode) + (setq company-minimum-prefix-length 1 + company-idle-delay 0.0 + company-selection-wrap-around t + company-tooltip-align-annotations t + company-frontends '(company-pseudo-tooltip-frontend ; show tooltip even for single candidate + company-echo-metadata-frontend))) + +(provide 'init-company) +;;; end of file init-company.el diff --git a/lisp/init-company.el~ b/lisp/init-company.el~ new file mode 100644 index 0000000..3a78974 --- /dev/null +++ b/lisp/init-company.el~ @@ -0,0 +1,17 @@ +;;; init-company.el --- Companyy autocompletion +;;; Commentary: +;;; Code: +(when (maybe-require-package 'company) + (diminish 'company-mode) + (add-hook 'after-init-hook 'global-company-mode) + (setq company-minimum-prefix-length 1 + company-idle-delay 0.1 + company-selection-wrap-around t + company-tooltip-align-annotations t + company-frontends '(company-pseudo-tooltip-frontend ; show tooltip even for single candidate + company-echo-metadata-frontend)) + (define-key company-active-map (kbd "C-n") 'company-select-next) + (define-key company-active-map (kbd "C-p") 'company-select-previous) + ) +(provide 'init-company) +;;; end of file init-company.el diff --git a/lisp/init-corfu.el b/lisp/init-corfu.el new file mode 100644 index 0000000..10d0fe2 --- /dev/null +++ b/lisp/init-corfu.el @@ -0,0 +1,51 @@ +;;; init-corfu.el --- Interactive completion in buffers -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +;; WAITING: haskell-mode sets tags-table-list globally, breaks tags-completion-at-point-function +;; TODO Default sort order should place [a-z] before punctuation + +(setq tab-always-indent 'complete) + +(when (maybe-require-package 'orderless) + (with-eval-after-load 'vertico + (require 'orderless) + (setq completion-styles '(orderless basic)))) +(setq completion-category-defaults nil + completion-category-overrides nil) +(setq completion-cycle-threshold 4) + +(when (maybe-require-package 'corfu) + (with-eval-after-load 'eshell + (add-hook 'eshell-mode-hook (lambda () (setq-local corfu-auto nil)))) + (setq-default corfu-quit-no-match 'separator) + + (add-hook 'after-init-hook 'global-corfu-mode) + + (with-eval-after-load 'corfu + (corfu-popupinfo-mode)) + + (setq + corfu-auto t + corfu-auto-delay 0.1 + corfu-auto-prefix 2 + global-corfu-modes '((not erc-mode + circe-mode + help-mode + gud-mode + vterm-mode) + t) + corfu-cycle t + corfu-preselect 'prompt + corfu-count 16 + corfu-max-width 120 + corfu-on-exact-match nil + corfu-quit-at-boundary t + corfu-quit-no-match corfu-quit-at-boundary + tab-always-indent 'complete) + + ;; TODO: https://github.com/jdtsmith/kind-icon + ) + +(provide 'init-corfu) +;;; init-corfu.el ends here diff --git a/lisp/init-corfu.el~ b/lisp/init-corfu.el~ new file mode 100644 index 0000000..3119df3 --- /dev/null +++ b/lisp/init-corfu.el~ @@ -0,0 +1,39 @@ +;;; init-corfu.el --- Interactive completion in buffers -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +;; WAITING: haskell-mode sets tags-table-list globally, breaks tags-completion-at-point-function +;; TODO Default sort order should place [a-z] before punctuation + +(setq tab-always-indent 'complete) +(when (maybe-require-package 'orderless) + (with-eval-after-load 'vertico + (require 'orderless) + (setq completion-styles '(orderless basic)))) +(setq completion-category-defaults nil + completion-category-overrides nil) +(setq completion-cycle-threshold 4) + +(when (maybe-require-package 'corfu) + (setq-default corfu-auto t) + (with-eval-after-load 'eshell + (add-hook 'eshell-mode-hook (lambda () (setq-local corfu-auto nil)))) + (setq-default corfu-quit-no-match 'separator) + (add-hook 'after-init-hook 'global-corfu-mode) + + + + (with-eval-after-load 'corfu + (corfu-popupinfo-mode)) + + ;; Make Corfu also work in terminals, without disturbing usual behaviour in GUI + (when (maybe-require-package 'corfu-terminal) + (with-eval-after-load 'corfu + (corfu-terminal-mode))) + + ;; TODO: https://github.com/jdtsmith/kind-icon + ) + + +(provide 'init-corfu) +;;; init-corfu.el ends here diff --git a/lisp/init-dired.el b/lisp/init-dired.el new file mode 100644 index 0000000..e1edd21 --- /dev/null +++ b/lisp/init-dired.el @@ -0,0 +1,42 @@ +;;; init-dired.el --- Dired customisations -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: +(require-package 'dirvish) + +(setq dired-dwim-target t ; suggest a target for moving/copying intelligently + ;; don't prompt to revert, just do it + dired-auto-revert-buffer #'dired-buffer-stale-p + ;; Always copy/delete recursively + dired-recursive-copies 'always + dired-recursive-deletes 'top + ;; Ask whether destination dirs should get created when copying/removing files. + dired-create-destination-dirs 'ask + ;; Where to store image caches + image-dired-dir (concat cache-dir "image-dired/") + image-dired-db-file (concat image-dired-dir "db.el") + image-dired-gallery-dir (concat image-dired-dir "gallery/") + image-dired-temp-image-file (concat image-dired-dir "temp-image") + image-dired-temp-rotate-image-file (concat image-dired-dir "temp-rotate-image") + ;; Screens are larger nowadays, we can afford slightly larger thumbnails + image-dired-thumb-size 150) + +(dirvish-override-dired-mode) +(setq dirvish-cache-dire (concat cache-dir "dirvish-cache/")) +(setq dirvish-use-mode-line nil) ; hide mode line +(setq dirvish-hide-details nil) +(setq dirvish-use-header-line nil) ; hide header line (show the classic dired header) +(setq dirvish-reuse-session nil) + +(setq dirvish-attributes '(file-size) + dirvish-mode-line-format + '(:left (sort file-time symlink) :right (omit yank index))) +(setq dirvish-attributes nil + dirvish-use-header-line nil + dirvish-use-mode-line nil) + + + +(dirvish-peek-mode) + +(provide 'init-dired) +;;; init-dired.el ends here diff --git a/lisp/init-direnv.el b/lisp/init-direnv.el new file mode 100644 index 0000000..a144f8d --- /dev/null +++ b/lisp/init-direnv.el @@ -0,0 +1,12 @@ +;;; init-direnv.el --- Integrate with direnv -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(when (maybe-require-package 'envrc) + (with-eval-after-load 'envrc + (define-key envrc-mode-map (kbd "C-c e") 'envrc-command-map)) + (add-hook 'after-init-hook 'envrc-global-mode)) + +(provide 'init-direnv) + +;;; init-direnv.el ends here diff --git a/lisp/init-editing-utils.el b/lisp/init-editing-utils.el new file mode 100644 index 0000000..5c35c88 --- /dev/null +++ b/lisp/init-editing-utils.el @@ -0,0 +1,182 @@ +(global-set-key (kbd "M-Y") 'browse-kill-ring) +(global-set-key (kbd "M-Y") 'browse-kill-ring) +(global-set-key (kbd "M-Y") 'browse-kill-ring) +(global-set-key (kbd "M-Y") 'browse-kill-ring) +;;; init-editing-utils.el --- Day-to-day editing helpers -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(require-package 'unfill) + +(when (fboundp 'electric-pair-mode) + (add-hook 'after-init-hook 'electric-pair-mode)) +(add-hook 'after-init-hook 'electric-indent-mode) + +(maybe-require-package 'list-unicode-display) + + +;;; Some basic preferences + +(setq-default + blink-cursor-mode nil + bookmark-default-file (locate-user-emacs-file ".bookmarks.el") + buffers-menu-max-size 30 + case-fold-search t + column-number-mode t + ediff-split-window-function 'split-window-horizontally + ediff-window-setup-function 'ediff-setup-windows-plain + indent-tabs-mode nil + create-lockfiles nil + auto-save-default nil + make-backup-files nil + mouse-yank-at-point t + save-interprogram-paste-before-kill t + scroll-preserve-screen-position 'always + set-mark-command-repeat-pop t + show-paren-delay 0 + tooltip-delay 1.5 + truncate-lines t + truncate-partial-width-windows nil) + +(add-hook 'after-init-hook 'delete-selection-mode) + +(add-hook 'after-init-hook 'global-auto-revert-mode) +(setq global-auto-revert-non-file-buffers t + auto-revert-verbose nil) +(with-eval-after-load 'autorevert + (diminish 'auto-revert-mode)) + +(add-hook 'after-init-hook 'transient-mark-mode) + +(fset 'yes-or-no-p 'y-or-n-p) + +;; Huge files + +(when (fboundp 'so-long-enable) + (add-hook 'after-init-hook 'so-long-enable)) + + +;;; Newline behaviour (see also electric-indent-mode, enabled above) + +(with-eval-after-load 'subword + (diminish 'subword-mode)) + + +(when (fboundp 'display-line-numbers-mode) + (setq-default display-line-numbers-width 3) + (add-hook 'prog-mode-hook 'display-line-numbers-mode)) + + +(when (boundp 'display-fill-column-indicator) + (setq-default indicate-buffer-boundaries 'left) + (setq-default display-fill-column-indicator-character ?┊) + (add-hook 'prog-mode-hook 'display-fill-column-indicator-mode)) + + +(when (require-package 'rainbow-delimiters) + (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)) + +(when (maybe-require-package 'symbol-overlay) + (dolist (hook '(prog-mode-hook html-mode-hook yaml-mode-hook conf-mode-hook)) + (add-hook hook 'symbol-overlay-mode)) + (with-eval-after-load 'symbol-overlay + (diminish 'symbol-overlay-mode) + (define-key symbol-overlay-mode-map (kbd "M-i") 'symbol-overlay-put) + (define-key symbol-overlay-mode-map (kbd "M-I") 'symbol-overlay-remove-all) + (define-key symbol-overlay-mode-map (kbd "M-n") 'symbol-overlay-jump-next) + (define-key symbol-overlay-mode-map (kbd "M-p") 'symbol-overlay-jump-prev))) + +;;; Zap *up* to char is a handy pair for zap-to-char +(global-set-key (kbd "M-Z") 'zap-up-to-char) + + +(require-package 'browse-kill-ring) +(setq browse-kill-ring-separator "\f") +(global-set-key (kbd "M-Y") 'browse-kill-ring) +(with-eval-after-load 'browse-kill-ring + (define-key browse-kill-ring-mode-map (kbd "C-g") 'browse-kill-ring-quit) + (define-key browse-kill-ring-mode-map (kbd "M-n") 'browse-kill-ring-forward) + (define-key browse-kill-ring-mode-map (kbd "M-p") 'browse-kill-ring-previous)) +(with-eval-after-load 'page-break-lines + (add-to-list 'page-break-lines-modes 'browse-kill-ring-mode)) + + +;; Don't disable narrowing commands +(put 'narrow-to-region 'disabled nil) +(put 'narrow-to-page 'disabled nil) +(put 'narrow-to-defun 'disabled nil) +;; Don't disable case-change functions +(put 'upcase-region 'disabled nil) +(put 'downcase-region 'disabled nil) + + +;; Show matching parens +(add-hook 'after-init-hook 'show-paren-mode) + +(when (fboundp 'repeat-mode) + (add-hook 'after-init-hook 'repeat-mode)) + +;;; Handy key bindings + +(when (maybe-require-package 'avy) + (global-set-key (kbd "C-;") 'avy-goto-char-timer)) + +(require-package 'multiple-cursors) +;; multiple-cursors +(global-set-key (kbd "C-<") 'mc/mark-previous-like-this) +(global-set-key (kbd "C->") 'mc/mark-next-like-this) +(global-set-key (kbd "C-+") 'mc/mark-next-like-this) +(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this) + +;; Train myself to use M-f and M-b instead +(global-unset-key [M-left]) +(global-unset-key [M-right]) + +(defun kill-back-to-indentation () + "Kill from point back to the first non-whitespace character on the line." + (interactive) + (let ((prev-pos (point))) + (back-to-indentation) + (kill-region (point) prev-pos))) + +(global-set-key (kbd "C-M-") 'kill-back-to-indentation) + + +;;; Page break lines + +(when (maybe-require-package 'page-break-lines) + (add-hook 'after-init-hook 'global-page-break-lines-mode) + (with-eval-after-load 'page-break-lines + (diminish 'page-break-lines-mode))) + + +;; Shift lines up and down with M-up and M-down. When paredit is enabled, +;; it will use those keybindings. For this reason, you might prefer to +;; use M-S-up and M-S-down, which will work even in lisp modes. + +(require-package 'move-dup) +(global-set-key [M-S-up] 'move-dup-move-lines-up) +(global-set-key [M-S-down] 'move-dup-move-lines-down) + +(global-set-key (kbd "C-c d") 'move-dup-duplicate-down) +(global-set-key (kbd "C-c u") 'move-dup-duplicate-up) + +;;; Cut/copy the current line if no region is active +(require-package 'whole-line-or-region) +(add-hook 'after-init-hook 'whole-line-or-region-global-mode) +(with-eval-after-load 'whole-line-or-region + (diminish 'whole-line-or-region-local-mode)) + + + +(require-package 'highlight-escape-sequences) +(add-hook 'after-init-hook 'hes-mode) + +(require-package 'which-key) +(add-hook 'after-init-hook 'which-key-mode) +(setq-default which-key-idle-delay 1.5) +(with-eval-after-load 'which-key + (diminish 'which-key-mode)) + +(provide 'init-editing-utils) +;;; init-editing-utils.el ends here diff --git a/lisp/init-editing-utils.el~ b/lisp/init-editing-utils.el~ new file mode 100644 index 0000000..0da2227 --- /dev/null +++ b/lisp/init-editing-utils.el~ @@ -0,0 +1,266 @@ +;;; init-editing-utils.el --- Day-to-day editing helpers -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(require-package 'unfill) + +(when (fboundp 'electric-pair-mode) + (add-hook 'after-init-hook 'electric-pair-mode)) +(add-hook 'after-init-hook 'electric-indent-mode) + +(maybe-require-package 'list-unicode-display) + + +;;; Some basic preferences + +(setq-default + blink-cursor-interval 0.4 + bookmark-default-file (locate-user-emacs-file ".bookmarks.el") + buffers-menu-max-size 30 + case-fold-search t + column-number-mode t + ediff-split-window-function 'split-window-horizontally + ediff-window-setup-function 'ediff-setup-windows-plain + indent-tabs-mode nil + create-lockfiles nil + auto-save-default nil + make-backup-files nil + mouse-yank-at-point t + save-interprogram-paste-before-kill t + scroll-preserve-screen-position 'always + set-mark-command-repeat-pop t + tooltip-delay 1.5 + truncate-lines nil + truncate-partial-width-windows nil) + +(add-hook 'after-init-hook 'delete-selection-mode) + +(add-hook 'after-init-hook 'global-auto-revert-mode) +(setq global-auto-revert-non-file-buffers t + auto-revert-verbose nil) +(with-eval-after-load 'autorevert + (diminish 'auto-revert-mode)) + +(add-hook 'after-init-hook 'transient-mark-mode) + + + +;; Huge files + +(when (fboundp 'so-long-enable) + (add-hook 'after-init-hook 'so-long-enable)) + +(require-package 'vlf) + +(defun ffap-vlf () + "Find file at point with VLF." + (interactive) + (let ((file (ffap-file-at-point))) + (unless (file-exists-p file) + (error "File does not exist: %s" file)) + (vlf file))) + + +;;; A simple visible bell which works in all terminal types +(require-package 'mode-line-bell) +(add-hook 'after-init-hook 'mode-line-bell-mode) + + + +;;; Newline behaviour (see also electric-indent-mode, enabled above) + +(defun sanityinc/newline-at-end-of-line () + "Move to end of line, enter a newline, and reindent." + (interactive) + (move-end-of-line 1) + (newline-and-indent)) + +(global-set-key (kbd "S-") 'sanityinc/newline-at-end-of-line) + + + +(with-eval-after-load 'subword + (diminish 'subword-mode)) + + + +(when (fboundp 'display-line-numbers-mode) + (setq-default display-line-numbers-width 3) + (add-hook 'prog-mode-hook 'display-line-numbers-mode)) + + + +(when (boundp 'display-fill-column-indicator) + (setq-default indicate-buffer-boundaries 'left) + (setq-default display-fill-column-indicator-character ?┊) + (add-hook 'prog-mode-hook 'display-fill-column-indicator-mode)) + + + +(when (require-package 'rainbow-delimiters) + (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)) + + +(when (maybe-require-package 'symbol-overlay) + (dolist (hook '(prog-mode-hook html-mode-hook yaml-mode-hook conf-mode-hook)) + (add-hook hook 'symbol-overlay-mode)) + (with-eval-after-load 'symbol-overlay + (diminish 'symbol-overlay-mode) + (define-key symbol-overlay-mode-map (kbd "M-i") 'symbol-overlay-put) + (define-key symbol-overlay-mode-map (kbd "M-I") 'symbol-overlay-remove-all) + (define-key symbol-overlay-mode-map (kbd "M-n") 'symbol-overlay-jump-next) + (define-key symbol-overlay-mode-map (kbd "M-p") 'symbol-overlay-jump-prev))) + + +;;; Zap *up* to char is a handy pair for zap-to-char +(global-set-key (kbd "M-Z") 'zap-up-to-char) + + + +(require-package 'browse-kill-ring) +(setq browse-kill-ring-separator "\f") +(global-set-key (kbd "M-Y") 'browse-kill-ring) +(with-eval-after-load 'browse-kill-ring + (define-key browse-kill-ring-mode-map (kbd "C-g") 'browse-kill-ring-quit) + (define-key browse-kill-ring-mode-map (kbd "M-n") 'browse-kill-ring-forward) + (define-key browse-kill-ring-mode-map (kbd "M-p") 'browse-kill-ring-previous)) +(with-eval-after-load 'page-break-lines + (add-to-list 'page-break-lines-modes 'browse-kill-ring-mode)) + + +;; Don't disable narrowing commands +(put 'narrow-to-region 'disabled nil) +(put 'narrow-to-page 'disabled nil) +(put 'narrow-to-defun 'disabled nil) +;; Don't disable case-change functions +(put 'upcase-region 'disabled nil) +(put 'downcase-region 'disabled nil) + + +;; Show matching parens +(add-hook 'after-init-hook 'show-paren-mode) + +(when (fboundp 'repeat-mode) + (add-hook 'after-init-hook 'repeat-mode)) + + +;;; Handy key bindings + +(with-eval-after-load 'help + (define-key help-map "A" 'describe-face)) + +(global-set-key (kbd "C-.") 'set-mark-command) +(global-set-key (kbd "C-x C-.") 'pop-global-mark) + +(when (maybe-require-package 'avy) + (global-set-key (kbd "C-;") 'avy-goto-char-timer)) + +(require-package 'multiple-cursors) +;; multiple-cursors +(global-set-key (kbd "C-<") 'mc/mark-previous-like-this) +(global-set-key (kbd "C->") 'mc/mark-next-like-this) +(global-set-key (kbd "C-+") 'mc/mark-next-like-this) +(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this) + +;; Train myself to use M-f and M-b instead +(global-unset-key [M-left]) +(global-unset-key [M-right]) + +(defun kill-back-to-indentation () + "Kill from point back to the first non-whitespace character on the line." + (interactive) + (let ((prev-pos (point))) + (back-to-indentation) + (kill-region (point) prev-pos))) + +(global-set-key (kbd "C-M-") 'kill-back-to-indentation) + + + +;;; Page break lines + +(when (maybe-require-package 'page-break-lines) + (add-hook 'after-init-hook 'global-page-break-lines-mode) + (with-eval-after-load 'page-break-lines + (diminish 'page-break-lines-mode))) + + + +;; Shift lines up and down with M-up and M-down. When paredit is enabled, +;; it will use those keybindings. For this reason, you might prefer to +;; use M-S-up and M-S-down, which will work even in lisp modes. + +(require-package 'move-dup) +(global-set-key [M-S-up] 'move-dup-move-lines-up) +(global-set-key [M-S-down] 'move-dup-move-lines-down) + +(global-set-key (kbd "C-c d") 'move-dup-duplicate-down) +(global-set-key (kbd "C-c u") 'move-dup-duplicate-up) + + +;;; Fix backward-up-list to understand quotes, see http://bit.ly/h7mdIL + +(defun sanityinc/backward-up-sexp (arg) + "Jump up to the start of the ARG'th enclosing sexp." + (interactive "p") + (let ((ppss (syntax-ppss))) + (cond ((elt ppss 3) + (goto-char (elt ppss 8)) + (sanityinc/backward-up-sexp (1- arg))) + ((backward-up-list arg))))) + +(global-set-key [remap backward-up-list] 'sanityinc/backward-up-sexp) ; C-M-u, C-M-up + + + +;;; Cut/copy the current line if no region is active +(require-package 'whole-line-or-region) +(add-hook 'after-init-hook 'whole-line-or-region-global-mode) +(with-eval-after-load 'whole-line-or-region + (diminish 'whole-line-or-region-local-mode)) + + + +;; M-^ is inconvenient, so also bind M-j +(global-set-key (kbd "M-j") 'join-line) + + +;; Random line sorting +(defun sanityinc/sort-lines-random (beg end) + "Sort lines in region from BEG to END randomly." + (interactive "r") + (save-excursion + (save-restriction + (narrow-to-region beg end) + (goto-char (point-min)) + (let ;; To make `end-of-line' and etc. to ignore fields. + ((inhibit-field-text-motion t)) + (sort-subr nil 'forward-line 'end-of-line nil nil + (lambda (s1 s2) (eq (random 2) 0))))))) + + + +(require-package 'highlight-escape-sequences) +(add-hook 'after-init-hook 'hes-mode) + + +(require-package 'which-key) +(add-hook 'after-init-hook 'which-key-mode) +(setq-default which-key-idle-delay 1.5) +(with-eval-after-load 'which-key + (diminish 'which-key-mode)) + + +(defun sanityinc/disable-features-during-macro-call (orig &rest args) + "When running a macro, disable features that might be expensive. +ORIG is the advised function, which is called with its ARGS." + (let (post-command-hook + font-lock-mode + (tab-always-indent (or (eq 'complete tab-always-indent) tab-always-indent))) + (apply orig args))) + +(advice-add 'kmacro-call-macro :around 'sanityinc/disable-features-during-macro-call) + + +(provide 'init-editing-utils) +;;; init-editing-utils.el ends here diff --git a/lisp/init-eglot.el b/lisp/init-eglot.el new file mode 100644 index 0000000..5b13d68 --- /dev/null +++ b/lisp/init-eglot.el @@ -0,0 +1,13 @@ +;;; init-eglot.el --- LSP support via eglot -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; Code: + +(when (maybe-require-package 'eglot) + (maybe-require-package 'consult-eglot)) + + + +(provide 'init-eglot) +;;; init-eglot.el ends here diff --git a/lisp/init-elpa.el b/lisp/init-elpa.el new file mode 100644 index 0000000..4af3bd4 --- /dev/null +++ b/lisp/init-elpa.el @@ -0,0 +1,52 @@ +;;; Package --- config -*- lexical-binding: t -*- +(require 'package) + +;; We install seperate package repositories for each Emacs version to prevent bytecode incompatibility +(setq package-user-dir + (expand-file-name (format "elpa-%s.%s" emacs-major-version emacs-minor-version) + user-emacs-directory)) + + +; Standard Package repository +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) + +(defun require-package (package &optional min-version no-refresh) +"Install given PACKAGE, optionally requiring MIN-VERSION. +If NO-REFRESH is non-nil, the available package lists will not be +re-downloaded in order to locate PACKAGE." + (when (stringp min-version) + (setq min-version (version-to-list min-version))) + (or (package-installed-p package min-version) + (let* ((known (cdr (assoc package package-archive-contents))) + (best (car (sort known (lambda (a b) + (version-list-<= (package-desc-version b) + (package-desc-version a))))))) + (if (and best (version-list-<= min-version (package-desc-version best))) + (package-install best) + (if no-refresh + (error "No version of %s >= %S is available" package min-version) + (package-refresh-contents) + (require-package package min-version t))) + (package-installed-p package min-version)))) + + +(defun maybe-require-package (package &optional min-version no-refresh) + "Try to install PACKAGE, and return non-nil if successful. +In the event of failure, return nil and print a warning message. +Optionally require MIN-VERSION. If NO-REFRESH is non-nil, the +available package lists will not be re-downloaded in order to +locate PACKAGE." + (condition-case err + (require-package package min-version no-refresh) + (error + (message "Couldn't install optional package `%s': %S" package err) + nil))) + + + +(setq package-enable-at-startup nil) +(setq package-native-compile t) +(package-initialize) + +(provide 'init-elpa) +;;; init-elpa.el end of file diff --git a/lisp/init-elpa.el~ b/lisp/init-elpa.el~ new file mode 100644 index 0000000..cc84ef7 --- /dev/null +++ b/lisp/init-elpa.el~ @@ -0,0 +1,6 @@ +(require 'package) + +;; We install seperate package repositories for each Emacs version to prevent bytecode incompatibility + +; Standard Package repository +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) diff --git a/lisp/init-evil.el~ b/lisp/init-evil.el~ new file mode 100644 index 0000000..149a2f3 --- /dev/null +++ b/lisp/init-evil.el~ @@ -0,0 +1,20 @@ +(maybe-require-package 'evil) +(maybe-require-package 'evil-collection) +(maybe-require-package 'evil-goggles) + +(setq + evil-want-keybinding nil + evil-want-C-u-scroll t + evil-mode-beyond-eol t + evil-mode-fine-undo t + evil-undo-system 'undo-redo) + +(evil-mode 1) + +(evil-collection-init '(magit ibuffer))) + +(setq evil-goggles-duration 0.15) +(evil-goggles-mode t)) + +(provide 'init-evil) + diff --git a/lisp/init-evil.org~ b/lisp/init-evil.org~ new file mode 100644 index 0000000..7e15cda --- /dev/null +++ b/lisp/init-evil.org~ @@ -0,0 +1 @@ +(use-package diff --git a/lisp/init-exec-path.el b/lisp/init-exec-path.el new file mode 100644 index 0000000..494b4c4 --- /dev/null +++ b/lisp/init-exec-path.el @@ -0,0 +1,18 @@ +;;; init-exec-path.el --- Set up exec-path to help Emacs find programs -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(require-package 'exec-path-from-shell) + +(with-eval-after-load 'exec-path-from-shell + (dolist (var '("SSH_AUTH_SOCK" "SSH_AGENT_PID" "GPG_AGENT_INFO" "LANG" "LC_CTYPE" "NIX_SSL_CERT_FILE" "NIX_PATH")) + (add-to-list 'exec-path-from-shell-variables var))) + + +(when (or (memq window-system '(mac ns x pgtk)) + (unless (memq system-type '(ms-dos windows-nt)) + (daemonp))) + (exec-path-from-shell-initialize)) + +(provide 'init-exec-path) +;;; init-exec-path.el ends here diff --git a/lisp/init-flycheck.el b/lisp/init-flycheck.el new file mode 100644 index 0000000..6217292 --- /dev/null +++ b/lisp/init-flycheck.el @@ -0,0 +1,9 @@ +;;; init-flycheck.el --- Flycheck configuration +;;; Commentary: +;;; Code: + +(when (maybe-require-package 'flycheck) + (add-hook 'after-init-hook 'global-flycheck-mode) ) + +(provide 'init-flycheck) +;;; init-flycheck.el ends here diff --git a/lisp/init-flymake.el b/lisp/init-flymake.el new file mode 100644 index 0000000..36f7c4d --- /dev/null +++ b/lisp/init-flymake.el @@ -0,0 +1,34 @@ +;;; init-flymake.el --- Configure Flymake global behaviour -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(maybe-require-package 'flymake "1.2.1") + +;; Use flycheck checkers with flymake, to extend its coverage +(when (maybe-require-package 'flymake-flycheck) + ;; Disable flycheck checkers for which we have flymake equivalents + (with-eval-after-load 'flycheck + (setq-default + flycheck-disabled-checkers + (append (default-value 'flycheck-disabled-checkers) + '(emacs-lisp emacs-lisp-checkdoc emacs-lisp-package sh-shellcheck)))) + + (add-hook 'flymake-mode-hook 'flymake-flycheck-auto) + (add-hook 'prog-mode-hook 'flymake-mode) + (add-hook 'text-mode-hook 'flymake-mode)) + +(with-eval-after-load 'flymake + ;; Provide some flycheck-like bindings in flymake mode to ease transition + (define-key flymake-mode-map (kbd "C-c ! l") 'flymake-show-buffer-diagnostics) + (define-key flymake-mode-map (kbd "C-c ! n") 'flymake-goto-next-error) + (define-key flymake-mode-map (kbd "C-c ! p") 'flymake-goto-prev-error) + (define-key flymake-mode-map (kbd "C-c ! c") 'flymake-start)) + + (setq eldoc-documentation-function 'eldoc-documentation-compose) + + (add-hook 'flymake-mode-hook + (lambda () + (add-hook 'eldoc-documentation-functions 'flymake-eldoc-function nil t))) + +(provide 'init-flymake) +;;; init-flymake.el ends here diff --git a/lisp/init-folding.el b/lisp/init-folding.el new file mode 100644 index 0000000..8859c66 --- /dev/null +++ b/lisp/init-folding.el @@ -0,0 +1,13 @@ +;;; init-folding.el --- Support code and region folding -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(when (maybe-require-package 'origami) + (global-origami-mode 1) + (with-eval-after-load 'origami + (define-key origami-mode-map (kbd "C-c f") 'origami-recursively-toggle-node) + (define-key origami-mode-map (kbd "C-c F") 'origami-toggle-all-nodes))) + + +(provide 'init-folding) +;;; init-folding.el ends here diff --git a/lisp/init-general.el b/lisp/init-general.el new file mode 100644 index 0000000..d7f1903 --- /dev/null +++ b/lisp/init-general.el @@ -0,0 +1,165 @@ +;;; init-general.el --- config for general keybindings +;;; Commentary: +;;; Code: +(require-package 'general) + + +(general-evil-setup) + + ;; set up 'SPC' as the global leader key +(general-create-definer cr/leader-keys + :states '(normal insert visual emacs) + :keymaps 'override + :prefix "SPC" ;; set leader + :global-prefix "M-SPC") ;; access leader in insert mode + +(cr/leader-keys + "SPC" '(counsel-M-x :wk "Counsel M-x") + "." '(find-file :wk "Find file")) + +(cr/leader-keys + "b" '(:ignore t :wk "Bookmarks/Buffers") + "b b" '(switch-to-buffer :wk "Switch to buffer") + "b p" '(previous-buffer :wk "Switch to previous buffer") + "d d" '(dired :wk "Open dired") + "d f" '(dired-finish-edit :wk "Writable dired finish edit") + "d j" '(dired-jump :wk "Dired jump to current") + "d w" '(wdired-change-to-wdired-mode :wk "Writable dired")) + +(cr/leader-keys + "e" '(:ignore t :wk "Ediff/Eshell/Eval/EWW") + "e b" '(eval-buffer :wk "Evaluate elisp in buffer") + "e d" '(eval-defun :wk "Evaluate defun containing or after point") + "e e" '(eval-expression :wk "Evaluate an elisp expression") + "e f" '(ediff-files :wk "Run ediff on a pair of files") + "e F" '(ediff-files3 :wk "Run ediff on three files") + "e h" '(counsel-esh-history :which-key "Eshell history") + "e l" '(eval-last-sexp :wk "Evaluate elisp expression before point") + "e r" '(eval-region :wk "Evaluate elisp in region")) + +(cr/leader-keys + "f" '(:ignore t :wk "Files") + "f c" '((lambda () (interactive) + (find-file "~/.emacs.d/init.el")) + :wk "Open emacs init.el") + "f e" '((lambda () (interactive) + (dired "~/.emacs.d")) + :wk "Open user-emacs-directory in dired") + "f d" '(find-grep-dired :wk "Search for string in files in DIR") + "f g" '(counsel-grep-or-swiper :wk "Search for string current file") + "f j" '(counsel-file-jump :wk "Jump to a file below current directory") + "f l" '(counsel-locate :wk "Locate a file") + "f r" '(counsel-recentf :wk "Find recent files") + "f u" '(sudo-edit-find-file :wk "Sudo find file") + "f U" '(sudo-edit :wk "Sudo edit file")) + +(cr/leader-keys + "g" '(:ignore t :wk "Git") + "g /" '(magit-displatch :wk "Magit dispatch") + "g ." '(magit-file-displatch :wk "Magit file dispatch") + "g b" '(magit-branch-checkout :wk "Switch branch") + "g c" '(:ignore t :wk "Create") + "g c b" '(magit-branch-and-checkout :wk "Create branch and checkout") + "g c c" '(magit-commit-create :wk "Create commit") + "g c f" '(magit-commit-fixup :wk "Create fixup commit") + "g C" '(magit-clone :wk "Clone repo") + "g f" '(:ignore t :wk "Find") + "g f c" '(magit-show-commit :wk "Show commit") + "g f f" '(magit-find-file :wk "Magit find file") + "g f g" '(magit-find-git-config-file :wk "Find gitconfig file") + "g F" '(magit-fetch :wk "Git fetch") + "g g" '(magit-status :wk "Magit status") + "g i" '(magit-init :wk "Initialize git repo") + "g l" '(magit-log-buffer-file :wk "Magit buffer log") + "g r" '(vc-revert :wk "Git revert file") + "g s" '(magit-stage-file :wk "Git stage file") + "g t" '(git-timemachine :wk "Git time machine") + "g u" '(magit-stage-file :wk "Git unstage file")) + +(cr/leader-keys + "h" '(:ignore t :wk "Help") + "h a" '(counsel-apropos :wk "Apropos") + "h b" '(describe-bindings :wk "Describe bindings") + "h c" '(describe-char :wk "Describe character under cursor") + "h d" '(:ignore t :wk "Emacs documentation") + "h f" '(describe-function :wk "Describe function") + "h F" '(describe-face :wk "Describe face") + "h i" '(info :wk "Info") + "h k" '(describe-key :wk "Describe key") + "h l" '(view-lossage :wk "Display recent keystrokes and the commands run") + "h m" '(describe-mode :wk "Describe mode") + "h t" '(load-theme :wk "Load theme") + "h v" '(describe-variable :wk "Describe variable") + "h w" '(where-is :wk "Prints keybinding for command if set") + "h x" '(describe-command :wk "Display full documentation for command")) + +(cr/leader-keys + "m" '(:ignore t :wk "Org") + "m a" '(org-agenda :wk "Org agenda") + "m e" '(org-export-dispatch :wk "Org export dispatch") + "m i" '(org-toggle-item :wk "Org toggle item") + "m t" '(org-todo :wk "Org todo") + "m B" '(org-babel-tangle :wk "Org babel tangle") + "m T" '(org-todo-list :wk "Org todo list")) + +(cr/leader-keys + "m b" '(:ignore t :wk "Tables") + "m b -" '(org-table-insert-hline :wk "Insert hline in table")) + +(cr/leader-keys + "m d" '(:ignore t :wk "Date/deadline") + "m d t" '(org-time-stamp :wk "Org time stamp")) + +(cr/leader-keys + "o" '(:ignore t :wk "Open") + "o d" '(dashboard-open :wk "Dashboard") + "o e" '(elfeed :wk "Elfeed RSS") + "o f" '(make-frame :wk "Open buffer in new frame") + "o F" '(select-frame-by-name :wk "Select frame by name")) + +;; projectile-command-map already has a ton of bindings +;; set for us, so no need to specify each individually. +(cr/leader-keys + "p" '(projectile-command-map :wk "Projectile")) + +(cr/leader-keys + "s" '(:ignore t :wk "Search") + "s d" '(dictionary-search :wk "Search dictionary") + "s m" '(man :wk "Man pages") + "s t" '(tldr :wk "Lookup TLDR docs for a command")) + +(cr/leader-keys + "t" '(:ignore t :wk "Toggle") + "t f" '(flycheck-mode :wk "Toggle flycheck") + "t l" '(display-line-numbers-mode :wk "Toggle line numbers") + "t o" '(org-mode :wk "Toggle org mode") + "t r" '(rainbow-mode :wk "Toggle rainbow mode") + "t t" '(visual-line-mode :wk "Toggle truncated lines") + "t v" '(vterm-toggle :wk "Toggle vterm") + "t u" '((lambda () (interactive) (load-file "~/.emacs.d/init.el")) :wk "Reload config")) + +(cr/leader-keys + "w" '(:ignore t :wk "Windows/Words") + ;; Window splits + "w c" '(evil-window-delete :wk "Close window") + "w n" '(evil-window-new :wk "New window") + "w s" '(evil-window-split :wk "Horizontal split window") + "w v" '(evil-window-vsplit :wk "Vertical split window") + ;; Window motions + "w h" '(evil-window-left :wk "Window left") + "w j" '(evil-window-down :wk "Window down") + "w k" '(evil-window-up :wk "Window up") + "w l" '(evil-window-right :wk "Window right") + "w w" '(evil-window-next :wk "Goto next window") + ;; Move Windows + "w H" '(buf-move-left :wk "Buffer move left") + "w J" '(buf-move-down :wk "Buffer move down") + "w K" '(buf-move-up :wk "Buffer move up") + "w L" '(buf-move-right :wk "Buffer move right") + ;; Words + "w d" '(downcase-word :wk "Downcase word") + "w u" '(upcase-word :wk "Upcase word") + "w =" '(count-words :wk "Count words/lines for buffer")) + +(provide 'init-general) +;;; end of file init-general.el diff --git a/lisp/init-git.el b/lisp/init-git.el new file mode 100644 index 0000000..fc40ee6 --- /dev/null +++ b/lisp/init-git.el @@ -0,0 +1,93 @@ +;;; init-git.el --- Git SCM support -*- lexical-binding: t -*- +;;; Commentary: + +;; See also init-github.el. + +;;; Code: + +;; TODO: link commits from vc-log to magit-show-commit +;; TODO: smerge-mode +(require-package 'git-modes) +(when (maybe-require-package 'git-timemachine) + (global-set-key (kbd "C-x v t") 'git-timemachine-toggle)) + +(require-package 'git-link) + +(when (maybe-require-package 'magit) + (setq-default magit-diff-refine-hunk 'all) + + ;;(sanityinc/fullframe-mode 'magit-status-mode) ; TODO get this done + + ;; Hint: customize `magit-repository-directories' so that you can use C-u M-F12 to + ;; quickly open magit on any one of your projects. + (global-set-key [(meta f12)] 'magit-status) + (global-set-key (kbd "C-x g") 'magit-status) + (global-set-key (kbd "C-x M-g") 'magit-dispatch) + ;; Tell magit to automatically put us in vi-insert-mode when committing a change. + (add-hook 'with-editor-mode-hook #'evil-insert-state) + + (defun sanityinc/magit-or-vc-log-file (&optional prompt) + (interactive "P") + (if (and (buffer-file-name) + (eq 'Git (vc-backend (buffer-file-name)))) + (if prompt + (magit-log-buffer-file-popup) + (magit-log-buffer-file t)) + (vc-print-log))) + + (with-eval-after-load 'vc + (define-key vc-prefix-map (kbd "l") 'sanityinc/magit-or-vc-log-file))) + + +(with-eval-after-load 'magit + (define-key magit-status-mode-map (kbd "C-M-") 'magit-section-up)) + +(maybe-require-package 'magit-todos) + +(when (maybe-require-package 'git-commit) + (add-hook 'git-commit-mode-hook 'goto-address-mode)) + + +;; Convenient binding for vc-git-grep +(with-eval-after-load 'vc + (define-key vc-prefix-map (kbd "f") 'vc-git-grep)) + + + +;;; git-svn support + +;; (when (maybe-require-package 'magit-svn) +;; (require-package 'magit-svn) +;; (autoload 'magit-svn-enabled "magit-svn") +;; (defun sanityinc/maybe-enable-magit-svn-mode () +;; (when (magit-svn-enabled) +;; (magit-svn-mode))) +;; (add-hook 'magit-status-mode-hook #'sanityinc/maybe-enable-magit-svn-mode)) + +(with-eval-after-load 'compile + (dolist (defn (list '(git-svn-updated "^\t[A-Z]\t\\(.*\\)$" 1 nil nil 0 1) + '(git-svn-needs-update "^\\(.*\\): needs update$" 1 nil nil 2 1))) + (add-to-list 'compilation-error-regexp-alist-alist defn) + (add-to-list 'compilation-error-regexp-alist (car defn)))) + +(defvar git-svn--available-commands nil "Cached list of git svn subcommands") +(defun git-svn--available-commands () + (or git-svn--available-commands + (setq git-svn--available-commands + (sanityinc/string-all-matches + "^ \\([a-z\\-]+\\) +" + (shell-command-to-string "git svn help") 1)))) + +(autoload 'vc-git-root "vc-git") + +(defun git-svn (dir command) + "Run a git svn subcommand in DIR." + (interactive (list (read-directory-name "Directory: ") + (completing-read "git-svn command: " (git-svn--available-commands) nil t nil nil (git-svn--available-commands)))) + (let* ((default-directory (vc-git-root dir)) + (compilation-buffer-name-function (lambda (major-mode-name) "*git-svn*"))) + (compile (concat "git svn " command)))) + + +(provide 'init-git) +;;; init-git.el ends here diff --git a/lisp/init-gui-frames.el b/lisp/init-gui-frames.el new file mode 100644 index 0000000..145bd71 --- /dev/null +++ b/lisp/init-gui-frames.el @@ -0,0 +1,32 @@ +;; Suppres GUI features + +(setq use-file-dialog nil) +(setq use-dialog-box nil) +(setq inhibit-startup-screen t) + +(tool-bar-mode -1) +(set-scroll-bar-mode nil) +(menu-bar-mode -1) + +(let ((no-border '(internal-border-width . 0))) + (add-to-list 'default-frame-alist no-border) + (add-to-list 'initial-frame-alist no-border)) + + +(setq frame-title-format + '((:eval (if (buffer-file-name) + (abbreviate-file-name (buffer-file-name)) + "%b")))) + +(require-package 'default-text-scale) +(add-hook 'after-init-hook 'default-text-scale-mode) + +(require-package 'disable-mouse) +(add-hook 'after-init-hook 'global-disable-mouse-mode) + +(when (fboundp 'pixel-scroll-precision-mode) + (pixel-scroll-precision-mode)) + + +(provide 'init-gui-frames) + diff --git a/lisp/init-gui-frames.el~ b/lisp/init-gui-frames.el~ new file mode 100644 index 0000000..32ade7c --- /dev/null +++ b/lisp/init-gui-frames.el~ @@ -0,0 +1,10 @@ +;; Suppres GUI features + +(setq use-file-dialog nil) +(setq use-dialog-box nil) +(setq inhibit-startup-screen t) + +(tool-bar-mode -1)) +(set-scroll-bar-mode nil)) +(menu-bar-mode -1) + diff --git a/lisp/init-highlight-todo.el b/lisp/init-highlight-todo.el new file mode 100644 index 0000000..a3c251c --- /dev/null +++ b/lisp/init-highlight-todo.el @@ -0,0 +1,16 @@ +(maybe-require-package 'hl-todo) + +(add-hook (org-mode . hl-todo-mode)) +(add-hook (prog-mode . hl-todo-mode)) + +(setq hl-todo-highlight-punctuation ":") +(setq hl-todo-keyword-faces + `( + ("TODO" warning bold) + ("FIXME" error bold) + ("HACK" font-lock-constant-face bold) + ("REVIEW" font-lock-keyword-face bold) + ("NOTE" success bold) + ("DEPRECATED" font-lock-doc-face bold))) + +(provide 'init-hl-todo) diff --git a/lisp/init-ibuffer.el b/lisp/init-ibuffer.el new file mode 100644 index 0000000..e7eb133 --- /dev/null +++ b/lisp/init-ibuffer.el @@ -0,0 +1,56 @@ +;;; init-ibuffer.el --- ibuffer settings -*- lexical-binding: t -*- +;;; Commentary: + +;; TODO: enhance ibuffer-fontification-alist +;; See http://www.reddit.com/r/emacs/comments/21fjpn/fontifying_buffer_list_for_emacs_243/ + +;;; Code: + +(require-package 'ibuffer-vc) + +(defun ibuffer-set-up-preferred-filters () + (ibuffer-vc-set-filter-groups-by-vc-root) + (unless (eq ibuffer-sorting-mode 'filename/process) + (ibuffer-do-sort-by-filename/process))) + +(add-hook 'ibuffer-hook 'ibuffer-set-up-preferred-filters) + +(setq-default ibuffer-show-empty-filter-groups nil) + +;; fullframe-mode 'ibuffer-mode) + + +(with-eval-after-load 'ibuffer + ;; Use human readable Size column instead of original one + (define-ibuffer-column size-h + (:name "Size" :inline t) + (file-size-human-readable (buffer-size)))) + + +;; Modify the default ibuffer-formats (toggle with `) +(setq ibuffer-formats + '((mark modified read-only vc-status-mini " " + (name 22 22 :left :elide) + " " + (size-h 9 -1 :right) + " " + (mode 12 12 :left :elide) + " " + vc-relative-file) + (mark modified read-only vc-status-mini " " + (name 22 22 :left :elide) + " " + (size-h 9 -1 :right) + " " + (mode 14 14 :left :elide) + " " + (vc-status 12 12 :left) + " " + vc-relative-file))) + +(setq ibuffer-filter-group-name-face 'font-lock-doc-face) + +(global-set-key (kbd "C-x C-b") 'ibuffer) + +(provide 'init-ibuffer) +;;; init-ibuffer.el ends here diff --git a/lisp/init-ibuffer.el~ b/lisp/init-ibuffer.el~ new file mode 100644 index 0000000..acc2960 --- /dev/null +++ b/lisp/init-ibuffer.el~ @@ -0,0 +1,56 @@ +;;; init-ibuffer.el --- ibuffer settings -*- lexical-binding: t -*- +;;; Commentary: + +;; TODO: enhance ibuffer-fontification-alist +;; See http://www.reddit.com/r/emacs/comments/21fjpn/fontifying_buffer_list_for_emacs_243/ + +;;; Code: + +(require-package 'ibuffer-vc) + +(defun ibuffer-set-up-preferred-filters () + (ibuffer-vc-set-filter-groups-by-vc-root) + (unless (eq ibuffer-sorting-mode 'filename/process) + (ibuffer-do-sort-by-filename/process))) + +(add-hook 'ibuffer-hook 'ibuffer-set-up-preferred-filters) + +(setq-default ibuffer-show-empty-filter-groups nil) + +(sanityinc/fullframe-mode 'ibuffer-mode) + + +(with-eval-after-load 'ibuffer + ;; Use human readable Size column instead of original one + (define-ibuffer-column size-h + (:name "Size" :inline t) + (file-size-human-readable (buffer-size)))) + + +;; Modify the default ibuffer-formats (toggle with `) +(setq ibuffer-formats + '((mark modified read-only vc-status-mini " " + (name 22 22 :left :elide) + " " + (size-h 9 -1 :right) + " " + (mode 12 12 :left :elide) + " " + vc-relative-file) + (mark modified read-only vc-status-mini " " + (name 22 22 :left :elide) + " " + (size-h 9 -1 :right) + " " + (mode 14 14 :left :elide) + " " + (vc-status 12 12 :left) + " " + vc-relative-file))) + +(setq ibuffer-filter-group-name-face 'font-lock-doc-face) + +(global-set-key (kbd "C-x C-b") 'ibuffer) + +(provide 'init-ibuffer) +;;; init-ibuffer.el ends here diff --git a/lisp/init-isearch.el b/lisp/init-isearch.el new file mode 100644 index 0000000..5852071 --- /dev/null +++ b/lisp/init-isearch.el @@ -0,0 +1,13 @@ +;;; init-isearch.el --- isearch settings -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +;; Show number of matches while searching +(when (maybe-require-package 'anzu) + (add-hook 'after-init-hook 'global-anzu-mode) + (setq anzu-mode-lighter "") + (global-set-key [remap query-replace-regexp] 'anzu-query-replace-regexp) + (global-set-key [remap query-replace] 'anzu-query-replace)) + +(provide 'init-isearch) +;;; init-isearch.el ends here diff --git a/lisp/init-lisp.el b/lisp/init-lisp.el new file mode 100644 index 0000000..218bdae --- /dev/null +++ b/lisp/init-lisp.el @@ -0,0 +1,273 @@ +;;; init-lisp.el --- Emacs lisp settings, and common config for other lisps -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(setq-default debugger-bury-or-kill 'kill) + +(require-package 'elisp-slime-nav) +(dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook)) + (add-hook hook 'turn-on-elisp-slime-nav-mode)) +(add-hook 'emacs-lisp-mode-hook (lambda () (setq mode-name "ELisp"))) + +(defun sanityinc/headerise-elisp () + "Add minimal header and footer to an elisp buffer in order to placate flycheck." + (interactive) + (let ((fname (if (buffer-file-name) + (file-name-nondirectory (buffer-file-name)) + (error "This buffer is not visiting a file")))) + (save-excursion + (goto-char (point-min)) + (insert ";;; " fname " --- Insert description here -*- lexical-binding: t -*-\n" + ";;; Commentary:\n" + ";;; Code:\n\n") + (goto-char (point-max)) + (insert ";;; " fname " ends here\n")))) + + +;; Make C-x C-e run 'eval-region if the region is active + +(defun sanityinc/eval-last-sexp-or-region (prefix) + "Eval region from BEG to END if active, otherwise the last sexp." + (interactive "P") + (if (and (mark) (use-region-p)) + (eval-region (min (point) (mark)) (max (point) (mark))) + (pp-eval-last-sexp prefix))) + +(global-set-key [remap eval-expression] 'pp-eval-expression) + +(with-eval-after-load 'lisp-mode + (define-key emacs-lisp-mode-map (kbd "C-x C-e") 'sanityinc/eval-last-sexp-or-region) + (define-key emacs-lisp-mode-map (kbd "C-c C-e") 'pp-eval-expression)) + +(when (maybe-require-package 'ipretty) + (add-hook 'after-init-hook 'ipretty-mode)) + + +(defun sanityinc/make-read-only (_expression out-buffer-name &rest _) + "Enable `view-mode' in the output buffer - if any - so it can be closed with `\"q\"." + (when (get-buffer out-buffer-name) + (with-current-buffer out-buffer-name + (view-mode 1)))) +(advice-add 'pp-display-expression :after 'sanityinc/make-read-only) + + + +(defun sanityinc/load-this-file () + "Load the current file or buffer. +The current directory is temporarily added to `load-path'. When +there is no current file, eval the current buffer." + (interactive) + (let ((load-path (cons default-directory load-path)) + (file (buffer-file-name))) + (if file + (progn + (save-some-buffers nil (apply-partially 'derived-mode-p 'emacs-lisp-mode)) + (load-file (buffer-file-name)) + (message "Loaded %s" file)) + (eval-buffer) + (message "Evaluated %s" (current-buffer))))) + +(with-eval-after-load 'lisp-mode + (define-key emacs-lisp-mode-map (kbd "C-c C-l") 'sanityinc/load-this-file)) + + + +(defun sanityinc/maybe-set-bundled-elisp-readonly () + "If this elisp appears to be part of Emacs, then disallow editing." + (when (and (buffer-file-name) + (string-match-p "\\.el\\.gz\\'" (buffer-file-name))) + (setq buffer-read-only t) + (view-mode 1))) + +(add-hook 'emacs-lisp-mode-hook 'sanityinc/maybe-set-bundled-elisp-readonly) + + +;; Use C-c C-z to toggle between elisp files and an ielm session +;; I might generalise this to ruby etc., or even just adopt the repl-toggle package. + +(defvar-local sanityinc/repl-original-buffer nil + "Buffer from which we jumped to this REPL.") + +(defvar sanityinc/repl-switch-function 'switch-to-buffer-other-window) + +(defun sanityinc/switch-to-ielm () + (interactive) + (let ((orig-buffer (current-buffer))) + (if (get-buffer "*ielm*") + (funcall sanityinc/repl-switch-function "*ielm*") + (ielm)) + (setq sanityinc/repl-original-buffer orig-buffer))) + +(defun sanityinc/repl-switch-back () + "Switch back to the buffer from which we reached this REPL." + (interactive) + (if sanityinc/repl-original-buffer + (funcall sanityinc/repl-switch-function sanityinc/repl-original-buffer) + (error "No original buffer"))) + +(with-eval-after-load 'elisp-mode + (define-key emacs-lisp-mode-map (kbd "C-c C-z") 'sanityinc/switch-to-ielm)) +(with-eval-after-load 'ielm + (define-key ielm-map (kbd "C-c C-z") 'sanityinc/repl-switch-back)) + + +;; Hippie-expand + +(defun set-up-hippie-expand-for-elisp () + "Locally set `hippie-expand' completion functions for use with Emacs Lisp." + (make-local-variable 'hippie-expand-try-functions-list) + (add-to-list 'hippie-expand-try-functions-list 'try-complete-lisp-symbol t) + (add-to-list 'hippie-expand-try-functions-list 'try-complete-lisp-symbol-partially t)) + + + +;; Automatic byte compilation + +(when (maybe-require-package 'auto-compile) + (setq auto-compile-delete-stray-dest nil) + (add-hook 'after-init-hook 'auto-compile-on-save-mode) + (add-hook 'after-init-hook 'auto-compile-on-load-mode)) + + +;; Load .el if newer than corresponding .elc + +(setq load-prefer-newer t) + + + +(require-package 'immortal-scratch) +(add-hook 'after-init-hook 'immortal-scratch-mode) + + +;;; Support byte-compilation in a sub-process, as +;;; required by highlight-cl + +(defun sanityinc/byte-compile-file-batch (filename) + "Byte-compile FILENAME in batch mode, ie. a clean sub-process." + (interactive "fFile to byte-compile in batch mode: ") + (let ((emacs (car command-line-args))) + (compile + (concat + emacs " " + (mapconcat + 'shell-quote-argument + (list "-Q" "-batch" "-f" "batch-byte-compile" filename) + " "))))) + + + +;; Enable desired features for all lisp modes + +(defun sanityinc/enable-check-parens-on-save () + "Run `check-parens' when the current buffer is saved." + (add-hook 'after-save-hook #'check-parens nil t)) + +(defvar sanityinc/lispy-modes-hook + '(enable-paredit-mode + sanityinc/enable-check-parens-on-save) + "Hook run in all Lisp modes.") + + +(when (maybe-require-package 'aggressive-indent) + (add-to-list 'sanityinc/lispy-modes-hook 'aggressive-indent-mode)) + +(defun sanityinc/lisp-setup () + "Enable features useful in any Lisp mode." + (run-hooks 'sanityinc/lispy-modes-hook)) + +(require 'derived) + +(dolist (mode '(emacs-lisp-mode ielm-mode lisp-mode inferior-lisp-mode lisp-interaction-mode)) + (add-hook (derived-mode-hook-name mode) 'sanityinc/lisp-setup)) + +(when (boundp 'eval-expression-minibuffer-setup-hook) + (add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)) + +(add-to-list 'auto-mode-alist '("\\.emacs-project\\'" . emacs-lisp-mode)) +(add-to-list 'auto-mode-alist '("archive-contents\\'" . emacs-lisp-mode)) + + + +;; Delete .elc files when reverting the .el from VC or magit + +;; When .el files are open, we can intercept when they are modified +;; by VC or magit in order to remove .elc files that are likely to +;; be out of sync. + +;; This is handy while actively working on elisp files, though +;; obviously it doesn't ensure that unopened files will also have +;; their .elc counterparts removed - VC hooks would be necessary for +;; that. + +(defvar sanityinc/vc-reverting nil + "Whether or not VC or Magit is currently reverting buffers.") + +(defun sanityinc/maybe-remove-elc (&rest _) + "If reverting from VC, delete any .elc file that will now be out of sync." + (when sanityinc/vc-reverting + (when (and (eq 'emacs-lisp-mode major-mode) + buffer-file-name + (string= "el" (file-name-extension buffer-file-name))) + (let ((elc (concat buffer-file-name "c"))) + (when (file-exists-p elc) + (message "Removing out-of-sync elc file %s" (file-name-nondirectory elc)) + (delete-file elc)))))) +(advice-add 'revert-buffer :after 'sanityinc/maybe-remove-elc) + +(defun sanityinc/reverting (orig &rest args) + (let ((sanityinc/vc-reverting t)) + (apply orig args))) +(advice-add 'magit-revert-buffers :around 'sanityinc/reverting) +(advice-add 'vc-revert-buffer-internal :around 'sanityinc/reverting) + + + +(require-package 'macrostep) + +(with-eval-after-load 'lisp-mode + (define-key emacs-lisp-mode-map (kbd "C-c x") 'macrostep-expand)) + + + +;; A quick way to jump to the definition of a function given its key binding +(global-set-key (kbd "C-h K") 'find-function-on-key) + + + +;; Extras for theme editing +(when (maybe-require-package 'rainbow-mode) + (defun sanityinc/enable-rainbow-mode-if-theme () + (when (and (buffer-file-name) (string-match-p "\\(color-theme-\\|-theme\\.el\\)" (buffer-file-name))) + (rainbow-mode))) + (add-hook 'emacs-lisp-mode-hook 'sanityinc/enable-rainbow-mode-if-theme) + (add-hook 'help-mode-hook 'rainbow-mode) + (with-eval-after-load 'rainbow-mode + (diminish 'rainbow-mode))) + + + +(when (maybe-require-package 'highlight-quoted) + (add-hook 'emacs-lisp-mode-hook 'highlight-quoted-mode)) + + +(when (maybe-require-package 'package-lint-flymake) + (add-hook 'emacs-lisp-mode-hook #'package-lint-flymake-setup)) + + + +;; ERT +(with-eval-after-load 'ert + (define-key ert-results-mode-map (kbd "g") 'ert-results-rerun-all-tests)) + + +;;(maybe-require-package 'cl-libify) + + +(maybe-require-package 'flycheck-relint) + + + +(maybe-require-package 'cask-mode) + +(provide 'init-lisp) +;;; init-lisp.el ends here diff --git a/lisp/init-local.el b/lisp/init-local.el new file mode 100644 index 0000000..3170c8f --- /dev/null +++ b/lisp/init-local.el @@ -0,0 +1,22 @@ +;;; Local Configuration --- This is a local config -*- lexical-bindings: t -*- +;;; Code: + +(set-frame-font "Iosevka Nerd Font-14" nil t) + + +;; Personal information +(setq user-full-name "Charlie Root") +(setq user-mail-address "charlie@charlieroot.dev") + +(setq make-backup-files nil) +(setq auto-save-default nil) +(setq create-lockfiles nil) + + +;; Org config stuff +(setq org-directory "~/Nextcloud/Org") +(setq org-agenda-files (list "inbox.org" "agenda.org")) + + + +(provide 'init-local) diff --git a/lisp/init-locales.el b/lisp/init-locales.el new file mode 100644 index 0000000..6e35194 --- /dev/null +++ b/lisp/init-locales.el @@ -0,0 +1,26 @@ +;;; init-locales.el --- Configure default locale -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(defun sanityinc/locale-var-encoding (v) + "Return the encoding portion of the locale string V, or nil if missing." + (when v + (save-match-data + (let ((case-fold-search t)) + (when (string-match "\\.\\([^.]*\\)\\'" v) + (intern (downcase (match-string 1 v)))))))) + +(dolist (varname '("LC_ALL" "LANG" "LC_CTYPE")) + (let ((encoding (sanityinc/locale-var-encoding (getenv varname)))) + (unless (memq encoding '(nil utf8 utf-8)) + (message "Warning: non-UTF8 encoding in environment variable %s may cause interop problems with this Emacs configuration." varname)))) + +(when (fboundp 'set-charset-priority) + (set-charset-priority 'unicode)) +(prefer-coding-system 'utf-8) +(setq locale-coding-system 'utf-8) +(unless (eq system-type 'windows-nt) + (set-selection-coding-system 'utf-8)) + +(provide 'init-locales) +;;; init-locales.el ends here diff --git a/lisp/init-look.el b/lisp/init-look.el new file mode 100644 index 0000000..052b75d --- /dev/null +++ b/lisp/init-look.el @@ -0,0 +1,36 @@ +;;; Line spacing, can be 0 for code and 1 or 2 for text +;;; ------------------------------------------------------------------- +(setq-default line-spacing 0) +(setq x-underline-at-descent-line t) +(setq widget-image-enable nil) +;;; ------------------------------------------------------------------- + +;;; Line cursor and no blink +;;; ------------------------------------------------------------------- +(set-default 'cursor-type '(bar . 1)) +(blink-cursor-mode 0) +;;; ------------------------------------------------------------------- +;;; Highlight current line +;;; ------------------------------------------------------------------- +(global-hl-line-mode +1) + +;;; No sound +;;; ------------------------------------------------------------------- +(setq visible-bell t) +(setq ring-bell-function 'ignore) +;;; ------------------------------------------------------------------- + + +;;; No Tooltips +;;; ------------------------------------------------------------------- +(tooltip-mode 0) +;;; ------------------------------------------------------------------- + + +;;; Paren mode is part of the theme +;;; ------------------------------------------------------------------- +(show-paren-mode t) +;;; ------------------------------------------------------------------- + + +(provide 'init-look) diff --git a/lisp/init-meow.el b/lisp/init-meow.el new file mode 100644 index 0000000..ec2d19f --- /dev/null +++ b/lisp/init-meow.el @@ -0,0 +1,121 @@ +(require 'meow) + + +(defun meow-setup () + (setq meow-cheatsheet-physical-layout meow-cheatsheet-physical-layout-iso) + (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwertz) + + (meow-thing-register 'angle + '(pair (";") (":")) + '(pair (";") (":"))) + + (setq meow-char-thing-table + '((?f . round) + (?d . square) + (?s . curly) + (?a . angle) + (?r . string) + (?p . paragraph) + (?l . line) + (?b . buffer))) + + (meow-leader-define-key + ;; Use SPC (0-9) for digit arguments. + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument) + '("-" . meow-keypad-describe-key) + '("_" . meow-cheatsheet)) + + (meow-normal-define-key + ;; expansion + '("0" . meow-expand-0) + '("1" . meow-expand-1) + '("2" . meow-expand-2) + '("3" . meow-expand-3) + '("4" . meow-expand-4) + '("5" . meow-expand-5) + '("6" . meow-expand-6) + '("7" . meow-expand-7) + '("8" . meow-expand-8) + '("9" . meow-expand-9) + '("ä" . meow-reverse) + + ;; movement + '("h" . meow-left) + '("j" . meow-next) + '("k" . meow-prev) + '("l" . meow-right) + + + ;; expansion + '("H" . meow-left-expand) + '("J" . meow-next-expand) + '("K" . meow-prev-expand) + '("L" . meow-right-expand) + + '("/" . meow-visit) + '("-" . meow-search) + + '("w" . meow-next-word) + '("W" . meow-next-symbol) + '("b" . meow-back-word) + '("B" . meow-back-symbol) + + '("z" . meow-mark-word) + '("Z" . meow-mark-symbol) + '("x" . meow-line) + '("X" . meow-goto-line) + '("m" . meow-block) + '("q" . meow-join) + '("g" . meow-grab) + '("G" . meow-pop-grab) + '("m" . meow-swap-grab) + '("M" . meow-sync-grab) + '("v" . meow-cancel-selection) + '("V" . meow-pop-selection) + + '("f" . meow-till) + '("F" . meow-find) + + '("," . meow-beginning-of-thing) + '("." . meow-end-of-thing) + '(";" . meow-inner-of-thing) + '(":" . meow-bounds-of-thing) + + ;; editing + '("D" . meow-kill) + '("c" . meow-change) + '("d" . meow-delete) + '("C" . meow-save) + '("p" . meow-yank) + '("P" . meow-yank-pop) + + '("i" . meow-insert) + '("O" . meow-open-above) + '("a" . meow-append) + '("o" . meow-open-below) + + '("u" . undo-only) + '("U" . undo-redo) + + '("n" . open-line) + '("N" . split-line) + + '("ü" . indent-rigidly-left-to-tab-stop) + '("+" . indent-rigidly-right-to-tab-stop) + + ;; ignore escape + '("" . ignore))) + +(with-eval-after-load 'meow + (meow-setup) + (meow-global-mode 1)) +(provide 'init-meow) diff --git a/lisp/init-meow.el~ b/lisp/init-meow.el~ new file mode 100644 index 0000000..1a23dd7 --- /dev/null +++ b/lisp/init-meow.el~ @@ -0,0 +1,118 @@ +(require-package 'meow) +(defun meow-setup () + (setq meow-cheatsheet-physical-layout meow-cheatsheet-physical-layout-iso) + (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwertz) + + (meow-thing-register 'angle + '(pair (";") (":")) + '(pair (";") (":"))) + + (setq meow-char-thing-table + '((?f . round) + (?d . square) + (?s . curly) + (?a . angle) + (?r . string) + (?v . paragraph) + (?c . line) + (?x . buffer))) + + (meow-leader-define-key + ;; Use SPC (0-9) for digit arguments. + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument) + '("-" . meow-keypad-describe-key) + '("_" . meow-cheatsheet)) + + (meow-normal-define-key + ;; expansion + '("0" . meow-expand-0) + '("1" . meow-expand-1) + '("2" . meow-expand-2) + '("3" . meow-expand-3) + '("4" . meow-expand-4) + '("5" . meow-expand-5) + '("6" . meow-expand-6) + '("7" . meow-expand-7) + '("8" . meow-expand-8) + '("9" . meow-expand-9) + '("ä" . meow-reverse) + + ;; movement + '("i" . meow-prev) + '("k" . meow-next) + '("j" . meow-left) + '("l" . meow-right) + + '("z" . meow-search) + '("-" . meow-visit) + + ;; expansion + '("I" . meow-prev-expand) + '("K" . meow-next-expand) + '("J" . meow-left-expand) + '("L" . meow-right-expand) + + '("u" . meow-back-word) + '("U" . meow-back-symbol) + '("o" . meow-next-word) + '("O" . meow-next-symbol) + + '("a" . meow-mark-word) + '("A" . meow-mark-symbol) + '("s" . meow-line) + '("S" . meow-goto-line) + '("w" . meow-block) + '("q" . meow-join) + '("g" . meow-grab) + '("G" . meow-pop-grab) + '("m" . meow-swap-grab) + '("M" . meow-sync-grab) + '("p" . meow-cancel-selection) + '("P" . meow-pop-selection) + + '("x" . meow-till) + '("y" . meow-find) + + '("," . meow-beginning-of-thing) + '("." . meow-end-of-thing) + '(";" . meow-inner-of-thing) + '(":" . meow-bounds-of-thing) + + ;; editing + '("d" . meow-kill) + '("f" . meow-change) + '("t" . meow-delete) + '("c" . meow-save) + '("v" . meow-yank) + '("V" . meow-yank-pop) + + '("e" . meow-insert) + '("E" . meow-open-above) + '("r" . meow-append) + '("R" . meow-open-below) + + '("h" . undo-only) + '("H" . undo-redo) + + '("b" . open-line) + '("B" . split-line) + + '("ü" . indent-rigidly-left-to-tab-stop) + '("+" . indent-rigidly-right-to-tab-stop) + + ;; ignore escape + '("" . ignore))) + +(meow-setup) +(meow-global-mode 1) + +(provide 'init-meow) diff --git a/lisp/init-minibuffer.el b/lisp/init-minibuffer.el new file mode 100644 index 0000000..9ea7245 --- /dev/null +++ b/lisp/init-minibuffer.el @@ -0,0 +1,56 @@ +;;; init-minibuffer.el --- Config for minibuffer completion -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(when (maybe-require-package 'vertico) + (add-hook 'after-init-hook 'vertico-mode) + + (when (maybe-require-package 'embark) + (with-eval-after-load 'vertico + (define-key vertico-map (kbd "C-c C-o") 'embark-export) + (define-key vertico-map (kbd "C-c C-c") 'embark-act))) + + (when (maybe-require-package 'consult) + (defmacro sanityinc/no-consult-preview (&rest cmds) + `(with-eval-after-load 'consult + (consult-customize ,@cmds :preview-key "M-P"))) + + (sanityinc/no-consult-preview + consult-ripgrep + consult-git-grep consult-grep + consult-bookmark consult-recent-file consult-xref + consult--source-recent-file consult--source-project-recent-file consult--source-bookmark) + + (when (and (executable-find "rg")) + (defun sanityinc/consult-ripgrep-at-point (&optional dir initial) + (interactive (list prefix-arg (when-let ((s (symbol-at-point))) + (symbol-name s)))) + (consult-ripgrep dir initial)) + (sanityinc/no-consult-preview sanityinc/consult-ripgrep-at-point) + (global-set-key (kbd "M-?") 'sanityinc/consult-ripgrep-at-point)) + + (global-set-key [remap switch-to-buffer] 'consult-buffer) + (global-set-key [remap switch-to-buffer-other-window] 'consult-buffer-other-window) + (global-set-key [remap switch-to-buffer-other-frame] 'consult-buffer-other-frame) + (global-set-key [remap goto-line] 'consult-goto-line) + + + + (when (maybe-require-package 'embark-consult) + (with-eval-after-load 'embark + (require 'embark-consult) + (add-hook 'embark-collect-mode-hook 'embark-consult-preview-minor-mode))))) + +;; (when (maybe-require-package 'vertico-posframe) +;; (add-hook 'after-init-hook 'vertico-posframe-mode) +;; (setq vertico-posframe-poshandler #'posframe-poshandler-frame-bottom-right-corner) +;; (setq vertico-posframe-border-width 4) +;; ) + +(when (maybe-require-package 'marginalia) + (add-hook 'after-init-hook 'marginalia-mode)) + + +(provide 'init-minibuffer) +;;; init-minibuffer.el ends here diff --git a/lisp/init-modeline.el b/lisp/init-modeline.el new file mode 100644 index 0000000..7f6d4cc --- /dev/null +++ b/lisp/init-modeline.el @@ -0,0 +1,58 @@ +;;; init-modeline.el --- dooom-modeline configuration +;;; Commentary: +;;; Code: +(setq-default mode-line-format + (list + + ;; the buffer name; the file name as a tool tip + '(:eval (propertize " %b " + 'face + (let ((face (buffer-modified-p))) + (if face 'font-lock-warning-face + 'font-lock-type-face)) + 'help-echo (buffer-file-name))) + + ;; line and column + " (" ;; '%02' to set to 2 chars at least; prevents flickering + (propertize "%02l" 'face 'font-lock-keyword-face) "," + (propertize "%02c" 'face 'font-lock-keyword-face) + ") " + + ;; relative position, size of file + " [" + (propertize "%p" 'face 'font-lock-constant-face) ;; % above top + "/" + (propertize "%I" 'face 'font-lock-constant-face) ;; size + "] " + + ;; spaces to align right + '(:eval (propertize + " " 'display + `((space :align-to (- (+ right right-fringe right-margin) + ,(+ 3 (string-width (if (listp mode-name) (car mode-name) mode-name)))))))) + + ;(propertize org-mode-line-string 'face '(:foreground "#5DD8FF")) + + '(eval (propertize + `((let ((backend (vc-backend buffer-file-name))) + (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2))))) + ) + )) + +(set-face-attribute 'mode-line nil + :background "#353644" + :foreground "white" + :box '(:line-width 8 :color "#353644") + :overline nil + :underline nil) + +(set-face-attribute 'mode-line-inactive nil + :background "#565063" + :foreground "white" + :box '(:line-width 8 :color "#565063") + :overline nil + :underline nil) + + +(provide 'init-modeline) +;;; end of init-doom-modeline.el diff --git a/lisp/init-org.el b/lisp/init-org.el new file mode 100644 index 0000000..5395b10 --- /dev/null +++ b/lisp/init-org.el @@ -0,0 +1,381 @@ +;;; init-org.el --- Org-mode config -*- lexical-binding: t -*- +;;; Commentary: + +;; Among settings for many aspects of `org-mode', this code includes +;; an opinionated setup for the Getting Things Done (GTD) system based +;; around the Org Agenda. I have an "inbox.org" file with a header +;; including + +;; #+CATEGORY: Inbox +;; #+FILETAGS: INBOX + +;; and then set this file as `org-default-notes-file'. Captured org +;; items will then go into this file with the file-level tag, and can +;; be refiled to other locations as necessary. + +;; Those other locations are generally other org files, which should +;; be added to `org-agenda-files-list' (along with "inbox.org" org). +;; With that done, there's then an agenda view, accessible via the +;; `org-agenda' command, which gives a convenient overview. +;; `org-todo-keywords' is customised here to provide corresponding +;; TODO states, which should make sense to GTD adherents. + +;;; Code: + +(maybe-require-package 'org-cliplink) + +(define-key global-map (kbd "C-c l") 'org-store-link) +(define-key global-map (kbd "C-c a") 'org-agenda) + +(defvar sanityinc/org-global-prefix-map (make-sparse-keymap) + "A keymap for handy global access to org helpers, particularly clocking.") + +(define-key sanityinc/org-global-prefix-map (kbd "j") 'org-clock-goto) +(define-key sanityinc/org-global-prefix-map (kbd "l") 'org-clock-in-last) +(define-key sanityinc/org-global-prefix-map (kbd "i") 'org-clock-in) +(define-key sanityinc/org-global-prefix-map (kbd "o") 'org-clock-out) +(define-key global-map (kbd "C-c o") sanityinc/org-global-prefix-map) + + +;; Various preferences +(setq org-log-done t + org-edit-timestamp-down-means-later t + org-hide-emphasis-markers t + org-catch-invisible-edits 'show + org-export-coding-system 'utf-8 + org-fast-tag-selection-single-key 'expert + org-html-validation-link nil + org-export-kill-product-buffer-when-displayed t + org-tags-column 80) + +;; Lots of stuff from http://doc.norang.ca/org-mode.html + +;; Re-align tags when window shape changes +(with-eval-after-load 'org-agenda + (add-hook 'org-agenda-mode-hook + (lambda () (add-hook 'window-configuration-change-hook 'org-agenda-align-tags nil t)))) + +(add-hook 'org-mode-hook 'visual-line-mode) + + +(maybe-require-package 'writeroom-mode) + +(define-minor-mode prose-mode + "Set up a buffer for prose editing. +This enables or modifies a number of settings so that the +experience of editing prose is a little more like that of a +typical word processor." + :init-value nil :lighter " Prose" :keymap nil + (if prose-mode + (progn + (when (fboundp 'writeroom-mode) + (writeroom-mode 1)) + (setq truncate-lines nil) + (setq word-wrap t) + (setq cursor-type 'bar) + (when (eq major-mode 'org) + (kill-local-variable 'buffer-face-mode-face)) + (buffer-face-mode 1) + ;;(delete-selection-mode 1) + (setq-local blink-cursor-interval 0.6) + (setq-local show-trailing-whitespace nil) + (setq-local line-spacing 0.2) + (setq-local electric-pair-mode nil) + (ignore-errors (flyspell-mode 1)) + (visual-line-mode 1)) + (kill-local-variable 'truncate-lines) + (kill-local-variable 'word-wrap) + (kill-local-variable 'cursor-type) + (kill-local-variable 'blink-cursor-interval) + (kill-local-variable 'show-trailing-whitespace) + (kill-local-variable 'line-spacing) + (kill-local-variable 'electric-pair-mode) + (buffer-face-mode -1) + ;; (delete-selection-mode -1) + (flyspell-mode -1) + (visual-line-mode -1) + (when (fboundp 'writeroom-mode) + (writeroom-mode 0)))) + +;;(add-hook 'org-mode-hook 'buffer-face-mode) + + +(setq org-support-shift-select t) + +;;; Capturing + +(global-set-key (kbd "C-c c") 'org-capture) + +(setq org-capture-templates + `(("t" "todo" entry (file "") ; "" => `org-default-notes-file' + "* NEXT %?\n%U\n" :clock-resume t) + ("n" "note" entry (file "") + "* %? :NOTE:\n%U\n%a\n" :clock-resume t) + ("i" "Inbox" entry (file "inbox.org") + ,(concat "* TODO %?\n" + "/Entered on/ %U")) + )) + + + +;;; Refiling + +(setq org-refile-use-cache nil) + +;; Targets include this file and any file contributing to the agenda - up to 5 levels deep +(setq org-refile-targets '((nil :maxlevel . 5) (org-agenda-files :maxlevel . 5))) + +(with-eval-after-load 'org-agenda + (add-to-list 'org-agenda-after-show-hook 'org-show-entry)) + +(advice-add 'org-refile :after (lambda (&rest _) (org-save-all-org-buffers))) + +;; Exclude DONE state tasks from refile targets +(defun sanityinc/verify-refile-target () + "Exclude todo keywords with a done state from refile targets." + (not (member (nth 2 (org-heading-components)) org-done-keywords))) +(setq org-refile-target-verify-function 'sanityinc/verify-refile-target) + +(defun sanityinc/org-refile-anywhere (&optional goto default-buffer rfloc msg) + "A version of `org-refile' which allows refiling to any subtree." + (interactive "P") + (let ((org-refile-target-verify-function)) + (org-refile goto default-buffer rfloc msg))) + +(defun sanityinc/org-agenda-refile-anywhere (&optional goto rfloc no-update) + "A version of `org-agenda-refile' which allows refiling to any subtree." + (interactive "P") + (let ((org-refile-target-verify-function)) + (org-agenda-refile goto rfloc no-update))) + +;; Targets start with the file name - allows creating level 1 tasks +;;(setq org-refile-use-outline-path (quote file)) +(setq org-refile-use-outline-path t) +(setq org-outline-path-complete-in-steps nil) + +;; Allow refile to create parent tasks with confirmation +(setq org-refile-allow-creating-parent-nodes 'confirm) + + +;;; To-do settings + +(setq org-todo-keywords + (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!/!)") + (sequence "PROJECT(p)" "|" "DONE(d!/!)" "CANCELLED(c@/!)") + (sequence "WAITING(w@/!)" "DELEGATED(e!)" "HOLD(h)" "|" "CANCELLED(c@/!)"))) + org-todo-repeat-to-state "NEXT") + +(setq org-todo-keyword-faces + (quote (("NEXT" :inherit warning) + ("PROJECT" :inherit font-lock-string-face)))) + + + +;;; Agenda views + +(setq-default org-agenda-clockreport-parameter-plist '(:link t :maxlevel 3)) + + +(let ((active-project-match "-INBOX/PROJECT")) + + (setq org-stuck-projects + `(,active-project-match ("NEXT"))) + + (setq org-agenda-compact-blocks t + org-agenda-sticky t + org-agenda-start-on-weekday nil + org-agenda-span 'day + org-agenda-include-diary nil + org-agenda-hide-tags-regexp "." + org-agenda-sorting-strategy + '((agenda habit-down time-up user-defined-up effort-up category-keep) + (todo category-up effort-up) + (tags category-up effort-up) + (search category-up)) + org-agenda-window-setup 'current-window + org-agenda-custom-commands + `(("N" "Notes" tags "NOTE" + ((org-agenda-overriding-header "Notes") + (org-tags-match-list-sublevels t))) + ("g" "GTD" + ((agenda "" nil) + (tags "INBOX" + ((org-agenda-overriding-header "Inbox") + (org-tags-match-list-sublevels nil))) + (stuck "" + ((org-agenda-overriding-header "Stuck Projects") + (org-agenda-tags-todo-honor-ignore-options t) + (org-tags-match-list-sublevels t) + (org-agenda-todo-ignore-scheduled 'future))) + (tags-todo "-INBOX" + ((org-agenda-overriding-header "Next Actions") + (org-agenda-tags-todo-honor-ignore-options t) + (org-agenda-todo-ignore-scheduled 'future) + (org-agenda-skip-function + '(lambda () + (or (org-agenda-skip-subtree-if 'todo '("HOLD" "WAITING")) + (org-agenda-skip-entry-if 'nottodo '("NEXT"))))) + (org-tags-match-list-sublevels t) + (org-agenda-sorting-strategy + '(todo-state-down effort-up category-keep)))) + (tags-todo ,active-project-match + ((org-agenda-overriding-header "Projects") + (org-tags-match-list-sublevels t) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-INBOX/-NEXT" + ((org-agenda-overriding-header "Orphaned Tasks") + (org-agenda-tags-todo-honor-ignore-options t) + (org-agenda-todo-ignore-scheduled 'future) + (org-agenda-skip-function + '(lambda () + (or (org-agenda-skip-subtree-if 'todo '("PROJECT" "HOLD" "WAITING" "DELEGATED")) + (org-agenda-skip-subtree-if 'nottododo '("TODO"))))) + (org-tags-match-list-sublevels t) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "/WAITING" + ((org-agenda-overriding-header "Waiting") + (org-agenda-tags-todo-honor-ignore-options t) + (org-agenda-todo-ignore-scheduled 'future) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "/DELEGATED" + ((org-agenda-overriding-header "Delegated") + (org-agenda-tags-todo-honor-ignore-options t) + (org-agenda-todo-ignore-scheduled 'future) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-INBOX" + ((org-agenda-overriding-header "On Hold") + (org-agenda-skip-function + '(lambda () + (or (org-agenda-skip-subtree-if 'todo '("WAITING")) + (org-agenda-skip-entry-if 'nottodo '("HOLD"))))) + (org-tags-match-list-sublevels nil) + (org-agenda-sorting-strategy + '(category-keep)))) + ;; (tags-todo "-NEXT" + ;; ((org-agenda-overriding-header "All other TODOs") + ;; (org-match-list-sublevels t))) + ))))) + + +(add-hook 'org-agenda-mode-hook 'hl-line-mode) + + +;;; Org clock + +;; Save the running clock and all clock history when exiting Emacs, load it on startup +(with-eval-after-load 'org + (org-clock-persistence-insinuate)) +(setq org-clock-persist t) +(setq org-clock-in-resume t) + +;; Save clock data and notes in the LOGBOOK drawer +(setq org-clock-into-drawer t) +;; Save state changes in the LOGBOOK drawer +(setq org-log-into-drawer t) +;; Removes clocked tasks with 0:00 duration +(setq org-clock-out-remove-zero-time-clocks t) + +;; Show clock sums as hours and minutes, not "n days" etc. +(setq org-time-clocksum-format + '(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t)) + + + +;;; Show the clocked-in task - if any - in the header line +(defun sanityinc/show-org-clock-in-header-line () + (setq-default header-line-format '((" " org-mode-line-string " ")))) + +(defun sanityinc/hide-org-clock-from-header-line () + (setq-default header-line-format nil)) + +(add-hook 'org-clock-in-hook 'sanityinc/show-org-clock-in-header-line) +(add-hook 'org-clock-out-hook 'sanityinc/hide-org-clock-from-header-line) +(add-hook 'org-clock-cancel-hook 'sanityinc/hide-org-clock-from-header-line) + +(with-eval-after-load 'org-clock + (define-key org-clock-mode-line-map [header-line mouse-2] 'org-clock-goto) + (define-key org-clock-mode-line-map [header-line mouse-1] 'org-clock-menu)) + + + + +;; TODO: warn about inconsistent items, e.g. TODO inside non-PROJECT +;; TODO: nested projects! + + + +;;; Archiving + +(setq org-archive-mark-done nil) +(setq org-archive-location "%s_archive::* Archive") + + + + + +(require-package 'org-pomodoro) +(setq org-pomodoro-keep-killed-pomodoro-time t) +(with-eval-after-load 'org-agenda + (define-key org-agenda-mode-map (kbd "P") 'org-pomodoro)) + + +;; ;; Show iCal calendars in the org agenda +;; (when (and *is-a-mac* (require 'org-mac-iCal nil t)) +;; (setq org-agenda-include-diary t +;; org-agenda-custom-commands +;; '(("I" "Import diary from iCal" agenda "" +;; ((org-agenda-mode-hook #'org-mac-iCal))))) + +;; (add-hook 'org-agenda-cleanup-fancy-diary-hook +;; (lambda () +;; (goto-char (point-min)) +;; (save-excursion +;; (while (re-search-forward "^[a-z]" nil t) +;; (goto-char (match-beginning 0)) +;; (insert "0:00-24:00 "))) +;; (while (re-search-forward "^ [a-z]" nil t) +;; (goto-char (match-beginning 0)) +;; (save-excursion +;; (re-search-backward "^[0-9]+:[0-9]+-[0-9]+:[0-9]+ " nil t)) +;; (insert (match-string 0)))))) + +(with-eval-after-load 'org + (when (maybe-require-package 'org-bullets) + (add-hook 'org-mode 'org-bullets-mode))) + +(with-eval-after-load 'org + (define-key org-mode-map (kbd "C-M-") 'org-up-element) + ) + +(with-eval-after-load 'org + (org-babel-do-load-languages + 'org-babel-load-languages + (seq-filter + (lambda (pair) + (locate-library (concat "ob-" (symbol-name (car pair))))) + '((R . t) + (ditaa . t) + (dot . t) + (emacs-lisp . t) + (gnuplot . t) + (haskell . nil) + (latex . t) + (ledger . t) + (ocaml . nil) + (octave . t) + (plantuml . t) + (python . t) + (ruby . t) + (screen . nil) + (sh . t) ;; obsolete + (shell . t) + (sql . t) + (sqlite . t))))) + + +(provide 'init-org) +;;; init-org.el ends here diff --git a/lisp/init-paredit.el b/lisp/init-paredit.el new file mode 100644 index 0000000..4c2712b --- /dev/null +++ b/lisp/init-paredit.el @@ -0,0 +1,59 @@ +;;; init-paredit.el --- Configure paredit structured editing -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(require-package 'paredit) + + +(defun sanityinc/maybe-map-paredit-newline () + (unless (or (derived-mode-p 'inferior-emacs-lisp-mode 'cider-repl-mode) + (minibufferp)) + (local-set-key (kbd "RET") 'paredit-newline))) + +(add-hook 'paredit-mode-hook 'sanityinc/maybe-map-paredit-newline) + +(with-eval-after-load 'paredit + (diminish 'paredit-mode " Par") + ;; Suppress certain paredit keybindings to avoid clashes, including + ;; my global binding of M-? + (dolist (binding '("RET" "C-" "C-" "C-M-" "C-M-" "M-s" "M-?")) + (define-key paredit-mode-map (read-kbd-macro binding) nil)) + (define-key paredit-mode-map (kbd "M-") 'paredit-splice-sexp-killing-backward)) + + + +;; Use paredit in the minibuffer +;; TODO: break out into separate package +;; http://emacsredux.com/blog/2013/04/18/evaluate-emacs-lisp-in-the-minibuffer/ +(add-hook 'minibuffer-setup-hook 'sanityinc/conditionally-enable-paredit-mode) + +(defvar paredit-minibuffer-commands '(eval-expression + pp-eval-expression + eval-expression-with-eldoc + ibuffer-do-eval + ibuffer-do-view-and-eval) + "Interactive commands for which paredit should be enabled in the minibuffer.") + +(defun sanityinc/conditionally-enable-paredit-mode () + "Enable paredit during lisp-related minibuffer commands." + (when (memq this-command paredit-minibuffer-commands) + (enable-paredit-mode))) + +(add-hook 'sanityinc/lispy-modes-hook 'enable-paredit-mode) + +(when (maybe-require-package 'puni) + ;;(add-hook 'prog-mode-hook 'puni-mode) + (add-hook 'sanityinc/lispy-modes-hook (lambda () (puni-mode -1))) + (with-eval-after-load 'puni + (define-key puni-mode-map (kbd "M-(") 'puni-wrap-round) + (define-key puni-mode-map (kbd "C-(") 'puni-slurp-backward) + (define-key puni-mode-map (kbd "C-)") 'puni-slurp-forward) + (define-key puni-mode-map (kbd "C-}") 'puni-barf-forward) + (define-key puni-mode-map (kbd "C-{") 'puni-barf-backward) + (define-key puni-mode-map (kbd "M-") 'puni-splice-killing-backward) + (define-key puni-mode-map (kbd "C-w") nil))) + + + +(provide 'init-paredit) +;;; init-paredit.el ends here diff --git a/lisp/init-projectile.el b/lisp/init-projectile.el new file mode 100644 index 0000000..61c8a9d --- /dev/null +++ b/lisp/init-projectile.el @@ -0,0 +1,21 @@ +;;; init-projectile.el --- Use Projectile for navigation within projects -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(when (maybe-require-package 'projectile) + (add-hook 'after-init-hook 'projectile-mode) + + ;; Shorter modeline + (setq-default projectile-mode-line-prefix " Proj") + + (when (executable-find "rg") + (setq-default projectile-generic-command "rg --files --hidden -0")) + + (with-eval-after-load 'projectile + (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)) + + (maybe-require-package 'ibuffer-projectile)) + + +(provide 'init-projectile) +;;; init-projectile.el ends here diff --git a/lisp/init-recentf.el b/lisp/init-recentf.el new file mode 100644 index 0000000..983fc89 --- /dev/null +++ b/lisp/init-recentf.el @@ -0,0 +1,12 @@ +;;; init-recentf.el --- Settings for tracking recent files -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(add-hook 'after-init-hook 'recentf-mode) +(setq-default + recentf-max-saved-items 1000 + recentf-exclude `("/tmp/" "/ssh:" ,(concat package-user-dir "/.*-autoloads\\.el\\'"))) + + +(provide 'init-recentf) +;;; init-recentf.el ends here diff --git a/lisp/init-spelling.el b/lisp/init-spelling.el new file mode 100644 index 0000000..6e11ad0 --- /dev/null +++ b/lisp/init-spelling.el @@ -0,0 +1,16 @@ +;;; init-spelling.el --- Spell check settings -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(require 'ispell) + +(when (executable-find ispell-program-name) + ;; Add spell-checking in comments for all programming language modes + (add-hook 'prog-mode-hook 'flyspell-prog-mode) + + (with-eval-after-load 'flyspell + (define-key flyspell-mode-map (kbd "C-;") nil) + (add-to-list 'flyspell-prog-text-faces 'nxml-text-face))) + +(provide 'init-spelling) +;;; init-spelling.el ends here diff --git a/lisp/init-terminal.el b/lisp/init-terminal.el new file mode 100644 index 0000000..2643af5 --- /dev/null +++ b/lisp/init-terminal.el @@ -0,0 +1,8 @@ +(require-package 'vterm) +(require-package 'vterm-toggle) + + +(setq shell-file-name "fish") +(setq vterm-max-scrollback 5000) + +(provide 'init-terminal) diff --git a/lisp/init-themes.el b/lisp/init-themes.el new file mode 100644 index 0000000..b91148b --- /dev/null +++ b/lisp/init-themes.el @@ -0,0 +1,46 @@ +;;; init-themes.el --- Defaults for themes -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(require-package 'catppuccin-theme) + +;; Don't prompt to confirm theme safety. This avoids problems with +;; first-time startup on Emacs > 26.3. +(setq custom-safe-themes t) + +;; If you don't customize it, this is the theme you get. +(setq-default custom-enabled-themes '(catppuccin)) + + + + + +;; Toggle between light and dark + +(defun light () + "Activate a light color theme." + (interactive) + (setq custom-enabled-themes '(modus-operandi)) + (reapply-themes)) + +(defun dark () + "Activate a dark color theme." + (interactive) + (setq custom-enabled-themes '(modus-vivendi)) + (reapply-themes)) + + +(when (maybe-require-package 'dimmer) + (setq-default dimmer-fraction 0.15) + (setq dimmer-buffer-exclusion-regexps '(" \\*\\(LV\\|transient\\)\\*" + "^ \\*.*posframe.*buffer.*\\*$" + "^\\*Minibuf-[0-9]+\\*" + "^.\\*which-key\\*$" + "^.\\*Echo.*\\*")) + (add-hook 'after-init-hook 'dimmer-mode) + (with-eval-after-load 'dimmer + (advice-add 'frame-set-background-mode :after (lambda (&rest args) (dimmer-process-all)))) + ) + +(provide 'init-themes) +;;; init-themes.el ends here diff --git a/lisp/init-treesitter.el b/lisp/init-treesitter.el new file mode 100644 index 0000000..04c607a --- /dev/null +++ b/lisp/init-treesitter.el @@ -0,0 +1,77 @@ +;;; init-treesitter.el --- Enable Treesitter-based major modes -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +;; You can download per-architecture pre-compiled release from +;; https://github.com/emacs-tree-sitter/tree-sitter-langs Rename +;; contained grammars to add prefix "libtree-sitter-", place in +;; ~/.emacs.d/tree-sitter. +;; +;; Nix users can pre-install all grammars alongside their Emacs, see +;; https://github.com/nix-community/emacs-overlay/issues/341 +;; +;; Note that grammar files from different sources can be differently +;; named and configured, so there could be different results. Some +;; common remappings are included below. + + +;;; Enable built-in and pre-installed TS modes if the grammars are available + +(defun sanityinc/auto-configure-treesitter () + "Find and configure installed grammars, remap to matching -ts-modes if present. +Return a list of languages seen along the way." + (let ((grammar-name-to-emacs-lang '(("c-sharp" . "csharp") + ("cpp" . "c++") + ("gomod" . "go-mod") + ("javascript" . "js"))) + seen-grammars) + (dolist (dir (cons (expand-file-name "tree-sitter" user-emacs-directory) + treesit-extra-load-path)) + (when (file-directory-p dir) + (dolist (file (directory-files dir)) + (let ((fname (file-name-sans-extension (file-name-nondirectory file)))) + (when (string-match "libtree-sitter-\\(.*\\)" fname) + (let* ((file-lang (match-string 1 fname)) + (emacs-lang (or (cdr (assoc-string file-lang grammar-name-to-emacs-lang)) file-lang))) + ;; Override library if its filename doesn't match the Emacs name + (unless (or (memq (intern emacs-lang) seen-grammars) + (string-equal file-lang emacs-lang)) + (let ((libname (concat "tree_sitter_" (replace-regexp-in-string "-" "_" file-lang)))) + (add-to-list 'treesit-load-name-override-list + (list (intern emacs-lang) fname libname)))) + ;; If there's a corresponding -ts mode, remap the standard mode to it + (let ((ts-mode-name (intern (concat emacs-lang "-ts-mode"))) + (regular-mode-name (intern (concat emacs-lang "-mode")))) + (when (fboundp ts-mode-name) + (message "init-treesitter: using %s in place of %s" ts-mode-name regular-mode-name) + (add-to-list 'major-mode-remap-alist + (cons regular-mode-name ts-mode-name)))) + ;; Remember we saw this language so we don't squash its config when we + ;; find another lib later in the treesit load path + (push (intern emacs-lang) seen-grammars))))))) + seen-grammars)) + +(sanityinc/auto-configure-treesitter) + + +;;; Support remapping of additional libraries + +(defun sanityinc/remap-ts-mode (non-ts-mode ts-mode grammar) + "Explicitly remap NON-TS-MODE to TS-MODE if GRAMMAR is available." + (when (and (fboundp 'treesit-ready-p) + (treesit-ready-p grammar t) + (fboundp ts-mode)) + (add-to-list 'major-mode-remap-alist (cons non-ts-mode ts-mode)))) + +;; When there's js-ts-mode, we also prefer it to js2-mode +(sanityinc/remap-ts-mode 'js2-mode 'js-ts-mode 'javascript) +(sanityinc/remap-ts-mode 'clojurescript-mode 'clojurescript-ts-mode 'clojure) + + +;; Default +(setq treesit-font-lock-level 4) + + + +(provide 'init-treesitter) +;;; init-treesitter.el ends here diff --git a/lisp/init-uniquify.el b/lisp/init-uniquify.el new file mode 100644 index 0000000..eb528e0 --- /dev/null +++ b/lisp/init-uniquify.el @@ -0,0 +1,15 @@ +;;; init-uniquify.el --- Configure uniquification of buffer names -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +;; Nicer naming of buffers for files with identical names +(require 'uniquify) + +(setq uniquify-buffer-name-style 'reverse) +(setq uniquify-separator " • ") +(setq uniquify-after-kill-buffer-p t) +(setq uniquify-ignore-buffers-re "^\\*") + + +(provide 'init-uniquify) +;;; init-uniquify.el ends here diff --git a/lisp/init-vc.el b/lisp/init-vc.el new file mode 100644 index 0000000..7417d8c --- /dev/null +++ b/lisp/init-vc.el @@ -0,0 +1,19 @@ +;;; init-vc.el --- Version control support -*- lexical-binding: t -*- +;;; Commentary: + +;; Most version control packages are configured separately: see +;; init-git.el, for example. + +;;; Code: + +(when (maybe-require-package 'diff-hl) + (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh) + (add-hook 'after-init-hook 'global-diff-hl-mode) + + (with-eval-after-load 'diff-hl + (define-key diff-hl-mode-map (kbd " ") 'diff-hl-diff-goto-hunk) + (define-key diff-hl-mode-map (kbd "M-C-]") 'diff-hl-next-hunk) + (define-key diff-hl-mode-map (kbd "M-C-[") 'diff-hl-previous-hunk))) + +(provide 'init-vc) +;;; init-vc.el ends here diff --git a/lisp/init-wakatime.el b/lisp/init-wakatime.el new file mode 100644 index 0000000..d964a0e --- /dev/null +++ b/lisp/init-wakatime.el @@ -0,0 +1,9 @@ +;;; init-wakatime.el --- Wakatime for Emacs +;;; Commentary: +;;; Code: +(maybe-require-package 'wakatime-mode) + +(global-wakatime-mode t) + +(provide 'init-wakatime) +;;; init-wakatime.el ends here diff --git a/lisp/init-whitespace.el b/lisp/init-whitespace.el new file mode 100644 index 0000000..b208215 --- /dev/null +++ b/lisp/init-whitespace.el @@ -0,0 +1,27 @@ +;;; init-whitespace.el --- Special handling for whitespace -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(setq-default show-trailing-whitespace nil) + + +;;; Whitespace + +(defun sanityinc/show-trailing-whitespace () + "Enable display of trailing whitespace in this buffer." + (setq-local show-trailing-whitespace t)) + +(dolist (hook '(prog-mode-hook text-mode-hook conf-mode-hook)) + (add-hook hook 'sanityinc/show-trailing-whitespace)) + + +(require-package 'whitespace-cleanup-mode) +(add-hook 'after-init-hook 'global-whitespace-cleanup-mode) +(with-eval-after-load 'whitespace-cleanup-mode + (diminish 'whitespace-cleanup-mode)) + +(global-set-key [remap just-one-space] 'cycle-spacing) + + +(provide 'init-whitespace) +;;; init-whitespace.el ends here diff --git a/lisp/init-whitespace.el~ b/lisp/init-whitespace.el~ new file mode 100644 index 0000000..2c58e1d --- /dev/null +++ b/lisp/init-whitespace.el~ @@ -0,0 +1,27 @@ +;;; init-whitespace.el --- Special handling for whitespace -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(setq-default show-trailing-whitespace t) + + +;;; Whitespace + +(defun sanityinc/show-trailing-whitespace () + "Enable display of trailing whitespace in this buffer." + (setq-local show-trailing-whitespace t)) + +(dolist (hook '(prog-mode-hook text-mode-hook conf-mode-hook)) + (add-hook hook 'sanityinc/show-trailing-whitespace)) + + +(require-package 'whitespace-cleanup-mode) +(add-hook 'after-init-hook 'global-whitespace-cleanup-mode) +(with-eval-after-load 'whitespace-cleanup-mode + (diminish 'whitespace-cleanup-mode)) + +(global-set-key [remap just-one-space] 'cycle-spacing) + + +(provide 'init-whitespace) +;;; init-whitespace.el ends here diff --git a/tramp b/tramp new file mode 100644 index 0000000..42749d6 --- /dev/null +++ b/tramp @@ -0,0 +1,8 @@ +;; -*- lisp-data -*- <24/09/06 10:38:11 ~/.emacs.d/tramp> +;; Tramp connection history. Don't change this file. +;; Run `M-x tramp-cleanup-all-connections' instead. + +(((tramp-file-name "cache" nil nil nil nil nil nil) + ("tramp-version" "2.8.0-pre")) + ((tramp-file-name "ssh" "user" nil "host" nil nil nil) nil) + ((tramp-file-name "sudo" "root" nil "hermit" nil nil nil) nil))