diff --git a/dot_config/emacs/early-init.el.new b/dot_config/emacs/early-init.el.new new file mode 100644 index 0000000..99b3e3d --- /dev/null +++ b/dot_config/emacs/early-init.el.new @@ -0,0 +1,91 @@ +;;; early-init.el --- GNU Emacs Early Initialization File -*- lexical-binding: t; -*- + +;; Copyright (c) 2023 Andrew Scott + +;; Author: Andrew Scott +;; Keywords: convenience, tools +;; URL: https://codeberg.org/andyscott/dotfiles + +;; This file is not part of GNU Emacs. + +;;; Commentary: + +;; My customizations for early Emacs initialization + +;;; License: + +;; MIT No Attribution + +;; Permission is hereby granted, free of charge, to any person obtaining a copy of this +;; software and associated documentation files (the "Software"), to deal in the Software +;; without restriction, including without limitation the rights to use, copy, modify, +;; merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +;; permit persons to whom the Software is furnished to do so. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +;; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +;; PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +;;; Code: + +;; Disable package.el +(setq package-enable-at-startup nil) + +;; Ensure other default libs are loaded +(setq inhibit-default-init nil) + +;; Load newest byte code +(setq load-prefer-newer t) + +;; Enable async native compilation and suppress warnings +(when (featurep 'native-compile) + (setq native-comp-deferred-compilation t + native-comp-async-report-warnings-errors nil)) + +;; Raise garbage collection threshold +(setq gc-cons-threshold 100000000 + gc-cons-percentage 0.1) + +;; Don't advertise instructions for frame exit +(setq server-client-instructions nil) + +;; Don't implicitly resize the frame +(setq frame-inhibit-implied-resize t) + +;; Disable startup screen +(setq inhibit-startup-screen t) + +;; Visible bell only +(setq visible-bell t) + +;; Fonts +(push '(font . "Hack-24") default-frame-alist) +(set-face-font 'default "Hack-24") +(set-face-font 'fixed-pitch "Hack-24") +(set-face-font 'variable-pitch "DejaVu Sans-24") + +;; Disable some GUI options +(push '(tool-bar-lines . 0) default-frame-alist) +(push '(menu-bar-lines . 0) default-frame-alist) +(push '(vertical-scroll-bars) default-frame-alist) + +;; Relocate emacs-user-directory to XDG_DATA_HOME +(setq user-emacs-directory + (expand-file-name "emacs/" (or (getenv "XDG_DATA_HOME") "~/.local/share/"))) + +;; Set cache directory +(setq xdg-cache-home (expand-file-name "emacs/" (or (getenv "XDG_CACHE_HOME") "~/.cache/"))) +(unless (file-directory-p xdg-cache-home) + (make-directory xdg-cache-home)) + +;; Move eln-cache to XDG_CACHE_HOME +(when (fboundp 'startup-redirect-eln-cache) + (if (< emacs-major-version 29) + (push (expand-file-name "eln-cache/" xdg-cache-home) native-comp-eln-load-path) + (startup-redirect-eln-cache (expand-file-name "eln-cache/" xdg-cache-home)))) + +(provide 'early-init) +;;; early-init.el ends here diff --git a/dot_config/emacs/init.el.new b/dot_config/emacs/init.el.new new file mode 100644 index 0000000..7ea713f --- /dev/null +++ b/dot_config/emacs/init.el.new @@ -0,0 +1,580 @@ +;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*- + +;; Copyright (c) 2023 Andrew Scott + +;; Author: Andrew Scott +;; Keywords: convenience, tools +;; URL: https://codeberg.org/andyscott/dotfiles + +;; This file is not part of GNU Emacs. + +;;; Commentary: + +;; My personal Emacs configuration. + +;;; License: + +;; MIT No Attribution + +;; Permission is hereby granted, free of charge, to any person obtaining a copy of this +;; software and associated documentation files (the "Software"), to deal in the Software +;; without restriction, including without limitation the rights to use, copy, modify, +;; merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +;; permit persons to whom the Software is furnished to do so. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +;; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +;; PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +;;; Code: + +;; Profile emacs startup +(add-hook 'emacs-startup-hook + (lambda () + (message "Emacs loaded in %s with %d garbage collections." + (format "%.2f seconds" + (float-time + (time-subtract (current-time) before-init-time))) + gcs-done))) + +;;; Initialize elpaca +(defvar elpaca-installer-version 0.5) +(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) +(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) +(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) +(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" + :ref nil + :files (:defaults (:exclude "extensions")) + :build (:not elpaca--activate-package))) +(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) + (build (expand-file-name "elpaca/" elpaca-builds-directory)) + (order (cdr elpaca-order)) + (default-directory repo)) + (add-to-list 'load-path (if (file-exists-p build) build repo)) + (unless (file-exists-p repo) + (make-directory repo t) + (when (< emacs-major-version 28) (require 'subr-x)) + (condition-case-unless-debug err + (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) + ((zerop (call-process "git" nil buffer t "clone" + (plist-get order :repo) repo))) + ((zerop (call-process "git" nil buffer t "checkout" + (or (plist-get order :ref) "--")))) + (emacs (concat invocation-directory invocation-name)) + ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" + "--eval" "(byte-recompile-directory \".\" 0 'force)"))) + ((require 'elpaca)) + ((elpaca-generate-autoloads "elpaca" repo))) + (progn (message "%s" (buffer-string)) (kill-buffer buffer)) + (error "%s" (with-current-buffer buffer (buffer-string)))) + ((error) (warn "%s" err) (delete-directory repo 'recursive)))) + (unless (require 'elpaca-autoloads nil t) + (require 'elpaca) + (elpaca-generate-autoloads "elpaca" repo) + (load "./elpaca-autoloads"))) +(add-hook 'after-init-hook #'elpaca-process-queues) +(elpaca `(,@elpaca-order)) + +;; use-package +(elpaca elpaca-use-package + (elpaca-use-package-mode) + (setq elpaca-use-package-by-default t)) + +(elpaca-wait) + +;;; Built-in features +(use-package emacs + :elpaca nil + :init + ;;; General Options + + ;; Discard external customizations + (setq-default custom-file null-device) + + ;; Don't ask about running processes on exit + (setq confirm-kill-processes nil) + + ;; Better scrolling + (setq scroll-step 1 + scroll-conservatively 1000 + scroll-preserve-screen-position t + mouse-wheel-follow-mouse 't + mouse-wheel-progressive-speed nil + ;; 1st #: lines to scroll, 2nd #: while holding shift + mouse-wheel-scroll-amount '(2 ((shift) .1))) + (when (fboundp 'pixel-scroll-precision-mode) + (pixel-scroll-precision-mode t)) + + ;; Tabs + (setq tab-always-indent 'complete) + (setq-default tab-width 4 + indent-tabs-mode nil) + + ;; Line/Column numbers + (setq column-number-mode t) + (dolist (hook '(conf-mode-hook + prog-mode-hook + text-mode-hook)) + (add-hook hook #'display-line-numbers-mode)) + + ;; Disable suspend-frame shortcut + (global-set-key (kbd "") nil) + + ;; Escape behaves like C-g + (global-set-key (kbd "") 'keyboard-escape-quit) + + ;; Prefer UTF-8 character coding + (prefer-coding-system 'utf-8) + (set-default-coding-systems 'utf-8) + (set-terminal-coding-system 'utf-8) + (set-keyboard-coding-system 'utf-8) + + ;; More reasonable keybinds for resizing windows + (global-set-key (kbd "S-C-") 'shrink-window-horizontally) + (global-set-key (kbd "S-C-") 'enlarge-window-horizontally) + (global-set-key (kbd "S-C-") 'shrink-window) + (global-set-key (kbd "S-C-") 'enlarge-window) + + ;; Built-in C settings + (setq-default c-basic-offset 2 + c-default-style "k&r") + + ;;; Vertico + ;; Add prompt to `completing-read-multiple' + (defun crm-indicator (args) + (cons (format "[CRM%s] %s" + (replace-regexp-in-string + "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" + crm-separator) + (car args)) + (cdr args))) + (advice-add #'completing-read-multiple :filter-args #'crm-indicator) + + ;; Recursive minibuffers + (setq enable-recursive-minibuffers t) + + ;; Disable prompt in minibuffer + (setq minibuffer-prompt-properties + '(read-only t cursor-intangible t face minibuffer-prompt)) + (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)) + +(use-package display-fill-column-indicator + :elpaca nil + :hook ((conf-mode markdown-mode prog-mode) . display-fill-column-indicator-mode) + :config (setq-default fill-column 80)) + +(use-package elec-pair + :elpaca nil + :config (electric-pair-mode)) + +;; Move auto saves to XDG_CACHE_HOME +(use-package files + :elpaca nil + :init + (let ((auto-save-directory (concat xdg-cache-home "auto-save-list/"))) + (setq backup-directory-alist `(".*" . ,auto-save-directory) + auto-save-file-name-transforms `(".*" ,auto-save-directory t))) + :config + (setq delete-old-versions t + kept-new-versions 5 + kept-old-versions 3 + require-final-newline t + version-control t)) + +(use-package paren + :elpaca nil + :config (show-paren-mode)) + +(use-package recentf + :elpaca nil + :init (setq recentf-save-file (expand-file-name "recentf" xdg-cache-home)) + :config + (setq recentf-auto-cleanup 'never + recentf-max-menu-items 15 + recentf-max-saved-items 100) + (recentf-mode)) + +(use-package savehist + :elpaca nil + :init (setq savehist-file (concat xdg-cache-home "history")) + :config + (setq savehist-autosave-interval 60 + savehist-additional-variables '(search-ring regexp-search-ring)) + (savehist-mode)) + +(use-package saveplace + :elpaca nil + :init (setq save-place-file (concat xdg-cache-home "places")) + :config (save-place-mode)) + +(use-package whitespace + :elpaca nil + :init + (dolist (hook '(conf-mode-hook + prog-mode-hook + text-mode-hook)) + (add-hook hook #'whitespace-mode)) + (add-hook 'before-save-hook #'whitespace-cleanup) + :config + (setq whitespace-line-column 100 + whitespace-style '(big-indent + face + lines-tail + missing-newline-at-eof + tabs + trailing))) + +(elpaca-wait) +;;; Packages +;; Theme +(use-package everforest + :elpaca (everforest + :host sourcehut + :repo "theorytoe/everforest-theme") + :config + (setq custom-safe-themes t) + (load-theme 'everforest-hard-dark t) + (let ((line (face-attribute 'mode-line :foreground)) + (inactive (face-attribute 'mode-line-inactive :background))) + (set-face-attribute 'mode-line nil :overline line) + (set-face-attribute 'mode-line-inactive nil :overline line) + (set-face-attribute 'mode-line-inactive nil :underline line) + (set-face-attribute 'mode-line nil :box nil) + (set-face-attribute 'mode-line-inactive nil :box nil) + (set-face-attribute 'mode-line-inactive nil :background inactive))) + +;; Mode line +(use-package minions + :defer 1 + :config (minions-mode)) + +(use-package keycast + :defer t + :config + (setq keycast-mode-line-insert-after 'moody-mode-line-buffer-identification)) + +(use-package moody + :defer 1 + :config + (setq x-underline-at-descent-line t) + (moody-replace-eldoc-minibuffer-message-function) + (moody-replace-mode-line-buffer-identification) + (moody-replace-mode-line-front-space) + (moody-replace-vc-mode)) + +;; Show keybind hints +(use-package which-key + :defer 1 + :config + (setq which-key-idle-delay 0.3) + (which-key-mode)) + +;; Better annotations +(use-package marginalia + :defer 1 + :bind (:map minibuffer-local-map + ("M-A" . marginalia-cycle)) + :config (marginalia-mode)) + +;; Better undo/redo +(use-package undo-tree + :defer 3 + :config + (setq undo-tree-auto-save-history t + undo-tree-history-directory-alist + `((".*" . ,(concat xdg-cache-home "undo-tree/")))) + (global-undo-tree-mode)) + +;; Completion style +(use-package orderless + :custom + (completion-styles '(orderless basic)) + (completion-category-overrides '((file (styles basic partial-completion))))) + +;; Completion UI +(use-package vertico + :init (vertico-mode) + :config + (setq vertico-cycle t + vertico-count 10 + vertico-resize t + vertico-scroll-margin 1 + completion-ignore-case t + read-buffer-completion-ignore-case t + read-file-name-completion-ignore-case t)) + +;; Command menu for items around point +(use-package embark + :defer 3 + :init + (setq prefix-help-command #'embark-prefix-help-command) + ;; documentation from first source + (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target) + ;; documentation from multiple sources + ;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly) + :bind + (("C-." . embark-act) + ("C-;" . embark-dwim) + ("C-h B" . embark-bindings)) + :config + ;; Hide the Embark live/completions buffer mode line + (push '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))) display-buffer-alist)) + +;; Search and navigation +(use-package consult + :init + ;; Register formatting + (setq register-preview-delay 0.6 + register-preview-function #'consult-register-format) + ;; Register preview window + (advice-add #'register-preview :override #'consult-register-window) + ;; Select xref locations with preview + (setq xref-show-xrefs-function #'consult-xref + xref-show-definitions-function #'consult-xref) + :config + (setq consult-narrow-key "<" + consult-preview-key 'any) + ;; Switch project root function + ;; (autoload 'projectile-project-root "projectile") + :bind (;; C-c bindings in `mode-specific-map' + ("C-c M-x" . consult-mode-command) + ("C-c h" . consult-history) + ("C-c k" . consult-kmacro) + ("C-c m" . consult-man) + ("C-c i" . consult-info) + ([remap Info-search] . consult-info) + ;; C-x bindings in `ctl-x-map' + ("C-x M-:" . consult-complex-command) ; orig. repeat-complex-command + ("C-x b" . consult-buffer) ; orig. switch-to-buffer + ("C-x 4 b" . consult-buffer-other-window) ; orig. switch-to-buffer-other-window + ("C-x 5 b" . consult-buffer-other-frame) ; orig. switch-to-buffer-other-frame + ("C-x r b" . consult-bookmark) ; orig. bookmark-jump + ("C-x p b" . consult-project-buffer) ; orig. project-switch-to-buffer + ("C-x M-r" . consult-recent-file) + ;; Custom M-# bindings for fast register access + ("M-#" . consult-register-load) + ("M-'" . consult-register-store) ; orig. abbrev-prefix-mark (unrelated) + ("C-M-#" . consult-register) + ;; Other custom bindings + ("M-y" . consult-yank-pop) ; orig. yank-pop + ;; M-g bindings in `goto-map' + ("M-g e" . consult-compile-error) + ("M-g f" . consult-flymake) ; Alternative: consult-flycheck + ("M-g g" . consult-goto-line) ; orig. goto-line + ("M-g M-g" . consult-goto-line) ; orig. goto-line + ("M-g o" . consult-outline) ; Alternative: consult-org-heading + ("M-g m" . consult-mark) + ("M-g k" . consult-global-mark) + ("M-g i" . consult-imenu) + ("M-g I" . consult-imenu-multi) + ;; M-s bindings in `search-map' + ("M-s d" . consult-find) + ("M-s D" . consult-locate) + ("M-s g" . consult-grep) + ("M-s G" . consult-git-grep) + ("M-s r" . consult-ripgrep) + ("M-s l" . consult-line) + ("M-s L" . consult-line-multi) + ("M-s k" . consult-keep-lines) + ("M-s u" . consult-focus-lines) + ;; Isearch integration + ("M-s e" . consult-isearch-history) + :map isearch-mode-map + ("M-e" . consult-isearch-history) ; orig. isearch-edit-string + ("M-s e" . consult-isearch-history) ; orig. isearch-edit-string + ("M-s l" . consult-line) ; needed by consult-line to detect isearch + ("M-s L" . consult-line-multi) ; needed by consult-line to detect isearch + ;; Minibuffer history + :map minibuffer-local-map + ("M-s" . consult-history) ; orig. next-matching-history-element + ("M-r" . consult-history))) ; orig. previous-matching-history-element + +;; Consult-specific Embark actions +(use-package embark-consult + :defer 3 + :hook (embark-collect-mode . consult-preview-at-point-mode)) + +;; In-buffer completion +(use-package corfu + :defer 3 + :elpaca (corfu :files (:defaults "extensions/*")) + :init + (global-corfu-mode) + (corfu-popupinfo-mode) + :custom + (corfu-min-width 60) + (corfu-max-width corfu-min-width) + (corfu-auto t) + (corfu-auto-delay 0.3) + (corfu-cycle t) + (corfu-popupinfo-delay 0.6) + (corfu-separator ?\s) + :bind (:map corfu-map ("M-SPC" . corfu-insert-separator))) + +(use-package kind-icon + :after corfu + :init (setq svg-lib-icons-dir (concat xdg-cache-home "svg-lib/")) + :config + (setq kind-icon-default-face 'corfu-default + kind-icon-blend-background nil) + (push #'kind-icon-margin-formatter corfu-margin-formatters)) + +;; Git +(use-package magit + :init + (setq transient-history-file (concat xdg-cache-home "transient-history")) + :bind ("C-M-;" . magit-status) + :commands (magit-status + magit-get-current-branch) + :custom + (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) + +(use-package git-timemachine + :bind ("C-M-'" . git-timemachine)) + +;; Project Managment +(use-package projectile + :defer 1 + :init + (setq projectile-known-projects-file (concat xdg-cache-home "projectile-bookmarks")) + :bind ("C-c p" . projectile-command-map) + :config + (push "*node_modules" projectile-globally-ignored-directories) + (projectile-mode)) + +(use-package treemacs + :defer 1 + :init (setq treemacs-persist-file (concat xdg-cache-home "treemacs-persist")) + :bind + (:map global-map + ("M-0" . treemacs-select-window) + ("C-x t 1" . treemacs-delete-other-windows) + ("C-x t t" . treemacs) + ("C-x t B" . treemacs-bookmark) + ("C-x t C-t" . treemacs-find-file) + ("C-x t M-t" . treemacs-find-tag)) + :config + (setq treemacs-git-mode 'deferred) + (treemacs-filewatch-mode) + (treemacs-git-commit-diff-mode)) + +(use-package consult-projectile) + +(use-package treemacs-magit) + +(use-package treemacs-projectile) + +;;; Language support +;; Auto-format +(use-package apheleia + :defer 5 + :config (apheleia-global-mode)) + +(use-package reformatter ; required for zig fmt + :after zig-mode) + +;; Visualize color names +(use-package rainbow-mode + :hook ((conf-mode prog-mode) . rainbow-mode)) + +;; Syntax parsing/highlighting +(use-package treesit-auto + :defer 3 + :config + (setq treesit-auto-install 'prompt) + (global-treesit-auto-mode)) + +;; Syntax checking +(use-package flycheck + :hook (lsp-mode . flycheck-mode) + :config (setq flycheck-python-flake8-executable "flake8")) + +(use-package consult-flycheck) + +;; LSP +(use-package lsp-mode + :commands lsp lsp-deferred + :hook + (((c-mode c++-mode python-mode zig-mode) . lsp) + (lsp-mode . lsp-enable-which-key-integration)) + :config + (setq lsp-idle-delay 0.6 + lsp-prefer-flymake nil)) + +(use-package lsp-ui + :hook (lsp-mode . lsp-ui-mode) + :config + (setq lsp-ui-doc-position 'bottom-and-right + lsp-ui-sideline-delay 0.6 + lsp-ui-sideline-show-code-actions t + lsp-ui-sideline-show-hover t + lsp-ui-sideline-update-mode 'line + lsp-ui-flycheck-enable t + lsp-ui-flycheck-list-position 'right + lsp-ui-peek-enable t)) + +(use-package consult-lsp + :bind + (:map lsp-mode-map + ([remap xref-find-apropos] . consult-lsp-symbols))) + +(use-package lsp-treemacs) + +;; Debugging +(use-package dap-mode + :after lsp-mode + :bind + (:map dap-mode-map + ("" . dap-debug) + ("" . dap-next) + ("" . dap-step-in) + ("S-" . dap-disconnect) + ("C-S-" . dap-debug-restart)) + :config + (setq dap-auto-configure-features '(sessions locals tooltip) + dap-lldb-debug-program "/usr/bin/lldb-vscode" + dap-python-debugger 'debugpy) + (eval-when-compile + (require 'cl-lib)) + (require 'dap-python) + (require 'dap-lldb) + (require 'dap-gdb-lldb) + (dap-gdb-lldb-setup) + ;; Templates + (dap-register-debug-template + "Rust :: LLDB Run Configuration" + (list :type "lldb" + :request "launch" + :name "LLDB::Run" + :gdbpath "rust-lldb"))) + +(use-package realgud) + +(use-package realgud-lldb) + +;; Zig +(use-package zig-mode + :init + (push '(zig-mode . "zig") lsp-language-id-configuration) + (lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection "/usr/bin/zls") + :major-modes '(zig-mode) + :server-id 'zls)) + :hook + (zig-mode . (lambda () + (setq-local fill-column 100) + (setq-local tab-width 4)))) + +;;; File format/markup support +(use-package markdown-mode) + +(use-package toml-mode) + +(use-package yaml-pro) +;;; init.el ends here