modular features

This commit is contained in:
Levi Neely 2024-09-15 15:37:37 +02:00
parent b4d972d618
commit 9ce4016802
49 changed files with 1214 additions and 1041 deletions

View File

@ -34,13 +34,9 @@
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(custom-safe-themes
'("9c22d1654fbfed0285a519541b5ea76462d9b03d778d1dc34779fd38613bf7c8" "9fb561389e5ac5b9ead13a24fb4c2a3544910f67f12cfcfe77b75f36248017d0" "88f7ee5594021c60a4a6a1c275614103de8c1435d6d08cc58882f920e0cec65e" "aec7b55f2a13307a55517fdf08438863d694550565dee23181d2ebd973ebd6b8" "014cb63097fc7dbda3edf53eb09802237961cbb4c9e9abd705f23b86511b0a69" "81f53ee9ddd3f8559f94c127c9327d578e264c574cda7c6d9daddaec226f87bb" "3770d0ae70172461ee0a02edcff71b7d480dc54066e8960d8de9367d12171efb" "f64189544da6f16bab285747d04a92bd57c7e7813d8c24c30f382f087d460a33" "f079ef5189f9738cf5a2b4507bcaf83138ad22d9c9e32a537d61c9aae25502ef" "835d934a930142d408a50b27ed371ba3a9c5a30286297743b0d488e94b225c5f" default))
'(elfeed-feeds '("https://hnrss.org/newest"))
'(mc/always-run-for-all t)
'(org-agenda-files nil)
'(package-selected-packages
'(org-journal plan9-theme parchment-theme acme-theme wrap-region surround go-playground dired-sidebar consult persistent-scratch scratch cape kind-icon corfu eat eshell-toggle eshell-git-prompt eshell-bookmark eshell-autojump eshell-atuin elfeed vertico orderless plz ace-mc ace-jump-mode flycheck fic-mode kotlin-mode rego-mode protobuf-mode multi-web-mode mmm-mode python-mode php-mode json-mode yaml-mode go-mode plantuml-mode graphviz-dot-mode magit denote unicode-fonts nerd-icons-ibuffer nerd-icons-completion nerd-icons-dired doom-modeline which-key multiple-cursors dash async-status async consult-projectile))
'(safe-local-variable-values
'((flycheck-disabled-checkers emacs-lisp-checkdoc emacs-lisp)))
'(tab-width 2))
(custom-set-faces
;; custom-set-faces was added by Custom.

View File

@ -0,0 +1,32 @@
(defun ensure-alioth-mounted ()
"Check if ~/alioth is mounted, and if not, mount it."
(unless (file-exists-p "~/alioth/.exists")
(mount-alioth-sshfs)))
(defun umount-alioth-sshfs ()
"Unmount Alioth Uberspace using SSHFS."
(interactive)
(let ((default-directory "~"))
(shell-command "umount ~/alioth")))
(defun mount-alioth-sshfs ()
"Mount Alioth Uberspace using SSHFS."
(interactive)
(let ((default-directory "~"))
(shell-command "sshfs lkn@alioth.uberspace.de:/home/lkn/ ~/alioth")))
(add-hook 'find-file-hook
(lambda ()
(when (string-prefix-p (expand-file-name "~/alioth/")
(expand-file-name (buffer-file-name)))
(ensure-alioth-mounted))))
(add-hook 'dired-mode-hook
(lambda ()
(when (string-prefix-p (expand-file-name "~/alioth/")
(expand-file-name default-directory))
(ensure-alioth-mounted))))
(provide 'feature-alioth)

View File

@ -0,0 +1,5 @@
(require 'feature-pkg)
(pkg/require 'plz)
(provide 'feature-apitest)

View File

@ -0,0 +1,4 @@
(pkg/require 'async)
(pkg/require 'async-status)
(provide 'feature-async)

View File

@ -0,0 +1,18 @@
(defun ensure-alioth-mounted ()
"Check if ~/alioth is mounted, and if not, mount it."
(unless (file-exists-p "~/alioth/.exists")
(mount-alioth-sshfs)))
(defun umount-alioth-sshfs ()
"Unmount Alioth Uberspace using SSHFS."
(interactive)
(let ((default-directory "~"))
(shell-command "umount ~/alioth")))
(defun mount-alioth-sshfs ()
"Mount Alioth Uberspace using SSHFS."
(interactive)
(let ((default-directory "~"))
(shell-command "sshfs lkn@alioth.uberspace.de:/home/lkn/ ~/alioth")))
(provide 'feature-alioth)

View File

@ -0,0 +1,14 @@
(require 'feature-pkg)
(pkg/require 'avy)
(avy-setup-default)
(setq avy-background t)
(global-set-key (kbd "C-x j j") #'avy-goto-char)
(global-set-key (kbd "C-x j c") #'avy-goto-char-2)
(global-set-key (kbd "C-x j l") #'avy-goto-line)
(global-set-key (kbd "C-x j w") #'avy-goto-word-1)
(global-set-key (kbd "C-x j .") #'avy-resume)
(provide 'feature-avy)

View File

@ -0,0 +1,91 @@
;;; cfg-emacs.el -- configure emacs behavior and user interface
;;;
;;; Commentary:
;;; Exactly what it looks like.
;;;
;;; Code:
(message "Loading base features...")
(defun copy-file-path-to-clipboard ()
"Copy the current buffer's file path to the clipboard."
(interactive)
(let ((filepath (buffer-file-name)))
(when filepath
(kill-new filepath)
(message "Copied file path: %s" filepath))))
(defun my-compile-init-file ()
"Compile the init file."
(let ((init-file (file-truename user-init-file)))
(when (string= (buffer-file-name) init-file)
(byte-compile-file init-file))))
(defun my/setup-elisp-formatting-key ()
"Set up the formatting key for Emacs Lisp buffers."
(local-set-key (kbd "C-c f") 'my/format-elisp-buffer))
(add-hook 'emacs-lisp-mode-hook #'my/setup-elisp-formatting-key)
(defun my/reload-init-file ()
"Reload the Emacs init file."
(interactive)
(load-file user-init-file))
(defun my/format-elisp-buffer ()
"Format the whole elisp buffer."
(interactive)
(save-excursion
(indent-region (point-min) (point-max))))
(tool-bar-mode -1)
(setq backup-by-copying t
completion-cycle-threshold 3
create-lockfiles nil
delete-old-versions t
enable-recursive-minibuffers t
focus-follows-mouse t
indent-tabs-mode nil
inhibit-startup-screen t
kept-new-versions 20
kept-old-versions 2
minibuffer-prompt-properties '(read-only t cursor-intangible t
face minibuffer-prompt)
mouse-autoselect-window t
read-extended-command-predicate #'command-completion-default-include-p
read-process-output-max (* 1024 1024)
tab-always-indent 'complete
tab-width 4
use-short-answers t
version-control t
backup-directory-alist `((".*" . ,(concat user-emacs-directory "backup")))
read-extended-command-predicate #'command-completion-default-include-p
gc-cons-threshold 100000000
auth-sources '("~/.authinfo.gpg")
warning-minimum-level :emergency
text-mode-ispell-word-completion nil
tramp-persistency-file-name "~/.config/emacs/tramp"
tramp-inline-compress-start-size 1000)
;; load custom file
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file))
;; compile init.el on save
(add-hook 'after-save-hook #'my-compile-init-file)
;; setup base key bindings
(global-set-key (kbd "M-/") 'dabbrev-expand)
(global-set-key (kbd "M-s r") 'replace-regexp)
(global-set-key (kbd "M-s M-r") 'replace-string)
(global-set-key (kbd "C-x E n p") #'narrow-to-page)
(global-set-key (kbd "C-x E n f") #'narrow-to-defun)
(global-set-key (kbd "C-x E n r") #'narrow-to-region)
(global-set-key (kbd "C-x E w") #'widen)
(global-set-key (kbd "C-x c r") #'my/reload-init-file)
(global-set-key (kbd "C-x y b p") 'copy-file-path-to-clipboard)
(provide 'feature-base)
;;; feature-base.el ends here.

View File

@ -0,0 +1,20 @@
(require 'eww)
(setq shr-max-image-proportion 0.7)
(setq shr-image-animate nil)
(setq browse-url-browser-function 'eww-browse-url)
;; for pages that require JS for some stupid reason...
(defun browse-url-xdg-open (url &optional _new-window)
"Open URL using the default browser via `xdg-open'."
(interactive (browse-url-interactive-arg "URL: "))
(call-process "xdg-open" nil 0 nil url))
(defun eww-open-in-default-browser ()
"Open the current EWW page in the default system browser."
(interactive)
(browse-url-xdg-open (eww-current-url)))
(define-key eww-mode-map (kbd "C-c o") 'eww-open-in-default-browser)
(provide 'feature-browser)

View File

@ -0,0 +1,37 @@
;;; feature-consult-projectile.el --- consult/projectile integration
;;; Commentary:
;;; Integrate consult and projectile.
;;;
;;; Code:
(require 'feature-pkg)
(require 'feature-consult)
(require 'feature-projectile)
(defun my-consult-projectile-find-file ()
"Use consult-projectile-find-file, consult-find-file outside of project."
(interactive)
(if (projectile-project-p)
(consult-projectile-find-file)
(consult-projectile)))
(pkg/with-eval-after-load
(consult projectile)
(advice-add 'projectile-find-file :override #'consult-projectile-find-file)
(advice-add 'projectile-find-dir :override #'consult-projectile-find-dir)
(advice-add 'projectile-switch-to-buffer :override #'consult-projectile-switch-to-buffer)
(advice-add 'projectile-switch-project :override #'consult-projectile-switch-project))
(global-set-key (kbd "C-x p") projectile-command-map)
(define-key projectile-command-map (kbd "f") #'consult-projectile-find-file)
(define-key projectile-command-map (kbd "d") #'consult-projectile-find-dir)
(define-key projectile-command-map (kbd "b") #'consult-projectile-switch-to-buffer)
(define-key projectile-command-map (kbd "s") #'consult-projectile-switch-project)
(define-key projectile-command-map (kbd "p") #'consult-projectile)
(define-key projectile-command-map (kbd "/") #'consult-ripgrep)
(define-key projectile-command-map (kbd "f") #'my-consult-projectile-find-file)
(provide 'feature-consult-projectile)
;;; feature-consult-projectile.el ends here.

View File

@ -0,0 +1,53 @@
;;; feature-consult.el --- setup consult for emacs
;;; Commentary:
;;; Setup consult for Emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'consult)
(setq consult-preview-key nil)
;; use ripgrep
(setq consult-ripgrep-command "rg --null --line-buffered --color=ansi --max-columns=1000 --no-heading --line-number . -e ARG OPTS")
(setq consult-grep-command "rg --null --line-buffered --color=ansi --max-columns=1000 --no-heading --line-number . -e ARG OPTS")
;; mode-specific histories
(setq consult-mode-histories
'((comint-mode . comint-input-ring)
(eshell-mode . eshell-history-ring)
(geiser-repl-mode . geiser-repl--history)
(inferior-python-mode . comint-input-ring)
(minibuffer-local-map . consult-history)))
(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-recent-file
consult--source-project-recent-file
:preview-key '(:debounce 0.4 any))
;; async search
(setq consult-async-min-input 2
consult-async-refresh-delay 0.15
consult-async-input-throttle 0.2
consult-async-input-debounce 0.1)
;; select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
(global-set-key (kbd "C-s") #'consult-line)
(global-set-key (kbd "C-r") #'consult-line-multi)
(global-set-key (kbd "C-c h") #'consult-history)
(global-set-key (kbd "C-c m") #'consult-mode-command)
(global-set-key (kbd "C-c k") #'consult-kmacro)
(global-set-key (kbd "C-c s") #'consult-ripgrep)
(provide 'feature-consult)
;;; feature-consult.el ends here.

View File

@ -0,0 +1,11 @@
(defun generate-tags-for-directory (directory)
"Generate CTAGS for the specified DIRECTORY."
(interactive
(list (read-directory-name "Generate tags for directory: " default-directory nil t)))
(let ((default-directory directory))
(shell-command "ctags -e -R .")
(message "Tags generated for %s" directory)))
(global-set-key (kbd "C-x E t") 'generate-tags-for-directory)
(provide 'feature-ctags)

View File

@ -0,0 +1,92 @@
;;; feature-denote-index.el -- index and metadata for denote notes
;;;
;;; Commentary: Provides a mechanism for maintaining an index of
;;; denote notes with useful metadata to facilitate search.
;;;
;;; Code:
(require 'feature-denote)
(defvar my/denote-metadata-index-file (concat denote-directory "../denote-metadata.org")
"Path to the metadata index file.")
(defun my/extract-date-from-filename (file)
"Extract date from FILE name. Assumes first 8 characters are YYYYMMDD."
(substring (file-name-nondirectory file) 0 8))
(defun my/format-date (date-string)
"Format DATE-STRING (YYYYMMDD) as YYYY-MM-DD."
(format "%s-%s-%s"
(substring date-string 0 4)
(substring date-string 4 6)
(substring date-string 6 8)))
(defun my/extract-summary (file)
"Extract summary from FILE."
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(when (re-search-forward "^\\* Summary$" nil t)
(forward-line)
(let ((start (point)))
(if (re-search-forward "^\\*" nil t)
(string-trim (buffer-substring-no-properties start (line-beginning-position)))
(string-trim (buffer-substring-no-properties start (point-max))))))))
(defun my/update-denote-metadata-index ()
"Update the metadata index for Denote notes in Org format."
(interactive)
(with-temp-file my/denote-metadata-index-file
(insert "#+TITLE: Denote Metadata Index\n")
(insert "#+AUTHOR: Your Name\n")
(insert "#+DATE: " (format-time-string "%Y-%m-%d") "\n\n")
(dolist (file (directory-files-recursively denote-directory "\\.org$"))
(let ((file-contents (with-temp-buffer
(insert-file-contents file)
(buffer-string))))
(with-temp-buffer
(insert file-contents)
(goto-char (point-min))
(when (re-search-forward "^#\\+title: \\(.+\\)$" nil t)
(let* ((title (string-trim (match-string 1)))
(keywords (denote-extract-keywords-from-path file))
(date-string (my/extract-date-from-filename file))
(formatted-date (my/format-date date-string))
(is-journal (and (listp keywords) (member "journal" keywords)))
(summary (if is-journal
(format "Journal entry for [%s]" formatted-date)
(my/extract-summary file))))
(with-current-buffer (find-file-noselect my/denote-metadata-index-file)
(goto-char (point-max))
(insert (format "* [[file:%s][%s]]\n" file title))
(insert " :PROPERTIES:\n")
(insert (format " :KEYWORDS: %s\n" keywords))
(insert (format " :DATE: [%s]\n" formatted-date))
(insert " :END:\n\n")
(insert (if summary
summary
"No summary provided."))
(unless (string-suffix-p "\n\n" (or summary ""))
(insert "\n\n"))))))))))
(defun my/search-denote-notes ()
"Use consult-ripgrep to search only the Denote metadata index file."
(interactive)
(let* ((index-file my/denote-metadata-index-file)
(default-directory (file-name-directory index-file))
(file-name (file-name-nondirectory index-file))
(consult-ripgrep-args
(concat "rg --null --ignore-case --type org --line-buffered --color=never "
"--max-columns=500 --no-heading --line-number "
"--max-depth 0 "
(shell-quote-argument file-name))))
(if (file-exists-p index-file)
(consult-ripgrep default-directory)
(message "Metadata index file not found: %s" index-file))))
(global-set-key (kbd "C-x n /") #'my/search-denote-notes)
(provide 'feature-denote-index)
;;; feature-denote-index.el ends here

View File

@ -0,0 +1,77 @@
;;; feature-denote-multidir.el --- denote with multi-dir support
;;; Commentary:
;;; Extend denote with support for multiple notes directories.
;;;
;;; Code:
(require 'feature-denote)
(require 'feature-denote-index)
(require 'feature-alioth) ;; depends on alioth for some functions
(defvar my/denote-local-notes-directory "~/notes/")
(defvar my/denote-remote-notes-directory "~/alioth/notes/")
(setq denote-directory my/denote-local-notes-directory)
(defun my/denote-open-or-create ()
"Ensure alioth is mounted before creating or opening a note."
(interactive)
(ensure-alioth-mounted)
(let ((target (denote-file-prompt nil nil :no-require-match)))
(if (and target (file-exists-p target))
(find-file target)
(denote--command-with-features (denote-command-prompt) :use-file-prompt-as-def-title nil nil nil))))
(defun my/denote-echo-current-directory ()
"Echo the current value of denote-directory."
(declare (interactive-only t))
(interactive)
(message "Current Denote directory: %s" denote-directory))
(defun my/denote-directory-segment ()
"Return the current Denote directory for the mode line."
(when (bound-and-true-p denote-directory)
(format " Denote:%s " (file-name-nondirectory (directory-file-name denote-directory)))))
(defun my/denote-switch-directory ()
"Switch current denote working directory."
(interactive)
(let ((new-dir (if (string= denote-directory my/denote-local-notes-directory)
my/denote-remote-notes-directory
my/denote-local-notes-directory)))
(setq denote-directory new-dir)
(setq my/denote-metadata-index-file (concat denote-directory "../denote-metadata.org"))
(message "Denote directory switched to %s" new-dir)))
(defun my/denote-use-both-directories (orig-fun &rest args)
"Temporarily use both directories for a given ORIG-FUN and ARGS."
(let ((original-dir denote-directory)
(result nil))
(setq denote-directory my/denote-local-notes-directory)
(setq result (apply orig-fun args))
(setq denote-directory my/denote-remote-notes-directory)
(setq result (append result (apply orig-fun args)))
(setq denote-directory original-dir)
result))
(defun my/denote-create-note ()
"Create a note in directory of choice."
(interactive)
(let* ((dirs (list my/denote-local-notes-directory my/denote-remote-notes-directory))
(chosen-dir (completing-read "Choose directory: " dirs)))
(let ((denote-directory chosen-dir))
(call-interactively #'denote))))
(advice-add 'denote-directory-files
:around #'my/denote-use-both-directories)
(advice-add 'denote-directory-subdirectories
:around #'my/denote-use-both-directories)
(global-set-key (kbd "C-x n f") #'my/denote-open-or-create)
(global-set-key (kbd "C-x n n") #'my/denote-create-note)
(global-set-key (kbd "C-x n d s") #'my/denote-switch-directory)
(global-set-key (kbd "C-x n d d") #'my/denote-echo-current-directory)
(provide 'feature-denote-multidir)
;;; feature-denote-multidir.el ends here.

View File

@ -0,0 +1,52 @@
;;; feature-denote.el --- note taking
;;; Commentary:
;;; Configure denote for note taking purposes.
;;;
;;; Code:
(require 'feature-pkg)
(require 'feature-dired)
(pkg/require 'denote)
(denote-rename-buffer-mode 1)
(setq denote-save-buffers nil
denote-known-keywords '("emacs" "golang" "dev")
denote-infer-keywords t
denote-sort-keywords t
denote-file-type nil
denote-history-completion-in-prompts nil
denote-prompts '(title keywords)
denote-excluded-directories-regexp nil
denote-excluded-keywords-regexp nil
denote-rename-confirmations '(rewrite-front-matter modify-file-name)
denote-date-prompt-use-org-read-date t
denote-date-format nil
denote-backlinks-show-context t)
(global-unset-key (kbd "C-x n"))
(global-set-key (kbd "C-x n c") #'denote-region)
(global-set-key (kbd "C-x n !") #'denote-date)
(global-set-key (kbd "C-x n z") #'denote-signature)
(global-set-key (kbd "C-x n s") #'denote-subdirectory)
(global-set-key (kbd "C-x n S-n") #'denote-type)
(global-set-key (kbd "C-x n t") #'denote-template)
(global-set-key (kbd "C-x n l l") #'denote-link)
(global-set-key (kbd "C-x n l a") #'denote-add-links)
(global-set-key (kbd "C-x n l f") #'denote-find-link)
(global-set-key (kbd "C-x n b l") #'denote-backlinks)
(global-set-key (kbd "C-x n b f") #'denote-find-backlink)
(global-set-key (kbd "C-x n r r") #'denote-rename-file)
(global-set-key (kbd "C-x n r f") #'denote-rename-file-using-front-matter)
(let ((map dired-mode-map))
(define-key map (kbd "C-x n d") #'denote-dired-mode)
(define-key map (kbd "C-x n i") #'denote-link-dired-marked-notes)
(define-key map (kbd "C-x n k") #'denote-dired-rename-marked-files-with-keywords)
(define-key map (kbd "C-x n r r") #'denote-dired-rename-files)
(define-key map (kbd "C-x n r f") #'denote-dired-rename-marked-files-using-front-matter))
(provide 'feature-denote)
;;; feature-denote.el ends here.

View File

@ -0,0 +1,23 @@
;;; feature-detached.el --- dtach for Emacs
;;; Commentary:
;;; Setup dtach and Emacs integration.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'detached)
(setq detached-terminal-data-command system-type)
(detached-init)
(global-set-key [remap async-shell-command] 'detached-shell-command)
(global-set-key [remap compile] 'detached-compile)
(global-set-key [remap recompile] 'detached-compile-recompile)
(global-set-key [remap detached-open-session] 'detached-consult-session)
(provide 'feature-detached)
;;; feature-detached.el ends here.

View File

@ -0,0 +1,29 @@
;;; feature-dired.el --- dired stuff
;;; Commentary:
;;; Configure Dired stuff.
;;;
;;; Code:
(require 'feature-pkg)
(require 'dired)
(pkg/require 'dired-sidebar)
(defun my/dired-duplicate-file (file)
"Duplicate the current FILE in Dired."
(interactive "p")
(let ((filename (dired-get-filename))
(target '()))
(setq target (concat (file-name-sans-extension filename)
"-old"
(if (> file 1) (number-to-string file))
(file-name-extension filename t)))
(if (file-directory-p filename)
(copy-file filename target))))
(global-set-key (kbd "<f12>") 'dired-sidebar-toggle-sidebar)
(define-key dired-mode-map (kbd "C-c d") 'my/dired-duplicate-file)
(provide 'feature-dired)
;;; feature-dired.el ends here.

View File

@ -0,0 +1,15 @@
(require 'feature-pkg)
(pkg/require 'embark)
(setq prefix-help-command #'embark-prefix-help-command)
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none))))
(global-set-key (kbd "C-.") #'embark-act)
(global-set-key (kbd "C-;") #'embark-dwim)
(global-set-key (kbd "C-h B") #'embark-bindings)
(provide 'feature-embark)

View File

@ -0,0 +1,19 @@
;;; feature-eshell.el --- eshell enhancements.
;;; Commentary:
;;; Configure eshell enhancements.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'eshell)
(pkg/require 'eshell-autojump)
(pkg/require 'eshell-bookmark)
(pkg/require 'eshell-git-prompt)
(pkg/require 'eshell-toggle)
(global-set-key (kbd "C-<escape>") #'eshell-toggle)
(provide 'feature-eshell)
;;; feature-eshell.el ends here.

View File

@ -0,0 +1,20 @@
;; themes
(pkg/require 'acme-theme)
;; modeline
(pkg/require 'doom-modeline)
(doom-modeline-mode 1)
;; icons
(pkg/require 'nerd-icons)
(pkg/require 'nerd-icons-dired)
(pkg/require 'nerd-icons-completion)
(pkg/require 'nerd-icons-ibuffer)
(pkg/require 'kind-icon)
(add-hook 'dired-mode-hook #'nerd-icons-dired-mode)
;; fonts
(pkg/require 'unicode-fonts)
(provide 'feature-eyecandy)

View File

@ -0,0 +1,3 @@
(pkg/require 'go-playground)
(provide 'feature-golang-playground)

View File

@ -0,0 +1,6 @@
(pkg/require 'go-mode)
(add-to-list 'auto-mode-alist '("\\.go$" . go-mode))
(add-hook 'before-save-hook #'gofmt-before-save)
(provide 'feature-golang)

View File

@ -0,0 +1,7 @@
(pkg/require 'graphviz-dot-mode)
(with-eval-after-load 'org
(org-babel-do-load-languages
'org-babel-load-languages '((dot . t))))
(provide 'feature-graphviz)

View File

@ -0,0 +1,5 @@
(pkg/require 'json-mode)
(add-to-list 'auto-mode-alist '("\\.json$" . json-mode))
(provide 'feature-json)

View File

View File

@ -0,0 +1,5 @@
(pkg/require 'kotlin-mode)
;;(add-to-list 'auto-mode-alist ("\\.kt$" . kotlin-mode))
(provide 'feature-kotlin)

View File

@ -0,0 +1,24 @@
(require 'feature-pkg)
(pkg/require 'ellama)
(require 'llm-ollama)
(setq ellama-language "English")
(setq ellama-provider 'ollama)
(setq ellama-ollama-binary "/usr/local/bin/ollama")
(setopt ellama-provider
(make-llm-ollama
:chat-model "codellama:latest"
:embedding-model "nomic-embed-text"
:default-chat-non-standard-params '(("num_ctx" . 8192))))
(setq ellama-keymap-prefix "C-x A e")
(with-eval-after-load 'ellama
(ellama-setup-keymap))
(pkg/require 'org-ai)
(add-hook 'org-mode-hook #'org-ai-mode)
(provide 'feature-llm)

View File

@ -0,0 +1,10 @@
(require 'feature-pkg)
(straight-use-package
'(lmtf :type git :host github :repo "lneely/lmtf"))
(with-eval-after-load 'lmtf
(define-key emacs-lisp-mode-map (kbd "C-c t !") #'lmtf-run-all-tests)
(define-key emacs-lisp-mode-map (kbd "C-c t r") #'lmtf-show-results))
(provide 'feature-lmtf)

View File

@ -0,0 +1,62 @@
;;; feature-magit.el --- git integration
;;; Commentary:
;;; Setup git integration with Emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'magit)
(setq magit-display-buffer-function
#'magit-display-buffer-same-window-except-diff-v1)
;; git reset --soft $(git merge-base branch1 branch2)
(defun magit-reset-to-merge-base ()
"Reset to merge-base of two branches using Magit's branch selection."
(interactive)
(require 'magit)
(let* ((branch1 (magit-read-branch "Select first branch: "))
(branch2 (magit-read-branch "Select second branch: "))
(merge-base (magit-git-string "merge-base" branch1 branch2)))
(if merge-base
(progn
(magit-reset-internal "--soft" merge-base)
(message "Reset to merge-base of %s and %s" branch1 branch2))
(user-error "No merge-base found between %s and %s" branch1 branch2))))
;; git reset --soft @{u}
(defun magit-reset-to-upstream ()
"Reset to upstream of the current branch using Magit."
(interactive)
(require 'magit)
(let ((current-branch (magit-get-current-branch)))
(if current-branch
(let ((upstream (magit-get-upstream-branch current-branch)))
(if upstream
(progn
(magit-reset-internal "--soft" "@{u}")
(message "Reset to upstream of %s (%s)" current-branch upstream))
(user-error "No upstream branch set for %s" current-branch)))
(user-error "Not on a branch"))))
(defvar my/magit-prefix-map (make-sparse-keymap))
(define-key ctl-x-map "g" my/magit-prefix-map)
(define-key my/magit-prefix-map "g" #'magit-status)
(define-key my/magit-prefix-map "rb" #'magit-reset-to-merge-base)
(define-key my/magit-prefix-map "ru" #'magit-reset-to-upstream)
(define-key my/magit-prefix-map "ll" #'magit-log)
(define-key my/magit-prefix-map "la" #'magit-log-all)
(define-key my/magit-prefix-map "lf" #'magit-log-buffer-file)
(define-key my/magit-prefix-map "Rs" #'magit-reset-soft)
(define-key my/magit-prefix-map "Rh" #'magit-reset-hard)
(define-key my/magit-prefix-map "!" #'magit-run)
(define-key my/magit-prefix-map "bb" #'magit-branch)
(define-key my/magit-prefix-map "bc" #'magit-branch-create)
(define-key my/magit-prefix-map "bs" #'magit-branch-checkout)
(define-key my/magit-prefix-map "mm" #'magit-merge)
(define-key my/magit-prefix-map "dd" #'magit-diff)
(provide 'feature-magit)
;;; feature-magit.el ends here.

View File

@ -0,0 +1,19 @@
;;; feature-multi-cursor.el --- multiple cursors
;;; Commentary:
;;; Multiple cursor support for Emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'multiple-cursors)
(multiple-cursors-mode 1)
(global-set-key (kbd "C-x C-<") 'mc/edit-lines)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-x C->") 'mc/mark-all-like-this)
(provide 'feature-multi-cursor)
;;; feature-multi-cursor.el ends here.

View File

@ -0,0 +1,16 @@
;;; feature-orderless.el --- fuzzy search
;;; Commentary:
;;; Setup fuzzy search for Emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'orderless)
(setq completion-styles '(orderless basic)
completion-category-overrides '((file (styles . (partial-completion))))
orderless-matching-styles '(orderless-flex orderless-prefixes orderless-initialism)
orderless-component-separator #'orderless-escapable-split-on-space)
(provide 'feature-orderless)
;;; feature-orderless.el ends here.

View File

@ -0,0 +1,133 @@
;;; feature-org.el --- org-mode
;;; Commentary:
;;; Setup org-mode for Emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'org)
(defun my-org-agenda-format-item (item)
"Format an agenda or to-do ITEM without the filename, but keep the keyword."
(let* ((marker (or (get-text-property 0 'org-marker item)
(get-text-property 0 'org-hd-marker item)))
(line (when marker
(org-with-point-at marker
(buffer-substring (line-beginning-position) (line-end-position)))))
(todo-keyword (when marker
(org-with-point-at marker
(org-get-todo-state))))
(truncated-line (when line
(replace-regexp-in-string "^\\[#[A-Z]\\] " "" line))))
(if truncated-line
(let ((clean-item (replace-regexp-in-string "^\\(\\*+ \\)" "" truncated-line)))
(if todo-keyword
(concat todo-keyword " " (replace-regexp-in-string (concat "^" todo-keyword " ?") "" clean-item))
clean-item))
item)))
(defun my/add-remote-todo-file ()
"Add remote TODO.org file to org-agenda-files."
(interactive)
(unless org-agenda-files
(setq org-agenda-files
(list "~/alioth/TODO.org"))))
(defun my/org-config ()
"Setup personal 'org-mode' configuration."
(setq org-agenda-inhibit-startup t
org-adapt-indentation nil
org-todo-keywords '((sequence "HOLD(h)" "TODO(t)" "WAIT(w)" "|"
"DONE(d)" "CNCL(x)"))
org-todo-keyword-faces
'(("HOLD" . (:foreground "orange" :weight bold))
("TODO" . (:foreground "red" :weight bold))
("DONE" . (:foreground "green" :weight bold))
("CNCL" . (:foreground "gray" :weight bold)))
org-agenda-prefix-format '((agenda . "%i %?-12t% s ")
(todo . " %i ")
(tags . " %i ")
(search . " %i "))
org-agenda-hide-tags-regexp "."
org-agenda-todo-keyword-format "%s"
org-archive-location "%s_archive::datetree/"
org-log-done 'note
org-agenda-hide-tags-regexp nil
org-agenda-tags-column -80
org-log-into-drawer t)
(setq org-stuck-projects
'("+prj/-maybe-someday" ("TODO" "WAIT" "CNCL" "prj") nil ""))
(setq org-tags-exclude-from-inheritance '("prj")))
(defun my/org-refile-config ()
"Setup org-refile targets."
(defvar org-refile-targets)
(defvar org-refile-use-outline-path)
(defvar org-outline-path-complete-in-steps)
(defvar org-refile-allow-creating-parent-nodes)
(setq org-refile-targets
'((nil :maxlevel . 9)
("~/alioth/lkn/TODO.org" :maxlevel . 9))
org-refile-use-outline-path 'file
org-outline-path-complete-in-steps nil
org-refile-allow-creating-parent-nodes 'confirm))
(defun my/org-capture-config ()
"Setup org-capture."
(setq org-capture-templates
'(("t" "TODO" entry (file "~/alioth/TODO.org")
"* TODO %?\n %i" :prepend t)))
(with-eval-after-load 'denote
(defvar denote-org-capture-specifiers)
(setq denote-org-capture-specifiers "%l\n%i\n%?")
(add-to-list 'org-capture-templates
'("n" "New note (with denote.el)" plain
(file denote-last-path)
#'denote-org-capture
:no-save t
:immediate-finish nil
:kill-buffer t
:jump-to-captured t))))
(defun my/reload-org-config ()
"Reload the org configuration."
(interactive)
(my/org-config)
(message "Org configuration reloaded"))
(defun my/visit-todo ()
"Visit TODO.org in home."
(interactive)
(find-file "~/alioth/TODO.org"))
(defun my/kill-all-org-agenda-buffers ()
"Close all org-agenda-related buffers."
(interactive)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (or (derived-mode-p 'org-agenda-mode)
(and (buffer-file-name)
(member (buffer-file-name) (org-agenda-files))))
(kill-buffer buffer))))
(message "Closed all org-agenda-related buffers."))
(add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode))
(advice-add 'org-agenda :before #'my/add-remote-todo-file)
(advice-add 'org-agenda-format-item-line
:filter-return #'my-org-agenda-format-item)
(advice-add 'org-agenda-format-item
:filter-return #'my-org-agenda-format-item)
(org-babel-do-load-languages 'org-babel-load-languages
'((shell . t)))
;; key bindings
(global-set-key (kbd "C-x c O") 'my/reload-org-config)
(global-set-key (kbd "C-x O a") 'org-agenda)
(global-set-key (kbd "C-x O c") 'org-capture)
(global-set-key (kbd "C-x O t") 'my/visit-todo)
(global-set-key (kbd "C-x O k") 'my/kill-all-org-agenda-buffers)
(provide 'feature-org)
;;; feature-org.el ends here.

View File

@ -0,0 +1,74 @@
(require 'package)
(with-eval-after-load 'package
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/")
'("nongnu" . "https://elpa.nongnu.org/nongnu/")))
(package-initialize)
;; install 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/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(defun pkg/ensure-installed (package)
"Ensure that PACKAGE is installed."
(unless (package-installed-p package)
(package-refresh-contents)
(package-install package)))
(defmacro pkg/require (feature &optional filename noerror)
"Ensure FEATURE is installed, then require it.
FILENAME and NOERROR are passed to `require'."
`(progn
(pkg/ensure-installed ,feature)
(require ,feature ,filename ,noerror)))
(defmacro pkg/require-defer (feature &optional filename noerror)
"Defer loading of FEATURE until it's actually needed.
Ensure FEATURE is installed first.
FILENAME, if non-nil, is the file to load to provide FEATURE.
If NOERROR is non-nil, don't signal an error if the file is not found."
`(progn
(pkg/ensure-installed ,feature)
(unless (featurep ',feature)
(autoload #',(intern (format "%s-autoloaded" feature))
,(or filename (symbol-name feature))
nil t)
(defalias ',feature #',(intern (format "%s-autoloaded" feature))))
',feature))
(defun pkg/require-defer-load (feature)
"Check if a deferred FEATURE is already loaded."
(unless (featurep feature)
(unload-feature feature t)
(require feature)
(fmakunbound (intern (format "%s-autoloaded" feature))))
feature)
(defmacro pkg/require-defer-timer (feature seconds)
"Ensure FEATURE is installed, then defer its loading by SECONDS idle time."
`(progn
(pkg/ensure-installed ,feature)
(run-with-idle-timer ,seconds nil #'require ',feature)))
(defun pkg/packages-loaded-p (&rest packages)
"Return t if all PACKAGES are loaded."
(cl-every #'featurep packages))
(defmacro pkg/with-eval-after-load (packages &rest body)
"Run BODY after all PACKAGES are loaded."
`(if (apply #'pkg/packages-loaded-p ',packages)
(progn ,@body)
(eval-after-load (car (last ',packages))
'(pkg/run-after-packages-load ',packages ,@body))))
(provide 'feature-pkg)

View File

@ -0,0 +1,12 @@
(pkg/require 'plantuml-mode)
(setq plantuml-default-exec-mode 'jar
plantuml-jar-path "/usr/share/plantuml/plantuml.jar"
org-plantuml-jar-path (expand-file-name
"/usr/share/plantuml/plantuml.jar"))
(with-eval-after-load 'org
(org-babel-do-load-languages
'org-babel-load-languages '((plantuml . t))))
(provide 'feature-plantuml)

View File

@ -0,0 +1,15 @@
;;; feature-projectile.el --- project management
;;; Commentary:
;;; Project management for Emacs nerds.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'projectile)
(projectile-mode +1)
(provide 'feature-projectile)
;;; feature-projectile.el ends here.

View File

@ -0,0 +1,6 @@
(pkg/require 'protobuf-mode)
(add-to-list 'auto-mode-alist '("\\.proto$" . protobuf-mode))
(provide 'feature-protobuf)

View File

@ -0,0 +1,7 @@
(pkg/require 'python-mode)
(pkg/require 'python-environment)
(add-to-list 'auto-mode-alist '("\\.py$" . python-mode))
(add-to-list 'auto-mode-alist '("BUILD\\'" . python-mode))
(provide 'feature-python)

View File

@ -0,0 +1,3 @@
(pkg/require 'rego-mode)
(provide 'feature-rego)

View File

@ -0,0 +1,12 @@
;;; feature-orderless.el --- rss feeds in emacs
;;; Commentary:
;;; Read RSS feeds in Emacs, stop browsing the web.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'elfeed)
(provide 'feature-rss)
;;; feature-rss.el ends here.

View File

@ -0,0 +1,34 @@
;;; feature-scratch.el --- scratch buffer enhancements
;;; Commentary:
;;; Scratch buffer enhancements for Emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'scratch)
(pkg/require 'persistent-scratch)
(defun my-set-scratch-mode ()
"Set default scratch mode."
(funcall 'text-mode))
(persistent-scratch-setup-default)
(setq persistent-scratch-directory "~/.local/state/emacs/"
persistent-scratch-autosave-interval 30
persistent-scratch-what-to-save '(((:current . "*scratch*") .
(major-mode point narrowing)))
persistent-scratch-save-file (expand-file-name
"scratch" persistent-scratch-directory))
(unless (file-exists-p persistent-scratch-directory)
(make-directory persistent-scratch-directory t))
(add-hook 'scratch-create-buffer-hook 'my-set-scratch-mode)
(add-hook 'after-init-hook #'persistent-scratch-autosave-mode)
(global-set-key (kbd "C-c s") #'persistent-scratch-save)
(global-set-key (kbd "C-c r") #'persistent-scratch-restore)
(provide 'feature-scratch)
;;; feature-scratch.el ends here.

View File

View File

@ -0,0 +1,16 @@
(require 'feature-pkg)
(pkg/require 'yasnippet)
(pkg/require 'yasnippet-snippets)
(setq yas-snippet-dirs '("~/.config/emacs/snippets/"))
(yas-global-mode 1)
(global-set-key (kbd "C-x y i") #'yas-insert-snippet)
(global-set-key (kbd "C-x y n") #'yas-new-snippet)
(global-set-key (kbd "C-x y v") #'yas-visit-snippet-file)
(add-hook 'prog-mode-hook #'yas-minor-mode)
(add-hook 'org-mode-hook #'yas-minor-mode)
(provide 'feature-snippets)

View File

@ -0,0 +1,17 @@
;;; feature-syntax.el --- syntax related stuff
;;; Commentary:
;;; Configure syntax-related settings.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'fic-mode)
(pkg/require 'flycheck)
(global-flycheck-mode)
(setq flycheck-emacs-lisp-load-path 'inherit)
(provide 'feature-syntax)
;;; feature-syntax.el ends here.

View File

@ -0,0 +1,29 @@
;;; feature-vertico.el --- better minibuffer
;;; Commentary:
;;; Better minibuffer for emacs.
;;;
;;; Code:
(require 'feature-pkg)
(pkg/require 'vertico)
(vertico-mode)
(setq vertico-cycle t
vertico-count 13
read-file-name-completion-ignore-case t
read-buffer-completion-ignore-case t
completion-ignore-case t
completion-styles '(orderless basic)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion))))
(pkg/with-eval-after-load
(vertico)
(require 'vertico-quick)
(define-key vertico-map (kbd "C-q") #'vertico-quick-insert)
(define-key vertico-map (kbd "M-q") #'vertico-quick-exit))
(provide 'feature-vertico)
;;; feature-vertico.el ends here.

View File

@ -0,0 +1,9 @@
(pkg/require 'mmm-mode)
(pkg/require 'multi-web-mode)
(pkg/require 'php-mode)
(pkg/require 'emmet-mode)
(add-to-list 'auto-mode-alist '("\\.php$" . php-mode))
(provide 'feature-web)

View File

@ -0,0 +1,5 @@
(pkg/require 'which-key)
(which-key-mode)
(provide 'feature-which-key)

View File

@ -0,0 +1,5 @@
(pkg/require 'yaml-mode)
(add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
(provide 'feature-yaml)

File diff suppressed because it is too large Load Diff

1
emacs/lisp/org-ai Submodule

@ -0,0 +1 @@
Subproject commit 02a43259e357846372672b58ba9416093493b3fb

View File

@ -7,4 +7,4 @@
("aicld" "* ${1:What}\n\n#+begin_ai :service anthropic :model claude-3-5-sonnet-20240620\n[SYS]: ${2:You are a helpful assistant.}\n\n[ME]: ${0}\n#+end_ai\n" "aicld" nil nil nil "/home/lkn/.config/emacs/snippets/org-mode/aicld" nil nil)))
;;; Do not edit! File generated at Tue Sep 10 15:15:33 2024
;;; Do not edit! File generated at Sat Sep 14 15:30:36 2024