markdown-oxide
markdown-oxide copied to clipboard
Editor Agnostic PKM: you bring the text editor and we bring the PKM - inspired by and compatible with Obsidian
Markdown Oxide
Markdown Oxide is attempting to be the best Personal Knowledge Management (PKM) system for software enthusiasts - people like me who (in addition to note-taking) are addicted to creating the best text editing experience. Bring your own text editor and let markdown-oxide
be your PKM!
Obsidian strongly inspires Markdown Oxide's PKM features - in fact, Markdown Oxide is fully compatible with your Obsidian vault. Markdown Oxide does not aim to fully replace Obsidian; it serves to provide a feature-rich and advanced note-taking experience. Obsidian remains a terrific front-end for your linked markdown notes. Also, in terms of features, Markdown Oxide and Obsidian are quite alligned.
Markdown Oxide's features are implemented in the form of a language server aiming to be fully compatible with your favorite text editor and its ecosystem. Read on to learn what Markdown Oxide provides and how to install and configure it.
Installation
(if you want to skip to the features, click here)
Neovim
-
Given Neovim access to the binary.
-
Cargo Install (from source)
cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide
-
Cargo binstall[1] (from hosted binary)
cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide
-
AUR (from source)
paru -S markdown-oxide-git
yay -S markdown-oxide-git
- Mason.nvim (from hosted binary)
- Nix Unstable:
pkgs.markdown-oxide
-
-
Modify your Neovim Configuration
-
Modify LSP Config (making sure to adjust capabilities as follows)
-- An example nvim-lspconfig capabilities setting local capabilities = require("cmp_nvim_lsp").default_capabilities(vim.lsp.protocol.make_client_capabilities()) -- Ensure that dynamicRegistration is enabled! This allows the LS to take into account actions like the -- Create Unresolved File code action, resolving completions for unindexed code blocks, ... capabilities.workspace = { didChangeWatchedFiles = { dynamicRegistration = true, }, } require("lspconfig").markdown_oxide.setup({ capabilities = capabilities, -- again, ensure that capabilities.workspace.didChangeWatchedFiles.dynamicRegistration = true on_attach = on_attach -- configure your on attach config })
-
Modify your nvim-cmp configuration
Modify your nvim-cmp source settings for nvim-lsp (note: you must have nvim-lsp installed)
{ name = 'nvim_lsp', option = { markdown_oxide = { keyword_pattern = [[\(\k\| \|\/\|#\)\+]] } } },
-
(optional) Enable Code Lens (eg for UI reference count)
Modify your lsp
on_attach
function.-- refresh codelens on TextChanged and InsertLeave as well vim.api.nvim_create_autocmd({ 'TextChanged', 'InsertLeave', 'CursorHold', 'LspAttach' }, { buffer = bufnr, callback = vim.lsp.codelens.refresh, }) -- trigger codelens refresh vim.api.nvim_exec_autocmds('User', { pattern = 'LspAttached' })
-
(optional; requires latest commit) Enable opening daily notes with natural langauge
Modify your lsp
on_attach
function to support opening daily notes with, for example,:Daily two days ago
or:Daily next monday
. The specification can be found here-- setup Markdown Oxide daily note commands if client.name == "markdown_oxide" then vim.api.nvim_create_user_command( "Daily", function(args) local input = args.args vim.lsp.buf.execute_command({command="jump", arguments={input}}) end, {desc = 'Open daily note', nargs = "*"} ) end
-
VSCode
Install the vscode extension (called Markdown Oxide
). As for how the extension uses uses the language server, there are two options
-
Recommended: the extension will download the server's binary and use that
-
The extension will use
markdown-oxide
from path. To install to your path, there are the following methods for VSCode:-
Cargo Install (from source)
cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide
-
Cargo binstall[1] (from hosted binary)
cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide
-
AUR (from source)
paru -S markdown-oxide-git
yay -S markdown-oxide-git
- Nix Unstable:
pkgs.markdown-oxide
-
Zed
Markdown Oxide is available as an extension titled Markdown Oxide
. Similarly to VSCode, there are two methods for this extension to access the language server
-
Recommended: the extension will download the server's binary and use that
-
The extension will use
markdown-oxide
from path. To install to your path, there are the following methods for Zed:-
Cargo Install (from source)
cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide
-
Cargo binstall[1] (from hosted binary)
cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide
-
AUR (from source)
paru -S markdown-oxide-git
yay -S markdown-oxide-git
- Nix Unstable:
pkgs.markdown-oxide
-
[!Note] Zed does not implement some of the language server protocol that this LS uses. Namely, unindexed block completions do not work at all. There are also other issues with the language server unique to Zed (such as completions being unexpectedly hidden). Over time, these issues will be resolved; for now, Zed provides an interesting exhibition for a potential (beautiful + fast) note-taking experience provided by markdown oxide
Helix
For Helix, all you must do is install the language server's binary to your path. The following installation methods are available:
-
Cargo Install (from source)
cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide
-
Cargo binstall[1] (from hosted binary)
cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide
-
AUR (from source)
paru -S markdown-oxide-git
yay -S markdown-oxide-git
- Nix Unstable:
pkgs.markdown-oxide
[!Note] There are some major issues with markdown oxide on helix as it does not fully implement the language server protocol. Most obtrusive is that helix does not implement
is_incomplete
for completions, and since completion filtering and sorting happens on the server (for performance), you must manually re-request completions after typing (one method I have found is to exit and re-enter insert mode)
Linking Syntax
The linking syntax is that of Obsidian's and can be found here https://help.obsidian.md/Linking+notes+and+files/Internal+links
Generally, this is [[relativeFilePath(#heading)?(|display text)?]]
e.g. [[articles/markdown oxide#Features|Markdown Oxide Features]] to link to a heading in Markdown Oxide.md
file in the articles
folder or [[Obsidian]] for the Obsidian.md
file in the root folder. Markdown oxide also supports markdown links
Features
[!NOTE] To interact with a file as a referenceable (for getting references, renaming, hover-view, ...), put your cursor/pointer anywhere on the markdown fide where there is not another referenceable (heading, tag, ...).
Completions
-
Wikilink Completions
-
Markdown Link Completions
-
Unindexed Block Completions; Fuzzy search through the whole folder of files and link anywhere, following obsidian block linking syntax
to use this, type
[[
, and after you press space, completions for every block in the vault will appear; continue typing to fuzzy match the block that you want; finally, select the block; a link will be inserted to the text document and an index (ex ^1j239) will be appended to the block in its respective file. In Neovim, this text will not be written yet into the file (it will be edited in an unsaved buffer) so type:wa
, and it should be resolved (as long as you havedynamicRegistration = true
as described here!
-
Tag Completions
-
Footnote Completions
-
Unresolved File and Heading Completions
For those who like to reference things before they are written,
markdown-oxide
has terrific support for unresolved references! It provides completions for unresolved references, provides lsp_references for them, and provides code actions to create files + append headings.
-
Callout Completions
-
Nested Callout Completions
-
Alias Completions
- [ ] Subheading completions in the form [[file#heading#subheading]] from https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+heading+in+a+note (Note: right now you can link to subheadings through [[file#subheading]])
- [ ] Headings in the current file
- [ ] Metadata completions
- [ ] Dataview completions
- [ ] Metadata tag completions
- [ ] ```query``` code block completions
- [ ] Semantic Search unindexed block completions
- [ ] Contextual linking completions using vector database
References
-
File References: Gets references to the file and all headings and blocks in the file
-
Heading References
-
Tag References: Gets all references to the tag and subtags
-
Indexed Block References
-
Footnote References
-
Unresolved file and heading references
[!NOTE] I strongly recommend using Lspsaga for references for two reasons. First because this LS sorts references by the date their files were modified and unlike
vim.lsp.buf.references()
andTelescope lsp_references
,Lspsaga finder
maintains this sorting order. Second it also allows you to edit the references in place, similar to Logseq
Hover
markdown-oxide
provides a preview of the text for an item (if there is any) as well as a snapshot of the backlinks to the item (if applicable). You can hover over both references and referenceables -- hover over headings and links to headings; as well as files and links to files.
In the hover, several backlines to the referenceable are listed, ordered by date modified.
[!NOTE] I write most of the content for a note not in the note itself, but in backlinks to the note; I also write in notes at times. Assuming content is both in backlinks and in written text, hover packages text and backlinks together to give a true preview of a referenceable.
Gif of Hover for both references and referenceables
Code Actions
-
Create file for unresolved file link
-
Append heading to file and create the file if necessary
- [ ] Link suggestions (by text match or other)
- [ ] Refactoring: Move headers or selections to a new file
- [ ] Link an unlinked reference
- [ ] Link all unlinked references to a referenceable
Diagnostics
- [X] Unresolved reference
- [ ] Unlinked reference
Symbols
- [X] File symbols: Headings and subheadings
- [X] Workspace headings: everything linkable: files, headings, tags, ... Like a good search feature
- [ ] Lists and indented lists
Rename
-
Rename File
-
Rename Heading
-
Rename Tag
Daily Notes
Daily Note completions relative to the current date
-
...for wikilinks
-
...for markdown links
Config
Markdown-Oxide
supports several configuration options. All can be specified in a ~/.config/moxide/settings.toml
or .moxide.toml
file and moxide tries to import some settings (daily notes formatting) from Obsidian directly. Here are the options with the defaults
# Leave blank to try to import from Obsidian Daily Notes
# Formatting from https://docs.rs/chrono/latest/chrono/format/strftime/index.html
dailynote = "%Y-%m-%d" # this is akin to YYYY-MM-DD from Obsidian
# Fuzzy match file headings in completions
heading_completions = true
# Set true if you title your notes by the first heading
# Right now, if true this will cause completing a file link in the markdown style
# to insert the name of the first heading in the display text area
# [](file) -> [first heading of file.md](file)
# If false, [](file) -> [](file) (for example)
title_headings = true
# Show diagnostics for unresolved links; note that even if this is turned off,
# special semantic tokens will be sent for the unresolved links, allowing you
# to visually identify unresolved links
unresolved_diagnostics = true
semantic_tokens = true
# Resolve tags in code blocks
tags_in_codeblocks = true
# Resolve references in code blocks
references_in_codeblocks = true
# The folder for new files to be created in; this is relevant for the code action that creates
# from an unresolved link. If not specified, it will import from your obsidian config option titled
# "Default Location for new notes" -- which is "" by default too.
new_file_folder_path = ""
# The folder for new daily notes: this is applied for the create file for unresolved link code action
# as well as the Today, Tomorrow, Yesterday, and Daily... lsp commands
#
# This is also imported from obsidian if not specified: specifically the option titled "New file location"
daily_notes_folder = ""
# Whether markdown links should include an extension or not
# for example [File](file.md) or [File](file)
include_md_extension_md_link = false
# Whether wikilinks should include an extension or not (needed for Markor compatibility)
# for example [[File]] or [[File.md]]
include_md_extension_wikilink = false
# Enable hover; this is relevant for VSCode and Zed where hover could be triggered on mouse hover
# and could be annoying
hover = true
Alternatives
- https://github.com/gw31415/obsidian-lsp: I have been in discussions with the author; The author doesn't have time to maintain the project. Also, I, of course, love the idea, but the current LS doesn't provide many obsidian-specific features yet.
- https://github.com/WhiskeyJack96/logseqlsp: This is a cool project and a great inspiration for Logseq support (which is upcoming). status: it doesn't seem that it is maintained and it (obviously) does not provide support for all of the obsidian syntax
- The og https://github.com/artempyanykh/marksman: I used this for a while, but it is not obsidian specific and didn't act well with my vault. Additionally, the block completions in markdown-oxide allow for a fuzzy/grep search of the entire vault to generate the completions; I don't think Markman has any features like this; (this is a feature that Logseq signified for PKM; the concept that anything is linkable is quite powerful)
Links
1: https://github.com/cargo-bins/cargo-binstall