diff --git a/.aspell.en.pws b/.aspell.en.pws index 6af9e80..45aff39 100644 --- a/.aspell.en.pws +++ b/.aspell.en.pws @@ -1,4 +1,4 @@ -personal_ws-1.1 en 375 +personal_ws-1.1 en 376 ACSII AST ASTs @@ -99,6 +99,7 @@ Shyam StackExchange Submittable Subsegment +Summarisation Surjection TODO Tcl diff --git a/init.el b/init.el index 844601e..5aafd10 100644 --- a/init.el +++ b/init.el @@ -1643,948 +1643,6 @@ fonts (•̀ᴗ•́)و" (setq url-cache-directory "~/emacs.d/.cache/") (setq org-display-remote-inline-images 'cache) -;; Add a note whenever a task's deadline or scheduled date is changed. -(setq org-log-redeadline 'time) -(setq org-log-reschedule 'time) - -(define-key global-map "\C-ca" 'org-agenda) - -;; List of all the files & directories where todo items can be found. Only one -;; for now: My default notes file. -(setq org-agenda-files (list org-default-notes-file)) - -;; Display tags really close to their tasks. -(setq org-agenda-tags-column -10) - -;; How many days ahead the default agenda view should look -(setq org-agenda-span 'day) -;; May be any number; the larger the slower it takes to generate the view. -;; One day is thus the fastest ^_^ - -;; How many days early a deadline item will begin showing up in your agenda list. -(setq org-deadline-warning-days 14) - -;; In the agenda view, days that have no associated tasks will still have a line showing the date. -(setq org-agenda-show-all-dates t) - -;; Scheduled items marked as complete will not show up in your agenda view. -(setq org-agenda-skip-scheduled-if-done t) -(setq org-agenda-skip-deadline-if-done t) - -(setq org-agenda-start-on-weekday nil) - -;; Start each agenda item with ‘○’, then show me it's %timestamp and how many -;; times it's been re-%scheduled. -(setq org-agenda-prefix-format " ○ %t%s") - -(use-package origami ) -(use-package org-super-agenda - - :hook (org-agenda-mode . origami-mode) ;; Easily fold groups via TAB. - :bind (:map org-super-agenda-header-map ("" . origami-toggle-node)) - :config - (org-super-agenda-mode) - (setq org-super-agenda-groups - '((:name "Important" :priority "A") - (:name "Personal" :habit t) - ;; For everything else, nicely display their heading hierarchy list. - (:auto-map (lambda (e) (org-format-outline-path (org-get-outline-path))))))) - -;; MA: No noticable effect when using org-super-agenda :/ -;; -;; Leave new line at the end of an entry. -;; (setq org-blank-before-new-entry '((heading . t) (plain-list-item . t))) - -(setq org-lowest-priority ?C) ;; Now org-speed-eky ‘,’ gives 3 options -(setq org-priority-faces -'((?A :foreground "red" :weight bold) ;; :background "LightCyan1") - (?B :foreground "orange" :weight bold) - (?C :foreground "green" :weight bold))) -;; See all colours with: M-x list-colors-display - -(use-package org-fancy-priorities - - :hook (org-mode . org-fancy-priorities-mode) - :custom (org-fancy-priorities-list '("MUST DO" "MID" "LOW")) ;; "OPTIONAL" - ;; Let's use the “Eisenhower map of priority”… - ;; :custom (org-fancy-priorities-list '("Urgent and Important" ;; Do now! - ;; "Not Urgent But Important" ;; Do schedule this. - ;; "Urgent But Not Important" ;; Delegate? - ;; "Not Urgent and Not Important")) ;; Don't do / Optional - ) - -(require 'org-agenda) - -;; How should the columns view look? -(setq org-columns-default-format "%60ITEM(Task) %6Effort(Estim){:} %3PRIORITY %TAGS") - -;; Press “c” in Org agenda to see the columns view; (default binding C-c C-x C-c is too long!) -(org-defkey org-agenda-mode-map "c" #'org-agenda-columns) -(org-defkey org-agenda-mode-map "C" #'org-agenda-goto-calendar) - -;; Press “e” in columns view to alter “e”ffort “e”stimates. -(require 'org-colview) -(org-defkey org-columns-map "e" - ;; Refresh after making an effort estimate. - (lambda () (interactive) (org-agenda-set-effort) (org-agenda-columns))) - - (setq org-tags-column -77) ;; the default - -;; Press ‘:’ on a heading to add a tag, press TAB to see all tags, press RETURN on a tag to add it, press TAB again to add more tags, when all done press RETURN twice. -(use-package helm-org ) ;; Helm for org headlines and keywords completion. -(add-to-list 'helm-completing-read-handlers-alist - '(org-set-tags-command . helm-org-completing-read-tags)) - -;; Also provides: helm-org-capture-templates - -(setq org-tag-alist - '( - ("Work" . ?w) - ("Personal" . ?p) - ;; Instead of a “:meeting:” tag, I prefer to call it “social credit” (✿◠‿◠) - ("SocialCredit" . ?s) - ;; “Out Of Office” - ("OOO" . ?o) - ("Family" . ?f) - ("Errand" . ?e) - ("Reading" . ?r) - ("BlogRoll" . ?b) - ("Urgent" . ?u))) - - -;; I can't see the entire tags menu when using doom-modeline, so let's redisplay -;; when the tags menu appears. -;; See https://emacs.stackexchange.com/a/70856 -(advice-add #'fit-window-to-buffer :before (lambda (&rest _) (redisplay t))) - - -(use-package org-pretty-tags - - :config - (setq org-pretty-tags-surrogate-strings - '(("Neato" . "💡") - ("Blog" . "✍") - ("Audio" . "♬") - ("Video" . "📺") - ("Book" . "📚") - ("Running" . "🏃") - ("Question" . "❓") - ("Wife" . "💕") - ("Text" . "💬") ; 📨 📧 - ("Friends" . "👪") - ("Self" . "🍂") - ("Finances" . "💰") - ("Car" . "🚗") ; 🚙 🚗 🚘 - ("Urgent" . "🔥"))) ;; 📥 📤 📬 - (org-pretty-tags-global-mode 1)) - -;; Tasks get a 25 minute count down timer -(setq org-timer-default-timer 25) - -;; Use the timer we set when clocking in happens. -(add-hook 'org-clock-in-hook - (lambda () (org-timer-set-timer '(16)))) - -;; unless we clocked-out with less than a minute left, -;; show disappointment message. -(add-hook 'org-clock-out-hook - (lambda () - (unless (s-prefix? "0:00" (org-timer-value-string)) - (message-box "The basic 25 minutes on this difficult task are not up; it's a shame to see you leave.")) - (org-timer-stop))) - -;; Attempting to move a task to a DONE state is blocked if the has a child task that is not marked as DONE -(setq org-enforce-todo-dependencies t) - -;; TODO: Add the line “(declare (indent defun))” right after the docstring of “lf-define”, -;; so that Emacs indents it like a “defun”. -;; See https://www.gnu.org/software/emacs/manual/html_node/elisp/Indenting-Macros.html -;; -;; Until then, use the following incantation: -(lf-define (get 'lf-define 'lisp-indent-function) 'defun) - - -(lf-define my/declare-workflow-states (states) - [:requires (listp states) :ensures (stringp result)] - "Declare STATES as todo-states. STATES is a list of (name on-entry on-exit color) lists." - (setq org-todo-keywords (list (cons 'sequence - (cl-loop for (state . props) in states - for first-letter = (downcase (substring state 0 1)) - for on-entry = (plist-get props :on-entry) - for on-exit = (plist-get props :on-exit) - for entry = (if (not on-entry) "" (if (equal on-entry 'note) "@" "!")) - for exit = (if (not on-exit) "" (if (equal on-exit 'note) "/@" "/!")) - collect (if (equal state "|") state (format "%s(%s%s%s)" state first-letter entry exit)))))) - (setq org-todo-keyword-faces - (cl-loop for (state . props) in states - collect (list state :foreground (plist-get props :foreground) :weight 'bold))) - "✔ Invoke “org-mode-restart” in existing Org buffers for this to take effect.") - - -;; These denote ‘progress’ on a task. -;; For contextual information, one uses “tags”. -;; For example, a delegated task could be in state “STARTED” and tagged “:delegate:James:”. -(my/declare-workflow-states - ;; Transitions: TODO → INVESTIGATED → STARTED ⟷ {AWAITING_REVIEW | PAUSED} → {DONE | CANCELLED} - '( - ;; Tasks that are not started and not planned. They could be the - ;; backlogs or the GTD’s someday/maybe. These tasks could be converted - ;; to NEXT during a weekly review. - ("TODO" :foreground "red") - - ;; A task moves from TODO to NEXT only when I've actually split the task - ;; into small achievable chunks; ie i've done some investigation into - ;; the task and thought about what steps I need to do to actually get - ;; the task done. With this planning in place, I can then ensure I - ;; allocate sufficient timeblocks to work on the subtasks of this - ;; task. (Aside, a “project” is a task with multiple subtasks.) - ;; - ;; - ;; Use my 1/1 time with my manager/peers to review my INVESTIGATED/NEXT - ;; findings for the tickets of the current sprint. I just want to make - ;; sure I'm on the right track, before starting to work on them. Or, if - ;; a ticket is not investigated, do that with my manager. I find that while it - ;; might take me half an hour or more, it'll take like 5 minutes with - ;; him since he's familiar with the code-base. - ;; - ;; - ;; ≈ NEXT. Tasks that are not started but planned to do as soon as I - ;; can. When there is no actionable STARTED (e.g., blocked), I start one - ;; of those and convert it to STARTED. - ("INVESTIGATED" :on-entry timestamp :foreground "dark orange") - - ;; Tasks that are working in progress (“open loops”). I work on these - ;; tasks before starting another NEXT task to avoid too many open loops - ;; at any moment. - ("STARTED" :on-entry timestamp :foreground "blue") ;; When did I start? - - ;; I'm not actively working on this task anymore. I may return to it later. - ("PAUSED" :on-entry note :on-exit timestamp :foreground "magenta") ;; When & why is the task paused? - - ;; When a task goes into WAITING, I've finished the task as much as possible - ;; and now need to rely on someone else; e.g., for feedback. - ;; - ;; I don't want to see these scheduled tasks in my Agenda. - ;; - ;; In the Weekly Review, I will take time to look at my WAITING tasks - ;; and if they've been waiting ~2 weeks, then I should message the relevant people to unblock it. - ;; - ;; “In progress, but blocked by others” - ("WAITING" :on-entry timestamp :foreground "red2") ;; When did this task enter in-review? - - ;; I'm actively working on this task, and not waiting on any one else, - ;; but there is some blocker; e.g., a merge dependency issue or a conflict to resolve. - ;; Sometimes these are quick to dispatch; other times they're blocked by PAUSED/WAITING tasks. - ;; - ;; This is essentially DONE, but there's some blocker. - ("APPROVED" :on-entry timestamp :foreground "magenta") - - ("|") ;; All states after this special marker are “terminal” and so not shown in the org-agenda: (setq org-agenda-skip-scheduled-if-done t) - - ("DONE" :on-entry timestamp :foreground "forest green") ;; When did this task finish? - - ;; This is useful at work to keep track of *why* we have decided against doing a task; in my Org file there may be more, private, reasons not mentioned in the company's Jira file. (For example). - ;; - ;; This is useful at home since I might have had the same task/idea again and it's useful to know *why* I didn't do it last time; also useful for when doing Annual Reviews. - ("CANCELLED" :on-entry note :foreground "saddle brown"))) ;; Why was this task cancelled? (Notes come with a timestamp!) - -;; Since DONE is a terminal state, it has no exit-action. -;; Let's explicitly indicate time should be noted. -(setq org-log-done 'time) -;; → Take a look at org-log-done and org-log-into-drawer. These will tell org to log the date and time when an item's status is changed (you can specify). -;; → When the agenda is built you can show all these logged items on the date they were completed with org-agenda-log-mode, org-agenda-log-mode-items, and org-agenda-start-with-log-mode. -;; → This allows me to place TODO items anywhere I want (my logbook, notes, and a scratch list) and as I complete them through the week they're all shown in the agenda according to when I completed each. -;; → I use org-clock-in to the task I'm working on, then a simple clocktable with some dates will show me exactly what I worked on. -;; → [Weekly Review] which creates a day-by-day summary of the time I worked on what tasks. On Friday, I can look at this and see what I did over the week. - -;; I prefer to log TODO creation also -(setq org-treat-insert-todo-heading-as-state-change t) - -;; When a task goes into the WAITING state, please remove its schedule -;; so that it does not appear in my agenda. (However, it's still not “done” and so appears when I do “C-c a t” for example.) -;; Source: https://emacs.stackexchange.com/a/2760 -(add-hook 'org-after-todo-state-change-hook - (defun rasmus/remove-schedule () - "Remove SCHEDULED-cookie is switching state to WAITING." - (save-excursion - (and (equal (org-get-todo-state) "WAITING") - (org-get-scheduled-time (point)) - (when (search-forward-regexp org-scheduled-time-regexp nil t) - (or (delete-region (match-beginning 0) (match-end 0)) t)) - (get-buffer "*Org Agenda*") - (with-current-buffer "*Org Agenda*" - (org-agenda-redo)))))) - -(setq org-use-fast-todo-selection t) - -;; Install the tool -; (async-shell-command "brew tap adoptopenjdk/openjdk; brew cask install adoptopenjdk13") ;; Dependency -; (async-shell-command "brew install plantuml") - -;; Tell emacs where it is. -;; E.g., (async-shell-command "find / -name plantuml.jar") -(setq org-plantuml-jar-path - "/usr/local/Cellar/plantuml/1.2022.14/libexec/plantuml.jar") - -;; Enable C-c C-c to generate diagrams from plantuml src blocks. -(add-to-list 'org-babel-load-languages '(plantuml . t) ) -(require 'ob-plantuml) - -; Use fundamental mode when editing plantuml blocks with C-c ' -(add-to-list 'org-src-lang-modes '("plantuml" . fundamental)) - -;; Record a note on what was accomplished when clocking out of an item. -(setq org-log-note-clock-out nil) ;; I break tasks down & use C-c C-z, so no need for this anymore. - -(setq confirm-kill-emacs 'yes-or-no-p) - -;; Resume clocking task when emacs is restarted -(org-clock-persistence-insinuate) - -;; Show lot of clocking history -(setq org-clock-history-length 23) - -;; Resume clocking task on clock-in if the clock is open -(setq org-clock-in-resume t) - -;; Sometimes I change tasks I'm clocking quickly ---this removes clocked tasks with 0:00 duration -(setq org-clock-out-remove-zero-time-clocks t) - -;; Clock out when moving task to a done state -(setq org-clock-out-when-done t) - -;; Save the running clock and all clock history when exiting Emacs, load it on startup -(setq org-clock-persist t) - -;; Do not prompt to resume an active clock -(setq org-clock-persist-query-resume nil) - -;; Include current clocking task in clock reports -(setq org-clock-report-include-clocking-task t) - - (push '("Effort_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00") - org-global-properties) - -(setq org-clock-sound "~/.emacs.d/school-bell.wav") - -(require 'org-habit) ;; To actually see the consistency graph in org-agenda - -;; Show habits for every day in the agenda. -(setq org-habit-show-habits t) -(setq org-habit-show-habits-only-for-today nil) - -;; This shows the ‘Seinfeld consistency’ graph closer to the habit heading. -(setq org-habit-graph-column 90) - -;; In order to see the habit graphs, which I've placed rightwards, let's -;; always open org-agenda in ‘full screen’. -;; (setq org-agenda-window-setup 'only-window) - -(setq org-habit-completed-glyph ?😊) -(setq org-habit-today-glyph 33) - -;; When showing the agenda, do not collect habits together at the bottom, as is the default. -(add-to-list 'org-agenda-sorting-strategy '(agenda time-up priority-down category-keep)) - -(defun jump-to-org-agenda () - (interactive) - (let ((buf (get-buffer "*Org Agenda*")) - wind) - (if buf - (if (setq wind (get-buffer-window buf)) - (select-window wind) - (if (called-interactively-p) - (progn - (select-window (display-buffer buf t t)) - (org-fit-window-to-buffer) - ;; (org-agenda-redo) - ) - (with-selected-window (display-buffer buf) - (org-fit-window-to-buffer) - ;; (org-agenda-redo) - ))) - (call-interactively 'org-agenda-list))) - ;;(let ((buf (get-buffer "*Calendar*"))) - ;; (unless (get-buffer-window buf) - ;; (org-agenda-goto-calendar))) - ) - -(run-with-idle-timer 300 t 'jump-to-org-agenda) - -;; Obtain a notifications and text-to-speech utilities -(system-packages-ensure "say") ;; Built-into MacOS, but can be downloaded in Ubuntu -(system-packages-ensure "terminal-notifier") ;; MacOS specific -;; System Preferences → Notifications → Terminal Notifier → Allow “alerts”. -;; E.g.,: (shell-command "terminal-notifier -title \"Hiya\" -message \"hello\"") -;; Ensure you're not in “Mac OS Focus” mode: https://cleanmymac.com/blog/notifications-not-showing-mac - -(cl-defun my/notify (message &key (titled "") at repeat-every-hour open) - "Notify user with both an visual banner, with a beep sound, and a text-to-speech recitation. - -When the user clicks on the resulting notification, unless a -given OPEN url is provided, the Emacs application is brough into -focus. - -MESSAGE and TITLE are strings; AT is a time string as expected of -`run-at-time' such as \"11.23pm\" or \"5 sec\"; REPEAT-EVERY-HOUR -is a floating-point number of hours to continuously repeat the -alert. OPEN is a URL that is opened when the user clicks the -notification. This can be a web or file URL, or any custom URL -scheme. - -I initially used optional arguments, but realised that in due time -it would be more informative to use named arguments instead. - -Example uses: - -;; In 5 minutes from now, remind me to watch this neato video! -(my/notify \"🔔 Get things done! 📎 💻 \" - :open \"https://www.youtube.com/watch?v=23tusPiiNZk&ab_channel=Motiversity\" - :at \"5 minutes\") - ;; :at \"5 sec\" - -;; Remind me to exercise every 1.5hours; starting at 8:00am. -(my/notify \"Take a 5min break and get your blood flowing!\" - :titled \"Exercise\" - :at \"8:00am\" - :repeat-every-hour 1.5) - -;; Actually getting things done! -(my/notify \"Is what you're doing actually in alignment with your goals? - Maybe it's time to do another task?\" - :titled \"Check your agenda!\" - :at \"10:00am\" - :repeat-every-hour 2) - -" - (run-at-time at ;; the time to make the alert - (when repeat-every-hour (* 60 60 repeat-every-hour)) - #'async-shell-command - (format "%s" (s-replace "\n" "" - (s-join " " (--map (format "%s" it) - `(terminal-notifier - -title ,(pp-to-string titled) - -message ,(s-replace "\\n" "\n" (pp-to-string message)) - ;; Play a random sound when the notification appears. See sound names with: ls /System/Library/Sounds - ;; Use the special NAME “default” for the default notification sound. - -sound ,(progn (require 'seq) (seq-random-elt (s-split "\n" (shell-command-to-string "ls /System/Library/Sounds")))) - ;; Don't create duplicates of the notification, just one instance; - ;; i.e., each notification belongs to a group and only one alert of the group may be present at any one time. - -group ,(pp-to-string titled) - ;; Activate the application specified by ID when the user clicks the notification. - -activate org.gnu.Emacs - ,@(when open `(-open ,(pp-to-string open))) - ;; Run the shell command COMMAND when the user clicks the notification. - ;; -execute COMMAND - & ;; … and then speak! … - ;; NOTE:This was getting annyoning in the middle of work meetings. - say ,(s-replace "\\n" " " (pp-to-string message)) - ))))))) - -;; (Emojis look terrible in Lisp; but much better when the alert is actually made!) - -;; Remind me to exercise every 1.5hours; starting at 8:00am. -(my/notify "Take a 5min break and get your blood flowing!\n\t\t🚣 🏃‍♂️ 🧗‍♂️ 🧘‍♂️ 🏊 🏋 🚴‍♂️" - :titled "🤾‍♀️ Exercise 🚵‍♂️" - :at "8:00am" - :repeat-every-hour 1.5 - :open "https://www.youtube.com/watch?v=23tusPiiNZk&ab_channel=Motiversity") - -;; Actually getting things done! -(my/notify "Is what you're doing actually in alignment with your goals? ✔️📉 - Maybe it's time to do another task? 📋" - :titled "📆 Check your agenda! 🔔" - :at "10:00am" - :repeat-every-hour 2) - -;; Provides notifications for scheduled or deadlined agenda entries. -(use-package org-alert - :config - (setq org-alert-interval 300 - org-alert-notify-cutoff 10 - org-alert-notify-after-event-cutoff 10) - (org-alert-enable)) - -(use-package alert - :config (setq alert-default-style 'osx-notifier)) - -(alert "HELLO") - -(my/notify "🔔 Get things done! 📎 💻 " - :open "https://www.youtube.com/watch?v=23tusPiiNZk&ab_channel=Motiversity" - :at "1 sec") - -;; Make every other line of a buffer grey (or whatever you like). -;; Useful for buffers that list things. -;; I want it to make my Org tables look nice. Even better when org-modern is activated. -(use-package stripe-buffer - :defer 100 - :config (add-hook 'org-mode-hook 'turn-on-stripe-table-mode)) - -(setq org-agenda-files (list "~/Documents/notes.org")) - -(setq org-agenda-span 'week) - -;; (setq org-agenda-custom-commands '(("o" "Open Loops" tags-tree "TODO=\"STARTED\"" ))) - -(setq org-log-into-drawer t) ;; hide the log state change history a bit better - - -;; Quick key to go to the currently clocked-in entry, or to the most recently clocked one. -;; With prefix arg, offer recently clocked tasks for selection. -(bind-key* "C-c SPC" - (lambda (&optional prefix) - (interactive) - (org-clock-goto prefix) - (org-narrow-to-subtree))) - - -(setq org-fold-catch-invisible-edits 'show-and-error ;; Avoid accidental edits to folded sections - org-special-ctrl-a/e t ;; C-a/C-e know about leading “*” and ending :tags: - ;; Agenda styling - org-agenda-tags-column -80 - org-agenda-time-grid '((daily today require-timed) - (800 1000 1200 1400 1600 1800 2000) - " ───── " "───────────────") - org-agenda-current-time-string "◀── now ─────────────────────────────────────────────────") - -;; p to “p”ush back a task to the next day. -(add-hook 'org-agenda-mode-hook - ;; Note: There's also org-agenda-date-earlier to change the date by -1 day. - (lambda () - (define-key org-agenda-mode-map "p" 'org-agenda-date-later) - - ;; Reschedule agenda items to today, “right 𝓃ow”, with a single command - (define-key org-agenda-mode-map "n" (defun org-agenda-reschedule-to-today () - (interactive) - (flet ((org-read-date (&rest rest) (current-time))) - (call-interactively 'org-agenda-schedule)))))) - -;; Relevant function is “C-c C-z”. -;; -;; In Org-Agenda, “l” to see top-level clocked in/out logs. -;; On a given item, press “L” to see its note logs. -;; -;; Or, just “v L” to see all logged notes in the agenda view. -;; -(setq org-log-note-headings '((done . "CLOSING NOTE %t") - (state . "State %-12s from %-12S %t") - (note . "%t") - ;; (reschedule . "Rescheduled from %S on %t") ;; Default - (reschedule . "Schedule changed on %t: %S -> %s") - (delschedule . "Not scheduled, was %S on %t") - (redeadline . "Deadline changed on %t: %S -> %s") - ;; (redeadline . "New deadline from %S on %t") ;; Default - (deldeadline . "Removed deadline, was %S on %t") - (refile . "Refiled on %t") - (clock-out . ""))) - - -;; Remove the “\\\n” added to the end of notes. -(advice-add 'org-store-log-note :after - (cl-defun remove-\\ (&rest _) (org-narrow-to-subtree) (replace-in-buffer "\\\\\\\\\n" "") (widen))) - -;; Start each agenda item with ‘○’, then show me it's %timestamp and how many -;; times it's been re-%scheduled. -(setq org-agenda-prefix-format " ○ %?-12t%-6e%s ") - -;; (setq org-agenda-deadline-leaders '("DUE: " "In %3d d.: " "%2d d. ago: ")) - -;; Don't say “Scheduled ⟨Task⟩”, just show “⟨Task⟩”. -;; If something's overdue, say “Overdue 𝓃× ⟨Task⟩”. -(setq org-agenda-scheduled-leaders '("" "Overdue%2dx ")) - -;; list items will be treated like low-level headlines; i.e., folded by default. -(setq org-cycle-include-plain-lists 'integrate) - -;; clear checkbox when repeating a todo task -(add-hook 'org-todo-repeat-hook #'org-reset-checkbox-state-subtree) - -;; clear sub-sub-tasks when repeating a todo task. -;; ⇒ If I have “** A [%] \n #+STYLE: habit \n SCHEDULED: <2024-04-19 Fri .+1d> \n *** DONE B” -;; then on “** A” I press ‘t’ then mark it as ‘DONE’, then the “*** B” task resets to ‘TODO’. -;; -;; In particular, sometimes I have reference/posterity info “*** something to remember” which need not be marked TODO/DONE, -;; since it has no todo state, it is not impacted by this hook. Notable example includes “** Review feedback :drill: \n *** Fact 1 \n *** Fact 2” -;; using: M-x org-drill-tree. -(add-hook 'org-todo-repeat-hook - (lambda () (org-map-entries (lambda () (when (and (> (length (org-get-outline-path)) 1) (equal (org-get-todo-state) "DONE")) (org-todo "TODO"))) t 'tree))) - - -;; If current day is Sat/Sun, then schedule to the next upcoming monday (but retain time hours). -;; TODO: Maybe only do this if an org entry has a property, say, “ :ONLY_WEEKDAYS: t ” -(add-hook 'org-todo-repeat-hook - (lambda () (org-map-entries - (lambda () - (let* ((scheduled (date-to-time (org-entry-get (point) "SCHEDULED"))) - (day (format-time-string "%a" scheduled))) - (when (member day '("Sat" "Sun")) - (org-schedule nil (format-time-string "+1mon %T" scheduled)) - (message "Musa says this is a weekend-only habit (◕‿◕)")))) - t - 'tree))) - - -;; Run hooks “ON_[STARTED∣DONE]” state changes. -;; (MA: Consider adding “ON_𝒳” for all states 𝒳, using above workflow loop.) -;; (MA: Consider turning the example /below/ into a single property hook, say “:TEMPORARILY_TREAT_SUBTREES_AS_CHECKBOXES: t”) -;; -;; For example, in the following, when we press “t s” to put “A” into “STARTED A” the declared code is run: -;; It essentially treats all children trees, temporarily, as checkboxes: Pressing “t” toggles between “ ∣ TODO ∣ DONE” -;; and does not log any info about state change of the subtrees. (Also, the “STARTED A” is becomes “A”). -;; Then when we press “t” on “A” we get “DONE A”, which invokes the associated ON_DONE code, which just resets things to before -;; we began working on task “A”. -;; -;; ** A -;; :PROPERTIES: -;; :ON_STARTUP: (progn (if (search-forward-regexp org-todo-regexp nil t) (or (delete-region (match-beginning 0) (match-end 0)) t)) (setq remember/org-todo-keywords org-todo-keywords) (setq org-todo-keywords '("TODO" "DONE")) (setq remember/org-log-done org-log-done) (setq org-log-done nil) (org-mode-restart)) -;; :ON_DONE: (progn (setq org-todo-keywords remember/org-todo-keywords org-log-done remember/org-log-done) (org-mode-restart)) -;; :END: -;; -;; *** TODO B -;; -(add-hook 'org-after-todo-state-change-hook - (defun my/special-ON_STARTED-property-hook () - "When a task enters STARTED/DONE state, execute the code in its ON_STARTED/ON_DONE property." - (save-excursion - ;; yet another property support - (when (equal (org-get-todo-state) "TODO") - ;; Instead of ignore-errors, it should only evaluate the string /if/ it is present. - (ignore-errors (eval (car (read-from-string (eval (org-entry-get (point) "ON_TODO"))))))) - - ;; yet another property support - (when (equal (org-get-todo-state) "STARTED") - ;; Instead of ignore-errors, it should only evaluate the string /if/ it is present. - (ignore-errors (eval (car (read-from-string (eval (org-entry-get (point) "ON_STARTED"))))))) - - ;; yet another property support - (when (equal (org-get-todo-state) "DONE") - ;; Instead of ignore-errors, it should only evaluate the string /if/ it is present. - (ignore-errors (eval (car (read-from-string (eval (org-entry-get (point) "ON_DONE"))))))) - - ;; yet another property support -- AXE? - (when (equal "t" (org-entry-get (point) "TEMPORARILY_TREAT_SUBTREES_AS_CHECKBOXES")) - (when (equal (org-get-todo-state) "TODO") - (let ((current-prefix-arg :random-theme)) (my/toggle-theme)) - (org-narrow-to-subtree) - (beginning-of-buffer) - (setq remember/org-todo-keywords org-todo-keywords - org-todo-keywords '("TODO" "DONE") - remember/org-log-done org-log-done - org-log-done nil - remember/org-log-note-headings org-log-note-headings - org-log-note-headings nil) - (org-mode-restart)) - (when (or (equal (org-get-todo-state) "DONE") (equal (org-get-todo-state) "")) - (setq org-todo-keywords remember/org-todo-keywords - org-log-done remember/org-log-done - org-log-note-headings remember/org-log-note-headings) - (org-mode-restart)))))) - -;; “C-c a t” ⇒ List all (non-recurring non-someday) todos sorted by state, priority, effort -;; “C-c a a” ⇒ Daily agenda view, followed by unscheduled open loops -;; -;; Query Language :: https://orgmode.org/manual/Matching-tags-and-properties.html -;; For general-purpose SQL-like queries against all Org entries, consider using org-ql: https://github.com/alphapapa/org-ql -;; For example, to find all entries that have any timestamp in a given period. -;; Another example: Suppose you know that there is a “src” block you're looking for in your notes, but -;; you're not sure which entry it is in, you can use org-ql to find all entries that contain a “src” block. -;; Moreover, you can refine the query by considering only a specific time window, if the entry has any timestamp at all. - -;; You can even use org-ql in org-agenda-custom-commands! See https://github.com/alphapapa/org-ql/blob/master/examples.org#stuck-projects-block-agenda -;; or, even, better: https://www.reddit.com/r/emacs/comments/cnrt2d/comment/ewtqez8/ -;; That is, you can write SQL-like queries for your agenda, if you prefer. -;; Moreover, one could use org-ql-agenda as an alternative implementation of org-agenda, -;; but their are pros/cons to both, neither is strictly better: org-ql has better queries, org-agenda has different features (such as weekly view). ⟵ This might not be true anymore. -;; MA: I may switch to org-ql since org-ql-block is about 80% faster than org-agenda! -;; MA: Actually, no thanks: I dislike that my agenda is broken down my projects, I like the usual timebased grid ordering of org-agenda. -;; ⇒ This is the only blocker, if I can fix it, then I'd be happy to use org-ql / org-super-agenda. -;; ⇒ Note: Any use of org-ql in org-agenda-custom-commands actually recreates the agenda buffer from scratch: It's not what you get by calling classic org-agenda! -;; See: https://www.reddit.com/r/emacs/comments/cnrt2d/comment/ewhf0zj/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button -;; i.e., see org-super-agenda -(setq org-agenda-custom-commands - '(("t" "My list of all TODO entries" tags-todo "-recurring-someday+LEVEL=2" - ((org-agenda-overriding-header "\nTODOs sorted by state, priority, effort") - (org-agenda-sorting-strategy '(todo-state-down priority-down effort-up)) - (org-super-agenda-groups (progn (org-super-agenda-mode t) '( - (:name "Important" :and (:priority "A" :not (:todo ("DONE" "CANCELED")))) - (:name "Process your Inbox" :tag "inbox") - (:name "Approved" :todo "APPROVED") - (:name "Started" :todo "STARTED") - (:name "Waiting" :todo "WAITING") - (:name "Low Priority" :priority "C" :tag "maybe")))))) - ("w" "WAITING Tasks" - ((tags "todo=\"WAITING\"+LEVEL=2"))) - ;; To see EVERYTHING I've done, just press “C-c a a v w l” and it will activate logbook mode. - ;; - ;; This is a helpful view: - ;; As the week moves along, I know what I have left to do - ;; and can choose to /not/ do low-priority tasks, or to - ;; act as a motivator for me to work faster or focus better, etc. - ("a" "Daily Agenda; Productivity ≈ ♯DONE / ♯TASKS" - (;; TODO: MAYBE MOVE DOWN: (tags-todo "inbox" ((org-agenda-prefix-format " %?-12t% s") (org-agenda-overriding-header "\nProcess your Inbox\n"))) - (agenda "" ((org-agenda-span 'day) (org-agenda-overriding-header (progn (org-super-agenda-mode -1) "Please focus on 𝒪𝓃𝓁𝓎 these tasks for the day!")))) - ;; Show me deadline items grouped together - (agenda nil - ((org-agenda-entry-types '(:deadline)) - (org-agenda-format-date "") - (org-deadline-warning-days 7) - (org-agenda-show-all-dates nil) ;; Only show if there are actually entries - (org-agenda-skip-function - '(org-agenda-skip-entry-if 'notregexp "\\* NEXT")) - (org-agenda-overriding-header "\nDeadlines"))) - ;; What I've left to do is all incomplete tasks scheduled within the next 5-𝓃 days, where 𝓃 is the numeral of the current week day. - ;; ;; Mon=1, ⋯, Thu=4, ⋯ - (tags (with-today - ;; Add 1 to include tasks scheduled for today. - (format "-recurring-TODO=\"DONE\"+SCHEDULED>=\"<-%sd>\"+SCHEDULED<=\"<+%sd>\"" (1+ it) it)) - ((org-agenda-overriding-header "What I have left to do this week"))) - ;; Press E to toggle seeing ~5 lines of each entry; might be helpful for rescheduling or doing a task sooner. - ;; https://emacs.stackexchange.com/questions/41468/show-notes-in-org-mode-agenda - ;; - ;; What I've done so far is all tasks closed in the past 𝓃-days, where 𝓃 is the numeral of the current week day. - ;; ;; Mon=1, ⋯, Thu=4, ⋯ - (tags (with-today (format - ;; NOTE: AND “&” bindings tigher than OR “|”. - ;; TODO [LOW PRIORITY]: The second clause, on WAITING, should reference this week. E.g., state entered this week. - "-recurring&LEVEL=2&TODO=\"DONE\"&CLOSED>=\"<-%sd>\"|-recurring&LEVEL=2&TODO=\"WAITING\"" it)) - ((org-agenda-overriding-header "What I've done so far this week"))) - ;; Section on what I “Completed Today”. Not useful now in my life since I do 1 or do large non-recuring tasks per day. - ;; (tags "CLOSED>=\"\"" ((org-agenda-overriding-header "\nCompleted today\n"))) - (tags "-Someday+todo=\"STARTED\"" - ((org-agenda-overriding-header "Please 𝒓𝒆𝒅𝒖𝒄𝒆 the number of (unscheduled) open loops") - (org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled)))) - )))) - -(defmacro with-today (&rest body) - "Evaluate BODY which may mention `it' to refer to the numeral denoting today" - `(-let [it (calendar-day-of-week (calendar-current-date))] ,@body)) - -(with-today it) - -(setq org-agenda-span 'day) - -(defun replace-in-buffer (regexp replacement) - "Perform a regexp replace in the entire buffer." - (save-excursion - (goto-char (point-min)) - (while (re-search-forward regexp nil t) - (replace-match replacement)))) - -;; Press “?” on a leading headline star to see other speed commands. -;; -;; Press “d” to mark a task as DONE without logging any meta-data -(add-to-list 'org-speed-commands (cons "d" - (cl-defun my/mark-as-DONE-without-logging-meta-data () - (org-narrow-to-subtree) - (replace-in-buffer (concat "\\(^\\*+ \\)" org-todo-regexp "?") "\\1DONE") (widen) - (message "Nicely 𝑑𝑜𝑛𝑒!")))) - - (cl-defmacro my/work-links (type url &optional (export-display '(format "%s-%s" type label))) - "Given a link of TYPE with a URL, produce the correct org-link. - - EXPORT-DISPLAY is string-valued term that may mention the symbolic names ‘type’ and ‘label’. - This is how the link looks upon export." - `(org-link-set-parameters - ,type - :follow (lambda (label) (browse-url (format ,url label))) - :export (lambda (label description backend) - (-let [full-url (format ,url label)] - (pcase backend - ('html (format "%s" full-url (-let [type ,type] ,export-display))) - ('latex (format "\\href{%s}{%s}" full-url label)) - (_ full-url)))) - :face '(:foreground "green" :weight bold - :underline "blue" :overline "blue"))) - -(defvar COMPANY (exec-path-from-shell-copy-env "COMPANY") - "Name of place I work at. - - It's setup in ~/.zshrc") -;; Note, “getenv” requires an Emacs restart if the shell vars changed /after/ starting Emacs. - -(my/work-links "FWD" (lf-string "https://bugs.local.${(downcase COMPANY)}.com/browse/FWD-%s")) -(my/work-links "OUT" (lf-string "https://bugs.local.${(downcase COMPANY)}.com/browse/OUT-%s")) -(my/work-links "gerrit" (lf-string "https://gerrit.local.${(downcase COMPANY)}.com/c/fwd/+/%s")) - -;; Open all such links in Chrome -(setq browse-url-browser-function 'browse-url-default-macosx-browser) - -;; Location of my todos / captured notes file -(setq org-default-notes-file "~/Documents/notes.org") - -(defmacro def-capture (name location template) -"Creates a method “my/capture-NAME”, which opens a capture buffer named NAME showing TEMPLATE. -When you press `C-c C-c`, the note is saved as an entry (ie TEMPLATE should start with “* ”.) -in `org-default-notes-file' section named LOCATION. - -+ NAME, LOCATION, TEMPLATE are all strings that may contain spaces. - ⇒ If you want to evaluate a function in TEMPLATE, use the syntax “%(f args)”. - See https://stackoverflow.com/a/69331239 for an example. -+ Example: (def-capture \"Friends Info\" \"Journal\" \"* %t\") - This can be used as “M-x my/capture-friends-info” or via an Org link: “[[elisp:( my/capture-friends-info)]]”. - - Note: My “Journal” is nested in a section called “Workflow”, and capture finds it anyways (。◕‿◕。) - (More precisely, Org-Capture looks for the first (sub)headline called “Journal” /anywhere/ and uses that as the target location.) - -Usage: -1. M-x my/capture-NAME ⇒ Capture something to my LOCATION; no menu used. -2. C-u M-x my/capture-NAME ⇒ Jump to my LOCATION. -3. C-u C-u M-x my/capture-NAME ⇒ Goto last note stored (by any my/capture-* method). -" - `(defun ,(intern (concat "my/capture-" (s-replace-regexp " " "-" (downcase name)))) (&optional prefix) - (interactive "p") - (-let [org-capture-templates - ;; I'm using omega 𝓌 as a placeholder; i.e., a gensym-like key. - `(("𝓌" ,,name entry (file+headline ,,org-default-notes-file ,,location) ,,template :clock-in t :clock-keep t))] - (org-capture (list prefix) "𝓌") - (unless (> prefix 1) (rename-buffer ,name))))) - -;; I mark inbox captures as “TODO” so that they appear in my task list (C-c a t) in the event -;; I've forgotten to process my inbox. -;; -;; When I process my “* Inbox” section, I am left with an empty Org section and so delete it. -;; ⇒ “C-c c” will create the section if it does not exist. -;; ⇒ Deleting it is a nice ‘cheery on top’ when processing my inbox (✿◠‿◠) -;; -;; The process of adding a task is very fast and non-disruptive to my work. The -;; capture template includes the date added. This is useful when reviewing tasks -;; to see how long the task has been on the list and if I have been -;; procrastinating. -(bind-key* "C-c c" (def-capture "Inbox Entry" "Inbox" "* TODO %?\n Captured: %U \n")) - -(defalias #'my/new-journal-entry (def-capture "Journal Entry" "Journal" - (s-join "\n\n" (list - (format-time-string "* %Y-%m-%d %a %R :mood_𝒏%?:") - "My most important goal for the day is: " - (let (todays-agenda) (org-agenda-list 1) (setq todays-agenda (buffer-string)) (org-agenda-quit) - (concat "Here's what my day looks like so far:\n" todays-agenda)))))) - -(def-capture "Daily Retrospective" "Journal" - (concat - ;; The “:mood_𝓃:” tag is so that I can easily see my moods across my entries. - ;; Keeping track of mood is a simple way to monitor success; e.g., whether GTD is working for me or not. - (format-time-string "* %Y-%m-%d %a %R :mood_%^{Mood at the end of the day?}:retro:daily:\n") -" -Instructions: Read section contents and replace them with your own words.%? - -** Monitoring Mood For Success - - Why do I feel the way I do? - - 1 ≈ 😢 extremely negative; 5 ≈ :neutral_face: neutral; 10 ≈ 😁 extremely positive. - -** Celebrating Successes - - Acknowledge and celebrate your achievements, no matter how small. - - Recognising your progress boosts morale and motivation, inspiring you to continue striving for success. - - /Give yourself credit for your efforts!/ - -** Goal Alignment - - Were today's actions directed at achieving the sprint's goals? Stay focused! - - Review your day by reviewing the tasks you clocked into. - - %(let ((org-clock-clocktable-default-properties (-snoc org-clock-clocktable-default-properties :block 'today :timestamp 'nil))) (beginning-of-line) (kill-line) (org-clock-report)) - - - Set SMART goals for tomorrow. - -** Stress Reduction - - Any challenges or frustrations encountered today? - -** Continuous Improvement - - What went well, what didn't go as planned, and were there any unexpected challenges today? - - Learn from your experiences & brainstorm strategies better outcomes in the future. - - Consider what factors contributed to these challenges and how you responded to them. - - What thought patterns were influencing my outcomes? - -** Express Gratitude - - Conclude your retrospective by expressing gratitude for the positive aspects of your day. - - Reflect on the people, opportunities, and experiences that brought you joy or fulfilment. -")) - -;; This only works well if my tasks have timestamps; ie are scheduled ^_^ -(setq org-clock-clocktable-default-properties - '(:scope ("~/Documents/notes.org") ;; Consider the current file - :hidefiles t ;; Hide the file column when multiple files are used to produced the table. - :maxlevel 5 ;; Consider sub-sub-sections - :block lastweek ;; Only show me what I did last week - ;; Other values: 2024-04, lastmonth, yesterday, thisyear, 2024 - ;; :tstart "<-2w>" :tend "" ;; Show me the past two weeks - ;; :tstart "<2006-08-10 Thu 10:00>" :tend "<2006-08-10 Thu 12:00>" ;; Show me a particular range - :step day ;; Split the report into daily chunks - :formula % ;; Show me the percentage of time a task took relative to my day - :link t ;; Link the item headlines in the table to their origins - :narrow 55! ;; Limit the width of the headline column in the Org table - :tcolumns 1 ;; Show only 1 column ---not multiple, for the sections and subsections and etc. - :timestamp t ;; Show the timestamp, if any - :tags t ;; Do not show task tags in a column; I use mostly hierarchies for my tasks right now. - ;; :match "billable|notes-travel" ;; ⇒ Includes tags “billable” and “notes”, excludes tag “travel” - ;; More examples at: https://orgmode.org/manual/Matching-tags-and-properties.html#Matching-tags-and-properties - ;; For example, we can match tags & priority & todo states & property drawer values; “/DONE” matches all tasks with state being ‘DONE’. - :match "-OOO" ;; Exclude tasks tagged “OOO”, which means “Out of Office” ---e.g., taking a break, or praying, or out for an appointment. - ;; :formatter org-clocktable-write-default ;; This is the default way to print a table; it looks very long and annoying to change. - ;; :sort (3 . ?N) ;; Sort descendingly on time. Not ideal, since I'm very hierarchical. - )) -;; More properties at: https://orgmode.org/manual/The-clock-table.html -;; [Low Priority] Figure out whether I've underworked or overworked? ⇒ https://www.erichgrunewald.com/posts/how-i-track-my-hour-balance-with-a-custom-org-mode-clock-table/ - -;; I prefer “27h” over “1d 3h”. -(setq org-duration-format 'h:mm) - - - -;; In Org-agenda, press “v r” to view the clock report -;; (This method is invoked when you hit “v r” in Org-agenda.) -(defalias 'org-agenda-clockreport-mode 'my/what-did-i-work-on-this-week) - -(defun my/what-did-i-work-on-this-week () - (interactive) - (my/what-did-i-work-on - "*What Did I Work On This Week?*" - org-clock-clocktable-default-properties)) - -(defun my/what-did-i-work-on-today () - (interactive) - (my/what-did-i-work-on - "*What Did I Work on Today?*" - (-snoc org-clock-clocktable-default-properties :block 'today))) - -(defun my/what-did-i-work-on (buffer-title clocktable-properties) - (switch-to-buffer buffer-title) - (org-mode) - ;; (org-modern-mode) Tables don't look good with the unicode/timestamp svg - (-let [org-clock-clocktable-default-properties clocktable-properties] - (org-clock-report)) - ;; For some reason, some of org-modern carries from the current buffer to the new buffer. - (org-modern-mode +1) - (org-modern-mode -1) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward "\\\\_" nil t) - (replace-match "⇒") - (org-table-align)))) - -(defun my/see-sorted-todos () - "See TODOs sorted by state, priority, then effort. - -This view shows me all tasks, sorted, and from there I can pick & schedule & edit as desired. - -Much nicer than me physically sorting tasks! - -The main benefit here is I can keep /active/ tasks under their -own disjoint ‘projects’, yet still have a nice unified view of -all of my /active/ *and* non-active tasks. - -⇒ You can mark DONE and archive from the sorted view. -⇒ But leave that to the Weekly Review, so that you can extract any - reference information or Lessons Learned out of the tasks to be archived. - -See: https://emacs.stackexchange.com/questions/9585/org-how-to-sort-headings-by-todo-and-then-by-priority -" - (interactive) - (let ((org-agenda-custom-commands '(("𝓌" nil todo "*" - ((org-agenda-overriding-header "\nTODOs sorted by state, priority, effort") - (org-agenda-sorting-strategy '(todo-state-down priority-down effort-up))))))) - (org-agenda nil "𝓌" t) - (beginning-of-buffer))) - ;; [[file:init.org::*highlight quoted symbols][highlight quoted symbols:1]] (use-package highlight-quoted :defer nil diff --git a/init.org b/init.org index 58db3df..cf07ac0 100644 --- a/init.org +++ b/init.org @@ -5843,2690 +5843,6 @@ Example: [[https://miro.medium.com/v2/resize:fit:4800/1*bpG6TxN-nS6enHkp-KIZgg.jpeg][1% better everyday, push-ups!]] -* TODO Life within Org-mode :Posterity: -:PROPERTIES: -:CUSTOM_ID: Life-within-Org-mode -:header-args: :tangle yes -:END: - -It's hard to estimate how long a task takes if you don't keep track of time -spent by ‘clocking-in and clocking-out’ of tasks. We can ‘capture’ todos right -in the middle of a task /without/ context-switching; e.g., no opening a todos -file! After some reflection on the relative importance of the tasks, we can -schedule them into our ‘agenda’. - - Let's do this! - -** Using Org-Mode as a Day Planner -:PROPERTIES: -:CUSTOM_ID: Using-Org-Mode-as-a-Day-Planner -:END: - - ⟪ This section is based on a dated, yet delightful, tutorial - of the same title by [[http://newartisans.com/2007/08/using-org-mode-as-a-day-planner/][John Wiegley]]. ⟫ - -We want a day-planner with the following use: -0. “Mindlessly” & rapidly create new tasks. -1. Schedule and archive tasks at the end, or start, of the work day. -2. Glance at a week's tasks, shuffle if need be. -3. Prioritise the day's tasks. Aim for ≤15 tasks. -4. Progress towards completion of ~A~ tasks by documenting work completed. -5. Repeat! During the day, if anything comes up, capture it and intentionally - forget about it. - -#+begin_box :background-color orange -#+begin_center -badge:Workflow|CheatSheet|informational|https://alhassy.github.io/emacs.d/Workflow.pdf - -A 1-page, 3-column, PDF summarising the ideas and keybindings of this section -~(งಠ_ಠ)ง~ -#+end_center -#+end_box - -*** Capturing ideas & notes without interrupting the current workflow :Disabled: -:PROPERTIES: -:CUSTOM_ID: Capturing-ideas-notes-without-interrupting-the-current-workflow -:header-args: :tangle no -:END: - -[[https://orgmode.org/org.html#Setting-up-capture][Capture]] lets me quickly make notes & capture ideas, with associated reference -material, without any interruption to the current work flow. Without losing -focus on what you're doing, quickly jot down a note of something important that -just came up. - -#+begin_details ‘my/org-capture’ Implementation -#+begin_src emacs-lisp -(cl-defun my/org-capture-buffer (&optional keys no-additional-remarks - (heading-regexp "Subject: \\(.*\\)")) - "Capture the current [narrowed] buffer as a todo/note. - -This is mostly intended for capturing mail as todo tasks ^_^ - -When NO-ADDITIONAL-REMARKS is provided, and a heading is found, -then make and store the note without showing a pop-up. -This is useful for when we capture self-contained mail. - -The HEADING-REGEXP must have a regexp parenthesis construction -which is used to obtain a suitable heading for the resulting todo/note." - (interactive "P") - (let* ((current-content (substring-no-properties (buffer-string))) - (heading (progn (string-match heading-regexp current-content) - (or (match-string 1 current-content) "")))) - (org-capture keys) - (insert heading "\n\n\n\n" (s-repeat 80 "-") "\n\n\n" current-content) - - ;; The overtly verbose conditions are for the sake of clarity. - ;; Moreover, even though the final could have “t”, being explicit - ;; communicates exactly the necessary conditions. - ;; Being so verbose leads to mutual exclusive clauses, whence order is irrelevant. - (cond - ((s-blank? heading) - (beginning-of-buffer) (end-of-line)) - ((and no-additional-remarks (not (s-blank? heading))) - (org-capture-finalize)) - ((not (or no-additional-remarks (s-blank? heading))) - (beginning-of-buffer) (forward-line 2) (indent-for-tab-command))))) -#+end_src -With that in-hand, we use a wrapper to ~org-capture~ to make use of it. -#+begin_src emacs-lisp -(defun my/org-capture (&optional prefix keys) - "Capture something! - - C-c c ⇒ Capture something -C-u C-c c ⇒ Capture current [narrowed] buffer. -C-u 5 C-c c ⇒ Capture current [narrowed] buffer without adding additional remarks. -C-u C-u C-c c ⇒ Goto last note stored. - -At work, ‘C-c c’ just captures notes under ‘Tasks’; no menu used." - (interactive "p") - (pcase prefix - (4 (my/org-capture-buffer keys)) - (5 (my/org-capture-buffer keys :no-additional-remarks)) - (t (if my/personal-machine? - (org-capture prefix keys) - (org-capture prefix "t"))))) -#+end_src -#+end_details - -#+begin_src emacs-lisp :results raw replace :exports results :wrap box -(s-join "\n" (--map (concat "+ [[kbd:" (s-replace "⇒" "]]" it)) (cddr (s-split "\n" (documentation #'my/org-capture))))) -#+end_src - -#+RESULTS: -#+begin_box -+ [[kbd: C-c c ]] Capture something -+ [[kbd:C-u C-c c ]] Capture current [narrowed] buffer. -+ [[kbd:C-u 5 C-c c ]] Capture current [narrowed] buffer without adding additional remarks. -+ [[kbd:C-u C-u C-c c ]] Goto last note stored. -#+end_box - -E.g., I have a task, or something I wish to note down, rather than opening some -file, then making a heading, then writing it; instead, I press kbd:C-c_c_t and a -pop-up appears, I make my note, and it disappears ---with my notes file(s) now -being altered! Moreover, by default it provides a timestamp and a link to the -file location where I made the note ---helpful for tasks, tickets, to be tackled -later on. - -#+begin_src emacs-lisp -;; Location of my todos / captured notes file -(unless noninteractive - (setq org-default-notes-file - (if my/personal-machine? - "~/Dropbox/todo.org" - "~/Desktop/Work-2022-01-01.org"))) - -;; “C-c c” to quickly capture a task/note -(define-key global-map "\C-cc" #'my/org-capture) ;; See above. -#+end_src - -#+begin_details "By default we only get a ‘tasks’ form of capture, let's add some more." -#+begin_src emacs-lisp -(cl-defun my/make-org-capture-template - (shortcut heading &optional (no-todo nil) (description heading) (scheduled nil)) - "Quickly produce an org-capture-template. - - After adding the result of this function to ‘org-capture-templates’, - we will be able perform a capture with “C-c c ‘shortcut’” - which will have description ‘description’. - It will be added to the tasks file under heading ‘heading’. - - ‘no-todo’ omits the ‘TODO’ tag from the resulting item; e.g., - when it's merely an interesting note that needn't be acted upon. - - Default for ‘description’ is ‘heading’. Default for ‘no-todo’ is ‘nil’. - - Scheduled items appear in the agenda; true by default. - - The target is ‘file+headline’ and the type is ‘entry’; to see - other possibilities invoke: C-h o RET org-capture-templates. - The “%?” indicates the location of the Cursor, in the template, - when forming the entry. - " - `(,shortcut ,description entry - (file+headline org-default-notes-file ,heading) - ,(concat "*" (unless no-todo " TODO") " %?\n" - (when nil ;; this turned out to be a teribble idea. - ":PROPERTIES:\n:" - (if scheduled - "SCHEDULED: %^{Any time ≈ no time! Please schedule this task!}t" - "CREATED: %U") - "\n:END:") "\n\n ") - :empty-lines 1 :time-prompt t)) -#+end_src - -#+begin_src emacs-lisp -(setq org-capture-templates - (cl-loop for (shortcut heading) - in (-partition 2 '("t" "Tasks, Getting Things Done" - "r" "Reference Material" - "m" "Email" - "e" "Emacs (•̀ᴗ•́)و" - "i" "Islam" - "b" "Blog" - "a" "Arbitrary Reading and Learning" - "l" "Programming Languages" - "p" "Personal Matters")) - collect (my/make-org-capture-template shortcut heading))) -#+end_src - -Rather than adding notes to particular Org headings in my =todo.org= file, I could -defer such a choice by having only one template and have ~C-c a~ automatically use -it. Then I could ‘refile’ tasks to their appropriate parent headings with ~w~. -This allows us to seperate the concerns of capturing ideas from doing any form -of processing. Something to consider. - -#+begin_src emacs-lisp -;; Update: Let's schedule tasks during the GTD processing phase. -;; -;; For now, let's automatically schedule items a week in advance. -;; TODO: FIXME: This overwrites any scheduling I may have performed. -;; (defun my/org-capture-schedule () -;; (org-schedule nil "+7d")) -;; -;; (add-hook 'org-capture-before-finalize-hook 'my/org-capture-schedule) -#+end_src -#+end_details - -For now I capture everything into a single file. One would ideally keep -separate client, project, information in its own org file. -+ ⇒ Org capture actually lets us add /any/ type of entry, ‘programmable template’, - to /any/ type of file! ⇐ - * Look at doc:my/make-org-capture-template, above, to notice that capture - actually lets you add /any/ type of item to /any/ file. -+ ( For now, I'm only using it to add entries to my tasks lists. ) -+ Org-protocol is a way to create capture notes in org-mode from other applications. - -Let's also ensure *[[orange:TODO]]*-s respect hierarchical structure. -#+BEGIN_SRC emacs-lisp -;; Cannot mark an item DONE if it has a TODO child. -;; Conversely, all children must be DONE in-order for a parent to be DONE. -(setq org-enforce-todo-dependencies t) -#+END_SRC - -*Where am I currently capturing?* -+ During meetings, when a nifty idea pops into my mind, I quickly capture it. - - I've found taking my laptop to meetings makes me an active listener - and I get much more out of my meetings since I'm taking notes. -+ Through out the day, as I browse the web, read, and work; random ideas pop-up, and I capture them indiscriminately. -+ I envision that for a phone call, I would open up a capture to make note of what the call entailed so I can review it later. -+ Yet another place to capture content is from mail, such as for reference - material, or self-contained tasks. - # See [[#Capturing-Mail-as-Todo-Notes][above]] for this discussion. -+ Anywhere you simply want to make a note, for the current heading, just press - kbd:C-c_C-z. The notes are just your remarks along with a timestamp; they are - collected at the top of the tree, under the heading. - - #+begin_src emacs-lisp - ;; Ensure notes are stored at the top of a tree. - (setq org-reverse-note-order nil) - #+end_src - -Quickly look up some reference material... -#+begin_src emacs-lisp -(cl-defun my/reference (&optional (file org-default-notes-file)) - "Look up some reference material super quick. - -By default we look in user's Org TODOs file. - -FILE should be an ORG file with a top-level heading that starts with ‘Reference’. -We show its subheadings in a completing-read menu, then narrow to that entry." - (interactive) - (find-file file) - (widen) - (goto-char (point-min)) - (re-search-forward "^* Reference") ;; Start of line. - (org-narrow-to-subtree) - (org-cycle) (org-cycle) - (let* ((headings (org-map-entries (lambda () (org-element-property :title (org-element-at-point)) ) "LEVEL=2")) - (topic (completing-read "What to review? " headings))) - (search-forward (concat "** " topic)) - (org-narrow-to-subtree) - (org-cycle))) - -(defalias 'my/review-reference-notes 'my/reference) -(defalias 'w-reference 'my/reference) ;; “w”ork -#+end_src - -**** COMMENT Emacs as a reference platform: Instead of manually finding files, looking for :Place_beside_w_reference_function: -:PROPERTIES: -:CUSTOM_ID: COMMENT-Emacs-as-a-reference-platform-Instead-of-manually-finding-files-looking-for -:END: - info, then closing them; we can press a key combination to see some reference - matter _quickly_ then press _q_ to dismiss it just as quickly. We can do this with - a combination of (local-set-key (kbd "q") 'kill-buffer-and-window) and - (read-only-mode); but better would be to open a file and put it in special-mode - which has this _q_ behaviour [see simple.el special-mode-map for other bindinfs] - or to use the built-in with-electric-help macro, or make-help-screen & (require - 'help-macro).. Moreover, for lots of reference matter, a hydra can be used to - obtain a nice menu. My setup is to use doc:w-reference. - - -Anyhow… -*** Step 1: When new tasks come up -:PROPERTIES: -:CUSTOM_ID: Step-1-When-new-tasks-come-up -:END: - -Isn't it great that we can squirrel away info into some default location -then immediately return to what we were doing before ---with speed & minimal distraction! ♥‿♥ -Indeed, if our system for task management were slow then we may not produce -tasks and so forget them altogether! ~щ(゜ロ゜щ)~ - -+ Entering tasks is a desirably impulsive act; do not make any further - scheduling considerations. - - The next step, the review stage occurring at the end or the start of the - workday, is for processing. - -#+begin_quote -The reason for this is that entering new tasks should be impulsive, not reasoned. -Your reasoning skills are required for the task at hand, not every new tidbit. -You may even find that during the few hours that transpire between creating a -task and categorizing it, you’ve either already done it or discovered it doesn’t -need to be done at all! ---[[http://newartisans.com/2007/08/using-org-mode-as-a-day-planner/][John Wiegley]] -#+end_quote - -When my computer isn't handy, I'll make a note on my phone then transfer it later. -*** Step 2: Filing your tasks -:PROPERTIES: -:CUSTOM_ID: Step-2-Filing-your-tasks -:END: -At a later time, a time of reflection, we go to our tasks list and actually -schedule time to get them done by kbd:C-c_C-s, doc:org-schedule, then pick a -date by entering a number in the form ~+𝓃~ to mean that task is due ~𝓃~ days from -now. - -+ Tasks with no due date are ones that “could happen anytime”, most likely no time at all. -+ At least schedule tasks reasonably far off in the future, then reassess when the time comes. -+ An uncompleted task is by default rescheduled to the current day, each day, along with how overdue it is. - - Aim to consciously reschedule such tasks! - - Let's keep track of how many times, and when, we have pushed events to other dates. - #+BEGIN_SRC emacs-lisp -;; Add a note whenever a task's deadline or scheduled date is changed. -(setq org-log-redeadline 'time) -(setq org-log-reschedule 'time) -#+END_SRC - -#+begin_box custard - With time, it will become clear what is an unreasonable day - verses what is an achievable day. -#+end_box - -[[https://orgmode.org/manual/Repeated-tasks.html][Repeat tasks]] by a repeater such as ‘+1m’ or ‘+7d’ in their timestamps; e.g., -~:SCHEDULED: <2005-10-01 Sat +1m>.~ Likewise, to schedule an event (to repeat) for -multiple days, just use a bunch of timestamps (with repeaters): ~:SCHEDULED: -<2022-01-04 Tues 9:00 +1w><2022-01-06 Thu +1w><2022-01-07 Fri 9:00 +1w>~. -(Notice that we have ~:~ on each side of the keyword; and we have a time of day -for the event.) - --------------------------------------------------------------------------------- - -A ‘project’ is a task that has multiple steps, each as a checkbox item. It can -be given a percentage marker to show progress: Place ~[%]~ after its name, then -press [[kbd:C-c_#]] ---doc:org-update-statistics-cookies--- on the name to see a -completion percentage ---press kbd:C-c_C-c on a checkbox item to toggle its -completion state. - -*** Step 3: Quickly review the upcoming week -:PROPERTIES: -:CUSTOM_ID: Step-3-Quickly-review-the-upcoming-week -:END: - -The next day we begin our work, we press kbd:C-c_a_a to see the scheduled tasks -for this week ---kbd:C-c_C-s to re-schedule the task under the cursor and [[kbd:r]] -to refresh the agenda. -#+begin_src emacs-lisp -(define-key global-map "\C-ca" 'org-agenda) -#+end_src - -+ Show the next 𝓃 days schedule ⇐ =C-u 𝓃 C-c a a=. - -# The next section, [[Super Agenda]], will discuss acting on entries in the agenda -# buffer. - --------------------------------------------------------------------------------- - -Org agenda is an interactive tool for generating summary reports from Org data ----e.g., commonly, the weekly task list is generated from todo tasks. - -The agenda dispatch menu, ~C-c a~, has options for displaying tasks ---e.g., ~C-c a -m~ generates a list of entries having the same tags. new ways to view tasks by -altering the ~org-agenda-custom-commands~ variable ---e.g., above we added two, -one for completed tasks and one for unscheduled tasks. - -# Moreover, we can overlay due dates and priorities to tasks in a non-intrusive -# way that is easy to edit by hand. -#+begin_details "Let's setup the basics of our agenda." -#+begin_src emacs-lisp -;; List of all the files & directories where todo items can be found. Only one -;; for now: My default notes file. -(setq org-agenda-files (list org-default-notes-file)) - -;; Display tags really close to their tasks. -(setq org-agenda-tags-column -10) - -;; How many days ahead the default agenda view should look -(setq org-agenda-span 'day) -;; May be any number; the larger the slower it takes to generate the view. -;; One day is thus the fastest ^_^ - -;; How many days early a deadline item will begin showing up in your agenda list. -(setq org-deadline-warning-days 14) - -;; In the agenda view, days that have no associated tasks will still have a line showing the date. -(setq org-agenda-show-all-dates t) - -;; Scheduled items marked as complete will not show up in your agenda view. -(setq org-agenda-skip-scheduled-if-done t) -(setq org-agenda-skip-deadline-if-done t) -#+end_src -#+end_details - -#+begin_details Super Simple ‘agenda’ Mini-tutorial -link-here:Super-Simple-‘agenda’-Mini-tutorial - -The agenda view, like nearly all Emacs entities, is interactive: -+ =𝓃 f,b= ⇒ Look forward at next week's agenda, or backward to a previous week. - - The optional $𝓃$ means do the action =𝓃=-many times; - it defaults to 1. -+ =w, d= ⇒ toggle week view, or day view; use ~v~ to see possible views. - - E.g., ~C-u 2017 v y~ shows us the specific year 2017. -+ =𝓃 n,p= to navigate to next and previous entries. -+ =t= ⇒ cycle TODO state of the current entry. -+ =±= ⇒ cycle priority state. -+ =𝓃 S-⇆= ⇒ Shift date time by $𝓃$ days; 1 day by default. -+ =C-c C-s= ⇒ Reschedule an entry; prefix it with ~C-u~ to remove a scheduled entry. - - [[https://orgmode.org/manual/Repeated-tasks.html][Repeat tasks]] by a repeater such as ‘+1m’ or ‘+7d’ - in their timestamps; e.g., ~DEADLINE: <2005-10-01 Sat +1m>.~ -+ =s= ⇒ save all agenda buffers; i.e., save the org-files where the agenda items live. -+ =g= ⇒ Rebuild agenda according to any changes made thus far. -+ =F= ⇒ Toggle ‘follow mode’: As you go up/down entries, you can see their - details in an adjacent window. - - =SPC= ⇒ Show details of a single entry in other window; stay in Agenda. -+ =RET, TAB= ⇒ Go to the current entry in the current window or in a new - adjacent window, so as to alter task details. - -# ;; Easy way to capture tasks when in agenda view. -# (define-key org-agenda-mode-map "c" #'org-capture) - -#+end_details - -The agenda view –--even in the 7-days-at-a-time view--– will always begin on the -current day. This is important, since while using org-mode as a day planner, -you never want to think of days gone past. That’s something you do in other -ways, such as when reviewing completed tasks. -#+begin_src emacs-lisp -(setq org-agenda-start-on-weekday nil) - -;; Start each agenda item with ‘○’, then show me it's %timestamp and how many -;; times it's been re-%scheduled. -(setq org-agenda-prefix-format " ○ %t%s") -#+end_src - -#+begin_details Grouping agenda entries together -Instead of having the day's tasks all in one field, org-super-agenda allows us -to use predicates to group entries together; e.g., by considering an entry's -=:tags:= or its priority level. Since I'm placing all my tasks in a single file, -under appropriate parent headings, I want entries to be shown according to their -parent heading. Of-course, the top-most grouping, the important tasks, should be -pulled out of their group and placed at the top. -#+BEGIN_SRC emacs-lisp -(use-package origami ) -(use-package org-super-agenda - - :hook (org-agenda-mode . origami-mode) ;; Easily fold groups via TAB. - :bind (:map org-super-agenda-header-map ("" . origami-toggle-node)) - :config - (org-super-agenda-mode) - (setq org-super-agenda-groups - '((:name "Important" :priority "A") - (:name "Personal" :habit t) - ;; For everything else, nicely display their heading hierarchy list. - (:auto-map (lambda (e) (org-format-outline-path (org-get-outline-path))))))) - -;; MA: No noticable effect when using org-super-agenda :/ -;; -;; Leave new line at the end of an entry. -;; (setq org-blank-before-new-entry '((heading . t) (plain-list-item . t))) -#+END_SRC - -:OlderSetup: -#+BEGIN_SRC emacs-lisp :tangle no - ;; Default order is 0, first come first serve. - ;; Items are “or”-ed by default. - '((:name "Important" - :tag "PackageFormer" - :tag "PF" - :tag "research" - :and (:tag "JC" :priority "A") - :and (:tag "WK" :priority "A") - :priority "A") - - ;; Groups supply their own section names when none are given - (:name "Living the dream!" :tag "personal") - (:name "Discrete Mathematics" :tag "2fa3") - (:name "Emacs Init" :tag "init") - ;; (:priority<= "B" :order 1) - ;; Everything else automatically gets its own group - (:auto-category t) - ))) -#+END_SRC -:End: -# + Origami mode ---see below in [[Text Folding with Origami-mode]]--- -# works well with super-agenda. Just ~M-x origami-mode~ then ~C-c f~ to -# enable the folding hydra. -# -The [[https://github.com/alphapapa/org-super-agenda][org-super-agenda]] homepage shows complex configurations and pleasant -screenshots contrasting with and without the system. -E.g., you can change how entries in particular headings are displayed and coloured. -#+end_details -*** Step 4: Getting ready for the day -:PROPERTIES: -:CUSTOM_ID: Step-4-Getting-ready-for-the-day -:END: -After having seen our tasks for the week, we press [[kbd:d]] to enter daily view for -the current day. Now we decide whether the items for today are ~A~: of high -urgency & important; ~B~: of moderate urgency & importance; or ~C~: Pretty much -optional, or very quick or fun to do. -+ ~A~ tasks should be both important /and/ urgently done on the day they were scheduled. - - Such tasks should be relatively rare! - - If you have too many, you're anxious about priorities and rendering - priorities useless. -+ ~C~ tasks can always be scheduled for another day without much worry. - - Act! If the thought of rescheduling causes you to worry, upgrade it to a - ~B~ or ~A~. -+ As such, most tasks will generally be priority ~B~: - Tasks that need to be done, but the exact day isn't as critical as with an - ~A~ task. These are the “bread and butter” tasks that make up your day to day - life. - -On a task item, or any org-heading, press [[kbd:,]] then one of [[kbd:A/B/C]] to set its -priority. Then [[kbd:r]] to refresh. - -#+begin_details Pretty Prioritisation Markers -link-here:Pretty-Prioritisation-Markers -Let's set four priority levels and their colours: The more intense colours -are for more urgent tasks. -#+begin_src emacs-lisp -(setq org-lowest-priority ?C) ;; Now org-speed-eky ‘,’ gives 3 options -(setq org-priority-faces -'((?A :foreground "red" :weight bold) ;; :background "LightCyan1") - (?B :foreground "orange" :weight bold) - (?C :foreground "green" :weight bold))) -;; See all colours with: M-x list-colors-display -#+end_src - -+ ~C-c ,~ anywhere to set the priority of the current heading. - - We may press ~A-D~ or ~SPC~ to an remove existing priority. - -Priority markers are of the form ~[#𝒳]~, the [[https://github.com/harrybournis/org-fancy-priorities][fancy priorities]] package visually -renders them as words or icons. -#+begin_src emacs-lisp -(use-package org-fancy-priorities - - :hook (org-mode . org-fancy-priorities-mode) - :custom (org-fancy-priorities-list '("MUST DO" "MID" "LOW")) ;; "OPTIONAL" - ;; Let's use the “Eisenhower map of priority”… - ;; :custom (org-fancy-priorities-list '("Urgent and Important" ;; Do now! - ;; "Not Urgent But Important" ;; Do schedule this. - ;; "Urgent But Not Important" ;; Delegate? - ;; "Not Urgent and Not Important")) ;; Don't do / Optional - ) -#+end_src -#+end_details - -At work, my tasks list is massive and constantly growing; so to avoid stressing -myself out, I try to add /time effort estimates/ to my tasks with -doc:org-set-effort then I open my Org agenda and run ~d~ (for day view) then -doc:org-agenda-columns (~C-c C-x C-c~) to see a column-view of my time estimates -/along/ with *a total time estimate for the day.* Since there are unexpected -pair-programming calls, or meetings go longer than expected, I only schedule for -7 hours each day (in a usual 8-hour work day); i.e., if my time estimates exceed -7h then I reschedule or cancel some things. - -#+begin_src emacs-lisp -(require 'org-agenda) - -;; How should the columns view look? -(setq org-columns-default-format "%60ITEM(Task) %6Effort(Estim){:} %3PRIORITY %TAGS") - -;; Press “c” in Org agenda to see the columns view; (default binding C-c C-x C-c is too long!) -(org-defkey org-agenda-mode-map "c" #'org-agenda-columns) -(org-defkey org-agenda-mode-map "C" #'org-agenda-goto-calendar) - -;; Press “e” in columns view to alter “e”ffort “e”stimates. -(require 'org-colview) -(org-defkey org-columns-map "e" - ;; Refresh after making an effort estimate. - (lambda () (interactive) (org-agenda-set-effort) (org-agenda-columns))) -#+end_src - -Near the top of my TODOS file, I have the following clickable link: It looks pretty and when I click it, takes me where I need to go. -# ;; Show sum of efforts for a day in Org-Agenda day title -#+begin_src org :tangle no -[[elisp:(progn (org-agenda nil "a") (org-agenda-columns) (delete-other-windows))][Show agenda with time estimates]] -#+end_src - -*** Step 5: Doing the work -:PROPERTIES: -:CUSTOM_ID: Step-5-Doing-the-work -:END: - -Since ~A~ tasks are the important and urgent ones, if you do all of the ~A~ tasks and -nothing else today, no one would suffer. It's a good day (─‿‿─). - -There should be no scheduling nor prioritising at this stage. -You should not be touching your tasks file until your next review session: -Either at the end of the day or the start of the next. - -+ Leverage priorities! E.g., When a full day has several ~C~ tasks, reschedule - them for later in the week without a second thought. - - You've already provided consideration when assigning priorities. - -*** Step 6: Moving a task toward completion -:PROPERTIES: -:CUSTOM_ID: Step-6-Moving-a-task-toward-completion -:END: - -My workflow states are described in the section -[[Workflow States]] and contain states: ~TODO, STARTED, WAITING, ON_HOLD, CANCELLED, DONE~. -+ Tasks marked ~WAITING~ are ones for which we are awaiting some event, like someone - to reply to our query. As such, these tasks can be rescheduled until I give up - or the awaited event happens ---in which case I go to ~STARTED~ and document - the reply to my query. -+ The task may be put off indefinitely with ~ON_HOLD~, or I may choose never to do it - with ~CANCELLED~. Along with ~DONE~, these three mark a task as completed - and so it needn't appear in any agenda view. - -I personally clock-in and clock-out of tasks ---keep reading---, where upon -clocking-out I'm prompted for a note about what I've accomplished so far. -Entering a comment about what I've done, even if it's very little, feels like -I'm getting something done. It's an explicit marker of progress. - -In the past, I would make a “captain's log” at the end of the day, but that's -like commenting code after it's written, I didn't always feel like doing it and -it wasn't that important after the fact. The continuous approach of noting after -every clock-out is much more practical, for me at least. - -*** Step 7: Archiving Tasks :Disabled: -:PROPERTIES: -:CUSTOM_ID: Step-7-Archiving-Tasks -:header-args: :tangle no -:END: -During the review state, when a task is completed, ‘archive’ it with -doc:org-archive-subtree or kbd:C-c_C-x_C-s: This marks it as done, adds a time -stamp, and moves it to a local ~*.org_archive~ file. What was our *[[red:‘to do’]]* list -becomes a *[[green:‘ta da’]]* list showcasing all we have done (•̀ᴗ•́)و - -Archiving keeps task lists clutter free, but unlike deletion it allows us, -possibly rarely, to look up details of a task or what tasks were completed in a -certain time frame ---which may be a motivational act, to see that you have -actually completed more than you thought, provided you make and archive tasks -regularly. We can use [[doc:org-search-view][~M-x org-search-view~]] to search an org file /and/ the -archive file too, if we enable it so. -#+BEGIN_SRC emacs-lisp -;; C-c a s ➩ Search feature also looks into archived files. -;; Helpful when need to dig stuff up from the past. -(setq org-agenda-text-search-extra-files '(agenda-archives)) -#+END_SRC - -#+begin_src emacs-lisp -;; enables the org-agenda variables. -(require 'org-agenda) ;; Need this to have “org-agenda-custom-commands” defined. - -(unless noninteractive - ;; ➩ Show my agenda upon Emacs startup. - (org-agenda "a" "a")) -#+end_src - -Let's install some helpful views for our agenda. - -+ ~C-c a c~: See completed tasks at the end of the day and archive them. - #+begin_src emacs-lisp -;; Pressing ‘c’ in the org-agenda view shows all completed tasks, -;; which should be archived. -(add-to-list 'org-agenda-custom-commands - '("c" todo "DONE|ON_HOLD|CANCELLED" nil)) -#+end_src - -+ ~C-c a u~: See unscheduled, undeadlined, and undated tasks in my todo files. - Which should then be scheduled or archived. - #+begin_src emacs-lisp -(add-to-list 'org-agenda-custom-commands - '("u" alltodo "" - ((org-agenda-skip-function - (lambda () - (org-agenda-skip-entry-if 'scheduled 'deadline 'regexp "\n]+>"))) - (org-agenda-overriding-header "Unscheduled TODO entries: ")))) -#+end_src - -/At the end of the day, let's schedule at least 3 things that must be done the -next day; i.e., have priority =A=./ - -** Tag! You're it! -:PROPERTIES: -:CUSTOM_ID: Tag-You're-it -:END: - -Even when items are categorised under their own parent headings, they may be -related in some way and that can made explicit by adding a ~:tag:~ to their -headings; e.g., two entries both have the ~:jasim:@work:~ tags, then looking for -the ~:@work:~ tag shows me all entries that are tagged as “at work”. - - | Tags provide a cross-section of one's entries. | - -Tags let us find related stuff quickly, even though they're differently -categorised. - -/After calling ~org-agenda~, we may select ~m~ to match for tags, or use -~org-tags-view~ to search for tags./ - -*What to tag?* Common tags are =:@laptop:, :@work:, :@home:= to identify the -location where tasks take place ---Use: When I'm at a particular place, I need -only consider tasks that apply to that place ;-) Other tags I use are =:𝑭𝑳:= to -identify remarks or email or request from person 𝑭irstname 𝑳astname; or -something that might be interesting to that person. I also use ~:video:, :book:, -:paper:~; which let me quickly find all videos! Finally, I also use -=:project_name:= to identify notes that may be of interest to a particular -project, but are more appropriately categorised elsewhere ---e.g., when learning -about an Emacs feature, I may tag my notes with another project's name to -consider whether that feature could be useful there. - -*How to tag?* - -You can just add a ~:tag₁:⋯:tagₙ:~ after a heading. If you press space, before the -tags, then they are automatically indented flushright to column 77; postive -numbers do not flushright but use exact column number. -#+BEGIN_SRC emacs-lisp - (setq org-tags-column -77) ;; the default -#+END_SRC - -Use ~C-c C-q~, or ~org-set-tags-command~, on a heading or just the speed key ~:~ on -the asterisks of a heading to set the tags of an item ---as usual, with Helm we -obtain a window of all existing tags to select from. Unfortunatley, this only -supports having one tag; for more, you can add them in manually or … - -#+begin_src emacs-lisp -;; Press ‘:’ on a heading to add a tag, press TAB to see all tags, press RETURN on a tag to add it, press TAB again to add more tags, when all done press RETURN twice. -(use-package helm-org ) ;; Helm for org headlines and keywords completion. -(add-to-list 'helm-completing-read-handlers-alist - '(org-set-tags-command . helm-org-completing-read-tags)) - -;; Also provides: helm-org-capture-templates -#+end_src - -Now ~:~ or ~C-c C-q~ will show existing tags for the current heading, press ~TAB~ to -obtain a list of all exisiting tags, press ~C-SPC~ to select the desired tags, -then =TAB= or =RET= to confirm the resulting tag list, and ~RET~ to finish or ~TAB~ to -select more tags. -- Press “:” on a heading to interactively select tags for it, please ENTER when - done selecting tags. -- Press “C-u :” to align all tags. - -Let's render tags by Unicode symbols. -#+begin_src emacs-lisp -(setq org-tag-alist - '( - ("Work" . ?w) - ("Personal" . ?p) - ;; Instead of a “:meeting:” tag, I prefer to call it “social credit” (✿◠‿◠) - ("SocialCredit" . ?s) - ;; “Out Of Office” - ("OOO" . ?o) - ("Family" . ?f) - ("Errand" . ?e) - ("Reading" . ?r) - ("BlogRoll" . ?b) - ("Urgent" . ?u))) - - -;; I can't see the entire tags menu when using doom-modeline, so let's redisplay -;; when the tags menu appears. -;; See https://emacs.stackexchange.com/a/70856 -(advice-add #'fit-window-to-buffer :before (lambda (&rest _) (redisplay t))) - - -(use-package org-pretty-tags - - :config - (setq org-pretty-tags-surrogate-strings - '(("Neato" . "💡") - ("Blog" . "✍") - ("Audio" . "♬") - ("Video" . "📺") - ("Book" . "📚") - ("Running" . "🏃") - ("Question" . "❓") - ("Wife" . "💕") - ("Text" . "💬") ; 📨 📧 - ("Friends" . "👪") - ("Self" . "🍂") - ("Finances" . "💰") - ("Car" . "🚗") ; 🚙 🚗 🚘 - ("Urgent" . "🔥"))) ;; 📥 📤 📬 - (org-pretty-tags-global-mode 1)) -#+end_src - -** Automating [[https://en.wikipedia.org/wiki/Pomodoro_Technique][Pomodoro]] ---“Commit for only 25 minutes!” :book: -:PROPERTIES: -:CUSTOM_ID: Automating-https-en-wikipedia-org-wiki-Pomodoro-Technique-Pomodoro-Commit-for-only-25-minutes -:END: - -Effort estimates are for an entire task. -Yet, sometimes it's hard to even get started on some tasks. - -+ The code below ensures a 25 minute timer is started whenever clocking in happens. - - - The timer is in the lower right of the modeline. - -+ When the timer runs out, we get a notification. - -+ We may have the momentum to continue on the difficult task, or clock-out and - take a break after documenting what was accomplished. - -#+BEGIN_SRC emacs-lisp -;; Tasks get a 25 minute count down timer -(setq org-timer-default-timer 25) - -;; Use the timer we set when clocking in happens. -(add-hook 'org-clock-in-hook - (lambda () (org-timer-set-timer '(16)))) - -;; unless we clocked-out with less than a minute left, -;; show disappointment message. -(add-hook 'org-clock-out-hook - (lambda () - (unless (s-prefix? "0:00" (org-timer-value-string)) - (message-box "The basic 25 minutes on this difficult task are not up; it's a shame to see you leave.")) - (org-timer-stop))) -#+END_SRC - -Note that this does not conflict with the total effort estimate for the task. - -(I'm told there's a package already made for this ---maybe I need to stop writing -code, and do more searches; then again, I've learned a lot by writing code.) - -** Journaling -:PROPERTIES: -:CUSTOM_ID: Journaling -:header-args: :tangle no -:END: - -*** Intro to why even journal :ignore: -:PROPERTIES: -:CUSTOM_ID: Intro-to-why-even-journal -:END: - -Thus far I've made it easy to quickly capture ideas and tasks, not so much on -the analysis phase: - -- What was accomplished today? -- What are some notably bad habits? Good habits? -- What are some future steps? - -Rather than overloading the capture mechanism for such thoughts, let's employ -~org-journal~ ---journal entries are stored in files such as ~journal/20190407~, -where the file name is simply the date, or only one file per year as I've set it -up below. Each entry is the week day, along with the date, then each child tree -is an actual entry with a personal title preceded by the time the entry was -made. Unlike capture and its agenda support, journal ensures entries are -maintained in chronological order with calendar support. - -Since org files are plain text files, an entry can be written anywhere and later -ported to the journal. Or, written directly in the journal file if we add the -necessary Org-header: Asterisks and time. - -The separation of concerns is to emphasise the capture stage as being quick and -relatively mindless, whereas the journaling stage as being mindful. Even though -we may utilise capture to provide quick support for including journal entries, I -have set my journal to be on a yearly basis ---one file per year--- since I want -to be able to look at previous entries when making the current entry; after all, -it's hard to compare and contrast easily unless there's multiple entries opened -already. - -As such, ideally at the end of the day, I can review what has happened, and what -has not, and why this is the case, and what I intend to do about it, and what -problems were encountered and how they were solved ---in case the problem is -encountered again in the future. *Consequently, if I encounter previously -confronted situations, problems,* *all I have to do is reread my journal to get an -idea of how to progress.* Read more about [[https://www.google.com/search?q=on+the+importance+of+reviwing+your+day+daily&oq=on+the+importance+of+reviwing+your+day+daily&aqs=chrome..69i57.367j0j7&sourceid=chrome&ie=UTF-8][the importance of reviewing your day on -a daily basis]]. - -Moreover, by journaling with Org on a daily basis, it can be relatively easy to -produce a report on what has been happening recently, at work for example. I'd -like to have multiple journals, for work and for personal life, as such I will -utilise a prefix argument to obtain my work specific entries. - -*** The Setup -:PROPERTIES: -:CUSTOM_ID: The-Setup -:END: - - -# As of Oct2022, Using org-journal breaks my permissions. E.g., org-time-stamp / C-c . results in " -# directory-files-recursively: Opening directory: Operation not permitted, /Users/musa/Desktop" - - -Anyhow, the setup: -#+begin_src emacs-lisp -(use-package org-journal - - ;; C-u C-c j ⇒ Work journal ;; C-c j ⇒ Personal journal - :bind (("C-c j" . my/org-journal-new-entry)) - :config - (setq org-journal-dir "~/Desktop/" ;; "~/Dropbox/journal/" - org-journal-file-type 'yearly - org-journal-file-format "Personal-%Y-%m-%d.org") - - (defun my/org-journal-new-entry (prefix) - "Open today’s journal file and start a new entry. - - With a prefix, we use the work journal; otherwise the personal journal." - (interactive "P") - (let ((org-journal-dir (if prefix "~/Desktop/" org-journal-dir)) - (org-journal-file-format (if prefix "Work-%Y-%m-%d.org" org-journal-file-format))) - (org-journal-new-entry nil) - (org-mode) - (org-show-all)))) -#+end_src - -# Convenient org-journal Snippet Extensions -# Kill journal buffer after saving buffer (By @dhruvparamhans) -# (defun org-journal-save-entry-and-exit() -# "Simple convenience function. -# Saves the buffer of the current day's entry and kills the window -# Similar to org-capture like behavior" -# (interactive) -# (save-buffer) -# (kill-buffer-and-window)) -# (define-key org-journal-mode-map (kbd "C-x C-s") -# 'org-journal-save-entry-and-exit) -# - -*** Super Terse Tutorial -:PROPERTIES: -:CUSTOM_ID: Super-Terse-Tutorial -:END: - -Bindings available in ~org-journal-mode~, when journaling: -+ ~C-c C-j~: Insert a new entry into the current journal file. - - Note that keys for ~org-journal-new-entry~ shadow those for ~org-goto~. -+ ~C-c C-s~: Search the journal for a string. - - Note that keys for ~org-journal-search~ shadow those for ~org-schedule~. - -# C-c C-f - go to the next journal file. -# C-c C-b - go to the previous journal file. - -# Some key-bindings in org-journal overwrite org-mode key bindings - -# Major modes are supposed to only use key bindings of the form C-c C-?, where ? -# can be any letter. With org-mode already using most interesting keys, -# collisions are inevitable. Currently, org-journal overwrites -# -# C-c C-f (org-forward-heading-same-level) with org-journal-open-next-entry -# C-c C-b (org-backward-heading-same-level) with org-journal-open-previous-entry -# - -All journal entries are registered in the Emacs Calendar. To see available -journal entries do ~M-x calendar~. Bindings available in the calendar-mode: - -+ ~j~: View an entry in a new buffer. - # C-j - view an entry but do not switch to it. -+ ~i j~: ‘I’nsert a new ‘j’ournal entry into the day’s file. -+ ~f w/m/y/f/F~: ‘F’ind, search, in all entries of the current week, month, year, all of time, - of in all entries in the future. -# -# [ - go to previous day with journal entries. -# ] - go to next day with journal entries. - - - -All journal entries are registered in the Emacs Calendar. To see available journal entries do M-x calendar. Bindings available in the calendar-mode: -- [[kbd: j d]] display an entry; use [[kbd: j r]] to jump to the new reading buffer; - reading is in doc:view-mode: [[kbd:q]] to quit reading and [[kbd:SPC]] to scroll. -+ [[kbd: j s w/m/y/f]] search the journal entries of the current - week/month/year or for all time -+ ~[/]~ go the previous/next day with journal entries - --------------------------------------------------------------------------------- - -*** Guided Journaling -:PROPERTIES: -:CUSTOM_ID: Guided-Journaling -:END: - -Sometimes it can be tough to journal, but filling in a template can be a way to -get started. Later on, we will setup [[Snippets ---Template Expansion]] which will -allow us to write =journal_guided= then ~TAB~ to obtain the template below. Each =$𝓃= -indicates a position that we may input text, after which we ~TAB~ to move to next -location. - -Just like the ~undo-tree~ setup at the start of this read, we use a =noweb-ref= -to present this template in a natural position; then later when template -expansion it setup, we request it to be tangled. - -#+begin_src org :noweb-ref templates-from-other-places-in-my-init :tangle no -,** journal_guided: Introspection & Growth -I'm writing from ${1:location}. - -Gut answer, today I feel ${2:scale}/10. -⇒ ${3:Few words or paragraphs to explain what's on your mind.} - -${4: All things which cause us to groan or recoil are part of the tax of -life. These things you should never hope or seek to escape. Life is a battle, -and to live is to fight. - -⟨ Press TAB once you've read this mantra. ⟩ -$(when yas-moving-away-p "") -} -`(progn - (eww "https://www.dailyinspirationalquotes.in/") - (sit-for 2) (when nil let eww load) - (read-only-mode -1) - (goto-line 52) - (kill-line) - (kill-buffer) - (yank))` -${7: -Self Beliefs: -+ I am working on a healthier lifestyle, including a low-carb diet. - - - I’m also investing in a healthy, long-lasting relationship. - - ➩ These are what I want and are important to me. ⇦ - -+ I will not use any substances to avoid real issues in my life. I must own them. - -+ Everything I’m searching for is already inside of me. - -+ Progress is more important than perfection. - -⟨ Press TAB once you've read these beliefs. ⟩ -$(when yas-moving-away-p "") -} - -*Three things I'm grateful for:* -1. ${8:??? … e.g., old relationship, something great yesterday, an opportunity I - have today, something simple near me within sight} -2. ${9:??? … e.g., old relationship, something great yesterday, an opportunity I - have today, something simple near me within sight} -3. ${10:??? … e.g., old relationship, something great yesterday, an opportunity I - have today, something simple near me within sight} - -*Three things that would make today great:* -1. ${11:???} -2. ${12:???} -3. ${13:???} - -*What one thing is top of mind today?* -${14:???} - -*What’s one opportunity I want to go after?* -${15:???} - -*What’s one thing I’m really proud of OR I’m amazed and in awe of?* -${16:???} - -$0 -#+end_src - -Besides a bit of webscraping to obtain a daily inspirational quote image, and -the necessary yasnippet code, this template was taken from a discussion on -[[https://news.ycombinator.com/item?id=20849148][Hacker news: “I find journaling indispensable”]]. In time, I will likely alter it -to meet my needs, but I like it as it is right now (•̀ᴗ•́)و - -** Workflow States -:PROPERTIES: -:CUSTOM_ID: Workflow-States -:END: - -Here are some of my common workflow states, ---the ‘X/Y’ indicates to do action ‘X’ -when entering a state and ‘Y’ when leaving it, with ‘!’ denoting a timestamp -should be generated and ‘@’ denoting a user note should be made. -#+begin_src emacs-lisp -;; Attempting to move a task to a DONE state is blocked if the has a child task that is not marked as DONE -(setq org-enforce-todo-dependencies t) - -;; TODO: Add the line “(declare (indent defun))” right after the docstring of “lf-define”, -;; so that Emacs indents it like a “defun”. -;; See https://www.gnu.org/software/emacs/manual/html_node/elisp/Indenting-Macros.html -;; -;; Until then, use the following incantation: -(lf-define (get 'lf-define 'lisp-indent-function) 'defun) - - -(lf-define my/declare-workflow-states (states) - [:requires (listp states) :ensures (stringp result)] - "Declare STATES as todo-states. STATES is a list of (name on-entry on-exit color) lists." - (setq org-todo-keywords (list (cons 'sequence - (cl-loop for (state . props) in states - for first-letter = (downcase (substring state 0 1)) - for on-entry = (plist-get props :on-entry) - for on-exit = (plist-get props :on-exit) - for entry = (if (not on-entry) "" (if (equal on-entry 'note) "@" "!")) - for exit = (if (not on-exit) "" (if (equal on-exit 'note) "/@" "/!")) - collect (if (equal state "|") state (format "%s(%s%s%s)" state first-letter entry exit)))))) - (setq org-todo-keyword-faces - (cl-loop for (state . props) in states - collect (list state :foreground (plist-get props :foreground) :weight 'bold))) - "✔ Invoke “org-mode-restart” in existing Org buffers for this to take effect.") - - -;; These denote ‘progress’ on a task. -;; For contextual information, one uses “tags”. -;; For example, a delegated task could be in state “STARTED” and tagged “:delegate:James:”. -(my/declare-workflow-states - ;; Transitions: TODO → INVESTIGATED → STARTED ⟷ {AWAITING_REVIEW | PAUSED} → {DONE | CANCELLED} - '( - ;; Tasks that are not started and not planned. They could be the - ;; backlogs or the GTD’s someday/maybe. These tasks could be converted - ;; to NEXT during a weekly review. - ("TODO" :foreground "red") - - ;; A task moves from TODO to NEXT only when I've actually split the task - ;; into small achievable chunks; ie i've done some investigation into - ;; the task and thought about what steps I need to do to actually get - ;; the task done. With this planning in place, I can then ensure I - ;; allocate sufficient timeblocks to work on the subtasks of this - ;; task. (Aside, a “project” is a task with multiple subtasks.) - ;; - ;; - ;; Use my 1/1 time with my manager/peers to review my INVESTIGATED/NEXT - ;; findings for the tickets of the current sprint. I just want to make - ;; sure I'm on the right track, before starting to work on them. Or, if - ;; a ticket is not investigated, do that with my manager. I find that while it - ;; might take me half an hour or more, it'll take like 5 minutes with - ;; him since he's familiar with the code-base. - ;; - ;; - ;; ≈ NEXT. Tasks that are not started but planned to do as soon as I - ;; can. When there is no actionable STARTED (e.g., blocked), I start one - ;; of those and convert it to STARTED. - ("INVESTIGATED" :on-entry timestamp :foreground "dark orange") - - ;; Tasks that are working in progress (“open loops”). I work on these - ;; tasks before starting another NEXT task to avoid too many open loops - ;; at any moment. - ("STARTED" :on-entry timestamp :foreground "blue") ;; When did I start? - - ;; I'm not actively working on this task anymore. I may return to it later. - ("PAUSED" :on-entry note :on-exit timestamp :foreground "magenta") ;; When & why is the task paused? - - ;; When a task goes into WAITING, I've finished the task as much as possible - ;; and now need to rely on someone else; e.g., for feedback. - ;; - ;; I don't want to see these scheduled tasks in my Agenda. - ;; - ;; In the Weekly Review, I will take time to look at my WAITING tasks - ;; and if they've been waiting ~2 weeks, then I should message the relevant people to unblock it. - ;; - ;; “In progress, but blocked by others” - ("WAITING" :on-entry timestamp :foreground "red2") ;; When did this task enter in-review? - - ;; I'm actively working on this task, and not waiting on any one else, - ;; but there is some blocker; e.g., a merge dependency issue or a conflict to resolve. - ;; Sometimes these are quick to dispatch; other times they're blocked by PAUSED/WAITING tasks. - ;; - ;; This is essentially DONE, but there's some blocker. - ("APPROVED" :on-entry timestamp :foreground "magenta") - - ("|") ;; All states after this special marker are “terminal” and so not shown in the org-agenda: (setq org-agenda-skip-scheduled-if-done t) - - ("DONE" :on-entry timestamp :foreground "forest green") ;; When did this task finish? - - ;; This is useful at work to keep track of *why* we have decided against doing a task; in my Org file there may be more, private, reasons not mentioned in the company's Jira file. (For example). - ;; - ;; This is useful at home since I might have had the same task/idea again and it's useful to know *why* I didn't do it last time; also useful for when doing Annual Reviews. - ("CANCELLED" :on-entry note :foreground "saddle brown"))) ;; Why was this task cancelled? (Notes come with a timestamp!) - -;; Since DONE is a terminal state, it has no exit-action. -;; Let's explicitly indicate time should be noted. -(setq org-log-done 'time) -;; → Take a look at org-log-done and org-log-into-drawer. These will tell org to log the date and time when an item's status is changed (you can specify). -;; → When the agenda is built you can show all these logged items on the date they were completed with org-agenda-log-mode, org-agenda-log-mode-items, and org-agenda-start-with-log-mode. -;; → This allows me to place TODO items anywhere I want (my logbook, notes, and a scratch list) and as I complete them through the week they're all shown in the agenda according to when I completed each. -;; → I use org-clock-in to the task I'm working on, then a simple clocktable with some dates will show me exactly what I worked on. -;; → [Weekly Review] which creates a day-by-day summary of the time I worked on what tasks. On Friday, I can look at this and see what I did over the week. - -;; I prefer to log TODO creation also -(setq org-treat-insert-todo-heading-as-state-change t) - -;; When a task goes into the WAITING state, please remove its schedule -;; so that it does not appear in my agenda. (However, it's still not “done” and so appears when I do “C-c a t” for example.) -;; Source: https://emacs.stackexchange.com/a/2760 -(add-hook 'org-after-todo-state-change-hook - (defun rasmus/remove-schedule () - "Remove SCHEDULED-cookie is switching state to WAITING." - (save-excursion - (and (equal (org-get-todo-state) "WAITING") - (org-get-scheduled-time (point)) - (when (search-forward-regexp org-scheduled-time-regexp nil t) - (or (delete-region (match-beginning 0) (match-end 0)) t)) - (get-buffer "*Org Agenda*") - (with-current-buffer "*Org Agenda*" - (org-agenda-redo)))))) -#+end_src - -In particular, we transition from ~TODO~ to ~STARTED~ once 15 minutes, or a -reasonable amount, of work has transpired. Since all but one state are marked -for logging, we could use the ~lognotestate~ logging facility of org-mode, which -prompts for a note every time a task’s state is changed. - -Entering a comment about what I've done, even if it's very little, feels like -I'm getting something done. It's an explicit marker of progress and motivates me -to want to change my task's states more often until I see it marked ~DONE~. - -Now we press ~C-c C-t~ then the letter shortcut to actually make the state of an org heading. -#+begin_src emacs-lisp -(setq org-use-fast-todo-selection t) -#+end_src - -We can also change through states using Shift- left, or right. -# (setq org-treat-S-cursor-todo-selection-as-state-change nil) - -Let's draw a state diagram to show what such a workflow looks like. - -[[http://plantuml.com/index][PlantUML]] supports drawing diagrams in a tremendously simple format ----it even supports Graphviz/DOT directly and many other formats. -Super simple setup instructions can be found [[http://eschulte.github.io/babel-dev/DONE-integrate-plantuml-support.html][here]]; below are a bit more -involved instructions. Read the manual [[http://plantuml.com/guide][here]]. - -#+begin_src emacs-lisp -;; Install the tool -; (async-shell-command "brew tap adoptopenjdk/openjdk; brew cask install adoptopenjdk13") ;; Dependency -; (async-shell-command "brew install plantuml") - -;; Tell emacs where it is. -;; E.g., (async-shell-command "find / -name plantuml.jar") -(setq org-plantuml-jar-path - "/usr/local/Cellar/plantuml/1.2022.14/libexec/plantuml.jar") - -;; Enable C-c C-c to generate diagrams from plantuml src blocks. -(add-to-list 'org-babel-load-languages '(plantuml . t) ) -(require 'ob-plantuml) - -; Use fundamental mode when editing plantuml blocks with C-c ' -(add-to-list 'org-src-lang-modes '("plantuml" . fundamental)) -#+end_src -# -# (async-shell-command "cp workflow.png ~/alhassy.github.io/assets/img/") - -Let's use this! -# The source block is replaced with the generated image in-place, by default. -# #+begin_src plantuml :file workflow.png :exports code :cache (progn (async-shell-command "cp workflow.png ~/alhassy.github.io/assets/img/") "yes") -#+begin_src plantuml :file images/workflow.png :tangle no :exports both :eval never-export :results replace -skinparam defaultTextAlignment center /' Text alignment '/ - -skinparam titleBorderRoundCorner 15 -skinparam titleBorderThickness 2 -skinparam titleBorderColor red -skinparam titleBackgroundColor Aqua-CadetBlue -title My Personal Task States - -[*] -> Todo /' This is my starting state '/ -Done -right-> [*] /' This is an end state '/ -Cancelled -up-> [*] /' This is an end state '/ - -/'A task is “Todo”, then it's “started”, then finally it's “done”. '/ -Todo -right-> Started -Started -down-> Waiting -Waiting -up-> Started -Started -right-> Done - -/'Along the way, I may pause the task for some reason then - return to it. This may be since I'm “Blocked” since I need - something, or the task has been put on “hold” since it may not - be important right now, and it may be “cancelled” eventually. -'/ - -Todo -down-> Waiting -Waiting -up-> Todo -Waiting -up-> Done - -Todo -down-> On_Hold -On_Hold -> Todo - -On_Hold -down-> Cancelled -Waiting -down-> Cancelled -Todo -down-> Cancelled - -/' The Org-mode shortcuts for these states are as follows. '/ -Todo : t -On_Hold : h -Started : s -Waiting : w -Cancelled : c -Done : d - -/' If a task is paused, we should document why this is the case. '/ -note right of Waiting: Note what is\nblocking us. -note right of Cancelled: Note reason\nfor cancellation. -note bottom of On_Hold: Note reason\nfor reduced priority. - -center footer ♥‿♥ Org-mode is so cool (•̀ᴗ•́)و -/' Note that we could omit the “center, left, right” if we wished, - or used a “header” instead.'/ -#+end_src - -#+RESULTS: -[[file:images/workflow.png]] - -# (org-display-inline-images t t) -# (shell-command "rm workflow.png") -# +HTML: My Personal Task States - -Of note: - -+ Multiline comments are with ~/' comment here '/~, single quote starts a one-line comment. - -+ Nodes don't need to be declared, and their names may contain spaces if they are enclosed in double-quotes. - -+ One forms an arrow between two nodes by writing a line with ~x ->[label here] y~ - or ~y <- x~; or using ~-->~ and ~<--~ for dashed lines. The label is optional. - - To enforce a particular layout, use ~-X->~ where ~X ∈ {up, down, right, left}~. - -+ To declare that a node ~x~ has fields ~d, f~ we make two new lines having - ~x : f~ and ~x : d~. - -+ One adds a note near a node ~x~ as follows: ~note right of x: words then newline\nthen more words~. - - Likewise for notes on the ~left, top, bottom~. - - - A note can be on several lines. It's terminated by ~end note~. - -+ Interesting sprites and many other things can be done with PlantUML. Read the docs. - -This particular workflow is inspired by [[http://doc.norang.ca/org-mode.html][Bernt Hansen]] ---while quickly searching -through the PlantUML [[http://plantuml.com/guide][manual]]: The above is known as an “activity diagram” and -it's covered in §4. - -Org-mode may be used with PlantUML: -+ See §11,12 for using Org-mode notation to form ‘mindmaps’ and ‘work breakdown - structures’. - -+ Org-mode text formatters are also acknowledged but the delimiters must be - doubled; see §16.1. - -You can quickly write and see the resulting UMLs using -https://liveuml.com/, for the most part. - -** Clocking Work Time -:PROPERTIES: -:CUSTOM_ID: Clocking-Work-Time -:END: - -Let's keep track of the time we spend working on tasks that we may have captured -for ourselves the previous day. Such statistics provides a good idea of how -long it actually takes me to accomplish a certain task in the future and it lets -me know where my time has gone. - -+ Clock in :: on a heading with ~I~, or in the subtree with ~C-c C-x C-i~. -+ Clock out :: of a heading with ~O~, or in the subtree with ~C-c C-x C-o~. -+ Clock report :: See clocked times with ~C-c C-x C-r~. - -After clocking out, the start and end times, as well as the elapsed time, are -added to a drawer to the heading. We can punch in and out of tasks as many times -as desired, say we took a break or switched to another task, and they will all -be recorded into the drawer. - -#+begin_src emacs-lisp -;; Record a note on what was accomplished when clocking out of an item. -(setq org-log-note-clock-out nil) ;; I break tasks down & use C-c C-z, so no need for this anymore. -#+end_src - -To get started, we could estimate how long a task will take and clock-in; then -clock-out and see how long it actually took. - -# To review the day’s accomplishments, type ‘l’ -# (org-agenda-log-mode) from the agenda view. - -Sometimes, at the beginning at least, I would accidentally invoke the transposed -command ~C-x C-c~, which saves all buffers and quits Emacs. So here's a helpful -way to ensure I don't quit Emacs accidentally. -#+begin_src emacs-lisp -(setq confirm-kill-emacs 'yes-or-no-p) -#+end_src - -A few more settings: -#+begin_src emacs-lisp -;; Resume clocking task when emacs is restarted -(org-clock-persistence-insinuate) - -;; Show lot of clocking history -(setq org-clock-history-length 23) - -;; Resume clocking task on clock-in if the clock is open -(setq org-clock-in-resume t) - -;; Sometimes I change tasks I'm clocking quickly ---this removes clocked tasks with 0:00 duration -(setq org-clock-out-remove-zero-time-clocks t) - -;; Clock out when moving task to a done state -(setq org-clock-out-when-done t) - -;; Save the running clock and all clock history when exiting Emacs, load it on startup -(setq org-clock-persist t) - -;; Do not prompt to resume an active clock -(setq org-clock-persist-query-resume nil) - -;; Include current clocking task in clock reports -(setq org-clock-report-include-clocking-task t) -#+end_src - -*** Finding tasks to clock in -:PROPERTIES: -:CUSTOM_ID: Finding-tasks-to-clock-in -:END: -Use one of the following options, with the top-most being the first to be tried. -+ From anywhere, ~C-u C-c C-x C-i~ yields a pop-up for recently clocked in tasks. -+ Pick something off today's agenda scheduled items. -+ Pick a ~Started~ task from the agenda view, work on this unfinished task. -+ Pick something from the ~TODO~ tasks list in the agenda view. - -# Reporting activities -# C-c C-x i - -~C-c C-x C-d~ also provides a quick summary of clocked time for the current org file. - -*** Estimates versus actual time -:PROPERTIES: -:CUSTOM_ID: Estimates-versus-actual-time -:END: -Before clocking into a task, add to the properties drawer ~:Effort: 1:25~ or ~C-c -C-x C-e~, for a task that you estimate will take an hour and twenty-five minutes, -for example. Now the modeline will mention the time elapsed alongside the task -name. *Woah!* - -#+begin_src emacs-lisp - (push '("Effort_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00") - org-global-properties) -#+end_src - -#+begin_quote org -Use speed keys ~e/E~ to insert an effort estimate, with the above being provided - options, or to increment the current effort to the next one in the above list. -#+end_quote - -This is also useful when you simply want to put a time limit on a task that - wont be completed anytime soon, say writing a thesis or a long article, but - you still want to work on it for an hour a day and be warned when you exceed - such a time constraint. - - :Not_working_for_me: - Even if you switch tasks then clock into this task again, the alarm will ring - again, nagging you to actual listen to yourself and work on other matters. - - #+begin_src emacs-lisp -(setq org-clock-sound "~/.emacs.d/school-bell.wav") -#+end_src - :end: - - When you've gone above your estimate time, the modeline colours it red. - -** Habit Formation -:PROPERTIES: -:CUSTOM_ID: Habit-Formation -:END: - -/The/ reason to use habits is that they come with a graph indicating consistency -by colour, and the goal of the game is to have [[https://lifehacker.com/jerry-seinfelds-productivity-secret-281626][the longest possible chain]] ---no -red days! - -A ‘habit’ is a usual (recurring) task marked as a habit: -Use =C-c C-x p= to set the =STYLE= property to =habit= on a task to set it as a habit. - -#+BEGIN_SRC emacs-lisp -(require 'org-habit) ;; To actually see the consistency graph in org-agenda - -;; Show habits for every day in the agenda. -(setq org-habit-show-habits t) -(setq org-habit-show-habits-only-for-today nil) - -;; This shows the ‘Seinfeld consistency’ graph closer to the habit heading. -(setq org-habit-graph-column 90) - -;; In order to see the habit graphs, which I've placed rightwards, let's -;; always open org-agenda in ‘full screen’. -;; (setq org-agenda-window-setup 'only-window) - -(setq org-habit-completed-glyph ?😊) -(setq org-habit-today-glyph 33) - -;; When showing the agenda, do not collect habits together at the bottom, as is the default. -(add-to-list 'org-agenda-sorting-strategy '(agenda time-up priority-down category-keep)) -#+END_SRC - -| /inch by inch anything's a cinch!/ | - -~!~ means today and ~⋆~ means a task has been done on that day; -intuitively green means you're on track, yellow is warning sign of overdue, -red is overdue, and blue is an acceptable break day. - -# ! means today and * means a task has been done on that day. The color interpretation is intuitive: Green means on track, yellow warning sign of overdue, red overdue, and blue “still early, don’t feel bad taking a break”. -[[https://cpbotha.net/2019/11/02/forming-and-maintaining-habits-using-orgmode/org-habits-screenshot.png]] - -Here's an example habit from the [[https://orgmode.org/manual/Tracking-your-habits.html][Org-mode manual]], where ~.+𝒳d/𝒴d~ reads -/perform the habit once every 𝒳 days, but never let me go 𝒴 days without doing it./ -- (If you are procrastinating often, you can add a period in front of the - repeater, such as .+2d which will reschedule the completed item two days /after - it is completed/.) -#+begin_example org -,** TODO Shave - SCHEDULED: <2020-01-08 Wed .+2d/4d> - :PROPERTIES: - :STYLE: habit - :END: -#+end_example -/Shave every 2 days, but we can take a 3-day break; however, on the 4th day, -gotta shave!/ (To “ignore” a habit, just reschedule it for another day.) - -Remember that in the agenda view if you alter a task, say with ~t~ to mark it -done, then you need to use ~s~ to save the underlying todo/notes files; otherwise, -any ~g~ will revert the change in the agenda buffer. - -Habits are about “getting a little bit better at being alive, every day”. -- I don't mark habits with =TODO= so that they don't clutter up by Org-Agenda - Todos List, =C-c a t=. However, I still press ~t~ and set them to ~DONE~ and see a - message indicating that they're now rescheduled for a future time. - # (If you use ~t~ on a habit headline and mark it as ~Done~, you'll see that it - # briefly toggles to ~DONE~ and then automatically switches back to ~TODO~.) - - When this happens, the :LAST_REPEAT: timestamp will be automatically updated - to the current time, and, more importantly, the SCHEDULED date will be - automatically updated to the next earliest date when this habit should be - exercised. - - Habits appear grey in the agenda view, so that the non-habits stick out, and - hopefully in-time the habits become second nature and no longer need to be - in my agenda ---or at least, require little thought (which is happening with - the aid of checklists for my habits). - -/People underestimate what can be done if you have a spare hour./ - -** Keep agenda in view, so I don't get distracted from the day's goals -[[https://orgmode.org/worg/org-hacks.html#orgdabf067:~:text=This%20keeps%20my%20tasks%20%22always%20in%20mind%22%20whenever%20I%20come%20back%20to%20Emacs%20after%20doing%20something%20else][Source]] - -#+begin_src emacs-lisp -(defun jump-to-org-agenda () - (interactive) - (let ((buf (get-buffer "*Org Agenda*")) - wind) - (if buf - (if (setq wind (get-buffer-window buf)) - (select-window wind) - (if (called-interactively-p) - (progn - (select-window (display-buffer buf t t)) - (org-fit-window-to-buffer) - ;; (org-agenda-redo) - ) - (with-selected-window (display-buffer buf) - (org-fit-window-to-buffer) - ;; (org-agenda-redo) - ))) - (call-interactively 'org-agenda-list))) - ;;(let ((buf (get-buffer "*Calendar*"))) - ;; (unless (get-buffer-window buf) - ;; (org-agenda-goto-calendar))) - ) - -(run-with-idle-timer 300 t 'jump-to-org-agenda) -#+end_src -*** Actually Doing Things ---or /Sending notifications from Emacs/ -:PROPERTIES: -:CUSTOM_ID: Actually-Doing-Things -:END: - -Let's setup a little audio-visual reminder to regularly check my agenda -and ensure I'm not narrowing on a single task and ignoring others. - -+ More generally, we can use this snippet of code to let Emacs notify us of - other things. - -+ For instance, the doc:message function shows text in the minibuffer, which - might be missed when there are multiple incoming messages or focus is on a - non-Emacs application (gasp!). Then, doc:my/notify could be used to produce - MacOS system-wide notifications. - -The [[https://askubuntu.com/a/501917][text-to-speech tool]] we'll use is ~say~; which [[https://www.lifewire.com/mac-say-command-with-talking-terminal-2260772#:~:text=In%20the%20left%20pane%2C%20select,voices%20your%20Mac%20can%20use.][on a Mac can be activated]] -in a browser: Select some text, right-click, select ~Speech~, then ~Start/Stop Speaking~. -- TODO: Make the command below randomly use an English speaking voice; “tldr say” to learn more. -- TODO: Also finish reading the above mentioned links, with nice examples. - -#+begin_src emacs-lisp -;; Obtain a notifications and text-to-speech utilities -(system-packages-ensure "say") ;; Built-into MacOS, but can be downloaded in Ubuntu -(system-packages-ensure "terminal-notifier") ;; MacOS specific -;; System Preferences → Notifications → Terminal Notifier → Allow “alerts”. -;; E.g.,: (shell-command "terminal-notifier -title \"Hiya\" -message \"hello\"") -;; Ensure you're not in “Mac OS Focus” mode: https://cleanmymac.com/blog/notifications-not-showing-mac -#+end_src - -By default, notifications are in banner style ---they go away automatically--- -we can use alert style ---in which they stay until dismissed--- in MacOS as -follows: =System Preferences → Notifications → terminal-notifier → Alerts=. - -#+begin_src emacs-lisp -(cl-defun my/notify (message &key (titled "") at repeat-every-hour open) - "Notify user with both an visual banner, with a beep sound, and a text-to-speech recitation. - -When the user clicks on the resulting notification, unless a -given OPEN url is provided, the Emacs application is brough into -focus. - -MESSAGE and TITLE are strings; AT is a time string as expected of -`run-at-time' such as \"11.23pm\" or \"5 sec\"; REPEAT-EVERY-HOUR -is a floating-point number of hours to continuously repeat the -alert. OPEN is a URL that is opened when the user clicks the -notification. This can be a web or file URL, or any custom URL -scheme. - -I initially used optional arguments, but realised that in due time -it would be more informative to use named arguments instead. - -Example uses: - -;; In 5 minutes from now, remind me to watch this neato video! -(my/notify \"🔔 Get things done! 📎 💻 \" - :open \"https://www.youtube.com/watch?v=23tusPiiNZk&ab_channel=Motiversity\" - :at \"5 minutes\") - ;; :at \"5 sec\" - -;; Remind me to exercise every 1.5hours; starting at 8:00am. -(my/notify \"Take a 5min break and get your blood flowing!\" - :titled \"Exercise\" - :at \"8:00am\" - :repeat-every-hour 1.5) - -;; Actually getting things done! -(my/notify \"Is what you're doing actually in alignment with your goals? - Maybe it's time to do another task?\" - :titled \"Check your agenda!\" - :at \"10:00am\" - :repeat-every-hour 2) - -" - (run-at-time at ;; the time to make the alert - (when repeat-every-hour (* 60 60 repeat-every-hour)) - #'async-shell-command - (format "%s" (s-replace "\n" "" - (s-join " " (--map (format "%s" it) - `(terminal-notifier - -title ,(pp-to-string titled) - -message ,(s-replace "\\n" "\n" (pp-to-string message)) - ;; Play a random sound when the notification appears. See sound names with: ls /System/Library/Sounds - ;; Use the special NAME “default” for the default notification sound. - -sound ,(progn (require 'seq) (seq-random-elt (s-split "\n" (shell-command-to-string "ls /System/Library/Sounds")))) - ;; Don't create duplicates of the notification, just one instance; - ;; i.e., each notification belongs to a group and only one alert of the group may be present at any one time. - -group ,(pp-to-string titled) - ;; Activate the application specified by ID when the user clicks the notification. - -activate org.gnu.Emacs - ,@(when open `(-open ,(pp-to-string open))) - ;; Run the shell command COMMAND when the user clicks the notification. - ;; -execute COMMAND - & ;; … and then speak! … - ;; NOTE:This was getting annyoning in the middle of work meetings. - say ,(s-replace "\\n" " " (pp-to-string message)) - ))))))) -#+end_src - -#+RESULTS: -: my/notify - -The following two actual uses cases are also mentioned in doc:my/notify -docstring, since I want the documentation to be self-contained. -#+begin_src emacs-lisp -;; (Emojis look terrible in Lisp; but much better when the alert is actually made!) - -;; Remind me to exercise every 1.5hours; starting at 8:00am. -(my/notify "Take a 5min break and get your blood flowing!\n\t\t🚣 🏃‍♂️ 🧗‍♂️ 🧘‍♂️ 🏊 🏋 🚴‍♂️" - :titled "🤾‍♀️ Exercise 🚵‍♂️" - :at "8:00am" - :repeat-every-hour 1.5 - :open "https://www.youtube.com/watch?v=23tusPiiNZk&ab_channel=Motiversity") - -;; Actually getting things done! -(my/notify "Is what you're doing actually in alignment with your goals? ✔️📉 - Maybe it's time to do another task? 📋" - :titled "📆 Check your agenda! 🔔" - :at "10:00am" - :repeat-every-hour 2) -#+end_src - -+ [[https://emacs.stackexchange.com/questions/3844/good-methods-for-setting-up-alarms-audio-visual-triggered-by-org-mode-events][Here]] is an approach to triggering audio-visual alarms from Org-mode events - ---using ~org-agenda-to-appt~. - -+ Emacs's built in [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Appointments.html][appointment notification facility]] can also be used as a alarm - clock via ~M-x appt-add~. - -The [[https://github.com/jcs-elpa/marquee-header][marquee-header]] package let's show messages as “horizontal moving text along -the top of the Emacs frame”, which is neat. -- Slightly related is [[https://github.com/jcs-elpa/logms][logms]], which let's us make ~message~ calls but we can also - /see/ the context/source where those calls were made; as well as a clickable - link back to the source. - -================================================================================ - -#+begin_src emacs-lisp -;; Provides notifications for scheduled or deadlined agenda entries. -(use-package org-alert - :config - (setq org-alert-interval 300 - org-alert-notify-cutoff 10 - org-alert-notify-after-event-cutoff 10) - (org-alert-enable)) - -(use-package alert - :config (setq alert-default-style 'osx-notifier)) - -(alert "HELLO") - -(my/notify "🔔 Get things done! 📎 💻 " - :open "https://www.youtube.com/watch?v=23tusPiiNZk&ab_channel=Motiversity" - :at "1 sec") -#+end_src - -** Using Gnus for Gmail :Disabled: -:PROPERTIES: -:CUSTOM_ID: Using-Gnus-for-Gmail -:header-args: :tangle no -:END: - -:Alread_done_elsewhere: -Let's set the following personal Emacs-wide variables ---to be used in other -locations besides email. - -#+begin_src emacs-lisp -(setq user-full-name "Musa Al-hassy" - user-mail-address "alhassy@gmail.com") -#+end_src - -For some fun, run this cute method. -#+BEGIN_SRC emacs-lisp :tangle no -(animate-birthday-present user-full-name) -#+END_SRC -:End: - -By default, in Emacs, we may send mail: Write it in Emacs with ~C-x m~ ---or -doc:compose-mail---, then press ~C-c C-c~ to have it sent via your OS's default -mailing system ---mine appears to be Gmail via the browser. Or cancel sending -mail with ~C-c C-k~ ---the same commands for org-capturing, discussed earlier -(•̀ᴗ•́)و - -Folowing [[https://eschulte.github.io/emacs24-starter-kit/starter-kit-gnus.html][this tutorial]], to send and read email in Emacs we use [[https://en.wikipedia.org/wiki/Gnus][GNUS]], which, like -GNU itself, is a recursive acronym: GNUS Network User Service. - - 1. Execute, rather place in your init: - #+begin_src emacs-lisp - (setq message-send-mail-function 'smtpmail-send-it) - #+end_src - Revert to the default OS mailing method by setting this variable to - ~mailclient-send-it~. - - # (gnutls-available-p) - - 2. Follow only the [[https://www.emacswiki.org/emacs/GnusGmail#toc1][quickstart here]]; namely, make a file named ~~/.gnus~ containing: - #+begin_src emacs-lisp :tangle ~/.gnus -;; user-full-name and user-mail-address should be defined - -;; Get mail using port 993/IMAP/“Internet Message Access Protocol” -(setq gnus-select-method - '(nnimap "gmail" - (nnimap-address "imap.gmail.com") - (nnimap-server-port 993) - (nnimap-stream ssl))) - -;; Send mail using port 587/SMTP/“Simple Mail Transfer Protocol” -(setq message-send-mail-function 'smtpmail-send-it - smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil)) - smtpmail-auth-credentials '(("smtp.gmail.com" 587 "alhassy@gmail.com" nil)) - smtpmail-default-smtp-server "smtp.gmail.com" - smtpmail-smtp-server "smtp.gmail.com" - smtpmail-smtp-service 587) - #+end_src - # (system-packages-install "starttls") - # (setq gnus-ignored-newsgroups "^to\.\|^[0-9. ]+\( \|$\)\|^["]"[#'()]") - - 3. Get an email password for GNUS: - 1. Go to https://myaccount.google.com/security. - 2. Enable ~2-Step Verification~ - 3. Click on ~App passwords~, login, then generate a new password - with, say, name ~Emacs Gnus~. - 4. You will then obtain a secret password, the ~x~ marks below, which you insert - in a file named ~~/.authinfo~ as follows ---using your email address. - #+begin_src shell :tangle no - ​machine smtp.gmail.com login alhassy@gmail.com password xxxxxxxxxxxxxxxx port 587 - ​machine imap.gmail.com login alhassy@gmail.com password xxxxxxxxxxxxxxxx port 993 - default login alhassy@gmail.com password xxxxxxxxxxxxxxxx - #+end_src - - 4. In Emacs, ~M-x gnus~ to see what's there. - - - Or compose mail with ~C-x m~ then send it with ~C-c C-c~. - - Press ~C-h m~ to learn more about message mode for mail composition; or - read the [[https://www.gnus.org/manual/message.pdf][Message Manual]]. - - Only news groups with /unread mail/ are shown; to see all your groups (Gmail - ‘tags’), press ~A A~ (doc:gnus-group-list-active), then press ~u~ to toggle - (un)subscription to such groups and they will show up in the main group - buffer ---if they have /unread mail/. See [[https://sachachua.com/blog/2008/05/emacs-gnus-organize-your-mail/][here]] for a tutorial on splitting - mail groups, automatically or fancily filing them away. - --------------------------------------------------------------------------------- - -#+BEGIN_SRC emacs-lisp -;; After startup, if Emacs is idle for 10 seconds, then start Gnus. -;; Gnus is slow upon startup since it fetches all mails upon startup. -(when my/personal-machine? - (run-with-idle-timer 10 nil #'gnus)) -#+END_SRC - -Learn more by reading [[https://www.gnu.org/software/emacs/manual/html_mono/gnus.html#Top][The Gnus Newsreader Manual]]; also available within Emacs by -~C-h i m gnus~ (•̀ᴗ•́)و - -- Or look at the [[https://www.gnu.org/software/emacs/refcards/pdf/gnus-refcard.pdf][Gnus Reference Card]]. -- Or, less comprehensively, this [[https://github.com/redguardtoo/mastering-emacs-in-one-year-guide/blob/master/gnus-guide-en.org#subscribe-groups][outline]]. -- [[https://www.emacswiki.org/emacs/GnusTutorial][EmacsWiki]] has a less technical and more user friendly tutorial. -- Other possibly useful links: - + [[http://www.cataclysmicmutation.com/2010/11/multiple-gmail-accounts-in-gnus/][Multiple Gmail accounts in Gnus]] - --------------------------------------------------------------------------------- - -#+begin_details Super Terse Tutorial - -link-here:Super-Terse-Tutorial - - - ⟨ See the [[https://www.gnu.org/software/emacs/refcards/pdf/gnus-refcard.pdf][GNUS Reference Card]]! ⟩ - -In gnus, by default items you've looked at disappear ---i.e., are archived. -They can still be viewed in, say, your online browser if you like. -In the ~Group~ view, ~R~ resets gnus, possibly retriving mail or alterations -from other mail clients. ~q~ exits gnus in ~Group~ mode, ~q~ exits the particular -view to go back to summary mode. Only after pressing ~q~ from within a group -do changes take effect on articles ---such as moves, reads, deletes, etc. - -+ Expected keys: ~RET~ enter/open an item, ~q~ quit and return to previous view, ~g~ - refresh view ---i.e., ‘g’et new articles. - -+ =RET=: Enter a group by pressing, well, the enter key. - - Use ~SPC~ to open a group and automatically one first article there. - - Use ~C-u RET~ to see all mail in a folder instead of just unread mail. - -+ Only groups/folders with unread mail will be shown, use ~L/l~ to toggle between - listing all groups. - -+ ~SPC, DEL~ to scroll forward and backward; or ~C-v, M-v~ as always. - -+ =G G=: Search mail at server side in the group buffer. - - Limit search to particular folders/groups by marking them with ~#~, or - unmarking them with ~M-#~. - -+ ~/ /,a:~ Filter mail according to subject or author; there are many - other options, see [[https://www.gnu.org/software/emacs/manual/html_mono/gnus.html#Limiting][§3.8 Limiting]]. - -+ =d=: Mark an article as done, i.e., read it and it can be archived. - -+ =!=: Mark an article as read, but to be kept around ---e.g., you have not - replied to it, or it requires more reading at a later time. - - This lets us read mail offline; cached mail is found at =~/News/cache/=. - - #+BEGIN_SRC emacs-lisp :tangle "~/.gnus" - (setq gnus-use-cache 'use-as-much-cache-as-possible) -#+END_SRC - -+ =B m=: Move an article, in its current state, to another group ---i.e., - ‘label’ using Gmail parlance. - - - Something to consider doing when finished with an article. - - To delete an article, simply move it to ‘trash’ ---of course this will delete it - in other mail clients as well. There is no return from trash. - - Emails can always be archieved ---never delete, maybe? - - Anyhow, ~B m Trash~ is too verbose, let's just use ~t~ for “trash”: - #+BEGIN_SRC emacs-lisp -(with-eval-after-load 'gnus - (bind-key "t" - (lambda (N) (interactive "P") (gnus-summary-move-article N "[Gmail]/Trash")) - gnus-summary-mode-map)) - -;; Orginally: t ⇒ gnus-summary-toggle-header -#+END_SRC - - - Select and deselect many articles before - moving them by pressing ~#~ and ~M-#~, respectively, anywhere on the entry. - - - As usual, you can mark a region, =C-SPC=, then move all entries therein. - -+ =R, r=: Reply with sender's quoted text in place, or without but - still visible in an adjacent buffer. - - Likewise ~S W~ or ~S w~ to reply all, ‘wide reply’, with or without quoted text. - - ~C-c C-z~ Delete everything from current position till the end. - - ~C-c C-e~ Replace selected region with ‘[...]’; when omitting parts of quoted text. - -+ Press ~m~ to compose mail; or ~C-x m~ from anywhere in Emacs to do so. - - ~C-c C-c~ to send the mail. - - ~S D e~ to resend an article as new mail: Alter body, subject, etc, before - - ~C-c C-f~ to forward mail. - sending. - -+ ~C-c C-a~ to attach a file; it'll be embedded in the mail body as plaintext. - - Press ~o~ on an attachment to save it locally. -#+end_details - -#+begin_details GNUS Prettifications - -link-here:gnus-prettifications - -Let's add the icon  near my mail groups ^_^ -#+BEGIN_SRC emacs-lisp -;; Fancy icons for Emacs -;; Only do this once: -(use-package all-the-icons - :config (all-the-icons-install-fonts 'install-without-asking)) - -;; Make mail look pretty -(use-package all-the-icons-gnus - :disabled t - :config (all-the-icons-gnus-setup)) - -;; While we're at it: Make dired, ‘dir’ectory ‘ed’itor, look pretty -(use-package all-the-icons-dired - :disabled t - :hook (dired-mode . all-the-icons-dired-mode)) -#+END_SRC - -Next, let's paste in some [[http://groups.google.com/group/gnu.emacs.gnus/browse_thread/thread/a673a74356e7141f][eye-candy for Gnus]]: -#+begin_src emacs-lisp -(setq gnus-sum-thread-tree-vertical "│" - gnus-sum-thread-tree-leaf-with-other "├─► " - gnus-sum-thread-tree-single-leaf "╰─► " - gnus-summary-line-format - (concat - "%0{%U%R%z%}" - "%3{│%}" "%1{%d%}" "%3{│%}" - " " - "%4{%-20,20f%}" - " " - "%3{│%}" - " " - "%1{%B%}" - "%s\n")) -#+end_src -#+end_details - -#+begin_details "Sending Mail with Lisp ---e.g., as a Bulk Mailer" -link-here:bulk-mailer -#+begin_src emacs-lisp :results replace :wrap template -(defun my/email (to subject body) - (compose-mail to subject) - (insert body) - (message-send-mail) ;; Appends info to the message buffer - ; (let ((kill-buffer-query-functions nil)) (kill-this-buffer)) - (ignore-errors (undo)) ;; Undo that addition - (message-kill-buffer) - (message "Send email to %s" to)) ;; Close that message buffer -#+end_src - -#+begin_src emacs-lisp :results replace :wrap template :tangle no -;; Example -(my/email (format "%s <%s>" user-full-name user-mail-address) ;; To - "Test" ;; Subject - "Why hello there!") ;; Email body -#+end_src -#+end_details - -#+begin_details [Disabled] Auto-completing mail addresses - -# :CUSTOM_ID: Auto-completing-mail-addresses - -In order to get going quickly, using [[https://github.com/redguardtoo/gmail2bbdb][gmail2bbdb]], let's convert our Gmail -contacts into a BBDB file ---the [[http://bbdb.sourceforge.net/][Insidious Big Brother Database]] is an -address-book application that we'll use for E-mail; if you want to use it as a -address-book application to keep track of contacts, notes, their organisation, -etc, then consider additionally installing [[https://github.com/emacs-helm/helm-bbdb][helm-bbdb]] which gives a nice menu -interface. - - - From the [[https://www.google.com/contacts][Gmail Contacts page]], obtain a =contacts.vcf= file by clicking “More -> - Export -> vCard format -> Export”. -- Run command =M-x gmail2bbdb-import-file= and select =contacts.vcf=; a ~bbdb~ file - will be created in my Dropbox folder. -- Press ~C-x m~ then begin typing a contact's name and you'll be queried about - setting up BBDB, say yes. - -#+begin_src emacs-lisp :tangle no -(use-package gmail2bbdb - - :custom (gmail2bbdb-bbdb-file "~/Dropbox/bbdb")) - -(use-package bbdb - :after company ;; The “com”plete “any”thig mode is set below in §Prose - :hook (message-mode . bbdb-insinuate-gnus) - (gnus-startup-hook . bbdb-insinuate-gnus) - :custom (bbdb-file gmail2bbdb-bbdb-file) - (bbdb-use-pop-up t) ;; allow popups for addresses - :config (add-to-list 'company-backends 'company-bbdb)) - #+end_src - -Here is an [[http://emacs-fu.blogspot.com/2009/08/managing-e-mail-addresses-with-bbdb.html][emacs-fu]] article on managing e-mail addressed with bbdb. -#+end_details - -#+begin_details [Disabled] Feeds to Blogs -link-here:gnus-feeds-to-blogs -One can easily subscribe to an RSS feed in Gnus: Just press ~G R~ in the group -buffer view, then follow the prompts. However, doing so programmatically is much -harder. Below is my heartfelt attempt at doing so ---if you want a feed reader -in Emacs that “just works”, then [[https://github.com/skeeto/elfeed][elfeed]] is the way to go. When all is said and -done, the code below had me reading Gnus implementations and led me to conclude -that /Gnus has a great key-based interface but a /poor programming interface/ ---or -maybe I need to actually read the manual instead of frantically consulting -source code. - -My homemade hack to getting tagged feeds programmatically into Gnus. -#+begin_src emacs-lisp :tangle no -;; Always show Gnus items organised by topic. -(add-hook 'gnus-group-mode-hook 'gnus-topic-mode) - -;; From Group view, press ^, then SPC on Gwene, then look for the site you want to follow. -;; If it's not there, add it via the web interface http://gwene.org/ -(add-to-list 'gnus-secondary-select-methods '(nntp "news.gwene.org")) -;; -;; E.g., http://nullprogram.com/feed/ uses an Atom feed which Gnus does not -;; support natively. But it can be found on Gwene. - -(setq my/gnus-feeds - ;; topic title url - '(Emacs "C‘est La 𝒵" https://cestlaz.github.io/rss.xml - Emacs "Marcin Borkowski's Blog" http://mbork.pl?action=rss - Emacs "Howardism" http://www.howardism.org/rss.xml - Islam "Shia Islam Blogspot" http://welcometoshiaislam.blogspot.com/feeds/posts/default?alt=rss - Cats "Hedonistic Learning" http://www.hedonisticlearning.com/rss.xml - Cats "Functorial Blog" https://blog.functorial.com/feed.rss - Programming "Joel on Software" http://www.joelonsoftware.com/rss.xml - Haskell "Lysxia's Blog" https://blog.poisson.chat/rss.xml)) - -;; If fubared, then: -;; (ignore-errors (f-delete "~/News/" 'force) (f-delete "~/.newsrc.eld")) - -;; Execute this after a Gnus buffer has been opened. -(progn -(use-package with-simulated-input) -(cl-loop for (topic title url) - in (-partition 3 my/gnus-feeds) - ;; url & topic are symbols, make them strings. - for url′ = (symbol-name url) - for topic′ = (symbol-name topic) - ;; Avoid spacing issues by using a Unicode ghost space “ ”. - for title′ = (gnus-newsgroup-savable-name (s-replace " " " " title)) - for input = (format "C-SPC C-a %s RET RET" title′) - do - ; cl-letf* (((symbol-function 'insert) (lambda (x) nil))) ;; see the (undo) below. - ;; Add the group - (with-simulated-input input - (gnus-group-make-rss-group url′)) - ;; Ensure it lives in the right topic category. - (if (equal 'no-such-topic (alist-get topic gnus-topic-alist 'no-such-topic nil #'string=)) - (push (list topic′ title′) gnus-topic-alist) ;; make topic if it doesnt exist - (setf (alist-get topic′ gnus-topic-alist 'no-such-topic nil #'string=) - (cons title′ (alist-get topic gnus-topic-alist 'no-such-topic nil #'string=))))) - ;; Acknowledgement - (message "Now switch into the GNUS group buffer, and refresh the topics; i.e., t t.")) - - ;; The previous command performs an insert, since it's intended to be interactively - ;; used; let's undo the insert. - ; (undo-only) - -;; (setq gnus-permanently-visible-groups ".*") -;; -;; Show topic alphabetically? The topics list is rendered in reverse order. -;; (reverse (cl-sort gnus-topic-alist 'string-lessp :key 'car)) -#+end_src - -Ironically, I've decide that “no, I do not want to see my blogs in Emacs” for -the same reasons I do not activelly use ~M-x eww~ to browse the web in Emacs: I -like seeing the colours, fonts, and math symbols that the authours have labored -over to producing quality content. Apparently, I'm shallow and I'm okay with it ----but not that shallow, since I'm constantly pushing Emacs which looks ugly by -default but it's unreasonably powerful. -#+end_details -*** Capturing Mail as Todo/Notes -:PROPERTIES: -:CUSTOM_ID: Capturing-Mail-as-Todo-Notes -:END: - -Sometime mail contains useful reference material or may be a self-contained -task. Rather than using our inbox as a todo-list, we can copy the content of the -mail and store it away in our todos/notes files. [[#Capturing-ideas-notes-without-interrupting-the-current-workflow][Capturing]], above, is a way to, -well, capture ideas and notes /without/ interrupting the current workflow. Above, -in the section on capturing, we define doc:my/org-capture-buffer which quickly -captures the contents of the current buffer as notes to store away. We use that -method in the article view of mail so that [[kbd:c]] captures mail content with the -option to provide additional remarks, and [[kbd:C]] to silently do so without -additional remarks. - -#+BEGIN_SRC emacs-lisp -(with-eval-after-load 'gnus - ;; Orginally: c ⇒ gnus-summary-catchup-and-exit - (bind-key "c" #'my/org-capture-buffer gnus-article-mode-map) - ;; Orginally: C ⇒ gnus-summary-cancel-article - (bind-key "C" - (lambda (&optional keys) - (interactive "P") (my/org-capture-buffer keys 'no-additional-remarks)) - gnus-article-mode-map)) -#+END_SRC - -Gnus’ default =c= only enables a bad habit: Subscribing to stuff that you don't -read, since you can mark all entries as read with one key. We now replace it -with a ‘c’apturing mechanism that captures the current message as a todo or note -for further processing. Likewise, the default =C= is to cancel posting an article; -we replace it to be a /silent capture: Squirrel away informative mail content -without adding additional remarks./ -*** Email contacts -:PROPERTIES: -:CUSTOM_ID: Email-contacts -:END: - -I have a personal file, ~contacts.org~, with Emacs Lisp src blocks contributing to -a list variable ~my/contacts~. This list consists of entries of the shape: -#+begin_src emacs-lisp :tangle no -(:name "Jasim Jasonsama" :phone 123-455-4321 :email bobert_billiam@emacsmail.com) -#+end_src - -With the following snippet, I can write ~contacts~ then kbd:TAB to select a -personal contact. -#+begin_src org :noweb-ref templates-from-other-places-in-my-init :tangle no :comments none -,** contacts: Get the email of one of my personal contacts - -${1:`(and (or (featurep 'my/contacts) (org-babel-load-file "~/Dropbox/contacts.org")) -(yas-choose-value (--map (format "%s <%s>" (getf it :name) (getf it :email)) -my/contacts)))`} $0 -#+end_src - -** [[https://github.com/sabof/stripe-buffer][Add stripes to "list" buffers]] -:PROPERTIES: -:CUSTOM_ID: https-github-com-sabof-stripe-buffer-Add-stripes-to-list-buffers -:END: - -#+begin_src emacs-lisp -;; Make every other line of a buffer grey (or whatever you like). -;; Useful for buffers that list things. -;; I want it to make my Org tables look nice. Even better when org-modern is activated. -(use-package stripe-buffer - :defer 100 - :config (add-hook 'org-mode-hook 'turn-on-stripe-table-mode)) -#+end_src - -** Basic Agenda Config -#+begin_src emacs-lisp -(setq org-agenda-files (list "~/Documents/notes.org")) - -(setq org-agenda-span 'week) - -;; (setq org-agenda-custom-commands '(("o" "Open Loops" tags-tree "TODO=\"STARTED\"" ))) - -(setq org-log-into-drawer t) ;; hide the log state change history a bit better - - -;; Quick key to go to the currently clocked-in entry, or to the most recently clocked one. -;; With prefix arg, offer recently clocked tasks for selection. -(bind-key* "C-c SPC" - (lambda (&optional prefix) - (interactive) - (org-clock-goto prefix) - (org-narrow-to-subtree))) - - -(setq org-fold-catch-invisible-edits 'show-and-error ;; Avoid accidental edits to folded sections - org-special-ctrl-a/e t ;; C-a/C-e know about leading “*” and ending :tags: - ;; Agenda styling - org-agenda-tags-column -80 - org-agenda-time-grid '((daily today require-timed) - (800 1000 1200 1400 1600 1800 2000) - " ───── " "───────────────") - org-agenda-current-time-string "◀── now ─────────────────────────────────────────────────") - -;; p to “p”ush back a task to the next day. -(add-hook 'org-agenda-mode-hook - ;; Note: There's also org-agenda-date-earlier to change the date by -1 day. - (lambda () - (define-key org-agenda-mode-map "p" 'org-agenda-date-later) - - ;; Reschedule agenda items to today, “right 𝓃ow”, with a single command - (define-key org-agenda-mode-map "n" (defun org-agenda-reschedule-to-today () - (interactive) - (flet ((org-read-date (&rest rest) (current-time))) - (call-interactively 'org-agenda-schedule)))))) -#+end_src - -** Informative [[https://arc.net/l/quote/jhczngfy][log notes]] - -Let's change only two pieces, to make them more informative. -#+begin_src emacs-lisp -;; Relevant function is “C-c C-z”. -;; -;; In Org-Agenda, “l” to see top-level clocked in/out logs. -;; On a given item, press “L” to see its note logs. -;; -;; Or, just “v L” to see all logged notes in the agenda view. -;; -(setq org-log-note-headings '((done . "CLOSING NOTE %t") - (state . "State %-12s from %-12S %t") - (note . "%t") - ;; (reschedule . "Rescheduled from %S on %t") ;; Default - (reschedule . "Schedule changed on %t: %S -> %s") - (delschedule . "Not scheduled, was %S on %t") - (redeadline . "Deadline changed on %t: %S -> %s") - ;; (redeadline . "New deadline from %S on %t") ;; Default - (deldeadline . "Removed deadline, was %S on %t") - (refile . "Refiled on %t") - (clock-out . ""))) - - -;; Remove the “\\\n” added to the end of notes. -(advice-add 'org-store-log-note :after - (cl-defun remove-\\ (&rest _) (org-narrow-to-subtree) (replace-in-buffer "\\\\\\\\\n" "") (widen))) -#+end_src - - -** COMMENT See all motivational images I have, and indent things so it's clearer when something is a child of something else - -TODO: Causes weird max-image-size issues? - -#+begin_src emacs-lisp -(defun my/org-settings () - (org-display-inline-images) - (org-indent-mode) - nil) - -(add-hook 'org-mode-hook #'my/org-settings) -#+end_src - -** COMMENT org-num-mode :SeemsTooBrokenForMe: -#+begin_src emacs-lisp -;; Please dynamically number all headlines -(setq org-startup-numerated t) - ;; More options @ https://orgmode.org/manual/Dynamic-Headline-Numbering.html - -;; Prefer “𝓏” instead of “𝓍.𝓎.𝓏” ---indentation ‘org-indent-mode’ resolves ambiguity -(setq org-num-format-function (defun my/org-num-format (number-path) (format "%s " (car (last number-path))))) -#+end_src - -** How tasks look in org agenda -#+begin_src emacs-lisp -;; Start each agenda item with ‘○’, then show me it's %timestamp and how many -;; times it's been re-%scheduled. -(setq org-agenda-prefix-format " ○ %?-12t%-6e%s ") - -;; (setq org-agenda-deadline-leaders '("DUE: " "In %3d d.: " "%2d d. ago: ")) - -;; Don't say “Scheduled ⟨Task⟩”, just show “⟨Task⟩”. -;; If something's overdue, say “Overdue 𝓃× ⟨Task⟩”. -(setq org-agenda-scheduled-leaders '("" "Overdue%2dx ")) -#+end_src - -** I use lots of “checkbox lists” in my routines: I want to think about things once, then follow the routine on auto-pilot -#+begin_src emacs-lisp -;; list items will be treated like low-level headlines; i.e., folded by default. -(setq org-cycle-include-plain-lists 'integrate) - -;; clear checkbox when repeating a todo task -(add-hook 'org-todo-repeat-hook #'org-reset-checkbox-state-subtree) - -;; clear sub-sub-tasks when repeating a todo task. -;; ⇒ If I have “** A [%] \n #+STYLE: habit \n SCHEDULED: <2024-04-19 Fri .+1d> \n *** DONE B” -;; then on “** A” I press ‘t’ then mark it as ‘DONE’, then the “*** B” task resets to ‘TODO’. -;; -;; In particular, sometimes I have reference/posterity info “*** something to remember” which need not be marked TODO/DONE, -;; since it has no todo state, it is not impacted by this hook. Notable example includes “** Review feedback :drill: \n *** Fact 1 \n *** Fact 2” -;; using: M-x org-drill-tree. -(add-hook 'org-todo-repeat-hook - (lambda () (org-map-entries (lambda () (when (and (> (length (org-get-outline-path)) 1) (equal (org-get-todo-state) "DONE")) (org-todo "TODO"))) t 'tree))) - - -;; If current day is Sat/Sun, then schedule to the next upcoming monday (but retain time hours). -;; TODO: Maybe only do this if an org entry has a property, say, “ :ONLY_WEEKDAYS: t ” -(add-hook 'org-todo-repeat-hook - (lambda () (org-map-entries - (lambda () - (let* ((scheduled (date-to-time (org-entry-get (point) "SCHEDULED"))) - (day (format-time-string "%a" scheduled))) - (when (member day '("Sat" "Sun")) - (org-schedule nil (format-time-string "+1mon %T" scheduled)) - (message "Musa says this is a weekend-only habit (◕‿◕)")))) - t - 'tree))) - - -;; Run hooks “ON_[STARTED∣DONE]” state changes. -;; (MA: Consider adding “ON_𝒳” for all states 𝒳, using above workflow loop.) -;; (MA: Consider turning the example /below/ into a single property hook, say “:TEMPORARILY_TREAT_SUBTREES_AS_CHECKBOXES: t”) -;; -;; For example, in the following, when we press “t s” to put “A” into “STARTED A” the declared code is run: -;; It essentially treats all children trees, temporarily, as checkboxes: Pressing “t” toggles between “ ∣ TODO ∣ DONE” -;; and does not log any info about state change of the subtrees. (Also, the “STARTED A” is becomes “A”). -;; Then when we press “t” on “A” we get “DONE A”, which invokes the associated ON_DONE code, which just resets things to before -;; we began working on task “A”. -;; -;; ** A -;; :PROPERTIES: -;; :ON_STARTUP: (progn (if (search-forward-regexp org-todo-regexp nil t) (or (delete-region (match-beginning 0) (match-end 0)) t)) (setq remember/org-todo-keywords org-todo-keywords) (setq org-todo-keywords '("TODO" "DONE")) (setq remember/org-log-done org-log-done) (setq org-log-done nil) (org-mode-restart)) -;; :ON_DONE: (progn (setq org-todo-keywords remember/org-todo-keywords org-log-done remember/org-log-done) (org-mode-restart)) -;; :END: -;; -;; *** TODO B -;; -(add-hook 'org-after-todo-state-change-hook - (defun my/special-ON_STARTED-property-hook () - "When a task enters STARTED/DONE state, execute the code in its ON_STARTED/ON_DONE property." - (save-excursion - ;; yet another property support - (when (equal (org-get-todo-state) "TODO") - ;; Instead of ignore-errors, it should only evaluate the string /if/ it is present. - (ignore-errors (eval (car (read-from-string (eval (org-entry-get (point) "ON_TODO"))))))) - - ;; yet another property support - (when (equal (org-get-todo-state) "STARTED") - ;; Instead of ignore-errors, it should only evaluate the string /if/ it is present. - (ignore-errors (eval (car (read-from-string (eval (org-entry-get (point) "ON_STARTED"))))))) - - ;; yet another property support - (when (equal (org-get-todo-state) "DONE") - ;; Instead of ignore-errors, it should only evaluate the string /if/ it is present. - (ignore-errors (eval (car (read-from-string (eval (org-entry-get (point) "ON_DONE"))))))) - - ;; yet another property support -- AXE? - (when (equal "t" (org-entry-get (point) "TEMPORARILY_TREAT_SUBTREES_AS_CHECKBOXES")) - (when (equal (org-get-todo-state) "TODO") - (let ((current-prefix-arg :random-theme)) (my/toggle-theme)) - (org-narrow-to-subtree) - (beginning-of-buffer) - (setq remember/org-todo-keywords org-todo-keywords - org-todo-keywords '("TODO" "DONE") - remember/org-log-done org-log-done - org-log-done nil - remember/org-log-note-headings org-log-note-headings - org-log-note-headings nil) - (org-mode-restart)) - (when (or (equal (org-get-todo-state) "DONE") (equal (org-get-todo-state) "")) - (setq org-todo-keywords remember/org-todo-keywords - org-log-done remember/org-log-done - org-log-note-headings remember/org-log-note-headings) - (org-mode-restart)))))) - -;; “C-c a t” ⇒ List all (non-recurring non-someday) todos sorted by state, priority, effort -;; “C-c a a” ⇒ Daily agenda view, followed by unscheduled open loops -;; -;; Query Language :: https://orgmode.org/manual/Matching-tags-and-properties.html -;; For general-purpose SQL-like queries against all Org entries, consider using org-ql: https://github.com/alphapapa/org-ql -;; For example, to find all entries that have any timestamp in a given period. -;; Another example: Suppose you know that there is a “src” block you're looking for in your notes, but -;; you're not sure which entry it is in, you can use org-ql to find all entries that contain a “src” block. -;; Moreover, you can refine the query by considering only a specific time window, if the entry has any timestamp at all. - -;; You can even use org-ql in org-agenda-custom-commands! See https://github.com/alphapapa/org-ql/blob/master/examples.org#stuck-projects-block-agenda -;; or, even, better: https://www.reddit.com/r/emacs/comments/cnrt2d/comment/ewtqez8/ -;; That is, you can write SQL-like queries for your agenda, if you prefer. -;; Moreover, one could use org-ql-agenda as an alternative implementation of org-agenda, -;; but their are pros/cons to both, neither is strictly better: org-ql has better queries, org-agenda has different features (such as weekly view). ⟵ This might not be true anymore. -;; MA: I may switch to org-ql since org-ql-block is about 80% faster than org-agenda! -;; MA: Actually, no thanks: I dislike that my agenda is broken down my projects, I like the usual timebased grid ordering of org-agenda. -;; ⇒ This is the only blocker, if I can fix it, then I'd be happy to use org-ql / org-super-agenda. -;; ⇒ Note: Any use of org-ql in org-agenda-custom-commands actually recreates the agenda buffer from scratch: It's not what you get by calling classic org-agenda! -;; See: https://www.reddit.com/r/emacs/comments/cnrt2d/comment/ewhf0zj/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button -;; i.e., see org-super-agenda -(setq org-agenda-custom-commands - '(("t" "My list of all TODO entries" tags-todo "-recurring-someday+LEVEL=2" - ((org-agenda-overriding-header "\nTODOs sorted by state, priority, effort") - (org-agenda-sorting-strategy '(todo-state-down priority-down effort-up)) - (org-super-agenda-groups (progn (org-super-agenda-mode t) '( - (:name "Important" :and (:priority "A" :not (:todo ("DONE" "CANCELED")))) - (:name "Process your Inbox" :tag "inbox") - (:name "Approved" :todo "APPROVED") - (:name "Started" :todo "STARTED") - (:name "Waiting" :todo "WAITING") - (:name "Low Priority" :priority "C" :tag "maybe")))))) - ("w" "WAITING Tasks" - ((tags "todo=\"WAITING\"+LEVEL=2"))) - ;; To see EVERYTHING I've done, just press “C-c a a v w l” and it will activate logbook mode. - ;; - ;; This is a helpful view: - ;; As the week moves along, I know what I have left to do - ;; and can choose to /not/ do low-priority tasks, or to - ;; act as a motivator for me to work faster or focus better, etc. - ("a" "Daily Agenda; Productivity ≈ ♯DONE / ♯TASKS" - (;; TODO: MAYBE MOVE DOWN: (tags-todo "inbox" ((org-agenda-prefix-format " %?-12t% s") (org-agenda-overriding-header "\nProcess your Inbox\n"))) - (agenda "" ((org-agenda-span 'day) (org-agenda-overriding-header (progn (org-super-agenda-mode -1) "Please focus on 𝒪𝓃𝓁𝓎 these tasks for the day!")))) - ;; Show me deadline items grouped together - (agenda nil - ((org-agenda-entry-types '(:deadline)) - (org-agenda-format-date "") - (org-deadline-warning-days 7) - (org-agenda-show-all-dates nil) ;; Only show if there are actually entries - (org-agenda-skip-function - '(org-agenda-skip-entry-if 'notregexp "\\* NEXT")) - (org-agenda-overriding-header "\nDeadlines"))) - ;; What I've left to do is all incomplete tasks scheduled within the next 5-𝓃 days, where 𝓃 is the numeral of the current week day. - ;; ;; Mon=1, ⋯, Thu=4, ⋯ - (tags (with-today - ;; Add 1 to include tasks scheduled for today. - (format "-recurring-TODO=\"DONE\"+SCHEDULED>=\"<-%sd>\"+SCHEDULED<=\"<+%sd>\"" (1+ it) it)) - ((org-agenda-overriding-header "What I have left to do this week"))) - ;; Press E to toggle seeing ~5 lines of each entry; might be helpful for rescheduling or doing a task sooner. - ;; https://emacs.stackexchange.com/questions/41468/show-notes-in-org-mode-agenda - ;; - ;; What I've done so far is all tasks closed in the past 𝓃-days, where 𝓃 is the numeral of the current week day. - ;; ;; Mon=1, ⋯, Thu=4, ⋯ - (tags (with-today (format - ;; NOTE: AND “&” bindings tigher than OR “|”. - ;; TODO [LOW PRIORITY]: The second clause, on WAITING, should reference this week. E.g., state entered this week. - "-recurring&LEVEL=2&TODO=\"DONE\"&CLOSED>=\"<-%sd>\"|-recurring&LEVEL=2&TODO=\"WAITING\"" it)) - ((org-agenda-overriding-header "What I've done so far this week"))) - ;; Section on what I “Completed Today”. Not useful now in my life since I do 1 or do large non-recuring tasks per day. - ;; (tags "CLOSED>=\"\"" ((org-agenda-overriding-header "\nCompleted today\n"))) - (tags "-Someday+todo=\"STARTED\"" - ((org-agenda-overriding-header "Please 𝒓𝒆𝒅𝒖𝒄𝒆 the number of (unscheduled) open loops") - (org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled)))) - )))) - -(defmacro with-today (&rest body) - "Evaluate BODY which may mention `it' to refer to the numeral denoting today" - `(-let [it (calendar-day-of-week (calendar-current-date))] ,@body)) - -(with-today it) - -(setq org-agenda-span 'day) -#+end_src - -#+begin_src emacs-lisp -(defun replace-in-buffer (regexp replacement) - "Perform a regexp replace in the entire buffer." - (save-excursion - (goto-char (point-min)) - (while (re-search-forward regexp nil t) - (replace-match replacement)))) - -;; Press “?” on a leading headline star to see other speed commands. -;; -;; Press “d” to mark a task as DONE without logging any meta-data -(add-to-list 'org-speed-commands (cons "d" - (cl-defun my/mark-as-DONE-without-logging-meta-data () - (org-narrow-to-subtree) - (replace-in-buffer (concat "\\(^\\*+ \\)" org-todo-regexp "?") "\\1DONE") (widen) - (message "Nicely 𝑑𝑜𝑛𝑒!")))) -#+end_src - -#+RESULTS: -: ((d . my/mark-as-DONE-without-logging-meta-data) (f org-speed-move-safe 'org-forward-heading-same-level) (b org-speed-move-safe 'org-backward-heading-same-level) (F . org-next-block) (B . org-previous-block) (u org-speed-move-safe 'outline-up-heading) (j . org-goto) (g org-refile '(4)) (Outline Visibility) (c . org-cycle) (C . org-shifttab) ( . org-display-outline-path) (s . org-toggle-narrow-to-subtree) (k . org-cut-subtree) (= . org-columns) (Outline Structure Editing) (U . org-metaup) (D . org-metadown) (r . org-metaright) (l . org-metaleft) (R . org-shiftmetaright) (L . org-shiftmetaleft) (i progn (forward-char 1) (call-interactively 'org-insert-heading-respect-content)) (^ . org-sort) (w . org-refile) (a . org-archive-subtree-default-with-confirmation) (@ . org-mark-subtree) (# . org-toggle-comment) (Clock Commands) (I . org-clock-in) (O . org-clock-out) (Meta Data Editing) (t . org-todo) (, org-priority) (0 org-priority 32) (1 org-priority 65) (2 org-priority 66) (3 org-priority 67) (: . org-set-tags-command) (e . org-set-effort) (E . org-inc-effort) (W lambda (m) (interactive sMinutes before warning: ) (org-entry-put (point) APPT_WARNTIME m)) (Agenda Views etc) (v . org-agenda) (/ . org-sparse-tree) (Misc) (o . org-open-at-point) (? . org-speed-command-help) (< org-agenda-set-restriction-lock 'subtree) (> org-agenda-remove-restriction-lock)) - -** Work links -:PROPERTIES: -:CUSTOM_ID: my-work-links -:END: - -In my private ~work.el~ file, I have declarations of the form ~(my/work-links -"REPO" "https://⟨COMPANY⟩.atlassian.net/browse/REPO-%s")~ so that I can write -things like ~REPO:1234~ to get a nice green bold link in Org-mode that will take -me to that Jira link. I also have similar links to take me to the Github -repositories, backlogs, and Kanban boards. - -#+begin_src emacs-lisp - (cl-defmacro my/work-links (type url &optional (export-display '(format "%s-%s" type label))) - "Given a link of TYPE with a URL, produce the correct org-link. - - EXPORT-DISPLAY is string-valued term that may mention the symbolic names ‘type’ and ‘label’. - This is how the link looks upon export." - `(org-link-set-parameters - ,type - :follow (lambda (label) (browse-url (format ,url label))) - :export (lambda (label description backend) - (-let [full-url (format ,url label)] - (pcase backend - ('html (format "%s" full-url (-let [type ,type] ,export-display))) - ('latex (format "\\href{%s}{%s}" full-url label)) - (_ full-url)))) - :face '(:foreground "green" :weight bold - :underline "blue" :overline "blue"))) - #+end_src - -#+begin_src emacs-lisp -(defvar COMPANY (exec-path-from-shell-copy-env "COMPANY") - "Name of place I work at. - - It's setup in ~/.zshrc") -;; Note, “getenv” requires an Emacs restart if the shell vars changed /after/ starting Emacs. - -(my/work-links "FWD" (lf-string "https://bugs.local.${(downcase COMPANY)}.com/browse/FWD-%s")) -(my/work-links "OUT" (lf-string "https://bugs.local.${(downcase COMPANY)}.com/browse/OUT-%s")) -(my/work-links "gerrit" (lf-string "https://gerrit.local.${(downcase COMPANY)}.com/c/fwd/+/%s")) - -;; Open all such links in Chrome -(setq browse-url-browser-function 'browse-url-default-macosx-browser) -#+end_src -** Quick Capture - -#+begin_src elisp -;; Location of my todos / captured notes file -(setq org-default-notes-file "~/Documents/notes.org") -#+end_src - -#+begin_src elisp -(defmacro def-capture (name location template) -"Creates a method “my/capture-NAME”, which opens a capture buffer named NAME showing TEMPLATE. -When you press `C-c C-c`, the note is saved as an entry (ie TEMPLATE should start with “* ”.) -in `org-default-notes-file' section named LOCATION. - -+ NAME, LOCATION, TEMPLATE are all strings that may contain spaces. - ⇒ If you want to evaluate a function in TEMPLATE, use the syntax “%(f args)”. - See https://stackoverflow.com/a/69331239 for an example. -+ Example: (def-capture \"Friends Info\" \"Journal\" \"* %t\") - This can be used as “M-x my/capture-friends-info” or via an Org link: “[[elisp:( my/capture-friends-info)]]”. - - Note: My “Journal” is nested in a section called “Workflow”, and capture finds it anyways (。◕‿◕。) - (More precisely, Org-Capture looks for the first (sub)headline called “Journal” /anywhere/ and uses that as the target location.) - -Usage: -1. M-x my/capture-NAME ⇒ Capture something to my LOCATION; no menu used. -2. C-u M-x my/capture-NAME ⇒ Jump to my LOCATION. -3. C-u C-u M-x my/capture-NAME ⇒ Goto last note stored (by any my/capture-* method). -" - `(defun ,(intern (concat "my/capture-" (s-replace-regexp " " "-" (downcase name)))) (&optional prefix) - (interactive "p") - (-let [org-capture-templates - ;; I'm using omega 𝓌 as a placeholder; i.e., a gensym-like key. - `(("𝓌" ,,name entry (file+headline ,,org-default-notes-file ,,location) ,,template :clock-in t :clock-keep t))] - (org-capture (list prefix) "𝓌") - (unless (> prefix 1) (rename-buffer ,name))))) -#+end_src - -*** C-c c ⇒ Capture inbox entry -#+begin_src elisp -;; I mark inbox captures as “TODO” so that they appear in my task list (C-c a t) in the event -;; I've forgotten to process my inbox. -;; -;; When I process my “* Inbox” section, I am left with an empty Org section and so delete it. -;; ⇒ “C-c c” will create the section if it does not exist. -;; ⇒ Deleting it is a nice ‘cheery on top’ when processing my inbox (✿◠‿◠) -;; -;; The process of adding a task is very fast and non-disruptive to my work. The -;; capture template includes the date added. This is useful when reviewing tasks -;; to see how long the task has been on the list and if I have been -;; procrastinating. -(bind-key* "C-c c" (def-capture "Inbox Entry" "Inbox" "* TODO %?\n Captured: %U \n")) -#+end_src - -*** Capture morning journal entry -#+begin_src elisp -(defalias #'my/new-journal-entry (def-capture "Journal Entry" "Journal" - (s-join "\n\n" (list - (format-time-string "* %Y-%m-%d %a %R :mood_𝒏%?:") - "My most important goal for the day is: " - (let (todays-agenda) (org-agenda-list 1) (setq todays-agenda (buffer-string)) (org-agenda-quit) - (concat "Here's what my day looks like so far:\n" todays-agenda)))))) -#+end_src - -*** Capture evening journal entry -#+begin_src elisp -(def-capture "Daily Retrospective" "Journal" - (concat - ;; The “:mood_𝓃:” tag is so that I can easily see my moods across my entries. - ;; Keeping track of mood is a simple way to monitor success; e.g., whether GTD is working for me or not. - (format-time-string "* %Y-%m-%d %a %R :mood_%^{Mood at the end of the day?}:retro:daily:\n") -" -Instructions: Read section contents and replace them with your own words.%? - -,** Monitoring Mood For Success - - Why do I feel the way I do? - - 1 ≈ 😢 extremely negative; 5 ≈ :neutral_face: neutral; 10 ≈ 😁 extremely positive. - -,** Celebrating Successes - - Acknowledge and celebrate your achievements, no matter how small. - - Recognising your progress boosts morale and motivation, inspiring you to continue striving for success. - - /Give yourself credit for your efforts!/ - -,** Goal Alignment - - Were today's actions directed at achieving the sprint's goals? Stay focused! - - Review your day by reviewing the tasks you clocked into. - - %(let ((org-clock-clocktable-default-properties (-snoc org-clock-clocktable-default-properties :block 'today :timestamp 'nil))) (beginning-of-line) (kill-line) (org-clock-report)) - - - Set SMART goals for tomorrow. - -,** Stress Reduction - - Any challenges or frustrations encountered today? - -,** Continuous Improvement - - What went well, what didn't go as planned, and were there any unexpected challenges today? - - Learn from your experiences & brainstorm strategies better outcomes in the future. - - Consider what factors contributed to these challenges and how you responded to them. - - What thought patterns were influencing my outcomes? - -,** Express Gratitude - - Conclude your retrospective by expressing gratitude for the positive aspects of your day. - - Reflect on the people, opportunities, and experiences that brought you joy or fulfilment. -")) -#+end_src - -** org-clock-clocktable-default-properties and “my/what-did-i-work-on-this-week” - -#+begin_src emacs-lisp -;; This only works well if my tasks have timestamps; ie are scheduled ^_^ -(setq org-clock-clocktable-default-properties - '(:scope ("~/Documents/notes.org") ;; Consider the current file - :hidefiles t ;; Hide the file column when multiple files are used to produced the table. - :maxlevel 5 ;; Consider sub-sub-sections - :block lastweek ;; Only show me what I did last week - ;; Other values: 2024-04, lastmonth, yesterday, thisyear, 2024 - ;; :tstart "<-2w>" :tend "" ;; Show me the past two weeks - ;; :tstart "<2006-08-10 Thu 10:00>" :tend "<2006-08-10 Thu 12:00>" ;; Show me a particular range - :step day ;; Split the report into daily chunks - :formula % ;; Show me the percentage of time a task took relative to my day - :link t ;; Link the item headlines in the table to their origins - :narrow 55! ;; Limit the width of the headline column in the Org table - :tcolumns 1 ;; Show only 1 column ---not multiple, for the sections and subsections and etc. - :timestamp t ;; Show the timestamp, if any - :tags t ;; Do not show task tags in a column; I use mostly hierarchies for my tasks right now. - ;; :match "billable|notes-travel" ;; ⇒ Includes tags “billable” and “notes”, excludes tag “travel” - ;; More examples at: https://orgmode.org/manual/Matching-tags-and-properties.html#Matching-tags-and-properties - ;; For example, we can match tags & priority & todo states & property drawer values; “/DONE” matches all tasks with state being ‘DONE’. - :match "-OOO" ;; Exclude tasks tagged “OOO”, which means “Out of Office” ---e.g., taking a break, or praying, or out for an appointment. - ;; :formatter org-clocktable-write-default ;; This is the default way to print a table; it looks very long and annoying to change. - ;; :sort (3 . ?N) ;; Sort descendingly on time. Not ideal, since I'm very hierarchical. - )) -;; More properties at: https://orgmode.org/manual/The-clock-table.html -;; [Low Priority] Figure out whether I've underworked or overworked? ⇒ https://www.erichgrunewald.com/posts/how-i-track-my-hour-balance-with-a-custom-org-mode-clock-table/ - -;; I prefer “27h” over “1d 3h”. -(setq org-duration-format 'h:mm) - - - -;; In Org-agenda, press “v r” to view the clock report -;; (This method is invoked when you hit “v r” in Org-agenda.) -(defalias 'org-agenda-clockreport-mode 'my/what-did-i-work-on-this-week) - -(defun my/what-did-i-work-on-this-week () - (interactive) - (my/what-did-i-work-on - "*What Did I Work On This Week?*" - org-clock-clocktable-default-properties)) - -(defun my/what-did-i-work-on-today () - (interactive) - (my/what-did-i-work-on - "*What Did I Work on Today?*" - (-snoc org-clock-clocktable-default-properties :block 'today))) - -(defun my/what-did-i-work-on (buffer-title clocktable-properties) - (switch-to-buffer buffer-title) - (org-mode) - ;; (org-modern-mode) Tables don't look good with the unicode/timestamp svg - (-let [org-clock-clocktable-default-properties clocktable-properties] - (org-clock-report)) - ;; For some reason, some of org-modern carries from the current buffer to the new buffer. - (org-modern-mode +1) - (org-modern-mode -1) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward "\\\\_" nil t) - (replace-match "⇒") - (org-table-align)))) -#+end_src - -#+RESULTS: -: my/what-did-i-work-on - -** my/see-sorted-todos -#+begin_src elisp -(defun my/see-sorted-todos () - "See TODOs sorted by state, priority, then effort. - -This view shows me all tasks, sorted, and from there I can pick & schedule & edit as desired. - -Much nicer than me physically sorting tasks! - -The main benefit here is I can keep /active/ tasks under their -own disjoint ‘projects’, yet still have a nice unified view of -all of my /active/ *and* non-active tasks. - -⇒ You can mark DONE and archive from the sorted view. -⇒ But leave that to the Weekly Review, so that you can extract any - reference information or Lessons Learned out of the tasks to be archived. - -See: https://emacs.stackexchange.com/questions/9585/org-how-to-sort-headings-by-todo-and-then-by-priority -" - (interactive) - (let ((org-agenda-custom-commands '(("𝓌" nil todo "*" - ((org-agenda-overriding-header "\nTODOs sorted by state, priority, effort") - (org-agenda-sorting-strategy '(todo-state-down priority-down effort-up))))))) - (org-agenda nil "𝓌" t) - (beginning-of-buffer))) -#+end_src - * Lisp Programming :PROPERTIES: :CUSTOM_ID: Lisp-Programming diff --git a/yankpad.org b/yankpad.org index 900364e..e6e1d97 100644 --- a/yankpad.org +++ b/yankpad.org @@ -405,70 +405,4 @@ https://twitter.com/musa314 A Mechanisation of Internal Galois Connections In Order Theory Formalised Without Meets https://macsphere.mcmaster.ca/bitstream/11375/17276/2/thesis.pdf -** journal_guided: Introspection & Growth -I'm writing from ${1:location}. -Gut answer, today I feel ${2:scale}/10. -⇒ ${3:Few words or paragraphs to explain what's on your mind.} - -${4: All things which cause us to groan or recoil are part of the tax of -life. These things you should never hope or seek to escape. Life is a battle, -and to live is to fight. - -⟨ Press TAB once you've read this mantra. ⟩ -$(when yas-moving-away-p "") -} -`(progn - (eww "https://www.dailyinspirationalquotes.in/") - (sit-for 2) (when nil let eww load) - (read-only-mode -1) - (goto-line 52) - (kill-line) - (kill-buffer) - (yank))` -${7: -Self Beliefs: -+ I am working on a healthier lifestyle, including a low-carb diet. - - - I’m also investing in a healthy, long-lasting relationship. - - ➩ These are what I want and are important to me. ⇦ - -+ I will not use any substances to avoid real issues in my life. I must own them. - -+ Everything I’m searching for is already inside of me. - -+ Progress is more important than perfection. - -⟨ Press TAB once you've read these beliefs. ⟩ -$(when yas-moving-away-p "") -} - -*Three things I'm grateful for:* -1. ${8:??? … e.g., old relationship, something great yesterday, an opportunity I - have today, something simple near me within sight} -2. ${9:??? … e.g., old relationship, something great yesterday, an opportunity I - have today, something simple near me within sight} -3. ${10:??? … e.g., old relationship, something great yesterday, an opportunity I - have today, something simple near me within sight} - -*Three things that would make today great:* -1. ${11:???} -2. ${12:???} -3. ${13:???} - -*What one thing is top of mind today?* -${14:???} - -*What’s one opportunity I want to go after?* -${15:???} - -*What’s one thing I’m really proud of OR I’m amazed and in awe of?* -${16:???} - -$0 -** contacts: Get the email of one of my personal contacts - -${1:`(and (or (featurep 'my/contacts) (org-babel-load-file "~/Dropbox/contacts.org")) -(yas-choose-value (--map (format "%s <%s>" (getf it :name) (getf it :email)) -my/contacts)))`} $0