dotfiles/dot_config/emacs/init.el

750 lines
25 KiB
EmacsLisp

;;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*-
;; Author: Andrew Scott <git at andyscott dot me>
;; Keywords: convenience, tools
;; URL: https://codeberg.org/andyscott/dotfiles
;; This file is not part of GNU Emacs.
;; Copyright (c) 2023 Andrew Scott
;; 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.
;;; Commentary:
;; My Emacs initialization file.
;;; Code:
;; Profile init time
;; Replace `emacs-startup-hook' w/ `elpaca-after-init-hook' to profile `Elpaca'
(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)))
;; View profiler report after init
;; (profiler-start 'cpu+mem)
;; (add-hook 'elpaca-after-init-hook (lambda () (profiler-stop) (profiler-report)))
;; Profile function performance
;; (require 'elp)
;; (with-eval-after-load file
;; (elp-instrument-package file))
;; (add-hook 'elpaca-after-init-hook
;; (lambda () (elp-results) (elp-restore-package (intern file))))
;; Elpaca
(defvar elpaca-installer-version 0.7)
(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 :depth 1
:files (:defaults "elpaca-test.el" (: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 (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(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))
;; Configure `use-package' with `Elpaca'
(defmacro use-feature (name &rest args)
"Like `use-package' but accounting for asynchronous installation.
NAME and ARGS are in `use-package'. Credit to @progfolio:
https://github.com/progfolio/.emacs.d?tab=readme-ov-file#use-package"
(declare (indent defun))
`(use-package ,name
:ensure nil
,@args))
(elpaca elpaca-use-package
(require 'elpaca-use-package)
(elpaca-use-package-mode)
(setopt use-package-always-ensure t))
(if debug-on-error
(setopt use-package-verbose t
use-package-expand-minimally nil
use-package-compute-statistics t)
(setopt use-package-verbose nil
use-package-expand-minimally t))
;; TODO - remove this when done profiling startup
(setopt use-package-compute-statistics t)
;; Wait for `Elpaca' to process current queue
(elpaca-wait)
;;; Built-in Packages:
;; Revert a buffer if the file has changed
(use-feature autorevert
:config (global-auto-revert-mode t)
:defer 3
:init (setopt auto-revert-interval 0.01))
;; Customize compilation & related buffers
(use-feature compile
:commands (compile recompile)
:config (setopt compilation-ask-about-save nil
compilation-scroll-output 'first-error))
;; Write external customizations to /dev/null
(use-feature cus-edit
:init (setopt custom-file null-device))
;; Customize fill column indicator
(use-feature display-fill-column-indicator
:hook ((conf-mode
markdown-mode
prog-mode) . display-fill-column-indicator-mode))
;; Customize line number display
(use-feature display-line-numbers
:hook ((conf-mode
prog-mode) . display-line-numbers-mode))
;; Customize LSP options
(use-feature eglot
:bind
(:map eglot-mode-map
("C-c c a" . eglot-code-actions)
("C-c c o" . eglot-code-actions-organize-imports)
("C-c c r" . eglot-rename)
("C-c c f" . eglot-format))
:config
(push '(astro-mode . ("astro-ls" "--stdio"
:initializationOptions
(:typescript (:tsdk "/usr/lib/node_modules/typescript/lib")))) eglot-server-programs)
(push '((rust-ts-mode rust-mode) . ("rustup" "run" "stable" "rust-analyzer"
:initializationOptions
(:check (:command "clippy")))) eglot-server-programs)
(setopt eglot-autoshutdown t
eglot-ignored-server-capabilities
'(;; :colorProvider ; "Decorate color references"
;; :documentFormattingProvider ; "Format buffer"
;; :documentHighlightProvider ; "Highlight symbols automatically"
:documentOnTypeFormattingProvider ; "On-type formatting"
;; :documentRangeFormattingProvider ; "Format portion of buffer"
;; :hoverProvider ; "Documentation on hover"
:inlayHintProvider ; "Inlay hints"
))
:hook ((astro-mode
c-ts-mode
c++-ts-mode
rust-ts-mode
zig-mode) . eglot-ensure))
;; Automatic parenthesis/brackets matching
(use-feature elec-pair
:hook ((conf-mode
markdown-mode
prog-mode) . electric-pair-mode))
;; Options defined in C source code & other misc. global customizations
(use-feature emacs
:bind
(:map global-map
;; Disable `suspend-frame' shortcut
("C-z" . nil)
;; Escape behaves like C-g
("<escape>" . keyboard-escape-quit)
;; Resizing buffers
("S-C-<left>" . shrink-window-horizontally)
("S-C-<right>" . enlarge-window-horizontally)
("S-C-<down>" . shrink-window)
("S-C-<up>" . enlarge-window))
:config
(setopt cursor-type 'bar
fill-column 80
scroll-step 1
scroll-conservatively 1000
scroll-preserve-screen-position t)
:init
;; Vertico
(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)
(setopt enable-recursive-minibuffers t ; Recursive minibuffers
minibuffer-prompt-properties ; Disable prompt in minibuffer
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode))
;; Customize file handling & automatic backups
(use-feature files
:config
(let ((auto_save_directory (concat xdg_cache_home "auto-save-list/")))
(unless (file-directory-p auto_save_directory)
(make-directory auto_save_directory))
(setopt backup-directory-alist `((".*" . ,auto_save_directory))
auto-save-file-name-transforms `((".*" ,auto_save_directory t))))
(setopt backup-by-copying t
confirm-kill-processes nil
delete-old-versions t
kept-new-versions 5
kept-old-versions 3
require-final-newline t
version-control t))
;; Customize syntax checking
(use-feature flymake
:bind
(:map flymake-mode-map
("C-c f d" . flymake-show-buffer-diagnostics)
("C-c f D" . flymake-show-project-diagnostics)
("C-c f n" . flymake-goto-next-error)
("C-c f p" . flymake-goto-prev-error)))
;; Customize spell checking
(use-feature flyspell
:hook
(((git-commit-mode
org-mode
text-mode) . flyspell-mode)
(prog-mode . flyspell-prog-mode)))
;; Customize frame behavior/cursor blinking
(use-feature frame
:config (setopt blink-cursor-delay 1.0
blink-cursor-interval 0.75))
;; Ensure UTF-8 terminal encoding
(use-feature mule
:config (unless (display-graphic-p)
(set-terminal-coding-system 'utf-8)))
;; Customize mouse wheel
(use-feature mwheel
:config
(setopt mouse-wheel-follow-mouse t
mouse-wheel-progressive-speed nil
mouse-wheel-scroll-amount '(2 ((shift) . 1))))
;; Visualize matching parenthesis/brackets
(use-feature paren
:hook ((conf-mode
markdown-mode
prog-mode) . show-paren-mode))
;; Enable smooth mouse wheel scrolling when available
(when (fboundp 'pixel-scroll-precision-mode)
(use-feature pixel-scroll
:config (pixel-scroll-precision-mode)))
(use-feature project
:config (setopt project-vc-extra-root-markers '("Cargo.toml")))
;; Customize handling of recent files
(use-feature recentf
:config
(setopt recentf-max-menu-items 100
recentf-max-saved-items 1000
recentf-save-file (concat xdg_cache_home "recentf"))
(recentf-mode))
;; Customize saving mini-buffer history
(use-feature savehist
:config
(setopt savehist-autosave-interval 120
savehist-file (concat xdg_cache_home "history"))
(savehist-mode))
;; Customize saving place in files
(use-feature saveplace
:config
(setopt save-place-file (concat xdg_cache_home "places"))
(save-place-mode))
;; Unload `seq' before `Elpaca' starts building
;; https://github.com/progfolio/elpaca/issues/216#issuecomment-1868444883
(defun +elpaca-unload-seq (e)
(and (featurep 'seq) (unload-feature 'seq t))
(elpaca--continue-build e))
(defun +elpaca-seq-build-steps ()
(append (butlast (if (file-exists-p (expand-file-name "seq" elpaca-builds-directory))
elpaca--pre-built-steps elpaca-build-steps))
(list '+elpaca-unload-seq 'elpaca--activate-package)))
(use-package seq
:ensure `(seq :build ,(+elpaca-seq-build-steps)))
;; "A grab-bag of basic Emacs commands"
(use-feature simple
:config
(setopt indent-tabs-mode nil
read-extended-command-predicate #'command-completion-default-include-p)
:hook
(((conf-mode
prog-mode) . column-number-mode)
(text-mode . auto-fill-mode)))
;; Customize text buffers
(use-feature text-mode
:config (setq-local fill-column 120))
;; Customize tree-sitter parsing
(use-feature treesit
:config
(push '(c++-mode . c++-ts-mode) major-mode-remap-alist)
(setopt treesit-font-lock-level 4))
;; Customize whitespace visualization & cleanup
(use-feature whitespace
:config
(add-hook 'before-save-hook #'whitespace-cleanup)
(setopt whitespace-line-column nil
whitespace-style '(face
lines-char
missing-newline-at-eof
space-after-tab
space-before-tab
tabs
trailing))
:hook
((conf-mode
prog-mode
text-mode) . whitespace-mode))
;;; Packages:
;; Shows current/total matches in mode line
(use-package anzu
:config (global-anzu-mode)
:defer 3)
;; Auto-format
(use-package apheleia
:defer t)
;; Extensions for `completion-at-point'
(use-package cape
:bind ("M-p" . cape-prefix-map))
;; Catppuccin theme
(use-package catppuccin-theme
:config
(setopt custom-safe-themes t
catppuccin-flavor 'macchiato)
(catppuccin-reload)
(load-theme 'catppuccin t))
;; Search and navigation
(use-package consult
: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
:init
;; Register formatting
(setopt 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
(setopt xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref))
;; UI for the workspace/symbols procedure calls
(use-package consult-eglot
:after (eglot)
:bind
(:map eglot-mode-map
("C-c c s" . consult-eglot-symbols)))
;; In-buffer completion
(use-package company
:bind
(:map company-active-map
("RET" . nil)
("[return]" . nil)
("TAB" . company-complete-selection)
("<tab>" . company-complete-selection)
("C-n" . company-select-next)
("C-p" . company-select-previous))
:config
(setopt company-global-modes '(not gud-mode not comint-mode)
company-tooltip-align-annotations t)
:hook (prog-mode . company-mode))
;; FIXME - I crash emacs
(use-package corfu
:disabled
:bind
(:map corfu-map
("M-SPC" . corfu-insert-separator)
("RET" . nil))
:config
(setopt corfu-auto t
corfu-cycle t)
(global-corfu-mode)
(corfu-popupinfo-mode)
:defer 3
:ensure (corfu :files (:defaults "extensions/*")))
;; Use `emacs-lsp-booster' with `Eglot'
(use-package eglot-booster
:after eglot
:config (eglot-booster-mode)
:ensure (eglot-booster :host github :repo "jdtsmith/eglot-booster"))
;; Command menu for items around point
(use-package embark
: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)
:defer 3
:init (setopt prefix-help-command #'embark-prefix-help-command))
(use-package embark-consult
:hook (embark-collect-mode . consult-preview-at-point-mode))
;; Correction functions for `flyspell'
(use-package flyspell-correct
:after (flyspell)
:bind
(:map flyspell-mode-map
("C-M-." . flyspell-correct-wrapper)))
;; Highlight keywords
(use-package hl-todo
:bind
(:map hl-todo-mode-map
("C-c t p" . hl-todo-previous)
("C-c t n" . hl-todo-next)
("C-c t o" . hl-todo-occur)
("C-c t i" . hl-todo-insert))
:config
(setopt hl-todo-highlight-punctuation ":!?"
hl-todo-keyword-faces '(("DEBUG" warning bold)
("HACK" warning bold)
("FIXME" error bold)
("NOTE" highlight italic)
("REVIEW" highlight italic)
("TODO" bookmark-face bold)))
:ensure (hl-todo :depth nil)
:hook (prog-mode . hl-todo-mode))
;; Icons for `corfu'
(use-package kind-icon
:disabled
:after (corfu)
:config
(push #'kind-icon-margin-formatter corfu-margin-formatters)
(setopt kind-icon-default-face 'corfu-default))
;; Git
(use-package transient ; Must declare before magit
:defer t)
(use-package magit
:bind ("C-M-;" . magit-status)
:config
(setopt magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1
transient-history-file (concat xdg_cache_home "transient-history")))
(use-package magit-todos
:hook (magit-mode . magit-todos-mode))
;; Better annotations
(use-package marginalia
:config (marginalia-mode)
:defer 1)
;;; File format/markup support
(use-package markdown-mode
:commands (markdown-mode)
:config (setq-local fill-column 120))
;; Better C++ font locking
(use-package modern-cpp-font-lock
:hook (c++-ts-mode . modern-c++-font-lock-mode))
;; Mode line
(use-package moody
: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)
:defer 1)
(use-package minions
:after (moody)
:config (minions-mode))
;; Various nerd icon packages
(use-package nerd-icons
:defer 1)
(use-package nerd-icons-completion
:after (nerd-icons marginalia)
:config (nerd-icons-completion-mode)
:hook (marginalia-mode . nerd-icons-completion-marginalia-setup))
(use-package nerd-icons-corfu
:after (nerd-icons corfu)
:config (push #'nerd-icons-corfu-formatter corfu-margin-formatters))
(use-package nerd-icons-dired
:hook (dired-mode . nerd-icons-dired-mode))
(use-package nerd-icons-ibuffer
:hook (ibuffer-mode . nerd-icons-ibuffer-mode))
;; Completion style
(use-package orderless
:config
(setopt completion-styles '(orderless basic)
completion-category-overrides '((file (styles basic partial-completion)))
orderless-matching-styles '(orderless-regexp
orderless-literal
orderless-initialism))
:defer 1)
;; Project Management
(use-package projectile
:disabled
:bind ("C-c p" . projectile-command-map)
:config
(setopt projectile-known-projects-file (concat xdg_cache_home "projectile-bookmarks")
projectile-project-search-path '(("~/Nextcloud/Projects/src/" . 2)))
(push "*node_modules" projectile-globally-ignored-directories)
(projectile-mode))
;; Visualize color names
(use-package rainbow-mode
:hook ((conf-mode
prog-mode
toml-ts-mode) . rainbow-mode))
;; `gud' rewrite with additional features
(use-package realgud
:defer t)
;; `realgud' front-end for LLDB
(use-package realgud-lldb
:defer t)
(use-package rust-mode
:init (setopt rust-mode-treesitter-derive t)
:commands (rust-mode))
;; Automatically download tree-sitter grammars
(use-package treesit-auto
:defer 1
:config
(setopt treesit-auto-install t)
(setq as/c-tsauto-config
(make-treesit-auto-recipe
:lang 'c
:ts-mode 'c-ts-mode
:remap 'c-mode
:url "https://github.com/tree-sitter/tree-sitter-c"
:revision "v0.20.7"
:ext "\\.c\\'"))
(setq as/cpp-tsauto-config
(make-treesit-auto-recipe
:lang 'cpp
:ts-mode 'c++-ts-mode
:remap 'c++-mode
:url "https://github.com/tree-sitter/tree-sitter-cpp"
:revision "v0.21.0"
:ext "\\.cpp\\'"))
(push as/c-tsauto-config treesit-auto-recipe-list)
(push as/cpp-tsauto-config treesit-auto-recipe-list)
;;(add-to-list 'treesit-auto-recipe-list as/cpp-tsauto-config)
(treesit-auto-add-to-auto-mode-alist 'all)
(global-treesit-auto-mode))
;; Better undo/redo
(use-package undo-fu
:bind (("C-z" . undo-fu-only-undo)
("C-M-z" . undo-fu-only-redo))
:defer 1)
(use-package undo-fu-session
:after (undo-fu)
:config
(setopt undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")
undo-fu-session-directory (concat xdg_cache_home "undo-fu-session/"))
(undo-fu-session-global-mode))
;; Mini-buffer completion UI
(use-package vertico
:config
(setopt 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)
:init (vertico-mode))
;; Web and SSG
(define-derived-mode astro-mode web-mode "astro")
(use-package web-mode
:config
(setopt web-mode-attribute-indent-offset 2
web-mode-code-indent-offset 2
web-mode-css-indent-offset 2
web-mode-markup-indent-offset 2
web-mode-enable-front-matter-block t
web-mode-engines-alist '(("blade" . "\\.blade\\.")
("razor" . "\\.cshtml\\'")))
:mode
("\\.astro\\'" . astro-mode)
("\\.\\(cshtml\\|html?\\|razor\\)\\'" . web-mode))
;; Show keybind hints
(use-package which-key
:config
(setopt which-key-idle-delay 0.3
;; which-key-sort-order 'which-key-description-order
which-key-side-window-max-width 0.33)
(which-key-mode)
:defer 1)
;; Expand abbreviations to templates
(use-package yasnippet
:bind
(:map yas-minor-mode-map
("C-c y i" . yas-insert-snippet)
("C-c y v" . yas-visit-snippet-file))
:config (yas-reload-all)
:hook (prog-mode . yas-minor-mode))
(use-package yasnippet-snippets
:after (yasnippet))
(use-package consult-yasnippet
:after (yasnippet)
:bind
(:map yas-minor-mode-map
("C-c y c" . consult-yasnippet)))
;; YAML
(use-package yaml-pro
:hook (yaml-ts-mode . yaml-pro-ts-mode))
;; Zig
(use-package reformatter ; required for `zig-format' functions
:after (zig-mode))
(use-package zig-mode
:commands (zig-mode)
:config
(defun zig-compile ()
(interactive)
(save-buffer)
(zig--run-cmd "build"))
(setq-local fill-column 100)
(setopt zig-format-on-save nil))
(push "~/.config/emacs/lisp/" load-path)
(require 'init-org)
;;; init.el ends here