Autocommit 2021-09-03T13:44+05:00

Hostname: eminence
This commit is contained in:
Pavel Korytov 2021-09-03 13:44:06 +05:00
parent 78150f2c3e
commit fce34a425d
7 changed files with 498 additions and 23 deletions

View file

@ -937,7 +937,7 @@ fi
```
### `autocommmit` {#autocommmit}
### `autocommit` {#autocommit}
A script to autocommit files in a repository. I use it to sync my org directory and password store. I guess it's not how git is intended to be used, but it works for me.

View file

@ -897,7 +897,7 @@ The script below allows me to:
```bash
hostname=$(hostname)
# Settings varying on the hostname
export WLAN_INTERFACE=$(nmcli -f DEVICE con show | grep -Ev "(.*docker.*|DEVICE|br.*|tun.*|--)" | xargs)
export WLAN_INTERFACE=$(nmcli -f DEVICE con show | grep -Ev "(.*docker.*|DEVICE|br.*|tun.*|veth.*|--)" | xargs)
if [ "$hostname" = "azure" ]; then
TRAY_MONITOR="eDP-1"
# export WLAN_INTERFACE="wlp3s0"
@ -936,7 +936,7 @@ declare -A BLOCKS=(
)
# Geolocation for some modules
export LOC="SPB"
export LOC="TMN"
export IPSTACK_API_KEY=$(pass show My_Online/APIs/ipstack | head -n 1)
@ -2346,6 +2346,7 @@ This section generates manifests for various desktop software that I'm using.
| dev | node |
| dev | openjdk |
| dev | go |
| dev | gcc-toolchain |
### Manifests {#manifests}

View file

@ -124,6 +124,12 @@ As with other files in the repo, parts prefixed with (OFF) are not used but kept
- [Productivity & Knowledge management](#productivity-and-knowledge-management)
- [Capture templates & various settings](#capture-templates-and-various-settings)
- [Custom agendas](#custom-agendas)
- [org-ql](#org-ql)
- [Review workflow](#review-workflow)
- [Data from git & org-roam](#data-from-git-and-org-roam)
- [Data from org-journal](#data-from-org-journal)
- [Data from org-agenda via org-ql](#data-from-org-agenda-via-org-ql)
- [Capture template](#capture-template)
- [Org Journal](#org-journal)
- [Org Roam](#org-roam)
- [org-roam-ui](#org-roam-ui)
@ -234,7 +240,7 @@ As with other files in the repo, parts prefixed with (OFF) are not used but kept
- [Notmuch](#notmuch)
- [Elfeed](#elfeed)
- [Some additions](#some-additions)
- [YouTube](#youtube)
- [YouTube & EMMS](#youtube-and-emms)
- [EMMS](#emms)
- [MPD](#mpd)
- [MPV](#mpv)
@ -2966,6 +2972,262 @@ Log DONE time
```
#### org-ql {#org-ql}
[org-ql](https://github.com/alphapapa/org-ql) is a package to query the org files. I'm using it in my review workflow, perhaps later I'll find another usecases.
```emacs-lisp
(use-package org-ql
:straight (:fetcher github
:repo "alphapapa/org-ql"
:files (:defaults (:exclude "helm-org-ql.el"))))
```
#### Review workflow {#review-workflow}
My take on a review workflow. As a baseline, I want to have a template that lists the important changes since the last review and other basic information. I'm doing reviews regularly, but the time intervals still may vary, hence this flexibility.
##### Data from git & org-roam {#data-from-git-and-org-roam}
First, as I have [autocommit]({{< relref "Console" >}}) set up in my org directory, here is a handy function to get an alist of changed files of a form `(status . path)`. In principle, the `rev` parameter can be a commit, tag, etc but here I'm interested in a form like `@{2021-08-30}`.
```emacs-lisp
(setq my/git-diff-status
'(("A" . added)
("C" . copied)
("D" . deleted)
("M" . modified)
("R" . renamed)
("T" . type-changed)
("U" . unmerged)))
(defun my/get-files-status (rev)
(let ((files (shell-command-to-string (concat "git diff --name-status " rev))))
(mapcar
(lambda (file)
(let ((elems (split-string file "\t")))
(cons
(cdr (assoc (car elems) my/git-diff-status))
(nth 1 elems))))
(split-string files "\n" t))))
```
I'll use it to get a list of added and changed Roam files since the last review. Date should have be in a format `YYYY-MM-DD`.
```emacs-lisp
(defun my/org-changed-files-since-date (date)
(let ((default-directory org-directory))
(my/get-files-status (format "@{%s}" date))))
```
Now we are ready to format this list to insert it into the capture template.
```emacs-lisp
(defun my/org-review-format-roam (rev)
(let* ((changes (my/org-changed-files-since-date rev))
(new-roam
(seq-filter
(lambda (elem)
(and (eq (car elem) 'added)
(string-match-p (rx bos "roam") (cdr elem))))
changes))
(changed-roam
(seq-filter
(lambda (elem)
(and (eq (car elem) 'modified)
(string-match-p (rx bos "roam") (cdr elem))))
changes)))
(concat
(unless (seq-empty-p new-roam)
(concat "** New Roam entries \n"
(mapconcat
(lambda (entry)
(format "- [[file:%s][%s]]" (cdr entry) (cdr entry)))
new-roam
"\n")
"\n"))
(unless (seq-empty-p changed-roam)
(concat "** Changed Roam entries \n"
(mapconcat
(lambda (entry)
(format "- [[file:%s][%s]]" (cdr entry) (cdr entry)))
changed-roam
"\n"))))))
```
##### Data from org-journal {#data-from-org-journal}
Second, I want to have a list of new jounal entries since the last review.
```emacs-lisp
(defun my/org-journal-entries-since-date (rev-date)
(mapcar
(lambda (date)
(let ((time (encode-time (parse-time-string date))))
`((file . ,(org-journal--get-entry-path time))
(header . ,(format-time-string org-journal-date-format time)))))
(seq-filter
(lambda (date) (string-lessp rev-date date))
(mapcar
(lambda (date)
(format "%04d-%02d-%02dT00:00:00+0300" (nth 2 date) (nth 0 date) (nth 1 date)))
(org-journal--list-dates)))))
```
Format the results:
```emacs-lisp
(defun my/org-review-format-journal (rev-date)
(mapconcat
(lambda (item)
(format "- [[file:%s::*%s][%s]]"
(cdr (assoc 'file item))
(cdr (assoc 'header item))
(cdr (assoc 'header item))))
(my/org-journal-entries-since-date rev-date)
"\n"))
```
##### Data from org-agenda via org-ql {#data-from-org-agenda-via-org-ql}
Third, I want to list some changes in my agenda. This section will change depending on what I'm currently working on.
So, here is a list of queries results of which I want to see in the review template. The format is `(name date-field order-by-field query)`.
```emacs-lisp
(setq my/org-ql-review-queries
`(("Waitlist" scheduled scheduled
(and
(done)
(tags-inherited "waitlist")))
("Personal tasks done" closed ,nil
(and
(tags-inherited "personal")
(todo "DONE")))
("Attended meetings" closed scheduled
(and
(tags "meeting")
(todo "PASSED")))
("Done project tasks" closed deadline
(and
(todo "DONE")
(ancestors
(heading "Tasks"))))))
```
The query will be executed like this: `(and (date-field :from rev-date) query)`
```emacs-lisp
(defun my/org-review-exec-ql (saved rev-date)
(let ((query `(and
(,(nth 1 saved) :from ,rev-date)
,(nth 3 saved))))
(org-ql-query
:select #'element
:from (org-agenda-files)
:where query
:order-by (nth 2 saved))))
```
Format one element of query result.
```emacs-lisp
(defun my/org-review-format-element (elem)
(concat
(string-pad
(plist-get (cadr elem) :raw-value)
40)
(when-let (scheduled (plist-get (cadr elem) :scheduled))
(concat " [SCHEDULED: " (plist-get (cadr scheduled) :raw-value) "]"))
(when-let (deadline (plist-get (cadr elem) :deadline))
(concat " [DEADLINE: " (plist-get (cadr deadline) :raw-value) "]"))))
```
Execute all the saved queries and format an Org list for the capture template.
```emacs-lisp
(defun my/org-review-format-queries (rev-date)
(mapconcat
(lambda (results)
(concat "** " (car results) "\n"
(string-join
(mapcar (lambda (r) (concat "- " r)) (cdr results))
"\n")
"\n"))
(seq-filter
(lambda (result)
(not (seq-empty-p (cdr result))))
(mapcar
(lambda (saved)
(cons
(car saved)
(mapcar
#'my/org-review-format-element
(my/org-review-exec-ql saved rev-date))))
my/org-ql-review-queries))
"\n"))
```
##### Capture template {#capture-template}
Now, we have to put all this together and define a capture template for the review.
I'll use a separate directory for the review files, just like for org-journal and org-roam. The filename will have a format `YYYY-MM-DD.org`, which will also free me from the effort of storing the last review date somewhere.
If somehow there are no files in the folder, fallback to the current date minus one week.
```emacs-lisp
(setq my/org-review-directory "review")
(defun my/org-review-get-filename ()
(concat my/org-review-directory "/" (format-time-string "%Y-%m-%d.org" (current-time))))
(defun my/get-last-review-date ()
(substring
(or
(-max-by
'string-greaterp
(-filter
(lambda (f) (not (or (string-equal f ".") (string-equal f ".."))))
(directory-files (f-join org-directory my/org-review-directory))))
(format-time-string
"%Y-%m-%d"
(time-subtract
(current-time)
(seconds-to-time (* 60 60 24 7)))))
0 10))
```
A template looks like this:
```emacs-lisp
(setq my/org-review-capture-template
`("r" "Review" plain (file ,(my/org-review-get-filename))
,(string-join
'("#+TITLE: Review %t"
""
"Last review date: %(org-timestamp-translate (org-timestamp-from-string (format \"<%s>\" (my/get-last-review-date))))"
""
"* Roam"
"%(my/org-review-format-roam (my/get-last-review-date))"
"* Journal"
"New journal entries:"
"%(my/org-review-format-journal (my/get-last-review-date))"
"* Agenda"
"%(my/org-review-format-queries (my/get-last-review-date))"
"* Thoughts :crypt:"
"%?")
"\n")))
(add-to-list 'org-capture-templates my/org-review-capture-template t)
```
#### Org Journal {#org-journal}
[org-journal](https://github.com/bastibe/org-journal) is a plugin for maintaining a journal in org mode. I want to have its entries separate from my knowledge base.
@ -4101,8 +4363,7 @@ Trying this one out instead of vue-mode and svelte-mode, because this one seems
:config
(add-hook 'web-mode-hook 'smartparens-mode)
(add-hook 'web-mode-hook 'hs-minor-mode)
(my/set-smartparens-indent 'web-mode)
(add-hook 'web-mode-hook ))
(my/set-smartparens-indent 'web-mode))
```
Hooking this up with lsp.
@ -5338,7 +5599,7 @@ Open a URL with eww.
```
##### YouTube {#youtube}
##### YouTube & EMMS {#youtube-and-emms}
Previously this block was opening MPV with `start-process`, but now I've managed to hook up MPV with EMMS. So there is the EMMS+elfeed "integration".
@ -5364,12 +5625,13 @@ Now, a function to add YouTube link with metadata from elfeed to EMMS.
(let ((track (emms-track
'url (my/get-youtube-url (elfeed-entry-link entry)))))
(emms-track-set track 'info-title (elfeed-entry-title entry))
(setq my/test track)
(emms-playlist-insert-track track))))
(defun my/elfeed-add-emms-youtube ()
(interactive)
(emms-add-elfeed elfeed-show-entry))
(emms-add-elfeed elfeed-show-entry)
(elfeed-tag elfeed-show-entry 'watched)
(elfeed-show-refresh))
(with-eval-after-load 'elfeed
(general-define-key

View file

@ -1552,7 +1552,7 @@ Before I figure out how to package this for Guix:
:straight (:host github :repo "SqrtMinusOne/wakatime-mode")
:if (not my/is-termux)
:config
<<wakatime-fixes>>
(setq wakatime-ignore-exit-codes '(0 1 102))
(advice-add 'wakatime-init :after (lambda () (setq wakatime-cli-path "/home/pavel/bin/wakatime-cli")))
;; (setq wakatime-cli-path (executable-find "wakatime"))
(global-wakatime-mode))
@ -4028,7 +4028,7 @@ My bit of config here:
:straight t
:init
(my-leader-def
:keymaps '(js-mode-map typescript-mode-map vue-mode-map svelte-mode-map)
:keymaps '(js-mode-map web-mode-map typescript-mode-map vue-mode-map svelte-mode-map)
"rr" #'prettier-prettify))
```
@ -4101,7 +4101,8 @@ Trying this one out instead of vue-mode and svelte-mode, because this one seems
:config
(add-hook 'web-mode-hook 'smartparens-mode)
(add-hook 'web-mode-hook 'hs-minor-mode)
(my/set-smartparens-indent 'web-mode))
(my/set-smartparens-indent 'web-mode)
(add-hook 'web-mode-hook ))
```
Hooking this up with lsp.
@ -4120,6 +4121,16 @@ Hooking this up with lsp.
(add-hook 'web-mode-hook #'my/web-mode-lsp)
```
Vue settings
```emacs-lisp
(defun my/web-mode-vue-setup ()
(when (string-match-p (rx ".vue" eos) (buffer-name))
(setq-local web-mode-script-padding 0)))
(add-hook 'web-mode-hook 'my/web-mode-vue-setup)
```
#### <span class="org-todo done OFF">OFF</span> (OFF) Vue.js {#off--vue-dot-js}
@ -4763,7 +4774,7 @@ For some reason it doesn't use pipenv python executable, so here is a small work
(if asc
(cdr asc)
(let ((python-executable
(string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python"))))
(string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null"))))
(if (string-match-p ".*not found.*" python-executable)
(message "Pipfile found, but not pipenv executable!")
(message (format "Found pipenv python: %s" python-executable))
@ -5469,7 +5480,7 @@ After all this is done, run `M-x emms-cache-set-from-mpd-all` to set cache from
[mpv](https://mpv.io/) is a decent media player, which has found a place in this configuration because it integrates with youtube-dl.
```emacs-lisp
(add-to-list 'emms-player-list 'emms-player-mpv t)
(add-to-list 'emms-player-list 'emms-player-mpv)
```
Also a custom regex. My demands for MPV include running `youtube-dl`, so there is a regex that matches youtube.com or some of the video formats.

View file

@ -13,7 +13,7 @@ The majority of the software is configured with [literate configuration](https:/
The files themselves are managed and deployed via [yadm](https://yadm.io/), but I mostly use Org Mode rich noweb whenever I can instead of what yadm offers.
My current GNU/Linux distribution is [GNU Guix](https://guix.gnu.org/). In the context of this repo, Guix allows me to list all the used programs in manifests, which means I have the same set of programs across multiple machines. Looks for Org tables with "Guix dependency" in the header.
My current GNU/Linux distribution is [GNU Guix](https://guix.gnu.org/). In the context of this repo, Guix allows me to list all the used programs in manifests, which means I have the same set of programs across multiple machines. Look for the tables with "Guix dependency" in the header.
Literate configuration files:
@ -70,7 +70,7 @@ Some of the notable programs are listed in the table below.
## Some statistics {#some-statistics}
Run the following to show the pictures with reasonable width:
If you are viewing the file in Emacs, eval the following to show the pictures with reasonable width:
```elisp
(setq-local org-image-actual-width '(1024))

View file

@ -793,7 +793,7 @@ bind <span style="color:#a6e22e">-M</span> insert <span style="color:#ae81ff">\e
<span style="color:#66d9ef">else</span>
notify-send <span style="color:#e6db74">&#34;Terminal&#34;</span> <span style="color:#e6db74">&#34;Command execution complete&#34;</span>
<span style="color:#66d9ef">fi</span>
</code></pre></div><h3 id="autocommmit"><code>autocommmit</code></h3>
</code></pre></div><h3 id="autocommit"><code>autocommit</code></h3>
<p>A script to autocommit files in a repository. I use it to sync my org directory and password store. I guess it&rsquo;s not how git is intended to be used, but it works for me.</p>
<p>Usage:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">autocommit &lt;repository&gt; [-F]

View file

@ -245,6 +245,15 @@
<ul>
<li><a href="#capture-templates-and-various-settings">Capture templates &amp; various settings</a></li>
<li><a href="#custom-agendas">Custom agendas</a></li>
<li><a href="#org-ql">org-ql</a></li>
<li><a href="#review-workflow">Review workflow</a>
<ul>
<li><a href="#data-from-git-and-org-roam">Data from git &amp; org-roam</a></li>
<li><a href="#data-from-org-journal">Data from org-journal</a></li>
<li><a href="#data-from-org-agenda-via-org-ql">Data from org-agenda via org-ql</a></li>
<li><a href="#capture-template">Capture template</a></li>
</ul>
</li>
<li><a href="#org-journal">Org Journal</a></li>
<li><a href="#org-roam">Org Roam</a>
<ul>
@ -425,7 +434,7 @@
<li><a href="#elfeed">Elfeed</a>
<ul>
<li><a href="#some-additions">Some additions</a></li>
<li><a href="#youtube">YouTube</a></li>
<li><a href="#youtube-and-emms">YouTube &amp; EMMS</a></li>
</ul>
</li>
<li><a href="#emms">EMMS</a>
@ -2398,6 +2407,198 @@
(<span style="color:#e6db74">&#34;tp&#34;</span> <span style="color:#e6db74">&#34;Personal tasks&#34;</span>
((tags-todo <span style="color:#e6db74">&#34;personal&#34;</span>
((org-agenda-prefix-format <span style="color:#e6db74">&#34; %i %-12:c [%e] &#34;</span>)))))))
</code></pre></div><h4 id="org-ql">org-ql</h4>
<p><a href="https://github.com/alphapapa/org-ql">org-ql</a> is a package to query the org files. I&rsquo;m using it in my review workflow, perhaps later I&rsquo;ll find another usecases.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package org-ql
:straight (:fetcher github
:repo <span style="color:#e6db74">&#34;alphapapa/org-ql&#34;</span>
:files (:defaults (:exclude <span style="color:#e6db74">&#34;helm-org-ql.el&#34;</span>))))
</code></pre></div><h4 id="review-workflow">Review workflow</h4>
<p>My take on a review workflow. As a baseline, I want to have a template that lists the important changes since the last review and other basic information. I&rsquo;m doing reviews regularly, but the time intervals still may vary, hence this flexibility.</p>
<h5 id="data-from-git-and-org-roam">Data from git &amp; org-roam</h5>
<p>First, as I have <a href="/configs/console/">autocommit</a> set up in my org directory, here is a handy function to get an alist of changed files of a form <code>(status . path)</code>. In principle, the <code>rev</code> parameter can be a commit, tag, etc but here I&rsquo;m interested in a form like <code>@{2021-08-30}</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/git-diff-status
<span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;A&#34;</span> <span style="color:#f92672">.</span> added)
(<span style="color:#e6db74">&#34;C&#34;</span> <span style="color:#f92672">.</span> copied)
(<span style="color:#e6db74">&#34;D&#34;</span> <span style="color:#f92672">.</span> deleted)
(<span style="color:#e6db74">&#34;M&#34;</span> <span style="color:#f92672">.</span> modified)
(<span style="color:#e6db74">&#34;R&#34;</span> <span style="color:#f92672">.</span> renamed)
(<span style="color:#e6db74">&#34;T&#34;</span> <span style="color:#f92672">.</span> type-changed)
(<span style="color:#e6db74">&#34;U&#34;</span> <span style="color:#f92672">.</span> unmerged)))
(defun my/get-files-status (rev)
(let ((files (shell-command-to-string (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;git diff --name-status &#34;</span> rev))))
(<span style="color:#a6e22e">mapcar</span>
(lambda (file)
(let ((elems (split-string file <span style="color:#e6db74">&#34;\t&#34;</span>)))
(<span style="color:#a6e22e">cons</span>
(<span style="color:#a6e22e">cdr</span> (<span style="color:#a6e22e">assoc</span> (<span style="color:#a6e22e">car</span> elems) my/git-diff-status))
(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> elems))))
(split-string files <span style="color:#e6db74">&#34;\n&#34;</span> <span style="color:#66d9ef">t</span>))))
</code></pre></div><p>I&rsquo;ll use it to get a list of added and changed Roam files since the last review. Date should have be in a format <code>YYYY-MM-DD</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-changed-files-since-date (date)
(let ((default-directory org-directory))
(my/get-files-status (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;@{%s}&#34;</span> date))))
</code></pre></div><p>Now we are ready to format this list to insert it into the capture template.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-review-format-roam (rev)
(let* ((changes (my/org-changed-files-since-date rev))
(new-roam
(seq-filter
(lambda (elem)
(and (<span style="color:#a6e22e">eq</span> (<span style="color:#a6e22e">car</span> elem) <span style="color:#e6db74">&#39;added</span>)
(string-match-p (rx bos <span style="color:#e6db74">&#34;roam&#34;</span>) (<span style="color:#a6e22e">cdr</span> elem))))
changes))
(changed-roam
(seq-filter
(lambda (elem)
(and (<span style="color:#a6e22e">eq</span> (<span style="color:#a6e22e">car</span> elem) <span style="color:#e6db74">&#39;modified</span>)
(string-match-p (rx bos <span style="color:#e6db74">&#34;roam&#34;</span>) (<span style="color:#a6e22e">cdr</span> elem))))
changes)))
(<span style="color:#a6e22e">concat</span>
(unless (seq-empty-p new-roam)
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;** New Roam entries \n&#34;</span>
(<span style="color:#a6e22e">mapconcat</span>
(lambda (entry)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;- [[file:%s][%s]]&#34;</span> (<span style="color:#a6e22e">cdr</span> entry) (<span style="color:#a6e22e">cdr</span> entry)))
new-roam
<span style="color:#e6db74">&#34;\n&#34;</span>)
<span style="color:#e6db74">&#34;\n&#34;</span>))
(unless (seq-empty-p changed-roam)
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;** Changed Roam entries \n&#34;</span>
(<span style="color:#a6e22e">mapconcat</span>
(lambda (entry)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;- [[file:%s][%s]]&#34;</span> (<span style="color:#a6e22e">cdr</span> entry) (<span style="color:#a6e22e">cdr</span> entry)))
changed-roam
<span style="color:#e6db74">&#34;\n&#34;</span>))))))
</code></pre></div><h5 id="data-from-org-journal">Data from org-journal</h5>
<p>Second, I want to have a list of new jounal entries since the last review.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-journal-entries-since-date (rev-date)
(<span style="color:#a6e22e">mapcar</span>
(lambda (date)
(let ((time (<span style="color:#a6e22e">encode-time</span> (parse-time-string date))))
<span style="color:#f92672">`</span>((file <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(org-journal--get-entry-path time))
(header <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">format-time-string</span> org-journal-date-format time)))))
(seq-filter
(lambda (date) (<span style="color:#a6e22e">string-lessp</span> rev-date date))
(<span style="color:#a6e22e">mapcar</span>
(lambda (date)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%04d-%02d-%02dT00:00:00+0300&#34;</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> date) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> date) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> date)))
(org-journal--list-dates)))))
</code></pre></div><p>Format the results:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-review-format-journal (rev-date)
(<span style="color:#a6e22e">mapconcat</span>
(lambda (item)
(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;- [[file:%s::*%s][%s]]&#34;</span>
(<span style="color:#a6e22e">cdr</span> (<span style="color:#a6e22e">assoc</span> <span style="color:#e6db74">&#39;file</span> item))
(<span style="color:#a6e22e">cdr</span> (<span style="color:#a6e22e">assoc</span> <span style="color:#e6db74">&#39;header</span> item))
(<span style="color:#a6e22e">cdr</span> (<span style="color:#a6e22e">assoc</span> <span style="color:#e6db74">&#39;header</span> item))))
(my/org-journal-entries-since-date rev-date)
<span style="color:#e6db74">&#34;\n&#34;</span>))
</code></pre></div><h5 id="data-from-org-agenda-via-org-ql">Data from org-agenda via org-ql</h5>
<p>Third, I want to list some changes in my agenda. This section will change depending on what I&rsquo;m currently working on.</p>
<p>So, here is a list of queries results of which I want to see in the review template. The format is <code>(name date-field order-by-field query)</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/org-ql-review-queries
<span style="color:#f92672">`</span>((<span style="color:#e6db74">&#34;Waitlist&#34;</span> scheduled scheduled
(and
(done)
(tags-inherited <span style="color:#e6db74">&#34;waitlist&#34;</span>)))
(<span style="color:#e6db74">&#34;Personal tasks done&#34;</span> closed <span style="color:#f92672">,</span><span style="color:#66d9ef">nil</span>
(and
(tags-inherited <span style="color:#e6db74">&#34;personal&#34;</span>)
(todo <span style="color:#e6db74">&#34;DONE&#34;</span>)))
(<span style="color:#e6db74">&#34;Attended meetings&#34;</span> closed scheduled
(and
(tags <span style="color:#e6db74">&#34;meeting&#34;</span>)
(todo <span style="color:#e6db74">&#34;PASSED&#34;</span>)))
(<span style="color:#e6db74">&#34;Done project tasks&#34;</span> closed deadline
(and
(todo <span style="color:#e6db74">&#34;DONE&#34;</span>)
(ancestors
(heading <span style="color:#e6db74">&#34;Tasks&#34;</span>))))))
</code></pre></div><p>The query will be executed like this: <code>(and (date-field :from rev-date) query)</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-review-exec-ql (saved rev-date)
(let ((query <span style="color:#f92672">`</span>(and
(<span style="color:#f92672">,</span>(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> saved) :from <span style="color:#f92672">,</span>rev-date)
<span style="color:#f92672">,</span>(<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">3</span> saved))))
(org-ql-query
:select <span style="color:#a6e22e">#&#39;</span>element
:from (org-agenda-files)
:where query
:order-by (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> saved))))
</code></pre></div><p>Format one element of query result.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-review-format-element (elem)
(<span style="color:#a6e22e">concat</span>
(string-pad
(<span style="color:#a6e22e">plist-get</span> (cadr elem) :raw-value)
<span style="color:#ae81ff">40</span>)
(when-let (scheduled (<span style="color:#a6e22e">plist-get</span> (cadr elem) :scheduled))
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34; [SCHEDULED: &#34;</span> (<span style="color:#a6e22e">plist-get</span> (cadr scheduled) :raw-value) <span style="color:#e6db74">&#34;]&#34;</span>))
(when-let (deadline (<span style="color:#a6e22e">plist-get</span> (cadr elem) :deadline))
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34; [DEADLINE: &#34;</span> (<span style="color:#a6e22e">plist-get</span> (cadr deadline) :raw-value) <span style="color:#e6db74">&#34;]&#34;</span>))))
</code></pre></div><p>Execute all the saved queries and format an Org list for the capture template.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/org-review-format-queries (rev-date)
(<span style="color:#a6e22e">mapconcat</span>
(lambda (results)
(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;** &#34;</span> (<span style="color:#a6e22e">car</span> results) <span style="color:#e6db74">&#34;\n&#34;</span>
(string-join
(<span style="color:#a6e22e">mapcar</span> (lambda (r) (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;- &#34;</span> r)) (<span style="color:#a6e22e">cdr</span> results))
<span style="color:#e6db74">&#34;\n&#34;</span>)
<span style="color:#e6db74">&#34;\n&#34;</span>))
(seq-filter
(lambda (result)
(not (seq-empty-p (<span style="color:#a6e22e">cdr</span> result))))
(<span style="color:#a6e22e">mapcar</span>
(lambda (saved)
(<span style="color:#a6e22e">cons</span>
(<span style="color:#a6e22e">car</span> saved)
(<span style="color:#a6e22e">mapcar</span>
<span style="color:#a6e22e">#&#39;</span>my/org-review-format-element
(my/org-review-exec-ql saved rev-date))))
my/org-ql-review-queries))
<span style="color:#e6db74">&#34;\n&#34;</span>))
</code></pre></div><h5 id="capture-template">Capture template</h5>
<p>Now, we have to put all this together and define a capture template for the review.</p>
<p>I&rsquo;ll use a separate directory for the review files, just like for org-journal and org-roam. The filename will have a format <code>YYYY-MM-DD.org</code>, which will also free me from the effort of storing the last review date somewhere.</p>
<p>If somehow there are no files in the folder, fallback to the current date minus one week.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/org-review-directory <span style="color:#e6db74">&#34;review&#34;</span>)
(defun my/org-review-get-filename ()
(<span style="color:#a6e22e">concat</span> my/org-review-directory <span style="color:#e6db74">&#34;/&#34;</span> (<span style="color:#a6e22e">format-time-string</span> <span style="color:#e6db74">&#34;%Y-%m-%d.org&#34;</span> (<span style="color:#a6e22e">current-time</span>))))
(defun my/get-last-review-date ()
(<span style="color:#a6e22e">substring</span>
(or
(-max-by
<span style="color:#e6db74">&#39;string-greaterp</span>
(-filter
(lambda (f) (not (or (<span style="color:#a6e22e">string-equal</span> f <span style="color:#e6db74">&#34;.&#34;</span>) (<span style="color:#a6e22e">string-equal</span> f <span style="color:#e6db74">&#34;..&#34;</span>))))
(<span style="color:#a6e22e">directory-files</span> (f-join org-directory my/org-review-directory))))
(<span style="color:#a6e22e">format-time-string</span>
<span style="color:#e6db74">&#34;%Y-%m-%d&#34;</span>
(<span style="color:#a6e22e">time-subtract</span>
(<span style="color:#a6e22e">current-time</span>)
(seconds-to-time (<span style="color:#a6e22e">*</span> <span style="color:#ae81ff">60</span> <span style="color:#ae81ff">60</span> <span style="color:#ae81ff">24</span> <span style="color:#ae81ff">7</span>)))))
<span style="color:#ae81ff">0</span> <span style="color:#ae81ff">10</span>))
</code></pre></div><p>A template looks like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/org-review-capture-template
<span style="color:#f92672">`</span>(<span style="color:#e6db74">&#34;r&#34;</span> <span style="color:#e6db74">&#34;Review&#34;</span> plain (file <span style="color:#f92672">,</span>(my/org-review-get-filename))
<span style="color:#f92672">,</span>(string-join
<span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;#+TITLE: Review %t&#34;</span>
<span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#e6db74">&#34;Last review date: %(org-timestamp-translate (org-timestamp-from-string (format \&#34;&lt;%s&gt;\&#34; (my/get-last-review-date))))&#34;</span>
<span style="color:#e6db74">&#34;&#34;</span>
<span style="color:#e6db74">&#34;* Roam&#34;</span>
<span style="color:#e6db74">&#34;%(my/org-review-format-roam (my/get-last-review-date))&#34;</span>
<span style="color:#e6db74">&#34;* Journal&#34;</span>
<span style="color:#e6db74">&#34;New journal entries:&#34;</span>
<span style="color:#e6db74">&#34;%(my/org-review-format-journal (my/get-last-review-date))&#34;</span>
<span style="color:#e6db74">&#34;* Agenda&#34;</span>
<span style="color:#e6db74">&#34;%(my/org-review-format-queries (my/get-last-review-date))&#34;</span>
<span style="color:#e6db74">&#34;* Thoughts :crypt:&#34;</span>
<span style="color:#e6db74">&#34;%?&#34;</span>)
<span style="color:#e6db74">&#34;\n&#34;</span>)))
(add-to-list <span style="color:#e6db74">&#39;org-capture-templates</span> my/org-review-capture-template <span style="color:#66d9ef">t</span>)
</code></pre></div><h4 id="org-journal">Org Journal</h4>
<p><a href="https://github.com/bastibe/org-journal">org-journal</a> is a plugin for maintaining a journal in org mode. I want to have its entries separate from my knowledge base.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package org-journal
@ -3265,8 +3466,7 @@ MimeType=x-scheme-handler/org-protocol
:config
(add-hook <span style="color:#e6db74">&#39;web-mode-hook</span> <span style="color:#e6db74">&#39;smartparens-mode</span>)
(add-hook <span style="color:#e6db74">&#39;web-mode-hook</span> <span style="color:#e6db74">&#39;hs-minor-mode</span>)
(my/set-smartparens-indent <span style="color:#e6db74">&#39;web-mode</span>)
(add-hook <span style="color:#e6db74">&#39;web-mode-hook</span> ))
(my/set-smartparens-indent <span style="color:#e6db74">&#39;web-mode</span>))
</code></pre></div><p>Hooking this up with lsp.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(setq my/web-mode-lsp-extensions
<span style="color:#f92672">`</span>(<span style="color:#f92672">,</span>(rx <span style="color:#e6db74">&#34;.svelte&#34;</span> eos)
@ -4208,7 +4408,7 @@ MimeType=x-scheme-handler/org-protocol
(let ((link (elfeed-entry-link elfeed-show-entry)))
(when link
(eww link))))
</code></pre></div><h5 id="youtube">YouTube</h5>
</code></pre></div><h5 id="youtube-and-emms">YouTube &amp; EMMS</h5>
<p>Previously this block was opening MPV with <code>start-process</code>, but now I&rsquo;ve managed to hook up MPV with EMMS. So there is the EMMS+elfeed &ldquo;integration&rdquo;.</p>
<p>The following function converts URLs from Invidious and the like to YouTube.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/get-youtube-url (link)
@ -4226,12 +4426,13 @@ MimeType=x-scheme-handler/org-protocol
(let ((track (emms-track
<span style="color:#e6db74">&#39;url</span> (my/get-youtube-url (elfeed-entry-link entry)))))
(emms-track-set track <span style="color:#e6db74">&#39;info-title</span> (elfeed-entry-title entry))
(setq my/test track)
(emms-playlist-insert-track track))))
(defun my/elfeed-add-emms-youtube ()
(interactive)
(emms-add-elfeed elfeed-show-entry))
(emms-add-elfeed elfeed-show-entry)
(elfeed-tag elfeed-show-entry <span style="color:#e6db74">&#39;watched</span>)
(elfeed-show-refresh))
(with-eval-after-load <span style="color:#e6db74">&#39;elfeed</span>
(general-define-key