71 KiB
Emacs
- early-init.el
[7/7].emacs[8/11]config.el and custom.el- Front matter
[9/9]Startup and general configurations[2/3]Advanced Features[0/2]Text[0/1]Case- Text Mode
[0/1]
[3/3]Shell[2/2]Saving Emacs Sessions
[8/21]Reading and Writing- Move correctly over camelCased words
- Understand the more common sentence with double space
- Join lines into paragraph
- Expand some words with auto-correct
- ediff
- tramp
- Clean up space
- Transform <a href> links into org links
- Count words per minute
- Enable dict mode
- Pick out passive voice and weasel words
- Org-babel docker
[1/6]Spelling and syntax- Read ebooks
- Annotate PDFs and EPUBs
- Link PDFs
- View EPUBs
- Zotero
[2/2]Security[2/3]AI- Accounting
- Browser
- Manage Docker in Emacs
- Periodic table of the elements
- Org-agent
- End matter
DONE early-init.el
For straight.el to pick up before package.el
(setq package-enable-at-startup nil)
DONE
[7/7] .emacs
- State "DONE" from "DONE" [2025-05-30 Fri 15:00]
- State "DONE" from "DONE" [2025-05-30 Fri 15:00]
- State "DONE" from "DONE" [2025-05-30 Fri 15:00]
- State "DONE" from "DONE" [2024-07-19 Fri 16:07]
- State "DONE" from "DONE" [2024-07-19 Fri 16:07]
- State "DONE" from "DONE" [2024-07-19 Fri 14:40]
- State "DONE" from "DONE" [2024-07-19 Fri 14:40]
- State "DONE" from "DONE" [2024-07-09 Tue 12:11]
- State "DONE" from "TODO" [2023-07-02 Sun 15:02]
DONE Front matter
;;; .emacs --- Global settings
;;; Commentary:
;;; Code:
;; -*- lexical-binding: t; -*-
DONE Garbage collector - increase threshold to 500 MB to ease startup
(setq gc-cons-threshold (* 500 1024 1024))
DONE
[3/3] Package.el
CNCL List package archives and initialize them (package.el)
(require 'package)
(setq package-archives '(
("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")
)
)
(setq package-install-upgrade-built-in t)
(setq package-check-signature "allow-unsigned")
(gnu-elpa-keyring-update)
(package-initialize)
(package-refresh-contents)
CNCL Install use-package (package.el)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package)
)
(eval-when-compile (require 'use-package)) ;; allow byte-compile while using use-package
CNCL Make sure Org is installed (package.el)
(unless (package-installed-p 'org)
(package-install 'org)
)
DONE
[3/3] Straight.el
DONE Bootstrap Straight.el and install use-package
(setq straight-repository-branch "develop") ;; Using develop branch temporarily to fix the org-roam-dailies issue. From https://github.com/org-roam/org-roam/issues/2361#issuecomment-1671601796
(eval-and-compile
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el"
(or (bound-and-true-p straight-base-dir)
user-emacs-directory)))
(bootstrap-version 7))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
)
t
DONE Integrate use-package and straight
(setq straight-use-package-by-default t)
DONE Make sure Org is installed (straight.el)
Freezing Org@9.5.5 fixes the issue with org-roam resulting in 'Wrong type argument: integer-or-marker-p, nil'
(unless (file-directory-p "~/.emacs.d/straight/versions") (make-directory (concat user-emacs-directory "straight/versions")))
; This goes in ~/.emacs.d/straight/versions/default.el
;; (("org" . "8ef6205a560cd3a92f8c5f8fe34953b80121c2cb")) ; org@9.5.5
;; (("org" . "5890aca3d29e593640b728308096a052998355b1")) ; org@9.6.7
:gamma
:tangle ~/.emacs.d/straight/versions/default.el
(("org-roam" . "d4c606078752ac7c1c8a492a042564f4294a23a6"))
(use-package org)
DONE Tangle emacs.org
(require 'ob-tangle)
;; Specify the input file and the output directory
(defvar config-org-file "~/memex/system/emacs.org")
(defvar config-el-file "~/.emacs.d/config.el")
(defvar org-use-property-inheritance t)
;; Tangle emacs.org into config.el and load config.el
(org-babel-tangle-file config-org-file)
(load-file config-el-file)
DONE Garbage collector - decrease threshold to 5 MB
(add-hook 'after-init-hook (lambda () (setq gc-cons-threshold (* 5 1024 1024))))
DONE End matter
(provide '.emacs)
;;; .emacs ends here
TODO
[8/11] config.el and custom.el
This Emacs configuration file is a fork of Sri Ramkswamy's and Sacha Chusa's settings. I am sure there is much more to learn from them as I go. Worth revisiting.
DONE Front matter
;;; Package --- Summary
;;; Commentary:
;;; Code:
;; -*- lexical-binding: t; -*-
;;; Package --- Summary
;;; Commentary:
;;; Code:
;; -*- lexical-binding: t; -*-
DONE
[9/9] Startup and general configurations
- State "DONE" from "DONE" [2024-07-20 Sat 11:55]
- State "DONE" from "TODO" [2024-07-19 Fri 15:10]
- State "DONE" from "TODO" [2024-07-10 Wed 10:45]
DONE Run Emacs as a server
(require 'server)
(unless (server-running-p) (server-start))
(defvar server-max-buffers 100)
DONE Custom file
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file) (load custom-file))
DONE use-package
- State "DONE" from "CNCL" [2024-07-16 Tue 18:02]
"A use-package declaration for simplifying your .emacs"
(require 'use-package)
;; (require 'bind-key)
;; (require 'use-package-ensure)
;; (setq use-package-always-ensure t) ; Ensure use-package installs all packages by default. Use :ensure nil to override.
;; (package-install-selected-packages)
CNCL Quelpa
(unless (package-installed-p 'quelpa)
(with-temp-buffer
(url-insert-file-contents "https://raw.githubusercontent.com/quelpa/quelpa/master/quelpa.el")
(eval-buffer)
(quelpa-self-upgrade)))
DONE System information
- State "DONE" from "TODO" [2023-08-28 Mon 18:46]
- State "DONE" from "DONE" [2023-08-28 Mon 18:43]
- State "DONE" from "NEXT" [2023-08-03 Thu 13:03]
I took this from Sacha's settings. This allows for tweaking configuations according to platform. I intend to use more of this more as I develop Emacs configs across platforms.
(defvar my-laptop-p (equal (system-name) "lilitop"))
(defvar my-server-p (and (equal (system-name) "localhost") (equal user-login-name "root")))
(defvar my-phone-p (not (null (getenv "ANDROID_ROOT")))
"If non-nil, GNU Emacs is running on Termux.")
(when my-phone-p (defvar gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"))
(global-auto-revert-mode) ; simplifies syncing
DONE Persistent history
(savehist-mode)
TODO Backup and versioning
(use-package magit
:ensure t
)
DONE Personal information
(setq user-full-name "Amr Gharbeia")
(defvar email-address "amr@gharbeia.net")
(defvar calendar-latitude 39.0)
(defvar calendar-longitude -77.1)
(defvar calendar-location-name "Washington, DC")
(defvar calendar-time-zone -300)
(defvar calendar-standard-time-zone-name "EST")
(defvar calendar-daylight-time-zone-name "EDT")
TODO
[2/3] Advanced Features
TODO
[0/2] Text
TODO
[0/1] Case
TODO Convert DOuble capitals to single capitals
- State "DONE" from "TODO" [2024-06-27 Thu 13:02]
- State "DONE" from "NEXT" [2023-08-09 Wed 13:51]
(defun my/dcaps-to-scaps ()
"Convert word in DOuble CApitals to Single Capitals."
(interactive)
(and (= ?w (char-syntax (char-before)))
(save-excursion
(and (if (called-interactively-p)
(skip-syntax-backward "w")
(= -3 (skip-syntax-backward "w"))
)
(let (case-fold-search)
(looking-at "\\b[[:upper:]]\\{2\\}[[:lower:]]")
)
(capitalize-word 1)
)
)
)
)
Then, let’s define a minor mode for it to be activated.
(define-minor-mode my-dubcaps-mode
"Toggle 'my-dubcaps-mode' and convert words in DOuble CApitals to Single Capitals as you type."
:init-value nil
:lighter (" DC")
(if my-dubcaps-mode
(add-hook 'post-self-insert-hook #'my/dcaps-to-scaps nil 'local)
(remove-hook 'post-self-insert-hook #'my/dcaps-to-scaps 'local)))
Finally, let’s add a hook so that it is on for all the text files Emacs opens.
(add-hook 'text-mode-hook #'my-dubcaps-mode)
Also, since we add a minor mode string (it might be useful sometimes), currently I prefer to diminish it.
(defun my/diminish-dubcaps ()
(interactive)
(diminish 'my-dubcaps-mode ""))
(add-hook 'my-dubcaps-mode-hook 'my/diminish-dubcaps)
TODO
Text Mode [0/1]
TODO
Outline Mode [0/1]
[4/10] Org Mode
- State "DONE" from "TODO" [2024-02-28 Wed 16:49]
(use-package org
:config
(defvar org-outline-path-complete-in-steps nil)
:bind (("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture)
:map org-mode-map)
)
(defvar org-directory (concat (getenv "HOME") "/memex/"))
[5/6] Looks
- State "DONE" from "TODO" [2024-07-19 Fri 15:58]
- State "DONE" from "TODO" [2024-07-16 Tue 21:51]
(defvar org-pretty-entities t) ; Improve org mode looks
(defvar org-hide-emphasis-markers t) ; Hide emphasis markup
(defvar org-num-mode nil)
(defvar org-startup-folded 'shw2levels)
- State "DONE" from "TODO" [2025-06-22 Sun 13:44]
- State "DONE" from "TODO" [2024-07-16 Tue 21:27]
- State "DONE" from [2023-08-28 Mon 18:17]
(defvar org-startup-indented t) ; Indent org heirarchy
(defvar org-adapt-indentation t)
(defvar org-hide-leading-stars t) ; Minimal Outline
(defvar org-odd-levels-only nil)
- State "DONE" from "TODO" [2025-06-22 Sun 13:45]
- State "DONE" from [2024-02-11 Sun 13:15]
(setq org-list-demote-modify-bullet t)
- State "DONE" from "TODO" [2025-06-22 Sun 13:45]
- State "DONE" from "TODO" [2024-07-16 Tue 21:27]
- State "DONE" from "TODO" [2024-06-27 Thu 13:06]
(use-package org-modern
:ensure t
:config
;; Choose some fonts
(set-face-attribute 'default nil :family "sans-serif")
(set-face-attribute 'variable-pitch nil :family "sans-serif")
(set-face-attribute 'org-modern-symbol nil :family "Iosevka")
;; Edit settings
(defvar org-auto-align-tags nil)
(defvar org-tags-column 0)
(defvar org-catch-invisible-edits 'show-and-error)
(defvar org-special-ctrl-a/e t)
(defvar org-insert-heading-respect-content t)
;; Org styling, hide markup etc.
(defvar org-hide-emphasis-markers t)
(defvar org-pretty-entities t)
;; Agenda styling
(defvar org-agenda-tags-column 0)
(defvar org-agenda-block-separator ?─)
(defvar org-agenda-time-grid
'((daily today require-timed)
(800 1000 1200 1400 1600 1800 2000)
" ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄"))
(defvar org-agenda-current-time-string
"◀── now ─────────────────────────────────────────────────")
;; Ellipsis styling
(defvar org-ellipsis "…")
(set-face-attribute 'org-ellipsis nil :inherit 'default :box nil)
(global-org-modern-mode)
)
- State "DONE" from "TODO" [2025-06-22 Sun 13:46]
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
- State "DONE" from "TODO" [2024-07-19 Fri 15:34]
(setq org-startup-with-inline-images t)
(setq org-image-actual-width '(300))
[4/5] Agenda
- State "DONE" from "TODO" [2025-06-22 Sun 13:57]
- State "DONE" from "TODO" [2024-07-19 Fri 15:52]
(setq org-deadline-warning-days 7)
(setq org-agenda-skip-additional-timestamps-same-entry t)
(setq org-agenda-span 'fortnight)
(setq org-agenda-tags-column 'auto)
(setq org-agenda-skip-scheduled-if-deadline-is-shown t)
- State "DONE" from "TODO" [2025-06-22 Sun 13:57]
(setq org-agenda-files (list
(concat org-directory "/inbox.org")
(concat org-directory "/org-gtd-tasks.org")
)
)
- State "DONE" from "TODO" [2025-06-22 Sun 13:58]
(use-package org-super-agenda)
[4/6] To-do
- State "DONE" from "TODO" [2024-07-19 Fri 15:53]
- State "DONE" from "TODO" [2024-07-19 Fri 15:53]
(setq org-todo-keywords
'(
(sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
(sequence "WAIT(w@/!)" "|" "CNCL(c@)")
)
)
(setq org-todo-keyword-faces
'(
("TODO" :foreground "red" :weight bold)
("NEXT" :foreground "red" :weight bold)
("WAIT" :foreground "yellow" :weight bold)
("DONE" :foreground "green" :weight bold)
("CNCL" :foreground "blue" :weight bold)
)
)
(setq org-enforce-todo-dependencies t)
(setq org-tags-exclude-from-inheritance '("crypt" "!private"))
(defun org-summary-todo (n-done n-not-done)
"Switch entry to 'DONE' when all subentries are done, to 'TODO' otherwise.
Uses N-DONE and N-NOT-DONE"
(let (org-log-done org-log-states) ; turn off logging
(org-todo (if (= n-not-done 0) "DONE" "TODO")
)
)
)
(add-hook 'org-after-todo-statistics-hook #'org-summary-todo)
- State "DONE" from "TODO" [2025-06-22 Sun 13:58]
I am now relying on org-gtd to create a GTD workflow:
- everything comes into ~/org/inbox.org
-
Items are clarified with textual context, then with including:
- a horizon
- tags
Items are then goes into one of the following buckets:
- a single action
- a project
- an action within an existing project
- a sometime/maybe
- a habit
- a knowledge/reference item
- discarded as trash
- The above categories are all now headers in ~/org-gtd-tasks.org, but should each have their own file in the future.
-
All actions are states
- TODO (instead of NEXT. Will decide if I will use next per the orthdoxy)
- WAIT
- DONE
- CNCL
I also used to have MAYBE and STARTED tags. Maybe to avoid having a different pool for it (GTD is old, relies on paper and is therefore sequential. Computers solved this problem). STARTED was the tag for the things I am doing, because my NEXT (TODO) list is huge at the moment, mainly because of decades of backlog.
- Reference is ~/org/library.org. I am beginning to think I might split this further as it grows. My main ~/library is massive, obviously.
- Calendar is still half connected to org-mode and GTD. Need to find a way to connect across devices. org-caldav looks promising.
(use-package org-gtd
:defer t
:init (setq org-gtd-update-ack "3.0.0")
:after org
:config
;; Keeping these two settings on instead of enabling (org-gtd-mode) until this issue is resolved https://github.om/Trevoke/org-gtd.el/issues/198
(setq org-edna-use-inheritance t)
(org-edna-mode)
;; (org-gtd-mode)
:bind (
("C-c d c" . org-gtd-capture)
("C-c d e" . org-gtd-engage)
("C-c d p" . org-gtd-process-inbox)
:map org-gtd-clarify-map
("C-c c" . org-gtd-organize)
)
)
(defvar org-gtd-directory org-directory)
(defvar org-gtd-organize-hooks '(org-gtd-set-area-of-focus org-set-tags-command))
(defvar org-gtd-organize-hooks '(org-gtd-set-area-of-focus))
(defvar org-gtd-areas-of-focus '(
"Atoms"
"Bits"
"Cells"
"Flags"
"Business"
"Wealth"
"Learning"
"Skills"
"Privacy"
"Archive"
"Library"
"Writing"
"Health"
"Home"
"Family"
"Social"
"Egypt"
)
)
(defvar org-gtd-clarify-show-horizons 'right)
(setq org-log-into-drawer "LOGBOOK")
- State "DONE" from "NEXT" [2023-08-03 Thu 13:16]
(setq org-clock-into-drawer t)
- State "DONE" from "TODO" [2024-07-16 Tue 21:36]
- State "DONE" from "TODO" [2023-07-31 Mon 14:33]
(setq org-habit-graph-column 80)
(setq org-habit-show-habits-only-for-today nil)
[3/3] Reifle
- State "DONE" from "TODO" [2025-06-22 Sun 13:59]
- State "DONE" from "TODO" [2025-06-22 Sun 13:59]
- State "DONE" from "TODO" [2024-07-16 Tue 21:38]
- State "DONE" from "TODO" [2023-07-07 Fri 16:51]
Allow refiling to agenda files, nine headers deep, either in current buffer or in agenda files.
(setq org-refile-targets '((nil :maxlevel . 9)
(org-agenda-files :maxlevel . 9)
)
)
- State "DONE" from "TODO" [2025-06-22 Sun 13:59]
- State "DONE" from "TODO" [2023-07-07 Fri 16:50]
This setting is related to the completion of refile targets. If set to `t`, you build the path in steps by selecting one note at a time. This might be useful with deep hierarchies, but can be slow. When set to `nil`, you can enter the path directly, and Org-Mode uses a Helm-like interface to auto-complete the path. This can be faster, but possibly more difficult with deep hierarchies.
(setq org-outline-path-complete-in-steps nil)
- State "DONE" from "TODO" [2023-07-07 Fri 16:50]
(setq org-refile-allow-creating-parent-nodes 'confirm)
[1/2] Capture
- State "DONE" from "DONE" [2024-07-19 Fri 15:50]
- State "DONE" from "DONE" [2023-08-17 Thu 14:06]
- State "DONE" from "DONE" [2023-08-11 Fri 14:16]
- State "DONE" from "TODO" [2023-07-05 Wed 16:51]
(defvar org-default-notes-file (concat org-directory "inbox.org"))
[4/4] Org-protocol
- State "DONE" from "DONE" [2024-07-19 Fri 15:49]
- State "DONE" from "TODO" [2023-07-05 Wed 13:21]
For GNU/Linux setup, put this in ~/.local/share/applications/org-protocol.desktop or in /usr/share/applications to set up system-wide.
[Desktop Entry]
Name=org-protocol
Comment=Intercept calls from emacsclient to trigger custom actions
Categories=Other;
Keywords=org-protocol;
Icon=emacs
Type=Application
Exec=emacsclient -- %u
Terminal=false
StartupWMClass=Emacs
MimeType=x-scheme-handler/org-protocol;
then update the cache database of MIME types handled by desktop files:
update-desktop-database ~/.local/share/applications/
(require 'org-protocol)
(setq org-protocol-default-buffer-for-file-links "*scratch*") ; fixes 'no buffers remain to edit error for org-protocol capturer
And finally, here are the capture templates for org-protocol captures.
(defvar org-capture-templates '(
("p" "Protocol"
entry
(file "inbox.org")
"* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?"
)
("L" "Protocol Link"
entry
(file "inbox.org")
"* %? [[%:link][%:description]]\n:PROPERTIES:\n:TITLE: %:description\n:URI: %:link\n:CREATED: %U\n:END:"
:prepend nil
:empty-lines 1
:created t
:kill-buffer t
)
)
)
(setq org-protocol-default-template-key "L")
- State "DONE" from "TODO" [2023-07-10 Mon 11:52]
This will create clickable titles, create "TITLE", " URL", and "CREATED" properties
(defun my/org-convert-orgzly-to-org-protocol ()
"Reformat Orgzly bookmark at point to org-protocol bookmark."
(interactive)
(when (org-at-heading-p)
(let ((headline (nth 4 (org-heading-components))))
;; Find and store the link. Delete the link line.
(search-forward-regexp "^https?://\\S-*" nil t)
(let ((link (match-string 0)))
(beginning-of-line)
(kill-line)
;; Delete any trailing blank spaces
(org-back-to-heading)
(end-of-line)
(when (not (org-on-heading-p))
(delete-char 1)
)
;; Set new headline
(goto-char (org-entry-beginning-position))
(org-edit-headline (format "[[%s][%s]]" link headline))
;; Set new properties
(org-set-property "TITLE" headline)
(org-set-property "URI" link)
(message "Reformatted Orgzly bookmark at point to org-protocol bookmark")
)
)
)
)
- State "DONE" from "TODO" [2023-08-19 Sat 18:17]
(setq org-roam-capture-templates
'(
("L" "link" plain
(function org-roam--capture-get-point)
"%?"
:file-name "web/%<%Y-%m-%dT%H%M%S>.org"
:head "#+TITLE: ${title}\n#+CREATED: %<%Y-%m-%dT%H%M%S>"
:immediate-finish t
:unnarrowed t
)
("h" "hugo post" plain
"%?"
:target (file+head "posts/${slug}.org"
"#+TITLE: ${title}\n#+DATE: %U\n#+HUGO_BASE_DIR: ~/gharbeia.net\n#+HUGO_SECTION: ./posts\n#+HUGO_AUTO_SET_LASTMOD: t\n#+HUGO_TAGS: article\n#+HUGO_DRAFT: true\n")
:immediate-finish t
:unnarrowed t
)
("p" "person" plain
"%?"
:if-new (file+head "people/${slug}.org"
"#+TITLE: ${title}")
:immediate-finish t
:unnarrowed t
)
)
)
(setq org-roam-dailies-capture-templates
'(
("d" "daily" plain
""
:target ("file+heaed %<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n\n")
:immediate-finish t
)
)
)
[1/5] Org-roam
- State "DONE" from "TODO" [2024-07-16 Tue 21:30]
- State "DONE" from "TODO" [2023-07-05 Wed 17:11]
(use-package org-roam
:init (setq org-roam-v2-ack t) ;; Acknowledge V2 upgrade
:after org
:config
(org-roam-db-autosync-enable)
(require 'org-roam-dailies)
:bind (
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph)
("C-c n r" . org-roam-node-random)
("C-c n h" . org-roam-node-convert-headline)
("C-c n i" . org-roam-node-insert)
("C-c n o" . org-id-get-create)
("C-c n t" . org-roam-tag-add)
("C-c n a" . org-roam-alias-add)
("C-c n l" . org-roam-buffer-display-dedicated)
)
)
(use-package org-roam
; :straight (:files (:defaults "extensions/*"))
:init (setq org-roam-v2-ack t) ;; Acknowledge V2 upgrade
:after org
:config
(org-roam-db-autosync-enable)
(require 'org-roam-dailies)
(setq org-roam-mode-sections
(list #'org-roam-backlinks-section
#'org-roam-reflinks-section
#'org-roam-unlinked-references-section
)
)
(add-to-list 'display-buffer-alist
'("\\*org-roam\\*"
(display-buffer-in-side-window)
(side . right)
(slot . 0)
(window-width . 0.33)
(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t)))))
:bind (
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph)
("C-c n r" . org-roam-node-random)
("C-c n h" . org-roam-node-convert-headline)
("C-c n i" . org-roam-node-insert)
("C-c n o" . org-id-get-create)
("C-c n t" . org-roam-tag-add)
("C-c n a" . org-roam-alias-add)
("C-c n l" . org-roam-buffer-display-dedicated)
)
)
(setq org-roam-directory (concat org-directory "notes"))
(setq org-roam-dailies-directory (concat org-directory "daily"))
(use-package sqlite3)
(require 'sqlite3)
- State "DONE" from "TODO" [2024-07-19 Fri 16:45]
- State "DONE" from "TODO" [2023-07-06 Thu 12:54]
(setq org-roam-file-exclude-regexp "^[.][.]?/")
- State "DONE" from "TODO" [2024-07-19 Fri 16:47]
Note that computing unlinked references may be slow, and has not been added in by default.
(setq org-roam-mode-sections
(list #'org-roam-backlinks-section
#'org-roam-reflinks-section
#'org-roam-unlinked-references-section
)
)
- State "DONE" from "TODO" [2023-08-19 Sat 18:13]
(defun my/org-roam-node-has-tag (node tag)
"Filter function to check if the given NODE has the specified TAG."
(member tag (org-roam-node-tags node))
)
(defun my/org-roam-node-find-by-tag ()
"Find and open an Org-roam node based on a specified tag."
(interactive)
(let ((tag (read-string "Enter tag: ")))
(org-roam-node-find nil nil (lambda (node) (my/org-roam-node-has-tag node tag))))
)
[0/3] Move org header to org-roam-daily
(defun my/org-move-entry-to-daily-notes ()
"Move the current org-mode headline to the daily notes file based on its :CREATED: property."
(interactive)
(let*
(
(created-prop (org-entry-get nil "CREATED"))
(created-date (when created-prop
(org-parse-time-string created-prop)))
(year (nth 5 created-date)) ; Extract year (6th element)
(month (nth 4 created-date)) ; Extract month (5th element)
(day (nth 3 created-date)) ; Extract day (4th element)
(target-date (format "%04d-%02d-%02d" year month day)) ; Format date string
(target-file (org-roam-dailies-goto target-date))
)
(when target-file
(org-cut-subtree)
(find-file target-file)
(goto-char (point-max))
(unless (bolp) (newline))
(org-paste-subtree)
)
)
)
(defun my/org-move-entry-to-daily-notes ()
"Move the current org-mode headline to the daily notes file based on its :CREATED: property."
(interactive)
(let*
(
(created-prop (org-entry-get nil "CREATED"))
(created-date (when created-prop
(org-parse-time-string created-prop)))
(year (nth 5 created-date)) ; Extract year (6th element)
(month (nth 4 created-date)) ; Extract month (5th element)
(day (nth 3 created-date)) ; Extract day (4th element)
(target-date (format "%04d-%02d-%02d" year month day)) ; Format date string
;(target-date "2024-01-01")
(target-file (concat org-roam-dailies-directory "/" target-date ".org"))
(find-file target-file)
)
)
(when target-file
(org-cut-subtree)
(find-file target-file)
(org-id-get-create)
;; #+title: target-date
(goto-char (point-max))
(unless (bolp) (newline))
(org-paste-subtree)
)
)
Arrived to from this conversation
Here's a breakdown of the functions and their roles:
- org-roam-dailies–capture
(defun org-roam-dailies--capture (time &optional goto keys)
"Capture an entry in a daily-note for TIME, creating it if necessary.
When GOTO is non-nil, go the note without creating an entry.
ELisp programs can set KEYS to a string associated with a template.
In this case, interactive selection will be bypassed."
(let ((org-roam-directory (expand-file-name org-roam-dailies-directory org-roam-directory))
(org-roam-dailies-directory "./"))
(org-roam-capture- :goto (when goto '(4))
:keys keys
:node (org-roam-node-create)
:templates org-roam-dailies-capture-templates
:props (list :override-default-time time)))
(when goto (run-hooks 'org-roam-dailies-find-file-hook)))
- `my/refile`: This function refiles a single headline by finding the file, reverting the buffer, and replacing fuzzy links with roam: links.
;;; lisp/refile.el -*- lexical-binding: t; -*-
(defun my/refile ()
"Refiles a headline (and its subtree) with a CREATED property to its corresponding daily."
(interactive)
(revert-buffer t t)
;; replace fuzzy links with roam: links (exclude non-fuzzy links, ie. links with `:')
(while (re-search-forward "\\[\\[\\([^:]+?\\)\\]\\]" nil t)
(replace-match "[[roam:\\1]]" nil nil))
; (org-roam-link-replace-all) ;; TODO create blank page if non-existent
;; remove blank lines because i think they are ugly
(while (re-search-forward "\n+" nil t)
(replace-match "\n" nil nil))
(let ((entries (org-map-entries #'my/refile--inbox-headline nil 'file)))
(message (format "Refiled %d headline(s)" (seq-count #'identity entries)))
)
)
- `my/refile–inbox-headline`: This function refiles a headline at the current point by deleting the CREATED property and capturing the headline using org-capture.
(defun my/refile--inbox-headline ()
"Refile headline at POINT."
(setq org-map-continue-from (point))
(if-let (capture-template (my/refile--get-template))
(my/refile--capture capture-template)
(my/refile--to-node)))
- `my/refile–capture`: This function runs org-capture on an inbox heading and inserts the result into the buffer.
(defun my/refile--capture (capture-template)
"Run 'org-capture' on inbox heading using CAPTURE-TEMPLATE."
;; (org-entry-delete nil "CREATED")
(let ((keys (car capture-template))
(heading (cdr capture-template))
(entry (org-no-properties (org-get-entry))))
(org-capture nil keys)
(insert heading "\n" entry))
(org-capture-finalize)
(org-cut-subtree)
)
- `my/refile–get-template`: This function parses the capture template prefix from the heading and returns a cons cell containing the keys and heading.
(defun my/refile--get-template ()
"Parse capture template prefix from heading."
(when-let* ((raw-heading (org-no-properties (org-get-heading)))
(match (string-match "@\\(\\w+\\) \\(.+\\)$" raw-heading))
(keys (match-string-no-properties 1 raw-heading))
(heading (match-string-no-properties 2 raw-heading)))
(cons keys heading))
)
- `my/refile–to-node`: This function refiles a headline to an Org-roam node.
(defun my/refile--to-node ()
"Refiles non-capture headings to org-roam node."
(if-let ((to (+org/entry-get-delete "TO")))
(my/refile--org-roam-node (org-roam-node-from-title-or-alias to))
(my/refile--to-daily)))
- `my/refile–to-daily`: This function refiles a headline to a daily node based on its CREATED property.
(defun my/refile--to-daily ()
"Refile headline at POINT to the associated daily node based on its `CREATED' property."
(when-let* ((created (org-entry-get nil "CREATED"))
(time (org-time-string-to-time created))
(daily-node (my/refile--get-daily-node time)))
(org-entry-delete nil "CREATED")
(my/refile--org-roam-node daily-node)))
- `my/refile–get-daily-node`: This function returns the Org-roam node for a given time.
(defun my/refile--get-daily-node (time)
"Return org-roam node for TIME."
(save-window-excursion
(org-roam-dailies--capture time t)
(org-roam-node-at-point)))
- `my/refile–org-roam-node`: This function refiles a node to an Org-roam node. The `my/refile–org-roam-node` function is quite long and complex, but it seems to be responsible for refiling a node to an Org-roam node. It takes several arguments, including the node to refile, and uses several org-roam functions to perform the refiling.
(defun my/refile--org-roam-node (node)
"Refile NODE at point to an Org-roam node.
If region is active, then use it instead of the node at point.
Implementation of `org-roam-refile' from org-roam PR #2388."
(interactive
(list (org-roam-node-read nil nil nil 'require-match)))
(let* ((regionp (org-region-active-p))
(region-start (and regionp (region-beginning)))
(region-end (and regionp (region-end)))
(file (org-roam-node-file node))
(nbuf (or (find-buffer-visiting file)
(find-file-noselect file)))
level reversed)
(if (equal (org-roam-node-at-point) node)
(user-error "Target is the same as current node")
(if regionp
(progn
(org-kill-new (buffer-substring region-start region-end))
(org-save-markers-in-region region-start region-end))
(progn
(if (org-before-first-heading-p)
(org-roam-demote-entire-buffer))
(org-copy-subtree 1 nil t)))
(with-current-buffer nbuf
(org-with-wide-buffer
(goto-char (org-roam-node-point node))
(setq level (org-get-valid-level (funcall outline-level) 1)
reversed (org-notes-order-reversed-p))
(goto-char
(if reversed
(or (outline-next-heading) (point-max))
(or (save-excursion (org-get-next-sibling))
(org-end-of-subtree t t)
(point-max))))
(unless (bolp) (newline))
(org-paste-subtree level nil nil t)
(and org-auto-align-tags
(let ((org-loop-over-headlines-in-active-region nil))
(org-align-tags)))
(when (fboundp 'deactivate-mark) (deactivate-mark))))
(if regionp
(delete-region (point) (+ (point) (- region-end region-start)))
(org-preserve-local-variables
(delete-region
(and (org-back-to-heading t) (point))
(min (1+ (buffer-size)) (org-end-of-subtree t t) (point)))))
;; If the buffer end-up empty after the refile, kill it and delete its
;; associated file.
(when (eq (buffer-size) 0)
(if (buffer-file-name)
(delete-file (buffer-file-name)))
(set-buffer-modified-p nil)
;; If this was done during capture, abort the capture process.
(when (and org-capture-mode
(buffer-base-buffer (current-buffer)))
(org-capture-kill))
(kill-buffer (current-buffer))))))
(defun +org/entry-get-delete (entry)
(prog1 (org-entry-get nil entry) (org-entry-delete nil entry)))
(defun my/org-roam-copy-todo-to-today ()
(interactive)
(let ((org-refile-keep t) ;; Set this to nil to delete the original!
(org-roam-dailies-capture-templates
'(("t" "tasks" entry "%?"
:if-new (file+head+olp "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n" ("Tasks")))))
(org-after-refile-insert-hook #'save-buffer)
today-file
pos)
(save-window-excursion
(org-roam-dailies--capture (current-time) t)
(setq today-file (buffer-file-name))
(setq pos (point)))
;; Only refile if the target file is different than the current file
(unless (equal (file-truename today-file)
(file-truename (buffer-file-name)))
(org-refile nil nil (list "Tasks" today-file nil pos)))))
(add-to-list 'org-after-todo-state-change-hook
(lambda ()
(when (equal org-state "DONE")
(my/org-roam-copy-todo-to-today))))
[1/1]
- State "DONE" from "TODO" [2025-03-24 Mon 17:31]
From Sriramkswamy:
Org has a powerful exporting feature. Let’s select the various formats to export and also mention how exactly we need it to export to LaTeX with syntax highlighting. I have also taken a good looking CSS configuration from Zhitao Gong and I use it for exporting by putting it in the same folder as my org file and adding #+HTML_HEAD: <link rel="stylesheet" type="text/css" href="org.css"/> to the top of my org file.
(setq org-export-with-smart-quotes t)
(setq org-export-backends '(beamer html latex md))
- State "DONE" from [2025-03-24 Mon 17:31]
(use-package ox-epub
)
(defvar org-attach-id-dir (concat org-directory "attachments"))
(defvar org-babel-do-load-languages 'org-babel-load-languages '((shell . t)))
- State "DONE" from "TODO" [2023-08-18 Fri 13:10]
(use-package org-cliplink
:bind
(("C-x p i" . org-cliplink))
)
(use-package deft
:commands (deft)
:init
(defvar deft-extensions '("org"))
(defvar deft-recursive nil)
(defvar deft-use-filename-as-title t)
:config
(defvar deft-directory org-directory)
(defvar deft-recursive t)
(defvar deft-strip-summary-regexp ":PROPERTIES:\n\\(.+\n\\)+:END:\n")
(defvar deft-use-filename-as-title t)
:bind ("C-c n d" . deft)
)
DONE
[3/3] Shell
- State "DONE" from "TODO" [2024-07-19 Fri 15:34]
- State "DONE" from "TODO" [2024-07-09 Tue 17:11]
DONE Bash completion
- State "DONE" from "TODO" [2024-07-16 Tue 20:35]
- State "DONE" from "TODO" [2023-08-18 Fri 13:02]
(use-package bash-completion
:config
(require 'bash-completion)
(bash-completion-setup)
)
(defvar shell-dynamic-complete-functions t)
DONE
[3/3] Eshell
- State "DONE" from "TODO" [2024-02-28 Wed 16:30]
(require 'bash-completion)
(add-hook 'eshell-mode-hook
(lambda ()
(add-hook 'completion-at-point-functions
'bash-completion-capf-nonexclusive nil t
)
)
)
- State "DONE" from "TODO" [2023-08-28 Mon 18:56]
(use-package xterm-color
:commands (xterm-color-filter)
)
(use-package eshell
:after xterm-color
:config
(define-key eshell-hist-mode-map (kbd "M-r") #'consult-history)
(add-hook 'eshell-mode-hook
(lambda ()
(setenv "TERM" "xterm-256color")))
(add-hook 'eshell-before-prompt-hook (setq xterm-color-preserve-properties t))
(add-to-list 'eshell-preoutput-filter-functions 'xterm-color-filter)
(setq eshell-output-filter-functions
(remove 'eshell-handle-ansi-color eshell-output-filter-functions)
)
)
(add-hook 'eshell-mode-hook
(lambda ()
(add-hook 'completion-at-point-functions
'bash-completion-capf-nonexclusive nil t)))
CNCL Emulate A Terminal (EAT)
- State "CNCL" from "TODO" [2024-04-01 Mon 15:52]
Moved to shell and eshell. Eat is not in repositories currently. - State "DONE" from [2023-08-30 Wed 20:43]
(use-package eat
:config
;; For `eat-eshell-mode'.
(add-hook 'eshell-load-hook #'eat-eshell-mode)
;; For `eat-eshell-visual-command-mode'.
(add-hook 'eshell-load-hook #'eat-eshell-visual-command-mode)
)
DONE
[2/2] Saving Emacs Sessions
- State "DONE" from "TODO" [2024-07-19 Fri 15:08]
- State "DONE" from "DONE" [2024-02-28 Wed 16:26]
DONE Close frame when done
- State "DONE" from "NEXT" [2023-08-03 Thu 13:21]
When a server buffer is done, the current window (frame) should be closed. This is useful in scenarios where Emacs is used as an external editor (for instance, from a version control system). When you're done editing, the frame closes automatically. If this is the only frame, Emacs will exit.
(add-hook 'server-done-hook (lambda () (delete-frame)))
DONE Save desktop session
(desktop-save-mode t)
TODO
[8/21] Reading and Writing
- State "DONE" from "TODO" [2023-07-06 Thu 12:32]
DONE Move correctly over camelCased words
- State "DONE" from "TODO" [2024-07-19 Fri 16:04]
(subword-mode)
DONE Understand the more common sentence with double space
- State "DONE" from "TODO" [2024-07-19 Fri 16:04]
(setq sentence-end-double-space nil)
DONE Join lines into paragraph
- State "DONE" from "TODO" [2024-07-19 Fri 16:03]
- State "DONE" from "TODO" [2023-07-06 Thu 12:31]
(defun my/fill-or-unfill-paragraph (&optional unfill region)
"Fill paragraph (or REGION). With the prefix argument UNFILL, fill it instead."
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'fill) t)))
(let ((fill-column (if unfill fill-column (point-max))))
(fill-paragraph nil region)))
(bind-key "M-q" 'my/fill-or-unfill-paragraph)
(defun my/fill-or-unfill-all-paragraphs (&optional unfill)
"Fill or unfill all paragraphs in the current buffer.
With the prefix argument UNFILL, fill them instead."
(interactive (list (if current-prefix-arg 'fill)))
(let ((fill-column (if unfill fill-column (point-max))))
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(fill-paragraph nil t)
(forward-paragraph)))))
(bind-key "M-Q" 'my/fill-or-unfill-all-paragraphs)
(remove-hook 'text-mode-hook #'turn-on-auto-fill)
(add-hook 'text-mode-hook 'turn-on-visual-line-mode)
TODO Expand some words with auto-correct
(setq save-abbrevs 'silently)
(setq-default abbrev-mode t)
TODO ediff
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(setq ediff-split-window-function 'split-window-horizontally)
TODO tramp
(setq tramp-default-method "ssh"
tramp-backup-directory-alist backup-directory-alist
tramp-ssh-controlmaster-options "ssh")
TODO Clean up space
- State "DONE" from "TODO" [2023-07-06 Thu 12:32]
(bind-key "M-SPC" 'cycle-spacing)
TODO Transform <a href> links into org links
- State "DONE" from [2023-08-19 Sat 19:41]
(defun my/transform-html-links-to-org ()
"Transform all HTML <a> links in the current buffer into 'org-mode' links."
(interactive)
(goto-char (point-min))
(while (re-search-forward "<a href=\"\\(.*?\\)\">\\(.*?\\)</a>" nil t)
(replace-match (org-make-link-string (match-string 1) (match-string 2)))))
TODO Count words per minute
- State "DONE" from "TODO" [2023-07-06 Thu 12:32]
(require 'org-clock)
(defun my/org-entry-wpm ()
(interactive)
(save-restriction
(save-excursion
(org-narrow-to-subtree)
(goto-char (point-min))
(let* ((words (count-words-region (point-min) (point-max)))
(minutes (org-clock-sum-current-item))
(wpm (/ words minutes)))
(message "WPM: %d (words: %d, minutes: %d)" wpm words minutes)
(kill-new (number-to-string wpm))
)
)
)
)
TODO Enable dict mode
(setq dictionary-server "automatic")
TODO Pick out passive voice and weasel words
- State "DONE" from "NEXT" [2023-08-09 Wed 13:52]
(use-package writegood-mode
:diminish writegood-mode
:config
(progn (add-hook 'text-mode-hook 'writegood-mode))
)
TODO Org-babel docker
- State "DONE" from "TODO" [2024-07-09 Tue 16:58]
(use-package ob-docker-build
:straight (ob-docker-build :type git :host github :repo "ifitzpat/ob-docker-build")
:defer t
:config
(add-to-list 'org-babel-load-languages '(docker-build . t))
(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
)
TODO
[1/6] Spelling and syntax
DONE Spell checking
- State "DONE" from "TODO" [2024-07-19 Fri 16:51]
- State "DONE" from "TODO" [2023-07-05 Wed 16:09]
This requires installation of hunspell
sudo apt install hunspell
(use-package flyspell
:config (setq ispell-program-name "hunspell"
ispell-default-dictionary "en_US"
)
:diminish (flyspell-mode . "φ")
:hook (text-mode . flyspell-mode)
:bind (
("M-<f7>" . flyspell-buffer)
("<f7>" . flyspell-word)
("C-;" . flyspell-auto-correct-previous-word)
)
)
TODO Flyspell correct
- State "DONE" from [2024-07-02 Tue 13:13]
(use-package flyspell-correct
:after flyspell
:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))
)
TODO Flycheck
- State "DONE" from "TODO" [2024-07-19 Fri 14:30]
- State "DONE" from "TODO" [2024-07-02 Tue 13:13]
Needs external checkers installed
(use-package flycheck
:init (global-flycheck-mode)
:diminish (flycheck-mode . "")
:config
(add-hook 'after-init-hook #'global-flycheck-mode)
(setq flycheck-emacs-lisp-load-path 'inherit)
(setq flycheck-emacs-lisp-load-path (concat user-emacs-directory "straight/build"))
)
TODO Flycheck bash
sudo apt install devscripts
(use-package flycheck-checkbashisms
:config
(flycheck-checkbashisms-setup)
)
TODO Yaml
- State "DONE" from "TODO" [2024-06-27 Thu 13:03]
(use-package yaml-mode
:config
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
)
TODO Docker
- State "DONE" from "TODO" [2024-06-27 Thu 13:03]
(use-package docker-compose-mode)
DONE Read ebooks
- State "DONE" from "NEXT" [2023-08-09 Wed 13:27]
(use-package calibredb
:defer t
:config
(setq calibredb-format-all-the-icons t)
(setq calibredb-format-icons-in-terminal t)
)
;; Forcefully reset the variable after loading calibredb
(defvar calibredb-root-dir (concat (getenv "HOME") "/library/books"))
(defvar calibredb-db-dir (expand-file-name "metadata.db" calibredb-root-dir))
; (defvar calibredb-library-alist (concat (getenv "HOME") "/library/books"))
;; (defvar calibredb-search-page-max-rows 1000)
(defvar calibredb-id-width 6)
(defvar calibredb-title-width 100)
(defvar calibredb-format-width 0)
(defvar calibredb-date-width 0)
(defvar calibredb-author-width 20)
(defvar calibredb-comment-width 0)
(defvar calibredb-tag-width 0)
Some keybindings
(defvar calibredb-show-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "?" #'calibredb-entry-dispatch)
(define-key map "o" #'calibredb-find-file)
(define-key map "O" #'calibredb-find-file-other-frame)
(define-key map "V" #'calibredb-open-file-with-default-tool)
(define-key map "s" #'calibredb-set-metadata-dispatch)
(define-key map "e" #'calibredb-export-dispatch)
(define-key map "q" #'calibredb-entry-quit)
(define-key map "y" #'calibredb-yank-dispatch)
(define-key map "," #'calibredb-quick-look)
(define-key map "." #'calibredb-dired-open)
(define-key map "\M-/" #'calibredb-rga)
(define-key map "\M-t" #'calibredb-set-metadata--tags)
(define-key map "\M-a" #'calibredb-set-metadata--author_sort)
(define-key map "\M-A" #'calibredb-set-metadata--authors)
(define-key map "\M-T" #'calibredb-set-metadata--title)
(define-key map "\M-c" #'calibredb-set-metadata--comments)
map)
"Keymap for `calibredb-show-mode'.")
(defvar calibredb-search-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [mouse-3] #'calibredb-search-mouse)
(define-key map (kbd "<RET>") #'calibredb-find-file)
(define-key map "?" #'calibredb-dispatch)
(define-key map "a" #'calibredb-add)
(define-key map "A" #'calibredb-add-dir)
(define-key map "c" #'calibredb-clone)
(define-key map "d" #'calibredb-remove)
(define-key map "D" #'calibredb-remove-marked-items)
(define-key map "j" #'calibredb-next-entry)
(define-key map "k" #'calibredb-previous-entry)
(define-key map "l" #'calibredb-virtual-library-list)
(define-key map "L" #'calibredb-library-list)
(define-key map "n" #'calibredb-virtual-library-next)
(define-key map "N" #'calibredb-library-next)
(define-key map "p" #'calibredb-virtual-library-previous)
(define-key map "P" #'calibredb-library-previous)
(define-key map "s" #'calibredb-set-metadata-dispatch)
(define-key map "S" #'calibredb-switch-library)
(define-key map "o" #'calibredb-find-file)
(define-key map "O" #'calibredb-find-file-other-frame)
(define-key map "v" #'calibredb-view)
(define-key map "V" #'calibredb-open-file-with-default-tool)
(define-key map "," #'calibredb-quick-look)
(define-key map "." #'calibredb-dired-open)
(define-key map "y" #'calibredb-yank-dispatch)
(define-key map "b" #'calibredb-catalog-bib-dispatch)
(define-key map "e" #'calibredb-export-dispatch)
(define-key map "r" #'calibredb-search-refresh-and-clear-filter)
(define-key map "R" #'calibredb-search-clear-filter)
(define-key map "q" #'calibredb-search-quit)
(define-key map "m" #'calibredb-mark-and-forward)
(define-key map "f" #'calibredb-toggle-favorite-at-point)
(define-key map "x" #'calibredb-toggle-archive-at-point)
(define-key map "h" #'calibredb-toggle-highlight-at-point)
(define-key map "u" #'calibredb-unmark-and-forward)
(define-key map "i" #'calibredb-edit-annotation)
(define-key map (kbd "<DEL>") #'calibredb-unmark-and-backward)
(define-key map (kbd "<backtab>") #'calibredb-toggle-view)
(define-key map (kbd "TAB") #'calibredb-toggle-view-at-point)
(define-key map "\M-n" #'calibredb-show-next-entry)
(define-key map "\M-p" #'calibredb-show-previous-entry)
(define-key map "/" #'calibredb-search-live-filter)
(define-key map "\M-t" #'calibredb-set-metadata--tags)
(define-key map "\M-a" #'calibredb-set-metadata--author_sort)
(define-key map "\M-A" #'calibredb-set-metadata--authors)
(define-key map "\M-T" #'calibredb-set-metadata--title)
(define-key map "\M-c" #'calibredb-set-metadata--comments)
map)
"Keymap for `calibredb-search-mode'.")
DONE Annotate PDFs and EPUBs
- State "DONE" from "TODO" [2024-07-19 Fri 14:35]
- State "DONE" from "NEXT" [2023-08-09 Wed 15:06]
(use-package org-noter)
(defvar org-noter-notes-search-path (list (concat org-directory "/library/books")))
(defvar org-noter-default-notes-file-names '("books.org"))
DONE Link PDFs
- State "DONE" from "TODO" [2024-07-19 Fri 16:54]
- State "DONE" from "NEXT" [2023-08-12 Sat 14:05]
(use-package org-noter-pdftools
:after org-noter
:config
;; Add a function to ensure precise note is inserted
(defun org-noter-pdftools-insert-precise-note (&optional toggle-no-questions)
(interactive "P")
(org-noter--with-valid-session
(let ((org-noter-insert-note-no-questions (if toggle-no-questions
(not org-noter-insert-note-no-questions)
org-noter-insert-note-no-questions))
(org-pdftools-use-isearch-link t)
(org-pdftools-use-freepointer-annot t))
(org-noter-insert-note (org-noter--get-precise-info)))))
;; fix https://github.com/weirdNox/org-noter/pull/93/commits/f8349ae7575e599f375de1be6be2d0d5de4e6cbf
(defun org-noter-set-start-location (&optional arg)
"When opening a session with this document, go to the current location.
With a prefix ARG, remove start location."
(interactive "P")
(org-noter--with-valid-session
(let ((inhibit-read-only t)
(ast (org-noter--parse-root))
(location (org-noter--doc-approx-location (when (called-interactively-p 'any) 'interactive))))
(with-current-buffer (org-noter--session-notes-buffer session)
(org-with-wide-buffer
(goto-char (org-element-property :begin ast))
(if arg
(org-entry-delete nil org-noter-property-note-location)
(org-entry-put nil org-noter-property-note-location
(org-noter--pretty-print-location location))))))))
(with-eval-after-load 'pdf-annot
(add-hook 'pdf-annot-activate-handler-functions #'org-noter-pdftools-jump-to-note)
)
)
DONE View EPUBs books
- State "DONE" from "TODO" [2024-07-19 Fri 14:37]
- State "DONE" from "NEXT" [2023-08-09 Wed 13:19]
(use-package nov
:config
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
)
TODO Zotero
(use-package helm-bibtex)
(defvar bibtex-completion-bibliography '("~/bibliography/zotero.bib"))
DONE
[2/2] Security
- State "DONE" from "TODO" [2024-07-16 Tue 21:49]
- State "DONE" from "TODO" [2024-07-09 Tue 14:16]
DONE Password-store
- State "DONE" from "TODO" [2024-07-16 Tue 21:49]
- State "DONE" from "TODO" [2023-07-06 Thu 11:44]
(use-package password-store)
DONE Auth source
- State "DONE" from "TODO" [2023-07-06 Thu 11:45]
(use-package auth-source
:config (auth-source-pass-enable)
)
TODO
[2/3] AI
DONE Ellama
- State "DONE" from "TODO" [2024-07-19 Fri 17:27]
- State "DONE" from "TODO" [2024-06-27 Thu 07:40]
;; YOU DON'T NEED NONE OF THIS CODE FOR SIMPLE INSTALL
;; IT IS AN EXAMPLE OF CUSTOMIZATION.
(use-package ellama
:init
(require 'llm-openai)
;; setup key bindings
(setq ellama-keymap-prefix "C-c e")
)
(setopt ellama-providers
'(
;; Ollama Provider (added here with a name)
("ollama" . (make-llm-ollama
;; Consider a dedicated embedding model if gemma isn't ideal for it.
:chat-model "gemma3:latest"
:embedding-model "gemma3:latest" ; Or e.g., "nomic-embed-text"
:default-chat-non-standard-params '(("num_ctx" . 8192))))
("openai" . (make-llm-openai
:key (auth-source-pass-get "api-key" "www/openai.com/amr@gharbeia.net")
:chat-model "gpt-4o"
:embedding-model "text-embedding-3-large"))
("google" . (make-llm-google
:key (auth-source-pass-get "gemini-api-key" "www/google.com/amr.gharbeia")
:chat-model "latest" ; Use "latest" or specific version
:embedding-model "text-embedding-004")) ; Or gecko, but 004 is newer
("groq" . (make-llm-openai-compatible
:url "https://api.groq.com/openai/v1"
:key (auth-source-pass-get "api-key" "www/console.groq.com/groq@amr.gharbeia.net")
;; Check Groq console for available models, these might change
:chat-model "llama3-70b-8192" ; Example, verify on Groq
:embedding-model "llama3-70b-8192")) ; Groq might not offer dedicated embedding models via this API
))
;; --- Set Active Providers ---
;; Choose your default provider from the list above by its name
(setopt ellama-provider "ollama") ; Or "ollama", "openai", "groq"
;; You can specify different providers for different tasks if needed
(setopt ellama-translation-provider "ollama")
(setopt ellama-naming-provider "ollama")
(setopt ellama-naming-scheme 'ellama-generate-name-by-llm)
;; --- Ensure auth-source is configured ---
;; (require 'auth-source)
;; (setq auth-sources '("~/.authinfo.gpg" "~/.authinfo" "~/.netrc"))
;; Make sure your API keys are correctly stored in one of these files.
;; Example .authinfo.gpg entry for OpenAI:
;; machine www/openai.com/amr@gharbeia.net login amr@gharbeia.net password YOUR_OPENAI_API_KEY
;; Example .authinfo.gpg entry for Google Gemini:
;; machine www/google.com/amr.gharbeia login amr.gharbeia password YOUR_GEMINI_API_KEY
;; Example .authinfo.gpg entry for Groq:
;; machine www/console.groq.com/groq@amr.gharbeia.net login groq@amr.gharbeia.net password YOUR_GROQ_API_KEY
(setq llm-debug t)
(use-package ellama
:ensure t
:bind ("C-c e" . ellama)
;; send last message in chat buffer with C-c C-c
:hook (org-ctrl-c-ctrl-c-final . ellama-chat-send-last-message)
:init (setopt ellama-auto-scroll t)
:config
;; show ellama context in header line in all buffers
(ellama-context-header-line-global-mode +1)
;; show ellama session id in header line in all buffers
(ellama-session-header-line-global-mode +1))
CNCL GPTel
- State "CNCL" from "DONE" [2024-04-01 Mon 15:32]
Moved to Ellama - State "DONE" from "TODO" [2024-02-28 Wed 16:49]
(use-package gptel)
(setq gptel-api-key (auth-source-pass-get "api-key" "www/console.groq.com/groq@amr.gharbeia.net"))
(gptel-make-openai "Groq" ;Any name you want
:host "api.groq.com"
:endpoint "/openai/v1/chat/completions"
:stream t
:key (auth-source-pass-get "api-key" "www/console.groq.com/groq@amr.gharbeia.net") ;can be a function that returns the key
:models '(llama-3.1-70b-versatile
llama-3.1-8b-instant
llama3-70b-8192
llama3-8b-8192
mixtral-8x7b-32768
gemma-7b-it))
TODO Elisa
(use-package elisa
:init
(setopt elisa-limit 5)
(require 'llm-ollama)
(setopt elisa-embeddings-provider (make-llm-ollama :embedding-model "nomic-embed-text"))
(setopt elisa-chat-provider (make-llm-ollama
:chat-model "sskostyaev/openchat:8k-rag"
:embedding-model "nomic-embed-text"))
)
DONE Accounting
- State "DONE" from "TODO" [2024-07-19 Fri 15:07]
- State "DONE" from "TODO" [2024-06-27 Thu 07:43]
(use-package beancount
:straight (beancount :type git :host github :repo "beancount/beancount-mode")
:config
(add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode))
(add-hook 'beancount-mode-hook #'outline-minor-mode)
(define-key beancount-mode-map (kbd "C-c C-n") #'outline-next-visible-heading)
(define-key beancount-mode-map (kbd "C-c C-p") #'outline-previous-visible-heading)
(add-hook 'beancount-mode-hook #'flymake-bean-check-enable)
)
On package.el, it is a manual install so far
(make-directory (expand-file-name "manual-packages/" user-emacs-directory) t)
(make-directory (expand-file-name "beancount/" (concat user-emacs-directory "manual-packages")) t)
(add-to-list 'load-path "~/.emacs.d/manual-packages/beancount-mode")
(require 'beancount)
(add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode))
(add-hook 'beancount-mode-hook #'outline-minor-mode)
(define-key beancount-mode-map (kbd "C-c C-n") #'outline-next-visible-heading)
(define-key beancount-mode-map (kbd "C-c C-p") #'outline-previous-visible-heading)
(add-hook 'beancount-mode-hook #'flymake-bean-check-enable)
cd ~/.emacs.d/manual-packages/
git clone https://github.com/beancount/beancount-mode/
DONE Browser
- State "DONE" from "TODO" [2024-07-19 Fri 17:28]
- State "DONE" from "TODO" [2023-07-07 Fri 15:29]
(use-package eww
:bind* (("M-m g x" . eww)
("M-m g :" . eww-browse-with-external-browser)
("M-m g #" . eww-list-histories)
("M-m g {" . eww-back-url)
("M-m g }" . eww-forward-url))
:config
(progn
(add-hook 'eww-mode-hook 'visual-line-mode)
)
)
DONE Manage Docker in Emacs
- State "DONE" from "TODO" [2024-07-19 Fri 17:29]
(use-package docker
:bind ("C-c d" . docker)
)
DONE Periodic table of the elements chemistry
- State "DONE" from "TODO" [2024-07-19 Fri 17:29]
- State "DONE" from "TODO" [2023-08-21 Mon 13:27]
(use-package chemtable)
Org-agent
;; 1. Manually add the path to your load-path
(add-to-list 'load-path "~/memex/projects/org-agent/src")
;; 2. Explicitly load the file
(require 'org-agent)
;; 3. Configure the variables AFTER the package is loaded
(setq org-agent-host "10.10.10.201")
(setq org-agent-port 9105)
(setq org-agent-executable-path nil)
;; 4. (Optional) Re-enable use-package features if you prefer
(use-package org-agent
:straight nil
:commands (org-agent-connect org-agent-disconnect))
(message "org-agent: Actuator manually verified at %s" org-agent-host)
;; (use-package org-agent
;; :straight nil
;; :load-path "~/memex-amero/projects/org-agent/src" ;; Adjust this to your local clone path
;; :commands (org-agent-connect org-agent-disconnect)
;; :init
;; Remote connection settings
;; (setq org-agent-host "10.10.10.43") ;; Your Docker server's IP
;; (setq org-agent-port 9105) ;; Must match ORG_AGENT_DAEMON_PORT in .env
;; Optimization: Automatically connect when entering Org-mode (optional)
;; :hook (org-mode . org-agent-connect)
;; :config
;; Ensure Emacs is acting as a proper sensor
;; (message "org-agent: Actuator configured for remote brain at %s"
;; (org-agent-host))
;; )
DONE End matter
(provide 'config)
;;; config.el ends here
(provide 'custom)
;;; custom.el ends here