Any plugins for formatting Markdown text?

I started learning Vim because I spend too much time formatting text right in Markdown editors. Vim motions help a lot with that, but I still want hotkeys or motions to format text in markdown to bold italic etc. Before I would think of implementing these in my own configuration, I would be surprised if there weren’t any Neovim plugins to do this. I found Markdown LSPs and plugins like Markdown Vim mode but none specific for using hotkeys or motions to format text. Here’s a page on Basic Syntax for Markdown: https://www.markdownguide.org/basic-syntax/

  • Hotkeys to change selected text to **bold** *italic*, _italic_ inline code etc.
    • ## Headings as well (any level from 1 to 6, # to ######)
    • Add links to them: [selected text](cursor position to write the link)
    • and inline code obviously.
  • > blockquotes, was well as indenting and outdenting them. indenting would be from > text to >> text.
    • Same thing with - bullet points.
  • Creating blank callouts and putting selecting text in callouts.

> [!callout label] title
> callout text or selected text.
  • Same thing with code blocks

``` cursor position (so I can specify the programming or markup language for syntax highlighting)
selected text
```

Would love a plugin for this as well, or some of it. I have these in my ~/.config/nvim/after/ftplugin/markdown.vim, only for bold/italic toggles. Requires nvim-surround:

function! s:MarkdownBoldToggle(visual) range
    if a:visual == v:true
        for l:line in range(a:firstline, a:lastline)
            if match(getline(l:line), '^\*\{2,3}[^\*]\+\*\{2,3}') >= 0
                exec 'keeppatterns' .. l:line .. 's/\%V\*\{2}\(.\+\)\*\{2}/\1/e'
            else
                exec 'keeppatterns' .. l:line .. 's/\%V.*\%V./**&**/e'
            endif
        endfor
    else  " Single-word variant requires vim-surround plugin.
        let l:curword = expand('<cWORD>')
        if match(l:curword, '^\*\{2}[^\*]\+\*\{2}') >= 0
            call nvim_feedkeys('Ehds*ds*', 'm', v:true)
        elseif match(l:curword, '^\*\{3}[^\*]\+\*\{3}') >= 0
            call nvim_feedkeys('Ehhds*ds*', 'm', v:true)
        else
            call nvim_feedkeys('ysiW*.*', 'm', v:true)
        endif
    endif
endfunction
function! s:MarkdownItalicToggle(visual) range
    if a:visual == v:true
        for l:line in range(a:firstline, a:lastline)
            if match(getline(l:line), '^\*\{3}[^\*]\+\*\{3}') >= 0
                exec 'keeppatterns' .. l:line .. 's/\%V\*\(.\+\)\*/\1/e'
            elseif match(getline(l:line), '^\*[^\*]\+\*') >= 0
                exec 'keeppatterns' .. l:line .. 's/\%V\*\(.\+\)\*/\1/e'
            else
                exec 'keeppatterns' .. l:line .. 's/\%V.*\%V./*&*/e'
            endif
        endfor
    else  " Single-word variant requires vim-surround plugin.
        let l:curword = expand('<cWORD>')
        if match(l:curword, '^\*\{1}[^\*]\+\*\{1}') >= 0
            call nvim_feedkeys('Ehds*', 'm', v:true)
        elseif match(l:curword, '^\*\{2}[^\*]\+\*\{2}') >= 0
            call nvim_feedkeys('ysiW*', 'm', v:true)
        elseif match(l:curword, '^\*\{3}[^\*]\+\*\{3}') >= 0
            call nvim_feedkeys('Ehhds*', 'm', v:true)
        else
            call nvim_feedkeys('ysiw*', 'm', v:true)
        endif
    endif
endfunction
if luaeval('require("nvim-surround") ~= nil')
    nnoremap <silent> <localleader>b :call <SID>MarkdownBoldToggle(v:false)<Cr>
    nnoremap <silent> <localleader>i :call <SID>MarkdownItalicToggle(v:false)<Cr>
    vnoremap <silent> <localleader>b :call <SID>MarkdownBoldToggle(v:true)<Cr>
    vnoremap <silent> <localleader>i :call <SID>MarkdownItalicToggle(v:true)<Cr>
endif

Just saw this plugin as well, seems to have some of those features in lua. Generally nvim-surround is good as a general purpose version but for what you want the linked plugin looks like it might be better. Note that it does require tree-sitter though. Might be scope here for a simpler plugin.

I’m using a different markdown plugin from the one @adigitoleo suggested. His looks like it may have more features? I haven’t done a careful comparison yet.

I may try the other one just for comparison sake :slight_smile: