runtime(java): Provide support for syntax preview features

Introduce a new API variable "g:java_syntax_previews" whose
value must be a list of syntax preview feature numbers.

Enumerate the currently supported numbers in a table at the
end of the documentation entry for "ft-java-syntax".

Also, disable the recognition of String Templates.  Despite
the withdrawal of this preview feature in its proposed form
from the upcoming JDK 23 release and the fact that the JDK
22 release is coming to EOL this September, an earlier
iteration of this preview feature was included in JDK 21
(LTS) whose EOL is projected to fall due in late 2028 and,
therefore, retain the current implementation.

Define "g:java_syntax_previews" and include number 430 in
its list to enable the recognition of String Templates:
------------------------------------------------------------
	let g:java_syntax_previews = [430]
------------------------------------------------------------

References:
https://openjdk.org/jeps/430 (Preview)
https://openjdk.org/jeps/459 (Second Preview)
https://openjdk.org/jeps/465 (Third Preview)
https://mail.openjdk.org/pipermail/amber-spec-experts/2024-April/004106.html

closes: #15579

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 51ef839..8aa053d 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 Aug 22
+" Last Change:		2024 Aug 26
 
 " Please check :help java.vim for comments on some of the options available.
 
@@ -30,6 +30,10 @@
   return a:y
 endfunction
 
+function! s:ff.IsRequestedPreviewFeature(n) abort
+  return exists("g:java_syntax_previews") && index(g:java_syntax_previews, a:n) + 1
+endfunction
+
 if !exists("*s:ReportOnce")
   function s:ReportOnce(message) abort
     echomsg 'syntax/java.vim: ' . a:message
@@ -367,9 +371,14 @@
 syn region  javaString		start=+"+ end=+"+ end=+$+ contains=javaSpecialChar,javaSpecialError,@Spell
 syn region  javaString		start=+"""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaSpecialChar,javaSpecialError,javaTextBlockError,@Spell
 syn match   javaTextBlockError	+"""\s*"""+
-syn region  javaStrTemplEmbExp	contained matchgroup=javaStrTempl start="\\{" end="}" contains=TOP
-exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,@Spell'
-exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,javaTextBlockError,@Spell'
+
+if s:ff.IsRequestedPreviewFeature(430)
+  syn region javaStrTemplEmbExp	contained matchgroup=javaStrTempl start="\\{" end="}" contains=TOP
+  exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,@Spell'
+  exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,javaTextBlockError,@Spell'
+  hi def link javaStrTempl	Macro
+endif
+
 syn match   javaCharacter	"'[^']*'" contains=javaSpecialChar,javaSpecialCharError
 syn match   javaCharacter	"'\\''" contains=javaSpecialChar
 syn match   javaCharacter	"'[^\\]'"
@@ -441,11 +450,16 @@
   syn match   javaDebugSpecial		contained "\\\%(u\x\x\x\x\|[0-3]\o\o\|\o\o\=\|[bstnfr"'\\]\)"
   syn region  javaDebugString		contained start=+"+ end=+"+ contains=javaDebugSpecial
   syn region  javaDebugString		contained start=+"""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaDebugSpecial,javaDebugTextBlockError
-  " The highlight groups of java{StrTempl,Debug{,Paren,StrTempl}}\,
-  " share one colour by default. Do not conflate unrelated parens.
-  syn region  javaDebugStrTemplEmbExp	contained matchgroup=javaDebugStrTempl start="\\{" end="}" contains=javaComment,javaLineComment,javaDebug\%(Paren\)\@!.*
-  exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaDebugStrTemplEmbExp,javaDebugSpecial'
-  exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaDebugStrTemplEmbExp,javaDebugSpecial,javaDebugTextBlockError'
+
+  if s:ff.IsRequestedPreviewFeature(430)
+    " The highlight groups of java{StrTempl,Debug{,Paren,StrTempl}}\,
+    " share one colour by default. Do not conflate unrelated parens.
+    syn region javaDebugStrTemplEmbExp	contained matchgroup=javaDebugStrTempl start="\\{" end="}" contains=javaComment,javaLineComment,javaDebug\%(Paren\)\@!.*
+    exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaDebugStrTemplEmbExp,javaDebugSpecial'
+    exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaDebugStrTemplEmbExp,javaDebugSpecial,javaDebugTextBlockError'
+    hi def link javaDebugStrTempl	Macro
+  endif
+
   syn match   javaDebugTextBlockError	contained +"""\s*"""+
   syn match   javaDebugCharacter	contained "'[^\\]'"
   syn match   javaDebugSpecialCharacter contained "'\\.'"
@@ -471,7 +485,6 @@
 
   hi def link javaDebug			Debug
   hi def link javaDebugString		DebugString
-  hi def link javaDebugStrTempl		Macro
   hi def link javaDebugTextBlockError	Error
   hi def link javaDebugType		DebugType
   hi def link javaDebugBoolean		DebugBoolean
@@ -580,7 +593,6 @@
 hi def link javaSpecialError		Error
 hi def link javaSpecialCharError	Error
 hi def link javaString			String
-hi def link javaStrTempl		Macro
 hi def link javaCharacter		Character
 hi def link javaSpecialChar		SpecialChar
 hi def link javaNumber			Number
diff --git a/runtime/syntax/testdir/dumps/java_previews_430_00.dump b/runtime/syntax/testdir/dumps/java_previews_430_00.dump
new file mode 100644
index 0000000..199bac0
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/java_previews_430_00.dump
@@ -0,0 +1,20 @@
+>/+0#0000e05#ffffff0@1| |V|I|M|_|T|E|S|T|_|S|E|T|U|P| |l|e|t| |g|:|j|a|v|a|_|s|y|n|t|a|x|_|p|r|e|v|i|e|w|s| |=| |[|4|3|0|]| +0#0000000&@22
+@75
+@75
+@75
+|c+0#00e0003&|l|a|s@1| +0#0000000&|S|t|r|i|n|g|T|e|m|p|l|a|t|e|T|e|s|t|s| @2|/+0#0000e05&@1| |J|D|K| |2|1|+| |(|-@1|e|n|a|b|l|e|-|p|r|e|v|i|e|w| |-@1|r|e|l|e|a|s|e| |2|1|)|.| +0#0000000&@3
+|{| @73
+@4|s+0#00e0003&|t|a|t|i|c| +0#0000000&|{| @62
+@8|S|y|s|t|e|m|.|o|u|t|.|p|r|i|n|t|l|n|(|S|T|R|.|"@2| @40
+| +0#e000e06&@7|"| +0#0000000&@65
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&| +0#0000000&@57
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@40
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&|"| +0#0000000&@39
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|\|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@26
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@29
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"@1| +0#0000000&@43
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"@1|\|"|"+0#0000000&@2|)|;| @36
+@75
+@8|S|t|r|i|n|g| |w|o@1|f| |=| |"+0#e000002&|W|o@1|f|"|,+0#0000000&| |d|o|g| |=| |"+0#e000002&|d|o|g|"|,+0#0000000&| |f|o|x| |=| |"+0#e000002&|f|o|x|"|;+0#0000000&| @19
+@75
+@57|1|,|1| @10|T|o|p| 
diff --git a/runtime/syntax/testdir/dumps/java_string_03.dump b/runtime/syntax/testdir/dumps/java_previews_430_01.dump
similarity index 83%
rename from runtime/syntax/testdir/dumps/java_string_03.dump
rename to runtime/syntax/testdir/dumps/java_previews_430_01.dump
index 9e88372..edc9697 100644
--- a/runtime/syntax/testdir/dumps/java_string_03.dump
+++ b/runtime/syntax/testdir/dumps/java_previews_430_01.dump
@@ -1,14 +1,14 @@
 | +0#e000e06#ffffff0@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@29
 | +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"@1| +0#0000000&@43
-| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"@1|\|"|"+0#0000000&@2|)|;| @5|/+0#0000e05&@1| |J|D|K| |2|1|+|.| +0#0000000&@19
+| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"@1|\|"|"+0#0000000&@2|)|;| @36
 @75
 @8|S|t|r|i|n|g| |w|o@1|f| |=| |"+0#e000002&|W|o@1|f|"|,+0#0000000&| |d|o|g| |=| |"+0#e000002&|d|o|g|"|,+0#0000000&| |f|o|x| |=| |"+0#e000002&|f|o|x|"|;+0#0000000&| @19
 > @74
-@8|S|t|r|i|n|g| |s|6| |=| |S|T|R| @51
+@8|S|t|r|i|n|g| |s|1| |=| |S|T|R| @51
 @12|.|"+0#e000e06&|A| |q|u|i|c|k| |b|r|o|w|n| |\|{|f+0#0000000&|o|x|}+0#e000e06&| |j|u|m|p|s| |o|v|e|r| |t|h|e| |l|a|z|y| |\|{|d+0#0000000&|o|g|}+0#e000e06&|"|;+0#0000000&| @11
-@8|S|t|r|i|n|g| |s|7| |=| |S|T|R|.|p|r|o|c|e|s@1|(|S|t|r|i|n|g|T|e|m|p|l|a|t|e|.|R|A|W| @24
+@8|S|t|r|i|n|g| |s|2| |=| |S|T|R|.|p|r|o|c|e|s@1|(|S|t|r|i|n|g|T|e|m|p|l|a|t|e|.|R|A|W| @24
 @12|.|"+0#e000e06&|\|"|\|{|w+0#0000000&|o@1|f|}+0#e000e06&|\|s|!|\|"@1|)+0#0000000&|;| @43
-@8|S|t|r|i|n|g| |s|8| |=| |S|T|R|.|"@2| @47
+@8|S|t|r|i|n|g| |s|3| |=| |S|T|R|.|"@2| @47
 | +0#e000e06&@11|A|\|s|\| +0#0000000&@58
 | +0#e000e06&@11|q|u|i|c|k| |\| +0#0000000&@55
 | +0#e000e06&@11|b|r|o|w|n|\|s|\| +0#0000000&@54
@@ -17,4 +17,4 @@
 | +0#e000e06&@11|o|v|e|r| |\| +0#0000000&@56
 | +0#e000e06&@11|t|h|e|\|s|\| +0#0000000&@56
 | +0#e000e06&@11|l|a|z|y| |\| +0#0000000&@56
-@57|5@1|,|0|-|1| @7|5|7|%| 
+@57|1|9|,|0|-|1| @7|2|6|%| 
diff --git a/runtime/syntax/testdir/dumps/java_string_04.dump b/runtime/syntax/testdir/dumps/java_previews_430_02.dump
similarity index 80%
rename from runtime/syntax/testdir/dumps/java_string_04.dump
rename to runtime/syntax/testdir/dumps/java_previews_430_02.dump
index 4336a92..fe1e951 100644
--- a/runtime/syntax/testdir/dumps/java_string_04.dump
+++ b/runtime/syntax/testdir/dumps/java_previews_430_02.dump
@@ -1,20 +1,20 @@
 | +0#e000e06#ffffff0@11|l|a|z|y| |\| +0#0000000&@56
 | +0#e000e06&@11|\|{|d+0#0000000&|o|g|}+0#e000e06&|"+0#0000000&@2|;| @52
-@8|S|t|r|i|n|g| |s|9| |=| |S|T|R|.|p|r|o|c|e|s@1|(|S|t|r|i|n|g|T|e|m|p|l|a|t|e|.|R|A|W| @24
+@8|S|t|r|i|n|g| |s|4| |=| |S|T|R|.|p|r|o|c|e|s@1|(|S|t|r|i|n|g|T|e|m|p|l|a|t|e|.|R|A|W| @24
 @12|.| @61
 @12|"@2| @59
 | +0#e000e06&@11>"|\|{|w+0#0000000&|o@1|f|}+0#e000e06&|\|s|!|\|"|"+0#0000000&@2|)|;| @44
-@8|S|t|r|i|n|g| |s|1|0| |=| |j|a|v|a|.|u|t|i|l|.|F|o|r|m|a|t|P|r|o|c|e|s@1|o|r|.|F|M|T| @24
+@8|S|t|r|i|n|g| |s|5| |=| |j|a|v|a|.|u|t|i|l|.|F|o|r|m|a|t|P|r|o|c|e|s@1|o|r|.|F|M|T| @25
 @12|.| |"+0#e000e06&|%|-|1|4|s|\|{|"+0#e000002&|A|\+0#e000e06&|s|"+0#e000002&| +0#0000000&|+| |S|T|R| |.| |"+0#e000e06&|q|u|i|c|k|"| +0#0000000&|+| |"+0#e000002&|b|r|o|w|n|"|}+0#e000e06&|%|s|\|{|f+0#0000000&|o|x|}+0#e000e06&| |"| +0#0000000&@10
 @12|+| |j|a|v|a|.|u|t|i|l|.|F|o|r|m|a|t|P|r|o|c|e|s@1|o|r|.|F|M|T| @31
 @12|.| |"+0#e000e06&|%|-|2|0|s|\|{|"+0#e000002&|j|u|m|p|s|\+0#e000e06&|s|o+0#e000002&|v|e|r| |t|h|e|\+0#e000e06&|s|"+0#e000002&| +0#0000000&@33
 @20|+| |S|T|R| |.| |"+0#e000e06&|l|a|z|y|"|}|%|s|\|{|d+0#0000000&|o|g|}+0#e000e06&|"|;+0#0000000&| @29
-@8|S|t|r|i|n|g| |s|1@1| |=| |S|T|R|.|"@2| @46
+@8|S|t|r|i|n|g| |s|6| |=| |S|T|R|.|"@2| @47
 | +0#e000e06&@11|\|"|\|{| +0#0000000&@11|/+0#0000e05&@1| |A| |n|e|s|t|e|d| |c|o|m@1|e|n|t|.| +0#0000000&@26
 @8|(|n+0#af5f00255&|e|w| +0#0000000&|j|a|v|a|.|u|t|i|l|.|f|u|n|c|t|i|o|n|.|F|u|n|c|t|i|o|n|<|S|t|r|i|n|g|,| |S|t|r|i|n|g|>|(|)| |{| @14
 @12|p+0#00e0003&|u|b|l|i|c| +0#0000000&|S|t|r|i|n|g| |a|p@1|l|y|(|S|t|r|i|n|g| |b|a|y|)| |{| |r+0#af5f00255&|e|t|u|r|n| +0#0000000&|b|a|y|;| |}|;| @14
 @8|}|)|.|a|p@1|l|y|(|w|o@1|f|)| @52
 @12|}+0#e000e06&|\|s|!|\|"|"+0#0000000&@2|;| @52
-@8|S|t|r|i|n|g| |s|1|2| |=| |j|a|v|a|.|u|t|i|l|.|F|o|r|m|a|t|P|r|o|c|e|s@1|o|r|.|F|M|T| @24
+@8|S|t|r|i|n|g| |s|7| |=| |j|a|v|a|.|u|t|i|l|.|F|o|r|m|a|t|P|r|o|c|e|s@1|o|r|.|F|M|T| @25
 @12|.|"@2| @58
-@57|7|3|,|4|-|1|3| @6|7|8|%| 
+@57|3|7|,|4|-|1|3| @6|6|3|%| 
diff --git a/runtime/syntax/testdir/dumps/java_string_05.dump b/runtime/syntax/testdir/dumps/java_previews_430_03.dump
similarity index 93%
rename from runtime/syntax/testdir/dumps/java_string_05.dump
rename to runtime/syntax/testdir/dumps/java_previews_430_03.dump
index 47804a9..df2afa2 100644
--- a/runtime/syntax/testdir/dumps/java_string_05.dump
+++ b/runtime/syntax/testdir/dumps/java_previews_430_03.dump
@@ -10,11 +10,11 @@
 | +0#e000e06&@15|t|h|e|\|s|\| +0#0000000&@52
 | +0#e000e06&@15|\|{| +0#0000000&|"+0#e000002&|l|a|z|y|"| +0#0000000&|}+0#e000e06&| |"+0#0000000&@2|}+0#e000e06&|\| +0#0000000&@41
 | +0#e000e06&@11|%|s|\|{| +0#0000000&|d|o|g| |}+0#e000e06&|"+0#0000000&@2|;| @48
-@8|S|t|r|i|n|g| |s|1|3| |=| |S|T|R| @50
+@8|S|t|r|i|n|g| |s|8| |=| |S|T|R| @51
 @12|.|"+0#e000e06&|\|"|\|{| +0#0000000&@9|/+0#0000e05&|*| |A| |n|e|s|t|e|d| |c|o|m@1|e|n|t|.| |*|/| +0#0000000&@23
 @8|(@1|j|a|v|a|.|u|t|i|l|.|f|u|n|c|t|i|o|n|.|F|u|n|c|t|i|o|n|<|S|t|r|i|n|g|,| |S|t|r|i|n|g|>|)| |b|a|y| |-|>| |b|a|y|)| @8
 @28|.|a|p@1|l|y|(|w|o@1|f|)| @34
 @12|}+0#e000e06&|\|s|!|\|"@1|;+0#0000000&| @54
 @4|}| @69
 |}| @73
-@57|9|1|,|4|-|1|3| @6|B|o|t| 
+@57|5@1|,|4|-|1|3| @6|B|o|t| 
diff --git a/runtime/syntax/testdir/dumps/java_string_00.dump b/runtime/syntax/testdir/dumps/java_string_00.dump
index 0d2f148..b973226 100644
--- a/runtime/syntax/testdir/dumps/java_string_00.dump
+++ b/runtime/syntax/testdir/dumps/java_string_00.dump
@@ -1,4 +1,4 @@
->c+0#00e0003#ffffff0|l|a|s@1| +0#0000000&|S|t|r|i|n|g|T|e|s|t|s| @2|/+0#0000e05&@1| |J|D|K| |2|1|+| |(|-@1|e|n|a|b|l|e|-|p|r|e|v|i|e|w| |-@1|r|e|l|e|a|s|e| |2|1|)|.| +0#0000000&@11
+>c+0#00e0003#ffffff0|l|a|s@1| +0#0000000&|S|t|r|i|n|g|T|e|s|t|s| @57
 |{| @73
 @4|s+0#00e0003&|t|a|t|i|c| +0#0000000&|{| @62
 @8|S|t|r|i|n|g| |s|1| |=| |"+0#e000002&|A| |q|u|i|c|k| |b|r|o|w|n| |f|o|x| |j|u|m|p|s| |o|v|e|r| |t|h|e| |l|a|z|y| |d|o|g|"|;+0#0000000&| @10
diff --git a/runtime/syntax/testdir/dumps/java_string_01.dump b/runtime/syntax/testdir/dumps/java_string_01.dump
index 84b6494..d703561 100644
--- a/runtime/syntax/testdir/dumps/java_string_01.dump
+++ b/runtime/syntax/testdir/dumps/java_string_01.dump
@@ -17,4 +17,4 @@
 @8|/+0#0000e05&@1| |T|h|e|r|e| |a|r|e| |S|P|A|C|E|,| |F@1|,| |H|T|,| |C|R|,| |a|n|d| |L|F| |a|f|t|e|r| |"@2|.| +0#0000000&@17
 @8|S|t|r|i|n|g| |e|m|p|t|y| |=| |"@2| |^+0#0000e05&|L| +0#0000000&@2|^+0#0000e05&|M| +0#0000000&@40
 | +0#e000002&@11|"+0#0000000&@2|;| @58
-@57|1|9|,|3|-|9| @7|1|5|%| 
+@57|1|9|,|3|-|9| @7|5|2|%| 
diff --git a/runtime/syntax/testdir/dumps/java_string_02.dump b/runtime/syntax/testdir/dumps/java_string_02.dump
index ef6549f..e0b0ae0 100644
--- a/runtime/syntax/testdir/dumps/java_string_02.dump
+++ b/runtime/syntax/testdir/dumps/java_string_02.dump
@@ -9,12 +9,12 @@
 | +0#e000002&@7|"@1|\+0#e000e06&|"|"+0#e000002&@1|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1| +0#0000000&@48
 | +0#e000002&@7|"@1|\+0#e000e06&|"|"+0#e000002&@1|\+0#e000e06&|"|"+0#e000002&| +0#0000000&@57
 | +0#e000002&@7|"@1|\+0#e000e06&|"|"+0#e000002&@1|\+0#e000e06&|"|"+0#e000002&|\+0#e000e06&|"|"+0#0000000&@2|)|;| @50
-@75
-@8|S|y|s|t|e|m|.|o|u|t|.|p|r|i|n|t|l|n|(|S|T|R|.|"@2| @40
-| +0#e000e06&@7|"| +0#0000000&@65
-| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&| +0#0000000&@57
-| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@40
-| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&|"| +0#0000000&@39
-| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|\|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@26
-| +0#e000e06&@7|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|"|\|{|"+0#e000002&|\+0#e000e06&|"|\|"|"+0#e000002&|}+0#e000e06&|\|{|"+0#e000002&|\+0#e000e06&|u|0@1|5|c|\|u|0@1|2@1|"+0#e000002&|}+0#e000e06&| +0#0000000&@29
-@57|3|7|,|3|-|9| @7|3|6|%| 
+@4|}| @69
+|}| @73
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|3|7|,|3|-|9| @7|B|o|t| 
diff --git a/runtime/syntax/testdir/input/java_previews_430.java b/runtime/syntax/testdir/input/java_previews_430.java
new file mode 100644
index 0000000..15d8ba2
--- /dev/null
+++ b/runtime/syntax/testdir/input/java_previews_430.java
@@ -0,0 +1,68 @@
+// VIM_TEST_SETUP let g:java_syntax_previews = [430]
+
+
+
+class StringTemplateTests	// JDK 21+ (--enable-preview --release 21).
+{
+	static {
+		System.out.println(STR."""
+		"
+		\{"\"\""}
+		\{"\"\""}\{"\u005c\u0022"}
+		\{"\"\""}\{"\u005c\u0022"}"
+		\{"\"\""}\"\{"\u005c\u0022\u005c\u0022"}
+		\{"\"\""}\"\{"\"\""}\{"\u005c\u0022"}
+		\{"\"\""}\"\{"\"\""}\""
+		\{"\"\""}\"\{"\"\""}\""\"""");
+
+		String woof = "Woof", dog = "dog", fox = "fox";
+
+		String s1 = STR
+			."A quick brown \{fox} jumps over the lazy \{dog}";
+		String s2 = STR.process(StringTemplate.RAW
+			."\"\{woof}\s!\"");
+		String s3 = STR."""
+			A\s\
+			quick \
+			brown\s\
+			\{fox} \
+			jumps\s\
+			over \
+			the\s\
+			lazy \
+			\{dog}""";
+		String s4 = STR.process(StringTemplate.RAW
+			.
+			"""
+			"\{woof}\s!\"""");
+		String s5 = java.util.FormatProcessor.FMT
+			. "%-14s\{"A\s" + STR . "quick" + "brown"}%s\{fox} "
+			+ java.util.FormatProcessor.FMT
+			. "%-20s\{"jumps\sover the\s"
+					+ STR . "lazy"}%s\{dog}";
+		String s6 = STR."""
+			\"\{			// A nested comment.
+		(new java.util.function.Function<String, String>() {
+			public String apply(String bay) { return bay; };
+		}).apply(woof)
+			}\s!\"""";
+		String s7 = java.util.FormatProcessor.FMT
+			."""
+			%-14s\{STR."""
+				A\s\
+				\{ "quick" } \
+				brown"""}\
+			%s\{ fox } \
+			%-20s\{STR."""
+				jumps\s\
+				over \
+				the\s\
+				\{ "lazy" } """}\
+			%s\{ dog }""";
+		String s8 = STR
+			."\"\{			/* A nested comment. */
+		((java.util.function.Function<String, String>) bay -> bay)
+							.apply(woof)
+			}\s!\"";
+	}
+}
diff --git a/runtime/syntax/testdir/input/java_string.java b/runtime/syntax/testdir/input/java_string.java
index 43a7a05..51c30b9 100644
--- a/runtime/syntax/testdir/input/java_string.java
+++ b/runtime/syntax/testdir/input/java_string.java
@@ -1,4 +1,4 @@
-class StringTests	// JDK 21+ (--enable-preview --release 21).
+class StringTests
 {
 	static {
 		String s1 = "A quick brown fox jumps over the lazy dog";
@@ -40,65 +40,5 @@
 		""\"""\u005c\u0022
 		""\"""\""
 		""\"""\""\"""");
-
-		System.out.println(STR."""
-		"
-		\{"\"\""}
-		\{"\"\""}\{"\u005c\u0022"}
-		\{"\"\""}\{"\u005c\u0022"}"
-		\{"\"\""}\"\{"\u005c\u0022\u005c\u0022"}
-		\{"\"\""}\"\{"\"\""}\{"\u005c\u0022"}
-		\{"\"\""}\"\{"\"\""}\""
-		\{"\"\""}\"\{"\"\""}\""\"""");		// JDK 21+.
-
-		String woof = "Woof", dog = "dog", fox = "fox";
-
-		String s6 = STR
-			."A quick brown \{fox} jumps over the lazy \{dog}";
-		String s7 = STR.process(StringTemplate.RAW
-			."\"\{woof}\s!\"");
-		String s8 = STR."""
-			A\s\
-			quick \
-			brown\s\
-			\{fox} \
-			jumps\s\
-			over \
-			the\s\
-			lazy \
-			\{dog}""";
-		String s9 = STR.process(StringTemplate.RAW
-			.
-			"""
-			"\{woof}\s!\"""");
-		String s10 = java.util.FormatProcessor.FMT
-			. "%-14s\{"A\s" + STR . "quick" + "brown"}%s\{fox} "
-			+ java.util.FormatProcessor.FMT
-			. "%-20s\{"jumps\sover the\s"
-					+ STR . "lazy"}%s\{dog}";
-		String s11 = STR."""
-			\"\{			// A nested comment.
-		(new java.util.function.Function<String, String>() {
-			public String apply(String bay) { return bay; };
-		}).apply(woof)
-			}\s!\"""";
-		String s12 = java.util.FormatProcessor.FMT
-			."""
-			%-14s\{STR."""
-				A\s\
-				\{ "quick" } \
-				brown"""}\
-			%s\{ fox } \
-			%-20s\{STR."""
-				jumps\s\
-				over \
-				the\s\
-				\{ "lazy" } """}\
-			%s\{ dog }""";
-		String s13 = STR
-			."\"\{			/* A nested comment. */
-		((java.util.function.Function<String, String>) bay -> bay)
-							.apply(woof)
-			}\s!\"";
 	}
 }