#+title: Emacs Config #+property: header-args:elisp :mkdirp yes :results silent :padline no #+property: header-args:elisp+ :tangle "~/.config/emacs/init.el" * General ** Settings Quality of life settings. #+begin_src elisp (setq-default help-window-select t delete-by-moving-to-trash t sentence-end-double-space nil confirm-kill-emacs 'yes-or-no-p scroll-conservatively 101 cursor-in-non-selected-windows nil) #+end_src ** Startup Screen Disable default startup screen. #+begin_src elisp (setq-default inhibit-startup-screen t) #+end_src ** GUI Bars Disable GUI bars. #+begin_src elisp (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1) #+end_src ** Minibuffer Enable vertical minibuffer. #+begin_src elisp (fido-vertical-mode) #+end_src ** Behaviour Automatically move cursor point on window split. #+begin_src elisp (advice-add 'split-window-below :after (lambda (&rest r) (other-window 1))) (advice-add 'split-window-right :after (lambda (&rest r) (other-window 1))) #+end_src Add advice to copy line at cursor point or region. #+begin_src elisp (defadvice kill-ring-save (before dwim-copy activate compile) "Copy the current line at cursor point or region." (interactive (if mark-active (list (region-beginning) (region-end)) (message "Line copied") (list (line-beginning-position) (line-beginning-position 2))))) #+end_src Add advice to cut line or region at cursor point. #+begin_src elisp (defadvice kill-region (before dwim-cut activate compile) "Cut the current line at point or region." (interactive (if mark-active (list (region-beginning) (region-end)) (list (line-beginning-position) (line-beginning-position 2))))) #+end_src Add advice to enable ~query-replace~ to search the whole buffer or region if selected, as the original default behaviour would only begin to replace from the cursor point position. #+begin_src elisp (defun +advice-goto-top-no-region (func &rest args) "Move point to top of buffer when no region applying ARGS to FUNC." (save-excursion (when (not (use-region-p)) (goto-char (point-min))) (apply func args))) (advice-add 'query-replace :around #'+advice-goto-top-no-region) (advice-add 'query-replace-regexp :around #'+advice-goto-top-no-region) #+end_src ** Editor Tab behaviour settings. #+begin_src elisp (setq-default tab-width 4 tab-always-indent 'complete backward-delete-char-untabify-method 'hungry indent-tabs-mode nil) #+end_src Replace selected region when yanking text. #+begin_src elisp (delete-selection-mode) #+end_src Auto update buffer on any file changes. #+begin_src elisp (global-auto-revert-mode) #+end_src Automatically remove trailing whitespace on file-save. #+begin_src elisp (add-hook 'before-save-hook #'whitespace-cleanup) #+end_src Increase default column width. #+begin_src elisp (setq-default fill-column 80) #+end_src Set whitespace column length and symbols. #+begin_src elisp (with-eval-after-load 'whitespace (setq-default whitespace-line-column fill-column whitespace-display-mappings '((space-mark ?\s [?·] [?.]) (newline-mark ?\n [?↴ ?\n]) (tab-mark ?\t [?➔ ?\t] [?\\ ?\t])))) #+end_src Enable pairing brackets. #+begin_src elisp (electric-pair-mode) #+end_src ** Theme Enable theme. #+begin_src elisp (load-theme 'modus-vivendi) #+end_src ** Modeline Enable column number in modeline. #+begin_src elisp (column-number-mode) #+end_src ** Completion Enable completions previews. #+begin_src elisp (add-hook 'prog-mode-hook #'completion-preview-mode) #+end_src Set completion keybindings. #+begin_src elisp (with-eval-after-load 'completion-preview (let ((map completion-preview-active-mode-map)) (keymap-set map "M-n" #'completion-preview-next-candidate) (keymap-set map "M-p" #'completion-preview-prev-candidate))) #+end_src ** Which-key Enable which-key that displays a pop-up window of posisble keybindings sequences. #+begin_src elisp (which-key-mode) #+end_src ** Winner-mode Enable winner-mode. #+begin_src elisp (winner-mode) #+end_src Set winner mode keybindings. #+begin_src elisp (with-eval-after-load 'winner (keymap-set winner-mode-map "C-<" #'winner-undo) (keymap-set winner-mode-map "C->" #'winner-redo)) #+end_src ** History *** Minibuffer History Enable saving minibuffer history. #+begin_src elisp :noweb yes (savehist-mode) (with-eval-after-load 'savehist <>) #+end_src Automatically save history on exit. #+begin_example elisp :tangle no :noweb-ref savehist-settings (add-hook 'kill-emacs-hook #'savehist-save) #+end_example Ensure savehist file is loaded. #+begin_src elisp :tangle no :noweb-ref savehist-settings (unless savehist-loaded (load-file savehist-file)) #+end_src Add addtional variable lists to save. #+begin_src elisp :tangle no :noweb-ref savehist-settings (dolist (var '(command-history register-alist mark-ring kill-ring search-ring regexp-search-ring)) (cl-pushnew var savehist-additional-variables)) #+end_src *** Recent Files Enable saving history of recent opened files. #+begin_src elisp :noweb yes (recentf-mode) (with-eval-after-load 'recentf <>) #+end_src Recentf settings. #+begin_src elisp :tangle no :noweb-ref recentf-settings (setq-default recentf-max-saved-items 50 recentf-auto-cleanup 'never) #+end_src Save recent files and cleanup file list on exit. #+begin_src elisp :tangle no :noweb-ref recentf-settings (add-hook 'kill-emacs-hook #'recentf-cleanup) (add-hook 'kill-emacs-hook #'recentf-save-list) #+end_src Disallow duplicates in history. #+begin_src elisp :tangle no :noweb-ref recentf-settings (setq-default history-delete-duplicates t) #+end_src *** Cursor Point Position Enable saving cursor point positions. #+begin_src elisp :noweb yes (save-place-mode) (with-eval-after-load 'saveplace <>) #+end_src Save place settings. #+begin_src elisp :tangle no :noweb-ref saveplace-settings (setq-default save-place-abbreviate-file-names t save-place-limit 800) #+end_src *** Bookmarks Don't display bookmark icon in fringe. #+begin_src elisp (with-eval-after-load 'bookmark (setq-default bookmark-fringe-mark nil)) #+end_src Disable auto-bookmarking org-mode files. #+begin_src elisp (with-eval-after-load 'org (setq-default org-bookmark-names-plist nil)) #+end_src ** Spell Checking Set dictionary. #+begin_src elisp (setq-default ispell-dictionary "british") #+end_src Enable spell checking. #+begin_src elisp (add-hook 'text-mode-hook #'flyspell-mode) (add-hook 'prog-mode-hook #'flyspell-prog-mode) #+end_src Add add word to dictionary function. #+begin_src elisp (defun +flyspell-add-word-to-dictionary () "Save word at point to personal dictionary." (interactive) (when-let ((loc (point)) (word (flyspell-get-word))) (when (yes-or-no-p (format "Add '%s' to dictionary?" (car word))) (flyspell-do-correct 'save nil (car word) loc (cadr word) (caddr word) loc) (save-buffer) (revert-buffer-quick) (message "Added '%s' to personal dictionary" (car word))))) #+end_src Set custom spell checking keybindings. #+begin_src elisp (setq-default flyspell-mode-map (make-sparse-keymap)) (with-eval-after-load 'flyspell (keymap-set flyspell-mode-map "C-x c c" #'flyspell-auto-correct-word) (keymap-set flyspell-mode-map "C-x c u" #'flyspell-auto-correct-previous-word) (keymap-set flyspell-mode-map "C-x c l" #'flyspell-check-previous-highlighted-word) (keymap-set flyspell-mode-map "C-x c n" #'flyspell-goto-next-error) (keymap-set flyspell-mode-map "C-x c b" #'flyspell-buffer) (keymap-set flyspell-mode-map "C-x c d" #'ispell-change-dictionary) (keymap-set flyspell-mode-map "C-x c i" #'+flyspell-add-word-to-dictionary)) #+end_src ** Dired #+begin_src elisp :noweb yes (with-eval-after-load 'dired <>) #+end_src Dired settings. #+begin_src elisp :tangle no :noweb-ref dired-settings (setq-default dired-guess-shell-alist-user '(("\\.pdf$" "zathura")) dired-listing-switched "-AFhlv --group-directories-first") #+end_src Auto enable omit mode on Dired startup. #+begin_src elisp :tangle no :noweb-ref dired-settings (add-hook 'dired-mode-hook (lambda () (dired-omit-mode) (toggle-truncate-lines 1))) #+end_src Add shred function. #+begin_src elisp :tangle no :noweb-ref dired-settings (if (executable-find "shred") (defun +dired-shred-file () "Shred marked files or a file at point in Dired." (interactive) (mapc (lambda (file) "Run the shred shell command on FILE." (if (file-regular-p file) (when (yes-or-no-p (format "Shred %s?" file)) (shell-command (format "shred -u \"%s\"" file))) (error "Aborting shred procedure; \"%s\" is not a file!" file))) (dired-get-marked-files))) (error "Shred command not found!")) #+end_src Add additional dired keybindings. #+begin_src elisp :tangle no :noweb-ref dired-settings (keymap-set dired-mode-map "b" #'dired-up-directory) (keymap-set dired-mode-map "z" #'+dired-shred-file) #+end_src Allow changing file permissions when in a writable dired buffer. #+begin_src elisp :tangle no :noweb-ref dired-settings (with-eval-after-load 'wdired (setq-default wdired-allow-to-change-permissions t)) #+end_src ** Search & Replace Case-sensitive search by default and show match count in minibuffer. #+begin_src elisp (with-eval-after-load 'isearch (setq-default case-fold-search nil isearch-lazy-count t)) #+end_src ** Org #+begin_src elisp :noweb yes (with-eval-after-load 'org <> <> <> <>) #+end_src #+begin_src elisp :noweb yes (with-eval-after-load 'org-keys <>) #+end_src #+begin_src elisp :noweb yes (with-eval-after-load 'org-agenda <>) #+end_src *** Org Settings :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-settings :END: Hide emphasis markers and set ellipse symbol. #+begin_src elisp (setq-default org-ellipsis "⤵" org-hide-emphasis-markers t) #+end_src Enable checkbox dependency checking. #+begin_src elisp (setq-default org-enforce-todo-dependencies t org-enforce-todo-checkbox-dependencies t org-checkbox-hierarchical-statistics nil) #+end_src Set org column format. #+begin_src elisp (setq-default org-columns-default-format "%70ITEM %TODO %10CLOCKSUM %16DEADLINE") #+end_src Enable notes for various actions. #+begin_src elisp (setq-default org-log-done 'time org-log-reschedule 'note org-log-redeadline 'note org-log-into-drawer t org-log-note-clock-out t) #+end_src Prioritise attribute tags for image width. #+begin_src elisp (setq-default org-image-actual-width nil) #+end_src Add advice to prompt for confirmation before commenting or cutting a subtree. #+begin_src elisp (advice-add 'org-cut-subtree :before-while (lambda (&rest _) "Prompts for confirmation before cutting subtree." (let ((heading (org-entry-get nil "ITEM"))) (y-or-n-p (format "Cut \"%s\" subtree?" heading))))) (advice-add 'org-toggle-comment :before-while (lambda (&rest _) "Prompt for confirmation before commenting a subtree." (let ((heading (org-entry-get nil "ITEM"))) (y-or-n-p (format "Toggle comment on \"%s\" subtree?" heading))))) #+end_src Use custom IDs for links. #+begin_src elisp (with-eval-after-load 'org-id (setq-default org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)) #+end_src *** Org To-dos & Tags :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-todo-tag-settings :END: Set to-do key words and selection type. #+begin_src elisp (setq-default org-use-fast-todo-selection 'expert org-todo-keywords '((sequence "IDLE(i)" "TODO(t)" "LIVE(l)" "WAIT(w@/!)" "|" "AXED(a@)" "DONE(d)"))) #+end_src Style keywords. #+begin_src elisp (set-face-attribute 'org-todo nil :weight 'bold :slant 'italic) (setq-default org-todo-keyword-faces '(("IDLE" . "grey") ("TODO" . "RoyalBlue1") ("LIVE" . "goldenrod2") ("WAIT" . "linen") ("DONE" . "SeaGreen3") ("AXED" . "OrangeRed2"))) #+end_src Add no-export tag. #+begin_src elisp (with-eval-after-load 'ox (cl-pushnew "NOEXPORT" org-export-exclude-tags)) #+end_src Set tag list. #+begin_src elisp (setq-default org-tag-alist '(;; Built-in Actions ("ARCHIVE") ("NOEXPORT") ("ignore") ;; General definitions ("blog") ("crypt") ("emacs") ("mail") ("note") ("web") ;; Code (:startgroup) ("code") (:grouptags) ("bash") ("c") ("cpp") ("css") ("elisp") ("html") (:endgroup) ;; Text (:startgroup) ("text") (:grouptags) ("article") ("book") ("man") ("pdf") ("txt") ("doc") (:endgroup) ;; Audio (:startgroup) ("audio") (:grouptags) ("audbook") ("music") ("podcast") (:endgroup) ;; Video (:startgroup) ("video") (:grouptags) ("movie") ("yt") (:endgroup))) #+end_src *** Org Speed Command Keys :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-speed-command-settings :END: Enable org speed commands. #+begin_src elisp (setq-default org-use-speed-commands t) #+end_src Alternative comment key =;= added to be consistent with ~org-toggle-comment~ (=C-c ;=). #+begin_src elisp (dolist (key '(("P" . org-set-property) ("$" . org-archive-subtree-default-with-confirmation) ("q" . org-set-tags-command) ("]" . org-shiftright) ("[" . org-shiftleft) (";" . org-toggle-comment) ("z" . org-add-note) ("y" . org-copy-subtree))) (cl-pushnew key org-speed-commands)) #+end_src Add ='= shortcut key to edit source blocks, which is consistent with ~org-edit-special~ (=C-c '=). #+begin_src elisp (cl-pushnew '("'" . org-edit-src-code) org-babel-key-bindings) #+end_src *** Org Babel :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-babel-settings :END: Add new structure template shortcuts when inserting a block. #+begin_src elisp (cl-pushnew '("se" . "src elisp") org-structure-template-alist) #+end_src Add advice to automatically open an edit buffer when inserting a structure template. #+begin_src elisp (defadvice org-insert-structure-template (after edit-src activate compile) "Auto enter an edit buffer when inserted an Org block." (call-interactively 'org-edit-special)) #+end_src Enable supported org babel languages. #+begin_src elisp (dolist (lang '(shell C latex plantuml)) (cl-pushnew `(,lang . t) org-babel-load-languages)) #+end_src Redisplay images when executing an org block. #+begin_src elisp (with-eval-after-load 'ob-core (add-hook 'org-babel-after-execute-hook (lambda () "Redisplay Org inline images." (when org-inline-image-overlays (org-redisplay-inline-images))))) #+end_src *** Org Export :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-export-settings :END: Use SVG LaTeX previews. #+begin_src elisp (setq-default org-preview-latex-default-process 'dvisvgm) (with-eval-after-load 'ox-html (setq-default org-html-with-latex 'dvisvgm)) #+end_src Set [[https://ctan.org/pkg/hyperref][hyperref]] LaTeX settings. #+begin_src elisp (with-eval-after-load 'ox-latex (setq-default org-latex-hyperref-template "\\hypersetup{ pdfauthor={%a}, pdftitle={%t}, pdfkeywords={%k}, pdfsubject={%d}, pdfcreator={%c}, pdflang={%L}, linktoc=all, colorlinks=true, urlcolor=blue, citecolor=blue, linkcolor=blue } ") ) #+end_src Add =doc= LaTeX class. #+begin_src elisp (with-eval-after-load 'ox-latex (cl-pushnew '("doc" " % Document Type \\documentclass[11pt]{article} % Geometry \\usepackage[a4paper,margin=1in]{geometry} % Paraskip \\usepackage{parskip} \\setlength{\\parindent}{0em} \\setlength{\\parskip}{1em} % Line height \\renewcommand{\\baselinestretch}{1.2} % Fancyhdr (header/footer) \\usepackage{fancyhdr} \\pagestyle{fancy} \\fancyhead[LH,LH]{\\scriptsize\\leftmark} \\fancyhead[RH,RH]{\\scriptsize\\rightmark} \\fancyfoot[CF]{\\thepage} \\fancyfootoffset{\\pagewidth} \\renewcommand{\\headrulewidth}{0.5pt} % top line thickness \\renewcommand{\\footrulewidth}{0.5pt} % bottom line thickness \\renewcommand{\\headruleskip}{10pt} % top line padding \\renewcommand{\\footruleskip}{10pt} % bottom line padding " ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}")) org-latex-classes) ) #+end_src *** Org Habit #+begin_src elisp (with-eval-after-load "org-habit" (setq-default org-habit-today-glyph ?T org-habit-completed-glyph ?+)) #+end_src *** Org Agenda :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-agenda-settings :END: Match encrypted org files for agenda. #+begin_src elisp (setq-default org-agenda-file-regexp "^[^.#].+\\.org\\(?:\\.gpg\\)?$") #+end_src Set agenda directory location and add files to agenda. #+begin_src elisp (let ((dir (expand-file-name "agenda/" org-directory))) (if (file-exists-p dir) (setq-default org-agenda-files (directory-files-recursively dir org-agenda-file-regexp)) (warn "Org-agenda directory '%s' not found" dir))) #+end_src Set agenda header formats. #+begin_src elisp (setq-default org-agenda-prefix-format '((agenda . "%?2i%-5c%?t%s\s") (todo . "%?2i%-5c") (tags . "⬜ %?2i%-5c") (search . "%?2i%-5c")) org-agenda-deadline-leaders '("!" "In %2d d.:" "[!%2dx]") org-agenda-scheduled-leaders '("+" "[+%2dx]") org-agenda-format-date "%F %A") #+end_src Set bulk actions and marker. #+begin_src elisp (setq-default org-agenda-bulk-custom-functions '((?k org-agenda-kill)) org-agenda-bulk-mark-char "☑️") #+end_src Set priority faces. #+begin_src elisp (setq-default org-priority-faces '((?A . (:foreground "red" :slant italic)) (?B . (:foreground "cadetblue" :slant italic)) (?C . (:foreground "goldenrod" :slant italic)))) #+end_src Set face for to-dos in agenda view. #+begin_src elisp (set-face-attribute 'org-agenda-dimmed-todo-face nil :weight 'bold :inherit nil :background 'unspecified) #+end_src Set sorting strategy. #+begin_src elisp (setq-default org-agenda-sorting-strategy '((agenda deadline-up time-up habit-down priority-up category-up) (todo todo-state-down deadline-up scheduled-up priority-down category-keep) (tags todo-state-down priority-down category-keep) (search category-keep))) #+end_src Set time grid. #+begin_src elisp (setq-default org-agenda-time-grid '((daily today require-timed) (0000 0100 0200 0300 0400 0500 0600 0700 0800 0900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000 2100 2200 2300) "⏰" "——————————————————————————————")) #+end_src **** Org Agenda Commands Command to view to personal planner. #+begin_src elisp (cl-pushnew '("=" "Day Planner: Personal" ((agenda "" ((org-agenda-overriding-header "PERSONAL AGENDA:") (org-agenda-span 'day) (org-agenda-include-deadlines nil) (org-agenda-show-all-dates nil))) (agenda "" ((org-agenda-overriding-header "\nPERSONAL DEADLINES:") (org-agenda-span 'day) (org-agenda-format-date "%F %A") (org-agenda-entry-types '(:deadline)) (org-agenda-skip-deadline-if-done t))) (tags-todo "-goal/TODO" ((org-agenda-overriding-header "\nPERSONAL TASKS:")))) ((org-habit-show-habits nil) (org-agenda-include-diary nil) (org-agenda-use-time-grid nil) (org-agenda-block-separator nil) (org-agenda-category-filter-preset '("-Work")))) org-agenda-custom-commands) #+end_src Command to view work planner. #+begin_src elisp (cl-pushnew '("-" "Day Planner: Work" ((agenda "" ((org-agenda-overriding-header "WORK AGENDA:") (org-agenda-start-day "monday") (org-agenda-span 5) (org-agenda-include-deadlines nil) (org-agenda-show-all-dates nil) (org-habit-show-habits nil))) (agenda "" ((org-agenda-overriding-header "\nWORK DEADLINES:") (org-agenda-span 'day) (org-agenda-time-grid nil) (org-agenda-format-date "%F %A") (org-agenda-entry-types '(:deadline)) (org-agenda-skip-deadline-if-done t))) (alltodo "" ((org-agenda-overriding-header "\nWORK TASKS:")))) ((org-agenda-block-separator nil) (org-agenda-category-filter-preset '("+Work")))) org-agenda-custom-commands) #+end_src Command to view all personal tasks. #+begin_src elisp (cl-pushnew '("l" "All Personal Tasks" tags-todo "-goal-milestone" ((org-agenda-overriding-header "PERSONAL TASKS:") (org-agenda-category-filter-preset '("-Work")))) org-agenda-custom-commands) #+end_src Command to view all work tasks. #+begin_src elisp (cl-pushnew '("k" "All Work Related Tasks" todo "" ((org-agenda-overriding-header "WORK TASKS:") (org-agenda-category-filter-preset '("+Work")))) org-agenda-custom-commands) #+end_src Command to organise idle tasks. #+begin_src elisp (cl-pushnew '("o" "Organise Tasks" todo "IDLE" ((org-agenda-overriding-header "TASKS TO ORGANISE:"))) org-agenda-custom-commands) #+end_src Command to view tasks that require archiving. #+begin_src elisp (cl-pushnew '("$" "Tasks to Archive" tags "CLOSED<=\"<-3m>\"+CATEGORY={Task}/DONE|AXED" ((org-agenda-show-inherited-tags nil) (org-agenda-todo-list-sublevels nil) (org-agenda-search-view-max-outline-level 1) (org-agenda-overriding-header "PERSONAL TASKS TO ARCHIVE"))) org-agenda-custom-commands) #+end_src Command to view habits. #+begin_src elisp (cl-pushnew '("h" "Habits" tags-todo "STYLE=\"habit\"" ((org-agenda-overriding-header "HABITS:"))) org-agenda-custom-commands) #+end_src Command to view projects. #+begin_src elisp (cl-pushnew '("p" "Projects" ((tags-todo "+proj|+goal|+milestone" ((org-agenda-overriding-header "PROJECTS:"))) (tags-todo "-proj-goal-milestone" ((org-agenda-overriding-header "\nPROJECT TASKS:")))) ((org-agenda-prefix-format "⬜ %?2i%-5c%?t%?s%(+org-agenda-breadcrumb)") (org-agenda-compact-blocks t) (org-agenda-category-filter-preset +project-categories) (org-agenda-sorting-strategy '(category-up deadline-up time-up priority-down effort-up)))) org-agenda-custom-commands) #+end_src Command to view clock report. #+begin_src elisp (cl-pushnew '("c" "Clock Review" agenda "" ((org-agenda-span 'day) (org-agenda-prefix-format " %-5c | %t | %s | ") (org-agenda-archives-mode t) (org-agenda-use-time-grid nil) (org-agenda-start-with-log-mode 'clockcheck) (org-agenda-start-with-clockreport-mode t) (org-agenda-clock-consistency-checks '(:min-duration 0 :max-gap 5 :inherit 'warning :default-face ((:background 'unspecified) (:family "monospace")))))) org-agenda-custom-commands) #+end_src Command to review the week. #+begin_src elisp (cl-pushnew '("r" "Review: Week" agenda "" ((org-agenda-overriding-header (format "WEEK %s REVIEW" (format-time-string "%U" (current-time)))) (org-habit-show-habits nil) (org-agenda-span 'week) (org-agenda-include-diary nil) (org-agenda-show-all-dates t) (org-agenda-clockreport-mode t))) org-agenda-custom-commands) #+end_src Command to review the month. #+begin_src elisp (cl-pushnew '("R" "Review: Month" agenda "" ((org-agenda-overriding-header (format "%s REVIEW" (upcase (format-time-string "%B" (current-time))))) (org-habit-show-habits nil) (org-agenda-span 'month) (org-agenda-include-diary nil) (org-agenda-show-all-dates t) (org-agenda-start-with-clockreport-mode t))) org-agenda-custom-commands) #+end_src Command to review the weekend. #+begin_src elisp (cl-pushnew '("w" "Review: Weekend" agenda "" ((org-agenda-overriding-header "WEEKEND REVIEW") (org-agenda-span 2) (org-agenda-start-day "saturday"))) org-agenda-custom-commands) #+end_src *** Org Clock-table Define a custom clocktable formatter function for ~+org-clocktable-format~. #+begin_src elisp (with-eval-after-load 'org-clock (defun +org-clocktable-format (&rest args) "A cleaner Org clocktable format." (apply #'org-clocktable-write-default args) (save-excursion ;; Rename headline (search-forward "Headline") (backward-kill-sexp) (insert "Tasks") (org-table-align) ;; Capitalise row (beginning-of-line) (setq this-command-keys-shift-translated t) (call-interactively 'end-of-line) (call-interactively 'capitalize-dwim) (deactivate-mark) ;; Remove cookies (org-mark-element) (while (re-search-forward "\\[[0-9]+\\(?:/[0-9]\\|%\\)\\] " nil t) (replace-match "")) (org-table-align) (exchange-point-and-mark t) ;; Move total time row to the end of the table (kill-whole-line) (condition-case nil (while t (org-table-move-row-down)) (error nil)) (org-table-insert-hline t)))) #+end_src Set default clocktable parameters. #+begin_src elisp :tangle no :noweb-ref org-agenda-settings (setq-default org-agenda-clockreport-parameter-plist '(:link t :fileskip0 t :hidefiles t :formatter +org-clocktable-format)) #+end_src *** Org Capture #+begin_src elisp :noweb yes (with-eval-after-load 'org-capture <> <>) #+end_src **** Capture Templates Task template. #+begin_src elisp :tangle no :noweb-ref capture-task-template "* IDLE %^{Task} %^G :PROPERTIES: :CAPTURED: %U :END:" #+end_src Event template. #+begin_src elisp :tangle no :noweb-ref capture-event-template "* %^{Event} SCHEDULED: %^T :PROPERTIES: :CAPTURED: %U :END:" #+end_src Note template. #+begin_src elisp :tangle no :noweb-ref capture-note-template "* %^{Note} %^G :PROPERTIES: :CAPTURED: %U :END:" #+end_src Meeting template. #+begin_src elisp :tangle no :noweb-ref capture-meeting-template "* TODO Meeting with: *%\\1* at *%\\2* :meeting: SCHEDULED: %^T :PROPERTIES: :CAPTURED: %U :NAME: %^{Name} :LOCATION: %^{Location} :END:" #+end_src Goal setting template. #+begin_src elisp :tangle no :noweb-ref capture-goal-template "* [/] %^{Goal Title} :goal: DEADLINE: %^{When do you expect this goal to be completed?}t :PROPERTIES: :CAPTURED: %U :END: :SMART: :SPECIFIC: %^{What SPECIFICALLY is the goal?} :MEASURABLE: %^{What RESULTS will determine the completion of the goal?} :ACTIONABLE: %^{What ACTIONS will you take to accomplish this goal?} :RELEVANT: %^{Why is it IMPORTANT to accomplish this goal?} :TIMELY: Due by =DEADLINE= :END:" #+end_src Daily review template. #+begin_src elisp :tangle no :noweb-ref capture-weekly-review-template ":PROPERTIES: :CAPTURED: %U :END: %? ,,#+BEGIN: clocktable :scope agenda-with-archives :block %t ,,#+END:" #+end_src Weekly review template. #+begin_src elisp :tangle no :noweb-ref capture-weekly-review-template ":PROPERTIES: :CAPTURED: %U :END: %? ,,#+BEGIN: clocktable :scope agenda-with-archives :block %<%Y>-W%<%V> ,,#+END:" #+end_src Monthly review template. #+begin_src elisp :tangle no :noweb-ref capture-monthly-review-template ":PROPERTIES: :CAPTURED: %U :END: %? ,,#+BEGIN: clocktable :scope agenda-with-archives :block %<%Y-%m> ,,#+END:" #+end_src **** Capture Template Quick Keys :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-capture-quick-keys :noweb yes :noweb-prefix no :END: Capture a quick task. #+begin_src elisp :noweb yes (cl-pushnew '("c" "Quick Task (personal)" entry (file "agenda/tasks.org") <> :prepend t :empty-lines-after 1 :immediate-finish t) org-capture-templates) #+end_src Capture event. #+begin_src elisp (cl-pushnew '("v" "Event" entry (file "agenda/events.org") <> :prepend t :empty-lines-after 1 :immediate-finish t) org-capture-templates) #+end_src Captured to last clocked file. #+begin_src elisp (cl-pushnew '("l" "Clocked File" item (clock) nil) org-capture-templates) #+end_src **** Capture Template Personal Keys :PROPERTIES: :header-args:elisp: :tangle no :noweb-ref org-capture-personal-keys :noweb yes :noweb-prefix no :END: Personal capture templates. #+begin_src elisp (cl-pushnew '("p" "personal...") org-capture-templates) (cl-pushnew '("pt" "Task" entry (file "agenda/tasks.org") <> :prepend t :empty-lines-after 1 :immediate-finish t) org-capture-templates) (cl-pushnew '("pT" "Detailed Task" entry (file "agenda/tasks.org") <> :prepend t :empty-lines-after 1) org-capture-templates) (cl-pushnew '("pp" "Plan Today" checkitem (file+olp+datetree "agenda/planner.org") nil :empty-lines-after 1 :jump-to-captured t) org-capture-templates) (cl-pushnew '("pn" "Note" entry (file "notes/notes.org") <> :empty-lines-after 1) org-capture-templates) (cl-pushnew '("pe" "Meeting" entry (file "agenda/tasks.org") <> :prepend t :empty-lines-after 1) org-capture-templates) #+end_src Review captures. #+begin_src elisp (cl-pushnew '("pr" "Review") org-capture-templates) (cl-pushnew '("prd" "Daily Review" plain (file+olp+datetree "agenda/planner.org" "Reviews" "Daily") <> :time-prompt t :empty-lines-after 1) org-capture-templates) (cl-pushnew '("prw" "Weekly Review" plain (file+olp+datetree "agenda/planner.org" "Reviews" "Weekly") <> :time-prompt t :tree-type week :jump-to-captured t :empty-lines-after 1) org-capture-templates) (cl-pushnew '("prm" "Monthly Review" plain (file+olp+datetree "agenda/planner.org" "Reviews" "Monthly") <> :time-prompt t :tree-type month :jump-to-captured t :empty-lines-after 1) org-capture-templates) #+end_src ** Error Checking Enable flymake for programming modes. #+begin_src elisp (add-hook 'prog-mode-hook #'flymake-mode) #+end_src Set flymake keybindings. #+begin_src elisp (with-eval-after-load 'flymake (keymap-set flymake-mode-map "M-# #" #'flymake-show-buffer-diagnostics) (keymap-set flymake-mode-map "M-# M-#" #'flymake-show-project-diagnostics) (keymap-set flymake-mode-map "M-# M-]" #'flymake-goto-next-error) (keymap-set flymake-mode-map "M-# M-[" #'flymake-goto-prev-error)) #+end_src * Keybindings Unlock previously unusable keybinding. #+begin_src elisp (define-key input-decode-map [?\C-\[] (kbd "")) #+end_src ** Global Keybindings To prevent other packages overriding any custom global keybinding, all custom global keybinding are stored in a global minor mode. #+begin_src elisp (define-minor-mode +global-keys "Minor to store my custom global keybindings." :global t :lighter " +GKEYS" :keymap (make-sparse-keymap)) (+global-keys) #+end_src File actions. #+begin_src elisp (keymap-set +global-keys-map "C-x x R" #'rename-visited-file) (keymap-set +global-keys-map "C-x x D" #'delete-file) #+end_src Window actions. #+begin_src elisp (keymap-set +global-keys-map "M-o" #'other-window) (keymap-set +global-keys-map "M-O" #'window-swap-states) (keymap-set +global-keys-map "M-V" #'scroll-other-window-down) (keymap-set +global-keys-map "C-S-V" #'scroll-other-window) (keymap-set +global-keys-map "C-M-<" #'beginning-of-buffer-other-window) (keymap-set +global-keys-map "C-M->" #'end-of-buffer-other-window) (keymap-set +global-keys-map "C-M-]" #'next-buffer) (keymap-set +global-keys-map "M-ESC" #'previous-buffer) ; C-M-[ translates to M-ESC #+end_src Set meta-key quick actions to mirror =C-x DIGIT= bindings, therefore reducing the need for additional keypresses. These bindings override their corresponding numerical argument, however these can be can be alternatively called with =C-u DIGIT= or =C-DIGIT=. #+begin_src elisp (keymap-set +global-keys-map "C-M-0" #'kill-buffer-and-window) (keymap-set +global-keys-map "C-M--" #'kill-this-buffer) (keymap-set +global-keys-map "M-0" #'delete-window) (keymap-set +global-keys-map "M-1" #'delete-other-windows) (keymap-set +global-keys-map "M-2" #'split-window-below) (keymap-set +global-keys-map "M-3" #'split-window-right) (keymap-set +global-keys-map "M-4" #'ctl-x-4-prefix) (keymap-set +global-keys-map "M-5" #'ctl-x-5-prefix) (keymap-set +global-keys-map "M-6" (keymap-global-lookup "C-x 6")) (keymap-set +global-keys-map "M-7" (keymap-global-lookup "C-x 7")) (keymap-set +global-keys-map "M-8" (keymap-global-lookup "C-x 8")) (keymap-set +global-keys-map "M-9" (keymap-global-lookup "C-x 9")) #+end_src Tab actions. #+begin_src elisp (keymap-set +global-keys-map "C-x C-" #'tab-new) (keymap-set +global-keys-map "C-x C-" #'tab-close) (keymap-set +global-keys-map "C-x t l" #'tab-list) (keymap-set +global-keys-map "C-x t " #'toggle-frame-tab-bar) #+end_src Improve region text manipulation. #+begin_src elisp (keymap-set +global-keys-map "M-c" #'capitalize-dwim) (keymap-set +global-keys-map "M-l" #'downcase-dwim) (keymap-set +global-keys-map "M-u" #'upcase-dwim) (keymap-set +global-keys-map "M-U" #'upcase-char) #+end_src Help actions. #+begin_src elisp (keymap-set +global-keys-map "C-h M" #'describe-keymap) (keymap-set +global-keys-map "C-h j" #'describe-char) #+end_src Display modes. #+begin_src elisp (keymap-set +global-keys-map "C-x x c" #'display-fill-column-indicator-mode) (keymap-set +global-keys-map "C-x x l" #'display-line-numbers-mode) (keymap-set +global-keys-map "C-x x h" #'hl-line-mode) (keymap-set +global-keys-map "C-x x o" #'overwrite-mode) (keymap-set +global-keys-map "C-x x s" #'prettify-symbols-mode) (keymap-set +global-keys-map "C-x x w" #'visual-line-mode) (keymap-set +global-keys-map "C-x x SPC" #'whitespace-mode) #+end_src Org functions. #+begin_src elisp (keymap-set +global-keys-map "C-c a" #'org-agenda) #+end_src ** Diff-mode Rebind diff-mode's ~diff-goto-source~ keybinding (due to conflict with =M-o=). Add version control next action shortcut in diff-mode buffer. #+begin_src elisp (with-eval-after-load 'diff-mode (keymap-set diff-mode-map "M-j" #'diff-goto-source) (keymap-set diff-mode-map "v" #'vc-next-action)) #+end_src