(load-file ".config/emacs/init-elpaca.el") (defun git-tracked-file-p (filename) "Check whether the file FILENAME is tracked by git." (let ((dirname (file-name-parent-directory filename))) (zerop (call-process "git" nil nil nil "-C" dirname "ls-files" "--error-unmatch" filename)))) (defun find-init-file () "Find the user's init file" (interactive) (find-file user-init-file)) (use-package emacs :ensure nil :bind (("C-z" . nil) ("C-z i" . find-init-file) ("C-z f" . ffap)) :hook ((after-save . executable-make-buffer-file-executable-if-script-p) (xref-after-update . outline-minor-mode)) :init (setq load-path (append (list (expand-file-name "~/Projects/lilypond/elisp")) load-path)) :config ; keep-sorted start (defalias 'yes-or-no-p 'y-or-n-p) (display-battery-mode) (display-time-mode) (load "lilypond-init.el") (prefer-coding-system 'utf-8) (put 'dired-find-alternate-file 'disabled nil) (set-default-file-modes #o750) (which-key-mode) (windmove-default-keybindings 'super) ; keep-sorted end :custom ; keep-sorted start (auto-save-interval 20) (auto-save-visited-mode t) (auto-save-visited-predicate (lambda () (git-tracked-file-p buffer-file-name))) (column-number-mode t) (dired-dwim-target 'dired-dwim-target-next) (display-time-24hr-format t) (display-time-day-and-date t) (global-auto-revert-mode t) (global-auto-revert-non-file-buffers t) (inhibit-startup-screen t) (show-paren-context-when-offscreen 'overlay) (xref-search-program 'ripgrep) ; keep-sorted end ) (use-package better-defaults :ensure (:repo "https://git.sr.ht/~technomancy/better-defaults")) (use-package treemacs-icons-dired :hook (dired-mode . treemacs-icons-dired-mode)) (use-package dired-subtree :after dired :bind (:map dired-mode-map ("" . dired-subtree-toggle) ("" . dired-subtree-cycle) ("" . dired-subtree-remove)) :config ; keep-sorted start (defadvice dired-subtree-cycle (after add-icons activate) (revert-buffer)) (defadvice dired-subtree-toggle (after add-icons activate) (revert-buffer)) ; keep-sorted end :custom (dired-subtree-use-backgrounds nil)) (use-package undo-tree :ensure (:repo "https://gitlab.com/tsc25/undo-tree") :init (global-undo-tree-mode) :custom (undo-tree-history-directory-alist '(("." . "~/.config/emacs/undo-tree")))) (use-package transient) (use-package magit :bind (("C-x g" . magit-status) ("C-x M-g" . magit-list-repositories)) :init (require 'magit-extras) :custom (magit-repository-directories '(("~/" . 0) ("~/Projects/" . 1)))) (use-package nyan-mode :init (nyan-mode 1) :custom (nyan-animate-nyancat t) (nyan-wavy-trail t)) (use-package mozc :bind (("C-c m" . mozc-mode))) (use-package material-theme :config (load-theme 'material t)) (use-package windmove :ensure nil :bind (("s-w" . windmove-up) ("s-a" . windmove-left) ("s-s" . windmove-down) ("s-d" . windmove-right))) (use-package counsel :bind (("C-s" . swiper-isearch) ("M-x" . counsel-M-x) ("M-y" . counsel-yank-pop) (" f" . counsel-describe-function) (" v" . counsel-describe-variable) ("C-x C-f" . counsel-find-file) ("C-x b" . ivy-switch-buffer) ("C-x d" . counsel-dired) ("C-c u" . counsel-unicode-char) ("C-c v" . ivy-push-view) ("C-c V" . ivy-pop-view) :map ivy-minibuffer-map ("C-" . ivy-immediate-done)) :init (ivy-add-actions 'project-find-file '(("x" counsel-locate-action-extern "open externally"))) :config (setq ivy-re-builders-alist '((t . ivy--regex-ignore-order))) :custom (ivy-mode 1) (ivy-count-format "(%d/%d) ")) (use-package org :ensure nil :bind (("C-c l" . org-store-link) ("C-c c" . org-capture) ("C-c a" . org-agenda) ("C-c b" . org-switchb) :map org-mode-map ("M-." . org-open-at-point) ("M-," . org-mark-ring-goto)) :custom ; keep-sorted start block=yes (org-agenda-start-on-weekday 0) (org-agenda-weekend-days '(5 6)) (org-default-notes-file "~/Documents/notes.org") (org-agenda-files (list org-default-notes-file)) (org-capture-templates '( ("i" "Thoughts on Debugging and Research" entry (file+headline org-default-notes-file "Inquiries") "** %?\n %U\n*** Failures and possible solutions") ("t" "Task" entry (file+headline org-default-notes-file "Tasks") "** TODO %?\n %U") )) (org-clock-sound "~/Music/single-ding.wav") ; keep-sorted end ) (use-package org-contrib) (use-package org-contacts :after org-contrib) (use-package age :custom (age-default-identity "~/.age/key") (age-default-recipient "~/.age/key.pub") :config (age-file-enable)) ;; EPUB reader (use-package nov :init (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))) (use-package company :init (global-company-mode)) (use-package apt-mode :disabled t) (use-package docker :bind ("C-c d" . docker) :custom (docker-command "podman") (docker-network-columns '((:name "Network ID" :width 20 :template "{{ json .ID }}" :sort nil :format nil) (:name "Name" :width 50 :template "{{ json .Name }}" :sort nil :format nil) (:name "Driver" :width 10 :template "{{ json .Driver }}" :sort nil :format nil)))) (use-package iedit) (use-package wgrep) (use-package apheleia :config (apheleia-global-mode) (setf (alist-get 'emacs-lisp-mode apheleia-mode-alist nil 'remove) nil) (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 lsp-mode :bind (:map lsp-mode-map ("M-?" . lsp-find-references)) :init (setq lsp-keymap-prefix "C-z l") :config (lsp-enable-which-key-integration t) :custom ; keep-sorted start (lsp-diagnostics-provider :flymake) (lsp-pylsp-plugins-mypy-enabled t) (lsp-pylsp-plugins-mypy-strict t) (lsp-pylsp-plugins-ruff-enabled t) ; keep-sorted end ) (use-package flymake :ensure nil :bind (:map flymake-mode-map ("C-c C-l" . flymake-show-buffer-diagnostics) ("C-x C-l" . flymake-show-project-diagnostics) ("C-c C-n" . flymake-goto-next-error) ("C-c C-p" . flymake-goto-prev-error))) ; Requires poetry to be installed (use-package poetry) (defun load-python-env () "Set up the Python IDE in the current project." (interactive) (progn (poetry-venv-workon) (lsp))) (defun symbols-at-point () "Utility function to get the hierarchy of the object at point." (let* ((lsp--document-symbols-request-async t) (symbols (lsp--get-document-symbols)) (symbols-hierarchy (lsp--symbols->document-symbols-hierarchy symbols))) (mapcar (lambda (symb) (list (gethash "name" symb) (lsp--get-symbol-type symb))) symbols-hierarchy))) (defun python-test-at-point () "Use LSP to identify the test at point." (let ((symbols (symbols-at-point))) (pcase symbols (`((,class "Class") (,method "Method") . ,_) (if (equal "test_" (substring method 0 5)) `(,class ,method) `(,class))) (`((,class "Class") . ,_) `(,class)) (_ ())))) (defun python-test-name-at-point () "Create a unittest-compatible descriptor for the test at point." (let* ((path (mapcar #'substring-no-properties lsp-headerline--path-up-to-project-segments)) (filename (f-no-ext (f-filename (buffer-file-name))))) (string-join (append path (list filename) (python-test-at-point)) "."))) (defun python-run-test-at-point (debug) "Identify and run the test at point. When DEBUG is set, run the test in the debugger." (interactive "P") (let ((python (or (executable-find "python3") (executable-find "python"))) (test-name (python-test-name-at-point))) (if debug (pdb (concat python " -m pdb -m unittest " test-name)) (compile (concat python " -m unittest " test-name))))) (use-package python :bind (:map python-mode-map ("C-c C-p" . nil) ("C-c C-l" . nil) ("C-c C-t" . python-run-test-at-point) ("C-M-t" . recompile)) :hook (python-mode . load-python-env)) ;; Jupyter notebook integration (use-package ein :bind (("C-z j" . ein:run) :map ein:notebook-mode-map ("C-c C-x k" . ein:notebook-switch-kernel)) :config (require 'ein-notebook) :custom ; keep-sorted start (ein:jupyter-default-notebook-directory "~/Projects/notebooks") (ein:output-area-inlined-images t) ; keep-sorted end ) (use-package direnv :config (direnv-mode)) (use-package rustic) (use-package power-mode) (use-package emms :config (require 'emms-setup) (emms-all) :custom ; keep-sorted start (emms-info-functions '(emms-info-native)) (emms-player-list '(emms-player-mpv)) ; keep-sorted end ) (defun my-qr-selection () (interactive) (if (use-region-p) (qrencode-region (region-beginning) (region-end)) (let ((url (thing-at-point-url-at-point))) (if (null url) (call-interactively #'qrencode-string) (qrencode--encode-to-buffer url))))) (use-package qrencode :bind (("C-z q" . my-qr-selection)))