panvimdoc

panvimdoc

Docs Build Sponsor Donate

Write documentation in pandoc markdown. Generate documentation in vimdoc.

image

::: center This software is released under a MIT License. :::

TLDR

  1. Add the following to ./.github/workflows/panvimdoc.yml:

    name: panvimdoc
    
    on:
      push:
        branches: [main]
        paths:
          - README.md 
          - .github/workflows/panvimdoc.yml 
    
    permissions:
      contents: write
    
    jobs:
      docs:
        runs-on: ubuntu-latest
        name: pandoc to vimdoc
        steps:
          - uses: actions/checkout@v2
          - uses: kdheepak/panvimdoc@main
            with:
              vimdoc: ${{ github.event.repository.name }}
          - uses: stefanzweifel/git-auto-commit-action@v4
            with:
              commit_message: "Auto generate docs"
              branch: ${{ github.head_ref }}
  2. README.md gets converted to ./doc/${{ github.event.repository.name }}.txt and auto-committed to the repo.

Optional: Add the following to ./.github/dependabot.yml to auto update your github action dependencies:

version: 2
updates:
  # Maintain dependencies for GitHub Actions
  - package-ecosystem: github-actions
    directory: "/"
    schedule:
      interval: weekly
    open-pull-requests-limit: 10

Usage

Generating vimdoc using GitHub Actions

Create an empty doc file:

touch doc/.gitkeep
git commit -am "Add empty doc folder"
git push

Then add the following to ./.github/workflows/panvimdoc.yml:

name: panvimdoc

on: [push]

jobs:
  docs:
    runs-on: ubuntu-latest
    name: pandoc to vimdoc
    steps:
      - uses: actions/checkout@v2
      - name: panvimdoc
        uses: kdheepak/panvimdoc@main
        with:
          vimdoc: __VIMDOC_PROJECT_NAME_HERE__ # Output vimdoc project name (required)
          # The following are all optional
          pandoc: "README.md" # Input pandoc file
          version: "NVIM v0.8.0" # Vim version number
          toc: true # Table of contents
          description: "" # Project description used in title (if empty, uses neovim version and current date)
          titledatepattern: "%Y %B %d" # Pattern for the date that used in the title
          demojify: false # Strip emojis from the vimdoc
          dedupsubheadings: true # Add heading to subheading anchor links to ensure that subheadings are unique
          treesitter: true # Use treesitter for highlighting codeblocks
          ignorerawblocks: true # Ignore raw html blocks in markdown when converting to vimdoc
          docmapping: false # Use h4 headers as mapping docs
          docmappingprojectname: true # Use project name in tag when writing mapping docs
          shiftheadinglevelby: 0 # Shift heading levels by specified number
          incrementheadinglevelby: 0 # Increment heading levels by specified number

The only required thing for you to do is to choose a __VIMDOC_PROJECT_NAME_HERE__ appropriately. This is usually the name of the plugin or the documentation file without the .txt extension. For example, the following:

- name: panvimdoc
  uses: kdheepak/panvimdoc@main
  with:
    vimdoc: panvimdoc

will output a file doc/panvimdoc.txt and the vim help tag for it will be panvimdoc using the main branch of the repository.

All the other options are optional.

It is recommended to pin to an exact version so you can be confident that no surprises occur for you or your users. See https://github.com/kdheepak/panvimdoc/releases/latest for which version to use. Once you pick a version, you can pin it like so:

- name: panvimdoc
  uses: kdheepak/panvimdoc@vX.X.X

For an example of how this is used, see one of the following workflows:

Or see any of the packages here that depend on this action: https://github.com/kdheepak/panvimdoc/network/dependents

Generating HTML using GitHub Actions

If you are interested in making your vim plugin documentation available as a HTML page, check out .github/workflows/docs.yml file.

You can find the Markdown file you are reading right now converted to HTML here: https://kdheepak.com/panvimdoc/

Here’s an example:

name: docs

on:
  push:
    branches: main

permissions:
  contents: write

jobs:
  publish-gh-page:
    runs-on: ubuntu-latest
    steps:
      - name: checkout code
        uses: actions/checkout@v3
      - name: pandoc markdown to html
        uses: docker://pandoc/latex:3.1
        with:
          args: >-
            --katex --from markdown+tex_math_single_backslash --to html5+smart
            --template="./scripts/template.html5" --css="/panvimdoc/css/theme.css"
            --css="/panvimdoc/css/skylighting-solarized-theme.css" --toc --wrap=none --metadata
            title="panvimdoc" doc/panvimdoc.md --lua-filter=scripts/include-files.lua
            --lua-filter=scripts/skip-blocks.lua -t html -o public/index.html
      - name: deploy to GitHub pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          branch: gh-pages
          folder: public

Using pre-commit locally

pre-commit lets you easily install and manage pre-commit hooks locally.

Two hooks are available, differing only in the way dependencies are handled:

To use a hook, first install pre-commit. Then, add the following to your .pre-commit-config.yaml (here panvimdoc-docker is used):

- repo: 'https://github.com/kdheepak/panvimdoc'
  rev: v4.0.1
  hooks:
    - id: panvimdoc-docker
      args:
        - '--project-name'
        - <your-project-name>

You can specify additional arguments to panvimdoc.sh using args. See the section below (or run ./panvimdoc.sh) for the full list of arguments.

To change the input file, modify the files field of the hook and supply the corresponding --input-file to args. In the example below, the hook will be triggered if any .md file changes:

- repo: 'https://github.com/kdheepak/panvimdoc'
  rev: v4.0.1
  hooks:
    - id: panvimdoc-docker
      files: ^.*\.md$
      args:
        - '--project-name'
        - <your-project-name>
        - '--input-file'
        - <your-input-file.md>

Using it manually locally

The ./panvimdoc.sh script runs pandoc along with all the filters and custom output writer.

$ ./panvimdoc.sh
Usage: ./panvimdoc.sh --project-name PROJECT_NAME --input-file INPUT_FILE --vim-version VIM_VERSION --toc TOC --description DESCRIPTION --dedup-subheadings DEDUP_SUBHEADINGS --treesitter TREESITTER

Arguments:
  --project-name: the name of the project
  --input-file: the input markdown file
  --vim-version: the version of Vim that the project is compatible with
  --toc: 'true' if the output should include a table of contents, 'false' otherwise
  --description: a project description used in title (if empty, uses neovim version and current date)
  --dedup-subheadings: 'true' if duplicate subheadings should be removed, 'false' otherwise
  --title-date-pattern: '%Y %B %d' a pattern for the date that used in the title
  --demojify: 'false' if emojis should not be removed, 'true' otherwise
  --treesitter: 'true' if the project uses Tree-sitter syntax highlighting, 'false' otherwise
  --ignore-rawblocks: 'true' if the project should ignore HTML raw blocks, 'false' otherwise
  --doc-mapping: 'true' if the project should use h4 headers as mapping docs, 'false' otherwise
  --doc-mapping-project-name: 'true' if tags generated for mapping docs contain project name, 'false' otherwise
  --shift-heading-level-by: 0 if you don't want to shift heading levels , n otherwise
  --increment-heading-level-by: 0 if don't want to increment the starting heading number, n otherwise

You will need pandoc v3.0.0 or greater for this script to work.

Motivation

Writing user-friendly documentation is important for every successful software project. This is particularly true when writing documentation for users in the world of vim plugins.

The process of writing and maintaining this documentation can often be a cumbersome, time-consuming task. This project is aims to make that process a little bit easier by allowing anyone to write documentation in markdown (or any format Pandoc supports) and converting it to vimdoc automatically. This way, plugin authors will have to write documentation just once (for example, as part of the README of the project), and the vim documentation can be autogenerated.

Rationale

  1. Simplicity: Writing in Markdown is often more intuitive for developers. By converting from Markdown to vimdoc, authors can maintain the simplicity of Markdown while adhering to the vimdoc standards.
  2. Unified Documentation: Plugin authors can write their documentation just once (such as in the project’s README) and automatically generate vim documentation, ensuring consistency and saving time.
  3. Preserving Vim Features: Vimdoc isn’t just plain text; it supports syntax highlighting, tags, links, and careful formatting using whitespace. It’s essential to preserve these features when converting to ensure the quality and usefulness of the documentation. See https://vimhelp.org/helphelp.txt.html#help-writing or @nanotree’s project for more information.
  4. Leveraging Pandoc: Unlike existing solutions, this project leverages Pandoc’s wide range of features, including support for multiple Markdown flavors and easy-to-write custom filters in Lua.
  5. Interoperability: The choice of Pandoc allows for enhanced flexibility, making it easier to extend functionality or even adapt the converter for other documentation formats in the future.

Background

Writing documentation in Markdown and converting it to vimdoc is not a novel idea.

For example, ibhagwan/ts-vimdoc.nvim is an implementation a neovim treesitter based markdown to vimdoc converter that works fairly well. There are no dependencies except for the Markdown treesitter parser. It is neovim only but you can use this on github actions even for a vim plugin documentation.

There’s also wincent/docvim which is written in Haskell. Finally, there’s FooSoft/md2vim which is written in Go.

However, none of these projects use Pandoc. Pandoc Markdown supports a wide number of features: See https://pandoc.org/MANUAL.html for more information. Most importantly, it supports a range of Markdown formats and flavors. And, Pandoc has filters and a custom output writer that can be configured in lua. Pandoc filters can extend the capability of Pandoc with minimal lua scripting, and these are very easy to write and maintain too.

That means, with this project, you can write your Vim documentation in Markdown, RestructuredText, AsciiDoc, etc and convert it to VimDoc, PDF, Word, HTML etc.

Goals

By offering a specification and reference implementation for converting Pandoc Markdown to vimdoc, this project aims to reduce friction in the documentation process for vim plugin authors.

Here are the specific goals that guide this project:

Features

This project offers a comprehensive suite of features designed to streamline the conversion process from Markdown to vimdoc:

Specification

The specification is described in panvimdoc.md along with examples. The generated output is in panvimdoc.txt. The reference implementation of the Pandoc lua filter is in panvimdoc.lua. See panvimdoc.sh for how to use this script, or check the Usage section.

References

Donate

If you’ve found this project helpful, you can show your appreciation by sponsoring me on GitHub Sponsors or donating via Strip.

Specification

See ./panvimdoc.txt for generated output of this file.

External includes

Use the following in your markdown file to include any other markdown file:

```{.include}
README.md
```

The path of the file is with respect to the working directory where pandoc is executed.

Codeblocks

Multi line Code blocks are indented 4 spaces and

are formatted

appropriately with > and <.

Alternatively, you can use vimdoc as the language for the code block to write raw text that will be inserted into the final document.

For example, the following:

```vimdoc
You can use codeblocks that have language as `vimdoc` to write raw vimdoc.
```

will be rendered verbatim in the generated documentation.

This can be used to write any custom whitespace formatted documentation in the generated vimdoc (for mappings, options etc).

Title

The first line of the documentation that is generated will look something like this:

*panvimdoc.txt*    For VIM - Vi IMproved 8.1       Last change: 2021 August 11

Heading

Main headings are numbered.

Sub Heading 2

Sub headings are upper cased heading.

Notice that both headings and subheadings have tags.

Sub Heading 3

Sub headings are upper cased, but do not have tags. They are also not included in the TOC. They are suffixed with ~ which highlights as bold text when the file is viewed on GitHub.

You can use markdown links in vimdoc.

You can link to the tags by using [sub heading 2](#sub-heading-2).

This way, any links will work in markdown README on GitHub or on the web using anchors AND will work as tags and links in vimdoc. The anchors are simply dropped in vimdoc inline. The onus is on the documentation writer to choose the correct anchor for the appropriate Markdown link.

In vimdoc tags are created when anchors to the internal document are used. If the target is an external link, the link is inlined.

If the external link is to the neovim documentation, an internal vim link is generated. For example:

This is excluded from the links section.

Lastly, if the markdown text is a url, the link is not added to the links section and instead is placed inline.

Linking to help tags

Markdown doucments may suggest help tags via :h help-tag, which are converted to |help-tag| “hot links” in vimdoc.

Mappings

While you can use codeblocks with the language vimdoc to insert text in the generated vimdoc, it can be useful to have a markdown friendly way to write documentation for mappings.

Pandoc supports definition lists: https://pandoc.org/MANUAL.html#definition-lists. This can be used to generate documentation of mappings. All of the content in curly braces {...} that is part of the header is dropped and a tag is created.

For example, the following in a markdown file:

:FnlCompileBuffer

: Compiles current active fennel buffer

:FnlCompile[!]

: Diff compiles all indexed fennel files
If bang! is present then forcefully compiles all `source` files

:Fnl {expr}

: Executes and Evalutate {expr} of fennel

     ```fennel
     :Fnl (print "Hello World")

     :Fnl (values some_var)
     ```

     Testing

becomes the following vimdoc:


                                             *projectName-:FnlCompileBuffer*


:FnlCompileBuffer                      Compiles current active fennel buffer


                                                   *projectName-:FnlCompile*


:FnlCompile[!]                         Diff compiles all indexed fennel files
                                       If bang! is present then forcefully compiles all `source` files


                                                          *projectName-:Fnl*


:Fnl {expr}                            Executes and Evalutate {expr} of fennel
                                       >fennel
                                           :Fnl (print "Hello World")

                                           :Fnl (values some_var)
                                       <
                                       Testing

Notice that the tag *projectName-:Command* is generated for you. Additionally, content in square brackets [...] or curly brackets {...} is also dropped for creating the tag name.

i.e. the term ### :[range]Command becomes the tag *projectName-:Command*.

See following mappings as examples:

pv{motion}

Command that operates over {motion} moved.

pvd

Command that takes [count] lines.

:[range]CommandName {doc=CommandName}

Command that operates over [range].

{Visual}pv

Command that operates over highlighted lines.

Table

Support for markdown tables is also available:

Option Background Default Description
lightness light nil Change background colors lightness. Options: 'bright', 'dim'.
darkness dark nil Change background colors darkness. Options: 'stark', 'warm'.
solid_vert_split both false Solid |hl-VertSplit| background.
solid_line_nr both false Solid |hl-LineNr| background.
solid_float_border both false Make |hl-FloatBorder| have a more distinguishable background highlight.
darken_noncurrent_window light false Make non-current window background darker than Normal.
lighten_noncurrent_window dark false Make non-current window background lighter than Normal.
italic_comments both true Make comments italicize.
darken_comments light 38 Percentage to darken comments relative to Normal bg.
lighten_comments dark 38 Percentage to lighten comments relative to Normal bg.
darken_non_text light 25 Percentage to darken |hl-NonText| relative to Normal bg.
lighten_non_text dark 30 Percentage to lighten |hl-NonText| relative to Normal bg.
darken_line_nr light 33 Percentage to darken |hl-LineNr| relative to Normal bg.
lighten_line_nr dark 35 Percentage to lighten |hl-LineNr| relative to Normal bg.
darken_cursor_line light 3 Percentage to darken |hl-CursorLine| relative to Normal bg.
lighten_cursor_line dark 4 Percentage to lighten |hl-CursorLine| relative to Normal bg.
colorize_diagnostic_underline_text both false Colorize the fg of DiagnosticUnderline*.
transparent_background both false Make background transparent.

Markdown only content

Sometimes you want to show content that is to be present in Markdown and on the rendered view on GitHub but ignored in the generated vimdoc. This can be placed inside panvimdoc-ignore-{start/end} blocks:

<!-- panvimdoc-ignore-start -->

<details>
    <summary>Vimdoc Ignored Section</summary>

This section will ignored when generating the vimdoc file.
This will only show up in the Markdown file.

</details>

<!-- panvimdoc-ignore-end -->

The following will only be present in the Markdown document.

The convenient advantage of using <!-- panvimdoc-ignore-{start/end} --> blocks in a HTML comment syntax is that the comment will not rendered in HTML or on GitHub, giving the documentation writers control to present the information differently on GitHub and in vimdoc. If you want to see examples of this, see the raw markdown version of this file.

The only thing to keep in mind is that you must leave new line spaces before and after a comment tag. For example, do not do this:

<!-- panvimdoc-ignore-start -->
![screenshot](./gif.gif)
<!-- panvimdoc-ignore-end -->

because it may cause the rest of your document to be ignored. Do this instead:

<!-- panvimdoc-ignore-start -->

![screenshot](./gif.gif)

<!-- panvimdoc-ignore-end -->

Vimdoc only content

Inversely to markdown only content, sometimes you want to show content only present in Vimdoc and hidden when viewed on Github.

This can be placed inside panvimdoc-include-comment comments.

As with markdown only content, you must include a blank link before and after the comment.


<!-- panvimdoc-include-comment You can include single lines  -->

<!-- panvimdoc-include-comment

Or multiple lines

- with other
- content
- types

# And vimdoc only headings

## That can include subheadings

Infact you can include any kind of content in the comment.

-->

Neovim is a great text editor.

Neovim supports :h lua plugins and is also:

Details and summary

You can even use <details> and <summary> tags for your README.md.

Summary

This section is the details.

The html tags are dropped and the following output is generated in the vimdoc file.

If you are using html <b> ... </b> tags, use them on new lines. Inline bold tags will have a ~ appended to the text and that may not be what you want.

Keyboard HTML tag

Use <kbd>CMD + o</kbd> in markdown, for example CMD + o.

Examples

First example

Examples

Second example

Remove emojis

:sparkles: Features

:zap: Requirements

:package: Installation