Since Org-roam v2 creates a top properties drawer (with an :ID:
tag) anyway, it is nice to stick other information there as well. Specifically, information that could be useful in some situation, but which usually we don’t want to see, like :AUTHOR:
(it’s probably you, and you know who you are), :CREATION_TIME:
(and why not use Unix epoch time?), and so on. I have org drawers fold themselves automatically, so the normally-useless information doesn’t distract me.
We can do this by leveraging Org-roam’s org-roam-capture-new-node-hook
, and some org-roam-add-property
function calls, as below.
But, while we’re at it, we might also record where a note was made from. There are a number of ways we might do this, but an easy one (only requiring curl
and an active Internet connection) is using ipinfo.io. curl ipinfo.io
will give you a bunch of information in JSON format about your internet provider, including latitude and longitude, which will likely be at least somewhere near your present location. And curl ipinfo.io/loc
will return just latitude,longitude.
(defun bms/add-other-auto-props-to-org-roam-properties ()
;; if the file already exists, don't do anything, otherwise...
(unless (file-exists-p (buffer-file-name))
;; if there's also a CREATION_TIME property, don't modify it
(unless (org-find-property "CREATION_TIME")
;; otherwise, add a Unix epoch timestamp for CREATION_TIME prop
;; (this is what "%s" does - see http://doc.endlessparentheses.com/Fun/format-time-string )
(org-roam-add-property
(format-time-string "%s"
(nth 5
(file-attributes (buffer-file-name))))
"CREATION_TIME"))
;; similarly for AUTHOR and MAIL properties
(unless (org-find-property "AUTHOR")
(org-roam-add-property roam-user "AUTHOR"))
(unless (org-find-property "MAIL")
(org-roam-add-property roam-email "MAIL"))
;; also add the latitude and longitude
(unless (org-find-property "LAT_LONG")
;; recheck location:
(bms/get-lat-long-from-ipinfo)
(org-roam-add-property (concat (number-to-string calendar-latitude) "," (number-to-string calendar-longitude)) "LAT-LONG"))))
;; hook to be run whenever an org-roam capture completes
(add-hook 'org-roam-capture-new-node-hook #'bms/add-other-auto-props-to-org-roam-properties)
;; function to find latitude & longitude
;; (requires curl to be installed on system)
(setq calendar-latitude 0)
(setq calendar-longitude 0)
(defun bms/get-lat-long-from-ipinfo ()
(let*
((latlong (substring
(shell-command-to-string "curl -s 'ipinfo.io/loc'")
0 -1))
(latlong-list (split-string latlong ",")))
(setq calendar-latitude (string-to-number (car latlong-list)))
(setq calendar-longitude (string-to-number (cadr latlong-list)))))
You might also calculate/set calendar-latitude
and calendar-longitude
in other ways. Including just hard-coding them for stationary machines. On Android, we could in theory make use of the Termux command termux-location
, which queries the device’s GPS. But unfortunately it doesn’t always work (if it can’t find a good connection to a GPS satellite) and even when it does work it’s slow, so it’s not something you’d want to call every time you made a note. GeoClue would be another possible source.
(If you’re using a VPN, you’ll want to escape from it somehow to get something closer to your real location. How you do this will vary based on your VPN provider and other factors. (If you’re calling from Emacs, and you use something like Mullvad, you may want to revise the shell-command-to-string
to call up a bash session/script, then exclude that specific bash session/script from the VPN, and then call curl
, so that the call references your “real” IP. E.g. if you’re using Mullvad, then:
#!/bin/bash
PID=`echo $$`
mullvad split-tunnel pid add "${PID}"
curl ipinfo.io/loc # for lat/long ; `curl ipinfo.io` for full info
might give you a start on something.))
Let me know if you think of other properties that could be useful to automatically add to Org-roam file properties.
]]>It’s pretty useful to be able to have access to these notes, and be able to quickly add notes, on mobile as well. I thought it might be useful to include here some notes on how to do, since (especially since v2 of Org-roam) there are some hurdles.
On Android/LineageOS install the F-Droid app store, and then from
there install Termux. Open Termux and install four things we’ll need
(strictly speaking you don’t need curl and ripgrep, but they’ll
be useful): Emacs, sqlite, curl, and ripgrep via pkg install emacs sqlite curl ripgrep
.
You can then open up Emacs via emacs
and get started.
I include here a commented partial version of my ~/.emacs.d/init.el
configuration file for my Termux/Emacs Org-roam setup:
;; BASIC SETUP:
;; package setup - bootstrap the package system
(require 'package)
(setq package-enable-at-startup nil)
(setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3")
(setq package-archives
'(("GNU ELPA" . "https://elpa.gnu.org/packages/")
("ORG" . "https://orgmode.org/elpa/")
("MELPA Stable" . "https://stable.melpa.org/packages/")
("MELPA" . "https://melpa.org/packages/"))
package-archive-priorities
'(("ORG" . 20)
("MELPA" . 15)
("MELPA Stable" . 10)
("GNU ELPA" . 5)))
(package-initialize)
;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
;; for Termux-specific things; useful if you want to share
;; configs across platforms
(defvar termux-p
(not (null (getenv "ANDROID_ROOT")))
"If non-nil, GNU Emacs is running on Termux.")
(when termux-p
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package)))
;; This makes Emacs in Termux use your Android browser for opening urls
(setq browse-url-browser-function 'browse-url-xdg-open)
;; mouse
;; enable mouse reporting for terminal emulators
;; this lets you scroll around by swiping
(unless window-system
(xterm-mouse-mode 1)
(global-set-key [mouse-4] (lambda ()
(interactive)
(scroll-down 1)))
(global-set-key [mouse-5] (lambda ()
(interactive)
(scroll-up 1))))
;; ORG
(use-package org
:ensure t
:ensure org-plus-contrib
:init
(setq org-src-fontify-natively t)
:config
;; (add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode))
(define-key org-mode-map (kbd "M-p") 'org-metaup)
(define-key org-mode-map (kbd "M-n") 'org-metadown)
(setq org-catch-invisible-edits 'show-and-error)
(setq org-cycle-separator-lines -1)
(setq org-return-follows-link t)
(setq org-export-with-toc 'nil)
(setq org-startup-folded 'content)
(setq org-ellipsis "⇣")
;; **** use regular android apps to view pdfs & images *****
(when termux-p
(add-to-list 'org-file-apps '("\\.pdf\\'" . "termux-open %s"))
(add-to-list 'org-file-apps '("\\.png\\'" . "termux-open %s"))
(add-to-list 'org-file-apps '("\\.jpg\\'" . "termux-open %s"))
(add-to-list 'org-file-apps '("\\.jpeg\\'" . "termux-open %s")))
;; needed for <s etc. expansion of code-blocks
(require 'org-tempo))
;; define our Org-roam user and their email (set to your desired name/email)
(defvar roam-user "Some User"
"The name of the Org-roam note author.")
(defvar roam-email "roman@mode.org"
"The public email of that author.")
(setq org-roam-v2-ack t)
;; we need this package for v2 of Org-oram
(use-package emacsql-sqlite3
:ensure t)
;; If you've replicated my setup; otherwise change to the Termux
;; local path.
(setq org-roam-directory (file-truename "~/Documents/Org/org-roam/"))
;; org-roam
(use-package org-roam
:ensure t
:custom
(setq org-roam-db-location (file-truename "~"))
(org-roam-directory (file-truename "~/Documents/Org/org-roam/"))
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n r" . org-roam-graph)
("C-c n i" . org-roam-node-insert)
("C-c n c" . org-roam-capture)
("C-c n g" . org-id-get-create)
;; Dailies
("C-c n n" . org-roam-dailies-capture-today)
("C-c n d" . org-roam-dailies-goto-today) ; find toDay
("C-c n v" . org-roam-dailies-goto-date)
("C-c n f" . org-roam-dailies-goto-next-note)
("C-c n b" . org-roam-dailies-goto-previous-note))
:config
;; this is a chunglak's hack to get sqlite to work on Android with org-roam v2:
;; from: https://github.com/org-roam/org-roam/issues/1605#issuecomment-885997237
(defun org-roam-db ()
"Entrypoint to the Org-roam sqlite database.
Initializes and stores the database, and the database connection.
Performs a database upgrade when required."
(unless (and (org-roam-db--get-connection)
(emacsql-live-p (org-roam-db--get-connection)))
(let ((init-db (not (file-exists-p org-roam-db-location))))
(make-directory (file-name-directory org-roam-db-location) t)
(let ((conn (emacsql-sqlite3 org-roam-db-location)))
(emacsql conn [:pragma (= foreign_keys ON)])
(set-process-query-on-exit-flag (emacsql-process conn) nil)
(puthash (expand-file-name org-roam-directory)
conn
org-roam-db--connection)
(when init-db
(org-roam-db--init conn))
(let* ((version (caar (emacsql conn "PRAGMA user_version")))
(version (org-roam-db--upgrade-maybe conn version)))
(cond
((> version org-roam-db-version)
(emacsql-close conn)
(user-error
"The Org-roam database was created with a newer Org-roam version. "
"You need to update the Org-roam package"))
((< version org-roam-db-version)
(emacsql-close conn)
(error "BUG: The Org-roam database scheme changed %s"
"and there is no upgrade path")))))))
(org-roam-db--get-connection))
(defun org-roam-db--init (db)
"Initialize database DB with the correct schema and user version."
(emacsql-with-transaction db
(emacsql db "PRAGMA foreign_keys = ON") ;; added
(emacsql db [:pragma (= foreign_keys ON)])
(pcase-dolist (`(,table ,schema) org-roam-db--table-schemata)
(emacsql db [:create-table $i1 $S2] table schema))
(pcase-dolist (`(,index-name ,table ,columns) org-roam-db--table-indices)
(emacsql db [:create-index $i1 :on $i2 $S3] index-name table columns))
(emacsql db (format "PRAGMA user_version = %s" org-roam-db-version))))
;; end chunglak hack
(org-roam-setup)
;; If using org-roam-protocol
(require 'org-roam-protocol))
;; These are my capture templates:
(setq org-roam-capture-templates
`(("d" "default" plain "%?" :if-new
(file+head "%<%Y%m%d%H%M%S>-${slug}.org"
,(concat "#+title: ${title}\n"
"#+date: %U\n\n"))
:unnarrowed t)))
(setq org-roam-dailies-directory "~/Documents/Org/org-roam/daily")
(setq org-roam-dailies-capture-templates
`(("d" "default" entry "* %?" :if-new
(file+head "%(concat org-roam-dailies-directory \"/%<%Y-%m-%d>.org\")"
,(concat "#+title: %<%Y-%m-%d>" "\n"
"#+filetags: :daily_journal:\n\n")))))
;; deft - one way to search Org-roam notes, but not the fastest (see below)
(use-package deft
:ensure t
:config
:after org
:bind
("C-c r d" . deft)
:custom
(deft-recursive t)
(deft-use-filter-string-for-filename t)
(deft-default-extension "org")
(deft-directory "~/Documents/Org/org-roam/"))
;; Here end the basic setup, but....
;; SOME OTHER THINGS YOU MIGHT ADD
;; bars seems pointless here, but if you like, don't do this
(menu-bar-mode -1)
(tool-bar-mode -1)
;; You could use a different theme
(use-package cyberpunk-theme
:ensure t
:config
(load-theme 'cyberpunk))
;;;;;;;;;;;;;;;;;;;;;
;; Spell-checking ;;;
;;;;;;;;;;;;;;;;;;;;;
(require 'flymake)
(setq ispell-program-name "hunspell") ; could be ispell as well, depending on your preferences
(setq ispell-dictionary "en_GB") ; this can obviously be set to any language your spell-checking program supports
;; I installed the en_GB ones, but these don't come in Termux by default. To add arbitrary hunspell languages, see:
;; https://www.reddit.com/r/termux/comments/k5o6mp/new_hunspell_dictionaries/?
;; in summary:
;; - how to add new: copy .aff and .dic files in /data/data/com.termux/files/usr/share/hunspell/
;; - where to get new: https://www.freeoffice.com/en/download/dictionaries
(dolist (hook '(org-mode-hook))
(add-hook hook (lambda () (flyspell-mode 1))))
(add-hook 'org-mode-hook (lambda () (setq ispell-parser 'tex))) ; make orgmode recognise LaTeX syntax [from http://stackoverflow.com/questions/11646880/flyspell-in-org-mode-recognize-latex-syntax-like-auctex ]
(add-hook 'text-mode-hook #'flyspell-mode)
;;;;;;;;;;;;;;;
;; Undo-Tree ;; - a new undo package
;;;;;;;;;;;;;;;
(use-package undo-tree
:ensure t
:config
;; (setq undo-tree-auto-save-history 1)
;; Each node in the undo tree should have a timestamp.
(setq undo-tree-visualizer-timestamps t)
;; Show a diff window displaying changes between undo nodes.
(setq undo-tree-visualizer-diff t)
(global-undo-tree-mode))
;; display time and date in modeline, if you like
(setq display-time-day-and-date t)
(display-time-mode 1)
;; prettier bullets
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
(setq org-bullets-bullet-list '("⋇" "∴" "∵" "∷" "∺")))
;; A nice way of quickly adding links.
;; (Though in Termux, you first must paste from your
;; Android clipboard and then copy/kill via Emacs before
;; it'll work.)
(use-package org-cliplink
:ensure t
:config
(define-key org-mode-map (kbd "C-c o c") #'org-cliplink))
;; This is also not needed, but adds some (dubiously) useful properties
;; to the Org-roam file's property drawer.
;; First, set up a system for getting location
;; (we could also try to leverage termux's built-in
;; GPS location abilities via `termux-location`, but
;; it seems a bit slow and doesn't even always work if
;; your device can't get a good satellite connection.)
(setq calendar-latitude 0)
(setq calendar-longitude 0)
(defun bms/get-lat-long-from-ipinfo ()
(let*
((latlong (substring
(shell-command-to-string "curl -s 'ipinfo.io/loc'") 0 -1))
(latlong-list (split-string latlong ",")))
(setq calendar-latitude (string-to-number (car latlong-list)))
(setq calendar-longitude (string-to-number (cadr latlong-list)))))
(defun bms/add-other-auto-props-to-org-roam-properties ()
(unless (file-exists-p (buffer-file-name))
(unless (org-find-property "CREATION_TIME")
(org-roam-add-property (format-time-string "%s"
(nth 5
(file-attributes (buffer-file-name))))
"CREATION_TIME"))
(unless (org-find-property "AUTHOR")
(org-roam-add-property roam-user "AUTHOR"))
(unless (org-find-property "MAIL")
(org-roam-add-property roam-email "MAIL"))
(unless (org-find-property "LAT_LONG")
(bms/get-lat-long-from-ipinfo)
(org-roam-add-property (concat (number-to-string calendar-latitude) "," (number-to-string calendar-longitude)) "LAT-LONG"))))
(add-hook 'org-roam-capture-new-node-hook #'bms/add-other-auto-props-to-org-roam-properties)
;; You could use Ivy or Helm or the default, but I
;; like Selectrum, Consult & friends. Plus we can leverage
;; Consult for a nice alternative to deft for note-searching.
;; You'll need this to use my ripgrep note searching feature below.
;; selectrum
(use-package selectrum
:ensure t
:config
(selectrum-mode +1))
;; ;; prescient - T9
(use-package prescient
:ensure t
:config
(setq prescient-persist-mode t)
(setq prescient-filter-method '(literal regexp initialism fuzzy))) ;; added fuzzy
(use-package orderless
:ensure t
:init (icomplete-mode) ; optional but recommended!
:custom (completion-styles '(orderless))
:config
(setq orderless-matching-styles '(orderless-flex))
;; This means that the company-capf backend will automatically use orderless, but following issue exists:
;; Pressing SPC takes you out of completion, so with the default separator you are limited to one component,
;; which is no fun. To fix this add a separator that is allowed to occur in identifiers, for example, for
;; Emacs Lisp code you could use an ampersand:
(setq orderless-component-separator "[ &]")
;; The matching portions of candidates aren’t highlighted. But while you can’t get different faces for
;; different components, you can at least get the matches highlighted in the sole available face with this configuration
(defun just-one-face (fn &rest args)
(let ((orderless-match-faces [completions-common-part]))
(apply fn args)))
(advice-add 'company-capf--candidates :around #'just-one-face))
(use-package selectrum-prescient
:ensure t
:config
;; to make sorting and filtering more intelligent
(selectrum-prescient-mode +1)
;; Filtering with orderless
(setq selectrum-refine-candidates-function #'orderless-filter)
(setq selectrum-highlight-candidates-function #'orderless-highlight-matches)
;; If you also configure `completion-styles` for orderless you might want to use the
;; following advice because orderless isn't well suited for initial gathering of
;; candidates by completion in region.
(advice-add #'completion--category-override :filter-return
(defun completion-in-region-style-setup+ (res)
"Fallback to default styles for region completions with orderless."
(or res
;; Don't use orderless for initial candidate gathering.
(and completion-in-region-mode-predicate
(not (minibufferp))
(equal '(orderless) completion-styles)
'(basic partial-completion emacs22)))))
;; Minibuffer-actions with embark
;; You should bind embark commands like embark-act, embark-act-noexit
;; and embark-export in minibuffer-local-map (as embark commands are not selectrum specific).
;; For available commands and other embark configurations see the embark documentation and its wiki.
(defun current-candidate+category ()
(when selectrum-is-active
(cons (selectrum--get-meta 'category)
(selectrum-get-current-candidate))))
(add-hook 'embark-target-finders #'current-candidate+category)
(defun current-candidates+category ()
(when selectrum-is-active
(cons (selectrum--get-meta 'category)
(selectrum-get-current-candidates
;; Pass relative file names for dired.
minibuffer-completing-file-name))))
(add-hook 'embark-candidate-collectors #'current-candidates+category)
;; No unnecessary computation delay after injection.
(add-hook 'embark-setup-hook 'selectrum-set-selected-candidate)
;; The following is not selectrum specific but included here for convenience.
;; If you don't want to use which-key as a key prompter skip the following code.
(setq embark-action-indicator
(lambda (map) (which-key--show-keymap "Embark" map nil nil 'no-paging)
#'which-key--hide-popup-ignore-command)
embark-become-indicator embark-action-indicator)
;; to save your command history on disk, so the sorting gets more
;; intelligent over time
(prescient-persist-mode +1))
;; Example configuration for Consult
(use-package consult
;; Replace bindings. Lazily loaded due by `use-package'.
:bind (("C-x M-:" . consult-complex-command)
("C-c h" . consult-history)
("C-c m" . consult-mode-command)
("C-x b" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window)
("C-x 5 b" . consult-buffer-other-frame)
("C-x r x" . consult-register)
("C-x r b" . consult-bookmark)
("M-g g" . consult-goto-line)
("M-g M-g" . consult-goto-line)
("M-g o" . consult-outline) ;; "M-s o" is a good alternative.
("M-g l" . consult-line) ;; "M-s l" is a good alternative.
("M-g m" . consult-mark) ;; I recommend to bind Consult navigation
("M-g k" . consult-global-mark) ;; commands under the "M-g" prefix.
("M-g r" . consult-ripgrep) ;; or consult-grep, consult-ripgrep
("M-g f" . consult-find) ;; or consult-locate, my-fdfind
("M-g i" . consult-project-imenu) ;; or consult-imenu
("M-g e" . consult-error)
("M-s m" . consult-multi-occur)
("M-y" . consult-yank-pop)
("<help> a" . consult-apropos))
;; The :init configuration is always executed (Not lazy!)
:init
;; Custom command wrappers. It is generally encouraged to write your own
;; commands based on the Consult commands. Some commands have arguments which
;; allow tweaking. Furthermore global configuration variables can be set
;; locally in a let-binding.
(defun my-fdfind (&optional dir)
(interactive "P")
(let ((consult-find-command '("fdfind" "--color=never" "--full-path")))
(consult-find dir)))
;; Replace `multi-occur' with `consult-multi-occur', which is a drop-in replacement.
(fset 'multi-occur #'consult-multi-occur)
;; Configure other variables and modes in the :config section, after lazily loading the package
:config
;; Configure preview. Note that the preview-key can also be configured on a
;; per-command basis via `consult-config'.
;; (setq consult-preview-key 'any) ;; any key triggers preview, the default
;; Optionally configure narrowing key.
;; Both < and C-+ work reasonably well.
(setq consult-narrow-key "<") ;; (kbd "C-+")
;; Optionally make narrowing help available in the minibuffer.
;; Probably not needed if you are using which-key.
;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
;; Optional configure a view library to be used by `consult-buffer'.
;; The view library must provide two functions, one to open the view by name,
;; and one function which must return a list of views as strings.
;; Example: https://github.com/minad/bookmark-view/
;; (setq consult-view-open-function #'bookmark-jump
;; consult-view-list-function #'bookmark-view-names)
;; Optionally configure a function which returns the project root directory
;; (autoload 'projectile-project-root "projectile")
;; (setq consult-project-root-function #'projectile-project-root)
)
;; Optionally add the `consult-flycheck' command.
(use-package consult-flycheck
:bind (:map flycheck-command-map
("!" . consult-flycheck)))
;; Optionally enable richer annotations using the Marginalia package
(use-package marginalia
:ensure t
;; The :init configuration is always executed (Not lazy!)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode))
(use-package embark
:ensure t
:bind
("C-S-a" . embark-act) ; pick some comfortable binding
:config
;; For Selectrum users:
(defun current-candidate+category ()
(when selectrum-is-active
(cons (selectrum--get-meta 'category)
(selectrum-get-current-candidate))))
(add-hook 'embark-target-finders #'current-candidate+category)
(defun current-candidates+category ()
(when selectrum-is-active
(cons (selectrum--get-meta 'category)
(selectrum-get-current-candidates
;; Pass relative file names for dired.
minibuffer-completing-file-name))))
(add-hook 'embark-candidate-collectors #'current-candidates+category)
;; No unnecessary computation delay after injection.
(add-hook 'embark-setup-hook 'selectrum-set-selected-candidate))
;; org-roam-rg-search - this is a much faster way to search Org-roam notes:
;; requires the Selectrum+Consult setup immediately preceding.
;; Use C-c r r to search notes via consult's ripgrep interface
(defun bms/org-roam-rg-search ()
"Search org-roam directory using consult-ripgrep. With live-preview."
(interactive)
(let ((consult-ripgrep "rg --null --ignore-case --type org --line-buffered --color=always --max-columns=500 --no-heading --line-number . -e ARG OPTS"))
(consult-ripgrep org-roam-directory)))
(global-set-key (kbd "C-c rr") 'bms/org-roam-rg-search)
;; speed-keys - see https://github.com/alhassy/emacs.d#manipulating-sections
(setq org-use-speed-commands t)
;; On an org-heading, C-a goes to after the star, heading markers. To use speed keys, run C-a C-a to get to the star markers.
;; C-e goes to the end of the heading, not including the tags.
(setq org-special-ctrl-a/e t)
;;drag images into orgmode
(use-package org-download
:ensure t
:config
(add-hook 'dired-mode-hook 'org-download-enable)
(global-set-key (kbd "C-c o i") #'org-download-yank)
(setq org-download-method 'attach))
(defun bms/org-attach-insert-link (&optional in-emacs)
"Insert attachment from list."
(interactive "P")
(let ((attach-dir (org-attach-dir)))
(if attach-dir
(let* ((file (pcase (org-attach-file-list attach-dir)
(`(,file) file)
(files (completing-read "Insert attachment: "
(mapcar #'list files) nil t))))
(path (expand-file-name file attach-dir))
(desc (file-name-nondirectory path)))
(let ((initial-input
(cond
((not org-link-make-description-function) desc)
(t (condition-case nil
(funcall org-link-make-description-function link desc)
(error
(message "Can't get link description from %S"
(symbol-name org-link-make-description-function))
(sit-for 2)
nil))))))
(setq desc (if (called-interactively-p 'any)
(read-string "Description: " initial-input)
initial-input))
(org-insert-link nil path (concat "attachment:" desc))))
(error "No attachment directory exist"))))
(define-key org-mode-map (kbd "C-c o l") #'bms/org-attach-insert-link)
;; in case you want some things not in melpa
;; you'll need it for the remaining things below
(use-package quelpa
:ensure t)
(use-package quelpa-use-package
:ensure t)
;; A bit of sugar for the visual appearance of Org syntax
;; Use if you like.
(use-package org-appear
:ensure t
:quelpa (org-appear :fetcher github :repo "awth13/org-appear")
:config
(setq org-hide-emphasis-markers t)
(add-hook 'org-mode-hook 'org-appear-mode))
;; You don't need this, but it's cool and it does work on Android:
;; see https://github.com/org-roam/org-roam-ui for features
(use-package org-roam-ui
:ensure t
:quelpa (org-roam-ui :fetcher github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
:after org-roam
:hook (org-roam . org-roam-ui-mode))
An excellent way of keeping Org notes (and files more generally) in sync between desktop, laptop, and mobile devices is Syncthing. On Android I recommend using the Syncthing-Fork app (via F-Droid), which has various improvements over the default Syncthing app on Android, including better file-access features. (On iOS there is now a third-party solution for syncing via Syncthing: Möbius-Sync. I have no idea how to use Emacs/Org-mode on iOS though, but I recall hearing about some ways of running a Linux shell on iOS like iSH, so possibly there’s some way.)
I have Syncthing sync my Org files to a directory in my main “home”
directory on Android Documents/Org
and then in Termux created a
Documents
directory and inside of that directory created a symlink to
my actual Org directory via ln -s storage/shared/Documents/Org Org
. I’ve found that is easier for allowing Syncthing to have access
to the files in order to keep them in sync. (And having my Org files
live at ~/Documents/Org
in Termux mimics the directory structure on my
Linux boxes, which makes lots of things easier in terms of sharing
configurations.)
ox-hugo
, an exporter from native Org mode format to
Hugo-ready markdown files, as well his theme/configuration for Hugo,
hugo-refined
(which the theme used here is largely based on), I
finally have an ideal Emacs-centric blogging environment, though I’m
sure I’ll continue to tweak things a bit.
Hugo itself is a static website generator, which interprets markdown files. It’s written in Go, a language developed at Google, which is notable for including Ken Thompson and Rob Pike among its creators.
This is more or less a continuation of my old blog, of a similar name, and will largely address Emacs/elisp and other lispy things, and Linux/UNIX/*nix and free/open source software and operating systems, but, like my old blog, probably also occasionally games and pre-20th century technology, as well as whatever else catches my interest (other than natural language things, which I’ll keep on my professional site).
]]>