1

Udated 2023-09-11: Changed example to asterisk as it is simpler and the question now refers to \zs instead of \ze as \zs seems to be the issue.

I am trying to adapt the VIM Markdown syntax file so that its behavior for italics with asterisks is more like the Github Markdown editor.

This pattern works exactly the way I want for matching italics:

syn match markdownItalic "\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*" contains=markdownItalicAsteriskStart,markdownItalicAsteriskEnd

To conceal the asterisks, I also need two patterns that exactly match the single asterisk characters that start and end the italics section. Trailing/leading whitespace NOT included. I have solved this, too. This is the search pattern I have found for finding the ending asterisk:

\(\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\)\zs\*

Unfortunately this only works when I use it interactively in VIM, but not when I use it in markdown.vim (s:conceal is a variable set analogous to s:concealends in the original):

exe 'syn match markdownItalicAsteriskEnd "\(\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\)\zs\*"' s:conceal

I suspect that it is \zs that does not work in my syntax file and have tried an alternative \@<= version. This almost works, but unfortunately cannot backtrack across more than one line (documented limitation) and therefore does not work for paragraphs in italics of more than two lines:

\(\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\)\@<=\*

Does anybody know what can cause \zs to fail in a Markdown syntax file?

Udate 2023-09-12: Some Tests and a Workaround

markdownItalicAsteriskStart

I have found three ways to detect the starting asterisk. They all work perfectly.

Using \@=:

\*\(\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*\)\@=

Using \ze:

\*\ze\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*

With offset:

exe 'syn match markdownItalicAsteriskStart "\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*"ms=s,me=s+1' s:conceal

markdownItalicAsteriskEnd

Knowing three ways to solve the starting asterisk I thought I would try the corresponding methods for the terminating asterisk. Unfortunately only one works for me.

Using \@<= (works, but limited to two lines as stated in the documentation):

\(\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\)\@<=\*

Using \zs (works perfectly in an interactive session, but does nothing when used in the syntax file; this is the subject of the question):

\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\zs\*

With offset (does not work):

exe 'syn match markdownItalicAsteriskEnd "\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*"ms=e-1,me=e' s:conceal

The reason why this version with offsets will not work across newlines is documented here. But it does nothing at all for me and I have no idea why.

Workaround

This is the workaround I will use. It works very well with the only limitation that paragraphs in italics cannot span more than two lines. Quite OK for me.

let s:conceal = ''
let s:concealends = ''
if has('conceal') && get(g:, 'markdown_syntax_conceal', 1) == 1
  let s:conceal = ' conceal'
  let s:concealends = ' concealends'
endif
exe 'syn match markdownItalicAsteriskStart "\*\(\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*\)\@="' s:conceal
exe 'syn match markdownItalicAsteriskEnd "\(\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\)\@<=\*"' s:conceal
syn match markdownItalic "\*\w\(\([^\n]\|\n[^\n]\)\{-}\)\w\*" contains=markdownItalicAsteriskStart,markdownItalicAsteriskEnd
5
  • Why do you use :help :execute?
    – romainl
    Sep 7 at 10:17
  • @romainl The original uses a variable let s:concealends = ' concealends' and I did something similar (I will edit my question). I tried now without execute and "hard-wired" conceal, just syn match markdownItalicUnderscoreEnd "\(\(\(^\|\W\)_\S\(\([^\n]\|\n[^\n]\)\{-}\)\S\)\zs_\)\ze\($\|\W\)" conceal. Unfortunately the beavior remains the same. Sep 7 at 14:19
  • 1
    @Friedrich I have removed the 2nd question. Sep 7 at 14:23
  • 3
    I don’t believe the syntax matches can overlap.
    – D. Ben Knoble
    Sep 10 at 22:40
  • @D. Ben Knoble: I am aware of three matches, the entire italics region and the leading and trailing asterisk. I see no way to avoid the overlap of the asterisks with the entire italics region for the intended purpose. Your hint led me to temporarily remove the "markdownItalicAsteriskStart" match and, indeed, now "markdownItalicAsteriskEnd" with \zs suddenly does something (although it does not cross newlines). Thanks for the pointer, there is some conflict/interaction there, although I have no idea what to do about it. Sep 12 at 15:03

0

Your Answer

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