tpope / vim-markdown

Vim Markdown runtime files
1.23k stars 191 forks source link

Prevent the folding of heading syntax in code fences #137

Closed axvr closed 5 years ago

axvr commented 5 years ago

Previously in Markdown files, Vim would treat heading syntax in code fences as Markdown headers. This commit ensures that only headers will be folded by checking the synIDattr of the item.

E.g. The comment in this code snippet would have been treated as a Markdown header.

```sh
# This is a comment
echo "Hello world"
```
gpanders commented 5 years ago

Any movement on this? I noticed the same problem earlier today and implemented a fix myself before I saw this one.

tpope commented 5 years ago

Can we do this without the syntax highlighting checks?

axvr commented 5 years ago

I honestly have no idea if this can be done (cleanly) without checking the syntax highlighting group, I would imagine that such a solution would be more complex and require a lot of regular expressions, however I am no expert and could've missed an obvious simple solution.

Unfortunately as documented in :help synID() this solution could cause some performance hits if the file is particularly large.

@gpanders, how did your solution differ to mine? Did it also check the highlight group?

tpope commented 5 years ago

Yeah I slightly misunderstood the issue, I think you're right. Let's change from looking for header highlighting to looking for # and not code block highlighting. That will make things more robust. Sometimes the syn functions lie if the area is off screen or a redraw is pending.

gpanders commented 5 years ago

My solution was similar (I also checked the syntax highlighting) but I did as @tpope said: I checked to make sure I was not in a code block:

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

  if index(map(synstack(v:lnum, 1), 'synIDattr(v:val, "name")'), 'markdownCode') > -1
    return "="
  endif

  " Regular headers
  let depth = match(line, '\(^#\+\)\@<=\( .*$\)\@=')
  if depth > 0
    return ">" . depth
  endif

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

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

  return "="
endfunction
axvr commented 5 years ago

@tpope, I've changed it so that it now checks the header is not within a code block as per your suggestion.

tpope commented 5 years ago

Thanks!