;;; init.el --- GNU Emacs Initialization File ;;; OPTIONS: ;; Disable package.el (interferes with straight.el) (setq package-enable-at-startup nil) ;; Disable native comp warnings (setq native-comp-async-report-warnings-errors nil) ;; Disable startup message (setq inhibit-startup-message t) ;; Don't ask about running processes on exit (setq confirm-kill-processes nil) ;; Visible bell (setq visible-bell t) ;; Write external customizations to /dev/null (setq-default custom-file null-device) ;; Disable some GUI options (menu-bar-mode -1) (scroll-bar-mode -1) (tool-bar-mode -1) (tooltip-mode -1) ;; Fringe width (set-fringe-mode 10) ;; Disable suspend-frame shortcut (define-key global-map "\C-z" nil) ;; Font (does nothing if mixed-pitch is used) ;; (set-face-attribute 'default nil :font "ibm plex mono light" :height 100) ;; 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 after-init-time before-init-time))) gcs-done))) ;; ESC behaves like C-g (global-set-key (kbd "") 'keyboard-escape-quit) ;; Parenthesis/bracket pairs (show-paren-mode t) (setq-default show-paren-style 'parenthesis) (electric-pair-mode 1) ;; Relocate emacs-user-directory to $XDG_DATA_HOME (setq user-emacs-directory (expand-file-name "~/.local/share/emacs/") url-history-file (expand-file-name "url/history" user-emacs-directory)) ;; Store autosaves in $XDG_CACHE_HOME (setq auto-save-file-name-transforms `((".*" "~/.cache/emacs/autosave/" t))) ;; Default encoding (set-default-coding-systems '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) ;; Scrolling (setq mouse-wheel-scroll-amount '(4 ((shift) . 1))) ; 1: lines to scroll, 2: while holding shift (setq mouse-wheel-progressive-speed nil) ; acceleration (setq mouse-wheel-follow-mouse 't) ; scroll window under cursor (setq scroll-step 1) ; keyboard scrolling ;; Tabs (setq-default indent-tabs-mode nil) (setq-default tab-width 4) (setq indent-line-function 'insert-tab) ;; Recent files (recentf-mode 1) (setq recentf-max-menu-items 25) (setq recentf-max-saved-items 25) ;; Line numbers (setq column-number-mode t) (dolist (mode '(text-mode-hook prog-mode-hook conf-mode-hook)) (add-hook mode (lambda () (display-line-numbers-mode 1)))) ;; Line width indicator (setq-default fill-column 80) (add-hook 'prog-mode-hook #'display-fill-column-indicator-mode) ;;; PACKAGE MANAGEMENT: ;; Install and load straight.el (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) ;; use-package (straight-use-package 'use-package) ;; use-package/straight integration (use-package straight :custom (straight-use-package-by-default t)) ;;; PACKAGES: ;; Automatically set paths to the new user-emacs-directory (use-package no-littering) ;; Automatically clean whitespace (use-package ws-butler :hook ((text-mode . ws-butler-mode) (prog-mode . ws-butler-mode))) ;; Keybindings overview by prefix key (use-package which-key :init (which-key-mode) :config (setq which-key-idle-delay 0.3)) ;; Save history over restarts (use-package savehist :init (savehist-mode)) ;; SSH ;; (use-package tramp ;; :config ;; (setq tramp-default-method "ssh")) ;; Completion with vertico/consult (use-package vertico :init (vertico-mode) ;; Different scroll margin ;; (set vertico-scroll-margin 0) ;; Show more candidates ;; (setq vertico-count 20) ;; Grow and shrink the Vertico minibuffer ;; (setq vertico-resize t) ;; Optionally enable cycling for `vertico-next' and `vertico-previous'. ;; (setq vertico-cycle t) ) (use-package emacs :init ;; Add prompt indicator 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) ;; Do not allow the cursor in the minibuffer prompt (setq minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) ;; Emacs 28: Hide commands in M-x which do not work in the current mode. ;; Vertico commands are hidden in normal buffers. (setq read-extended-command-predicate #'command-completion-default-include-p) (setq enable-recursive-minibuffers t)) (use-package consult :bind (;; C-c bindings (mode-specific-map) ("C-c h" . consult-history) ("C-c m" . consult-mode-command) ("C-c k" . consult-kmacro) ;; C-x bindings (ctl-x-map) ("C-x C-r" . consult-recent-file) ("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 ;; 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 (" a" . consult-apropos) ;; orig. apropos-command ;; M-g bindings (goto-map) ("M-g e" . consult-compile-error) ;; ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck ("M-g f" . 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 (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 m" . consult-multi-occur) ("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 ;; Enable automatic preview at point in the *Completions* buffer. This is ;; relevant when you use the default completion UI. :hook (completion-list-mode . consult-preview-at-point-mode) ;; The :init configuration is always executed (Not lazy) :init ;; Optionally configure the register formatting. This improves the register ;; preview for `consult-register', `consult-register-load', ;; `consult-register-store' and the Emacs built-ins. (setq register-preview-delay 0.5 register-preview-function #'consult-register-format) ;; Optionally tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. (advice-add #'register-preview :override #'consult-register-window) ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. :config ;; Optionally configure preview. The default value ;; is 'any, such that any key triggers the preview. (setq consult-preview-key 'any) ;; (setq consult-preview-key (kbd "M-.")) ;; (setq consult-preview-key (list (kbd "") (kbd ""))) ;; For some commands and buffer sources it is useful to configure the ;; :preview-key on a per-command basis using the `consult-customize' macro. (consult-customize consult-theme :preview-key '(:debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-bookmark consult-recent-file consult-xref consult--source-bookmark consult--source-file-register consult--source-recent-file consult--source-project-recent-file ;; :preview-key (kbd "M-.") :preview-key '(:debounce 0.4 any)) ;; Optionally configure the narrowing key. ;; Both < and C-+ work reasonably well. (setq consult-narrow-key "<") ;; (kbd "C-+") ;; Optionally make narrowing help available in the minibuffer. ;; You may want to use `embark-prefix-help-command' or which-key instead. ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help) ;; By default `consult-project-function' uses `project-root' from project.el. ;; Optionally configure a different project root function. ;; There are multiple reasonable alternatives to chose from. ;;;; 1. project.el (the default) ;; (setq consult-project-function #'consult--default-project--function) ;;;; 2. projectile.el (projectile-project-root) ;; (autoload 'projectile-project-root "projectile") ;; (setq consult-project-function (lambda (_) (projectile-project-root))) ;;;; 3. vc.el (vc-root-dir) ;; (setq consult-project-function (lambda (_) (vc-root-dir))) ;;;; 4. locate-dominating-file ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git"))) ) (use-package consult-flycheck) (use-package consult-git-log-grep :custom (consult-git-log-grep-open-function #'magit-show-commit)) (use-package consult-company :bind (:map company-mode-map ([remap completion-at-point] . consult-company))) (use-package consult-lsp :bind (:map lsp-mode-map ([remap xref-find-apropos] . consult-lsp-symbols))) ;; (use-package consult-projectile) (use-package consult-yasnippet) ;; Alternate completion style (use-package orderless :init ;; Configure a custom style dispatcher (see the Consult wiki) ;; (setq orderless-style-dispatchers '(+orderless-dispatch) ;; orderless-component-separator #'orderless-escapable-split-on-space) (setq completion-styles '(orderless basic) completion-category-defaults nil completion-category-overrides '((file (styles partial-completion))))) ;; Contextual actions (use-package marginalia :config (marginalia-mode)) (use-package embark :bind (("C-." . embark-act) ;; pick some comfortable binding ("C-;" . embark-dwim) ;; good alternative: M-. ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' :init ;; Optionally replace the key help with a completing-read interface (setq prefix-help-command #'embark-prefix-help-command) :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) (use-package embark-consult :hook (embark-collect-mode . consult-preview-at-point-mode)) ;;; ORG-MODE: (dolist (mode '(org-mode-hook)) (add-hook mode (lambda () (display-line-numbers-mode 0)))) (setq org-startup-indented t ; Indentation org-pretty-entities t ; Rich text/Special chars org-hide-emphasis-markers t ; Hide markup - see org-appear org-startup-with-inline-images t ; Image previews org-image-actual-width '(300)) (use-package org-appear :hook (org-mode . org-appear-mode)) (use-package org-superstar :hook (org-mode . org-superstar-mode) :config (setq org-superstar-special-todo-items t)) ;;; APPEARANCE: ;; Theme (setq custom-safe-themes t) (add-to-list 'custom-theme-load-path (expand-file-name "custom/themes/everforest-theme" user-emacs-directory)) (load-theme 'everforest-hard-dark t) ;; (use-package everforest ;; :straight (:type git :repo "https://git.sr.ht/~theorytoe/everforest-theme")) ;; Better distinction between work buffers and others ;; (use-package solaire-mode ;; :init ;; (solaire-global-mode t)) ;; Modeline (use-package minions :hook (doom-modeline-mode . minions-mode) (simple-modeline-mode . minions-mode)) (use-package doom-modeline :init (doom-modeline-mode) :custom (doom-modeline-height 32) ;(doom-modeline-bar-width .75) (doom-modeline-window-width-limit fill-column) (doom-modeline-lsp t) (doom-modeline-minor-modes t) (doom-modeline-persp-name nil) (doom-modeline-buffer-file-name-style 'truncate-upto-project) (doom-modeline-major-mode-icon t) (doom-modeline-major-mode-color-icon t) (doom-modeline-enable-word-count t) (doom-modeline-env-version t) (doom-modeline-env-load-string "...")) ;; Font (use-package mixed-pitch ;:hook ;(org-mode . mixed-pitch-mode) :config {{- if eq .chezmoi.hostname "helix"}} (set-face-attribute 'default nil :font "Hack" :height 180) (set-face-attribute 'fixed-pitch nil :font "Hack" :height 180) (set-face-attribute 'variable-pitch nil :font "DejaVu Sans" :height 200)) {{- else }} (set-face-attribute 'default nil :font "Hack" :height 90) (set-face-attribute 'fixed-pitch nil :font "Hack" :height 90) (set-face-attribute 'variable-pitch nil :font "DejaVu Sans" :height 100)) {{- end }} ;(add-hook 'mixed-pitch-mode-hook #'solaire-mode-reset) ;; Icons (use-package all-the-icons) ;; Hide some minor modes (use-package diminish) ;;; PROJECT MANAGEMENT: ;; Git (use-package magit :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)) ;; Treemacs (use-package treemacs :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))) (use-package lsp-treemacs :config (lsp-treemacs-sync-mode 1)) ;;; UTILITIES: ;; Text completion (use-package company :config (global-company-mode 1) (setq company-global-modes '(not gud-mode)) (setq company-global-modes '(not comint-mode)) :custom (company-idle-delay 0) (company-minimum-prefix-length 1) (company-tooltip-align-annotations t) :bind (:map company-active-map ("RET" . nil) ("[return]" . nil) ("TAB" . company-complete-selection) ("" . company-complete-selection) ("C-n" . company-select-next) ("C-p" . company-select-previous))) ;; Templating (use-package yasnippet :bind ("C-c y s" . yas-insert-snippet) ("C-c y v" . yas-visit-snippet-file) :config (yas-reload-all) (add-to-list 'yas-snippet-dirs (expand-file-name "custom/snippets" user-emacs-directory)) :hook (prog-mode . yas-minor-mode) (tex-mode . yas-minor-mode) (latex-mode . yas-minor-mode)) (use-package yasnippet-snippets) ;;; LANGUAGE SUPPORT: ;; LSP (use-package lsp-mode :init (setq lsp-keymap-prefix "C-c l") :commands (lsp lsp-deferred) :hook ((c-mode . lsp) (c++-mode . lsp) (go-mode . lsp) (java-mode . lsp) (js-mode . lsp) (latex-mode . lsp) (python-mode . lsp) (rust-mode . lsp) (tex-mode . lsp) (typescript-mode . lsp) (web-mode . lsp) (zig-mode . lsp) (lsp-mode . lsp-enable-which-key-integration)) :custom (lsp-eldoc-render-all nil) (lsp-idle-delay 0.6) ;; (lsp-rust-analyzer-cargo-watch-command "clippy") ;; (lsp-rust-analyzer-server-display-inlay-hints t) ;; (lsp-rust-analyzer-display-lifetime-elision-hints-enable "skip_trivial") ;; (lsp-rust-analyzer-display-chaining-hints t) ;; (lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names nil) ;; (lsp-rust-analyzer-display-closure-return-type-hints t) ;; (lsp-rust-analyzer-display-parameter-hints nil) ;; (lsp-rust-analyzer-display-reborrow-hints nil) :config (setq lsp-prefer-flymake nil)) ; prefer lsp-ui (flycheck) to flymake ; (setq lsp-disabled-clients '(clangd))) ; prefer ccls to clangd ; :bind ; (:map lsp-mode-map ; ("TAB" . completion-at-point))) (use-package lsp-ui :requires lsp-mode flycheck :hook (lsp-mode . lsp-ui-mode) :commands lsp-ui-mode :config (setq lsp-ui-doc-enable t) (setq lsp-ui-doc-use-childframe t) (setq lsp-ui-doc-position 'bottom-and-right) (setq lsp-ui-doc-include-signature t) (setq lsp-ui-sideline-enable t) (setq lsp-ui-sideline-show-hover t) (setq lsp-ui-flycheck-enable t) (setq lsp-ui-flycheck-list-position 'right) (setq lsp-ui-flycheck-live-reporting t) (setq lsp-ui-peek-enable t) (setq lsp-ui-peek-list-width 60) (setq lsp-ui-peek-peek-height 25) (lsp-ui-doc-show)) ;; Debugging (use-package dap-mode :after lsp-mode :commands dap-debug :config (dap-ui-mode 1) (dap-tooltip-mode 1) (eval-when-compile (require 'cl-lib)) (require 'dap-python) ;(require 'dap-node) (require 'dap-lldb) (require 'dap-gdb-lldb) (dap-gdb-lldb-setup) (dap-register-debug-template "Rust :: LLDB Run Configuration" (list :type "lldb" :request "launch" :name "LLDB::Run" :gdbpath "rust-lldb")) :bind (:map dap-mode-map ("" . dap-debug) ("" . dap-next) ("" . dap-step-in) ("S-" . dap-disconnect) ("C-S-" . dap-debug-restart))) (use-package realgud) (use-package realgud-lldb) ;; Syntax checking (use-package flycheck :hook (lsp-mode . flycheck-mode) :config (setq flycheck-python-flake8-executable "flake8")) ;; Format on save (use-package apheleia :init (apheleia-global-mode +1)) (use-package reformatter ;; required for zig fmt :after zig-mode) ;; Syntax parsing/highlighting (use native tree-sitter on emacs 29+) (use-package tree-sitter :config (global-tree-sitter-mode) (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode)) (use-package tree-sitter-langs) ;; C/C++ (setq dap-lldb-debug-program '("/usr/bin/lldb-vscode")) (setq-default c-default-style "k&r") (setq-default c-basic-offset 2) ;; (use-package ccls ;; :hook ((c-mode c++-mode objc-mode cuda-mode) . ;; (lambda () (require 'ccls) (lsp)))) (use-package modern-cpp-font-lock :hook (c++-mode . modern-c++-font-lock-mode)) ;; Golang (use-package go-mode :config (add-hook 'before-save-hook #'lsp-organize-imports)) ;; JavaScript/TypeScript, Web (setq css-indent-level 2) (setq css-indent-offset 2) (setq js-indent-level 2) (add-to-list 'auto-mode-alist '("\\.mjs\\'" . js-mode)) (use-package js2-mode :config (add-to-list 'interpreter-mode-alist '("#!/usr/bin/env node" . js2-mode)) ;(setq js2-strict-missing-semi-warning t) (setq js2-mode-show-strict-warnings t) :hook (js-mode . js2-minor-mode)) (use-package typescript-mode :config (setq typescript-indent-level 2) :mode ("\\.ts\\'" . typescript-mode) ("\\.tsx\\'" . typescript-mode)) ;; (use-package restclient ;; :init ;; (use-package company-restclient) ;; :mode ("\\.http\\'" . restclient-mode)) (use-package rainbow-mode :hook ((js-mode . rainbow-mode) (typescript-mode . rainbow-mode) (web-mode . rainbow-mode))) ;; (use-package skewer-mode ;; :init ;; (setq httpd-port 8080) ;; :hook ;; (('js-mode-hook 'skewer-mode) ;; ('css-mode-hook 'skewer-css-mode) ;; ('html-mode-hook 'skewer-html-mode))) ;; (use-package skewer-reload-stylesheets ;; :hook ;; (('css-mode-hook 'skewer-reload-stylesheets-start-editing) ;; ('scss-mode-hook 'skewer-reload-stylesheets-start-editing))) ;; (use-package simple-httpd) (use-package web-mode :config (setq web-mode-code-indent-offset 2) (setq web-mode-markup-indent-offset 2) (setq web-mode-attribute-indent-offset 2) :mode (("\\.phtml\\'" . web-mode) ("\\.tpl\\.php\\'" . web-mode) ("\\.jsp\\'" . web-mode) ("\\.as[cp]x\\'" . web-mode) ("\\.erb\\'" . web-mode) ("\\.mustache\\'" . web-mode) ("\\.djhtml\\'" . web-mode) ("\\.jst.ejs\\'" . web-mode) ("\\.html?\\'" . web-mode))) (use-package jsdoc :straight (jsdoc :type git :host github :repo "isamert/jsdoc.el") :bind ("C-c C-n" . jsdoc)) ;; LaTeX ;(use-package lsp-latex) ;'(setq lsp-tex-server 'digestif) ;; OpenGL / GLSL (use-package glsl-mode) ;; Protocol Buffers (use-package protobuf-mode) ;; Python (setq dap-python-debugger 'debugpy) (use-package lsp-pyright :hook (python-mode . (lambda () (require 'lsp-pyright) (lsp)))) ; or lsp-deferred (use-package numpydoc :after python :bind (:map python-mode-map ("C-c C-n" . numpydoc-generate)) :config (setq numpydoc-insert-examples-block nil)) (use-package conda :init (setq conda-anaconda-home (expand-file-name "/opt/miniconda3")) (setq conda-env-home-directory (expand-file-name "~/.conda/envs")) (conda-env-initialize-interactive-shells) ;(conda-env-autoactivate-mode) :hook ('find-file-hook . (lambda () (when (bound-and-true-p conda-project-env-path) (conda-env-activate-for-buffer))))) ;; Rust (use-package rustic :ensure :bind (:map rustic-mode-map ("M-j" . lsp-ui-imenu) ("M-?" . lsp-find-references) ("C-c C-c l" . flycheck-list-errors) ("C-c C-c a" . lsp-execute-code-action) ("C-c C-c r" . lsp-rename) ("C-c C-c q" . lsp-workspace-restart) ("C-c C-c Q" . lsp-workspace-shutdown) ("C-c C-c s" . lsp-rust-analyzer-status) ("C-c C-c e" . lsp-rust-analyzer-expand-macro) ("C-c C-c d" . dap-hydra) ("C-c C-c h" . lsp-ui-doc-glance))) ;; :config ;; uncomment for less flashiness ;; (setq lsp-eldoc-hook nil) ;; (setq lsp-enable-symbol-highlighting nil) ;; (setq lsp-signature-auto-activate nil) ;; comment to disable rustfmt on save ;; (add-hook 'rustic-mode-hook 'rk/rustic-mode-hook)) ;; (defun rk/rustic-mode-hook () ;; ;; so that run C-c C-c C-r works without having to confirm, but don't try to ;; ;; save rust buffers that are not file visiting. Once ;; ;; https://github.com/brotzeit/rustic/issues/253 has been resolved this should ;; ;; no longer be necessary. ;; (when buffer-file-name ;; (setq-local buffer-save-without-query t)) ;; (add-hook 'before-save-hook 'lsp-format-buffer nil t)) ;; TOML config files (use-package toml-mode) ;; Zig (use-package zig-mode :config (add-to-list 'lsp-language-id-configuration '(zig-mode . "zig")) (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)))) ;;; End init.el