diff --git a/ansible/roles/base/files/gitignore_global b/ansible/roles/base/files/gitignore_global index e0809b4..b1ecf38 100644 --- a/ansible/roles/base/files/gitignore_global +++ b/ansible/roles/base/files/gitignore_global @@ -1,2 +1,3 @@ .idea .python-version +.dir-locals.el diff --git a/ansible/roles/emacs/files/base.el b/ansible/roles/emacs/files/base.el deleted file mode 100644 index 743db2f..0000000 --- a/ansible/roles/emacs/files/base.el +++ /dev/null @@ -1,103 +0,0 @@ -(package-initialize) -(use-package use-package) - -(add-to-list 'package-archives - '("melpa" . "https://melpa.org/packages/") - ) - -(use-package auto-package-update - :ensure t - :config - (setq auto-package-update-delete-old-versions t - auto-package-update-interval 14) - (auto-package-update-maybe)) - -(defconst private-dir (expand-file-name "private" user-emacs-directory)) -(defconst temp-dir (format "%s/cache" private-dir) - "Hostname-based elisp temp directories") - -;; Emacs customizations -(setq-default - inhibit-startup-screen t - initial-scratch-message nil - ;; Send prompts to mini-buffer not the GUI - use-dialog-box nil - confirm-nonexistent-file-or-buffer t - save-interprogram-paste-before-kill t - mouse-yank-at-point t - require-final-newline t - visible-bell nil - ring-bell-function 'ignore - ;; Write custom variables to an unused file so in-editor changes do not persist. - custom-file "~/.emacs.d/.custom.el" - ;; http://ergoemacs.org/emacs/emacs_stop_cursor_enter_prompt.html - minibuffer-prompt-properties - '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt) - - ;; Disable non selected window highlight - cursor-in-non-selected-windows nil - highlight-nonselected-windows nil - ;; PATH - exec-path (append exec-path '("/usr/local/bin/")) - indent-tabs-mode nil - tab-width 4 - inhibit-startup-message t - fringes-outside-margins t - x-select-enable-clipboard t - use-package-always-ensure t - ispell-program-name "aspell" - browse-url-browser-function 'browse-url-generic - browse-url-generic-program "firefox-developer-edition" - frame-title-format '("" invocation-name ": "(:eval (if (buffer-file-name) - (abbreviate-file-name (buffer-file-name)) - "%b"))) - ;; mouse-wheel-progressive-speed nil ;; Don't accelerate mouse wheel - ;; mouse-wheel-scroll-amount '(5 ((shift) . 3)) - use-short-answers t - package-native-compile t - delete-selection-mode t - ;; Don't show warnings when compiling elisp to native binaries. - native-comp-async-report-warnings-errors 'silent - ) - -(defun assert-directory (p) - (unless (file-exists-p p) (make-directory p t)) - p - ) -(assert-directory (concat temp-dir "/auto-save-list/")) -(setq autoload-directory (concat user-emacs-directory (file-name-as-directory "elisp") (file-name-as-directory "autoload"))) -(add-to-list 'load-path (assert-directory autoload-directory)) - -;; Bookmarks -(setq - ;; persistent bookmarks - bookmark-save-flag t - bookmark-default-file (concat temp-dir "/bookmarks")) - -;; Backups enabled, use nil to disable -(setq - history-length 1000 - backup-inhibited nil - make-backup-files nil - auto-save-default nil - auto-save-list-file-name (concat temp-dir "/autosave") - create-lockfiles nil - backup-directory-alist `((".*" . ,(concat temp-dir "/backup/"))) - auto-save-file-name-transforms `((".*" ,(concat temp-dir "/auto-save-list/") t))) - -;; Disable toolbar & menubar -(menu-bar-mode -1) -(when (fboundp 'tool-bar-mode) - (tool-bar-mode -1)) -(when ( fboundp 'scroll-bar-mode) - (scroll-bar-mode -1)) - -(context-menu-mode +1) - -;; Delete trailing whitespace before save -(add-hook 'before-save-hook 'delete-trailing-whitespace) - -(use-package diminish) - -(provide 'base) -;;; base ends here diff --git a/ansible/roles/emacs/files/early-init.el b/ansible/roles/emacs/files/early-init.el new file mode 100644 index 0000000..ae8a347 --- /dev/null +++ b/ansible/roles/emacs/files/early-init.el @@ -0,0 +1,25 @@ +(setq gc-cons-threshold 100000000) ;; Increase garbage collection threshold for performance (default 800000) +;; Increase amount of data read from processes, default 4k +(when (>= emacs-major-version 27) + (setq read-process-output-max (* 1024 1024)) ;; 1mb + ) + +;; Suppress warnings +(setq byte-compile-warnings '(not obsolete)) +(setq warning-suppress-log-types '((comp) (bytecomp))) +(setq native-comp-async-report-warnings-errors 'silent) + +;; Set up default visual settings +(setq frame-resize-pixelwise t) +;; Disable toolbar & menubar +(menu-bar-mode -1) +(when (fboundp 'tool-bar-mode) + (tool-bar-mode -1)) +(when (display-graphic-p) + (context-menu-mode +1)) + +(setq default-frame-alist '((fullscreen . maximized) + (vertical-scroll-bars . nil) + (horizontal-scroll-bars . nil) + ;; Set dark colors in early-init to prevent flashes of white. + (background-color . "#000000"))) diff --git a/ansible/roles/emacs/files/base-extensions.el b/ansible/roles/emacs/files/elisp/base-extensions.el similarity index 89% rename from ansible/roles/emacs/files/base-extensions.el rename to ansible/roles/emacs/files/elisp/base-extensions.el index f78dfb1..360ab56 100644 --- a/ansible/roles/emacs/files/base-extensions.el +++ b/ansible/roles/emacs/files/elisp/base-extensions.el @@ -1,3 +1,5 @@ +(use-package diminish) + ;; Eglot recommends pulling the latest of the standard libraries it ;; uses from ELPA if you're not tracking the current emacs development ;; branch. @@ -27,18 +29,16 @@ :config (dashboard-setup-startup-hook)) -(use-package ediff - :config - (setq ediff-window-setup-function 'ediff-setup-windows-plain) - (setq-default ediff-highlight-all-diffs 'nil) - (setq ediff-diff-options "-w")) - (when (version<= "26.0.50" emacs-version ) (add-hook 'prog-mode-hook 'display-line-numbers-mode) (add-hook 'prog-mode-hook 'column-number-mode) ) -(use-package page-break-lines) +;; Display a horizontal line instead of ^L for page break characters +(use-package page-break-lines + :config + (global-page-break-lines-mode +1) + ) (use-package recentf ;; This is an emacs built-in but we're pulling the latest version diff --git a/ansible/roles/emacs/files/base-functions.el b/ansible/roles/emacs/files/elisp/base-functions.el similarity index 100% rename from ansible/roles/emacs/files/base-functions.el rename to ansible/roles/emacs/files/elisp/base-functions.el diff --git a/ansible/roles/emacs/files/base-global-keys.el b/ansible/roles/emacs/files/elisp/base-global-keys.el similarity index 100% rename from ansible/roles/emacs/files/base-global-keys.el rename to ansible/roles/emacs/files/elisp/base-global-keys.el diff --git a/ansible/roles/emacs/files/base-theme.el b/ansible/roles/emacs/files/elisp/base-theme.el similarity index 100% rename from ansible/roles/emacs/files/base-theme.el rename to ansible/roles/emacs/files/elisp/base-theme.el diff --git a/ansible/roles/emacs/files/elisp/base.el b/ansible/roles/emacs/files/elisp/base.el new file mode 100644 index 0000000..f8f4af2 --- /dev/null +++ b/ansible/roles/emacs/files/elisp/base.el @@ -0,0 +1,69 @@ +(package-initialize) +(use-package use-package) + +(add-to-list 'package-archives + '("melpa" . "https://melpa.org/packages/") + ) + +(use-package auto-package-update + :ensure t + :config + (setq auto-package-update-delete-old-versions t + auto-package-update-interval 14) + (auto-package-update-maybe)) + +(defun assert-directory (p) + (unless (file-exists-p p) (make-directory p t)) + p + ) + +(defconst private-dir (expand-file-name "private" user-emacs-directory)) +(defconst temp-dir (format "%s/cache" private-dir) + "Hostname-based elisp temp directories") +(assert-directory (concat temp-dir "/auto-save-list/")) +(setq autoload-directory (concat user-emacs-directory (file-name-as-directory "elisp") (file-name-as-directory "autoload"))) +(add-to-list 'load-path (assert-directory autoload-directory)) + +(setq-default + ;; Disable backup files and lockfiles + make-backup-files nil + auto-save-default nil + create-lockfiles nil + ;; Unless otherwise specified, always install packages if they are absent. + use-package-always-ensure t + ;; Point custom-file at /dev/null so emacs does not write any settings to my dotfiles. + custom-file "/dev/null" + ;; Don't pop up a small window at the bottom of emacs at launch. + inhibit-startup-screen t + inhibit-startup-message t + ;; Give the scratch buffer a clean slate. + initial-major-mode 'fundamental-mode + initial-scratch-message nil + ;; Send prompts to mini-buffer not the GUI + use-dialog-box nil + ;; End files with line break + require-final-newline t + ;; Use spaces, not tabs + indent-tabs-mode nil + ;; Use a better frame title + frame-title-format '("" invocation-name ": "(:eval (if (buffer-file-name) + (abbreviate-file-name (buffer-file-name)) + "%b"))) + ;; Use 'y' or 'n' instead of 'yes' or 'no' + use-short-answers t + ;; Natively compile packages + package-native-compile t + ;; Typed text replaces selection + delete-selection-mode t + ;; Confirm when opening a file that does not exist + confirm-nonexistent-file-or-buffer t + ) + +;; (setq-default fringes-outside-margins t) + +(pixel-scroll-precision-mode) + +;; Delete trailing whitespace before save +(add-hook 'before-save-hook 'delete-trailing-whitespace) + +(provide 'base) diff --git a/ansible/roles/emacs/files/common-lsp.el b/ansible/roles/emacs/files/elisp/common-lsp.el similarity index 68% rename from ansible/roles/emacs/files/common-lsp.el rename to ansible/roles/emacs/files/elisp/common-lsp.el index 9a1e550..40ad135 100644 --- a/ansible/roles/emacs/files/common-lsp.el +++ b/ansible/roles/emacs/files/elisp/common-lsp.el @@ -7,6 +7,8 @@ ;; M-? ;; ([remap xref-find-references] . lsp-ui-peek-find-references) ("C-c C-a" . eglot-code-actions) + ;; C-M-. + ([remap xref-find-apropos] . #'consult-eglot-symbols) ) :hook ( (eglot-managed-mode . (lambda () @@ -16,27 +18,19 @@ )) ) :config - ;; Increase garbage collection threshold for performance (default 800000) - (setq gc-cons-threshold 100000000) - - ;; Increase amount of data read from processes, default 4k - (when (>= emacs-major-version 27) - (setq read-process-output-max (* 1024 1024)) ;; 1mb - ) - + (fset #'jsonrpc--log-event #'ignore) ;; Disable logging LSP traffic for performance boost (set-face-attribute 'eglot-highlight-symbol-face nil :background "#0291a1" :foreground "black") (set-face-attribute 'eglot-mode-line nil :inherit 'mode-line :bold nil) - (use-package consult-eglot - :bind ( - :map eglot-mode-map - ;; C-M-. - ([remap xref-find-apropos] . #'consult-eglot-symbols) - ) - ) + :custom (eglot-autoshutdown t "Shut down server when last buffer is killed.") (eglot-sync-connect 0 "Don't block on language server starting.") + (eglot-send-changes-idle-time 0.1) + ) + +(use-package consult-eglot + :commands (consult-eglot-symbols) ) (provide 'common-lsp) diff --git a/ansible/roles/emacs/files/lang-bash.el b/ansible/roles/emacs/files/elisp/lang-bash.el similarity index 92% rename from ansible/roles/emacs/files/lang-bash.el rename to ansible/roles/emacs/files/elisp/lang-bash.el index b64f517..8ae8b0f 100644 --- a/ansible/roles/emacs/files/lang-bash.el +++ b/ansible/roles/emacs/files/elisp/lang-bash.el @@ -2,7 +2,7 @@ (use-package bash-ts-mode :ensure nil - :commands bash-ts-mode + :commands (bash-ts-mode) :init (add-to-list 'major-mode-remap-alist '(sh-mode . bash-ts-mode)) (add-to-list 'treesit-language-source-alist '(bash "https://github.com/tree-sitter/tree-sitter-bash")) diff --git a/ansible/roles/emacs/files/lang-dockerfile.el b/ansible/roles/emacs/files/elisp/lang-dockerfile.el similarity index 100% rename from ansible/roles/emacs/files/lang-dockerfile.el rename to ansible/roles/emacs/files/elisp/lang-dockerfile.el diff --git a/ansible/roles/emacs/files/lang-go.el b/ansible/roles/emacs/files/elisp/lang-go.el similarity index 100% rename from ansible/roles/emacs/files/lang-go.el rename to ansible/roles/emacs/files/elisp/lang-go.el diff --git a/ansible/roles/emacs/files/lang-javascript.el b/ansible/roles/emacs/files/elisp/lang-javascript.el similarity index 100% rename from ansible/roles/emacs/files/lang-javascript.el rename to ansible/roles/emacs/files/elisp/lang-javascript.el diff --git a/ansible/roles/emacs/files/lang-lua.el b/ansible/roles/emacs/files/elisp/lang-lua.el similarity index 100% rename from ansible/roles/emacs/files/lang-lua.el rename to ansible/roles/emacs/files/elisp/lang-lua.el diff --git a/ansible/roles/emacs/files/lang-markdown.el b/ansible/roles/emacs/files/elisp/lang-markdown.el similarity index 100% rename from ansible/roles/emacs/files/lang-markdown.el rename to ansible/roles/emacs/files/elisp/lang-markdown.el diff --git a/ansible/roles/emacs/files/lang-org.el b/ansible/roles/emacs/files/elisp/lang-org.el similarity index 100% rename from ansible/roles/emacs/files/lang-org.el rename to ansible/roles/emacs/files/elisp/lang-org.el diff --git a/ansible/roles/emacs/files/lang-python.el b/ansible/roles/emacs/files/elisp/lang-python.el similarity index 100% rename from ansible/roles/emacs/files/lang-python.el rename to ansible/roles/emacs/files/elisp/lang-python.el diff --git a/ansible/roles/emacs/files/elisp/lang-rust.el b/ansible/roles/emacs/files/elisp/lang-rust.el new file mode 100644 index 0000000..bc91069 --- /dev/null +++ b/ansible/roles/emacs/files/elisp/lang-rust.el @@ -0,0 +1,89 @@ +(require 'common-lsp) +(require 'util-tree-sitter) + +(defun locate-rust-analyzer () + "Find rust-analyzer." + (let ((rust-analyzer-paths (list (locate-rust-analyzer-rustup) (locate-rust-analyzer-ansible-built) (locate-rust-analyzer-in-path)))) + (let ((first-non-nil-path (seq-find (lambda (elt) elt) rust-analyzer-paths))) + first-non-nil-path + ) + ) + ) + +(defun locate-rust-analyzer-rustup () + "Find rust-analyzer through rustup." + (run-command-in-directory nil "rustup" "which" "rust-analyzer") + ) + +(defun locate-rust-analyzer-ansible-built () + "Find rust-analyzer where the ansible playbook built it." + (let ((rust-analyzer-path "/opt/rust-analyzer/target/release/rust-analyzer")) + (when (file-exists-p rust-analyzer-path) + rust-analyzer-path + ) + ) + ) + +(defun locate-rust-analyzer-in-path () + "Find rust-analyzer in $PATH." + (executable-find "rust-analyzer") + ) + +(use-package rust-ts-mode + :pin manual + :mode ( + ("\\.rs\\'" . rust-ts-mode) + ) + :commands (rust-ts-mode) + :hook ( + (rust-ts-mode . (lambda () + (eglot-ensure) + (let ((rust-analyzer-command (locate-rust-analyzer))) + (when rust-analyzer-command + ;; (add-to-list 'eglot-server-programs `(rust-ts-mode . (,rust-analyzer-command))) + (add-to-list 'eglot-server-programs `(rust-ts-mode . (,rust-analyzer-command :initializationOptions (:imports (:granularity (:enforce t :group "item") + :merge (:glob nil) + :prefix "self") + :inlayHints (:maxLength nil) + :workspace (:symbol (:search (:limit 1024))))))) + ) + ) + (add-hook 'before-save-hook 'eglot-format-buffer nil 'local) + )) + ) + :init + (add-to-list 'major-mode-remap-alist '(rust-mode . rust-ts-mode)) + (add-to-list 'treesit-language-source-alist '(rust "https://github.com/tree-sitter/tree-sitter-rust")) + (unless (treesit-ready-p 'yaml) (treesit-install-language-grammar 'rust)) + :config + ;; Add keybindings for interacting with Cargo + (use-package cargo + :hook (rust-ts-mode . cargo-minor-mode)) + ) + +(use-package toml-ts-mode + :ensure nil + :pin manual + :mode ( + ("\\.toml\\'" . toml-ts-mode) + ) + :commands (toml-ts-mode) + :init + (add-to-list 'treesit-language-source-alist '(toml "https://github.com/tree-sitter/tree-sitter-toml")) + (unless (treesit-ready-p 'toml) (treesit-install-language-grammar 'toml)) + ) + +;; Set additional rust-analyzer settings: +;; +;; (add-to-list 'eglot-server-programs `(rust-ts-mode . (,rust-analyzer-command :initializationOptions (:cargo (:features "all"))))) +;; +;; In addition to the above, directory-specific settings can be written to a .dir-locals.el with the contents: +;; +;; ( +;; (rust-ts-mode . ((eglot-workspace-configuration +;; . (:rust-analyzer (:cargo (:noDefaultFeatures t :features ["compare" "tracing"])))) +;; )) +;; ) + + +(provide 'lang-rust) diff --git a/ansible/roles/emacs/files/lang-terraform.el b/ansible/roles/emacs/files/elisp/lang-terraform.el similarity index 100% rename from ansible/roles/emacs/files/lang-terraform.el rename to ansible/roles/emacs/files/elisp/lang-terraform.el diff --git a/ansible/roles/emacs/files/lang-yaml.el b/ansible/roles/emacs/files/elisp/lang-yaml.el similarity index 96% rename from ansible/roles/emacs/files/lang-yaml.el rename to ansible/roles/emacs/files/elisp/lang-yaml.el index 1456df5..bf8cde1 100644 --- a/ansible/roles/emacs/files/lang-yaml.el +++ b/ansible/roles/emacs/files/elisp/lang-yaml.el @@ -12,6 +12,7 @@ ("environments/[^/]*/group_vars/[^/]*\\'" . yaml-ts-mode) ("environments/[^/]*/host_vars/[^/]*\\'" . yaml-ts-mode) ) + :commands (yaml-ts-mode) :hook ( (yaml-ts-mode . (lambda () (add-hook 'before-save-hook 'yaml-format-buffer nil 'local) diff --git a/ansible/roles/emacs/files/util-tree-sitter.el b/ansible/roles/emacs/files/elisp/util-tree-sitter.el similarity index 100% rename from ansible/roles/emacs/files/util-tree-sitter.el rename to ansible/roles/emacs/files/elisp/util-tree-sitter.el diff --git a/ansible/roles/emacs/files/util-vertico.el b/ansible/roles/emacs/files/elisp/util-vertico.el similarity index 100% rename from ansible/roles/emacs/files/util-vertico.el rename to ansible/roles/emacs/files/elisp/util-vertico.el diff --git a/ansible/roles/emacs/files/lang-rust.el b/ansible/roles/emacs/files/lang-rust.el deleted file mode 100644 index c78cd01..0000000 --- a/ansible/roles/emacs/files/lang-rust.el +++ /dev/null @@ -1,66 +0,0 @@ -(require 'common-lsp) -(require 'util-tree-sitter) - -(defun locate-rust-analyzer () - "Find rust-analyzer." - (let ((rust-analyzer-paths (list (locate-rust-analyzer-rustup) (locate-rust-analyzer-ansible-built)))) - (let ((first-non-nil-path (seq-find (lambda (elt) elt) rust-analyzer-paths))) - first-non-nil-path - ) - ) - ) - -(defun locate-rust-analyzer-rustup () - "Find rust-analyzer through rustup." - (run-command-in-directory nil "rustup" "which" "rust-analyzer") - ) - -(defun locate-rust-analyzer-ansible-built () - "Find rust-analyzer where the ansible playbook built it." - (let ((rust-analyzer-path "/opt/rust-analyzer/target/release/rust-analyzer")) - (when (file-exists-p rust-analyzer-path) - rust-analyzer-path - ) - ) - ) - -(use-package rust-ts-mode - :pin manual - :mode ( - ("\\.rs\\'" . rust-ts-mode) - ) - :hook ( - (rust-ts-mode . (lambda () - (eglot-ensure) - (let ((rust-analyzer-command (locate-rust-analyzer))) - (when rust-analyzer-command - (add-to-list 'eglot-server-programs (cons 'rust-ts-mode (list rust-analyzer-command))) - ) - ) - (add-hook 'before-save-hook 'eglot-format-buffer nil 'local) - )) - ) - :init - (add-to-list 'major-mode-remap-alist '(rust-mode . rust-ts-mode)) - (add-to-list 'treesit-language-source-alist '(rust "https://github.com/tree-sitter/tree-sitter-rust")) - (unless (treesit-ready-p 'yaml) (treesit-install-language-grammar 'rust)) - :config - ;; Add keybindings for interacting with Cargo - (use-package cargo - :hook (rust-ts-mode . cargo-minor-mode)) - ) - -(use-package toml-ts-mode - :ensure nil - :pin manual - :mode ( - ("\\.toml\\'" . toml-ts-mode) - ) - :commands (toml-ts-mode) - :init - (add-to-list 'treesit-language-source-alist '(toml "https://github.com/tree-sitter/tree-sitter-toml")) - (unless (treesit-ready-p 'toml) (treesit-install-language-grammar 'toml)) - ) - - -(provide 'lang-rust) diff --git a/ansible/roles/emacs/tasks/linux.yaml b/ansible/roles/emacs/tasks/linux.yaml index 2042292..1b964f1 100644 --- a/ansible/roles/emacs/tasks/linux.yaml +++ b/ansible/roles/emacs/tasks/linux.yaml @@ -2,7 +2,7 @@ package: name: - aspell-en - - emacs + - emacs-wayland state: present - name: Install packages diff --git a/ansible/roles/emacs/tasks/peruser.yaml b/ansible/roles/emacs/tasks/peruser.yaml index a30e2a6..2d6b9c1 100644 --- a/ansible/roles/emacs/tasks/peruser.yaml +++ b/ansible/roles/emacs/tasks/peruser.yaml @@ -22,6 +22,8 @@ loop: - src: init.el dest: .emacs.d/init.el + - src: early-init.el + dest: .emacs.d/early-init.el - name: Configure dotfiles when: 'emacs_flavor == "plain"' @@ -38,31 +40,13 @@ - name: Configure elisp files when: 'emacs_flavor == "full"' copy: - src: "files/{{ item }}" - dest: "{{ account_homedir.stdout }}/.emacs.d/elisp/{{ item }}" - mode: 0600 + src: "files/{{ item.src }}" + dest: "{{ account_homedir.stdout }}/{{ item.dest }}" owner: "{{ account_name.stdout }}" group: "{{ group_name.stdout }}" loop: - - base-extensions.el - - base-functions.el - - base-global-keys.el - - base-theme.el - - base.el - - common-lsp.el - - lang-bash.el - - lang-dockerfile.el - - lang-go.el - - lang-javascript.el - - lang-lua.el - - lang-markdown.el - - lang-org.el - - lang-python.el - - lang-rust.el - - lang-terraform.el - - lang-yaml.el - - util-vertico.el - - util-tree-sitter.el + - src: elisp + dest: .emacs.d/ - name: Configure zshrc additional imports copy: