emacs Sat Nov 30 18:51:30 IST 2024

This commit is contained in:
Aleksandr Mikhailov 2024-11-30 18:51:30 +02:00
commit d8be9fe9ea
14 changed files with 1330 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
etc
elpa
auto-save-list
.cache
var
straight
eln-cache
*~
\#*#
history
recentf
projects
.lsp-session-*
transient

13
custom.el Normal file
View File

@ -0,0 +1,13 @@
;;; -*- lexical-binding: t -*-
(custom-set-variables
;; custom-set-variables was added by Custom.
;; 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.
'(package-vc-selected-packages '((nm :url "https://github.com/Kodkollektivet/emacs-nm"))))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; 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.
)

65
early-init.el Normal file
View File

@ -0,0 +1,65 @@
;;; -*- lexical-binding: t; -*-
;; Some snake oil during the startup. Probably won't hurt and is
;; reverted right after the Emacs initialization finishes.
(setq inhibit-startup-message t)
(global-display-line-numbers-mode 1)
(add-hook 'after-init-hook
`(lambda ()
(setq gc-cons-threshold ,gc-cons-threshold))
'append)
(setq gc-cons-threshold most-positive-fixnum)
(defun bootstrap-straight ()
"Install and configure straight.el"
(setq straight-vc-git-default-clone-depth
(if-let ((depth (getenv "EMACS_STRAIGHT_DEPTH")))
(string-to-number depth)
'full))
(setq straight-check-for-modifications '(check-on-save find-when-checking)
straight-build-dir (format "build-%s" emacs-version)
straight-use-package-by-default t)
(setq straight-host-usernames '((github . "vifon")))
(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/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage)))
(defun bootstrap-use-package ()
"Install use-package.el"
(setq use-package-enable-imenu-support t)
(straight-use-package 'use-package)
(straight-use-package 'diminish)
(require 'use-package-ensure)
(setq use-package-always-ensure t)
;; (use-package auto-package-update
;; :config
;; (setq auto-package-update-delete-old-versions t)
;; (setq auto-package-update-hide-results t)
;; (auto-package-update-maybe)
;; )
)
(bootstrap-straight)
(bootstrap-use-package)
;; This is not needed in general, but my specific init.el tries to
;; explicitly load early-init.el if it wasn't loaded yet.
;; This `provide' is used to load it only once.
(provide 'early-init)

375
init.el Normal file
View File

@ -0,0 +1,375 @@
;; -*- lexical-binding: t; -*-
;;; This file is generated from the Emacs.org file in my dotfiles repository!
;;; ----- Basic Configuration -----
;; Core settings
(setq ;; Flash the UI instead of beeping
visible-bell nil
;; Yes, this is Emacs
inhibit-startup-message t
;; inhibit-startup-screen t
initial-scratch-message nil
;; initial-buffer-choice nil
frame-title-format nil
use-file-dialog nil
indicate-empty-lines t
;; Instruct auto-save-mode to save to the current file, not a backup file
auto-save-default nil
auto-save-timeout 3 ; number of seconds idle time before auto-save
; (default: 30)
auto-save-interval 200 ; number of keystrokes between auto-saves
; (default: 300)
x-select-enable-primary t
x-select-enable-clipboard t
mouse-drag-copy-region t
;; No backup files, please
make-backup-files nil
;; Make it easy to cycle through previous items in the mark ring
set-mark-command-repeat-pop t
;; Don't warn on large files
large-file-warning-threshold nil
;; Follow symlinks to VC-controlled files without warning
;; vc-follow-symlinks t
;; Don't warn on advice
ad-redefinition-action 'accept
;; Revert Dired and other buffers
global-auto-revert-non-file-buffers t
;; Silence compiler warnings as they can be pretty disruptive
native-comp-async-report-warnings-errors nil)
;; No scroll bars
(if (fboundp 'scroll-bar-mode) (set-scroll-bar-mode nil))
;; No toolbar
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(dolist (mode '(scroll-bar-mode
horizontal-scroll-bar-mode
menu-bar-mode
tooltip-mode
tool-bar-mode))
(when (fboundp mode)
(funcall mode 0)))
;; Core modes
(repeat-mode 1) ;; Enable repeating key maps
(menu-bar-mode 0) ;; Hide the menu bar
(tool-bar-mode 0) ;; Hide the tool bar
(savehist-mode 1) ;; Save minibuffer history
(scroll-bar-mode 0) ;; Hide the scroll bar
(xterm-mouse-mode 1) ;; Enable mouse events in terminal Emacs
(display-time-mode 1) ;; Display time in mode line / tab bar
(fido-vertical-mode 1) ;; Improved vertical minibuffer completions
(column-number-mode 1) ;; Show column number on mode line
(tab-bar-history-mode 1) ;; Remember previous tab window configurations
(auto-save-visited-mode 1) ;; Auto-save files at an interval
(global-visual-line-mode 1) ;; Visually wrap long lines in all buffers
(global-auto-revert-mode 1) ;; Refresh buffers with changed local files
(icomplete-mode 0)
;; (blink-cursor-mode 0)
(show-paren-mode t)
;; Tabs to spaces
(setq-default indent-tabs-mode nil
tab-width 2)
(fset 'yes-or-no-p 'y-or-n-p)
;; Display line numbers in programming modes
(add-hook 'prog-mode-hook #'display-line-numbers-mode)
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; Make icomplete slightly more convenient
;; (keymap-set icomplete-fido-mode-map "M-h" 'icomplete-fido-backward-updir)
;; (keymap-set icomplete-fido-mode-map "TAB" 'icomplete-force-complete)
;; Delete trailing whitespace before saving buffers
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; Move customization settings out of init.el
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file t))
;; Match completion substrings that may be out of order
(defun fn/override-fido-completion-styles ()
(setq-local completion-styles '(substring partial-completion emacs22)))
;; (add-hook 'icomplete-minibuffer-setup-hook 'fn/override-fido-completion-styles)
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-language-environment 'utf-8)
(set-default 'cursor-type '(hbar . 2))
;;; ----- System Identification -----
(defvar fn/is-termux
(string-suffix-p "Android" (string-trim (shell-command-to-string "uname -a"))))
(defvar fn/current-distro (or (and (eq system-type 'gnu/linux)
(file-exists-p "/etc/os-release")
(with-temp-buffer
(insert-file-contents "/etc/os-release")
(search-forward-regexp "^ID=\"?\\(.*\\)\"?$")
(intern (or (match-string 1)
"unknown"))))
'unknown))
(defvar fn/is-guix-system (eql fn/current-distro 'guix))
;;; ----- Package Management -----
;; Automatically install packages (when not on Guix) but don't load
;; them until requested
(setq use-package-always-ensure (not fn/is-guix-system)
use-package-always-defer t)
;;; ----- Configuration Management -----
(defvar fn/use-config-modules '()
"A list of module symbols to load once init.el is finished.")
(defvar fn/common-config-modules '(
fn-core
fn-present
fn-writing
fn-workflow
fn-coding
fn-interface
fn-vc
)
"Configuration modules most commonly used across my machines.")
;; Add configuration modules to load path
(add-to-list 'load-path '"~/.config/emacs/modules")
;; Load system-specific configuration
(let ((config-path
(format "~/.config/emacs/systems/%s.el" system-name)))
(if (file-exists-p config-path)
(load-file config-path)
(message "No per-system configuration found for %s!" system-name)))
;;; ----- Appearance -----
(defun fn/set-terminal-title (title)
(send-string-to-terminal (format "\e]0;%s\a" title)))
(defun fn/clear-background-color (&optional frame))
;; (interactive)
;; (or frame (setq frame (selected-frame)))
;; "unsets the background color in terminal mode"
;; (unless (display-graphic-p frame)
;; Set the terminal to a transparent version of the background color
;; (send-string-to-terminal
;; (format "\033]11;[90]%s\033\\"
;; (face-attribute 'default :background)))
;; (set-face-background 'default "unspecified-bg" frame)))
;; Clear the background color for transparent terminals
(unless (display-graphic-p)
(add-hook 'after-make-frame-functions 'fn/clear-background-color)
(add-hook 'window-setup-hook 'fn/clear-background-color)
(add-hook 'ef-themes-post-load-hook 'fn/clear-background-color))
(use-package modus-themes
:custom
(modus-themes-italic-constructs t)
(modus-themes-bold-constructs t)
(modus-themes-mixed-fonts t)
(modus-themes-variable-pitch-ui t)
(modus-themes-to-toggle '(modus-vivendi-tinted modus-operandi-tinted))
(modus-themes-common-palette-overrides
`((bg-mode-line-active bg-lavender)
(fg-mode-line-active fg-main)
(border-mode-line-active bg-magenta-warmer)))
:init
(load-theme 'modus-vivendi-tinted t)
(add-hook 'modus-themes-after-load-theme-hook #'fn/clear-background-color))
;;
;; Make vertical window separators look nicer in terminal Emacs
(set-display-table-slot standard-display-table 'vertical-border (make-glyph-code ?│))
;; Clean up the mode line
(setq-default mode-line-format
'("%e" " "
(:propertize
("" mode-line-mule-info mode-line-client mode-line-modified mode-line-remote))
mode-line-frame-identification
mode-line-buffer-identification
" "
mode-line-position
mode-line-format-right-align
" "
(project-mode-line project-mode-line-format)
" "
(vc-mode vc-mode)
" "
mode-line-modes
mode-line-misc-info
" ")
project-mode-line t
mode-line-buffer-identification '(" %b")
mode-line-position-column-line-format '(" %l:%c"))
;; Move global mode string to the tab-bar and hide tab close buttons
(setq tab-bar-close-button-show nil
tab-bar-separator " "
tab-bar-format '(tab-bar-format-menu-bar
tab-bar-format-tabs-groups
tab-bar-separator
tab-bar-format-align-right
tab-bar-format-global))
;; Turn on the tab-bar
(tab-bar-mode 1)
;; Customize time display
(setq display-time-load-average nil
display-time-format "%H:%M %b %d W%U")
;; ----- Special Buffers as Popup Window -----
(setq display-buffer-alist
'(("\\*\\(shell\\|.*term\\|.*eshell\\|help\\|compilation\\|Async Shell Command\\|Occur\\|xref\\).*\\*"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . bottom) ; Popups go at the bottom
(slot . 0) ; Use the first slot at the bottom
(post-command-select-window . t) ; Select the window upon display
(window-height . 0.3)))) ; 30% of the frame height
(defun fn/toggle-popup-window ()
(interactive)
(if-let ((popup-window
(get-window-with-predicate
(lambda (window)
(eq (window-parameter window 'window-side)
'bottom)))))
;; Focus the window if it is not selected, otherwise close it
(if (eq popup-window (selected-window))
(delete-window popup-window)
(select-window popup-window))
;; Find the most recent buffer that matches the rule and show it
;; NOTE: This logic is somewhat risky because it makes the assumption
;; that the popup rule comes first in `display-buffer-alist'.
;; I chose to do this because maintaining a separate variable
;; for this rule meant I had to re-evaluate 2 different forms
;; to update my rule list.
(if-let ((popup-buffer
(seq-find (lambda (buffer)
(buffer-match-p (caar display-buffer-alist)
(buffer-name buffer)))
(if (project-current)
(project-buffers (project-current))
(buffer-list (selected-frame))))))
(display-buffer popup-buffer (cdar display-buffer-alist))
(message "No popup buffers found."))))
;; TODO: This binding may need to change
(keymap-global-set "C-c p" #'fn/toggle-popup-window)
(with-eval-after-load 'term
(keymap-set term-raw-map "C-c p" #'fn/toggle-popup-window))
;;; ----- Essential Org Mode Configuration -----
(setq org-ellipsis ""
org-startup-folded 'content
org-cycle-separator-lines 2
org-fontify-quote-and-verse-blocks t)
;; Indent org-mode buffers for readability
(add-hook 'org-mode-hook #'org-indent-mode)
;; Set up Org Babel languages
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)))
;; Use org-tempo
(use-package org-tempo
:straight (:type built-in)
:ensure nil
:demand t
:config
(dolist (item '(("sh" . "src sh")
("el" . "src emacs-lisp")
("li" . "src lisp")
("sc" . "src scheme")
("ts" . "src typescript")
("py" . "src python")
("yaml" . "src yaml")
("json" . "src json")
("einit" . "src emacs-lisp :tangle emacs/init.el")
("emodule" . "src emacs-lisp :tangle emacs/modules/dw-MODULE.el")))
(add-to-list 'org-structure-template-alist item)))
;;; ----- Document Centering -----
(defvar center-document-desired-width 90
"The desired width of a document centered in the window.")
(defun center-document--adjust-margins ()
;; Reset margins first before recalculating
(set-window-parameter nil 'min-margins nil)
(set-window-margins nil nil)
;; Adjust margins if the mode is on
(when center-document-mode
(let ((margin-width (max 0
(truncate
(/ (- (window-width)
center-document-desired-width)
2.0)))))
(when (> margin-width 0)
(set-window-parameter nil 'min-margins '(0 . 0))
(set-window-margins nil margin-width margin-width)))))
(define-minor-mode center-document-mode
"Toggle centered text layout in the current buffer."
:lighter " Centered"
:group 'editing
(if center-document-mode
(add-hook 'window-configuration-change-hook #'center-document--adjust-margins 'append 'local)
(remove-hook 'window-configuration-change-hook #'center-document--adjust-margins 'local))
(center-document--adjust-margins))
(add-hook 'org-mode-hook #'center-document-mode)
;; Make sure ripgrep is used everywhere
(setq xref-search-program 'ripgrep
grep-command "rg -nS --noheading")
;; Load requested configuration modules
(dolist (module fn/use-config-modules)
(require module))
(dashboard-open)
(treemacs-start-on-boot)

153
modules/fn-coding.el Normal file
View File

@ -0,0 +1,153 @@
;; -*- lexical-binding: t; -*-
(use-package apheleia
:defer t
:bind ("C-c t a" . apheleia-mode)
:init (apheleia-global-mode)
:config
;; Set custom formatting commands
(dolist (formatter-cmd '(
(shfmt . ("shfmt" "-i" "4" "-ci" "-kp" "-sr"))
))
(add-to-list #'apheleia-formatters formatter-cmd))
;; Set custom formatters for modes
(dolist (formatter-mode '((emacs-lisp-mode . lisp-indent)
(clojure-mode . lisp-indent)
))
(add-to-list #'apheleia-mode-alist formatter-mode)))
;; Posframe is a pop-up tool that must be manually installed for dap-mode
(use-package posframe)
(use-package ripgrep)
;; Use the Debug Adapter Protocol for running tests and debugging
(use-package dap-mode
:hook
(lsp-mode . dap-mode)
(lsp-mode . dap-ui-mode))
(use-package yaml-mode
:mode "\\.ya?ml\\'")
(use-package lsp-mode
:straight (:type built-in)
;; Optional - enable lsp-mode automatically in scala files
;; You could also swap out lsp for lsp-deffered in order to defer loading
:hook
(scala-mode . lsp)
(lsp-mode . lsp-lens-mode)
(lsp-completion-mode . my/lsp-mode-setup-completion)
:init
(defun my/orderless-dispatch-flex-first (_pattern index _total)
(and (eq index 0) 'orderless-flex))
(defun my/lsp-mode-setup-completion ()
(setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
'(orderless))
;; Optionally configure the first word as flex filtered.
(add-hook 'orderless-style-dispatchers #'my/orderless-dispatch-flex-first nil 'local)
;; Optionally configure the cape-capf-buster.
(setq-local completion-at-point-functions (list (cape-capf-buster #'lsp-completion-at-point))))
:config
;; Uncomment following section if you would like to tune lsp-mode performance according to
;; https://emacs-lsp.github.io/lsp-mode/page/performance/
(setq lsp-idle-delay 0.500)
(setq lsp-log-io nil)
(setq lsp-completion-provider nil)
(setq lsp-modeline-code-actions-segments '(count name))
(setq lsp-headerline-breadcrumb-segments '(path symbols))
(setq lsp-prefer-flymake t)
;; Makes LSP shutdown the metals server when all buffers in the project are closed.
;; https://emacs-lsp.github.io/lsp-mode/page/settings/mode/#lsp-keep-workspace-alive
(setq lsp-keep-workspace-alive nil)
(setq lsp-auto-execute-action nil)
(setq lsp-nix-nil-formatter ["nixfmt"])
(with-eval-after-load 'lsp-mode
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\.bloop\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\.metals\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\.ammonite\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\.ivy2\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]\\.sbt\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]target\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]project/target\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]project/\\..+\\'")
(add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]dist\\'")))
(use-package lsp-ui
:config
(setq lsp-ui-sideline-show-diagnostics t)
(setq lsp-ui-sideline-show-code-actions t)
(setq lsp-ui-sideline-update-mode 'line)
(setq lsp-ui-peek-enable t)
(setq lsp-ui-doc-enable t)
(setq lsp-ui-doc-side 'right)
(setq lsp-ui-doc-position 'bottom)
(setq lsp-ui-doc-delay 3)
(setq lsp-ui-doc-show-with-cursor t)
(setq lsp-ui-doc-show-with-mouse t))
(use-package lsp-treemacs
:init
(lsp-treemacs-sync-mode 1))
(use-package scala-mode
:interpreter ("scala" . scala-mode))
;; Enable sbt mode for executing sbt commands
(use-package sbt-mode
:commands sbt-start sbt-command
:config
;; WORKAROUND: https://github.com/ensime/emacs-sbt-mode/issues/31
;; allows using SPACE when in the minibuffer
(substitute-key-definition
'minibuffer-complete-word
'self-insert-command
minibuffer-local-completion-map)
;; sbt-supershell kills sbt-mode: https://github.com/hvesalai/emacs-sbt-mode/issues/152
(setq sbt:program-options '("-Dsbt.supershell=false")))
(use-package nix-lsp
:straight (:type built-in)
:after (lsp-mode)
:custom
(lsp-nix-nil-formatter ["nixfmt"]))
(use-package nix-mode
:hook (nix-mode . lsp-deferred)
:mode "\\.nix\\'")
(use-package company-nixos-options
:after (company-mode)
:custom
(add-to-list 'company-backends 'company-nixos-options))
;; Add metals backend for lsp-mode
(use-package
lsp-metals
:straight (:type built-in))
(use-package dockerfile-mode
:init
(require 'dockerfile-mode))
(use-package tree-sitter
:config
(global-tree-sitter-mode))
(use-package tree-sitter-langs)
(use-package yasnippet
:hook (prog-mode . yas-minor-mode)
:config
(yas-reload-all))
(provide 'fn-coding)

144
modules/fn-core.el Normal file
View File

@ -0,0 +1,144 @@
;; -*- lexical-binding: t; -*-
(setq user-emacs-directory (expand-file-name "~/.cache/emacs/")
url-history-file (expand-file-name "url/history" user-emacs-directory))
(use-package no-littering
:demand t
:config
;; Set the custom-file to a file that won't be tracked by Git
(setq custom-file (if (boundp 'server-socket-dir)
(expand-file-name "custom.el" server-socket-dir)
(no-littering-expand-etc-file-name "custom.el")))
(when (file-exists-p custom-file)
(load custom-file t))
;; Don't litter project folders with backup files
(let ((backup-dir (no-littering-expand-var-file-name "backup/")))
(make-directory backup-dir t)
(setq backup-directory-alist
`(("\\`/tmp/" . nil)
("\\`/dev/shm/" . nil)
("." . ,backup-dir))))
(setq auto-save-default nil)
;; Tidy up auto-save files
(setq auto-save-default nil)
(let ((auto-save-dir (no-littering-expand-var-file-name "auto-save/")))
(make-directory auto-save-dir t)
(setq auto-save-file-name-transforms
`(("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'"
,(concat temporary-file-directory "\\2") t)
("\\`\\(/tmp\\|/dev/shm\\)\\([^/]*/\\)*\\(.*\\)\\'" "\\3")
("." ,auto-save-dir t)))))
;;; -- Native Compilation -----
;; Silence compiler warnings as they can be pretty disruptive
(setq native-comp-async-report-warnings-errors nil)
;; Set the right directory to store the native comp cache
(add-to-list 'native-comp-eln-load-path (expand-file-name "eln-cache/" user-emacs-directory))
(setq-default fill-column 120)
(use-package minions
:init
(minions-mode))
;; Revert Dired and other buffers
(setq global-auto-revert-non-file-buffers t)
;; Revert buffers when the underlying file has changed
(global-auto-revert-mode 1)
(use-package alert)
(use-package super-save
:config
(super-save-mode +1)
(setq super-save-auto-save-when-idle t)
;; (add-to-list 'super-save-predicates (lambda ()
;; (not (eq major-mode 'mu4e-compose-mode))))
)
;; If a popup does happen, don't resize windows to be equal-sized
(setq even-window-sizes nil)
(use-package popper
:bind (("C-M-'" . popper-toggle-latest)
("M-'" . popper-cycle)
("C-M-\"" . popper-toggle-type))
:custom
(popper-window-height 12)
(popper-reference-buffers '(eshell-mode
vterm-mode
geiser-repl-mode
help-mode
grep-mode
helpful-mode
compilation-mode))
:config
(require 'popper) ;; Needed because I disabled autoloads
(popper-mode 1))
;;; ----- Dired -----
(use-package all-the-icons)
(use-package all-the-icons-dired)
(use-package dired-ranger)
(defun fn/dired-mode-hook ()
(interactive)
(dired-hide-details-mode 1)
(unless (or fn/is-termux
(string-equal "/nix/store/" (expand-file-name default-directory)))
(all-the-icons-dired-mode 1))
(hl-line-mode 1))
(use-package dired
:straight (:type built-in)
:bind (:map dired-mode-map
("b" . dired-up-directory)
("H" . dired-hide-details-mode))
:config
(setq dired-listing-switches "-agho --group-directories-first"
dired-omit-files "^\\.[^.].*"
dired-omit-verbose nil
dired-dwim-target 'dired-dwim-target-next
dired-hide-details-hide-symlink-targets nil
dired-kill-when-opening-new-dired-buffer t
delete-by-moving-to-trash t)
(add-hook 'dired-mode-hook #'fn/dired-mode-hook))
(use-package savehist
:config
(setq history-length 25)
(savehist-mode 1))
;;; -- Make Help More Helpful -----
(use-package helpful
:custom
(counsel-describe-function-function #'helpful-callable)
(counsel-describe-variable-function #'helpful-variable)
:bind (([remap describe-function] . helpful-function)
([remap describe-symbol] . helpful-symbol)
([remap describe-variable] . helpful-variable)
([remap describe-command] . helpful-command)
([remap describe-key] . helpful-key)))
(provide 'fn-core)

23
modules/fn-desktop.el Normal file
View File

@ -0,0 +1,23 @@
;; -*- lexical-binding: t; -*-
;; Integrate with the system clipboard
(unless (display-graphic-p)
(use-package xclip
:demand t
:config
(xclip-mode 1)))
(use-package bluetooth)
;; Control NetworkManager via nmcli
(use-package nm
:vc (:url "https://github.com/Kodkollektivet/emacs-nm"
:rev :newest))
(use-package wakatime-mode
:init
(global-wakatime-mode))
(provide 'fn-desktop)

283
modules/fn-interface.el Normal file
View File

@ -0,0 +1,283 @@
;; -*- lexical-binding: t; -*-
(set-face-attribute 'default nil :font "BlexMono Nerd Font Mono" :height 130 :weight 'semi-light)
(use-package hydra)
(use-package vertico
:demand t
:bind (:map vertico-map
("C-j" . vertico-next)
("C-k" . vertico-previous)
("C-f" . vertico-exit-input)
:map minibuffer-local-map
("M-h" . vertico-directory-up))
:custom
(vertico-cycle t)
:custom-face
(vertico-current ((t (:background "#3a3f5a"))))
:config
(require 'vertico-directory)
(vertico-mode))
(use-package corfu
:bind (:map corfu-map
("C-j" . corfu-next)
("C-k" . corfu-previous)
("TAB" . corfu-insert)
([tab] . corfu-insert)
("C-f" . corfu-insert))
:custom
(corfu-cycle t)
(corfu-auto t)
(corfu-preview-current nil)
(corfu-quit-at-boundary t)
(corfu-quit-no-match t)
:config
(global-corfu-mode 1)
(defun corfu-enable-in-minibuffer ()
"Enable Corfu in the minibuffer if `completion-at-point' is bound."
(when (where-is-internal #'completion-at-point (list (current-local-map)))
;; (setq-local corfu-auto nil) ;; Enable/disable auto completion
(setq-local corfu-echo-delay nil ;; Disable automatic echo and popup
corfu-popupinfo-delay nil)
(corfu-mode 1)))
(add-hook 'minibuffer-setup-hook #'corfu-enable-in-minibuffer))
(use-package kind-icon
:after corfu
:custom (kind-icon-default-face 'corfu-default)
:config
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
(use-package orderless
:demand t
:config
(orderless-define-completion-style orderless+initialism
(orderless-matching-styles '(orderless-initialism
orderless-literal
orderless-regexp)))
(setq completion-styles '(orderless)
completion-category-defaults nil
orderless-matching-styles '(orderless-literal orderless-regexp)
completion-category-overrides
'((file (styles partial-completion)))))
(use-package wgrep
:after consult
:hook (grep-mode . wgrep-setup))
(use-package consult
:demand t
:bind (("C-s" . consult-line)
("C-M-l" . consult-imenu)
("C-M-j" . consult-buffer)
("C-x C-b" . consult-buffer)
:map minibuffer-local-map
("C-r" . consult-history))
:custom
(consult-project-root-function #'fn/get-project-root)
(completion-in-region-function #'consult-completion-in-region)
:config
(defun fn/get-project-root ()
(when (fboundp 'projectile-project-root)
(projectile-project-root))))
(use-package consult-dir
:bind (("C-x C-d" . consult-dir)
:map vertico-map
("C-x C-d" . consult-dir)
("C-x C-j" . consult-dir-jump-file))
:custom
(consult-dir-project-list-function nil))
(use-package marginalia
:after vertico
:custom
(marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light
nil))
:config
(marginalia-mode))
(use-package embark
:after vertico
:bind (("C-." . embark-act)
("M-." . embark-dwim)
:map minibuffer-local-map
("C-d" . embark-act)
:map embark-region-map
("D" . denote-region))
:config
;; Remove the mixed indicator to prevent the popup from being displayed
;; automatically
(delete #'embark-mixed-indicator embark-indicators)
(add-to-list 'embark-indicators 'embark-minimal-indicator)
;; Use Embark to show command prefix help
(setq prefix-help-command #'embark-prefix-help-command))
(use-package embark-consult
:after embark)
(use-package aggressive-indent)
(use-package rainbow-delimiters
:config
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
(use-package dashboard
:ensure t
;; :defer t
:init
(setq dashboard-startup-banner 3)
(setq dashboard-items '((recents . 5)
(projects . 5)))
;; Content is not centered by default. To center, set
(setq dashboard-center-content t)
;; vertically center content
(setq dashboard-vertically-center-content t)
;; To disable shortcut "jump" indicators for each section, set
(setq dashboard-show-shortcuts nil)
(setq dashboard-startupify-list '(dashboard-insert-banner
dashboard-insert-newline
dashboard-insert-navigator
dashboard-insert-newline
dashboard-insert-items
dashboard-insert-init-info
))
;; (add-to-list 'dashboard-items '(agenda) t)
;; (setq dashboard-week-agenda t)
:config
(dashboard-setup-startup-hook)
)
(use-package which-key
:config
(which-key-mode 1))
(use-package treemacs
:ensure t
:defer t
:init
(add-hook 'treemacs-mode-hook (lambda() (display-line-numbers-mode -1)))
(with-eval-after-load 'winum
(define-key winum-keymap (kbd "M-0") #'treemacs-select-window))
:config
(progn
(setq treemacs-collapse-dirs (if treemacs-python-executable 3 0)
treemacs-deferred-git-apply-delay 0.5
treemacs-directory-name-transformer #'identity
treemacs-display-in-side-window t
treemacs-eldoc-display 'simple
treemacs-file-event-delay 2000
treemacs-file-extension-regex treemacs-last-period-regex-value
treemacs-file-follow-delay 0.2
treemacs-file-name-transformer #'identity
treemacs-follow-after-init t
treemacs-expand-after-init t
treemacs-find-workspace-method 'find-for-file-or-pick-first
treemacs-git-command-pipe ""
treemacs-goto-tag-strategy 'refetch-index
treemacs-header-scroll-indicators '(nil . "^^^^^^")
treemacs-hide-dot-git-directory t
treemacs-indentation 2
treemacs-indentation-string " "
treemacs-is-never-other-window nil
treemacs-max-git-entries 5000
treemacs-missing-project-action 'ask
treemacs-move-files-by-mouse-dragging t
treemacs-move-forward-on-expand nil
treemacs-no-delete-other-windows t
treemacs-project-follow-cleanup nil
treemacs-persist-file (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
treemacs-position 'left
treemacs-read-string-input 'from-child-frame
treemacs-recenter-distance 0.1
treemacs-recenter-after-file-follow nil
treemacs-recenter-after-tag-follow nil
treemacs-recenter-after-project-jump 'always
treemacs-recenter-after-project-expand 'on-distance
treemacs-litter-directories '("/node_modules" "/.venv" "/.cask" )
treemacs-project-follow-into-home nil
treemacs-show-cursor nil
treemacs-show-hidden-files t
treemacs-silent-filewatch nil
treemacs-silent-refresh nil
treemacs-sorting 'alphabetic-asc
treemacs-select-when-already-in-treemacs 'move-back
treemacs-space-between-root-nodes t
treemacs-tag-follow-cleanup t
treemacs-tag-follow-delay 1.5
treemacs-text-scale nil
treemacs-user-mode-line-format nil
treemacs-user-header-line-format nil
treemacs-wide-toggle-width 70
treemacs-width 35
treemacs-width-increment 1
treemacs-width-is-initially-locked :on-nil
treemacs-workspace-switch-cleanup nil
treemacs-no-png-images t
treemacs-indent-guide-style 'block
)
;; The default width and height of the icons is 22 pixels. If you are
;; using a Hi-DPI display, uncomment this to double the icon size.
;; (treemacs-resize-icons 44)
(treemacs-git-mode 'deferred)
(treemacs-indent-guide-mode t)
(treemacs-git-commit-diff-mode t)
(treemacs-follow-mode t)
(treemacs-filewatch-mode t)
(treemacs-fringe-indicator-mode 'always)
(when treemacs-python-executable
(treemacs-git-commit-diff-mode t))
;; (pcase (cons (not (null (executable-find "git")))
;; (not (null treemacs-python-executable)))
;; (`(t . t)
;; (treemacs-git-mode 'deferred))
;; (`(t . _)
;; (treemacs-git-mode 'simple)))
(treemacs-hide-gitignored-files-mode nil)))
(use-package treemacs-magit
:after (treemacs magit))
(use-package spacious-padding
;; :after modus-theme
:custom
(spacious-padding-subtle-mode-line t)
(spacious-padding-subtle-mode-line
`(
:mode-line-active 'default
:mode-line-inactive vertical-border))
:init
(spacious-padding-mode)
;; (add-hook 'modus-themes-after-load-theme-hook 'spacious-padding-mode)
)
(provide 'fn-interface)

8
modules/fn-ops.el Normal file
View File

@ -0,0 +1,8 @@
;; -*- lexical-binding: t; -*-
(use-package kubed
:ensure t
:config
(keymap-global-set "C-c k" 'kubed-prefix-map))
(provide 'fn-ops)

41
modules/fn-present.el Normal file
View File

@ -0,0 +1,41 @@
;; -*- lexical-binding: t; -*-
(defun fn/present-prepare-slide ()
(when (and logos-focus-mode
(derived-mode-p 'org-mode))
(org-overview)
(org-show-entry)
(org-show-children)))
(defun fn/present-toggle ()
"Configures the buffer for a presentation."
(interactive)
(if logos-focus-mode
(progn
(setq-local face-remapping-alist nil)
(widen)
(logos-focus-mode 0))
(setq-local face-remapping-alist '((default (:height 1.5) default)
(org-document-title (:height 1.75) org-document-title)
(org-block-begin-line (:height 0.7) org-block)))
;; Narrow the buffer and start focus mode
(logos-narrow-dwim)
(logos-focus-mode 1)
;; Prepare the slide
(fn/present-prepare-slide)))
(use-package logos
:bind (([remap narrow-to-region] . logos-narrow-dwim)
([remap forward-page] . logos-forward-page-dwim)
([remap backward-page] . logos-backward-page-dwim))
:custom
(logos-outlines-are-pages t)
(logos-scroll-lock t)
:config
(setf (alist-get 'org-mode logos-outline-regexp-alist) "^\\*\\{1,2\\} +")
(add-hook 'logos-page-motion-hook #'fn/present-prepare-slide))
(provide 'fn-present)

49
modules/fn-vc.el Normal file
View File

@ -0,0 +1,49 @@
;; -*- lexical-binding: t; -*-
(use-package editorconfig
:ensure t
:init
(editorconfig-mode 1))
;; (use-package envrc
;; :hook (after-init . envrc-global-mode))
(defvar user-cache-directory (concat user-emacs-directory "var/"))
(use-package projectile
:demand t
:init
;; ensure projectile saves its files in a nice location
(setq projectile-cache-file
(concat user-cache-directory "projectile.cache"))
(setq projectile-known-projects-file
(concat user-cache-directory "projectile-bookmarks.eld"))
:config
(projectile-mode 1)
(setq projectile-globally-ignored-file-suffixes
'(
;; unity stuff
".meta" ".unity" ".asset" ".mat" ".cginc" ".prefab"
".renderTexture" ".lighting" ".shadergraph" ".shadersubgraph"
".shader" ".sceneWithBuildSettings" ".hlsl" ".vfx"
;; images
".png" ".xcf" ".jpg" ".jpeg" ".tif"
;; fonts
".ttf"
;; misc
".pdf"
))
(setq projectile-indexing-method 'hybrid)
;; :general
;; (leader-keys
;; "p" 'projectile-command-map)
)
(use-package treemacs-projectile)
(use-package magit)
(provide 'fn-vc)

113
modules/fn-workflow.el Normal file
View File

@ -0,0 +1,113 @@
;; -*- lexical-binding: t; -*-
;;; ----- TODO Configuration -----
(setq org-todo-keywords
'((sequence "TODO(t)" "WAIT(w)" "|" "DONE(d!)")))
(setq org-todo-keyword-faces
'(("GOAL" . (:foreground "orange red" :weight bold))
("WAIT" . (:foreground "HotPink2" :weight bold))
("BACK" . (:foreground "MediumPurple3" :weight bold))))
;;; ----- Context Tags -----
(setq-default org-tag-alist
'((:startgroup)
("Areas")
(:grouptags)
("@home" . ?H)
("@work" . ?W)
(:endgroup)
(:startgrouptag . nil)
("Contexts")
(:grouptags)
("@computer" . ?C)
("@mobile" . ?M)
("@calls" . ?A)
("@errands" . ?E)
(:endgrouptag)
;; Task Types
(:startgrouptag . nil)
("Types")
(:grouptags)
("@easy" . ?e)
("@hacking" . ?h)
("@writing" . ?w)
("@creative" . ?v)
("@accounting" . ?a)
("@email" . ?m)
("@system" . ?s)
(:endgrouptag)
;; Workflow states
(:startgroup . nil)
("States")
(:grouptags)
("@plan" . ?p)
("@review" . ?r)
("@followup" . ?f)
(:endgroup)))
;; Only make context tags inheritable (what about noexport?)
(setq org-use-tag-inheritance "^@")
;;; ----- Time Tracking -----
;; Clock in on the current task when setting a timer
(add-hook 'org-timer-set-hook #'org-clock-in)
;; Clock out of the current task when the timer is complete
(add-hook 'org-timer-done-hook #'org-clock-out)
;;; ----- Agenda Configuration -----
(defvar fn/base-agenda-files '("Inbox.org" "Schedule.org")
"The base agenda files that will always be included.")
(setq org-agenda-span 'day
org-agenda-start-with-log-mode t
org-agenda-files fn/base-agenda-files
org-agenda-window-setup 'current-window)
;; Make done tasks show up in the agenda log
(setq org-log-done 'time
org-log-into-drawer t)
;;; ----- Denote Integration -----
(defun fn/refresh-agenda-files ()
(interactive)
(setq org-agenda-files
(append (denote-directory-files "_pra")
fn/base-agenda-files)))
(defun fn/goto-weekly-note ()
(interactive)
(let* ((note-title (format-time-string "%Y-W%V"))
(existing-notes
(denote-directory-files (format "-%s" note-title) nil t)))
(if existing-notes
(find-file (car existing-notes))
(denote note-title '("plw")))))
(with-eval-after-load 'denote
;; Quick access commands
(keymap-set global-map "C-c n w" #'fn/goto-weekly-note)
;; Refresh agenda files the first time
(fn/refresh-agenda-files)
;; Update agenda files after notes are created or renamed
(add-hook 'denote-after-rename-file-hook #'fn/refresh-agenda-files)
(add-hook 'denote-after-new-note-hook #'fn/refresh-agenda-files))
(use-package esxml :ensure t)
(use-package ox-rss :ensure t)
(provide 'fn-workflow)

46
modules/fn-writing.el Normal file
View File

@ -0,0 +1,46 @@
;; -*- lexical-binding: t; -*-
(use-package denote
:demand t
:bind (("C-c n l" . denote-link-or-create)
("C-c n o" . denote-open-or-create)
("C-c n r" . denote-rename-file-using-front-matter))
:custom
(denote-directory "~/Notes")
(denote-rename-buffer-format "Denote: %t (%k)")
(denote-infer-keywords nil)
(denote-known-keywords
'("pra" "prb" "prc"
"ply" "plm" "plw"
"kt" "ke" "kp" "kl" "ka" "kap"
"kcp" "kca" "kcc"
"kra" "krb" "krv"
"rn"))
:config
(require 'denote-rename-buffer)
(require 'denote-org-extras)
;; Rename buffers with the note name
(denote-rename-buffer-mode 1)
;; Buttonize all denote links in text buffers
(add-hook 'text-mode-hook #'denote-fontify-links-mode-maybe))
(defun fn/setup-markdown-mode ()
(center-document-mode 1)
(display-line-numbers-mode 0))
(use-package markdown-mode
:config
(setq markdown-command "marked")
(add-hook 'markdown-mode-hook #'fn/setup-markdown-mode)
(dolist (face '((markdown-header-face-1 . 1.2)
(markdown-header-face-2 . 1.1)
(markdown-header-face-3 . 1.0)
(markdown-header-face-4 . 1.0)
(markdown-header-face-5 . 1.0)))
(set-face-attribute (car face) nil :weight 'normal :height (cdr face))))
(provide 'fn-writing)

3
systems/mearah.el Normal file
View File

@ -0,0 +1,3 @@
(setq fn/use-config-modules
(append fn/common-config-modules
'(fn-desktop)))