Feel-ix-343 / markdown-oxide

Editor Agnostic PKM: you bring the text editor and we bring the PKM - inspired by and compatible with Obsidian
GNU General Public License v3.0
684 stars 10 forks source link
language-server-protocol lsp lsp-server markdown obsidian obsidian-md rust rust-lang rust-language-server vscode-language-support vscode-languageserver

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

  1. Given Neovim access to the binary.

    • Cargo Install (from source) ```bash cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide ```

    • Cargo binstall[1] (from hosted binary) ```bash cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide ```

    • AUR (from source) ```bash paru -S markdown-oxide-git ``` ```bash yay -S markdown-oxide-git ```

    • Mason.nvim (from hosted binary)
    • Nix Unstable: pkgs.markdown-oxide
  2. Modify your Neovim Configuration

    • Modify LSP Config (making sure to adjust capabilities as follows) ```lua -- 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) ```lua { name = 'nvim_lsp', option = { markdown_oxide = { keyword_pattern = [[\(\k\| \|\/\|#\)\+]] } } }, ```

    • (optional) Enable Code Lens (eg for UI reference count) Modify your lsp `on_attach` function. ```lua -- 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](https://docs.rs/fuzzydate/latest/fuzzydate/) ```lua -- 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

  1. Recommended: the extension will download the server's binary and use that
  2. The extension will use markdown-oxide from path. To install to your path, there are the following methods for VSCode:

    • Cargo Install (from source) ```bash cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide ```

    • Cargo binstall[1] (from hosted binary) ```bash cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide ```

    • AUR (from source) ```bash paru -S markdown-oxide-git ``` ```bash 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

  1. Recommended: the extension will download the server's binary and use that
  2. The extension will use markdown-oxide from path. To install to your path, there are the following methods for Zed:

    • Cargo Install (from source) ```bash cargo install --locked --git https://github.com/Feel-ix-343/markdown-oxide.git markdown-oxide ```

    • Cargo binstall[1] (from hosted binary) ```bash cargo binstall --git 'https://github.com/feel-ix-343/markdown-oxide' markdown-oxide ```

    • AUR (from source) ```bash paru -S markdown-oxide-git ``` ```bash 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:

[!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

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() and Telescope 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 ![hover](https://github.com/Feel-ix-343/markdown-oxide/assets/88951499/ed6d8d48-e700-42f2-8ab6-d0b8d2d038f9)

Code Actions

Diagnostics

Symbols

Rename

Daily Notes

Daily Note completions relative to the current date

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

Links

1: https://github.com/cargo-bins/cargo-binstall