runtime(java): Recognise the CommonMark form (///) of Javadoc comments
Complement "g:java_ignore_javadoc" with "g:java_ignore_html"
and "g:java_ignore_markdown" to allow selectively disabling
the recognition of HTML and CommonMark respectively.
(Note that this is not a preview feature.)
======================== LIMITATION ========================
According to the syntactical details of JEP 467:
> Any leading whitespace and the three initial / characters
> are removed from each line.
>
> The lines are shifted left, by removing leading whitespace
> characters, until the non-blank line with the least
> leading whitespace has no remaining leading whitespace.
>
> Additional leading whitespace and any trailing whitespace
> in each line is preserved, because it may be significant.
the following example:
------------------------------------------------------------
/// A summary sentence.
/// A list:
/// - Item A.
/// - Item B.
///
/// Some code span, starting here `
/// 1 + 2 ` and ending at the previous \`.
------------------------------------------------------------
should be interpreted as if it were written thus:
------------------------------------------------------------
///A summary sentence.
/// A list:
/// - Item A.
/// - Item B.
///
/// Some code span, starting here `
/// 1 + 2 ` and ending at the previous \`.
------------------------------------------------------------
Since automatic line rewriting will not be pursued, parts of
such comments having significant whitespace may be ‘wrongly’
highlighted. For convenience, a &fex function is defined to
‘correct’ it: g:javaformat#RemoveCommonMarkdownWhitespace()
(:help ft-java-plugin).
References:
https://openjdk.org/jeps/467
https://spec.commonmark.org/0.31.2
closes: #15740
Co-authored-by: Tim Pope <code@tpope.net>
Signed-off-by: Aliaksei Budavei <0x000c70@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/runtime/syntax/java.vim b/runtime/syntax/java.vim
index 800faa4..737219a 100644
--- a/runtime/syntax/java.vim
+++ b/runtime/syntax/java.vim
@@ -3,7 +3,7 @@
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
" Repository: https://github.com/zzzyxwvut/java-vim.git
-" Last Change: 2024 Sep 19
+" Last Change: 2024 Sep 28
" Please check :help java.vim for comments on some of the options available.
@@ -156,6 +156,10 @@
let [s:ff.PeekTo, s:ff.PeekFrom, s:ff.GroupArgs] = repeat([s:ff.RightConstant], 3)
endif
+let s:with_html = !exists("g:java_ignore_html")
+let s:with_markdown = !exists("g:java_ignore_markdown")
+lockvar s:with_html s:with_markdown
+
" Java module declarations (JLS-17, §7.7).
"
" Note that a "module-info" file will be recognised with an arbitrary
@@ -172,7 +176,7 @@
hi def link javaModuleStmt Statement
hi def link javaModuleExternal Include
- if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
+ if !exists("g:java_ignore_javadoc") && (s:with_html || s:with_markdown) && g:main_syntax != 'jsp'
syn match javaDocProvidesTag contained "@provides\_s\+\S\+" contains=javaDocParam
syn match javaDocUsesTag contained "@uses\_s\+\S\+" contains=javaDocParam
hi def link javaDocProvidesTag Special
@@ -335,18 +339,52 @@
exec 'syn region javaCommentMarkupTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(re\%(gex\|gion\|placement\)\|substring\|t\%(arget\|ype\)\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.-]\|\k\)\+\)/ nextgroup=javaCommentMarkupTagAttr,javaSpaceError skipwhite oneline'
syn match javaCommentError contained "/\*"me=e-1 display
-if !exists("g:java_ignore_javadoc") && g:main_syntax != 'jsp'
- " The overridable "html*" default links must be defined _before_ the
- " inclusion of the same default links from "html.vim".
- hi def link htmlComment Special
- hi def link htmlCommentPart Special
- hi def link htmlArg Type
- hi def link htmlString String
+if !exists("g:java_ignore_javadoc") && (s:with_html || s:with_markdown) && g:main_syntax != 'jsp'
+ " The overridable "html*" and "markdown*" default links must be
+ " defined _before_ the inclusion of the same default links from
+ " "html.vim" and "markdown.vim".
+ if s:with_html || s:with_markdown
+ hi def link htmlComment Special
+ hi def link htmlCommentPart Special
+ hi def link htmlArg Type
+ hi def link htmlString String
+ endif
+
+ if s:with_markdown
+ hi def link markdownCode Special
+ hi def link markdownCodeBlock Special
+ hi def link markdownCodeDelimiter Special
+ hi def link markdownLinkDelimiter Comment
+ endif
+
syntax case ignore
+ " Note that javaDocSeeTag is valid in HTML and Markdown.
+ let s:ff.WithMarkdown = s:ff.RightConstant
+
" Include HTML syntax coloring for Javadoc comments.
- syntax include @javaHtml syntax/html.vim
- unlet b:current_syntax
+ if s:with_html
+ syntax include @javaHtml syntax/html.vim
+ unlet b:current_syntax
+ endif
+
+ " Include Markdown syntax coloring (v7.2.437) for Javadoc comments.
+ if s:with_markdown
+ try
+ syntax include @javaMarkdown syntax/markdown.vim
+ unlet b:current_syntax
+ let s:ff.WithMarkdown = s:ff.LeftConstant
+ catch /\<E48[45]:/
+ call s:ReportOnce(v:exception)
+ unlockvar s:with_markdown
+ let s:with_markdown = 0
+ lockvar s:with_markdown
+ hi clear markdownCode
+ hi clear markdownCodeBlock
+ hi clear markdownCodeDelimiter
+ hi clear markdownLinkDelimiter
+ endtry
+ endif
" HTML enables spell checking for all text that is not in a syntax
" item (:syntax spell toplevel); instead, limit spell checking to
@@ -357,10 +395,71 @@
call s:ReportOnce(v:exception)
endtry
- syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,@javaDocTags,javaTodo,javaCommentError,javaSpaceError,@Spell fold
- exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags'
- syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
- syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@summary\>\)\@=" matchgroup=javaCommentTitle end="}" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
+ if s:with_markdown
+ syn region javaMarkdownComment start="///" skip="^\s*///.*$" end="^" keepend contains=javaMarkdownCommentTitle,javaMarkdownShortcutLink,@javaMarkdown,@javaDocTags,javaTodo,@Spell nextgroup=javaMarkdownCommentTitle fold
+ syn match javaMarkdownCommentMask contained "^\s*///"
+ exec 'syn region javaMarkdownCommentTitle contained matchgroup=javaMarkdownComment start="\%(///.*\r\=\n\s*\)\@' . s:ff.Peek('80', '') . '<!///" matchgroup=javaMarkdownCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\n\%(\s*///\s*$\)\@=" end="\%(^\s*///\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 contains=javaMarkdownShortcutLink,@javaMarkdown,javaMarkdownCommentMask,javaTodo,@Spell,@javaDocTags'
+ exec 'syn region javaMarkdownCommentTitle contained matchgroup=javaMarkdownComment start="\%(///.*\r\=\n\s*\)\@' . s:ff.Peek('80', '') . '<!///\s*\%({@return\>\)\@=" matchgroup=javaMarkdownCommentTitle end="}\%(\s*\.*\)*" contains=javaMarkdownShortcutLink,@javaMarkdown,javaMarkdownCommentMask,javaTodo,@Spell,@javaDocTags,javaTitleSkipBlock'
+ exec 'syn region javaMarkdownCommentTitle contained matchgroup=javaMarkdownComment start="\%(///.*\r\=\n\s*\)\@' . s:ff.Peek('80', '') . '<!///\s*\%({@summary\>\)\@=" matchgroup=javaMarkdownCommentTitle end="}" contains=javaMarkdownShortcutLink,@javaMarkdown,javaMarkdownCommentMask,javaTodo,@Spell,@javaDocTags,javaTitleSkipBlock'
+
+ syn clear markdownId markdownLineStart markdownH1 markdownH2 markdownHeadingRule markdownRule markdownCode markdownCodeBlock markdownIdDeclaration
+ " REDEFINE THE MARKDOWN ITEMS ANCHORED WITH "^", OBSERVING THE
+ " DEFINITION ORDER.
+ syn match markdownLineStart contained "^\s*///\s*[<@]\@!" contains=@markdownBlock,javaMarkdownCommentTitle,javaMarkdownCommentMask nextgroup=@markdownBlock,htmlSpecialChar
+ " See https://spec.commonmark.org/0.31.2/#setext-headings.
+ syn match markdownH1 contained "^\s*/// \{,3}.\+\r\=\n\s*/// \{,3}=\+\s*$" contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink,javaMarkdownCommentMask
+ syn match markdownH2 contained "^\s*/// \{,3}.\+\r\=\n\s*/// \{,3}-\+\s*$" contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink,javaMarkdownCommentMask
+ " See https://spec.commonmark.org/0.31.2/#atx-headings.
+ syn region markdownH1 contained matchgroup=markdownH1Delimiter start=" \{,3}#\s" end="#*\s*$" keepend contains=@markdownInline,markdownAutomaticLink oneline
+ syn region markdownH2 contained matchgroup=markdownH2Delimiter start=" \{,3}##\s" end="#*\s*$" keepend contains=@markdownInline,markdownAutomaticLink oneline
+ syn match markdownHeadingRule contained "^\s*/// \{,3}[=-]\+\s*$" contains=javaMarkdownCommentMask
+ " See https://spec.commonmark.org/0.31.2/#thematic-breaks.
+ syn match markdownRule contained "^\s*/// \{,3}\*\s*\*\%(\s*\*\)\+\s*$" contains=javaMarkdownCommentMask
+ syn match markdownRule contained "^\s*/// \{,3}_\s*_\%(\s*_\)\+\s*$" contains=javaMarkdownCommentMask
+ syn match markdownRule contained "^\s*/// \{,3}-\s*-\%(\s*-\)\+\s*$" contains=javaMarkdownCommentMask
+ " See https://spec.commonmark.org/0.31.2/#indented-code-blocks.
+ syn region markdownCodeBlock contained start="^\s*///\%( \{4,}\|\t\)" end="^\ze\s*///\%(\s*$\| \{,3}\S\)" keepend contains=javaMarkdownCommentMask
+ " See https://spec.commonmark.org/0.31.2/#code-spans.
+ syn region markdownCode contained matchgroup=markdownCodeDelimiter start="\z(`\+\) \=" end=" \=\z1" keepend contains=markdownLineStart,javaMarkdownCommentMask
+ " See https://spec.commonmark.org/0.31.2/#fenced-code-blocks.
+ syn region markdownCodeBlock contained start="^\s*/// \{,3}\z(```\+\)\%(.\{-}[^`]`\)\@!" end="^\s*/// \{,3}\z1`*" keepend contains=javaMarkdownCommentMask
+ syn region markdownCodeBlock contained start="^\s*/// \{,3}\z(\~\~\~\+\)" end="^\s*/// \{,3}\z1\~*" keepend contains=javaMarkdownCommentMask
+ " See https://spec.commonmark.org/0.31.2/#link-reference-definitions.
+ syn region markdownIdDeclaration contained matchgroup=markdownLinkDelimiter start="^\s*/// \{,3\}!\=\[" end="\]:" keepend contains=javaMarkdownCommentMask nextgroup=markdownUrl oneline skipwhite
+ " See https://spec.commonmark.org/0.31.2/#link-label.
+ syn region markdownId contained matchgroup=markdownIdDelimiter start="\[\%([\t ]\]\)\@!" end="\]" contains=javaMarkdownSkipBrackets,javaMarkdownCommentMask
+ " Note that escaped brackets can be unbalanced.
+ syn match javaMarkdownSkipBrackets contained transparent "\\\[\|\\\]"
+ " See https://spec.commonmark.org/0.31.2/#shortcut-reference-link.
+ syn region javaMarkdownShortcutLink contained matchgroup=markdownLinkTextDelimiter start="!\=\[^\@!\%(\_[^][]*\%(\[\_[^][]*\]\_[^][]*\)*]\%([[(]\)\@!\)\@=" end="\]\%([[(]\)\@!" contains=@markdownInline,markdownLineStart,javaMarkdownSkipBrackets,javaMarkdownCommentMask nextgroup=markdownLink,markdownId skipwhite
+
+ for s:name in ['markdownFootnoteDefinition', 'markdownFootnote']
+ if hlexists(s:name)
+ exec 'syn clear ' . s:name
+ endif
+ endfor
+
+ unlet s:name
+
+ " COMBAK: Footnotes are recognised by "markdown.vim", but are not
+ " in CommonMark. See https://pandoc.org/MANUAL.html#footnotes.
+""""syn match markdownFootnoteDefinition contained "^\s*///\s*\[^[^\]]\+\]:" contains=javaMarkdownCommentMask
+
+ hi def link javaMarkdownComment Comment
+ hi def link javaMarkdownCommentMask javaMarkdownComment
+ hi def link javaMarkdownCommentTitle SpecialComment
+ hi def link javaMarkdownShortcutLink htmlLink
+ endif
+
+ if s:with_html
+ syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,@javaDocTags,javaTodo,javaCommentError,javaSpaceError,@Spell fold
+ exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags'
+ syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
+ syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@summary\>\)\@=" matchgroup=javaCommentTitle end="}" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock
+ hi def link javaDocComment Comment
+ hi def link javaCommentTitle SpecialComment
+ endif
+
" The members of javaDocTags are sub-grouped according to the Java
" version of their introduction, and sub-group members in turn are
" arranged in alphabetical order, so that future newer members can
@@ -403,13 +502,29 @@
syn match javaDocSerialFieldTag contained "@serialField\>"
syn match javaDocVersionTag contained "@version\>"
- syn match javaDocSeeTag contained "@see\>" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTagStar skipwhite skipempty
- syn match javaDocSeeTagStar contained "^\s*\*\+\%(\s*{\=@\|/\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3 skipwhite skipempty
+ syn match javaDocSeeTag contained "@see\>\s*" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTag4,javaDocSeeTagStar,javaDocSeeTagSlash skipwhite skipempty
+
+ if s:with_html
+ syn match javaDocSeeTagStar contained "^\s*\*\+\%(\s*{\=@\|/\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTag4 skipwhite skipempty
+ hi def link javaDocSeeTagStar javaDocComment
+ endif
+
+ if s:with_markdown
+ syn match javaDocSeeTagSlash contained "^\s*///\%(\s*{\=@\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTag4 skipwhite skipempty
+ hi def link javaDocSeeTagSlash javaMarkdownComment
+ endif
+
syn match javaDocSeeTag1 contained @"\_[^"]\+"@
syn match javaDocSeeTag2 contained @<a\s\+\_.\{-}</a>@ contains=@javaHtml extend
- syn match javaDocSeeTag3 contained @["< \t]\@!\%(\k\|[/.]\)*\%(##\=\k\+\%((\_[^)]*)\)\=\)\=@ nextgroup=javaDocSeeTag3Label skipwhite skipempty
+ exec 'syn match javaDocSeeTag3 contained @[' . s:ff.WithMarkdown('[', '') . '"< \t]\@!\%(\k\|[/.]\)*\%(##\=\k\+\%((\_[^)]*)\)\=\)\=@ nextgroup=javaDocSeeTag3Label skipwhite skipempty'
syn match javaDocSeeTag3Label contained @\k\%(\k\+\s*\)*$@
+ " COMBAK: No support for type javaDocSeeTag2 in Markdown.
+""if s:with_markdown
+"" syn match javaDocSeeTag4 contained @\[.\+\]\s\=\%(\[.\+\]\|(.\+)\)@ contains=@javaMarkdown extend
+"" hi def link javaDocSeeTag4 Special
+""endif
+
syn region javaCodeSkipBlock contained transparent start="{\%(@code\>\)\@!" end="}" contains=javaCodeSkipBlock,javaDocCodeTag
syn region javaDocCodeTag contained start="{@code\>" end="}" contains=javaDocCodeTag,javaCodeSkipBlock
@@ -418,9 +533,6 @@
syn region javaDocSnippetTag contained start="{@snippet\>" end="}" contains=javaDocSnippetTag,javaSnippetSkipBlock,javaDocSnippetTagAttr,javaCommentMarkupTag
syntax case match
- hi def link javaDocComment Comment
- hi def link javaDocSeeTagStar javaDocComment
- hi def link javaCommentTitle SpecialComment
hi def link javaDocParam Function
hi def link javaDocAuthorTag Special
@@ -729,7 +841,7 @@
let b:spell_options = "contained"
let &cpo = s:cpo_save
-unlet s:ff s:cpo_save
+unlet s:cpo_save s:ff s:with_html s:with_markdown
" See ":help vim9-mix".
if !has("vim9script")
@@ -757,4 +869,4 @@
setlocal foldtext=s:JavaSyntaxFoldTextExpr()
delfunction! g:JavaSyntaxFoldTextExpr
endif
-" vim: sw=2 ts=8 noet sta
+" vim: fdm=syntax sw=2 ts=8 noet sta