This commit is contained in:
Little Fluffy Clouds 2025-07-09 19:38:16 +03:00
commit fed46fec0b
8 changed files with 1329 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*
!.gitignore
!init.el
!early-init.el
!custom.el
!snippets
!emacs/*

50
custom.el Normal file
View File

@ -0,0 +1,50 @@
;; (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.
;; '(cursor ((t (:background "#ebdbb2"))))
;; '(secondary-selection ((t (:extend t :background "#504945"))))
;; '(show-paren-match ((t (:background "#504946" :weight bold))))
;; '(vhl/default-face ((t (:background "#504945"))))
;; '(wgrep-face ((t (:background "#504945" :foreground "#b8bb26" :weight bold)))))
(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.
'(custom-safe-themes
'("77fff78cc13a2ff41ad0a8ba2f09e8efd3c7e16be20725606c095f9a19c24d3d"
"b5fd9c7429d52190235f2383e47d340d7ff769f141cd8f9e7a4629a81abc6b19"
"0d2c5679b6d087686dcfd4d7e57ed8e8aedcccc7f1a478cd69704c02e4ee36fe"
"e8ceeba381ba723b59a9abc4961f41583112fc7dc0e886d9fc36fa1dc37b4079"
"aec7b55f2a13307a55517fdf08438863d694550565dee23181d2ebd973ebd6b8"
"dfb1c8b5bfa040b042b4ef660d0aab48ef2e89ee719a1f24a4629a0c5ed769e8"
"e1f4f0158cd5a01a9d96f1f7cdcca8d6724d7d33267623cc433fe1c196848554"
"7964b513f8a2bb14803e717e0ac0123f100fb92160dcf4a467f530868ebaae3e"
"691d671429fa6c6d73098fc6ff05d4a14a323ea0a18787daeb93fde0e48ab18b"
"48042425e84cd92184837e01d0b4fe9f912d875c43021c3bcb7eeb51f1be5710"
"88f7ee5594021c60a4a6a1c275614103de8c1435d6d08cc58882f920e0cec65e" default))
'(eat-semi-char-non-bound-keys
'([24] [28] [17] [7] [8] [27 3] [21] [27 120] [27 58] [27 33] [27 38] [C-insert]
[M-insert] [S-insert] [C-M-insert] [C-S-insert] [M-S-insert] [C-M-S-insert]
[C-delete] [M-delete] [S-delete] [C-M-delete] [C-S-delete] [M-S-delete]
[C-M-S-delete] [C-deletechar] [M-deletechar] [S-deletechar]
[C-M-deletechar] [C-S-deletechar] [M-S-deletechar] [C-M-S-deletechar]
[C-up] [C-down] [C-right] [C-left] [M-up] [M-down] [M-right] [M-left]
[S-up] [S-down] [S-right] [S-left] [C-M-up] [C-M-down] [C-M-right]
[C-M-left] [C-S-up] [C-S-down] [C-S-right] [C-S-left] [M-S-up] [M-S-down]
[M-S-right] [M-S-left] [C-M-S-up] [C-M-S-down] [C-M-S-right] [C-M-S-left]
[C-home] [M-home] [S-home] [C-M-home] [C-S-home] [M-S-home] [C-M-S-home]
[C-end] [M-end] [S-end] [C-M-end] [C-S-end] [M-S-end] [C-M-S-end] [C-prior]
[M-prior] [S-prior] [C-M-prior] [C-S-prior] [M-S-prior] [C-M-S-prior]
[C-next] [M-next] [S-next] [C-M-next] [C-S-next] [M-S-next] [C-M-S-next]))
'(org-agenda-files
'("~/org/archive/work/ledger.org" "/home/trickster/org/agenda.org"))
'(warning-suppress-types '((use-package))))
(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.
'(secondary-selection ((t (:extend t :background "#32353f")))))

72
early-init.el Normal file
View File

@ -0,0 +1,72 @@
(defvar +emacs--startup-restore-alist nil
"Variables and values to restore after init.")
(add-hook 'emacs-startup-hook
(defun emacs-startup@restore-values ()
"Restore values set during init.
This applies values in `+emacs--startup-restore-alist'."
(dolist (a +emacs--startup-restore-alist)
(set (car a) (cdr a)))))
(defun +set-during-startup (variable value &optional restore)
"Set VARIABLE to VALUE during startup, but restore to RESTORE.
If RESTORE is nil or not passed, save the original value and
restore that."
(unless nil ;after-init-time
(setf (alist-get variable +emacs--startup-restore-alist)
(or restore (symbol-value variable)))
(set-default variable value)))
;; Garbage collection
(defvar +gc-treshold (* 100 1024 1024)
"Threshold in bytes for when to start garbage collection")
(defun +gc-disable ()
"Functionally disable the Garbage collector."
(setq gc-cons-threshold most-positive-fixnum)
(setq gc-cons-percentage 0.8))
(defun +gc-enable ()
"Enable the Garbage collector."
(interactive)
(setq gc-cons-threshold +gc-treshold)
(setq gc-cons-percentage 0.2))
;; Disable gc during init
(+gc-disable)
;; Disable gc in minibuffers
;; BUG: memory leaks?
;; (add-hook 'minibuffer-setup-hook #'+gc-disable)
;; (add-hook 'minibuffer-exit-hook #'+gc-enable)
;; Enable gc after init
(add-hook 'emacs-startup-hook #'+gc-enable)
(add-hook 'after-init-hook #'+gc-enable)
;; prevent font caching for better perfomance
;; in return of bigger memory footprint
(setq inhibit-compacting-font-caches t)
(setq package-enable-at-startup nil)
;; Don't prematurely re-display
(+set-during-startup 'inhibit-redisplay t)
(+set-during-startup 'inhibit-message t)
;; Debug during init
(+set-during-startup 'debug-on-error t)
(push '(font . "Iosevka Comfy Fixed") default-frame-alist)
(set-face-font 'default "Iosevka Comfy Fixed")
(copy-face 'default 'fixed-pitch)
(set-face-attribute 'default nil :height 120)
;; prevent font caching for better perfomance
;; in return of bigger memory footprint
(setq inhibit-compacting-font-caches t)
(advice-add #'x-apply-session-resources :override #'ignore)
;; Debug during init
;; (+set-during-startup 'debug-on-error t)
(provide 'early-init)

133
emacs/defaults.el Normal file
View File

@ -0,0 +1,133 @@
(setq-default
auto-hscroll-mode 'current-line
dired-dwim-target t
auto-window-vscroll nil
apropos-do-all t
make-backup-files nil
auto-save-default nil
warning-minimum-level :error
create-lockfiles nil
confirm-kill-emacs #'y-or-n-p
delete-old-versions t
display-line-numbers-widen nil
display-line-numbers-current-absolute t
echo-keystrokes 0.1
enable-recursive-minibuffers t
enable-local-variables t
enable-local-eval t
executable-prefix-env t
fast-but-imprecise-scrolling t
fill-column 80
find-file-visit-truename t
frame-resize-pixelwise t
global-mark-ring-max 100
;; hscroll-margin 1
;; hscroll-step 1
imenu-auto-rescan 1
indent-tabs-mode nil
inhibit-startup-screen t
initial-buffer-choice t
kept-new-versions 2
kept-old-versions 2
kill-do-not-save-duplicates t
kill-read-only-ok t
kill-ring-max 100
kmacro-ring-max 20
kill-buffer-query-functions nil
load-prefer-newer t
mark-ring-max 50
mode-require-final-newline 'visit-save
mouse-drag-copy-region t
mouse-wheel-progressive-speed nil
mouse-yank-at-point t
read-answer-short t
read-process-output-max (* 1024 1024)
ring-bell-function 'ignore
save-interprogram-paste-before-kill t
;; scroll-conservatively 101
;; scroll-down-aggressively 0.01
;; scroll-margin 1
scroll-preserve-screen-position 1
;; scroll-step 1
;; scroll-up-aggressively 0.01
search-ring-max 200
sentence-end-double-space t
set-mark-command-repeat-pop t
show-paren-delay 0
show-paren-when-point-in-periphery t
show-paren-when-point-inside-paren t
tramp-backup-directory-alist backup-directory-alist
truncate-lines t
truncate-string-ellipsis ""
tab-width 4
undo-limit 100000000 ;; 10MB
use-dialog-box nil
use-file-dialog nil
use-short-answers t
vc-follow-symlinks t
vc-make-backup-files t
version-control t
view-read-only t
visible-bell nil
frame-resize-pixelwise t
frame-inhibit-implied-resize t
yank-pop-change-selection t)
(setq-default
locale-coding-system 'utf-8-unix
coding-system-for-read 'utf-8-unix
coding-system-for-write 'utf-8-unix
buffer-file-coding-system 'utf-8-unix
default-process-coding-system '(utf-8-unix . utf-8-unix)
x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(set-charset-priority 'unicode)
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8-unix)
(set-default-coding-systems 'utf-8-unix)
(set-terminal-coding-system 'utf-8-unix)
(set-keyboard-coding-system 'utf-8-unix)
(setq backup-directory-alist
`(("." . ,(concat user-emacs-directory "backups"))))
(pcase system-type
((or 'ms-dos 'windows-nt)
(set-clipboard-coding-system 'utf-16-le)
(set-selection-coding-system 'utf-16-le))
(_
(set-selection-coding-system 'utf-8)
(set-clipboard-coding-system 'utf-8)))
(dolist (disable-mode '(tooltip-mode
tool-bar-mode
menu-bar-mode
scroll-bar-mode
horizontal-scroll-bar-mode))
(when (fboundp disable-mode)
(funcall disable-mode -1)))
(setq-default mode-line-format (delq 'mode-line-modes mode-line-format))
(setq-default whitespace-style
'(face spaces empty tabs newline trailing space-mark tab-mark newline-mark))
(setq-default notmuch-search-oldest-first nil)
(setq-default remote-file-name-inhibit-locks t
tramp-use-scp-direct-remote-copying t
remote-file-name-inhibit-auto-save-visited t
tramp-copy-size-limit (* 1024 1024) ;; 1MB
tramp-verbose 2)
(connection-local-set-profile-variables
'remote-direct-async-process
'((tramp-direct-async-process . t)))
(connection-local-set-profiles
'(:application tramp :protocol "scp")
'remote-direct-async-process)
(setq-default magit-tramp-pipe-stty-settings 'pty)
(with-eval-after-load 'tramp
(with-eval-after-load 'compile
(remove-hook 'compilation-mode-hook #'tramp-compile-disable-ssh-controlmaster-options)))

395
emacs/org.el Normal file
View File

@ -0,0 +1,395 @@
(use-feature org
:bind (("C-c a" . org-agenda)
("C-c c" . org-capture)
:map org-mode-map
("C-c ]" . nil)
("C-c [" . nil)
("C-c ," . nil)
("C->" . org-do-demote)
("C-<" . org-do-promote))
:hook (org-mode . visual-line-mode)
:config
(setq org-refile-targets (quote ((nil :maxlevel . 9)
(org-agenda-files :maxlevel . 9))))
(setq org-default-notes-file "~/org/agenda.org")
(setq org-hide-leading-stars t)
(setq org-timestamp-rounding-minutes '(5 5))
(setq org-agenda-compact-blocks t)
(setq org-agenda-dim-blocked-tasks nil)
(setq org-enforce-todo-dependencies t)
(setq org-fast-tag-selection-include-todo t)
(setq org-use-fast-todo-selection t)
(setq org-use-fast-todo-selection t)
(setq org-fast-tag-selection-single-key 'expert)
(setq diary-file "~/org/diary.org")
(setq org-agenda-files (quote ("~/org/agenda.org")))
(add-hook 'org-agenda-finalize-hook '+remove-agenda-regions))
(defun +is-project-p ()
"A task with a 'PROJ' keyword"
(member (nth 2 (org-heading-components)) '("PROJ")))
(defun +is-project-p ()
"Any task with a todo keyword subtask."
(save-restriction
(widen)
(let ((has-subtask)
(subtree-end (save-excursion (org-end-of-subtree t)))
(is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
(save-excursion
(forward-line 1)
(while (and (not has-subtask)
(< (point) subtree-end)
(re-search-forward "^\*+ " subtree-end t))
(when (member (org-get-todo-state) org-todo-keywords-1)
(setq has-subtask t))))
(and is-a-task has-subtask))))
(setq org-clock-in-switch-to-state '+clock-in-to-next)
(defun +clock-in-to-next (kw)
"Switch a task from TODO to NEXT when clocking in.
Skips capture tasks, projects, and subprojects.
Switch projects and subprojects from NEXT back to TODO"
(when (not (and (boundp 'org-capture-mode) org-capture-mode))
(cond
((and (member (org-get-todo-state) (list "TODO"))
(not (+is-project-p)))
"NEXT")
((and (member (org-get-todo-state) (list "NEXT"))
(+is-project-p))
"TODO"))))
(defun +find-project-task ()
"Any task with a todo keyword that is in a project subtree"
(save-restriction
(widen)
(let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
(while (org-up-heading-safe)
(when (member (nth 2 (org-heading-components)) '("PROJ"))
(setq parent-task (point))))
(goto-char parent-task)
parent-task)))
(defun +is-project-subtree-p ()
"Any task with a todo keyword that is in a project subtree.
Callers of this function already widen the buffer view."
(let ((task (save-excursion (org-back-to-heading 'invisible-ok)
(point))))
(save-excursion
(+find-project-task)
(if (equal (point) task)
nil t))))
(defun +find-project-task ()
"Move point to the parent (project) task if any."
(save-restriction
(widen)
(let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
(while (org-up-heading-safe)
(when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
(setq parent-task (point))))
(goto-char parent-task)
parent-task)))
(defun +is-project-subtree-p ()
"Any task with a todo keyword that is in a project subtree.
Callers of this function already widen the buffer view."
(let ((task (save-excursion (org-back-to-heading 'invisible-ok)
(point))))
(save-excursion
(+find-project-task)
(if (equal (point) task)
nil
t))))
(defvar +hide-deadline-next-tasks t)
(defun +select-with-tag-function (select-fun-p)
(save-restriction
(widen)
(let ((next-headline
(save-excursion (or (outline-next-heading)
(point-max)))))
(if (funcall select-fun-p) nil next-headline))))
(defun +select-projects ()
"Selects tasks which are project headers"
(+select-with-tag-function #'+is-project-p))
(defun +select-project-tasks ()
"Skips tags which belong to projects (and is not a project itself)"
(+select-with-tag-function
#'(lambda () (and
(not (+is-project-p))
(+is-project-subtree-p)))))
(defun +select-standalone-tasks ()
"Skips tags which belong to projects. Is neither a project, nor does it blong to a project"
(+select-with-tag-function
#'(lambda () (and
(not (+is-project-p))
(not (+is-project-subtree-p))))))
(defun +select-projects-and-standalone-tasks ()
"Skips tags which are not projects"
(+select-with-tag-function
#'(lambda () (or
(+is-project-p)
(+is-project-subtree-p)))))
(defun +org-agenda-project-warning ()
"Is a project stuck or waiting. If the project is not stuck,
show nothing. However, if it is stuck and waiting on something,
show this warning instead."
(if (+org-agenda-project-is-stuck)
(if (+org-agenda-project-is-waiting) " !W" " !S") ""))
(defun +org-agenda-project-is-stuck ()
"Is a project stuck"
(if (+is-project-p) ; first, check that it's a project
(let* ((subtree-end (save-excursion (org-end-of-subtree t)))
(has-next))
(save-excursion
(forward-line 1)
(while (and (not has-next)
(< (point) subtree-end)
(re-search-forward "^\\*+ NEXT " subtree-end t))
(unless (member "WAITING" (org-get-tags-at))
(setq has-next t))))
(if has-next nil t)) ; signify that this project is stuck
nil)) ; if it's not a project, return an empty string
(defun +org-agenda-project-is-waiting ()
"Is a project stuck"
(if (+is-project-p) ; first, check that it's a project
(let* ((subtree-end (save-excursion (org-end-of-subtree t))))
(save-excursion
(re-search-forward "^\\*+ WAITING" subtree-end t)))
nil)) ; if it's not a project, return an empty string
;; Some helper functions for agenda views
(defun +org-agenda-prefix-string ()
"Format"
(let ((path (org-format-outline-path (org-get-outline-path))) ; "breadcrumb" path
(stuck (+org-agenda-project-warning))) ; warning for stuck projects
(if (> (length path) 0)
(concat stuck ; add stuck warning
" [" path "]") ; add "breadcrumb"
stuck)))
(defun +org-agenda-add-location-string ()
"Gets the value of the LOCATION property"
(let ((loc (org-entry-get (point) "LOCATION")))
(if (> (length loc) 0)
(concat "{" loc "} ")
"")))
(defvar +org-agenda-block--today-schedule
'(agenda "" ((org-agenda-overriding-header "Today's Schedule:")
(org-agenda-span 'day)
(org-agenda-ndays 1)
(org-agenda-start-on-weekday nil)
(org-agenda-start-day "+0d")))
"A block showing a 1 day schedule.")
(defvar +org-agenda-block--weekly-log
'(agenda "" ((org-agenda-overriding-header "Weekly Log")))
"A block showing my schedule and logged tasks for this week.")
(defvar +org-agenda-block--previous-calendar-data
'(agenda "" ((org-agenda-overriding-header "Previous Calendar Data (last 3 weeks)")
(org-agenda-start-day "-21d")
(org-agenda-span 21)
(org-agenda-start-on-weekday nil)))
"A block showing my schedule and logged tasks for the last few weeks.")
(defvar +org-agenda-block--upcoming-calendar-data
'(agenda "" ((org-agenda-overriding-header "Upcoming Calendar Data (next 2 weeks)")
(org-agenda-start-day "0d")
(org-agenda-span 14)
(org-agenda-start-on-weekday nil)))
"A block showing my schedule for the next couple weeks.")
(defvar +org-agenda-block--next-tasks
'(tags-todo "-INACTIVE-SOMEDAY-CANCELLED-ARCHIVE/!NEXT"
((org-agenda-overriding-header "Next Tasks:")
))
"Next tasks.")
(defvar +org-agenda-block--todo-tasks
'(tags-todo "-INACTIVE-SOMEDAY-CANCELLED-ARCHIVE/!TODO"
((org-agenda-overriding-header "Todo Tasks:")
))
"Next tasks.")
(defvar +org-agenda-block--waiting-tasks
'(tags-todo "-INACTIVE-SOMEDAY-CANCELLED-ARCHIVE/!WAITING"
((org-agenda-overriding-header "Waiting Tasks:")
))
"Tasks marked as waiting.")
(defvar +org-agenda-block--active-projects
'(tags-todo "-INACTIVE-SOMEDAY-CANCELLED-REFILEr/!"
((org-agenda-overriding-header "Active Projects:")
(org-agenda-skip-function '+select-projects)))
"All active projects: no inactive/someday/cancelled/refile.")
(defvar +org-agenda-block--standalone-tasks
'(tags-todo "-INACTIVE-SOMEDAY-CANCELLED-REFILE-ARCHIVE-STYLE=\"habit\"/!-NEXT"
((org-agenda-overriding-header "Standalone Tasks:")
(org-agenda-skip-function '+select-standalone-tasks)))
"Tasks (TODO) that do not belong to any projects.")
(defvar +org-agenda-block--remaining-project-tasks
'(tags-todo "-INACTIVE-SOMEDAY-CANCELLED-WAITING-REFILE-ARCHIVE/!-NEXT"
((org-agenda-overriding-header "Remaining Project Tasks:")
(org-agenda-skip-function '+select-project-tasks)))
"Non-NEXT TODO items belonging to a project.")
(defvar +org-agenda-block--inactive-tags
'(tags-todo "-SOMEDAY-ARCHIVE-CANCELLED/!INACTIVE"
((org-agenda-overriding-header "Inactive Projects and Tasks")
(org-tags-match-list-sublevels nil)))
"Inactive projects and tasks.")
(defvar +org-agenda-block--someday-tags
'(tags-todo "-INACTIVE-ARCHIVE-CANCELLED/!SOMEDAY"
((org-agenda-overriding-header "Someday Projects and Tasks")
(org-tags-match-list-sublevels nil)))
"Someday projects and tasks.")
(defvar +org-agenda-block--end-of-agenda
'(tags "ENDOFAGENDA"
((org-agenda-overriding-header "End of Agenda")
(org-tags-match-list-sublevels nil)))
"End of the agenda.")
(defvar +org-agenda-display-settings
'((org-agenda-start-with-log-mode t)
(org-agenda-log-mode-items '(clock))
(org-agenda-prefix-format '((agenda . " %-12:c%?-12t %(+org-agenda-add-location-string)% s")
(timeline . " % s")
(todo . " %-12:c %(+org-agenda-prefix-string) ")
(tags . " %-12:c %(+org-agenda-prefix-string) ")
(search . " %i %-12:c")))
(org-agenda-todo-ignore-deadlines 'near)
(org-agenda-todo-ignore-scheduled t))
"Display settings for my agenda views.")
(defvar +org-agenda-entry-display-settings
'(,+org-agenda-display-settings
(org-agenda-entry-text-mode t))
"Display settings for my agenda views with entry text.")
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "PROJ(p)" "|" "DONE(d)")
(sequence "TASK(T)")
(sequence "WAITING(w@/!)" "INACTIVE(i)" "SOMEDAY(s)" "|" "CANCELLED(c@/!)")))
(setq org-todo-state-tags-triggers
'(("CANCELLED" ("CANCELLED" . t))
("WAITING" ("SOMEDAY") ("INACTIVE") ("WAITING" . t))
("INACTIVE" ("WAITING") ("SOMEDAY") ("INACTIVE" . t))
("SOMEDAY" ("WAITING") ("INACTIVE") ("SOMEDAY" . t))
(done ("WAITING") ("INACTIVE") ("SOMEDAY"))
("TODO" ("WAITING") ("CANCELLED") ("INACTIVE") ("SOMEDAY"))
("TASK" ("WAITING") ("CANCELLED") ("INACTIVE") ("SOMEDAY"))
("NEXT" ("WAITING") ("CANCELLED") ("INACTIVE") ("SOMEDAY"))
("PROJ" ("WAITING") ("CANCELLED") ("INACTIVE") ("SOMEDAY"))
("DONE" ("WAITING") ("CANCELLED") ("INACTIVE") ("SOMEDAY"))))
(defvar org-capture-templates
'(("t" "todo" entry (file org-default-notes-file)
"* TODO %?\n%u\n%a\n")
("b" "Blank" entry (file org-default-notes-file)
"* %?\n%u")
("m" "Meeting" entry (file org-default-notes-file)
"* Meeting with %? :MEETING:\n")
("d" "Diary" entry (file+datetree 'diary-file)
"* %?\n%U\n")
("i" "Idea" entry (file org-default-notes-file)
"* %? :IDEA: \n%u")
("n" "Next Task" entry (file+headline org-default-notes-file "Tasks")
"** NEXT %? \nDEADLINE: %t")))
(setq org-agenda-time-grid
(quote
((daily today remove-match)
(800 1200 1600 2000)
"......" "----------------")))
(setq org-agenda-custom-commands
`((" " "Export Schedule"
(,+org-agenda-block--today-schedule
,+org-agenda-block--next-tasks
,+org-agenda-block--active-projects
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("l" "Weekly Log"
(,+org-agenda-block--weekly-log)
,+org-agenda-display-settings)
("r " "Agenda Review (all)"
(,+org-agenda-block--next-tasks
,+org-agenda-block--active-projects
,+org-agenda-block--standalone-tasks
,+org-agenda-block--waiting-tasks
,+org-agenda-block--remaining-project-tasks
,+org-agenda-block--inactive-tags
,+org-agenda-block--someday-tags
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("rn" "Agenda Review (next tasks)"
(,+org-agenda-block--next-tasks
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("rp" "Agenda Review (previous calendar data)"
(,+org-agenda-block--previous-calendar-data
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("ru" "Agenda Review (upcoming calendar data)"
(,+org-agenda-block--upcoming-calendar-data
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("rw" "Agenda Review (waiting tasks)"
(,+org-agenda-block--waiting-tasks
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("rP" "Agenda Review (projects list)"
(,+org-agenda-block--active-projects
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)
("ri" "Agenda Review (someday and inactive projects/tasks)"
(,+org-agenda-block--someday-tags
,+org-agenda-block--inactive-tags
,+org-agenda-block--end-of-agenda)
,+org-agenda-display-settings)))
;; Search for a "=" and go to the next line
(defun +org-agenda-next-section ()
"Go to the next section in an org agenda buffer."
(interactive)
(if (search-forward "===" nil t 1)
(forward-line 1)
(goto-char (point-max)))
(beginning-of-line))
;; Search for a "=" and go to the previous line
(defun +org-agenda-prev-section ()
"Go to the next section in an org agenda buffer."
(interactive)
(forward-line -2)
(if (search-forward "===" nil t -1)
(forward-line 1)
(goto-char (point-min))))
(defun +remove-agenda-regions ()
(save-excursion
(goto-char (point-min))
(let ((region-large t))
(while (and (< (point) (point-max)) region-large)
(set-mark (point))
(+org-agenda-next-section)
(if (< (- (region-end) (region-beginning)) 5) (setq region-large nil)
(if (< (count-lines (region-beginning) (region-end)) 4)
(delete-region (region-beginning) (region-end)))
)))))
(add-hook 'org-agenda-finalize-hook '+remove-agenda-regions)

433
emacs/packages.el Normal file
View File

@ -0,0 +1,433 @@
;;;
;;; Internal features
;;;
(use-feature emacs
:demand t
:custom
(scroll-conservatively 101 "Scroll just enough to bring text into view")
(enable-recursive-minibuffers t "Allow minibuffer commands in minibuffer")
(frame-title-format '(buffer-file-name "%f" ("%b"))
"Make frame title current file's name.")
(find-library-include-other-files nil)
(indent-tabs-mode nil "Use spaces, not tabs")
(tab-always-indent 'complete)
(text-mode-ispell-word-completion nil)
(read-extended-command-predicate #'command-completion-default-include-p)
(tab-stop-list (number-sequence 2 120 2))
(report-emacs-bug-no-explanations t)
(report-emacs-bug-no-confirmation t))
(use-feature epa
:config
;; (setenv "GPG_AGENT_INFO" nil)
(setf epg-pinentry-mode 'loopback)
)
(use-feature winner
:config
(winner-mode +1))
(use-feature notmuch
:config
(setq notmuch-show-logo nil))
(use-feature tramp
:config
(setq tramp-default-method "rsync")
(setq remote-file-name-inhibit-locks t
tramp-use-scp-direct-remote-copying t
remote-file-name-inhibit-auto-save-visited t
tramp-copy-size-limit (* 1024 1024) ;; 1MB
tramp-verbose 2)
(setq magit-tramp-pipe-stty-settings 'pty)
(connection-local-set-profile-variables
'remote-direct-async-process
'((tramp-direct-async-process . t)))
(connection-local-set-profiles
'(:application tramp :protocol "rsync")
'remote-direct-async-process)
(with-eval-after-load 'tramp
(with-eval-after-load 'compile
(remove-hook 'compilation-mode-hook #'tramp-compile-disable-ssh-controlmaster-options)))
)
(use-feature compile-mode
:config
(setq compilation-scroll-output t)
:bind ("C-c C-c" . compile))
(use-feature compile
:commands (compile recompile)
:custom (compilation-scroll-output 'first-error)
:config
(defun +compilation-colorize ()
"Colorize from `compilation-filter-start' to `point'."
(require 'ansi-color)
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max))))
(add-hook 'compilation-filter-hook #'+compilation-colorize))
;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-feature savehist
:init
(savehist-mode))
(use-feature dired
:commands (dired)
:custom
(dired-mouse-drag-files t)
(dired-listing-switches "-alh" "Human friendly file sizes.")
(dired-kill-when-opening-new-dired-buffer t)
(dired-omit-files "\\(?:\\.+[^z-a]*\\)")
:hook (dired-mode-hook . dired-omit-mode))
(use-feature ediff
:defer t
:custom
(ediff-window-setup-function #'ediff-setup-windows-plain)
(ediff-split-window-function #'split-window-horizontally))
(use-feature autorevert
:defer 2
:custom
(auto-revert-interval 0.01 "Instantaneously revert")
:config
(global-auto-revert-mode t))
;;;
;;; General
;;;
(use-package age
:ensure t
:config
(age-file-enable))
(use-package easy-kill
:bind
(([remap kill-ring-save] . easy-kill)))
(use-package doom-themes
:ensure t
:config
(load-theme 'doom-sourcerer t)
(setq doom-themes-disable-italic t)
)
(use-package corfu
:config
(global-corfu-mode))
(use-package avy
:bind
(("C-:" . avy-goto-char)))
(use-package git-timemachine
:ensure t)
(use-package crux
:ensure t
:config
(crux-with-region-or-buffer indent-region)
(crux-with-region-or-buffer untabify)
(crux-with-region-or-line comment-or-uncomment-region)
:bind
(("C-c o" . crux-open-with)
([remap default-indent-new-line] . crux-smart-open-line)
("C-M-j" . crux-smart-open-line-above)
("C-c u" . crux-view-url)
("C-c n" . crux-cleanup-buffer-or-region)
("C-c f d" . crux-recentf-find-directory)
("C-," . crux-duplicate-current-line-or-region)
("C-c M-d" . crux-duplicate-and-comment-current-line-or-region)
("C-c r" . crux-rename-file-and-buffer)
("C-c b k" . crux-kill-other-buffers)))
;; (use-package company
;; :config
;; (setq company-format-margin-function nil)
;; (setq company-tooltip-scrollbar-width 0)
;; (global-company-mode))
(use-package magit
:defer t
:bind
(("C-c v C" . magit-clone)
("C-c v ." . magit-file-dispatch)
("C-c v /" . magit-dispatch)
("C-c v g" . magit-status)
("C-c v G" . magit-status-here)
("C-c v x" . magit-file-delete)
("C-c v B" . magit-blame-addition)
("C-c v F" . magit-fetch)
("C-c v L" . magit-log-buffer-file)
("C-c v S" . magit-stage-file)
("C-c v U" . magit-unstage-file))
:custom
(magit-repository-directories (list (cons elpaca-repos-directory 1)))
(magit-diff-refine-hunk 'all)
(magit-deisplay-buffer-function #'+magit-display-buffer)
:config
(transient-bind-q-to-quit))
(use-package transient :defer t) ;; Use MELPA until built-in version updated.
(use-package vertico
:custom
;; (vertico-scroll-margin 0) ;; Different scroll margin
;; (vertico-count 20) ;; Show more candidates
(vertico-resize t) ;; Grow and shrink the Vertico minibuffer
(vertico-cycle t) ;; Enable cycling for `vertico-next/previous'
:init
(vertico-mode)
(vertico-multiform-mode)
:config
(add-to-list 'vertico-multiform-categories '(embark-keybinding grid))
;; Configure the display per command.
;; Use a buffer with indices for imenu
;; and a flat (Ido-like) menu for M-x.
(setq vertico-multiform-commands
'((consult-imenu buffer indexed)))
;; Configure the display per completion category.
;; Use the grid display for files and a buffer
;; for the consult-grep commands.
(setq vertico-multiform-categories
'((embark-keybinding grid)
(consult-grep buffer))))
;; (use-package org-caldav
;; :ensure t)
(use-package consult-yasnippet
:bind ("C-c C-y" . consult-yasnippet))
(use-package yasnippet
:bind (:map global-map
("C-z" . nil)
:map yas-minor-mode-map
("TAB" . nil)
("C-z" . yas-expand))
:config
(yas-global-mode +1))
(use-package yasnippet-snippets
:after (yasnippet)
:ensure t)
(use-package embark
:ensure t
:bind
(("C-." . embark-act)
("M-." . embark-dwim)
("C-h B" . embark-bindings))
:init
(setq prefix-help-command #'embark-prefix-help-command)
:config
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))))
(use-package embark-consult
:ensure t
:hook
(embark-collect-mode . consult-preview-at-point-mode))
(use-package orderless
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles partial-completion)))))
(use-package rg
:when (executable-find "rg")
:config
(setq xref-search-program 'ripgrep))
(use-package volatile-highlights
:config (volatile-highlights-mode t))
(use-package vundo)
(use-package marginalia
:ensure t
:config
(marginalia-mode))
(use-package consult
;; Replace bindings. Lazily loaded by `use-package'.
:bind (;; C-c bindings in `mode-specific-map'
("C-c M-x" . consult-mode-command)
("C-c h" . consult-history)
("C-c k" . consult-kmacro)
("C-c m" . consult-man)
("C-c i" . consult-info)
([remap Info-search] . consult-info)
;; C-x bindings in `ctl-x-map'
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x C-b" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
;; M-g bindings in `goto-map'
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings in `search-map'
("M-s d" . consult-find) ;; Alternative: consult-fd
("M-s c" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
;; Minibuffer history
:map minibuffer-local-map
("M-s" . consult-history) ;; orig. next-matching-history-element
("M-r" . consult-history)) ;; orig. previous-matching-history-element
:hook (completion-list-mode . consult-preview-at-point-mode)
:init
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
(advice-add #'register-preview :override #'consult-register-window)
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:config
(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-file-register
consult--source-recent-file consult--source-project-recent-file
:preview-key '(:debounce 0.4 any))
(setq consult-narrow-key "<") ;; "C-+"
)
(use-package ace-window
:ensure t
:bind (("M-o" . ace-window))
:config
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
(setq aw-scope 'frame)
(marginalia-mode))
(use-package golden-ratio
:config
(golden-ratio-mode 1)
;; Refer to issue #57 for the complete code, this is just for ease
(add-hook 'buffer-list-update-hook #'golden-ratio)
(add-hook 'focus-in-hook #'golden-ratio)
(add-hook 'focus-out-hook #'golden-ratio))
(use-package dired-subtree
:ensure t
:after dired
:bind
( :map dired-mode-map
("<tab>" . dired-subtree-toggle)
("TAB" . dired-subtree-toggle)
("<backtab>" . dired-subtree-remove)
("S-TAB" . dired-subtree-remove))
:config
(setq dired-subtree-use-backgrounds nil))
(use-package transpose-frame
:ensure t)
(use-package rainbow-mode
:ensure t)
;;
;; Language modes
;;
(use-package tide
:config
(defun +turn-on-tide-and-flycheck ()
(interactive)
(tide-setup)
(flycheck-mode 1))
(add-hook 'typescript-mode-hook '+turn-on-tide-and-flycheck))
;; (use-package rust-mode
;; :ensure t
;; :config
;; (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode)))
(use-package zig-mode
:config
(add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode)))
(use-package yaml-mode
:config
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)))
(use-package typescript-mode
:config
(add-to-list 'auto-mode-alist '("\\.mts\\'" . typescript-mode)))
(use-package lua-mode
:config
(add-to-list 'auto-mode-alist '("\\.lua\\'" . lua-mode)))
(use-package dockerfile-mode
:config (add-to-list 'auto-mode-alist '("\\Dockerfile\\'" . dockerfile-mode)))
(use-package markdown-mode
:hook (markdown-mode-hook . visual-line-mode)
:config (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)))
(use-package haskell-mode
:config
(require 'haskell-mode-autoloads)
(add-to-list 'Info-default-directory-list "~/lib/emacs/haskell-mode/")
(add-to-list 'auto-mode-alist '("\\.hs\\'" . haskell-mode)))
(use-package kotlin-mode
:config
(add-to-list 'auto-mode-alist '("\\.kt\\'" . kotlin-mode)))
(use-package php-mode
:config
(add-to-list 'auto-mode-alist '("\\.php\\'" . php-mode)))
(use-package terraform-mode
:config
(add-to-list 'auto-mode-alist '("\\.\\(hcl\\|tf\\)\\'" . terraform-mode)))

163
emacs/rc.el Normal file
View File

@ -0,0 +1,163 @@
(tool-bar-mode 0)
(menu-bar-mode 0)
(scroll-bar-mode 0)
(column-number-mode 1)
(show-paren-mode 1)
(electric-pair-mode 1)
;; (add-hook 'dired-mode-hook 'dired-hide-details-mode)
(add-hook 'dired-mode-hook 'dired-omit-mode)
(setq dired-omit-extensions nil)
(setq dired-omit-files (rx (seq bol ".")))
(display-line-numbers-mode -1)
(setq-default display-line-numbers nil)
(dolist (hook '(prog-mode-hook
yaml-mode-hook
git-commit-setup-hook))
(add-hook hook (lambda () (setq-local display-line-numbers 'relative))))
(setq global-hl-line-mode -1)
(defun +magit-display-buffer (buffer)
(display-buffer
buffer (if (derived-mode-p 'magit-mode)
'(display-buffer-same-window)
'(nil (inhibit-same-window . t)))))
;; (defun +duplicate-line ()
;; "Duplicate current line"
;; (interactive)
;; (let ((column (- (point) (point-at-bol)))
;; (line (let ((s (thing-at-point 'line t)))
;; (if s (string-remove-suffix "\n" s) ""))))
;; (move-end-of-line 1)
;; (newline)
;; (insert line)
;; (move-beginning-of-line 1)
;; (forward-char column)))
(defun +enlarge-window-horizontally ()
(interactive)
(enlarge-window-horizontally 5))
(defun +enlarge-window ()
(interactive)
(enlarge-window 5))
(defun +shrink-window-horizontally ()
(interactive)
(shrink-window-horizontally 5))
(defun +shrink-window ()
(interactive)
(shrink-window 5))
(defun +delete-word (arg)
"Delete characters forward until encountering the end of a word.
With argument, do this that many times.
This command does not push text to `kill-ring'."
(interactive "p")
(delete-region
(point)
(progn
(forward-word arg)
(point))))
;; (add-hook 'emacs-startup-hook (lambda ()
;; (when (get-buffer "*scratch*")
;; (kill-buffer "*scratch*"))))
;;; Whitespace mode
(defun +set-up-whitespace-handling ()
(interactive)
(whitespace-mode 1)
(add-to-list 'write-file-functions 'delete-trailing-whitespace))
(dolist (hook '(prog-mode-hook
yaml-mode-hook
git-commit-setup-hook))
(add-hook hook #'+set-up-whitespace-handling))
(defun +backward-delete-word (arg)
"Delete characters backward until encountering the beginning of a word.
With argument, do this that many times.
This command does not push text to `kill-ring'."
(interactive "p")
(+delete-word (- arg)))
;; (dolist (hook '(dired-mode-hook
;; vterm-mode-hook
;; ibuffer-mode-hook
;; scratch-buffer-hook))
;; (add-hook hook (lambda () (solaire-mode -1))))
;; (eval-after-load "simple"
;; `(defun get-scratch-buffer-create ()
;; "Return the *scratch* buffer, creating a new one if needed."
;; (run-hooks 'scratch-buffer-hook)
;; (or (get-buffer "*scratch*")
;; (let ((scratch (get-buffer-create "*scratch*")))
;; ;; Don't touch the buffer contents or mode unless we know that
;; ;; we just created it.
;; (with-current-buffer scratch
;; (when initial-scratch-message
;; (insert (substitute-command-keys initial-scratch-message))
;; (set-buffer-modified-p nil))
;; (funcall initial-major-mode))
;; scratch))))
(global-set-key (kbd "C-j")
(defun +join-next-line ()
(interactive)
(join-line -1)))
(defun temp-buffer-p (window new-buffer bury-or-kill)
(when (string-match-p "^\*.+\*$" (buffer-name new-buffer))
return t))
(setq switch-to-prev-buffer-skip 'temp-buffer-p)
(defun toggle-window-split ()
(interactive)
(if (= (count-windows) 2)
(let* ((this-win-buffer (window-buffer))
(next-win-buffer (window-buffer (next-window)))
(this-win-edges (window-edges (selected-window)))
(next-win-edges (window-edges (next-window)))
(this-win-2nd (not (and (<= (car this-win-edges)
(car next-win-edges))
(<= (cadr this-win-edges)
(cadr next-win-edges)))))
(splitter
(if (= (car this-win-edges)
(car (window-edges (next-window))))
'split-window-horizontally
'split-window-vertically)))
(delete-other-windows)
(let ((first-win (selected-window)))
(funcall splitter)
(if this-win-2nd (other-window 1))
(set-window-buffer (selected-window) this-win-buffer)
(set-window-buffer (next-window) next-win-buffer)
(select-window first-win)
(if this-win-2nd (other-window 1))))))
(global-set-key (kbd "C-x C-\\") 'toggle-window-split)
(global-set-key (kbd "C-c f r") 'recentf-open)
(global-set-key (kbd "C-c f f") 'find-file)
(global-set-key (kbd "C-x C-b") 'ibuffer)
(global-set-key (kbd "C-x }") '+enlarge-window-horizontally)
(global-set-key (kbd "C-x {") '+shrink-window-horizontally)
(global-set-key (kbd "C-c ^") '+enlarge-window)
(global-set-key (kbd "C-c 0") 'balance-windows)
(global-set-key (kbd "M-n") 'next-buffer)
(global-set-key (kbd "M-p") 'previous-buffer)
(global-set-key (kbd "<C-backspace>") '+backward-delete-word)
(global-set-key (kbd "<C-delete>") '+delete-word)
(global-unset-key (kbd "C-x C-f"))
(global-unset-key (kbd "C-x C-b"))
(set-input-method 'russian-computer)
(deactivate-input-method)

74
init.el Normal file
View File

@ -0,0 +1,74 @@
(add-hook 'elpaca-after-init-hook
(lambda ()
(message "Emacs loaded in %s with %d garbage collections."
(format "%.2f seconds"
(float-time
(time-subtract (current-time) before-init-time)))
gcs-done)))
(defvar elpaca-installer-version 0.11)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
:ref nil :depth 1 :inherit ignore
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca--activate-package)))
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
(build (expand-file-name "elpaca/" elpaca-builds-directory))
(order (cdr elpaca-order))
(default-directory repo))
(add-to-list 'load-path (if (file-exists-p build) build repo))
(unless (file-exists-p repo)
(make-directory repo t)
(when (<= emacs-major-version 28) (require 'subr-x))
(condition-case-unless-debug err
(if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
((zerop (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let* ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(plist-get order :repo) ,repo))))
((zerop (call-process "git" nil buffer t "checkout"
(or (plist-get order :ref) "--"))))
(emacs (concat invocation-directory invocation-name))
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
((require 'elpaca))
((elpaca-generate-autoloads "elpaca" repo)))
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
(error "%s" (with-current-buffer buffer (buffer-string))))
((error) (warn "%s" err) (delete-directory repo 'recursive))))
(unless (require 'elpaca-autoloads nil t)
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
(let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
(defmacro use-feature (name &rest args)
"Like `use-package' but accounting for asynchronous installation.
NAME and ARGS are in `use-package'."
(declare (indent defun))
`(use-package ,name
:ensure nil
,@args))
(elpaca elpaca-use-package
(require 'elpaca-use-package)
(elpaca-use-package-mode)
(setq use-package-always-ensure t))
(if debug-on-error
(setq use-package-verbose t
use-package-expand-minimally nil
use-package-compute-statistics t)
(setq use-package-verbose nil
use-package-expand-minimally t))
(setq default-input-method nil)
(setq custom-file "~/.emacs.d/custom.el")
(load "~/.emacs.d/emacs/packages.el")
(load "~/.emacs.d/emacs/defaults.el")
(load "~/.emacs.d/emacs/org.el")
(load "~/.emacs.d/emacs/rc.el")
(load-file custom-file)