;; -*- lexical-binding: t -*- ;; Copyright © 2018-2024 Uko Koknevics ;; Make sure early-init has been loaded. (unless (boundp 'loaded-early-init) (load (expand-file-name "early-init" (file-name-directory load-file-name)) nil t)) (when (version< emacs-version "29.1") (error "Using %s. Minimum supported version is 29.1." (emacs-version))) (setq-default user-full-name "Uko Kokņevičs" user-email-address "perkontevs@gmail.com") (defconst +linux+ (eq system-type 'gnu/linux)) (defconst +mac+ (eq system-type 'darwin)) (defconst +bsd+ (or +mac+ (eq system-type 'berkeley-unix))) (defconst +windows+ (memq system-type '(cygwin windows-nt ms-dos))) (defconst base-dir user-emacs-directory) (defconst local-dir (expand-file-name "local" base-dir)) (defconst local-config-dir (expand-file-name "config" local-dir)) (defconst tmp-dir (expand-file-name "tmp" local-dir)) (defconst shared-dir (expand-file-name "shared" base-dir)) (setq auto-save-file-name-transforms `((".*" ,tmp-dir t)) backup-directory-alist `((".*" . ,tmp-dir)) custom-file (expand-file-name "custom.el" shared-dir) shared-game-score-directory (expand-file-name "shared-game-score" shared-dir)) (defun $adv-write-to-sane-paths (fn &rest args) "Write 3rd party files to `local-config-dir` to keep `user-emacs-directory` clean." (let ((user-emacs-directory local-config-dir) (user-init-file custom-file)) (apply fn args))) (advice-add #'enable-command :around #'$adv-write-to-sane-paths) (advice-add #'disable-command :around #'$adv-write-to-sane-paths) (advice-add #'locate-user-emacs-file :around #'$adv-write-to-sane-paths) (when (file-exists-p custom-file) (load custom-file)) (add-to-list 'load-path (expand-file-name "arkta" user-emacs-directory)) ;; Improve Emacs security somewhat (setq gnutls-min-prime-bits 3072 gnutls-verify-error (and (fboundp 'gnutls-available-p) (gnutls-available-p) (not (getenv-internal "INSECURE"))) tls-checktrust gnutls-verify-error tls-program '("openssl s_client -connect %h:%p -CAfile %t -nbio -no_ssl3 -no_tls1 -no_tls1_1 -ign_eof" "gnutls-cli -p %p --dh-bits=3072 --ocsp --x509cafile=%t --strict-tofu --priority='SECURE128:+SECURE192:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3' %h" "gnutls-cli -p %p %h")) (when (boundp 'libgnutls-version) (setq gnutls-algorithm-priority (concat "SECURE128:+SECURE192:-VERS-ALL" (if (and (not +windows+) (>= libgnutls-version 30605)) ":+VERS-TLS1.3" ":+VERS-TLS1.2")))) ;; Make sure authinfo is GPG'd (setq auth-sources (list (expand-file-name "authinfo.gpg" local-config-dir) "~/.authinfo.gpp")) ;; Force case sensitivity (if case insensitive, `auto-mode-alist` will be scanned twice). (setq auto-mode-case-fold nil) ;; Don't draw stuff in other windows. (setq-default cursor-in-non-selected-windows nil) (setq highlight-nonselected-windows nil) ;; Faster scrolling (setq fast-but-imprecise-scrolling t) ;; Don't ping random stuff (setq ffap-machine-p-known 'reject) ;; Inhibit frame resizing (setq frame-inhibit-implied-resize t) ;; Don’t compact font caches during GC. (setq inhibit-compacting-font-caches t) (setq read-process-output-max (* 64 1024)) ;; Don't fontify if stuck on reading input (setq redisplay-skip-fontification-on-input t) (when +windows+ (setq w32-get-true-file-attributes nil w32-pipe-read-delay 0 w32-pipe-buffer-size read-process-output-max)) (setq inhibit-startup-screen t inhibit-startup-echo-area-message user-login-name inhibit-default-init t initial-major-mode 'fundamental-mode initial-scratch-message nil) ;; Install straight.el (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 6)) (unless (file-exists-p bootstrap-file) (message "This might take a long time...") (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)) ;; I don't want these (when (fboundp 'tool-bar-mode) (tool-bar-mode -1)) (when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1)) ;; Helper functions (defmacro defsetter (name &rest emacs-names) (let ((name (intern (concat "set-" (symbol-name name))))) `(defun ,name (value &optional default) (if default (progn ,@(mapcar (lambda (name) `(setq-default ,name value)) emacs-names)) ,@(mapcar (lambda (name) `(setq ,name value)) emacs-names))))) (defsetter fill-width fill-column) (defsetter tab-usage indent-tabs-mode) (defsetter tab-width c-basic-offset nasm-offset standard-indent tab-width) ;; Miscellany (set-face-attribute 'default nil :font (if +mac+ "Fira Code Retina" "Fira Code") :height 130) (set-fill-width 120 t) (set-tab-usage nil t) (set-tab-width 4 t) (add-hook 'before-save-hook #'delete-trailing-whitespace) ;; use-package (use-package use-package) ;; HIC SVNT DRACONES (use-package ace-window :straight t :bind (([remap other-window] . ace-window) ("C-x o" . ace-window))) (use-package auto-compile :straight t :hook ((emacs-lisp-mode . auto-compile-on-load-mode) (emacs-lisp-mode . auto-compile-on-save-mode))) (use-package c-ts-mode :after treesit :straight '(c-ts-mode :type built-in) :mode ("\\.c\\'" ("\\.cpp\\'" . c++-ts-mode)) :hook (c-ts-base-mode . (lambda () (set-tab-usage t) (set-tab-width 8))) :custom (c-ts-mode-indent-offset 8) (c-ts-mode-indent-style (lambda () `(((node-is ")") parent-bol 0) ((parent-is "argument_list") parent-bol 8) ((parent-is "parameter_list") parent-bol 8) ,@(alist-get 'linux (c-ts-mode--indent-styles 'c)))))) (use-package centaur-tabs :straight t :hook ((after-init . (lambda () (centaur-tabs-mode +1))) (dashboard-mode . (lambda () (centaur-tabs-local-mode +1)))) :bind (("C-x " . centaur-tabs-forward) ("C-x " . centaur-tabs-forward) ("C-x " . centaur-tabs-backward) ("C-x " . centaur-tabs-backward)) :custom (centaur-tabs-style "alternate") (centaur-tabs-height 35) (centaur-tabs-icon-type 'nerd-icons) (centaur-tabs-set-icons t) (centaur-tabs-gray-out-icons 'buffer) (centaur-tabs-set-bar 'over) (centaur-tabs-set-close-button nil) (centaur-tabs-set-modified-marker t) (centaur-tabs-modified-marker "●") (centaur-tabs-cycle-scope 'tabs)) (use-package cmake-ts-mode :after treesit :straight '(cmake-ts-mode :type built-in) :mode ("CMakeLists\\.txt\\'" "\\.cmake\\'")) (use-package company-mlton :straight '(company-mlton :host github :repo "MatthewFluet/company-mlton") :hook (sml-mode . company-mlton-init)) (use-package company :straight t :custom (company-format-margin-function #'company-text-icons-margin) (company-text-face-extra-attributes '(:weight bold)) (company-text-icons-add-background t) (company-tooltip-flip-when-above nil) (company-tooltip-limit 6) (company-tooltip-minimum 6) (company-tooltip-offset-display 'lines) :config (global-company-mode +1)) (use-package compile :straight '(compile :type built-in) :bind (("C-c k" . compile))) (use-package copyright :straight '(copyright :type built-in) :hook (before-save . (lambda () (save-mark-and-excursion (copyright-update) (copyright-fix-years)))) :custom (copyright-names-regexp "Eris\\|Ukko\\|Uko\\|Free Software") (copyright-year-ranges t)) (use-package counsel :straight t :config (counsel-mode +1)) (use-package csharp-ts-mode :after treesit :straight '(csharp-ts-mode :type built-in) :mode "\\.cs\\'") (use-package css-ts-mode :after treesit :straight '(css-ts-mode :type built-in) :mode "\\.css\\'") (use-package dart-mode :straight t :mode "\\.dart\\'") (use-package dashboard :straight t :hook ((after-init . dashboard-setup-startup-hook) (server-after-make-frame . dashboard-open)) :custom (dashboard-center-content nil) (dashboard-startup-banner (expand-file-name "logo.png" user-emacs-directory)) (dashboard-items '((projects . 5) (recents . 5) (bookmarks . 5))) (dashboard-projects-backend 'project-el) (dashboard-set-heading-icons t) (dashboard-set-file-icons t) (dashboard-set-init-info t)) (use-package display-fill-column-indicator :straight '(display-fill-column-indicator :type built-in) :hook ((after-init . (lambda () (global-display-fill-column-indicator-mode +1))) (dashboard-mode . (lambda () (display-fill-column-indicator-mode -1))))) (use-package display-line-numbers :straight '(display-line-numbers :type built-in) :hook ((after-init . (lambda () (global-display-line-numbers-mode +1))) (help-mode . (lambda () (display-line-numbers-mode -1))))) (use-package dockerfile-ts-mode :after treesit :straight '(dockerfile-ts-mode :type built-in) :mode "Dockerfile\\'") (use-package doom-modeline :straight t :custom (doom-modeline-bar-width 4) (doom-modeline-battery t) (doom-modeline-buffer-file-true-name t) (doom-modeline-height 25) (doom-modeline-hud t) (doom-modeline-hud-min-height 6) (doom-modeline-icon t) (doom-modeline-percent-position nil) (doom-modeline-project-detection 'project) (doom-modeline-total-line-number t) :config (doom-modeline-mode +1)) (use-package ebuild-mode :straight t :mode ("\\.ebuild\\'" "\\.eclass\\'")) (use-package editorconfig :straight t :config (editorconfig-mode +1)) (use-package eglot :straight '(eglot :type built-in) :hook ((gdscript-mode go-ts-mode) . eglot-ensure) :custom (eglot-ignored-server-capabilities . '(:documentFormattingProvider :documentRangeFormattingProvider :documentOnTypeFormattingProvider))) (use-package elixir-mode :straight t :mode "\\.exs?\\'" :hook (elixir-mode . (lambda () (add-hook 'before-save-hook #'elixir-format nil t)))) (use-package emojify :straight t :config (global-emojify-mode +1)) (use-package envrc :straight t :hook (after-init . envrc-global-mode)) (use-package files :straight '(files :type built-in) :custom (major-mode-remap-alist '((c-mode . c-ts-mode) (c-or-c++-mode . c-or-c++-ts-mode) (c++-mode . c++-ts-mode) (cmake-mode . cmake-ts-mode) (csharp-mode . csharp-ts-mode) (css-mode . css-ts-mode) (dockerfile-mode . dockerfile-ts-mode) (go-mode . go-ts-mode) (go-mod-mode . go-mod-ts-mode) (html-mode . mhtml-mode) (java-mode . java-ts-mode) (js-mode . js-ts-mode) (json-mode . json-ts-mode) (python-mode . python-ts-mode) (ruby-mode . ruby-ts-mode) (rust-mode . rust-ts-mode) (yaml-mode . yaml-ts-mode) (toml-mode . toml-ts-mode) (tsx-mode . tsx-ts-mode) (typescript-mode . typescript-ts-mode)))) (use-package gcmh :straight t :custom (gcmh-idle-delay 'auto) (gcmh-auto-idle-delay-factor 10) (gcmh-high-cons-threshold (* 16 1024 1024)) :config (gcmh-mode +1)) (use-package gdscript-mode :straight t :mode "\\.gd\\'") (use-package git-gutter :straight t :config (global-git-gutter-mode +1)) (use-package go-ts-mode :after treesit :straight '(go-ts-mode :type built-in) :mode "\\.go\\'" :hook (go-ts-mode . (lambda () (add-hook 'before-save-hook #'gofmt-before-save nil t)))) (use-package groovy-mode :straight t :mode ("Jenkinsfile\\'" "\\.gradle\\'" "\\.groovy\\'")) (use-package haskell-mode :straight t :mode "\\.hs\\'") (use-package hl-line :straight '(hl-line :type built-in) :config (global-hl-line-mode +1)) (use-package hl-todo :straight t :config (global-hl-todo-mode +1)) (use-package ibuffer :straight '(ibuffer :type built-in) :bind (("C-x C-b" . ibuffer) ([remap list-buffers] . ibuffer))) (use-package ivy :after (counsel swiper) :straight t :hook (after-init . (lambda () (ivy-mode +1))) :bind (("C-c r" . ivy-resume) ("C-c v" . ivy-push-view) ("C-c V" . ivy-pop-view)) :custom (ivy-use-virtual-buffers t) (ivy-count-format "(%d/%d) ")) (use-package java-ts-mode :after treesit :straight '(java-ts-mode :type built-in) :mode "\\.java\\'") (use-package js :after treesit :straight '(js :type built-in) :mode ("\\.js\\'" . js-ts-mode)) (use-package json-ts-mode :after treesit :straight '(json-ts-mode :type built-in) :mode "\\.json\\'") (use-package lua-mode :straight t :custom (lua-indent-level 4) :mode "\\.lua\\'") (use-package magit ;; TODO: Do some proper setup :straight t) (use-package makefile-mode :straight '(makefile-mode :type built-in) :mode (("Makefile\\'" . makefile-gmake-mode) "GNUmakefile\\'" "\\.mk\\(\\.template\\)?\\'")) (use-package markdown-mode :straight t :mode ("\\.md\\'" . gfm-mode)) (use-package modus-themes :straight t :config (load-theme 'modus-operandi)) (use-package nasm-mode :straight t :mode ("\\.asm\\'" "\\.inc\\'") :hook (nasm-mode . (lambda () (set-tab-width 4)))) (use-package nerd-icons :straight t :init (defun arkta/nerd-icons-maybe-install-fonts () (unless (find-font (font-spec :family nerd-icons-font-family)) ;; TODO: Maybe also reinstall them every month or so (nerd-icons-install-fonts t))) :hook (after-init . arkta/nerd-icons-maybe-install-fonts)) (use-package nix-mode :straight t :mode "\\.nix\\'") (use-package nxml-mode :straight '(nxml-mode :type built-in) :mode ("\\.xml\\'" "\\.svg\\'")) (use-package org :straight '(org :type built-in) :bind (("C-c l" . org-store-link) ("C-c a" . org-agenda)) :mode ("\\.org\\'" . org-mode) :init (use-package htmlize :straight t) :custom (org-agenda-files '("~/TODO.org")) (org-log-done t)) (use-package php-mode :straight t :mode "\\.php\\'") (use-package pico8-mode :straight '(pico8-mode :host github :repo "Kaali/pico8-mode") :mode "\\.p8\\'") (use-package prog-mode :straight '(prog-mode :type built-in) :preface (defun prepend-prettify (items) (setq prettify-symbols-alist (append items prettify-symbols-alist)) (prettify-symbols-mode -1) (prettify-symbols-mode +1)) (defun prettify-prog-mode () (prepend-prettify '((">=" . ?≥) ("<=" . ?≤)))) (defun prettify-cc-modes () (prepend-prettify '(("->" . ?→) ("<<" . ?≪) (">>" . ?≫) ("==" . (?= (tc . bc) ??)) ("!=" . (?≠ (tc . bc) ??)) ("^" . ?⊕) ("&&" . ?∧) ("||" . ?∨) ("<<=" . (?≪ (cr . cl) ?=)) (">>=" . (?≫ (cr . cl) ?=)) ("&=" . (?∩ (cr . cl) ?=)) ("|=" . (?∪ (cr . cl) ?=)) ("^=" . (?⊕ (cr . cl) ?=)) ("bool" . ?𝔹) ("_Bool" . ?𝔹) ("int" . ?ℤ) ("float" . ?ℚ) ("true" . ?𝕋) ("_True" . ?𝕋) ("false" . ?𝔽) ("_False" . ?𝔽)))) (defun prettify-lisp-modes () (prepend-prettify '(("lambda" . ?λ) ("lambda*" . (?λ (cr . Bc) ?⋆)) ("->" . ?→) ("=>" . ?⇒)))) :hook (c-mode-common . prettify-cc-modes) :hook (c-ts-base-mode . prettify-cc-modes) :hook (emacs-lisp-mode . prettify-lisp-modes) :hook (lisp-mode . prettify-lisp-modes) :hook (prog-mode . prettify-prog-mode) :hook (scheme-mode . prettify-lisp-modes)) ;; use-package project (require 'arkta-project) (use-package prolog :straight '(prolog :type built-in) :mode ("\\.pl\\'" . prolog-mode)) (use-package python :after treesit :straight '(python :type built-in) :mode ("\\.py\\'" . python-ts-mode)) (use-package rainbow-delimiters :straight t :hook ((emacs-lisp-mode lisp-mode scheme-mode) . rainbow-delimiters-mode)) (use-package rainbow-mode :straight t :hook (prog-mode . (lambda () (rainbow-mode +1)))) (use-package ruby-ts-mode :after treesit :straight '(ruby-ts-mode :type built-in) :mode "\\.rb\\'") (use-package rust-ts-mode :after treesit :straight '(rust-ts-mode :type built-in) :mode "\\.rs\\'") (use-package scala-mode :straight t :mode "\\.scala\\'") (use-package scheme :straight '(scheme :type built-in) :commands scheme-mode :mode ("\\.scm\\'" . scheme-mode) :config (put 'module 'scheme-indent-function 2)) (use-package simple :straight (simple :type built-in) :hook (text-mode . turn-on-auto-fill) :custom (backward-delete-char-untabify-method nil)) (use-package slime :straight t :commands slime :custom (inferior-lisp-program (executable-find "sbcl"))) (use-package smalltalk-mode :straight t :mode "\\.st\\'") (use-package sml-mode :straight t :mode "\\.sml\\'") (use-package solaire-mode :straight t :config (solaire-global-mode +1)) (use-package swiper :straight t :bind (([remap isearch-forward] . swiper-isearch) ([remap isearch-backward] . swiper-isearch-backward) ("C-s" . swiper-isearch) ("C-r" . swiper-isearch-backward))) (use-package time :straight '(time :type built-in) :custom (display-time-default-load-average nil) :config (display-time-mode +1)) (use-package toml-ts-mode :after treesit :straight '(toml-ts-mode :type built-in) :mode "\\.toml\\'") (use-package treemacs :straight t :commands (treemacs treemacs-select-window) :custom (treemacs-select-when-already-in-treemacs 'next-or-back) :bind (("C-c SPC" . treemacs-select-window) ("C-c C-SPC" . treemacs-select-window))) (use-package treesit :straight '(treesit :type built-in) :config (setq treesit-extra-load-path (list (expand-file-name "tree-sitter" local-config-dir))) (setq treesit-language-source-alist '((c "https://github.com/tree-sitter/tree-sitter-c.git") (cmake "https://github.com/uyha/tree-sitter-cmake.git") (cpp "https://github.com/tree-sitter/tree-sitter-cpp.git") (c-sharp "https://github.com/tree-sitter/tree-sitter-c-sharp.git") (css "https://github.com/tree-sitter/tree-sitter-css.git") (dockerfile "https://github.com/camdencheek/tree-sitter-dockerfile.git") (go "https://github.com/tree-sitter/tree-sitter-go.git") (gomod "https://github.com/camdencheek/tree-sitter-go-mod.git") (java "https://github.com/tree-sitter/tree-sitter-java.git") (javascript "https://github.com/tree-sitter/tree-sitter-javascript.git") (json "https://github.com/tree-sitter/tree-sitter-json.git") (python "https://github.com/tree-sitter/tree-sitter-python.git") (ruby "https://github.com/tree-sitter/tree-sitter-ruby.git") (rust "https://github.com/tree-sitter/tree-sitter-rust.git") (toml "https://github.com/ikatyang/tree-sitter-toml.git") (tsx "https://github.com/tree-sitter/tree-sitter-typescript.git" nil "tsx/src") (typescript "https://github.com/tree-sitter/tree-sitter-typescript.git" nil "typescript/src") (yaml "https://github.com/ikatyang/tree-sitter-yaml.git"))) (mapc (lambda (spec) (let ((name (car spec))) (unless (treesit-language-available-p name) (treesit-install-language-grammar name)))) treesit-language-source-alist)) (use-package typescript-ts-mode :after treesit :straight '(typescript-ts-mode :type built-in) :mode "\\.ts\\'") (use-package typst-mode :straight t :mode "\\.typ\\'") (use-package yaml-ts-mode :after treesit :straight '(yaml-ts-mode :type built-in) :mode "\\.ya?ml\\'") (use-package zig-mode :straight t :mode "\\.zig\\'")