Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/licht1stein/obsidian.el

Obsidian Notes for Emacs
https://github.com/licht1stein/obsidian.el

Last synced: about 2 months ago
JSON representation

Obsidian Notes for Emacs

Awesome Lists containing this project

README

        

#+TITLE: Obsidian Notes for Emacs
[[https://melpa.org/#/obsidian][file:https://melpa.org/packages/obsidian-badge.svg]] [[https://stable.melpa.org/#/obsidian][file:https://stable.melpa.org/packages/obsidian-badge.svg]]

Emacs front-end for [[https://obsidian.md/][Obsidian Notes]].

* Table of Contents :toc:
- [[#installation][Installation]]
- [[#about-obsidianel][About Obsidian.el]]
- [[#what-should-we-keep-doing-in-obsidian][What should we keep doing in Obsidian?]]
- [[#what-should-be-possible-to-do-in-emacs][What should be possible to do in Emacs?]]
- [[#how-does-obsidianel-work][How does obsidian.el work?]]
- [[#obsidian-mode][obsidian-mode]]
- [[#company-mode-completion][company-mode completion]]
- [[#hydra-menu][Hydra menu]]
- [[#manual-re-scan][Manual re-scan]]
- [[#following-links][Following links]]
- [[#following-backlinks][Following backlinks]]
- [[#inserting-links][Inserting links]]
- [[#jumping-between-notes][Jumping between notes]]
- [[#capturing-new-note][Capturing new note]]
- [[#searching-notes][Searching notes]]
- [[#finding-all-notes-with-a-tag][Finding all notes with a tag]]
- [[#move-note-to-another-folder][Move note to another folder]]
- [[#templates][Templates]]
- [[#why-obsidianel-and-not][Why obsidian.el and not...]]
- [[#obsidian-app-itself-athens-research-or-any-other-great-app][Obsidian App itself, Athens Research or any other great app?]]
- [[#org-roam-or-any-other-great-emacs-libraries][Org-roam or any other great Emacs libraries?]]
- [[#versioning][Versioning]]
- [[#contributing][Contributing]]
- [[#gratitude][Gratitude]]

* Installation
Obsidian.el is available from [[https://melpa.org][MELPA]] or [[https://stable.melpa.org/#/obsidian][MELPA Stable]] and can be installed with:

#+begin_src
M-x package-install RET obsidian RET
#+end_src

Put this in your ~init.el~:

#+begin_src elisp
(require 'obsidian)
(obsidian-specify-path "~/MY_OBSIDIAN_FOLDER")
;; If you want a different directory of `obsidian-capture':
(setq obsidian-inbox-directory "Inbox")
;; Clicking on a wiki link referring a non-existing file the file can be
;; created in the inbox (t) or next to the file with the link (nil).
;; Default: t - creating in the inbox
;(setq obsidian-wiki-link-create-file-in-inbox nil)
;; You may want to define a folder for daily notes. By default it is the inbox.
;(setq obsidian-daily-notes-directory "Daily Notes")
;; Directory of note templates, unset (nil) by default
;(setq obsidian-templates-directory "Templates")
;; Daily Note template name - requires a template directory. Default: Daily Note Template.md
;(setq obsidian-daily-note-template "Daily Note Template.md")

;; Define obsidian-mode bindings
(add-hook
'obsidian-mode-hook
(lambda ()
;; Replace standard command with Obsidian.el's in obsidian vault:
(local-set-key (kbd "C-c C-o") 'obsidian-follow-link-at-point)

;; Use either `obsidian-insert-wikilink' or `obsidian-insert-link':
(local-set-key (kbd "C-c C-l") 'obsidian-insert-wikilink)

;; Following backlinks
(local-set-key (kbd "C-c C-b") 'obsidian-backlink-jump)))

;; Optionally you can also bind a few functions:
;; replace "YOUR_BINDING" with the key of your choice:
(global-set-key (kbd "YOUR_BINDING") 'obsidian-jump) ;; Opening a note
(global-set-key (kbd "YOUR_BINDING") 'obsidian-capture) ;; Capturing a new note in the inbox
(global-set-key (kbd "YOUR_BINDING") 'obsidian-daily-note) ;; Creating daily note

;; Activate detection of Obsidian vault
(global-obsidian-mode t)
#+end_src

*Or using [[https://github.com/jwiegley/use-package][use-package]]:*

#+begin_src elisp
(use-package obsidian
:ensure t
:demand t
:config
(obsidian-specify-path "~/MY_OBSIDIAN_FOLDER")
(global-obsidian-mode t)
:custom
;; This directory will be used for `obsidian-capture' if set.
(obsidian-inbox-directory "Inbox")
;; Create missing files in inbox? - when clicking on a wiki link
;; t: in inbox, nil: next to the file with the link
;; default: t
;(obsidian-wiki-link-create-file-in-inbox nil)
;; The directory for daily notes (file name is YYYY-MM-DD.md)
(obsidian-daily-notes-directory "Daily Notes")
;; Directory of note templates, unset (nil) by default
;(obsidian-templates-directory "Templates")
;; Daily Note template name - requires a template directory. Default: Daily Note Template.md
;(obsidian-daily-note-template "Daily Note Template.md")
:bind (:map obsidian-mode-map
;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding.
("C-c C-o" . obsidian-follow-link-at-point)
;; Jump to backlinks
("C-c C-b" . obsidian-backlink-jump)
;; If you prefer you can use `obsidian-insert-link'
("C-c C-l" . obsidian-insert-wikilink)))
#+end_src

Optionally you can specify ~obsidian-inbox-directory~, it will be used by ~obsidian-capture~ to
store new notes into. If you don't set it the root folder of your Obsidian vault will be used.

* About Obsidian.el

I wanted to work with Obsidian Notes using Emacs. Obviously you already can open your Obsidian folder and start editing markdown files with Emacs. But I want to improve that and split the responsibilities between Emacs and Obsidian the way it makes sense for an Emacs user.

** What should we keep doing in Obsidian?
- Sync
- Mobile client (of course, and that's where Obsidian beats anything else in Emacs)
- Complex exploring (graph views etc)
- All the things done with complex plugins

** What should be possible to do in Emacs?
Obsidian.el must empower us to stay in Emacs for things that make sense in Emacs:

- [X] Creating and editing notes with convenient autocomplete for tags and links (nothing will ever compare to Emacs in terms of editing power)
- [X] Jumping between notes
- [X] Searching all notes
- [X] Finding all notes with a tag
- [X] Following backlinks
- [ ] Viewing backlinks in a separate list

When all of the above is ready we will almost never need the Obsidian app on desktop, but will still be able to use it on mobile or when specifically needed.

* How does obsidian.el work?
** obsidian-mode
When you require obsidian.el via ~use-package~ or in other ways (see snippet above), you have to specify the root folder of your Obsidian Notes vault. If ~global-obsidian-mode~ is enabled and if you specified the root folder, each time you open a markdown buffer it checks, if that file is part of your Obsidian Notes vault. If it is ~obsidian-mode~ minor mode is activated for this buffer.

** company-mode completion
[[./resources/tag-completion.png]]

Once the ~obsidian-mode~ is activated obsidian.el scans all markdown files in the vault for tags and links (links still WIP), and stores these lists in it's global variables. It also adds [[http://company-mode.github.io/][company-mode]] backends to suggest links and tags for completion.

** [[https://github.com/abo-abo/hydra][Hydra]] menu

When [[https://github.com/abo-abo/hydra][Hydra]] is installed, ~obsidian-hydra~ will be defined such that it can be used for bindings:

#+begin_src elisp
(bind-key (kbd "C-c M-o") 'obsidian-hydra/body 'obsidian-mode-map)
#+end_src

[[./resources/hydra-menu.png]]

** Including hidden dot files
Obsidian does not track hidden files; obsidian.el can be configured to either track them or ignore them by setting the value of `obsidian-include-hidden-files`.

** Manual re-scan
You can update the lists of tags, links etc. manually if it's lagging for some reason by running an interactive command:

#+begin_src
M-x obsidian-update RET
#+end_src

** Following links
Obsidian.el implements a custom command ~obsidian-follow-link-at-point~ which correctly follows markdown and wiki links generated by the Obsidian App. In the install example above this command is bound to ~C-c C-o~ in ~obsidian-mode~.

#+begin_src
M-x obsidian-follow-link-at-point RET
#+end_src

Note that the Obsidian app replaces spaces with ~%20~ when inserting markdown links, and doesn't do that when inserting wiki links. Obsidian.el follows this convention to maximize compatibility:

#+begin_src markdown
Markdown link with spaces: [2-sub with spaces and буквы](subdir/2-sub%20with%20spaces%20and%20буквы.md)

Wikilink with spaces: [[Subdir/2-sub with spaces and буквы]]
#+end_src

Both these types of links are correctly handled by ~obsidian-follow-link-at-point~.

** Following backlinks
You can quickly jump to backlinks to current file using ~obsidian-backlink-jump~

#+begin_src
M-x obsidian-backlink-jump RET
#+end_src

*** Multiple matches
Obsidian doesn't insert relative path by default, only does it when there are multiple files with the same name. ~obsidian-follow-link-at-point~ handles this correctly. Every time you follow a link it checks, if there's only one match for the filename linked. If there's just one it simply opens that file. If there's more than one it prompts you to select which file to open.

** Inserting links
[[./resources/insert-link.png]]

When inserting links, two different formats can be used to specify the file: the filename alone, or the path to the file within the Obsidian vault. The default is to only use the filename, but this behavior can be changed by setting the variable ~obsidian-links-use-vault-path~ to ~t~. Alternately, using the prefix argument before the call to insert a link will toggle this behavior, inserting a link with the format opposite of this variable.

There are two commands to insert links ~obsidian-insert-link~ and ~obsidian-insert-wikilink~, you can choose one depending on your preferred link format:

*** Inserts a link in Markdown format
Example: ~[Link description](path/to/file.md)~
#+begin_src
M-x obsidian-insert-link RET
#+end_src

Note, that when you insert a link to file that has spaces in it's name, like "facts about inserting links.md", Obsidian app would html-format the spaces, meaning the link will look like

#+begin_src markdown
[facts](facts%20about%20inserting%20links.md)
#+end_src

Obsidian.el follows this convention and does the same when inserting markdown links. ~obsidian-follow-link-at-point~ handles this correctly.

*** Insert a link in wikilink format
Example: ~[[path/fo/file.md|Link description]]~

#+begin_src
M-x obsidian-insert-wikilink RET
#+end_src

** Jumping between notes
Quickly jump between notes using ~obsidian-jump~

#+begin_src
M-x obsidian-jump RET
#+end_src

*** Aliases
If you have YAML front matter in your note, Obsidian.el will find aliases in it and add them to the ~obsidian-jump~ selection. Both ~aliases~ and ~alias~ keys are supported.

** Capturing new note
Use ~obsidian-capture~. If you specified ~obsidian-inbox-directory~, it will create new notes in this directory. Otherwise in your Obsidian vault root directory:

#+begin_src
M-x obsidian-capture RET
#+end_src

** Searching notes
Use ~obsidian-search~ to look for a string or a regular expression:

#+begin_src
M-x obsidian-search RET query RET
#+end_src

** Finding all notes with a tag
Use ~obsidian-tag-find~ to list all notes that contain a tag. Let's you choose a tag from list of all tags:

#+begin_src
M-x obsidian-tag-find RET
#+end_src

** Move note to another folder
Use ~obsidian-move-file~ to move current note to another folder:

#+begin_src
M-x obsidian-move-file RET
#+end_src

** Templates

Obsidian.el has a basic template support, where the Obsidian app's template placeholders can be used,
without customization. {{title}}, {{date}}, and {{time}} can be used. {{title}} is the name of the file without the extension.

*** Development tasks
- [X] Specify Obsidian folder and save it in variables
- [X] Enumerate files in the Obsidian folder and save a list
- [X] Run the scan when entering obsidian-mode
- [X] Functions to scan notes for tags
- [X] Get full list of all tags
- [X] company-backend with tags
- [X] commands to insert links in markdown and wikilink
- [X] Capture command to create a new note in Obsidian folder
- [X] Obsidian minor for matching .md files
- [X] Jumping between notes
- [X] Following links
- [X] Following backlinks

* Why obsidian.el and not...
** Obsidian App itself, Athens Research or any other great app?
Easy. When on desktop they are simply not Emacs. Not even Obsidian itself. Emacs beats anything else for things that it is built for. But you know this already, otherwise you wouldn't be here.

** Org-roam or any other great Emacs libraries?
The answer is mostly the same for all of them. Mobile support. Or rather — NO mobile support. I don't buy into the story that "you don't really need your PKM system on mobile", and "serious work is done only on desktop" etc. These are just excuses for the impossibility of building a full-fledged mobile version of Emacs.

So there were two ways to go about it: build a mobile app for something like org-roam (which would be cool, but is above my front-end skills) or build a light-weight Emacs client for something like Obsidian. I chose the simpler task.

* Versioning
The project uses [[https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md][break versioning]], meaning that upgrading from 1.0.x to 1.0.y will always be safe, upgrading from 1.x.x to 1.y.x might break something small, and upgrade from x.x.x to y.x.x will break almost everything.

* Contributing
PRs and issues are very welcome. In order to develop locally you need to install [[https://github.com/doublep/eldev/][eldev]]. After that you can run ~make~ commands, in particular ~make test~ and ~make lint~ to make sure that your code will pass all MELPA checks.

* Gratitude
- The work on Obsidian.el was made considerably easier and definitely more fun thanks to the great work of [[https://github.com/magnars][Magnar Sveen]] and his packages [[https://github.com/magnars/dash.el][dash.el]] and [[https://github.com/magnars/s.el][s.el]]. Thank you for making Elisp almost as convenient as Clojure!

- During the development of Obsidian.el I have learned and copied from the code of the amazing [[https://github.com/org-roam/org-roam][org-roam]] package. Thank you!