1

I have python examples in a markdown file in a code fence (e.g. when I convert a jupyter notebook into a markdown document). These snippets sometimes have code comments in them starting with #. The markdown folder, however, recognizes these as headings, so folds them as chapters. This, in turn, messes up the document outline.

How can I prevent this?

2 Answers 2

2

It would be really hard to do reliably.

Basically, if you brave enough, check what current markdown plugin uses for folding and try to rewrite it:

  1. :set foldmethod? to find out if it is expr or not
  2. :set foldexpr? to find out what is the function name expr uses
  3. create your own MarkdownFold() function (or whatever name is 2. showed)

So you would end up copy pasting existing MarkdownFold function to your vimrc and start hacking.

function! MarkdownFold()
  let line = getline(v:lnum)

  ...
  ...

  return "="
endfunction

In the end you will have to analyze if current line is python comment and skip it. Which would be the trickiest part. Is your line in a code block? How far backwards you should scan for code block beginning? Etc.

And depending on your implementation your vim would probably become slow for markdown files.

PS, I have tried to do similar thing for my implementation of folding for asciidoctor files, but couldn't do anything good, so I decided not to bother with it. Anyway == is far less common than ## :)

UPDATE

So it just came to my mind that it is possible to get syntax group of a current line. And you should be able to check if it is a markdown header or not. I have implemented it for my asciidoctor plugin and did this also for a markdown (I already have it in my after/ftplugin folder to tune it for markdown frontmatter).

Here is the result:

function! MarkdownFold()
  let line = getline(v:lnum)

  " Regular headers
  let depth = match(line, '\(^#\+\)\@<=\( .*$\)\@=')
  if depth > 0
    " check syntax, it should be markdownH1-6
    let syncode = synstack(v:lnum, 1)
    if len(syncode) > 0 && synIDattr(syncode[0], 'name') =~ 'markdownH[1-6]'
        return ">" . depth
    endif
  endif

  " Setext style headings
  let prevline = getline(v:lnum - 1)
  let nextline = getline(v:lnum + 1)
  if (line =~ '^.\+$') && (nextline =~ '^=\+$') && (prevline =~ '^\s*$')
    return ">1"
  endif

  if (line =~ '^.\+$') && (nextline =~ '^-\+$') && (prevline =~ '^\s*$')
    return ">2"
  endif

  " frontmatter
  if (v:lnum == 1) && (line =~ '^----*$')
      return ">1"
  endif

  return "="
endfunction

enter image description here

0

The masukomi/vim-markdown-folding plugin seems to solve this issue of # comment in fenced code being treated as headings. The difference with the default markdown folding that comes with the installation is that with the plugin, all headings are explicit and you cannot fold to a certain level, which may actually be what one wants unless you have too many headings.

2
  • 1
    Welcome to Vi and Vim! If you have info on how the plugin solves the issue, that would make a great addition (via an edit).
    – D. Ben Knoble
    Commented Jan 26, 2021 at 21:43
  • So the above-mentioned solution is for Vim 8.1, which has a markdown.vim filetype plugin dated 2016 Aug. 29. Install the vim-markdown-folding using a plug-in manager like vim-plug and the # comment in a code block will be displayed properly. In Vim 8.2 the default markdown.vim filetype plugin is dated 2019 Dec. 05 and has the comment inside the fenced code block issue solved. No need to have the plug-in.
    – whytong
    Commented Feb 1, 2021 at 21:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.