;;;; Tabs, indentation, and the TAB key (use-package emacs :ensure nil :demand t :config (setq tab-always-indent 'complete) (setq tab-first-completion nil) (setq-default tab-width 4 indent-tabs-mode nil) (electric-pair-mode 1)) ;;;; Parentheses (show-paren-mode) (use-package paren :ensure nil :hook (prog-mode . show-paren-local-mode) :config (setq show-paren-style 'mixed) (setq show-paren-when-point-in-periphery nil) (setq show-paren-when-point-inside-paren nil) (setq show-paren-context-when-offscreen 'overlay)) ; Emacs 29 ;;;; Eldoc (Emacs live documentation feedback) (use-package eldoc :ensure nil :hook (prog-mode . eldoc-mode) :config (setq eldoc-message-function #'message)) ; don't use mode line for M-x eval-expression, etc. ;;;; Eglot (built-in client for the language server protocol) (use-package eglot :ensure nil :demand t ;; Not a mistake, we need to load Eglot elisp code before ;; we open any Python file. :functions (eglot-ensure) :commands (eglot) :bind ( :map eglot-mode-map ("C-c e r" . eglot-rename) ("C-c e o" . eglot-code-action-organize-imports) ("C-c e d" . eldoc) ("C-c e c" . eglot-code-actions) ("C-c e f" . eglot-format) ;; Since eglot plugs into flymake anyway ("C-c e l" . flymake-show-buffer-diagnostics)) :config (setq eglot-sync-connect nil) (setq eglot-autoshutdown t) (setq eglot-extend-to-xref t)) ;;; Markdown (markdown-mode) (use-package markdown-mode :ensure t :defer t :config (setq markdown-fontify-code-blocks-natively t)) ;;; csv-mode (use-package csv-mode :ensure t :commands (csv-align-mode)) ;;; Flyspell (use-package flyspell :ensure nil :bind ( :map flyspell-mode-map ("C-;" . nil) :map flyspell-mouse-map ("<mouse-3>" . flyspell-correct-word)) :config (setq flyspell-issue-message-flag nil) (setq flyspell-issue-welcome-flag nil) (setq ispell-program-name "aspell") (setq ispell-dictionary "en_GB")) ;;; Flymake (use-package flymake :ensure nil :bind ( :map flymake-mode-map ("C-c ! s" . flymake-start) ("C-c ! l" . flymake-show-buffer-diagnostics) ; Emacs28 ("C-c ! L" . flymake-show-project-diagnostics) ; Emacs28 ("C-c ! n" . flymake-goto-next-error) ("C-c ! p" . flymake-goto-prev-error)) :hook (prog-mode . turn-on-flymake) :config (defun turn-on-flymake () (flymake-mode t)) (setq flymake-fringe-indicator-position 'left-fringe) (setq flymake-suppress-zero-counters t) (setq flymake-no-changes-timeout nil) (setq flymake-start-on-flymake-mode t) (setq flymake-start-on-save-buffer t) (setq flymake-proc-compilation-prevents-syntax-check t) (setq flymake-wrap-around nil) (setq flymake-mode-line-format '("" flymake-mode-line-exception flymake-mode-line-counters)) (setq flymake-mode-line-counter-format '("" flymake-mode-line-error-counter flymake-mode-line-warning-counter flymake-mode-line-note-counter "")) (setq flymake-show-diagnostics-at-end-of-line nil) ; Emacs 30 (remove-hook 'flymake-diagnostic-functions #'flymake-proc-legacy-flymake)) ;;; Elisp packaging requirements (use-package package-lint-flymake :ensure t :after flymake :config ;; We can't use `use-package' :hook because the hookname does not ;; end in -hook. (add-hook 'flymake-diagnostic-functions #'package-lint-flymake)) ;;; General configurations for prose/writing ;;;; `outline' (`outline-mode' and `outline-minor-mode') (use-package outline :ensure nil :bind ("<f10>" . outline-minor-mode) :config (setq outline-minor-mode-highlight nil) ; emacs28 (setq outline-minor-mode-cycle t) ; emacs28 (setq outline-minor-mode-use-buttons nil) ; emacs29---bless you for the nil option! (setq outline-minor-mode-use-margins nil)) ; as above ;;;; `dictionary' (use-package dictionary :ensure nil :config (setq dictionary-server "dict.org" dictionary-default-popup-strategy "lev" ; read doc string dictionary-create-buttons nil dictionary-use-single-buffer t)) (use-package paredit :ensure t :bind ( :map paredit-mode-map ("C-o" . paredit-open-round) ("M-D" . paredit-splice-sexp) ("C-A-d" . paredit-forward-down) ("C-A-u" . paredit-backward-up) ;; Unbind things that I don't need ("M-s" . nil) ; used for search related keybindings ("M-?" . nil) ; `xref-find-references' uses it. ("RET" . nil)); `ielm-return' uses it. :hook ((lisp-data-mode lisp-mode clojure-mode clojure-ts-mode cider-repl-mode inferior-emacs-lisp-mode) . paredit-mode)) (use-package apheleia :ensure t :demand t :after blackout :config (apheleia-global-mode +1) (with-eval-after-load 'apheleia-formatters (push '(zprint . ("zprint")) apheleia-formatters)) :hook (apheleia-mode . (lambda () (blackout 'apheleia-mode)))) (use-package multiple-cursors :ensure t :bind ("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("C-c C->" . mc/mark-all-like-this)) (use-package lsp-mode :ensure t :demand t :commands lsp :init (defun my/lsp-mode-setup-completion () (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults)) '(flex))) ;; Configure flex :bind (("C-c C-c Q" . lsp-workspace-shutdown) ("C-c C-c q" . lsp-workspace-restart)) :config (setq lsp-log-io nil lsp-semgrep-server-command nil lsp-completion-provider :none lsp-inlay-hint-enable t lsp-modeline-diagnostics-enable nil lsp-semantic-tokens-enable t lsp-semantic-tokens-warn-on-missing-face nil lsp-treemacs-error-list-current-project-only t lsp-ui-sideline-delay 0.1 lsp-ui-sideline-diagnostic-max-line-length 50 lsp-ui-sideline-enable nil lsp-ui-sideline-show-code-actions t lsp-ui-sideline-update-mode 'line lsp-eldoc-render-all t lsp-idle-delay 0.2 lsp-enable-snippet t read-process-output-max (* 1024 1024)) :hook ( (lsp-mode . lsp-enable-which-key-integration) (lsp-mode . subword-mode) (lsp-completion-mode . my/lsp-mode-setup-completion) ;;(before-save . lsp-format-buffer) )) (use-package cargo :ensure t) (use-package rustic :ensure t :bind (:map rustic-mode-map ("M-?" . lsp-find-references) ("C-c C-c a" . lsp-execute-code-action) ("C-c C-c r" . lsp-rename) ("C-c C-c l" . flycheck-list-errors) ("C-c C-c s" . lsp-rust-analyzer-status)) :hook rust-ts-mode :config (setq rustic-format-on-save t rust-indent-method-chain t rustic-format-trigger 'on-save rustic-lsp-format t rustic-lsp-client 'lsp) (setq-local buffer-save-without-query t) (setq-local lsp-semantic-tokens-enable t)) (use-package lsp-mode :ensure nil :defer t :config (setq lsp-rust-all-targets nil lsp-rust-analyzer-cargo-all-targets nil lsp-rust-analyzer-import-merge-behaviour "full" lsp-rust-analyzer-completion-auto-import-enable t lsp-rust-rustfmt-path "/home/ardent/.cargo/bin/rustfmt" lsp-rust-unstable-features t lsp-rust-analyzer-cargo-watch-command "clippy" lsp-rust-analyzer-server-display-inlay-hints t lsp-rust-analyzer-call-info-full t lsp-rust-analyzer-proc-macro-enable 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 t lsp-rust-analyzer-display-closure-return-type-hints t lsp-rust-analyzer-display-parameter-hints nil lsp-rust-analyzer-display-reborrow-hints t)) ;;;; Configuration for Python Programming (use-package python :ensure nil ;;; Uncomment this if you want Eglot to start automatically. I prefer ;;; calling `M-x eglot' myself. ;; :hook ((python-base-mode . eglot-ensure)) :config (setq python-shell-dedicated 'project) ;; Apheleia is an Emacs package for formatting code as you save ;; it. Here we are asking Apheleia to use Ruff for formatting our ;; Python code. (with-eval-after-load 'apheleia (setf (alist-get 'python-mode apheleia-mode-alist) '(ruff-isort ruff)) (setf (alist-get 'python-ts-mode apheleia-mode-alist) '(ruff-isort ruff)))) (use-package pet :ensure (:host github :repo "vedang/emacs-pet" :branch "fix-eglot-integration" ;; :remotes (("upstream" :repo "wyuenho/emacs-pet" :branch "main")) ) :ensure-system-package (dasel sqlite3) :config ;; The -10 here is a way to define the priority of the function in ;; the list of hook functions. We want `pet-mode' to run before any ;; other configured hook function. (add-hook 'python-base-mode-hook #'pet-mode -10)) ;;;; Configuration for Zig Programming (use-package zig-mode :ensure t ;;; Uncomment this if you want Eglot to start automatically. I don't ;;; recommend it, but that's just me. ;; :hook ((zig-mode . eglot-ensure)) ) ;;; Configuration for Clojure programming (use-package clojure-mode :ensure t) ;;; `clojure-ts-mode' is not stable enough right now. In particular, ;;; it clashes with `paredit-mode' sometimes, leading to Paredit ;;; throwing unbalanced-expression errorsand being unusable. So ;;; keeping this disabled and experimenting with how to fix it, for ;;; them moment. (defvar enable-clojure-ts-mode nil) (when (and (treesit-available-p) enable-clojure-ts-mode) (use-package clojure-ts-mode :ensure t)) ;;;; Cider provides tooling over nREPL for Clojure programming (use-package cider :ensure t :after (:any clojure-mode clojure-ts-mode) :config (defun cider-repl-prompt-on-newline (ns) "Return a prompt string with newline. NS is the namespace information passed into the function by cider." (concat ns ">\n")) (setq cider-repl-prompt-function #'cider-repl-prompt-on-newline)) ;;;; clj-refactor enables smart refactoring of Clojure code (use-package clj-refactor :ensure t :after (:any clojure-mode clojure-ts-mode) :hook ((clojure-mode . clj-refactor-mode) (clojure-ts-mode . clj-refactor-mode)) :config (cljr-add-keybindings-with-prefix "C-c m") ;; Don't magically add stuff to the namespace requires form (because ;; for big projects this operation is slow) it's easier to do this ;; by hand (=add-missing= operation) after you've typed out what you ;; wanted to. (setq cljr-magic-requires nil)) ;;;; flymake-kondor integrates flymake with clj-kondo, so that we get ;;;; great linting without needing to start a REPL or LSP server. (use-package flymake-kondor :ensure t :after (:any clojure-mode clojure-ts-mode flymake) :ensure-system-package (clj-kondo) :hook ((clojure-mode . flymake-kondor-setup) (clojure-ts-mode . flymake-kondor-setup))) ;;;; clojure-snippets are handy yasnippets for fast coding (use-package clojure-snippets :ensure t :after clojure-mode) ;;;; jet is an external tool to convert between json, transit and edn (use-package jet :ensure t :config (defun json->edn () "Convert the selected region, or entire file, from JSON to EDN." (interactive) (let ((b (if mark-active (region-beginning) (point-min))) (e (if mark-active (region-end) (point-max))) (jet (when (executable-find "jet") "jet --pretty --keywordize keyword --from json --to edn"))) (if jet (let ((p (point))) (shell-command-on-region b e jet (current-buffer) t) (goto-char p)) (user-error "Could not find jet installed"))))) (use-package geiser-guile :ensure t) (use-package macrostep-geiser :ensure t :after geiser-repl :config (add-hook 'geiser-repl-mode-hook #'macrostep-geiser-setup)) ;;; Settings for Interaction mode for Emacs-Lisp (use-package ielm :ensure nil :bind ( :map ielm-map ("C-j" . newline-and-indent))) (provide 'nebkor-langs)