OXY2DEV/markdoc.nvim

github github
programming-languages-supportmarkdown-and-latex
stars 44
issues 1
subscribers 1
forks 0
CREATED

UPDATED


🎇 markdoc.nvim

Tree-sitter based markdown to vimdoc converter for Neovim.

🪄 Features

  • Common markdown syntax support.
  • Common inline HTML support.
  • Aligned paragraph(via <p align=""></p> or <div align=""></div>)
  • Preserves whitespace.
  • Extended syntax support(e.g. Callouts).
  • Table converter with column alignment & text wrap support.
  • Custom Table of contents generator.
  • Custom file header support(with support for version, author, date modified).
  • Fully customizable.
  • Ability to configure per file(using JSON).
  • Ability to remove parts of the file when converting to Vimdoc(e.g. Top heading in README.md).

And much more!

🧭 Requirements

  • tree-sitter-markdown.
  • tree-sitter-markdown_inline.
  • tree-sitter-html(for inline HTML).

[!IMPORTANT] By default, callouts use nerd font characters. You can change this in the config to use normal text instead.

📦 Installation

🧩 Vim-plug

Plug "OXY2DEV/markdoc.nvim"

💤 lazy.nvim

{
    "OXY2DEV/markdoc.nvim"
},
return {
    "OXY2DEV/markdoc.nvim"
};

🦠 mini.deps

local MiniDeps = require("mini.deps");

MiniDeps.add({
    source = "OXY2DEV/markdoc.nvim",
})

🌒 rocks.nvim

[!WARNING] luarocks package may sometimes be a bit behind main.

:Rocks install markdoc.nvim

📥 GitHub release

Tagged releases can be found in the release page.

[!NOTE] Github releases may sometimes be slightly behind main.

🎇 Usage

There is a single command,

:Doc

When called without arguments, it runs on the current buffer.

When called with an argument,

:Doc README.md

It converts given file.

:Doc 0

Or buffer.

It can be called with multiple files/buffers.

:Doc README.md test.md

📬 API functions

There are 2 available API functions.

🧩 File conversion API

--[[ Converts **file** with `path` into `vimdoc`. ]]
---@param path string Path to file.
---@param user_config? markdoc.config Custom configuration. Overrides the file specific configuration.
---@param use? integer Buffer to dump the preview into. Has no effect if `generic.filename` is set.
markdoc.convert_file = function (path, user_config, use)
    -- ...
end

This function can be used to convert a file in path into vimdoc.

You can use it like so,

require("markdoc").convert_file("README.md", {
    generic = { filename = "doc/markdoc.nvim.txt" }
});

🧩 Buffer conversion API

--[[ Converts `buffer` into `vimdoc`. ]]
---@param buffer? integer Buffer ID. Defaults to *current* buffer.
---@param user_config? markdoc.config Custom configuration. Overrides the file specific configuration.
---@param use? integer Buffer to dump the preview into. Has no effect if `generic.filename` is set.
markdoc.convert_buffer = function (buffer, user_config, use)
    -- ...
end

This function can be used to convert a buffer into vimdoc.

You can use it like so,

require("markdoc").convert_buffer(0, {
    generic = { filename = "doc/markdoc.nvim.txt" }
});

This will convert current buffer.

✨ Special syntax

markdoc.nvim uses special comments to modify the file. These can be,

✨ File-specific configuration

Use <!--markdoc {}--> syntax for adding file specific configuration.

<!--markdoc
    {
        "generic": {
            "filename": "doc/markdoc.nvim.txt",
            "force_write": true,
            "header": {
                "desc": "Tree-sitter based `Markdown -> Vimdoc` converter for Neovim",
                "tag": "markdoc.nvim"
            }
        },
        "markdown": {
            "tags": {
                "Features$": [ "markdoc.nvim-features" ],

                "^generic$": [ "markdoc.nvim-generic" ],
                "^filename$": [ "markdoc.nvim-filename", "markdoc.nvim-generic.filename" ],
                "^force_write$": [ "markdoc.nvim-force_write", "markdoc.nvim-generic.force_write" ],
                "^winopts$": [ "markdoc.nvim-winopts", "markdoc.nvim-generic.winopts" ]
            }
        }
    }
-->

✨ Ignoring parts of the document

Use <!--markdoc_ignore_start--> & <!--markdoc_ignore_end--> syntax for specifying parts of the document that will be removed in the converted document.

<!--markdoc_ignore_start-->

# Invisible text

<!--markdoc_ignore_end-->

Tree-sitter based `markdown` to `vimdoc` converter for Neovim.

Some visible text

This will result in


Some visible text

✨ Table of contents

Table of contents can be generated by adding <TOC/> to a line.

<TOC/>

🔧 Configuration

The plugin can be set-up by using the setup() function.

require("markdoc").setup({
    markdown = {
        code_blocks = {
            fallback_language = "vim",
            indentation = "\t"
        },
    }
});

The following options are supported,

generic

Type: markdoc.config.generic

---@class markdoc.config.generic
---
---@field filename? string Name of help file.
---@field relative_path? boolean Is the file oath relative to the `source` file? Gets set to `false`, if `filename` starts with `~`.
---@field force_write? boolean Should `:write!` be used instead of `:write`?
---@field winopts? table Window options for the previewer.
---
---@field textwidth? integer Text width of the help file.
---@field indent? integer Number of spaces to use for indentation.
---
---@field header markdoc.config.generic.header
---@field links markdoc.config.generic.links
---@field images markdoc.config.generic.links
---@field toc markdoc.config.generic.toc

Generic configuration options. These are,

filename

Type: string

Name of the file to save to.

[!NOTE] This is relative to the current file being concerted!

[!IMPORTANT] markdoc doesn't create non-existing directories! You have to make sure the directories exist before using it!

relative_path

Type: string

When true(default value), generic.filename will be relative to the source file's location. When false, the filename will be relative to the current working directory.

[!NOTE] This is useful for automation if you wish to have some files be created relative to their source and others relative to current directory.

force_write

Type: boolean

When true, use :write! instead of :write.

winopts

Type: vim.api.keyset.win_config

Options passed to nvim_open_win() for showing file preview.

textwidth

Type: integer

Same as 'textwidth'(:h 'textwidth'). Used for text wrapping & setting the modeline.

Used by options that use ratios.

[!NOTE] This will fallback to 80 by default.

indent

Type: integer

Unused.

header

Type: markdoc.config.generic.header

Configuration for file header.

---@class markdoc.config.generic.header
---
---@field enabled? boolean
---
---@field tag? string Name of `help tag` for this file..
---@field desc? string Short description to show at top.
---
---@field author? string[] Author(s) of the help file.
---@field version? string Version string.
---@field last_modified? boolean Should the last modification date be shown?

links

Type: markdoc.config.generic.links

Configuration for link reference section.

---@class markdoc.config.generic.links
---
---@field enabled? boolean
---@field desc? string Short description to show at top of link section.
---
---@field list_marker? string
---@field url_format? string

images

Type: markdoc.config.generic.links

Configuration for image reference section. Same as above.

toc

Type: markdoc.config.generic.toc

Configuration for table of contents section.

---@class markdoc.config.generic.toc
---
---@field enabled? boolean
---
---@field heading? string
---@field heading_level? integer
---
---@field entries generic.toc.entry[]

Each entry in entries has the following structure.

---@class generic.toc.entry
---
---@field text string
---@field tag string

markdown

Markdown options.

---@class markdoc.config.markdown
---
---@field use_link_refs markdown.use_link_refs Should *references* be used instead of `URLs`
---@field link_ref_format? string `Format string` used for the link references. Default: `{%d}`.
---@field link_url_modifiers markdown.url_modifier.entry[] Changes the url based on a pattern
---
---@field heading_ratio integer[] Ratio for the amount of space a heading text & it's tags should take. Default: `{ 6, 4 }`.
---
---@field block_quotes markdoc.config.markdown.block_quotes
---@field code_blocks markdoc.config.markdown.code_blocks
---@field hr? string Text used to show `horizontal rules`
---@field list_items markdoc.config.markdown.list_items
---@field tables markdoc.config.markdown.tables
---@field tags markdoc.config.markdown.tags

use_link_refs

Type: markdown.use_link_refs

---@alias markdown.use_link_refs
---| boolean
---| fun (description: string, destination: string): boolean

Controls whether references be used instead of the URL.

With `use_link_refs = true`.

Link {1}

With `use_link_refs = true`.

Link www.example.com

link_ref_format

Type: string

Text used for formatting the reference of a link. Default is {%d}.

link_url_modifiers

Type: markdown.url_modifier.entry[]

---@class markdown.url_modifier.entry
---
---@field [1] string `Lua-pattern` to match.
---@field [2] markdown.url_modifier

Modifies URLs. Useful for section links(e.g. #link_url_modifiers).

Each entry has the following pattern.

---@alias markdown.url_modifier
---| string
---| fun (description: string, destination: string): string

heading_ratio

Type: [ integer, integer ]

Ratio of spaces taken by heading text & the tags. Default is { 6, 4 }.

[!NOTE] This may not be respected if a tag is too long.

block_quotes

Type: markdoc.config.markdown.block_quotes

---@class markdoc.config.markdown.block_quotes
---
---@field default markdown.block_quotes.opts
---@field [string] markdown.block_quotes.opts

Configuration for block quotes & callouts.

Each block quote type has the following options.

---@class markdown.block_quotes.opts
---
---@field border? string
---@field icon? string
---@field preview? string

code_blocks

Type: markdoc.config.markdown.code_blocks

---@class markdoc.config.markdown.code_blocks
---
---@field indentation? string Text used for indenting code block.
---@field fallback_language? string Fallback language for `code_blocks` without a language.

Configuration for code blocks.

hr

Type: string

Text representing a horizontal rule.

markdown = {
    hr = " ╶" .. string.rep("─", 76) .. "╴ ",
}

list_items

Type: markdoc.config.markdown.list_items

---@class markdoc.config.markdown.list_items
---
---@field marker_plus? string Text used to replace `+` markers.
---@field marker_minus? string Text used to replace `-` markers.
---@field marker_star? string Text used to replace `*` markers.
---
---@field marker_dot? string Text used to replace `%d+.` markers. May contain `%d` to add the marker number.
---@field marker_parenthesis? string Text used to replace `%d+)` markers. May contain `%d` to add the marker number.

tables

Type: markdoc.config.markdown.tables

---@class markdoc.config.markdown.tables
---
---@field max_col_size? integer Maximum width of a table `column`.
---@field preserve_whitespace? boolean Should **leading** & **trailing** whitespaces be preserved?
---@field default_alignment? "left" | "center" | "right" Default *text alignment* of table cells.
---@field borders? markdown.tables.border Table border.

Changes how table borders are shown.

Tables have the following options for border drawing.

---@class markdown.tables.border
---
---@field top markdown.tables.border.decoration
---@field bottom markdown.tables.border.decoration
---
---@field separator markdown.tables.border.decoration
---@field row_separator markdown.tables.border.decoration
---
---@field header markdown.tables.border.row
---@field row markdown.tables.border.row

top, bottom, separator & row_separator have the following options.

---@class markdown.tables.border.decoration
---
---@field [1] string Left border
---@field [2] string Character used to make creating columns.
---@field [3] string Right border
---
---@field [4] string Column separator.

header & row have the following options.

---@class markdown.tables.border.row
---
---@field [1] string Left border
---@field [2] string Column separator.
---@field [3] string Right border
markdown = {
    tables = {
        max_col_size = 20,
        preserve_whitespace = true,
        default_alignment = "left",

        borders = {
            header = { "│", "│", "│" },
            row = { "│", "│", "│" },

            separator = { "├", "─", "┤", "┼" },
            row_separator = { "├", "─", "┤", "┼" },

            top = { "╭", "─", "╮", "┬" },
            bottom = { "╰", "─", "╯", "┴" },
        },
    },
}

tags

Type: markdoc.config.markdown.tags

---@class markdoc.config.markdown.tags
---
---@field default? string[]
---@field [string] string[]

Maps heading text to a list of tags.

markdown = {
    tags = {
        ["^textwidth$"]: { "markdoc.nvim-textwidth", "markdoc.nvim-generic.textwidth" },
    },
}