commit fed46fec0b7f4109f8d00afd4529657a91b18b2f Author: Little Fluffy Clouds Date: Wed Jul 9 19:38:16 2025 +0300 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e81780c --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +* + +!.gitignore +!init.el +!early-init.el +!custom.el +!snippets +!emacs/* + diff --git a/custom.el b/custom.el new file mode 100644 index 0000000..42f10cc --- /dev/null +++ b/custom.el @@ -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"))))) diff --git a/early-init.el b/early-init.el new file mode 100644 index 0000000..0cbaa31 --- /dev/null +++ b/early-init.el @@ -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) diff --git a/emacs/defaults.el b/emacs/defaults.el new file mode 100644 index 0000000..4f1b6ab --- /dev/null +++ b/emacs/defaults.el @@ -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))) diff --git a/emacs/org.el b/emacs/org.el new file mode 100644 index 0000000..f2d663f --- /dev/null +++ b/emacs/org.el @@ -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) diff --git a/emacs/packages.el b/emacs/packages.el new file mode 100644 index 0000000..7169058 --- /dev/null +++ b/emacs/packages.el @@ -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 + ("" . dired-subtree-toggle) + ("TAB" . dired-subtree-toggle) + ("" . 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))) diff --git a/emacs/rc.el b/emacs/rc.el new file mode 100644 index 0000000..7ed3abc --- /dev/null +++ b/emacs/rc.el @@ -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 "") '+backward-delete-word) +(global-set-key (kbd "") '+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) diff --git a/init.el b/init.el new file mode 100644 index 0000000..60d3c6a --- /dev/null +++ b/init.el @@ -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)