diff --git a/init.el b/init.el index 1cdde5f..552638a 100644 --- a/init.el +++ b/init.el @@ -91,6 +91,6 @@ making an abbreviation to a function." ;; (require 'unravel-search) ;; (require 'unravel-dired) ;; (require 'unravel-window) -;; (require 'unravel-git) -;; (require 'unravel-org) +(require 'unravel-git) +(require 'unravel-org) (require 'unravel-langs) diff --git a/unravel-emacs.org b/unravel-emacs.org index 56a8ee7..a1a4317 100644 --- a/unravel-emacs.org +++ b/unravel-emacs.org @@ -62,7 +62,7 @@ Here is what the generated directory structure should look like: To make a change to this Emacs configuration, edit this file and then type =C-c C-v C-t= (=M-x org-babel-tangle=) to republish all the relevant files. -* The ~early-init.el~ file +* The =early-init.el= file #+begin_quote This is the first file that Emacs reads when starting up. It should @@ -139,7 +139,7 @@ Naming frames allows you to select them using completion (=M-x select-frame-by-n (add-hook 'after-init-hook (lambda () (set-frame-name "unravel"))) #+end_src -* The ~init.el~ file +* The =init.el= file :PROPERTIES: :CUSTOM_ID: h:dae63bd9-93a8-41c4-af1b-d0f39ba50974 :END: @@ -366,8 +366,8 @@ Now we are ready to load our per-module configuration files: ;; (require 'unravel-search) ;; (require 'unravel-dired) ;; (require 'unravel-window) - ;; (require 'unravel-git) - ;; (require 'unravel-org) + (require 'unravel-git) + (require 'unravel-org) (require 'unravel-langs) #+end_src @@ -854,7 +854,7 @@ in the function ~prot/enable-variable-pitch~. (provide 'unravel-theme) #+end_src -* The ~unravel-essentials.el~ module +* The =unravel-essentials.el= module :PROPERTIES: :CUSTOM_ID: h:0ef52ed9-7b86-4329-ae4e-eff9ab8d07f2 :END: @@ -1109,7 +1109,7 @@ The package offers the ~expreg-expand~ and ~expreg-contract~ commands. (provide 'unravel-essentials) #+end_src -* The ~unravel-completion.el~ module +* The =unravel-completion.el= module :PROPERTIES: :CUSTOM_ID: h:15edf2c3-4419-4101-928a-6e224958a741 :END: @@ -1826,7 +1826,7 @@ handle even massive completion tables gracefully. #+begin_src emacs-lisp :tangle "unravel-modules/unravel-completion.el" (provide 'unravel-completion) #+end_src -* The ~unravel-langs.el~ module +* The =unravel-langs.el= module :PROPERTIES: :CUSTOM_ID: h:f44afb76-a1d7-4591-934d-b698cc79a792 :END: @@ -2440,3 +2440,1246 @@ Prot is the developer of this package. (provide 'prot-embark) ;;; prot-embark.el ends here #+end_src + +** The =unravel-git.el= module +:PROPERTIES: +:CUSTOM_ID: h:65e3eff5-0bff-4e1f-b6c5-0d3aa1a0d232 +:END: + +[ Watch Prot's talk: [[https://protesilaos.com/codelog/2023-08-03-contribute-core-emacs/][Contribute to GNU Emacs core]] (2023-08-03). ] + +#+begin_quote +This section covers my settings for version control per se, but more +widely for tools related to checking different versions of files and +working with so-called "projects". +#+end_quote + +*** The =unravel-git.el= section about ediff +:PROPERTIES: +:CUSTOM_ID: h:89edea05-4d94-4ea1-b2a8-5ad01422618c +:END: + +[ Watch Prot's talk: [[https://protesilaos.com/codelog/2023-11-17-emacs-ediff-basics/][Emacs: ediff basics]] (2023-12-30) ] + +#+begin_quote +The built-in ~ediff~ feature provides several commands that let us +compare files or buffers side-by-side. The defaults of ~ediff~ are bad, +in my opinion: it puts buffers one on top of the other and places the +"control panel" in a separate Emacs frame. The first time I tried to +use it, I thought I broke my setup because it is unlike anything we +normally interact with. As such, the settings I have for +~ediff-split-window-function~ and ~ediff-window-setup-function~ are +what I would expect Emacs maintainers to adopt as the new default. I +strongly encourage everyone to start with them. + +In my workflow, the points of entry to the ~ediff~ feature are the +commands ~ediff-files~, ~ediff-buffers~. Sometimes I use the 3-way +variants with ~ediff-files3~ and ~ediff-buffers3~, though this is rare. +Do watch the video I link to in the beginning of this section, as it +covers the main functionality of this neat tool. I also show how it +integrates with ~magit~ ([[#h:b08af527-9ebf-4425-ac3a-24b4f371a4fd][The =unravel-git.el= section about ~magit~ (great Git client)]]). +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-git.el" :mkdirp yes +;;;; `ediff' +(use-package ediff + :ensure nil + :commands (ediff-buffers ediff-files ediff-buffers3 ediff-files3) + :init + (setq ediff-split-window-function 'split-window-horizontally) + (setq ediff-window-setup-function 'ediff-setup-windows-plain) + :config + (setq ediff-keep-variants nil) + (setq ediff-make-buffers-readonly-at-startup nil) + (setq ediff-merge-revisions-with-ancestor t) + (setq ediff-show-clashes-only t)) +#+end_src + +*** The =unravel-git.el= section about =project.el= +:PROPERTIES: +:CUSTOM_ID: h:7dcbcadf-8af6-487d-b864-e4ce56d69530 +:END: + +#+begin_quote +In Emacs parlance, a "project" is a collection of files and/or +directories that share the same root. The root of a project is +identified by a special file or directory, with =.git/= being one of +the defaults as it is a version control system supported by the +built-in =vc.el= ([[#h:50add1d8-f0f4-49be-9e57-ab280a4aa300][The =unravel-git.el= section about =vc.el= and related]]). + +We can specify more project roots as a list of strings in the user +option ~project-vc-extra-root-markers~. I work exclusively with Git +repositories, so I just add there a =.project= file in case I ever +need to register a project without it being controlled by ~git~. In +that case, the =.project= file is just an empty file in a directory +that I want to treat as the root of this project. + +The common way to switch to a project is to type =C-x p p=, which +calls the command ~project-switch-project~. It lists all registered +projects and also includes a =... (choose a dir)= option. By choosing +a new directory, we register it in our project list if it has a +recognisable root. Once we select a project, we are presented with a +list of common actions to start working on the project. These are +defined in the user option ~project-switch-commands~ and are activated +by the final key that accesses them from the =C-x p= prefix. As such, +do =M-x describe-keymap= and check the ~project-prefix-map~. For +example, I bind ~project-dired~ to =C-x p RET=, so =RET= accesses this +command after =C-x p p= as well. + +If any of the =project.el= commands is called from outside a project, +it first prompts for a project and then carries out its action. For +example, ~project-find-file~ will ask for a project to use, then +switch to it, and then prompt for a file inside of the specified +project. + +While inside a project, we have many commands that operate on the +project level. For example, =C-x p f= (~project-find-file~) searches +for a file across the project, while =C-x p b= (~project-switch-to-buffer~) +switches to a buffer that is specific to the project. Again, check the +~project-prefix-map~ for available commands. + +If not inside a project, the project-related commands will first +prompt to select a project (same as typing =C-x p p=) and then carry +out their action. + +I combine projects with my ~beframe~ package, so that when I switch to +a project I get a new frame that limits the buffers I visit there +limited to that frame ([[#h:77e4f174-0c86-460d-8a54-47545f922ae9][The =unravel-window.el= section about ~beframe~]]). +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-git.el" + ;;;; `project' + (use-package project + :ensure nil + :bind + (("C-x p ." . project-dired) + ("C-x p C-g" . keyboard-quit) + ("C-x p <return>" . project-dired) + ("C-x p <delete>" . project-forget-project)) + :config + (setopt project-switch-commands + '((project-find-file "Find file") + (project-find-regexp "Find regexp") + (project-find-dir "Find directory") + (project-dired "Root dired") + (project-vc-dir "VC-Dir") + (project-shell "Shell") + (keyboard-quit "Quit"))) + (setq project-vc-extra-root-markers '(".project")) ; Emacs 29 + (setq project-key-prompt-style t) ; Emacs 30 + + (advice-add #'project-switch-project :after #'prot-common-clear-minibuffer-message)) +#+end_src + +*** The =unravel-git.el= section about ~diff-mode~ +:PROPERTIES: +:CUSTOM_ID: h:8b426a69-e3cd-42ac-8788-f41f6629f879 +:END: + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-git.el" +;;;; `diff-mode' +(use-package diff-mode + :ensure nil + :defer t + :config + (setq diff-default-read-only t) + (setq diff-advance-after-apply-hunk t) + (setq diff-update-on-the-fly t) + ;; The following are from Emacs 27.1 + (setq diff-refine nil) ; I do it on demand, with my `agitate' package (more below) + (setq diff-font-lock-prettify t) ; I think nil is better for patches, but let me try this for a while + (setq diff-font-lock-syntax 'hunk-also)) +#+end_src + +*** The =unravel-git.el= section about ~magit~ (great Git client) +:PROPERTIES: +:CUSTOM_ID: h:b08af527-9ebf-4425-ac3a-24b4f371a4fd +:END: + +#+begin_quote +The ~magit~ package, maintained by Jonas Bernoulli, is the best +front-end to ~git~ I have ever used. Not only is it excellent at +getting the job done, it also helps you learn more about what ~git~ +has to offer. + +At the core of its interface is ~transient~. This is a library that +was originally developed as Magit-specific code that was then +abstracted away and ultimately incorporated into Emacs version 29. +With ~transient~, we get a window pop up with keys and commands +corresponding to them. The window is interactive, as the user can set +a value or toggle an option and have it take effect when the relevant +command is eventually invoked. For ~git~, in particular, this +interface is a genious way to surface the plethora of options. + +To start, call the command ~magit-status~. It brings up a buffer that +shows information about the state of the repository. Sections include +an overview of the current =HEAD=, untracked files, unstaged changes, +staged changes, and recent commits. Each section's visibility state +can be cycled by pressing =TAB= (variations of this are available---remember +to do =C-h m= (~describe-mode~) in an unfamiliar major mode to get +information about its key bindings). + +From the status buffer, we can perform all the usual version control +operations. By typing =?= (~magit-dispatch~), we bring up the main +~transient~ menu, with keys that then bring up their own submenus, +such as for viewing commit logs, setting the remotes, switching +branches, etc. +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-git.el" + ;;; Interactive and powerful git front-end (Magit) + (use-package transient + :defer t + :config + (setq transient-show-popup 0.5)) + + (use-package magit + :ensure t + :bind ("C-c g" . magit-status) + :init + (setq magit-define-global-key-bindings nil) + ;; (setq magit-section-visibility-indicator '("⮧")) + :config + (setq git-commit-summary-max-length 50) + ;; NOTE 2023-01-24: I used to also include `overlong-summary-line' + ;; in this list, but I realised I do not need it. My summaries are + ;; always in check. When I exceed the limit, it is for a good + ;; reason. + ;; (setq git-commit-style-convention-checks '(non-empty-second-line)) + + (setq magit-diff-refine-hunk t)) + + (use-package magit-repos + :ensure nil ; part of `magit' + :commands (magit-list-repositories) + :init + (setq magit-repository-directories + '(("~/src/prototypes" . 1)))) +#+end_src + +*** The =unravel-git.el= call to ~provide~ +:PROPERTIES: +:CUSTOM_ID: h:4e7035c5-9350-4c51-be85-85f2539ed295 +:END: + +Finally, we ~provide~ the module. + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-git.el" +(provide 'unravel-git) +#+end_src + +** The =unravel-org.el= module +:PROPERTIES: +:CUSTOM_ID: h:d799c3c0-bd6a-40bb-bd1a-ba4ea5367840 +:END: + +Watch these talks by Prot: + +- [[https://protesilaos.com/codelog/2023-12-18-emacs-org-advanced-literate-conf/][Advanced literate configuration with Org]] (2023-12-18) +- [[https://protesilaos.com/codelog/2023-05-23-emacs-org-basics/][Basics of Org mode]] (2023-05-23) +- [[https://protesilaos.com/codelog/2021-12-09-emacs-org-block-agenda/][Demo of my custom Org block agenda]] (2021-12-09) +- [[https://protesilaos.com/codelog/2020-02-04-emacs-org-capture-intro/][Primer on "org-capture"]] (2020-02-04) + +#+begin_quote +At its core, Org is a plain text markup language. By "markup +language", we refer to the use of common characters to apply styling, +such as how a word wrapped in asterisks acquires strong emphasis. +Check the video I link to above on the basics of Org mode. + +Though what makes Org powerful is not the markup per se, but the fact +that it has a rich corpus of Emacs Lisp code that does a lot with this +otherwise plain text notation. Some of the headline features: + +- Cycle the visibility of any heading and its subheadings. This lets + you quickly fold a section you do not need to see (or reveal the one + you care about). +- Mix prose with code in a single document to either make the whole + thing an actual program or to evaluate/demonstrate some snippets. +- Convert ("export") an Org file to a variety of formats, including + HTML and PDF. +- Use LaTeX inside of Org files to produce a scientific paper without + all the markup of LaTeX. +- Manage TODO lists and implement a concomitant methodology of + labelling task states. +- Quickly shift a "thing" (heading, list item, paragraph, ...) further + up or down in the file. +- Use tables with formulas as a lightweight alternative to spreadsheet + software. +- Capture data or fleeting thoughts efficiently using templates. +- Maintain an agenda for all your date-bound activities. +- Clock in and out of tasks, to eventually track how you are spending + your time. +- Link to files regardless of file type. This includes special links + such as to an Info manual or an email, if you also have that running + locally and integrated with Emacs ([[#h:755e195b-9471-48c7-963b-33055969b4e2][The =unravel-email.el= module]]). + +In other words, Org is highly capable and widely considered one of the +killer apps of Emacs. + +This section covers the relevant configurations. You will notice that +it is not limited to Org, as some other built-in features are also +relevant here. +#+end_quote + +*** The =unravel-org.el= section on the ~calendar~ +:PROPERTIES: +:CUSTOM_ID: h:94d48381-1711-4d6b-8449-918bc1e3836c +:END: + +#+begin_quote +The ~calendar~ is technically independent of Org, though it tightly +integrates with it. We witness this when we are setting timestamps, +such as while setting a =SCHEDULED= or =DEADLINE= entry for a given +heading. All I do here is set some stylistic preferences. + +Note that Emacs also has a ~diary~ command. I used it for a while, but +Org is far more capable, so I switched to it completely. +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" :mkdirp yes +;;; Calendar +(use-package calendar + :ensure nil + :commands (calendar) + :config + (setq calendar-mark-diary-entries-flag nil) + (setq calendar-mark-holidays-flag t) + (setq calendar-mode-line-format nil) + (setq calendar-time-display-form + '( 24-hours ":" minutes + (when time-zone (format "(%s)" time-zone)))) + (setq calendar-week-start-day 1) ; Monday + (setq calendar-date-style 'iso) + (setq calendar-time-zone-style 'numeric) ; Emacs 28.1 + + (require 'solar) + (setq calendar-latitude 35.17 ; Not my actual coordinates + calendar-longitude 33.36) + + (require 'cal-dst) + (setq calendar-standard-time-zone-name "+0200") + (setq calendar-daylight-time-zone-name "+0300")) +#+end_src + +*** The =unravel-org.el= section about appointment reminders (=appt.el=) +:PROPERTIES: +:CUSTOM_ID: h:bd4b0dcb-a925-4bd7-90db-6379a7ca6f5e +:END: + +#+begin_quote +The built in =appt.el= defines functionality for handling +notifications about appointments. It is originally designed to work +with the generic diary feature (the =M-x diary= one, I mean), which I +do not use anymore, but also integrates nicely with the Org agenda +([[#h:7fe87b83-2815-4617-a5f9-d3417dd9d248][The =unravel-org.el= Org agenda settings]]). I deepen this +integration further, such that after adding a task or changing its +state, the appointments mechanism re-reads my data to register new +notifications. This is done via a series of hooks and with the use of +the advice feature of Emacs Lisp. + +Here I am setting some simple settings to keep appointment notifations +minimal. I do not need them to inform me about the contents of my next +entry on the agenda: just show text on the mode line telling me how +many minutes are left until the event. + +In Org files, every heading can have an =APPT_WARNTIME= property: it takes +a numeric value representing minutes for a forewarning from =appt.el=. +I use this in tandem with ~org-capture~ for tasks that need to be +done at a specific time, such as coaching sessions ([[#h:f8f06938-0dfe-45c3-b4cf-996d36cba82d][The =unravel-org.el= Org capture templates (~org-capture~)]]). +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;; Appt (appointment reminders which also integrate with Org agenda) +(use-package appt + :ensure nil + :commands (appt-activate) + :config + (setq appt-display-diary nil + appt-display-format nil + appt-display-mode-line t + appt-display-interval 3 + appt-audible nil ; TODO 2023-01-25: t does nothing because I disable `ring-bell-function'? + appt-warning-time-regexp "appt \\([0-9]+\\)" ; This is for the diary + appt-message-warning-time 6) + + (with-eval-after-load 'org-agenda + (appt-activate 1) + + ;; NOTE 2021-12-07: In my `prot-org.el' (see further below), I add + ;; `org-agenda-to-appt' to various relevant hooks. + ;; + ;; Create reminders for tasks with a due date when this file is read. + (org-agenda-to-appt))) +#+end_src + +*** The =unravel-org.el= section with basic Org settings +:PROPERTIES: +:CUSTOM_ID: h:e03df1e0-b43e-49b5-978e-6a511165617c +:END: + +#+begin_quote +Org, also known as "Org mode", is one of the potentially most useful +feature sets available to every Emacs user. At its core, Org is a +lightweight markup language: you can have headings and paragraphs, +mark a portion of text with emphasis, produce bullet lists, include +code blocks, and the like. Though what really sets Org apart from +other markup languages is the rich corpus of Emacs Lisp written around +it to do all sorts of tasks with this otherwise plain text format. + +With Org you can write technical documents (e.g. the manuals of all my +Emacs packages), maintain a simple or highly sophisticated system for +task management, organise your life using the agenda, write tables +that can evaluate formulas to have spreadsheet functionality, have +embedded LaTeX, evaluate code blocks in a wide range of programming +languages and reuse their results for literate programming, include +the contents of other files into a singular file, use one file to +generate other files/directories with all their contents, and export +the Org document to a variety of formats like =.pdf= and =.odt=. +Furthermore, Org can be used as a lightweight, plain text database, as +each heading can have its own metadata. This has practical +applications in most of the aforementioned. + +In short, if something can be done with plain text, Org probably does +it already or has all the elements for piecing it together. This +document, among many of my published works, is testament to Org's +sheer power, which I explained at greater length in a video +demonstration: [[https://protesilaos.com/codelog/2023-12-18-emacs-org-advanced-literate-conf/][Advanced literate configuration with Org]] (2023-12-18). + +This being Emacs, everything is customisable and Org is a good example +of this. There are a lot of user options for us to tweak things to our +liking. I do as much, though know that Org is perfectly usable without +any configuration. The following sections contain further commentary +on how I use Org. +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" + ;;; Org-mode (personal information manager) + (use-package org + :ensure nil + :init + (setq org-directory (expand-file-name "~/Documents/org/")) + (setq org-imenu-depth 7) + + (add-to-list 'safe-local-variable-values '(org-hide-leading-stars . t)) + (add-to-list 'safe-local-variable-values '(org-hide-macro-markers . t)) + :bind + ( :map global-map + ("C-c l" . org-store-link) + ("C-c o" . org-open-at-point-global) + :map org-mode-map + ;; I don't like that Org binds one zillion keys, so if I want one + ;; for something more important, I disable it from here. + ("C-'" . nil) + ("C-," . nil) + ("M-;" . nil) + ("C-c M-l" . org-insert-last-stored-link) + ("C-c C-M-l" . org-toggle-link-display) + ("M-." . org-edit-special) ; alias for C-c ' (mnenomic is global M-. that goes to source) + :map org-src-mode-map + ("M-," . org-edit-src-exit) ; see M-. above + :map narrow-map + ("b" . org-narrow-to-block) + ("e" . org-narrow-to-element) + ("s" . org-narrow-to-subtree) + :map ctl-x-x-map + ("i" . prot-org-id-headlines) + ("h" . prot-org-ox-html)) + :config + ;; My custom extras, which I use for the agenda and a few other Org features. + (require 'prot-org) + + ;;;; general settings + (setq org-ellipsis "⮧") + (setq org-adapt-indentation nil) ; No, non, nein, όχι! + (setq org-special-ctrl-a/e nil) + (setq org-special-ctrl-k nil) + (setq org-M-RET-may-split-line '((default . nil))) + (setq org-hide-emphasis-markers nil) + (setq org-hide-macro-markers nil) + (setq org-hide-leading-stars nil) + (setq org-cycle-separator-lines 0) + (setq org-structure-template-alist + '(("s" . "src") + ("e" . "src emacs-lisp") + ("E" . "src emacs-lisp :results value code :lexical t") + ("t" . "src emacs-lisp :tangle FILENAME") + ("T" . "src emacs-lisp :tangle FILENAME :mkdirp yes") + ("x" . "example") + ("X" . "export") + ("q" . "quote"))) + (setq org-fold-catch-invisible-edits 'show) + (setq org-return-follows-link nil) + (setq org-loop-over-headlines-in-active-region 'start-level) + (setq org-modules '(ol-info ol-eww)) + (setq org-use-sub-superscripts '{}) + (setq org-insert-heading-respect-content t) + (setq org-read-date-prefer-future 'time) + (setq org-highlight-latex-and-related nil) ; other options affect elisp regexp in src blocks + (setq org-fontify-quote-and-verse-blocks t) + (setq org-fontify-whole-block-delimiter-line t) + (setq org-track-ordered-property-with-tag t) + (setq org-highest-priority ?A) + (setq org-lowest-priority ?C) + (setq org-default-priority ?A) + (setq org-priority-faces nil)) +#+end_src + +*** The =unravel-org.el= Org to-do and refile settings +:PROPERTIES: +:CUSTOM_ID: h:024dd541-0061-4a10-b10b-b17dcd4794b9 +:END: + +#+begin_quote +One of the many use-cases for Org is to maintain a plain text to-do +list. A heading that starts with a to-do keyword, such as =TODO= is +treated as a task and its state is considered not completed. + +We can switch between the task states with shift and the left or right +arrow keys. Or we can select a keyword directly with =C-c C-t=, which +calls ~org-todo~ by default. I personally prefer the latter approach, +as it is more precise. + +Whenever a task state changes, we can log that event in a special +=LOGBOOK= drawer. This is automatically placed right below the +heading, before any paragraph text. Logging data is an opt-in feature, +which I consider helpful ([[#h:0884658e-9eb5-47e3-9338-66e09004a1a0][The =unravel-org.el= Org time/state logging]]). + +Tasks can be associated with timestamps, typically a scheduled +date+time or a deadline+time. This can be helpful when we are +reviewing the source Org file, though it really shines in tandem with +the agenda. Any heading that has a timestamp and which belongs to a +file in the ~org-agenda-files~ will show up on the agenda in the given +date ([[#h:7fe87b83-2815-4617-a5f9-d3417dd9d248][The =unravel-org.el= Org agenda settings]]). + +By default, the ~org-todo-keywords~ are =TODO= and =DONE=. We can +write more keywords if we wish to implement a descriptive workflow. +For example, we can have a =WAIT= keyword for something that is to be +done but is not actionable yet. While the number of keywords is not +limited, the binary model is the same: we have words that represent +the incomplete state and those that count as the completion of the +task. For instance, both =CANCEL= and =DONE= mean that the task is not +actionable anymore and we move on to other things. As such, the extra +keywords are a way for the user to make tasks more descriptive and +easy to find. In the value of the ~org-todo-keywords~, we use the bar +character to separate the incomplete state to the left from the +completed one to the right. + +One of the agenda's headiline features is the ability to produce a +view that lists headings with the given keyword. So having the right +terms can make search and retrieval of data more easy. On the +flip-side, too many keywords add cognitive load and require more +explicit search terms to yield the desired results. I used to work +with a more descriptive set of keywords, but ultimately decided to +keep things simple. + +The refile mechanism is how we can reparent a heading, by moving it +from one place to another. We do this with the command ~org-refile~, +bound to =C-c C-w= by default. A common workflow where refiling is +essential is to have an "inbox" file or heading, where unprocessed +information is stored at, and periodically process its contents to +move the data where it belongs. Though it can also work fine without +any such inbox, in those cases where a heading should be stored +someplace else. The ~org-refile-targets~ specifies the files that are +available when we try to refile the current heading. With how I set it +up, all the agenda files plus the current file's headings up to level +2 are included as possible targets. + +In terms of workflow, I have not done a refile in a very long time, +because my entries always stay in the same place as I had envisaged at +the capture phase ([[#h:f8f06938-0dfe-45c3-b4cf-996d36cba82d][The =unravel-org.el= Org capture templates (~org-capture~)]]). +#+end_quote + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; refile, todo +(use-package org + :ensure nil + :config + (setq org-refile-targets + '((org-agenda-files . (:maxlevel . 2)) + (nil . (:maxlevel . 2)))) + (setq org-refile-use-outline-path t) + (setq org-refile-allow-creating-parent-nodes 'confirm) + (setq org-refile-use-cache t) + (setq org-reverse-note-order nil) + ;; ;; NOTE 2023-04-07: Leaving this here for demo purposes. + ;; (setq org-todo-keywords + ;; '((sequence "TODO(t)" "MAYBE(m)" "WAIT(w@/!)" "|" "CANCEL(c@)" "DONE(d!)") + ;; (sequence "COACH(k)" "|" "COACHED(K!)"))) + (setq org-todo-keywords + '((sequence "TODO(t)" "|" "CANCEL(c@)" "DONE(d!)") + (sequence "COACH(k)" "|" "COACHED(K!)"))) + + (defface prot/org-bold-done + '((t :inherit (bold org-done))) + "Face for bold DONE-type Org keywords.") + + (setq org-todo-keyword-faces + '(("CANCEL" . prot/org-bold-done))) + (setq org-use-fast-todo-selection 'expert) + + (setq org-fontify-done-headline nil) + (setq org-fontify-todo-headline nil) + (setq org-fontify-whole-heading-line nil) + (setq org-enforce-todo-dependencies t) + (setq org-enforce-todo-checkbox-dependencies t)) +#+end_src + +*** The =unravel-org.el= Org heading tags +:PROPERTIES: +:CUSTOM_ID: h:81de4e32-a1af-4e1f-9e10-90eb0c90afa2 +:END: + +Each Org heading can have one or more tags associated with it, while +all headings inherit any potential =#+FILETAGS=. We can add tags to a +heading when the cursor is over it by typing the ever flexible =C-c C-c=. +Though the more specific ~org-set-tags-command~ also gets the job +done, plus it does not require that the cursor is positioned on the +heading text. + +Tagging is useful for searching and retrieving the data we store. The +Org agenda, in particular, provides commands to filter tasks by tag: + +- [[#h:024dd541-0061-4a10-b10b-b17dcd4794b9][The =unravel-org.el= Org to-do and refile settings]] +- [[#h:7fe87b83-2815-4617-a5f9-d3417dd9d248][The =unravel-org.el= Org agenda settings]] + +The user option ~org-tag-alist~ lets us specify tags we always want to +use, though we can write tags per file as well by using the =#+TAGS= +keyword. I do the latter as a global list of tags is not useful in my +case. For example, when I wan checking my =coach.org= file for the +coaching sessions I provide, I do not need to see any of the tags that +make sense in my general =tasks.org=. + +Note that in the settings below I disable the auto-alignment that Org +does where it shifts tags to the right of the heading. I do not like +it. + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; tags +(use-package org + :ensure nil + :config + (setq org-tag-alist nil) + (setq org-auto-align-tags nil) + (setq org-tags-column 0)) +#+end_src + +*** The =unravel-org.el= Org time/state logging +:PROPERTIES: +:CUSTOM_ID: h:0884658e-9eb5-47e3-9338-66e09004a1a0 +:END: + +Org can keep a record of state changes, such as when we set an entry +marked with the =TODO= keyword as =DONE= or when we reschedule an +appointment ([[#h:7fe87b83-2815-4617-a5f9-d3417dd9d248][The =unravel-org.el= Org agenda settings]]). This data +is stored in a =LOGBOOK= drawer right below the heading. I choose to +keep track of this information, as it is sometimes useful to capture +mistakes or figure out intent in the absence of further clarification +(though I do tend to write why something happened). + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; log +(use-package org + :ensure nil + :config + (setq org-log-done 'time) + (setq org-log-into-drawer t) + (setq org-log-note-clock-out nil) + (setq org-log-redeadline 'time) + (setq org-log-reschedule 'time)) +#+end_src + +*** The =unravel-org.el= Org link settings +:PROPERTIES: +:CUSTOM_ID: h:da8ce883-7f21-4a6e-a41f-d668ad762b41 +:END: + +One of the nice things about Org is its flexible linking mechanism. It +can produce links to a variety of file types or buffers and even +navigate to a section therein. + +At its simplest form, we have the =file= link type, which points to a +file system path, with an optional extension for a match inside the +file, as documented in the manual. Evaluate this inside of Emacs: + +#+begin_example emacs-lisp +(info "(org) Search Options") +#+end_example + +Links to buffers are also common and valuable. For example, we can +have a link to a page produced by the ~man~ command, which gives us +quick access to the documentation of some program. When Org follows +that link, it opens the buffer in the appropriate major mode. For me, +the most common scenario is a link to an email, which I typically +associate with a task that shows up in my agenda: + +- [[#h:f8f06938-0dfe-45c3-b4cf-996d36cba82d][The =unravel-org.el= Org capture templates (~org-capture~)]] +- [[#h:49890997-448e-408d-bebe-2003259bb125][The =unravel-notmuch.el= glue code for ~org-capture~ (=ol-notmuch.el=)]] + +Org supports lots of link types out-of-the-box, though more can be +added by packages. My Denote does this: it defines a =denote= link +type which behaves the same way as the =file= type except that it uses +the identifier of the file instead of its full path (so eve if the +file is renamed, the link will work for as long as the identifier +remains the same). + +Links can be generated automatically as part of an ~org-capture~ +template. The command ~org-store-link~ produces one manually, storing +it to a special data structure from which it can be retrieved later +for insertion with the command ~org-insert-link~. The latter command +can also create new links, simply by receiving data that is different +from what was already stored. + +I bind ~org-store-link~ in main section of the Org configuration: +[[#h:e03df1e0-b43e-49b5-978e-6a511165617c][The =unravel-org.el= section with basic Org settings]]. + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; links +(use-package org + :ensure nil + :config + (require 'prot-org) ; for the above commands + + (setq org-link-context-for-files t) + (setq org-link-keep-stored-after-insertion nil) + (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)) +#+end_src + +*** The =unravel-org.el= Org code block settings +:PROPERTIES: +:CUSTOM_ID: h:1f5a0d46-5202-48dd-8048-b48ce17f3df8 +:END: + +This document benefits from Org's ability to combine prose with code, +by placing the latter inside of a block that is delimited by +=#+BEGIN_SRC= and =#+END_SRC= lines. + +Code blocks can use the syntax highlighting ("fontification" in Emacs +parlance) of a given major mode. They can also have optional +parameters passed to their header, which expand the capabilities of +the block. For instance, the following code block with my actual +configuration uses the fontification of the ~emacs-lisp-mode~ and has +a =:tangle= parameter with a value of a file system path. When I +invoke the command ~org-babel-tangle~, the contents of this block will +be added to that file, creating the file if necessary. + +More generally, Org is capable of evaluating code blocks and passing +their return value to other code blocks. It is thus possible to write +a fully fledged program as an Org document. This paradigm is known as +"literate programming". In the case of an Emacs configuration, such as +mine, it is called a "literate configuration" or variants thereof. I +did a video about my setup: [[https://protesilaos.com/codelog/2023-12-18-emacs-org-advanced-literate-conf/][Advanced literate configuration with Org]] (2023-12-18). + +Org can evaluate code blocks in many languages. This is known as "Org +Babel" and the files which implement support for a given language are +typically named =ob-LANG.el= where =LANG= is the name of the language. +We can load the requisite code for the languages we care about with +something like the following: + +#+begin_example emacs-lisp +(require 'ob-python) + +;; OR + +(use-package ob-python) + +;; OR for more control + +(use-package ob-python + :after org + :config + ;; Settings here + ) +#+end_example + +I seldom need to work with Org Babel, so I do not load any language +automatically. Note that Emacs Lisp is loaded by default. + +To evaluate a code block, we type Org's omnipotent =C-c C-c=. The +results will be produced below the code block. There is an optional +parameter that controls how---or even if---the results are displayed. + +There are many other types of block apart from =SRC=. Those do +different things, such as: + +- =#+BEGIN_QUOTE= :: Treat the contents as a block quote or equivalent. +- =#+BEGIN_VERSE= :: Do not reflow any like breaks (for poetry and such). +- =#+BEGIN_EXPORT= :: Evaluate the code for the given export target + (like =html= or =latex=), optionally replacing it with its results + or keeping both of them ([[#h:bd11d4d8-6e9f-4536-87a4-4018783bf8f5][The =unravel-org.el= Org export settings]]). + +This is a wonderful world of possibilities! + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; code blocks +(use-package org + :ensure nil + :config + (setq org-confirm-babel-evaluate nil) + (setq org-src-window-setup 'current-window) + (setq org-edit-src-persistent-message nil) + (setq org-src-fontify-natively t) + (setq org-src-preserve-indentation t) + (setq org-src-tab-acts-natively t) + (setq org-edit-src-content-indentation 0)) +#+end_src + +*** The =unravel-org.el= Org export settings +:PROPERTIES: +:CUSTOM_ID: h:bd11d4d8-6e9f-4536-87a4-4018783bf8f5 +:END: + +Org is a capable authoring tool in no small part because it can be +converted to other file formats. A typical example is to write a +technical document in Org and then export it to a PDF. Another +use-case is what I commonly do with the Emacs packages I maintain, +which I export to an Info manual (texinfo format) and an HTML web +page. + +The default set of export targets is specified in the value of the +user option ~org-export-backends~. It is one of those rare cases where +it has to be evaluated before the package is loaded. Other than that, +we can load an export backend by finding the correspond =ox-FORMAT.el= +file and either ~require~ it or load it with ~use-package~, like what +I showed for Org Babel ([[#h:1f5a0d46-5202-48dd-8048-b48ce17f3df8][The =unravel-org.el= Org code block settings]]). + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; export +(use-package org + :ensure nil + :init + ;; NOTE 2023-05-20: Must be evaluated before Org is loaded, + ;; otherwise we have to use the Custom UI. No thanks! + (setq org-export-backends '(html texinfo md)) + :config + (setq org-export-with-toc t) + (setq org-export-headline-levels 8) + (setq org-export-dispatch-use-expert-ui nil) + (setq org-html-htmlize-output-type nil) + (setq org-html-head-include-default-style nil) + (setq org-html-head-include-scripts nil)) +#+end_src + +*** The =unravel-org.el= Org capture templates (~org-capture~) +:PROPERTIES: +:CUSTOM_ID: h:f8f06938-0dfe-45c3-b4cf-996d36cba82d +:END: + +The ~org-capture~ command allows us to quickly store data in some +structured way. This is done with the help of a templating system +where we can, for example, record the date the entry was recorded, +prompt for user input, automatically use the email's subject as the +title of the task, and the like. The documentation string of +~org-capture-templates~ covers the technicalities. + +I use two Org files for my tasks. The one is =tasks.org=, which +contains the bulk of my entries. The other is =coach.org=, which is +specific to my coaching work: https://protesilaos.com/coach. + +The =tasks.org= consists of several top-level headings. Each contains +subheadings I need to review. You will notice how most of my +entries in ~org-capture-templates~ involve this file. With Org, it is +perfectly fine to work in a single file because we can fold headings +or narrow to them with ~org-narrow-to-subtree~. Furthermore, we can +navigate directly to a heading using minibuffer completion, such as +with the general purpose command ~prot-search-outline~ +([[#h:b902e6a3-cdd2-420f-bc99-3d973c37cd20][The =unravel-search.el= extras provided by the =prot-search.el= library]]). + +Despite the fact that Org copes well with large files, I still choose +to keep my coaching work in a separate file as a contingency plan. +Because =coach.org= includes information about appointments, I need to +be able to read it with ease from anywhere. This includes different +types of hardware, but also any kind of generic text editor or +terminal pager. I do not want to depend on features like folding, +narrowing, and the like, in times when something has gone awry. +Granted, this has never happened, though the idea makes sense. +Besides, two files are not hard to manage in this case. The +=coach.org= has a simple structure: each appointment is stored as a +top-level heading. + +As for my workflow, here is an overview: + +- When I want to capture data that I am not yet sure about, I add it + to the =tasks.org= "Unprocessed" heading. I periodically review + those to decide if I want to do something with them or not. If I do + not want them, I delete them. Otherwise, I file them under another + heading in the same file using the ~org-refile~ command ([[#h:024dd541-0061-4a10-b10b-b17dcd4794b9][The =unravel-org.el= Org to-do and refile settings]]). + Not everything goes into the "Unprocessed" headings, as I often + known in advance what an item is about. This is just a fallback for + those cases when I need more information to decide on the + appropriate action. + +- Tasks that have an inherent time component are given a =SCHEDULED= + or =DEADLINE= timestamp (set those on demand with the commands + ~org-schedule~ and ~org-deadline~, respectively). These are the only + tasks I want to see on my daily agenda ([[#h:7fe87b83-2815-4617-a5f9-d3417dd9d248][The =unravel-org.el= Org agenda settings]]). + The difference between =SCHEDULED= and =DEADLINE= is that the former + has no strict start or end time and so is flexible, while the latter + is more rigid. For example, "visit the vet today" does not have a + strict time associated with it because the doctor often deals with + emergency situations and thus their agenda is fluid. While a + coaching session of mine like "work on Emacs with PERSON" has to + start at the agreed upon time. + +- I do not arbitrarily assign timestamps to tasks. If something does + not have a scheduled date or a deadline, then it does not belong on + the agenda. Otherwise, those arbitrarily defined "events" accumulate + in the agenda and crowd out the actual time-sensitive tasks. As a + result, the cognitive load is heavier and things will not be done. + So when I want to do something at some point, but have no specific + plan for it, I add is to the =tasks.org= "Wishlist". When I have + free time, I review my wishlist and pick something to work on from + there depending on my available time and mood. This keeps my + workflow both focused and stress-free. + +- Finally, my =coach.org= only has time-sensitive appointments with a + =DEADLINE= associated with them. I organise the rest of my + activities in the given day based on those. + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; capture +(use-package org-capture + :ensure nil + :bind ("C-c c" . org-capture) + :config + (require 'prot-org) + + (setq org-capture-templates + `(("u" "Unprocessed" entry + (file+headline "tasks.org" "Unprocessed") + ,(concat "* %^{Title}\n" + ":PROPERTIES:\n" + ":CAPTURED: %U\n" + ":END:\n\n" + "%a\n%i%?") + :empty-lines-after 1) + ;; ("e" "Email note (unprocessed)" entry ; Also see `org-capture-templates-contexts' + ;; (file+headline "tasks.org" "Unprocessed") + ;; ,(concat "* TODO %:subject :mail:\n" + ;; ":PROPERTIES:\n" + ;; ":CAPTURED: %U\n" + ;; ":END:\n\n" + ;; "%a\n%i%?") + ;; :empty-lines-after 1) + ("w" "Add to the wishlist (may do some day)" entry + (file+headline "tasks.org" "Wishlist") + ,(concat "* %^{Title}\n" + ":PROPERTIES:\n" + ":CAPTURED: %U\n" + ":END:\n\n" + "%a%?") + :empty-lines-after 1) + ("c" "Clock in and do immediately" entry + (file+headline "tasks.org" "Clocked tasks") + ,(concat "* TODO %^{Title}\n" + ":PROPERTIES:\n" + ":EFFORT: %^{Effort estimate in minutes|5|10|15|30|45|60|90|120}\n" + ":END:\n\n" + "%a\n") + :prepend t + :clock-in t + :clock-keep t + :immediate-finish t + :empty-lines-after 1) + ("t" "Time-sensitive task" entry + (file+headline "tasks.org" "Tasks with a date") + ,(concat "* TODO %^{Title} %^g\n" + "%^{How time sensitive it is||SCHEDULED|DEADLINE}: %^t\n" + ":PROPERTIES:\n" + ":CAPTURED: %U\n" + ":END:\n\n" + "%a%?") + :empty-lines-after 1) + ("p" "Private lesson or service" entry + (file "coach.org") + #'prot-org-capture-coach + :prepend t + :empty-lines 1) + ("P" "Private service clocked" entry + (file+headline "coach.org" "Clocked services") + #'prot-org-capture-coach-clock + :prepend t + :clock-in t + :clock-keep t + :immediate-finish t + :empty-lines 1))) + + ;; NOTE 2024-11-10: I realised that I was not using this enough, so + ;; I decided to simplify my setup. Keeping it here, in case I need + ;; it again. + + ;; (setq org-capture-templates-contexts + ;; '(("e" ((in-mode . "notmuch-search-mode") + ;; (in-mode . "notmuch-show-mode") + ;; (in-mode . "notmuch-tree-mode"))))) + ) +#+end_src + +*** The =unravel-org.el= Org agenda settings +:PROPERTIES: +:CUSTOM_ID: h:7fe87b83-2815-4617-a5f9-d3417dd9d248 +:END: + +[ Watch: [[https://protesilaos.com/codelog/2021-12-09-emacs-org-block-agenda/][Demo of my custom Org block agenda]] (2021-12-09). It has + changed a bit since then, but the idea is the same. ] + +With the Org agenda, we can visualise the tasks we have collected in +our Org files or, more specifically, in the list of files specified in +the user option ~org-agenda-files~. In my workflow, only the files in +the ~org-directory~ can feed data into the agenda. Though Org provides +commands to add/remove the current file on demand: ~org-remove-file~, +and ~org-agenda-file-to-front~. If I ever need to write a task that is +specific to a certain file or buffer, then I use Org's linking +mechanism to point to the relevant context, but otherwise store my +task in the usual place ([[#h:f8f06938-0dfe-45c3-b4cf-996d36cba82d][The =unravel-org.el= Org capture templates (~org-capture~)]]). + +By default, Org provides many so-called "views" for the agenda. One of +the them is the daily/weekly agenda. Others show only the headings +with =TODO= keywords, or some other kind of search criteria. I +personally never use those views. I have my own custom agenda view, +which consolidates in a single buffer the following blocks on data, in +this order ([[#h:9974eac8-2167-45c4-90e0-12dd877403da][The =prot-org.el= library]]).: + +- Important tasks without a date :: When I add a top priority to + something, but there is no inherent deadline to it. + +- Pending scheduled tasks :: Tasks with a =SCHEDULED= date may + sometimes not be done when they ought to. So they need to be closer + to the top for me to do them as soon as I can. + +- Today's agenda :: What I am actually working on. Because I only + assign a timestamp to tasks that are indeed time-sensitive, this + always reflects the commitments I have for the day. + +- Next three days :: Like the above, but for the near future. + +- Upcoming deadlines (+14d) :: These are the deadlines I need to be + aware of for the 14 days after the next three days I am only + informed about. + +The Org agenda has lots of other extras, such as to filter the view. +Though I never use them. My custom agenda does exactly what I need +from it and thus keeps me focused. + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +;;;; agenda +(use-package org-agenda + :ensure nil + :bind + ;; I bind `org-agenda' to C-c A, so this one puts me straight into my + ;; custom block agenda. + ( :map global-map + ("C-c A" . org-agenda) + ("C-c a" . (lambda () + "Call Org agenda with `prot-org-custom-daily-agenda' configuration." + (interactive) + (org-agenda nil "A")))) + :config +;;;;; Custom agenda blocks + + (setq org-agenda-format-date #'prot-org-agenda-format-date-aligned) + + ;; Check the variable `prot-org-custom-daily-agenda' in prot-org.el + (setq org-agenda-custom-commands + `(("A" "Daily agenda and top priority tasks" + ,prot-org-custom-daily-agenda + ((org-agenda-fontify-priorities nil) + (org-agenda-prefix-format " %t %s") + (org-agenda-dim-blocked-tasks nil))) + ("P" "Plain text daily agenda and top priorities" + ,prot-org-custom-daily-agenda + ((org-agenda-with-colors nil) + (org-agenda-prefix-format "%t %s") + (org-agenda-current-time-string ,(car (last org-agenda-time-grid))) + (org-agenda-fontify-priorities nil) + (org-agenda-remove-tags t)) + ("agenda.txt")))) + +;;;;; Basic agenda setup + (setq org-default-notes-file (make-temp-file "emacs-org-notes-")) ; send it to oblivion + (setq org-agenda-files `(,org-directory)) + (setq org-agenda-span 'week) + (setq org-agenda-start-on-weekday 1) ; Monday + (setq org-agenda-confirm-kill t) + (setq org-agenda-show-all-dates t) + (setq org-agenda-show-outline-path nil) + (setq org-agenda-window-setup 'current-window) + (setq org-agenda-skip-comment-trees t) + (setq org-agenda-menu-show-matcher t) + (setq org-agenda-menu-two-columns nil) + (setq org-agenda-sticky nil) + (setq org-agenda-custom-commands-contexts nil) + (setq org-agenda-max-entries nil) + (setq org-agenda-max-todos nil) + (setq org-agenda-max-tags nil) + (setq org-agenda-max-effort nil) + +;;;;; General agenda view options + ;; NOTE 2021-12-07: Check further below my `org-agenda-custom-commands' + (setq org-agenda-prefix-format + '((agenda . " %i %-12:c%?-12t% s") + (todo . " %i %-12:c") + (tags . " %i %-12:c") + (search . " %i %-12:c"))) + (setq org-agenda-sorting-strategy + '(((agenda habit-down time-up priority-down category-keep) + (todo priority-down category-keep) + (tags priority-down category-keep) + (search category-keep)))) + (setq org-agenda-breadcrumbs-separator "->") + (setq org-agenda-todo-keyword-format "%-1s") + (setq org-agenda-fontify-priorities 'cookies) + (setq org-agenda-category-icon-alist nil) + (setq org-agenda-remove-times-when-in-prefix nil) + (setq org-agenda-remove-timeranges-from-blocks nil) + (setq org-agenda-compact-blocks nil) + (setq org-agenda-block-separator ?—) + +;;;;; Agenda marks + (setq org-agenda-bulk-mark-char "#") + (setq org-agenda-persistent-marks nil) + +;;;;; Agenda diary entries + (setq org-agenda-insert-diary-strategy 'date-tree) + (setq org-agenda-insert-diary-extract-time nil) + (setq org-agenda-include-diary nil) + ;; I do not want the diary, but there is no way to disable it + ;; altogether. This creates a diary file in the /tmp directory. + (setq diary-file (make-temp-file "emacs-diary-")) + (setq org-agenda-diary-file 'diary-file) ; TODO 2023-05-20: review Org diary substitute + +;;;;; Agenda follow mode + (setq org-agenda-start-with-follow-mode nil) + (setq org-agenda-follow-indirect t) + +;;;;; Agenda multi-item tasks + (setq org-agenda-dim-blocked-tasks t) + (setq org-agenda-todo-list-sublevels t) + +;;;;; Agenda filters and restricted views + (setq org-agenda-persistent-filter nil) + (setq org-agenda-restriction-lock-highlight-subtree t) + +;;;;; Agenda items with deadline and scheduled timestamps + (setq org-agenda-include-deadlines t) + (setq org-deadline-warning-days 0) + (setq org-agenda-skip-scheduled-if-done nil) + (setq org-agenda-skip-scheduled-if-deadline-is-shown t) + (setq org-agenda-skip-timestamp-if-deadline-is-shown t) + (setq org-agenda-skip-deadline-if-done nil) + (setq org-agenda-skip-deadline-prewarning-if-scheduled 1) + (setq org-agenda-skip-scheduled-delay-if-deadline nil) + (setq org-agenda-skip-additional-timestamps-same-entry nil) + (setq org-agenda-skip-timestamp-if-done nil) + (setq org-agenda-search-headline-for-time nil) + (setq org-scheduled-past-days 365) + (setq org-deadline-past-days 365) + (setq org-agenda-move-date-from-past-immediately-to-today t) + (setq org-agenda-show-future-repeats t) + (setq org-agenda-prefer-last-repeat nil) + (setq org-agenda-timerange-leaders + '("" "(%d/%d): ")) + (setq org-agenda-scheduled-leaders + '("Scheduled: " "Sched.%2dx: ")) + (setq org-agenda-inactive-leader "[") + (setq org-agenda-deadline-leaders + '("Deadline: " "In %3d d.: " "%2d d. ago: ")) + ;; Time grid + (setq org-agenda-time-leading-zero t) + (setq org-agenda-timegrid-use-ampm nil) + (setq org-agenda-use-time-grid t) + (setq org-agenda-show-current-time-in-grid t) + (setq org-agenda-current-time-string (concat "Now " (make-string 70 ?.))) + (setq org-agenda-time-grid + '((daily today require-timed) + ( 0500 0600 0700 0800 0900 1000 + 1100 1200 1300 1400 1500 1600 + 1700 1800 1900 2000 2100 2200) + "" "")) + (setq org-agenda-default-appointment-duration nil) + +;;;;; Agenda global to-do list + (setq org-agenda-todo-ignore-with-date t) + (setq org-agenda-todo-ignore-timestamp t) + (setq org-agenda-todo-ignore-scheduled t) + (setq org-agenda-todo-ignore-deadlines t) + (setq org-agenda-todo-ignore-time-comparison-use-seconds t) + (setq org-agenda-tags-todo-honor-ignore-options nil) + +;;;;; Agenda tagged items + (setq org-agenda-show-inherited-tags t) + (setq org-agenda-use-tag-inheritance + '(todo search agenda)) + (setq org-agenda-hide-tags-regexp nil) + (setq org-agenda-remove-tags nil) + (setq org-agenda-tags-column -100) + +;;;;; Agenda entry + ;; NOTE: I do not use this right now. Leaving everything to its + ;; default value. + (setq org-agenda-start-with-entry-text-mode nil) + (setq org-agenda-entry-text-maxlines 5) + (setq org-agenda-entry-text-exclude-regexps nil) + (setq org-agenda-entry-text-leaders " > ") + +;;;;; Agenda logging and clocking + ;; NOTE: I do not use these yet, though I plan to. Leaving everything + ;; to its default value for the time being. + (setq org-agenda-log-mode-items '(closed clock)) + (setq org-agenda-clock-consistency-checks + '((:max-duration "10:00" :min-duration 0 :max-gap "0:05" :gap-ok-around + ("4:00") + :default-face ; This should definitely be reviewed + ((:background "DarkRed") + (:foreground "white")) + :overlap-face nil :gap-face nil :no-end-time-face nil + :long-face nil :short-face nil))) + (setq org-agenda-log-mode-add-notes t) + (setq org-agenda-start-with-log-mode nil) + (setq org-agenda-start-with-clockreport-mode nil) + (setq org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2)) + (setq org-agenda-search-view-always-boolean nil) + (setq org-agenda-search-view-force-full-words nil) + (setq org-agenda-search-view-max-outline-level 0) + (setq org-agenda-search-headline-for-time t) + (setq org-agenda-use-time-grid t) + (setq org-agenda-cmp-user-defined nil) + (setq org-agenda-sort-notime-is-late t) ; Org 9.4 + (setq org-agenda-sort-noeffort-is-high t) ; Org 9.4 + +;;;;; Agenda column view + ;; NOTE I do not use these, but may need them in the future. + (setq org-agenda-view-columns-initially nil) + (setq org-agenda-columns-show-summaries t) + (setq org-agenda-columns-compute-summary-properties t) + (setq org-agenda-columns-add-appointments-to-effort-sum nil) + (setq org-agenda-auto-exclude-function nil) + (setq org-agenda-bulk-custom-functions nil) + + ;; ;;;;; Agenda habits + ;; (require 'org-habit) + ;; (setq org-habit-graph-column 50) + ;; (setq org-habit-preceding-days 9) + ;; ;; Always show the habit graph, even if there are no habits for + ;; ;; today. + ;; (setq org-habit-show-all-today t) + ) +#+end_src + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +(use-package prot-coach + :ensure nil + :commands (prot-coach-done-sessions-with-person)) +#+end_src + +*** The =unravel-org.el= call to ~provide~ +:PROPERTIES: +:CUSTOM_ID: h:62eb7ca3-2f79-45a6-a018-38238b486e98 +:END: + +Finally, we ~provide~ the module. This is the mirror function of +~require~ ([[#h:e6c4acf5-5b51-4b38-a86a-bf3f698ac872][The init.el final part to load the individual modules]]). + +#+begin_src emacs-lisp :tangle "unravel-modules/unravel-org.el" +(provide 'unravel-org) +#+end_src + diff --git a/unravel-modules/unravel-git.el b/unravel-modules/unravel-git.el new file mode 100644 index 0000000..67d5935 --- /dev/null +++ b/unravel-modules/unravel-git.el @@ -0,0 +1,78 @@ +;;;; `ediff' +(use-package ediff + :ensure nil + :commands (ediff-buffers ediff-files ediff-buffers3 ediff-files3) + :init + (setq ediff-split-window-function 'split-window-horizontally) + (setq ediff-window-setup-function 'ediff-setup-windows-plain) + :config + (setq ediff-keep-variants nil) + (setq ediff-make-buffers-readonly-at-startup nil) + (setq ediff-merge-revisions-with-ancestor t) + (setq ediff-show-clashes-only t)) + +;;;; `project' +(use-package project + :ensure nil + :bind + (("C-x p ." . project-dired) + ("C-x p C-g" . keyboard-quit) + ("C-x p <return>" . project-dired) + ("C-x p <delete>" . project-forget-project)) + :config + (setopt project-switch-commands + '((project-find-file "Find file") + (project-find-regexp "Find regexp") + (project-find-dir "Find directory") + (project-dired "Root dired") + (project-vc-dir "VC-Dir") + (project-shell "Shell") + (keyboard-quit "Quit"))) + (setq project-vc-extra-root-markers '(".project")) ; Emacs 29 + (setq project-key-prompt-style t) ; Emacs 30 + + (advice-add #'project-switch-project :after #'prot-common-clear-minibuffer-message)) + +;;;; `diff-mode' +(use-package diff-mode + :ensure nil + :defer t + :config + (setq diff-default-read-only t) + (setq diff-advance-after-apply-hunk t) + (setq diff-update-on-the-fly t) + ;; The following are from Emacs 27.1 + (setq diff-refine nil) ; I do it on demand, with my `agitate' package (more below) + (setq diff-font-lock-prettify t) ; I think nil is better for patches, but let me try this for a while + (setq diff-font-lock-syntax 'hunk-also)) + +;;; Interactive and powerful git front-end (Magit) +(use-package transient + :defer t + :config + (setq transient-show-popup 0.5)) + +(use-package magit + :ensure t + :bind ("C-c g" . magit-status) + :init + (setq magit-define-global-key-bindings nil) + ;; (setq magit-section-visibility-indicator '("⮧")) + :config + (setq git-commit-summary-max-length 50) + ;; NOTE 2023-01-24: I used to also include `overlong-summary-line' + ;; in this list, but I realised I do not need it. My summaries are + ;; always in check. When I exceed the limit, it is for a good + ;; reason. + ;; (setq git-commit-style-convention-checks '(non-empty-second-line)) + + (setq magit-diff-refine-hunk t)) + +(use-package magit-repos + :ensure nil ; part of `magit' + :commands (magit-list-repositories) + :init + (setq magit-repository-directories + '(("~/src/prototypes" . 1)))) + +(provide 'unravel-git) diff --git a/unravel-modules/unravel-org.el b/unravel-modules/unravel-org.el new file mode 100644 index 0000000..daf3fde --- /dev/null +++ b/unravel-modules/unravel-org.el @@ -0,0 +1,488 @@ +;;; Calendar +(use-package calendar + :ensure nil + :commands (calendar) + :config + (setq calendar-mark-diary-entries-flag nil) + (setq calendar-mark-holidays-flag t) + (setq calendar-mode-line-format nil) + (setq calendar-time-display-form + '( 24-hours ":" minutes + (when time-zone (format "(%s)" time-zone)))) + (setq calendar-week-start-day 1) ; Monday + (setq calendar-date-style 'iso) + (setq calendar-time-zone-style 'numeric) ; Emacs 28.1 + + (require 'solar) + (setq calendar-latitude 35.17 ; Not my actual coordinates + calendar-longitude 33.36) + + (require 'cal-dst) + (setq calendar-standard-time-zone-name "+0200") + (setq calendar-daylight-time-zone-name "+0300")) + +;;; Appt (appointment reminders which also integrate with Org agenda) +(use-package appt + :ensure nil + :commands (appt-activate) + :config + (setq appt-display-diary nil + appt-display-format nil + appt-display-mode-line t + appt-display-interval 3 + appt-audible nil ; TODO 2023-01-25: t does nothing because I disable `ring-bell-function'? + appt-warning-time-regexp "appt \\([0-9]+\\)" ; This is for the diary + appt-message-warning-time 6) + + (with-eval-after-load 'org-agenda + (appt-activate 1) + + ;; NOTE 2021-12-07: In my `prot-org.el' (see further below), I add + ;; `org-agenda-to-appt' to various relevant hooks. + ;; + ;; Create reminders for tasks with a due date when this file is read. + (org-agenda-to-appt))) + +;;; Org-mode (personal information manager) +(use-package org + :ensure nil + :init + (setq org-directory (expand-file-name "~/Documents/org/")) + (setq org-imenu-depth 7) + + (add-to-list 'safe-local-variable-values '(org-hide-leading-stars . t)) + (add-to-list 'safe-local-variable-values '(org-hide-macro-markers . t)) + :bind + ( :map global-map + ("C-c l" . org-store-link) + ("C-c o" . org-open-at-point-global) + :map org-mode-map + ;; I don't like that Org binds one zillion keys, so if I want one + ;; for something more important, I disable it from here. + ("C-'" . nil) + ("C-," . nil) + ("M-;" . nil) + ("C-c M-l" . org-insert-last-stored-link) + ("C-c C-M-l" . org-toggle-link-display) + ("M-." . org-edit-special) ; alias for C-c ' (mnenomic is global M-. that goes to source) + :map org-src-mode-map + ("M-," . org-edit-src-exit) ; see M-. above + :map narrow-map + ("b" . org-narrow-to-block) + ("e" . org-narrow-to-element) + ("s" . org-narrow-to-subtree) + :map ctl-x-x-map + ("i" . prot-org-id-headlines) + ("h" . prot-org-ox-html)) + :config + ;; My custom extras, which I use for the agenda and a few other Org features. + (require 'prot-org) + +;;;; general settings + (setq org-ellipsis "⮧") + (setq org-adapt-indentation nil) ; No, non, nein, όχι! + (setq org-special-ctrl-a/e nil) + (setq org-special-ctrl-k nil) + (setq org-M-RET-may-split-line '((default . nil))) + (setq org-hide-emphasis-markers nil) + (setq org-hide-macro-markers nil) + (setq org-hide-leading-stars nil) + (setq org-cycle-separator-lines 0) + (setq org-structure-template-alist + '(("s" . "src") + ("e" . "src emacs-lisp") + ("E" . "src emacs-lisp :results value code :lexical t") + ("t" . "src emacs-lisp :tangle FILENAME") + ("T" . "src emacs-lisp :tangle FILENAME :mkdirp yes") + ("x" . "example") + ("X" . "export") + ("q" . "quote"))) + (setq org-fold-catch-invisible-edits 'show) + (setq org-return-follows-link nil) + (setq org-loop-over-headlines-in-active-region 'start-level) + (setq org-modules '(ol-info ol-eww)) + (setq org-use-sub-superscripts '{}) + (setq org-insert-heading-respect-content t) + (setq org-read-date-prefer-future 'time) + (setq org-highlight-latex-and-related nil) ; other options affect elisp regexp in src blocks + (setq org-fontify-quote-and-verse-blocks t) + (setq org-fontify-whole-block-delimiter-line t) + (setq org-track-ordered-property-with-tag t) + (setq org-highest-priority ?A) + (setq org-lowest-priority ?C) + (setq org-default-priority ?A) + (setq org-priority-faces nil)) + +;;;; refile, todo +(use-package org + :ensure nil + :config + (setq org-refile-targets + '((org-agenda-files . (:maxlevel . 2)) + (nil . (:maxlevel . 2)))) + (setq org-refile-use-outline-path t) + (setq org-refile-allow-creating-parent-nodes 'confirm) + (setq org-refile-use-cache t) + (setq org-reverse-note-order nil) + ;; ;; NOTE 2023-04-07: Leaving this here for demo purposes. + ;; (setq org-todo-keywords + ;; '((sequence "TODO(t)" "MAYBE(m)" "WAIT(w@/!)" "|" "CANCEL(c@)" "DONE(d!)") + ;; (sequence "COACH(k)" "|" "COACHED(K!)"))) + (setq org-todo-keywords + '((sequence "TODO(t)" "|" "CANCEL(c@)" "DONE(d!)") + (sequence "COACH(k)" "|" "COACHED(K!)"))) + + (defface prot/org-bold-done + '((t :inherit (bold org-done))) + "Face for bold DONE-type Org keywords.") + + (setq org-todo-keyword-faces + '(("CANCEL" . prot/org-bold-done))) + (setq org-use-fast-todo-selection 'expert) + + (setq org-fontify-done-headline nil) + (setq org-fontify-todo-headline nil) + (setq org-fontify-whole-heading-line nil) + (setq org-enforce-todo-dependencies t) + (setq org-enforce-todo-checkbox-dependencies t)) + +;;;; tags +(use-package org + :ensure nil + :config + (setq org-tag-alist nil) + (setq org-auto-align-tags nil) + (setq org-tags-column 0)) + +;;;; log +(use-package org + :ensure nil + :config + (setq org-log-done 'time) + (setq org-log-into-drawer t) + (setq org-log-note-clock-out nil) + (setq org-log-redeadline 'time) + (setq org-log-reschedule 'time)) + +;;;; links +(use-package org + :ensure nil + :config + (require 'prot-org) ; for the above commands + + (setq org-link-context-for-files t) + (setq org-link-keep-stored-after-insertion nil) + (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)) + +;;;; code blocks +(use-package org + :ensure nil + :config + (setq org-confirm-babel-evaluate nil) + (setq org-src-window-setup 'current-window) + (setq org-edit-src-persistent-message nil) + (setq org-src-fontify-natively t) + (setq org-src-preserve-indentation t) + (setq org-src-tab-acts-natively t) + (setq org-edit-src-content-indentation 0)) + +;;;; export +(use-package org + :ensure nil + :init + ;; NOTE 2023-05-20: Must be evaluated before Org is loaded, + ;; otherwise we have to use the Custom UI. No thanks! + (setq org-export-backends '(html texinfo md)) + :config + (setq org-export-with-toc t) + (setq org-export-headline-levels 8) + (setq org-export-dispatch-use-expert-ui nil) + (setq org-html-htmlize-output-type nil) + (setq org-html-head-include-default-style nil) + (setq org-html-head-include-scripts nil)) + +;;;; capture +(use-package org-capture + :ensure nil + :bind ("C-c c" . org-capture) + :config + (require 'prot-org) + + (setq org-capture-templates + `(("u" "Unprocessed" entry + (file+headline "tasks.org" "Unprocessed") + ,(concat "* %^{Title}\n" + ":PROPERTIES:\n" + ":CAPTURED: %U\n" + ":END:\n\n" + "%a\n%i%?") + :empty-lines-after 1) + ;; ("e" "Email note (unprocessed)" entry ; Also see `org-capture-templates-contexts' + ;; (file+headline "tasks.org" "Unprocessed") + ;; ,(concat "* TODO %:subject :mail:\n" + ;; ":PROPERTIES:\n" + ;; ":CAPTURED: %U\n" + ;; ":END:\n\n" + ;; "%a\n%i%?") + ;; :empty-lines-after 1) + ("w" "Add to the wishlist (may do some day)" entry + (file+headline "tasks.org" "Wishlist") + ,(concat "* %^{Title}\n" + ":PROPERTIES:\n" + ":CAPTURED: %U\n" + ":END:\n\n" + "%a%?") + :empty-lines-after 1) + ("c" "Clock in and do immediately" entry + (file+headline "tasks.org" "Clocked tasks") + ,(concat "* TODO %^{Title}\n" + ":PROPERTIES:\n" + ":EFFORT: %^{Effort estimate in minutes|5|10|15|30|45|60|90|120}\n" + ":END:\n\n" + "%a\n") + :prepend t + :clock-in t + :clock-keep t + :immediate-finish t + :empty-lines-after 1) + ("t" "Time-sensitive task" entry + (file+headline "tasks.org" "Tasks with a date") + ,(concat "* TODO %^{Title} %^g\n" + "%^{How time sensitive it is||SCHEDULED|DEADLINE}: %^t\n" + ":PROPERTIES:\n" + ":CAPTURED: %U\n" + ":END:\n\n" + "%a%?") + :empty-lines-after 1) + ("p" "Private lesson or service" entry + (file "coach.org") + #'prot-org-capture-coach + :prepend t + :empty-lines 1) + ("P" "Private service clocked" entry + (file+headline "coach.org" "Clocked services") + #'prot-org-capture-coach-clock + :prepend t + :clock-in t + :clock-keep t + :immediate-finish t + :empty-lines 1))) + + ;; NOTE 2024-11-10: I realised that I was not using this enough, so + ;; I decided to simplify my setup. Keeping it here, in case I need + ;; it again. + + ;; (setq org-capture-templates-contexts + ;; '(("e" ((in-mode . "notmuch-search-mode") + ;; (in-mode . "notmuch-show-mode") + ;; (in-mode . "notmuch-tree-mode"))))) + ) + +;;;; agenda +(use-package org-agenda + :ensure nil + :bind + ;; I bind `org-agenda' to C-c A, so this one puts me straight into my + ;; custom block agenda. + ( :map global-map + ("C-c A" . org-agenda) + ("C-c a" . (lambda () + "Call Org agenda with `prot-org-custom-daily-agenda' configuration." + (interactive) + (org-agenda nil "A")))) + :config +;;;;; Custom agenda blocks + + (setq org-agenda-format-date #'prot-org-agenda-format-date-aligned) + + ;; Check the variable `prot-org-custom-daily-agenda' in prot-org.el + (setq org-agenda-custom-commands + `(("A" "Daily agenda and top priority tasks" + ,prot-org-custom-daily-agenda + ((org-agenda-fontify-priorities nil) + (org-agenda-prefix-format " %t %s") + (org-agenda-dim-blocked-tasks nil))) + ("P" "Plain text daily agenda and top priorities" + ,prot-org-custom-daily-agenda + ((org-agenda-with-colors nil) + (org-agenda-prefix-format "%t %s") + (org-agenda-current-time-string ,(car (last org-agenda-time-grid))) + (org-agenda-fontify-priorities nil) + (org-agenda-remove-tags t)) + ("agenda.txt")))) + +;;;;; Basic agenda setup + (setq org-default-notes-file (make-temp-file "emacs-org-notes-")) ; send it to oblivion + (setq org-agenda-files `(,org-directory)) + (setq org-agenda-span 'week) + (setq org-agenda-start-on-weekday 1) ; Monday + (setq org-agenda-confirm-kill t) + (setq org-agenda-show-all-dates t) + (setq org-agenda-show-outline-path nil) + (setq org-agenda-window-setup 'current-window) + (setq org-agenda-skip-comment-trees t) + (setq org-agenda-menu-show-matcher t) + (setq org-agenda-menu-two-columns nil) + (setq org-agenda-sticky nil) + (setq org-agenda-custom-commands-contexts nil) + (setq org-agenda-max-entries nil) + (setq org-agenda-max-todos nil) + (setq org-agenda-max-tags nil) + (setq org-agenda-max-effort nil) + +;;;;; General agenda view options + ;; NOTE 2021-12-07: Check further below my `org-agenda-custom-commands' + (setq org-agenda-prefix-format + '((agenda . " %i %-12:c%?-12t% s") + (todo . " %i %-12:c") + (tags . " %i %-12:c") + (search . " %i %-12:c"))) + (setq org-agenda-sorting-strategy + '(((agenda habit-down time-up priority-down category-keep) + (todo priority-down category-keep) + (tags priority-down category-keep) + (search category-keep)))) + (setq org-agenda-breadcrumbs-separator "->") + (setq org-agenda-todo-keyword-format "%-1s") + (setq org-agenda-fontify-priorities 'cookies) + (setq org-agenda-category-icon-alist nil) + (setq org-agenda-remove-times-when-in-prefix nil) + (setq org-agenda-remove-timeranges-from-blocks nil) + (setq org-agenda-compact-blocks nil) + (setq org-agenda-block-separator ?—) + +;;;;; Agenda marks + (setq org-agenda-bulk-mark-char "#") + (setq org-agenda-persistent-marks nil) + +;;;;; Agenda diary entries + (setq org-agenda-insert-diary-strategy 'date-tree) + (setq org-agenda-insert-diary-extract-time nil) + (setq org-agenda-include-diary nil) + ;; I do not want the diary, but there is no way to disable it + ;; altogether. This creates a diary file in the /tmp directory. + (setq diary-file (make-temp-file "emacs-diary-")) + (setq org-agenda-diary-file 'diary-file) ; TODO 2023-05-20: review Org diary substitute + +;;;;; Agenda follow mode + (setq org-agenda-start-with-follow-mode nil) + (setq org-agenda-follow-indirect t) + +;;;;; Agenda multi-item tasks + (setq org-agenda-dim-blocked-tasks t) + (setq org-agenda-todo-list-sublevels t) + +;;;;; Agenda filters and restricted views + (setq org-agenda-persistent-filter nil) + (setq org-agenda-restriction-lock-highlight-subtree t) + +;;;;; Agenda items with deadline and scheduled timestamps + (setq org-agenda-include-deadlines t) + (setq org-deadline-warning-days 0) + (setq org-agenda-skip-scheduled-if-done nil) + (setq org-agenda-skip-scheduled-if-deadline-is-shown t) + (setq org-agenda-skip-timestamp-if-deadline-is-shown t) + (setq org-agenda-skip-deadline-if-done nil) + (setq org-agenda-skip-deadline-prewarning-if-scheduled 1) + (setq org-agenda-skip-scheduled-delay-if-deadline nil) + (setq org-agenda-skip-additional-timestamps-same-entry nil) + (setq org-agenda-skip-timestamp-if-done nil) + (setq org-agenda-search-headline-for-time nil) + (setq org-scheduled-past-days 365) + (setq org-deadline-past-days 365) + (setq org-agenda-move-date-from-past-immediately-to-today t) + (setq org-agenda-show-future-repeats t) + (setq org-agenda-prefer-last-repeat nil) + (setq org-agenda-timerange-leaders + '("" "(%d/%d): ")) + (setq org-agenda-scheduled-leaders + '("Scheduled: " "Sched.%2dx: ")) + (setq org-agenda-inactive-leader "[") + (setq org-agenda-deadline-leaders + '("Deadline: " "In %3d d.: " "%2d d. ago: ")) + ;; Time grid + (setq org-agenda-time-leading-zero t) + (setq org-agenda-timegrid-use-ampm nil) + (setq org-agenda-use-time-grid t) + (setq org-agenda-show-current-time-in-grid t) + (setq org-agenda-current-time-string (concat "Now " (make-string 70 ?.))) + (setq org-agenda-time-grid + '((daily today require-timed) + ( 0500 0600 0700 0800 0900 1000 + 1100 1200 1300 1400 1500 1600 + 1700 1800 1900 2000 2100 2200) + "" "")) + (setq org-agenda-default-appointment-duration nil) + +;;;;; Agenda global to-do list + (setq org-agenda-todo-ignore-with-date t) + (setq org-agenda-todo-ignore-timestamp t) + (setq org-agenda-todo-ignore-scheduled t) + (setq org-agenda-todo-ignore-deadlines t) + (setq org-agenda-todo-ignore-time-comparison-use-seconds t) + (setq org-agenda-tags-todo-honor-ignore-options nil) + +;;;;; Agenda tagged items + (setq org-agenda-show-inherited-tags t) + (setq org-agenda-use-tag-inheritance + '(todo search agenda)) + (setq org-agenda-hide-tags-regexp nil) + (setq org-agenda-remove-tags nil) + (setq org-agenda-tags-column -100) + +;;;;; Agenda entry + ;; NOTE: I do not use this right now. Leaving everything to its + ;; default value. + (setq org-agenda-start-with-entry-text-mode nil) + (setq org-agenda-entry-text-maxlines 5) + (setq org-agenda-entry-text-exclude-regexps nil) + (setq org-agenda-entry-text-leaders " > ") + +;;;;; Agenda logging and clocking + ;; NOTE: I do not use these yet, though I plan to. Leaving everything + ;; to its default value for the time being. + (setq org-agenda-log-mode-items '(closed clock)) + (setq org-agenda-clock-consistency-checks + '((:max-duration "10:00" :min-duration 0 :max-gap "0:05" :gap-ok-around + ("4:00") + :default-face ; This should definitely be reviewed + ((:background "DarkRed") + (:foreground "white")) + :overlap-face nil :gap-face nil :no-end-time-face nil + :long-face nil :short-face nil))) + (setq org-agenda-log-mode-add-notes t) + (setq org-agenda-start-with-log-mode nil) + (setq org-agenda-start-with-clockreport-mode nil) + (setq org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2)) + (setq org-agenda-search-view-always-boolean nil) + (setq org-agenda-search-view-force-full-words nil) + (setq org-agenda-search-view-max-outline-level 0) + (setq org-agenda-search-headline-for-time t) + (setq org-agenda-use-time-grid t) + (setq org-agenda-cmp-user-defined nil) + (setq org-agenda-sort-notime-is-late t) ; Org 9.4 + (setq org-agenda-sort-noeffort-is-high t) ; Org 9.4 + +;;;;; Agenda column view + ;; NOTE I do not use these, but may need them in the future. + (setq org-agenda-view-columns-initially nil) + (setq org-agenda-columns-show-summaries t) + (setq org-agenda-columns-compute-summary-properties t) + (setq org-agenda-columns-add-appointments-to-effort-sum nil) + (setq org-agenda-auto-exclude-function nil) + (setq org-agenda-bulk-custom-functions nil) + + ;; ;;;;; Agenda habits + ;; (require 'org-habit) + ;; (setq org-habit-graph-column 50) + ;; (setq org-habit-preceding-days 9) + ;; ;; Always show the habit graph, even if there are no habits for + ;; ;; today. + ;; (setq org-habit-show-all-today t) + ) + +(use-package prot-coach + :ensure nil + :commands (prot-coach-done-sessions-with-person)) + +(provide 'unravel-org)