summaryrefslogtreecommitdiff
path: root/mnv/runtime/indent/testdir
diff options
context:
space:
mode:
Diffstat (limited to 'mnv/runtime/indent/testdir')
-rw-r--r--mnv/runtime/indent/testdir/README.txt100
-rw-r--r--mnv/runtime/indent/testdir/bash.in22
-rw-r--r--mnv/runtime/indent/testdir/bash.ok22
-rw-r--r--mnv/runtime/indent/testdir/bitbake.in21
-rw-r--r--mnv/runtime/indent/testdir/bitbake.ok21
-rw-r--r--mnv/runtime/indent/testdir/dts.in46
-rw-r--r--mnv/runtime/indent/testdir/dts.ok46
-rw-r--r--mnv/runtime/indent/testdir/html.in78
-rw-r--r--mnv/runtime/indent/testdir/html.ok78
-rw-r--r--mnv/runtime/indent/testdir/krl.in148
-rw-r--r--mnv/runtime/indent/testdir/krl.ok148
-rw-r--r--mnv/runtime/indent/testdir/lua.in19
-rw-r--r--mnv/runtime/indent/testdir/lua.ok19
-rw-r--r--mnv/runtime/indent/testdir/make.in20
-rw-r--r--mnv/runtime/indent/testdir/make.ok20
-rw-r--r--mnv/runtime/indent/testdir/matlab.in89
-rw-r--r--mnv/runtime/indent/testdir/matlab.ok89
-rw-r--r--mnv/runtime/indent/testdir/mnv.in225
-rw-r--r--mnv/runtime/indent/testdir/mnv.ok225
-rw-r--r--mnv/runtime/indent/testdir/mnv9.in795
-rw-r--r--mnv/runtime/indent/testdir/mnv9.ok795
-rw-r--r--mnv/runtime/indent/testdir/python.in96
-rw-r--r--mnv/runtime/indent/testdir/python.ok96
-rw-r--r--mnv/runtime/indent/testdir/rapid.in266
-rw-r--r--mnv/runtime/indent/testdir/rapid.ok266
-rw-r--r--mnv/runtime/indent/testdir/runtest.mnv146
-rw-r--r--mnv/runtime/indent/testdir/rust.in50
-rw-r--r--mnv/runtime/indent/testdir/rust.ok50
-rw-r--r--mnv/runtime/indent/testdir/sshconfig.in53
-rw-r--r--mnv/runtime/indent/testdir/sshconfig.ok53
-rw-r--r--mnv/runtime/indent/testdir/tcl.in19
-rw-r--r--mnv/runtime/indent/testdir/tcl.ok19
-rw-r--r--mnv/runtime/indent/testdir/thrift.in38
-rw-r--r--mnv/runtime/indent/testdir/thrift.ok38
-rw-r--r--mnv/runtime/indent/testdir/tools/tracer.mnv166
-rw-r--r--mnv/runtime/indent/testdir/vb.in176
-rw-r--r--mnv/runtime/indent/testdir/vb.ok176
-rw-r--r--mnv/runtime/indent/testdir/xml.in32
-rw-r--r--mnv/runtime/indent/testdir/xml.ok32
-rw-r--r--mnv/runtime/indent/testdir/yaml.in39
-rw-r--r--mnv/runtime/indent/testdir/yaml.ok39
41 files changed, 4876 insertions, 0 deletions
diff --git a/mnv/runtime/indent/testdir/README.txt b/mnv/runtime/indent/testdir/README.txt
new file mode 100644
index 0000000000..ba82c69a20
--- /dev/null
+++ b/mnv/runtime/indent/testdir/README.txt
@@ -0,0 +1,100 @@
+TESTING INDENT SCRIPTS
+
+We'll use FILETYPE for the filetype name here.
+
+
+FORMAT OF THE FILETYPE.IN FILE
+
+First of all, create a FILETYPE.in file. It should contain:
+
+- A modeline setting the 'filetype' and any other option values.
+ This must work like a comment for FILETYPE. E.g. for mnv:
+ " mnv: set ft=mnv sw=4 :
+
+- At least one block of lines to indent, prefixed with START_INDENT and
+ followed by END_INDENT. These lines must also look like a comment for your
+ FILETYPE. You would normally leave out all indent, so that the effect of
+ the indent command results in adding indent. Example:
+
+ " START_INDENT
+ func Some()
+ let x = 1
+ endfunc
+ " END_INDENT
+
+ If you just want to test normal indenting with default options, you can make
+ this a large number of lines. Just add all kinds of language constructs,
+ nested statements, etc. with valid syntax.
+
+- Optionally, add lines with INDENT_EXE after START_INDENT, followed by a MNV
+ command. This will be executed before indenting the lines. Example:
+
+ " START_INDENT
+ " INDENT_EXE let g:mnv_indent_cont = 6
+ let cmd =
+ \ 'some '
+ \ 'string'
+ " END_INDENT
+
+ When an indent script utilises timed "search*()"es and supports related
+ timeout configuration, consider setting a generous timeout value from
+ INDENT_EXE lines (look at "g:mnv_indent" in "testdir/mnv.in" for details).
+ Note that the command is not undone, you may need to reverse the effect for
+ the next block of lines.
+
+- Alternatively to indenting all the lines between START_INDENT and
+ END_INDENT, use an INDENT_AT line, which specifies a pattern to find the
+ line to indent. Example:
+
+ " START_INDENT
+ " INDENT_AT this-line
+ func Some()
+ let f = x " this-line
+ endfunc
+ " END_INDENT
+
+ Alternatively you can use INDENT_NEXT to indent the line below the matching
+ pattern. Keep in mind that quite often it will indent relative to the
+ matching line:
+
+ " START_INDENT
+ " INDENT_NEXT next-line
+ func Some()
+ " next-line
+ let f = x
+ endfunc
+ " END_INDENT
+
+ Or use INDENT_PREV to indent the line above the matching pattern:
+
+ " START_INDENT
+ " INDENT_PREV prev-line
+ func Some()
+ let f = x
+ " prev-line
+ endfunc
+ " END_INDENT
+
+It's best to keep the whole file valid for FILETYPE, so that syntax
+highlighting works normally, and any indenting that depends on the syntax
+highlighting also works.
+
+
+RUNNING THE TEST
+
+Before running the test, create a FILETYPE.ok file. You can leave it empty at
+first.
+
+Now run "make test" from the parent directory. After MNV has done the
+indenting you will see a FILETYPE.fail file. This contains the actual result
+of indenting, and it's different from the FILETYPE.ok file.
+
+Check the contents of the FILETYPE.fail file. If it is perfectly OK, then
+rename it to overwrite the FILETYPE.ok file. If you now run "make test" again,
+the test will pass and create a FILETYPE.out file, which is identical to the
+FILETYPE.ok file. The FILETYPE.fail file will be deleted.
+
+If you try to run "make test" again you will notice that nothing happens,
+because the FILETYPE.out file already exists. Delete it, or do "make clean",
+so that the text runs again. If you edit the FILETYPE.in file, so that it's
+newer than the FILETYPE.out file, the test will also run.
diff --git a/mnv/runtime/indent/testdir/bash.in b/mnv/runtime/indent/testdir/bash.in
new file mode 100644
index 0000000000..a47da0489d
--- /dev/null
+++ b/mnv/runtime/indent/testdir/bash.in
@@ -0,0 +1,22 @@
+#!/bin/bash
+# mnv: set ft=bash sw=2 noet:
+
+# START_INDENT
+a = 10
+b = 20
+
+function add() {
+c = $((a + b))
+}
+
+function print {
+# do nothing
+}
+
+if [[ $c -ge 15 ]];
+then
+print("ok")
+else
+print("not ok")
+fi
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/bash.ok b/mnv/runtime/indent/testdir/bash.ok
new file mode 100644
index 0000000000..8612b4d996
--- /dev/null
+++ b/mnv/runtime/indent/testdir/bash.ok
@@ -0,0 +1,22 @@
+#!/bin/bash
+# mnv: set ft=bash sw=2 noet:
+
+# START_INDENT
+a = 10
+b = 20
+
+function add() {
+ c = $((a + b))
+}
+
+function print {
+ # do nothing
+}
+
+if [[ $c -ge 15 ]];
+then
+ print("ok")
+else
+ print("not ok")
+fi
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/bitbake.in b/mnv/runtime/indent/testdir/bitbake.in
new file mode 100644
index 0000000000..62d099e2d6
--- /dev/null
+++ b/mnv/runtime/indent/testdir/bitbake.in
@@ -0,0 +1,21 @@
+# mnv: set filetype=bitbake :
+
+# START_INDENT
+# INDENT_EXE let g:pyindent_searchpair_timeout = 64
+# INDENT_EXE runtime autoload/python.mnv
+FOO = " \
+ bar \
+ baz \
+ qux \
+ "
+
+do_configure() {
+oe_conf
+}
+
+python do_task() {
+def foo(x):
+if y:
+print(x)
+}
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/bitbake.ok b/mnv/runtime/indent/testdir/bitbake.ok
new file mode 100644
index 0000000000..43b3aa1739
--- /dev/null
+++ b/mnv/runtime/indent/testdir/bitbake.ok
@@ -0,0 +1,21 @@
+# mnv: set filetype=bitbake :
+
+# START_INDENT
+# INDENT_EXE let g:pyindent_searchpair_timeout = 64
+# INDENT_EXE runtime autoload/python.mnv
+FOO = " \
+ bar \
+ baz \
+ qux \
+"
+
+do_configure() {
+ oe_conf
+}
+
+python do_task() {
+ def foo(x):
+ if y:
+ print(x)
+}
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/dts.in b/mnv/runtime/indent/testdir/dts.in
new file mode 100644
index 0000000000..dc35c0e6bd
--- /dev/null
+++ b/mnv/runtime/indent/testdir/dts.in
@@ -0,0 +1,46 @@
+/* mnv: set ft=dts noet sw=8 : */
+
+/* START_INDENT */
+/dts-v1/;
+#include <dt-bindings/pinctrl/pinctrl-imx6q.h>
+ #include "imx6qdl.dtsi"
+#include "imx6qdl-someboard.dtsi"
+
+ /delete-node/ &{/memory@10000000};
+
+ / {
+compatible = "some,board";
+/delete-node/ memory;
+
+ chosen {
+environment = &{usdhc4/partitions/partition@0};
+};
+}
+
+ &iomuxc {
+pinctrl-names = "default";
+pinctrl-0 = <&pinctrl_hog>;
+
+pinctrl_gpiohog: gpiohoggrp {
+fsl,pins = <
+MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x130b0
+MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x130b0
+>;
+};
+}
+
+&usdhc4 {
+partitions {
+compatible = "fixed-partitions";
+
+partition@0 {
+label = "environment";
+reg = <0x0 0xe0000>;
+};
+};
+};
+
+&{/aliases} {
+usb0 = &usb;
+};
+/* END_INDENT */
diff --git a/mnv/runtime/indent/testdir/dts.ok b/mnv/runtime/indent/testdir/dts.ok
new file mode 100644
index 0000000000..c00dcb4723
--- /dev/null
+++ b/mnv/runtime/indent/testdir/dts.ok
@@ -0,0 +1,46 @@
+/* mnv: set ft=dts noet sw=8 : */
+
+/* START_INDENT */
+/dts-v1/;
+#include <dt-bindings/pinctrl/pinctrl-imx6q.h>
+#include "imx6qdl.dtsi"
+#include "imx6qdl-someboard.dtsi"
+
+/delete-node/ &{/memory@10000000};
+
+/ {
+ compatible = "some,board";
+ /delete-node/ memory;
+
+ chosen {
+ environment = &{usdhc4/partitions/partition@0};
+ };
+}
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hog>;
+
+ pinctrl_gpiohog: gpiohoggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x130b0
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x130b0
+ >;
+ };
+}
+
+&usdhc4 {
+ partitions {
+ compatible = "fixed-partitions";
+
+ partition@0 {
+ label = "environment";
+ reg = <0x0 0xe0000>;
+ };
+ };
+};
+
+&{/aliases} {
+ usb0 = &usb;
+};
+/* END_INDENT */
diff --git a/mnv/runtime/indent/testdir/html.in b/mnv/runtime/indent/testdir/html.in
new file mode 100644
index 0000000000..2033f11c9a
--- /dev/null
+++ b/mnv/runtime/indent/testdir/html.in
@@ -0,0 +1,78 @@
+% mnv: set ft=html sw=4 ts=8 :
+
+
+% START_INDENT
+% INDENT_EXE let b:html_indent_line_limit = 64
+<html>
+ <body>
+<style>
+div#d1 { color: red; }
+div#d2 { color: green; }
+</style>
+ <script>
+ var v1 = "v1";
+var v2 = "v2";
+ </script>
+<div>
+<div>
+text
+</div>
+</div>
+
+<div
+class="foo bar">
+text
+</div>
+
+<div class="foo bar"
+data="something">
+text
+</div>
+
+<div class="foo
+bar">
+text
+</div>
+
+<dl>
+<dd>
+dd text
+</dd>
+<dt>
+dt text
+</dt>
+</dl>
+<div
+class="test"
+style="color: yellow">
+text
+</div>
+
+ </body>
+</html>
+
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let g:html_indent_style1 = "inc"
+% INDENT_EXE let g:html_indent_script1 = "zero"
+% INDENT_EXE let g:html_indent_attribute = 1
+% INDENT_EXE call HtmlIndent_CheckUserSettings()
+<html>
+ <body>
+<style>
+div#d1 { color: red; }
+div#d2 { color: green; }
+</style>
+ <script>
+ var v1 = "v1";
+var v2 = "v2";
+ </script>
+<div
+class="test"
+style="color: yellow">
+text
+</div>
+</body>
+</html>
+% END_INDENT
diff --git a/mnv/runtime/indent/testdir/html.ok b/mnv/runtime/indent/testdir/html.ok
new file mode 100644
index 0000000000..1f70fd62af
--- /dev/null
+++ b/mnv/runtime/indent/testdir/html.ok
@@ -0,0 +1,78 @@
+% mnv: set ft=html sw=4 ts=8 :
+
+
+% START_INDENT
+% INDENT_EXE let b:html_indent_line_limit = 64
+<html>
+ <body>
+ <style>
+div#d1 { color: red; }
+div#d2 { color: green; }
+ </style>
+ <script>
+ var v1 = "v1";
+ var v2 = "v2";
+ </script>
+ <div>
+ <div>
+ text
+ </div>
+ </div>
+
+ <div
+ class="foo bar">
+ text
+ </div>
+
+ <div class="foo bar"
+ data="something">
+ text
+ </div>
+
+ <div class="foo
+ bar">
+ text
+ </div>
+
+ <dl>
+ <dd>
+ dd text
+ </dd>
+ <dt>
+ dt text
+ </dt>
+ </dl>
+ <div
+ class="test"
+ style="color: yellow">
+ text
+ </div>
+
+ </body>
+</html>
+
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let g:html_indent_style1 = "inc"
+% INDENT_EXE let g:html_indent_script1 = "zero"
+% INDENT_EXE let g:html_indent_attribute = 1
+% INDENT_EXE call HtmlIndent_CheckUserSettings()
+<html>
+ <body>
+ <style>
+ div#d1 { color: red; }
+ div#d2 { color: green; }
+ </style>
+ <script>
+var v1 = "v1";
+var v2 = "v2";
+ </script>
+ <div
+ class="test"
+ style="color: yellow">
+ text
+ </div>
+ </body>
+</html>
+% END_INDENT
diff --git a/mnv/runtime/indent/testdir/krl.in b/mnv/runtime/indent/testdir/krl.in
new file mode 100644
index 0000000000..b06d0339c6
--- /dev/null
+++ b/mnv/runtime/indent/testdir/krl.in
@@ -0,0 +1,148 @@
+; mnv: set ft=krl :
+
+; START_INDENT
+
+def One()
+int i
+If i==1 then
+While i>=1
+For i=1 to 5 step 2
+Loop
+i = i+1
+EndLoop
+EndFor
+EndWhile
+Else
+Repeat
+Switch i
+Case 1
+Skip 123
+i = i+1
+EndSkip 123
+Spline with $acc=100, $vel.cp=3
+slin {x 100}
+scirc {x 110, y 110}, {x 120, y 90}
+slin {x 200} c_dis
+Time_Block Start
+slin {x 300} c_dis
+Time_Block Part = 22.2
+slin {y 400} c_dis
+Time_Block Part = 33.3
+Time_Block End = 10
+slin {y 200} c_dis
+Const_Vel Start +100 OnStart
+slin {y 300} c_dis
+slin {x 100}
+Const_Vel End -5.5
+slin {y 200} c_dis
+EndSpline
+Case 2,3
+PTP_Spline with $acc=100, $vel.ptp=100
+sptp {a1 0} c_ptp
+sptp {a1 90}
+EndSpline c_spl
+Default
+i = i+1
+EndSwitch
+Continue
+Until False
+EndIf
+end
+
+DEF Two()
+int i
+END
+
+global def Three()
+int i
+end
+
+GLOBAL DEF Four()
+int i
+END
+
+Global Def Five()
+int i
+End
+
+deffct bool fOne()
+int i
+endfct
+
+DEFFCT bool fTwo()
+int i
+ENDFCT
+
+global deffct bool fThree()
+int i
+endfct
+
+GLOBAL DEFFCT bool fFour()
+int i
+ENDFCT
+
+Global DefFct bool fFive()
+int i
+EndFct
+
+DefDat datfile()
+global int i=1
+; don't indent column 1 comments unless g:krlCommentIndent is set
+; global int o=2
+EndDat
+
+; END_INDENT
+
+; START_INDENT
+; INDENT_EXE let g:krlSpaceIndent = 0
+; INDENT_EXE set shiftwidth=4
+
+def bla()
+int i
+end
+
+; END_INDENT
+
+; START_INDENT
+; INDENT_EXE let g:krlCommentIndent = 1
+def bla()
+; indent this first column comment because of g:krlCommentIndent=1
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_EXE let g:krlIndentBetweenDef = 0
+def bla()
+int i ; don't indent this line because of g:krlIndentBetweenDef=0
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_AT this-line
+def Some()
+int f
+if true then
+f = 1 ; this-line
+endif
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_NEXT next-line
+def Some()
+ int i
+ ; next-line
+i = 1 ; should get indent of line 'int i' above
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_PREV prev-line
+def Some()
+int f
+if true then
+f = 1
+; prev-line
+endif
+end
+; END_INDENT
diff --git a/mnv/runtime/indent/testdir/krl.ok b/mnv/runtime/indent/testdir/krl.ok
new file mode 100644
index 0000000000..8badb912f6
--- /dev/null
+++ b/mnv/runtime/indent/testdir/krl.ok
@@ -0,0 +1,148 @@
+; mnv: set ft=krl :
+
+; START_INDENT
+
+def One()
+ int i
+ If i==1 then
+ While i>=1
+ For i=1 to 5 step 2
+ Loop
+ i = i+1
+ EndLoop
+ EndFor
+ EndWhile
+ Else
+ Repeat
+ Switch i
+ Case 1
+ Skip 123
+ i = i+1
+ EndSkip 123
+ Spline with $acc=100, $vel.cp=3
+ slin {x 100}
+ scirc {x 110, y 110}, {x 120, y 90}
+ slin {x 200} c_dis
+ Time_Block Start
+ slin {x 300} c_dis
+ Time_Block Part = 22.2
+ slin {y 400} c_dis
+ Time_Block Part = 33.3
+ Time_Block End = 10
+ slin {y 200} c_dis
+ Const_Vel Start +100 OnStart
+ slin {y 300} c_dis
+ slin {x 100}
+ Const_Vel End -5.5
+ slin {y 200} c_dis
+ EndSpline
+ Case 2,3
+ PTP_Spline with $acc=100, $vel.ptp=100
+ sptp {a1 0} c_ptp
+ sptp {a1 90}
+ EndSpline c_spl
+ Default
+ i = i+1
+ EndSwitch
+ Continue
+ Until False
+ EndIf
+end
+
+DEF Two()
+ int i
+END
+
+global def Three()
+ int i
+end
+
+GLOBAL DEF Four()
+ int i
+END
+
+Global Def Five()
+ int i
+End
+
+deffct bool fOne()
+ int i
+endfct
+
+DEFFCT bool fTwo()
+ int i
+ENDFCT
+
+global deffct bool fThree()
+ int i
+endfct
+
+GLOBAL DEFFCT bool fFour()
+ int i
+ENDFCT
+
+Global DefFct bool fFive()
+ int i
+EndFct
+
+DefDat datfile()
+ global int i=1
+; don't indent column 1 comments unless g:krlCommentIndent is set
+; global int o=2
+EndDat
+
+; END_INDENT
+
+; START_INDENT
+; INDENT_EXE let g:krlSpaceIndent = 0
+; INDENT_EXE set shiftwidth=4
+
+def bla()
+ int i
+end
+
+; END_INDENT
+
+; START_INDENT
+; INDENT_EXE let g:krlCommentIndent = 1
+def bla()
+ ; indent this first column comment because of g:krlCommentIndent=1
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_EXE let g:krlIndentBetweenDef = 0
+def bla()
+int i ; don't indent this line because of g:krlIndentBetweenDef=0
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_AT this-line
+def Some()
+int f
+if true then
+ f = 1 ; this-line
+endif
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_NEXT next-line
+def Some()
+ int i
+ ; next-line
+ i = 1 ; should get indent of line 'int i' above
+end
+; END_INDENT
+
+; START_INDENT
+; INDENT_PREV prev-line
+def Some()
+int f
+if true then
+ f = 1
+; prev-line
+endif
+end
+; END_INDENT
diff --git a/mnv/runtime/indent/testdir/lua.in b/mnv/runtime/indent/testdir/lua.in
new file mode 100644
index 0000000000..eb6e6f917b
--- /dev/null
+++ b/mnv/runtime/indent/testdir/lua.in
@@ -0,0 +1,19 @@
+-- mnv: set ft=lua sw=2 noet:
+
+-- START_INDENT
+function foo(a, b, c, d)
+ return { a, b, c, d }
+end
+
+local a = foo(
+1,
+2,
+"longxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+4
+)
+
+local b = {
+1,
+ 2,
+}
+-- END_INDENT
diff --git a/mnv/runtime/indent/testdir/lua.ok b/mnv/runtime/indent/testdir/lua.ok
new file mode 100644
index 0000000000..3613c29849
--- /dev/null
+++ b/mnv/runtime/indent/testdir/lua.ok
@@ -0,0 +1,19 @@
+-- mnv: set ft=lua sw=2 noet:
+
+-- START_INDENT
+function foo(a, b, c, d)
+ return { a, b, c, d }
+end
+
+local a = foo(
+ 1,
+ 2,
+ "longxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ 4
+)
+
+local b = {
+ 1,
+ 2,
+}
+-- END_INDENT
diff --git a/mnv/runtime/indent/testdir/make.in b/mnv/runtime/indent/testdir/make.in
new file mode 100644
index 0000000000..001c645476
--- /dev/null
+++ b/mnv/runtime/indent/testdir/make.in
@@ -0,0 +1,20 @@
+# mnv:ft=make
+# START_INDENT
+.POSIX :
+MAKEFLAGS += -rR
+
+.SUFFIXES: .F .f
+FC = f95
+FFLAGS =
+CPPFLAGS =
+
+.PHONY: help
+help:
+@echo indentation test
+
+.F.f:
+$(FC) $(CPPFLAGS) -E $< > $@
+
+.f.o:
+$(FC) $(FFLAGS) -c -o $@ $<
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/make.ok b/mnv/runtime/indent/testdir/make.ok
new file mode 100644
index 0000000000..e18f5064c3
--- /dev/null
+++ b/mnv/runtime/indent/testdir/make.ok
@@ -0,0 +1,20 @@
+# mnv:ft=make
+# START_INDENT
+.POSIX :
+MAKEFLAGS += -rR
+
+.SUFFIXES: .F .f
+FC = f95
+FFLAGS =
+CPPFLAGS =
+
+.PHONY: help
+help:
+ @echo indentation test
+
+.F.f:
+ $(FC) $(CPPFLAGS) -E $< > $@
+
+.f.o:
+ $(FC) $(FFLAGS) -c -o $@ $<
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/matlab.in b/mnv/runtime/indent/testdir/matlab.in
new file mode 100644
index 0000000000..86ca1199b5
--- /dev/null
+++ b/mnv/runtime/indent/testdir/matlab.in
@@ -0,0 +1,89 @@
+% mnv: set ft=matlab sw=4 :
+
+% START_INDENT
+if true
+disp foo
+elseif false
+disp bar
+end
+% END_INDENT
+
+% START_INDENT
+try
+statements
+catch exception
+statements
+end
+% END_INDENT
+
+% START_INDENT
+if true, ...
+if true
+disp hello
+end
+end
+% END_INDENT
+
+% START_INDENT
+switch a
+case expr
+if true, foo; end
+disp hello
+otherwise
+disp bar
+end
+% END_INDENT
+
+% START_INDENT
+if true
+A(1:end - 1)
+C{1:end - 1}
+disp foo
+end
+% END_INDENT
+
+% START_INDENT
+A = [{
+}
+] ...
+disp foo
+disp bar
+% END_INDENT
+
+% START_INDENT
+if true
+% end
+%% end
+disp foo
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 0
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 1
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 2
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
diff --git a/mnv/runtime/indent/testdir/matlab.ok b/mnv/runtime/indent/testdir/matlab.ok
new file mode 100644
index 0000000000..d185dff857
--- /dev/null
+++ b/mnv/runtime/indent/testdir/matlab.ok
@@ -0,0 +1,89 @@
+% mnv: set ft=matlab sw=4 :
+
+% START_INDENT
+if true
+ disp foo
+elseif false
+ disp bar
+end
+% END_INDENT
+
+% START_INDENT
+try
+ statements
+catch exception
+ statements
+end
+% END_INDENT
+
+% START_INDENT
+if true, ...
+ if true
+ disp hello
+ end
+end
+% END_INDENT
+
+% START_INDENT
+switch a
+ case expr
+ if true, foo; end
+ disp hello
+ otherwise
+ disp bar
+end
+% END_INDENT
+
+% START_INDENT
+if true
+ A(1:end - 1)
+ C{1:end - 1}
+ disp foo
+end
+% END_INDENT
+
+% START_INDENT
+A = [{
+ }
+ ] ...
+ disp foo
+disp bar
+% END_INDENT
+
+% START_INDENT
+if true
+ % end
+ %% end
+ disp foo
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 0
+function foo
+disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 1
+function foo
+disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 2
+function foo
+ disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
diff --git a/mnv/runtime/indent/testdir/mnv.in b/mnv/runtime/indent/testdir/mnv.in
new file mode 100644
index 0000000000..a004ffd285
--- /dev/null
+++ b/mnv/runtime/indent/testdir/mnv.in
@@ -0,0 +1,225 @@
+" mnv: set ft=mnv sw=4 :
+
+" START_INDENT
+" INDENT_EXE let g:mnv_indent = {'searchpair_timeout': 1024}
+" INDENT_EXE runtime autoload/dist/mnvindent.mnv
+func Some()
+let x = 1
+endfunc
+
+let cmd =
+\ 'some '
+\ 'string'
+
+if 1
+let x = [
+\ ]
+endif
+
+for x in [
+{key: 'value'},
+]
+eval 0
+endfor
+
+let t = [
+\ {
+\ 'k': 'val',
+\ },
+\ ]
+
+def Func()
+var d = dd
+->extend({
+})
+eval 0
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:mnv_indent_cont = 6
+
+let cmd =
+\ 'some '
+\ 'string'
+
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:mnv_indent_cont = 5
+
+let list = [
+\ 'one',
+\ 'two']
+
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE unlet g:mnv_indent_cont
+
+let list = [
+'one',
+'two',
+]
+echo
+
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+func Some()
+let f = x " this-line
+endfunc
+" END_INDENT
+
+" START_INDENT
+" INDENT_NEXT next-line
+func Some()
+ " next-line
+let f = x
+endfunc
+" END_INDENT
+
+" START_INDENT
+" INDENT_PREV prev-line
+func Some()
+let f = x
+" prev-line
+endfunc
+" END_INDENT
+
+" START_INDENT
+let a =<< END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
+let a =<< trim END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+let a=<< trim END
+ blah
+ blah
+ blah this-line
+END
+" END_INDENT
+
+" START_INDENT
+if v:true
+echo 0
+end
+" END_INDENT
+
+" START_INDENT
+augroup Name
+autocmd!
+augroup END
+" END_INDENT
+
+" START_INDENT
+substitute/pat /rep /
+echo
+" END_INDENT
+
+" START_INDENT
+try
+echo 1
+catch /pat / # comment
+echo 2
+endtry
+" END_INDENT
+
+" START_INDENT
+if end == 'xxx' || end == 'yyy'
+echo
+endif
+" END_INDENT
+
+" START_INDENT
+nunmap <buffer> (
+nunmap <buffer> )
+inoremap [ {
+inoremap ] }
+silent! xunmap i{
+silent! xunmap a{
+" END_INDENT
+
+" START_INDENT
+make_job = job_start([&shell, &shellcmdflag, make_cmd], {
+callback: function(MakeProcessOutput, [qfid]),
+close_cb: function(MakeCloseCb, [qfid]),
+exit_cb: MakeCompleted,
+in_io: 'null'
+})
+" END_INDENT
+
+" START_INDENT
+setlocal iskeyword+=[
+cword = expand('<cword>')
+" END_INDENT
+
+" START_INDENT
+if winsz == 0|let winsz= ""|endif
+exe "noswapfile ".winsz."wincmd s"
+" END_INDENT
+
+" START_INDENT
+function Func()
+if v:true
++
+echo
+-
+endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+silent! argdel *
+edit file
+" END_INDENT
+
+" START_INDENT
+call prop_type_add('indent_after_literal_dict', #{ foo: 'bar' })
+call prop_type_delete('indent_after_literal_dict')
+" END_INDENT
+
+" START_INDENT
+silent function Foo()
+return 42
+endfunction
+silent! function Bar()
+return 42
+endfunction
+" END_INDENT
+
+" START_INDENT
+if true
+nmap xxx,
+else
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+ var heredoc =<< END
+ foo
+ bar
+ baz
+ END
+endif
+" END_INDENT
+
+" START_INDENT
+set path=.,,
+set clipboard=unnamed,unnamedplus
+" END_INDENT
+
+" START_INDENT
+registers +
+echo 'text'
+" END_INDENT
diff --git a/mnv/runtime/indent/testdir/mnv.ok b/mnv/runtime/indent/testdir/mnv.ok
new file mode 100644
index 0000000000..f33d910fbf
--- /dev/null
+++ b/mnv/runtime/indent/testdir/mnv.ok
@@ -0,0 +1,225 @@
+" mnv: set ft=mnv sw=4 :
+
+" START_INDENT
+" INDENT_EXE let g:mnv_indent = {'searchpair_timeout': 1024}
+" INDENT_EXE runtime autoload/dist/mnvindent.mnv
+func Some()
+ let x = 1
+endfunc
+
+let cmd =
+ \ 'some '
+ \ 'string'
+
+if 1
+ let x = [
+ \ ]
+endif
+
+for x in [
+ {key: 'value'},
+ ]
+ eval 0
+endfor
+
+let t = [
+ \ {
+ \ 'k': 'val',
+ \ },
+ \ ]
+
+def Func()
+ var d = dd
+ ->extend({
+ })
+ eval 0
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:mnv_indent_cont = 6
+
+let cmd =
+ \ 'some '
+ \ 'string'
+
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:mnv_indent_cont = 5
+
+let list = [
+ \ 'one',
+ \ 'two']
+
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE unlet g:mnv_indent_cont
+
+let list = [
+ 'one',
+ 'two',
+]
+echo
+
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+func Some()
+ let f = x " this-line
+endfunc
+" END_INDENT
+
+" START_INDENT
+" INDENT_NEXT next-line
+func Some()
+ " next-line
+ let f = x
+endfunc
+" END_INDENT
+
+" START_INDENT
+" INDENT_PREV prev-line
+func Some()
+ let f = x
+" prev-line
+endfunc
+" END_INDENT
+
+" START_INDENT
+let a =<< END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
+let a =<< trim END
+ nothing
+END
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+let a=<< trim END
+ blah
+ blah
+ blah this-line
+END
+" END_INDENT
+
+" START_INDENT
+if v:true
+ echo 0
+end
+" END_INDENT
+
+" START_INDENT
+augroup Name
+ autocmd!
+augroup END
+" END_INDENT
+
+" START_INDENT
+substitute/pat /rep /
+echo
+" END_INDENT
+
+" START_INDENT
+try
+ echo 1
+catch /pat / # comment
+ echo 2
+endtry
+" END_INDENT
+
+" START_INDENT
+if end == 'xxx' || end == 'yyy'
+ echo
+endif
+" END_INDENT
+
+" START_INDENT
+nunmap <buffer> (
+nunmap <buffer> )
+inoremap [ {
+inoremap ] }
+silent! xunmap i{
+silent! xunmap a{
+" END_INDENT
+
+" START_INDENT
+make_job = job_start([&shell, &shellcmdflag, make_cmd], {
+ callback: function(MakeProcessOutput, [qfid]),
+ close_cb: function(MakeCloseCb, [qfid]),
+ exit_cb: MakeCompleted,
+ in_io: 'null'
+})
+" END_INDENT
+
+" START_INDENT
+setlocal iskeyword+=[
+cword = expand('<cword>')
+" END_INDENT
+
+" START_INDENT
+if winsz == 0|let winsz= ""|endif
+exe "noswapfile ".winsz."wincmd s"
+" END_INDENT
+
+" START_INDENT
+function Func()
+ if v:true
+ +
+ echo
+ -
+ endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+silent! argdel *
+edit file
+" END_INDENT
+
+" START_INDENT
+call prop_type_add('indent_after_literal_dict', #{ foo: 'bar' })
+call prop_type_delete('indent_after_literal_dict')
+" END_INDENT
+
+" START_INDENT
+silent function Foo()
+ return 42
+endfunction
+silent! function Bar()
+ return 42
+endfunction
+" END_INDENT
+
+" START_INDENT
+if true
+ nmap xxx,
+else
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+ var heredoc =<< END
+ foo
+ bar
+ baz
+END
+endif
+" END_INDENT
+
+" START_INDENT
+set path=.,,
+set clipboard=unnamed,unnamedplus
+" END_INDENT
+
+" START_INDENT
+registers +
+echo 'text'
+" END_INDENT
diff --git a/mnv/runtime/indent/testdir/mnv9.in b/mnv/runtime/indent/testdir/mnv9.in
new file mode 100644
index 0000000000..1e5fe084fd
--- /dev/null
+++ b/mnv/runtime/indent/testdir/mnv9.in
@@ -0,0 +1,795 @@
+mnv9script
+# mnv: set ft=mnv sw=4 :
+
+# START_INDENT
+# INDENT_EXE let g:mnv_indent = {'searchpair_timeout': 8192}
+# INDENT_EXE runtime autoload/dist/mnvindent.mnv
+var result = Func(
+arg1,
+arg2
+)
+# END_INDENT
+
+# START_INDENT
+var result = Func(arg1,
+arg2)
+# END_INDENT
+
+# START_INDENT
+filter(list, (k, v) =>
+v > 0)
+# END_INDENT
+
+# START_INDENT
+filter(list, (k, v) => {
+const x = get(list, k, 0)
+return x > 0
+})
+# END_INDENT
+
+# START_INDENT
+if x > 0
+filter(list, (k, v) => {
+const x = get(list, k, 1)
+return x > 0
+})
+endif
+# END_INDENT
+
+# START_INDENT
+{
+var temp = 'temp'
+}
+# END_INDENT
+
+# START_INDENT
+var text = lead
+.. middle
+.. end
+# END_INDENT
+
+# START_INDENT
+var text = lead ..
+middle ..
+end
+# END_INDENT
+
+# START_INDENT
+var total = start +
+end -
+correction
+# END_INDENT
+
+# START_INDENT
+var result = start
+:+ print
+# END_INDENT
+
+# START_INDENT
+var result = positive
+? PosFunc(arg)
+: NegFunc(arg)
+# END_INDENT
+
+# START_INDENT
+var result = GetBuilder()
+->BuilderSetWidth(333)
+->BuilderSetHeight(777)
+->BuilderBuild()
+# END_INDENT
+
+# START_INDENT
+var result = MyDict
+.member
+# END_INDENT
+
+# START_INDENT
+autocmd BufNewFile *.match if condition
+| echo 'match'
+| endif
+# END_INDENT
+
+# START_INDENT
+set cpo+=C
+var lines =<< trim END
+| this works
+END
+set cpo-=C
+# END_INDENT
+
+# START_INDENT
+syn region Text
+\ start='foo'
+#\ comment
+\ end='bar'
+# END_INDENT
+
+# START_INDENT
+au CursorHold * echom 'BEFORE bar'
+#\ some comment
+| echom 'AFTER bar'
+# END_INDENT
+
+# START_INDENT
+def MyFunc(text: string,
+separator = '-'
+): string
+enddef
+# END_INDENT
+
+# START_INDENT
+def MyFunc(
+text: string,
+separator = '-'
+): string
+enddef
+# END_INDENT
+
+# START_INDENT
+[var1, var2] =
+Func()
+# END_INDENT
+
+# START_INDENT
+const list = ['one',
+'two']
+# END_INDENT
+
+# START_INDENT
+const list = [
+'one',
+'two',
+]
+# END_INDENT
+
+# START_INDENT
+const dict = {one: 1,
+two: 2
+}
+# END_INDENT
+
+# START_INDENT
+const dict = {
+one: 1,
+two: 2
+}
+# END_INDENT
+
+# START_INDENT
+if true
+const dict =
+{
+one: 1,
+two: 2
+}
+endif
+# END_INDENT
+
+# START_INDENT
+def Func()
+return {
+one: 1
+}
+enddef
+# END_INDENT
+
+# START_INDENT
+echo {
+a: 0,
+# b
+# c
+}
+# END_INDENT
+
+# START_INDENT
+echo search(
+# comment
+'1'
+.. '2'
+)
+# END_INDENT
+
+# START_INDENT
+if true
+var v = ( # trailing "(" starts line continuation
+3 + 4 # nothing special
+) # end of expression indicates continued line
+var x: number # needs to align with previous "var"
+endif
+# END_INDENT
+
+# START_INDENT
+def Func() # {{{
+# comment
+if true
+return
+endif
+enddef
+# END_INDENT
+
+# START_INDENT
+echo {
+key:
+'value',
+}
+# END_INDENT
+
+# START_INDENT
+var id = time
+->timer_start((_) => {
+n = 0
+})
+# END_INDENT
+
+# START_INDENT
+var n =
+# comment
+1
++ 2
+
+var s = ''
+# END_INDENT
+
+# START_INDENT
+var keys = {
+J: 'j',
+"\<Home>": '1G',
+"\<End>": 'G',
+z: 'zz'
+}
+# END_INDENT
+
+# START_INDENT
+export def Func(
+n: number,
+s: string,
+...l: list<bool>
+)
+enddef
+# END_INDENT
+
+# START_INDENT
+var heredoc =<< trim ENDD
+var nested_heredoc =<< trim END
+END
+ENDD
+# END_INDENT
+
+# START_INDENT
+if true
+else " comment
+endif
+# END_INDENT
+
+# START_INDENT
+if true | echo 'one' | endif
+if true | echo 'two' | endif
+if true | echo 'three' | endif
+# END_INDENT
+
+# START_INDENT
+if true
+:'<-1 mark <
+else
+echo ''
+endif
+# END_INDENT
+
+# START_INDENT
+def Func()
+Cmd %
+enddef
+# END_INDENT
+
+# START_INDENT
+if true
+popup_move(id, {col: 1,
+line: 2})
+endif
+setwinvar(id, 'name', 3)
+# END_INDENT
+
+# START_INDENT
+var d = [
+{a: 'x',
+b: 'y'},
+FuncA(),
+FuncB(),
+]
+# END_INDENT
+
+# START_INDENT
+var ll = [[
+1,
+2,
+3], [
+4,
+5,
+6], [
+7,
+8,
+9]]
+# END_INDENT
+
+# START_INDENT
+var ld = [{
+a: 'xxx',
+b: 'yyy'}, {
+c: 'xxx',
+d: 'yyy'}, {
+e: 'xxx',
+f: 'yyy'}, {
+}]
+# END_INDENT
+
+# START_INDENT
+var d = {
+a: {
+b: {
+c: [{
+d: 'e',
+f: 'g',
+h: 'i'
+}],
+j: 'k',
+},
+},
+}
+# END_INDENT
+
+# START_INDENT
+if true
+var end: any
+if true
+end = 0
+elseif true
+echo
+endif
+endif
+# END_INDENT
+
+# START_INDENT
+if true
+var d = {
+end: 0}
+endif
+# END_INDENT
+
+# START_INDENT
+def Func(
+s: string,
+n = 1,
+m = 2
+)
+enddef
+# END_INDENT
+
+# START_INDENT
+var h =<< END
+text
+END
+
+def Func()
+echo
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func()
+var h =<< END
+text
+END
+echo 'test'
+enddef
+# END_INDENT
+
+# START_INDENT
+def Foo()
+lcd -
+enddef
+def Bar()
+echo
+enddef
+# END_INDENT
+
+# START_INDENT
+if true
+n = Func(1, 2,
+3)
+endif
+# END_INDENT
+
+# START_INDENT
+def Func(s: string,
+n: number): bool
+if true
+return false
+endif
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func(
+n: number)
+#
+echo
+enddef
+# END_INDENT
+
+# START_INDENT
+# INDENT_AT this-line
+def Func(
+ n: number)
+ #
+echo # this-line
+enddef
+# END_INDENT
+
+# START_INDENT
+if true
+if true
+normal! ==
+endif
+endif
+# END_INDENT
+
+# START_INDENT
+var d = {
+a: () => true,
+b: () => true
+&& true
+&& Foo(),
+c: () => Bar(),
+e: () => Baz(),
+}
+# END_INDENT
+
+# START_INDENT
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+return (Emit: func(any)) => {
+Cont((t: any) => {
+if Pred(t)
+Emit(t)
+endif
+})
+}
+enddef
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:mnv_indent.more_in_bracket_block = v:true
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+return (Emit: func(any)) => {
+Cont((t: any) => {
+if Pred(t)
+Emit(t)
+endif
+})
+}
+enddef
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:mnv_indent = {'searchpair_timeout': 8192}
+# END_INDENT
+
+# START_INDENT
+g:lightline = {
+'active': {
+'left': [ [ 'mode', 'paste' ], [ 'readonly', 'relativepath', 'modified' ] ],
+},
+'inactive': {
+'left': [ [ 'readonly', 'relativepath', 'modified' ] ],
+}
+}
+# END_INDENT
+
+# START_INDENT
+if getline(1, 10)
+->map((_, v: string): number => strcharlen(v))
+->max() > 1'000
+&l:breakindent = false
+&l:linebreak = false
+else
+&l:breakindent = true
+&l:linebreak = true
+endif
+# END_INDENT
+
+# START_INDENT
+var ext2cmd: dict<string> = {
+doc: $'antiword {fname}',
+docx: $'pandoc --from=docx --to=markdown {fname}',
+epub: $'pandoc --from=epub --to=markdown {fname}',
+odp: $'odt2txt {fname}',
+odt: $'odt2txt {fname}',
+pdf: $'pdftotext -nopgbrk -layout -q -eol unix {fname} -',
+rtf: 'unrtf --text',
+}
+# END_INDENT
+
+# START_INDENT
+const ptybuf: number = term_start(&shell, {
+hidden: true,
+exit_cb: (_, _) => {
+if true
+close
+else
+help
+endif
+}
+})
+# END_INDENT
+
+# START_INDENT
+var d = {
+a: 0,
+# a ' quote {{{
+#}}}
+b: 0,
+}
+# END_INDENT
+
+# START_INDENT
+echo printf('%s () %s',
+1,
+2
+)
+# END_INDENT
+
+# START_INDENT
+prop_add(1, col('.'), {
+length: 2,
+type: 'test'
+})
+# END_INDENT
+
+# START_INDENT
+echo (() => " string starting with space")()
+echo
+# END_INDENT
+
+# START_INDENT
+var variables = deepcopy(g:)
+->filter((k: string, _): bool =>
+k =~ '\c\V' .. keyword->escape('\')
+&& k !~ '\%(loaded\|did_plugin_\)')
+->items()
+->map((_, v): string => v[0] .. ' = ' .. string(v[1]))
+new
+# END_INDENT
+
+# START_INDENT
+var d = freq
+->map((_, v) =>
+v * (
+1
++ 2
+))
+for item in d
+->items()
+->sort((a, b) => b[1] - a[1])
+echo
+endfor
+# END_INDENT
+
+# START_INDENT
+var matching_abbrev: list<dict<string>> = copy(ABBREV)
+->filter((_, v: dict<string>): bool =>
+stridx(v.lhs, word_to_complete) == 0)
+->map((_, v: dict<string>) => ({
+word: v.lhs,
+menu: AbbrevRhs(v.rhs)->stridx('expand_') >= 0
+? AbbrevRhs(v.rhs)->matchstr('.*,\s*''\zs.*\ze'')')
+: AbbrevRhs(v.rhs)
+}))
+# END_INDENT
+
+# START_INDENT
+def Func()
+if true
+mnvgrep /^\C\s*\%(fu\%[nction]\|def\)\s\+/ file
+endif
+enddef
+# END_INDENT
+
+# START_INDENT
+silent if true
+echo
+endif
+# END_INDENT
+
+# START_INDENT
+def Func()
+sort :^.*[\/]:
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func()
+d = {
+}
+hd =<< trim END
+['
+]'
+END
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func()
+if true
+var hd =<< trim END
+if get(b:, 'current_syntax', '')
+endif
+END
+elseif true
+echo
+endif
+enddef
+# END_INDENT
+
+# START_INDENT
+# test for control-flow keyword followed by commented fold marker {{{
+if true
+echo
+endif #}}}
+# END_INDENT
+
+# START_INDENT
+if true
+if true
+windo if true | echo | endif
+augroup Name
+autocmd WinLeave * if true | eval 1 + 2 | endif
+augroup END
+endif
+endif
+# END_INDENT
+
+# START_INDENT
+if true
+echo ' =<< trim END'
+->len()
+endif
+# END_INDENT
+
+# START_INDENT
+function Func()
+if true
+if true
+if true | echo com | endif
+if true | echo com | endif
+endif
+else
+endif
+endfunction
+# END_INDENT
+
+# START_INDENT
+var matchpairs: string = &matchpairs
+var pairs: dict<list<string>>
+for [opening: string, closing: string]
+in matchpairs
+->split(',')
+->map((_, v: string): list<string> => split(v, ':'))
+pairs[opening] = [escape(opening, '[]'), escape(closing, '[]'), 'nW', 'w$']
+pairs[closing] = [escape(opening, '[]'), escape(closing, '[]'), 'bnW', 'w0']
+endfor
+# END_INDENT
+
+# START_INDENT
+{
+echo []
++ []
++ [{a: 1,
+b: 2}]
+}
+# END_INDENT
+
+# START_INDENT
+def Foo()
+Bar(1,
+[]->filter((_, v) => {
+return true
+}),
+() => {
+echo
+})
+enddef
+# END_INDENT
+
+# START_INDENT
+echo {
+k: () => {
+if true
+echo
+popup_setoptions(id,
+{title: 'title'})
+endif
+}
+}
+# END_INDENT
+
+# START_INDENT
+if true
+elseif
+endif
+# END_INDENT
+
+# START_INDENT
+if (
+true)
+&& true
+echo
+endif
+# END_INDENT
+
+# START_INDENT
+abstract class Shape
+var color = Color.Black
+var thickness = 10
+endclass
+# END_INDENT
+
+# START_INDENT
+class OtherThing
+var size: number
+static var totalSize: number
+
+static def ClearTotalSize(): number
+var prev = totalSize
+totalSize = 0
+return prev
+enddef
+endclass
+# END_INDENT
+
+# START_INDENT
+interface HasSurface
+var size: number
+def Surface(): number
+endinterface
+# END_INDENT
+
+# START_INDENT
+interface EnterExit
+def Enter(): void
+def Exit(): void
+endinterface
+# END_INDENT
+
+# START_INDENT
+enum Color
+White,
+Red,
+Green,
+Blue,
+Black
+endenum
+# END_INDENT
+
+# START_INDENT
+enum Digits
+INVALID(v:numbermax), # The null value.
+ZERO(0 * v:numbermin), ONE(2 - 1),
+TWO(1 + 1), THREE(9 / 3), FOUR(1 * 4),
+FIVE(1 + 2 + 2), SIX(36 / 3 / 2), SEVEN(7), EIGHT(2 * 2 * 2),
+NINE(3 + 3 + 3)
+const value: number
+def new(value: number)
+this.value = value
+enddef
+endenum
+# END_INDENT
+
+# START_INDENT
+def ToggleBoolOpt(opt: string)
+exe $"&{opt} = !&{opt}"
+$"&{opt}"
+->eval()
+->( (v) => v ? "ON" : "OFF" )()
+->printf($"{opt} %s")
+->popup_notification({})
+enddef
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/mnv9.ok b/mnv/runtime/indent/testdir/mnv9.ok
new file mode 100644
index 0000000000..bbcc235de5
--- /dev/null
+++ b/mnv/runtime/indent/testdir/mnv9.ok
@@ -0,0 +1,795 @@
+mnv9script
+# mnv: set ft=mnv sw=4 :
+
+# START_INDENT
+# INDENT_EXE let g:mnv_indent = {'searchpair_timeout': 8192}
+# INDENT_EXE runtime autoload/dist/mnvindent.mnv
+var result = Func(
+ arg1,
+ arg2
+)
+# END_INDENT
+
+# START_INDENT
+var result = Func(arg1,
+ arg2)
+# END_INDENT
+
+# START_INDENT
+filter(list, (k, v) =>
+ v > 0)
+# END_INDENT
+
+# START_INDENT
+filter(list, (k, v) => {
+ const x = get(list, k, 0)
+ return x > 0
+})
+# END_INDENT
+
+# START_INDENT
+if x > 0
+ filter(list, (k, v) => {
+ const x = get(list, k, 1)
+ return x > 0
+ })
+endif
+# END_INDENT
+
+# START_INDENT
+{
+ var temp = 'temp'
+}
+# END_INDENT
+
+# START_INDENT
+var text = lead
+ .. middle
+ .. end
+# END_INDENT
+
+# START_INDENT
+var text = lead ..
+ middle ..
+ end
+# END_INDENT
+
+# START_INDENT
+var total = start +
+ end -
+ correction
+# END_INDENT
+
+# START_INDENT
+var result = start
+:+ print
+# END_INDENT
+
+# START_INDENT
+var result = positive
+ ? PosFunc(arg)
+ : NegFunc(arg)
+# END_INDENT
+
+# START_INDENT
+var result = GetBuilder()
+ ->BuilderSetWidth(333)
+ ->BuilderSetHeight(777)
+ ->BuilderBuild()
+# END_INDENT
+
+# START_INDENT
+var result = MyDict
+ .member
+# END_INDENT
+
+# START_INDENT
+autocmd BufNewFile *.match if condition
+ | echo 'match'
+ | endif
+# END_INDENT
+
+# START_INDENT
+set cpo+=C
+var lines =<< trim END
+ | this works
+END
+set cpo-=C
+# END_INDENT
+
+# START_INDENT
+syn region Text
+ \ start='foo'
+ #\ comment
+ \ end='bar'
+# END_INDENT
+
+# START_INDENT
+au CursorHold * echom 'BEFORE bar'
+ #\ some comment
+ | echom 'AFTER bar'
+# END_INDENT
+
+# START_INDENT
+def MyFunc(text: string,
+ separator = '-'
+ ): string
+enddef
+# END_INDENT
+
+# START_INDENT
+def MyFunc(
+ text: string,
+ separator = '-'
+ ): string
+enddef
+# END_INDENT
+
+# START_INDENT
+[var1, var2] =
+ Func()
+# END_INDENT
+
+# START_INDENT
+const list = ['one',
+ 'two']
+# END_INDENT
+
+# START_INDENT
+const list = [
+ 'one',
+ 'two',
+]
+# END_INDENT
+
+# START_INDENT
+const dict = {one: 1,
+ two: 2
+}
+# END_INDENT
+
+# START_INDENT
+const dict = {
+ one: 1,
+ two: 2
+}
+# END_INDENT
+
+# START_INDENT
+if true
+ const dict =
+ {
+ one: 1,
+ two: 2
+ }
+endif
+# END_INDENT
+
+# START_INDENT
+def Func()
+ return {
+ one: 1
+ }
+enddef
+# END_INDENT
+
+# START_INDENT
+echo {
+ a: 0,
+ # b
+ # c
+}
+# END_INDENT
+
+# START_INDENT
+echo search(
+ # comment
+ '1'
+ .. '2'
+)
+# END_INDENT
+
+# START_INDENT
+if true
+ var v = ( # trailing "(" starts line continuation
+ 3 + 4 # nothing special
+ ) # end of expression indicates continued line
+ var x: number # needs to align with previous "var"
+endif
+# END_INDENT
+
+# START_INDENT
+def Func() # {{{
+ # comment
+ if true
+ return
+ endif
+enddef
+# END_INDENT
+
+# START_INDENT
+echo {
+ key:
+ 'value',
+}
+# END_INDENT
+
+# START_INDENT
+var id = time
+ ->timer_start((_) => {
+ n = 0
+ })
+# END_INDENT
+
+# START_INDENT
+var n =
+ # comment
+ 1
+ + 2
+
+var s = ''
+# END_INDENT
+
+# START_INDENT
+var keys = {
+ J: 'j',
+ "\<Home>": '1G',
+ "\<End>": 'G',
+ z: 'zz'
+}
+# END_INDENT
+
+# START_INDENT
+export def Func(
+ n: number,
+ s: string,
+ ...l: list<bool>
+ )
+enddef
+# END_INDENT
+
+# START_INDENT
+var heredoc =<< trim ENDD
+ var nested_heredoc =<< trim END
+ END
+ENDD
+# END_INDENT
+
+# START_INDENT
+if true
+else " comment
+endif
+# END_INDENT
+
+# START_INDENT
+if true | echo 'one' | endif
+if true | echo 'two' | endif
+if true | echo 'three' | endif
+# END_INDENT
+
+# START_INDENT
+if true
+ :'<-1 mark <
+else
+ echo ''
+endif
+# END_INDENT
+
+# START_INDENT
+def Func()
+ Cmd %
+enddef
+# END_INDENT
+
+# START_INDENT
+if true
+ popup_move(id, {col: 1,
+ line: 2})
+endif
+setwinvar(id, 'name', 3)
+# END_INDENT
+
+# START_INDENT
+var d = [
+ {a: 'x',
+ b: 'y'},
+ FuncA(),
+ FuncB(),
+]
+# END_INDENT
+
+# START_INDENT
+var ll = [[
+ 1,
+ 2,
+ 3], [
+ 4,
+ 5,
+ 6], [
+ 7,
+ 8,
+ 9]]
+# END_INDENT
+
+# START_INDENT
+var ld = [{
+ a: 'xxx',
+ b: 'yyy'}, {
+ c: 'xxx',
+ d: 'yyy'}, {
+ e: 'xxx',
+ f: 'yyy'}, {
+ }]
+# END_INDENT
+
+# START_INDENT
+var d = {
+ a: {
+ b: {
+ c: [{
+ d: 'e',
+ f: 'g',
+ h: 'i'
+ }],
+ j: 'k',
+ },
+ },
+}
+# END_INDENT
+
+# START_INDENT
+if true
+ var end: any
+ if true
+ end = 0
+ elseif true
+ echo
+ endif
+endif
+# END_INDENT
+
+# START_INDENT
+if true
+ var d = {
+ end: 0}
+endif
+# END_INDENT
+
+# START_INDENT
+def Func(
+ s: string,
+ n = 1,
+ m = 2
+ )
+enddef
+# END_INDENT
+
+# START_INDENT
+var h =<< END
+text
+END
+
+def Func()
+ echo
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func()
+ var h =<< END
+text
+END
+ echo 'test'
+enddef
+# END_INDENT
+
+# START_INDENT
+def Foo()
+ lcd -
+enddef
+def Bar()
+ echo
+enddef
+# END_INDENT
+
+# START_INDENT
+if true
+ n = Func(1, 2,
+ 3)
+endif
+# END_INDENT
+
+# START_INDENT
+def Func(s: string,
+ n: number): bool
+ if true
+ return false
+ endif
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func(
+ n: number)
+ #
+ echo
+enddef
+# END_INDENT
+
+# START_INDENT
+# INDENT_AT this-line
+def Func(
+ n: number)
+ #
+ echo # this-line
+enddef
+# END_INDENT
+
+# START_INDENT
+if true
+ if true
+ normal! ==
+ endif
+endif
+# END_INDENT
+
+# START_INDENT
+var d = {
+ a: () => true,
+ b: () => true
+ && true
+ && Foo(),
+ c: () => Bar(),
+ e: () => Baz(),
+}
+# END_INDENT
+
+# START_INDENT
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+ return (Emit: func(any)) => {
+ Cont((t: any) => {
+ if Pred(t)
+ Emit(t)
+ endif
+ })
+ }
+enddef
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:mnv_indent.more_in_bracket_block = v:true
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+ return (Emit: func(any)) => {
+ Cont((t: any) => {
+ if Pred(t)
+ Emit(t)
+ endif
+ })
+ }
+enddef
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:mnv_indent = {'searchpair_timeout': 8192}
+# END_INDENT
+
+# START_INDENT
+g:lightline = {
+ 'active': {
+ 'left': [ [ 'mode', 'paste' ], [ 'readonly', 'relativepath', 'modified' ] ],
+ },
+ 'inactive': {
+ 'left': [ [ 'readonly', 'relativepath', 'modified' ] ],
+ }
+}
+# END_INDENT
+
+# START_INDENT
+if getline(1, 10)
+ ->map((_, v: string): number => strcharlen(v))
+ ->max() > 1'000
+ &l:breakindent = false
+ &l:linebreak = false
+else
+ &l:breakindent = true
+ &l:linebreak = true
+endif
+# END_INDENT
+
+# START_INDENT
+var ext2cmd: dict<string> = {
+ doc: $'antiword {fname}',
+ docx: $'pandoc --from=docx --to=markdown {fname}',
+ epub: $'pandoc --from=epub --to=markdown {fname}',
+ odp: $'odt2txt {fname}',
+ odt: $'odt2txt {fname}',
+ pdf: $'pdftotext -nopgbrk -layout -q -eol unix {fname} -',
+ rtf: 'unrtf --text',
+}
+# END_INDENT
+
+# START_INDENT
+const ptybuf: number = term_start(&shell, {
+ hidden: true,
+ exit_cb: (_, _) => {
+ if true
+ close
+ else
+ help
+ endif
+ }
+})
+# END_INDENT
+
+# START_INDENT
+var d = {
+ a: 0,
+ # a ' quote {{{
+ #}}}
+ b: 0,
+}
+# END_INDENT
+
+# START_INDENT
+echo printf('%s () %s',
+ 1,
+ 2
+)
+# END_INDENT
+
+# START_INDENT
+prop_add(1, col('.'), {
+ length: 2,
+ type: 'test'
+})
+# END_INDENT
+
+# START_INDENT
+echo (() => " string starting with space")()
+echo
+# END_INDENT
+
+# START_INDENT
+var variables = deepcopy(g:)
+ ->filter((k: string, _): bool =>
+ k =~ '\c\V' .. keyword->escape('\')
+ && k !~ '\%(loaded\|did_plugin_\)')
+ ->items()
+ ->map((_, v): string => v[0] .. ' = ' .. string(v[1]))
+new
+# END_INDENT
+
+# START_INDENT
+var d = freq
+ ->map((_, v) =>
+ v * (
+ 1
+ + 2
+ ))
+for item in d
+ ->items()
+ ->sort((a, b) => b[1] - a[1])
+ echo
+endfor
+# END_INDENT
+
+# START_INDENT
+var matching_abbrev: list<dict<string>> = copy(ABBREV)
+ ->filter((_, v: dict<string>): bool =>
+ stridx(v.lhs, word_to_complete) == 0)
+ ->map((_, v: dict<string>) => ({
+ word: v.lhs,
+ menu: AbbrevRhs(v.rhs)->stridx('expand_') >= 0
+ ? AbbrevRhs(v.rhs)->matchstr('.*,\s*''\zs.*\ze'')')
+ : AbbrevRhs(v.rhs)
+ }))
+# END_INDENT
+
+# START_INDENT
+def Func()
+ if true
+ mnvgrep /^\C\s*\%(fu\%[nction]\|def\)\s\+/ file
+ endif
+enddef
+# END_INDENT
+
+# START_INDENT
+silent if true
+ echo
+endif
+# END_INDENT
+
+# START_INDENT
+def Func()
+ sort :^.*[\/]:
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func()
+ d = {
+ }
+ hd =<< trim END
+ ['
+ ]'
+ END
+enddef
+# END_INDENT
+
+# START_INDENT
+def Func()
+ if true
+ var hd =<< trim END
+ if get(b:, 'current_syntax', '')
+ endif
+ END
+ elseif true
+ echo
+ endif
+enddef
+# END_INDENT
+
+# START_INDENT
+# test for control-flow keyword followed by commented fold marker {{{
+if true
+ echo
+endif #}}}
+# END_INDENT
+
+# START_INDENT
+if true
+ if true
+ windo if true | echo | endif
+ augroup Name
+ autocmd WinLeave * if true | eval 1 + 2 | endif
+ augroup END
+ endif
+endif
+# END_INDENT
+
+# START_INDENT
+if true
+ echo ' =<< trim END'
+ ->len()
+endif
+# END_INDENT
+
+# START_INDENT
+function Func()
+ if true
+ if true
+ if true | echo com | endif
+ if true | echo com | endif
+ endif
+ else
+ endif
+endfunction
+# END_INDENT
+
+# START_INDENT
+var matchpairs: string = &matchpairs
+var pairs: dict<list<string>>
+for [opening: string, closing: string]
+ in matchpairs
+ ->split(',')
+ ->map((_, v: string): list<string> => split(v, ':'))
+ pairs[opening] = [escape(opening, '[]'), escape(closing, '[]'), 'nW', 'w$']
+ pairs[closing] = [escape(opening, '[]'), escape(closing, '[]'), 'bnW', 'w0']
+endfor
+# END_INDENT
+
+# START_INDENT
+{
+ echo []
+ + []
+ + [{a: 1,
+ b: 2}]
+}
+# END_INDENT
+
+# START_INDENT
+def Foo()
+ Bar(1,
+ []->filter((_, v) => {
+ return true
+ }),
+ () => {
+ echo
+ })
+enddef
+# END_INDENT
+
+# START_INDENT
+echo {
+ k: () => {
+ if true
+ echo
+ popup_setoptions(id,
+ {title: 'title'})
+ endif
+ }
+}
+# END_INDENT
+
+# START_INDENT
+if true
+elseif
+endif
+# END_INDENT
+
+# START_INDENT
+if (
+ true)
+ && true
+ echo
+endif
+# END_INDENT
+
+# START_INDENT
+abstract class Shape
+ var color = Color.Black
+ var thickness = 10
+endclass
+# END_INDENT
+
+# START_INDENT
+class OtherThing
+ var size: number
+ static var totalSize: number
+
+ static def ClearTotalSize(): number
+ var prev = totalSize
+ totalSize = 0
+ return prev
+ enddef
+endclass
+# END_INDENT
+
+# START_INDENT
+interface HasSurface
+ var size: number
+ def Surface(): number
+endinterface
+# END_INDENT
+
+# START_INDENT
+interface EnterExit
+ def Enter(): void
+ def Exit(): void
+endinterface
+# END_INDENT
+
+# START_INDENT
+enum Color
+ White,
+ Red,
+ Green,
+ Blue,
+ Black
+endenum
+# END_INDENT
+
+# START_INDENT
+enum Digits
+ INVALID(v:numbermax), # The null value.
+ ZERO(0 * v:numbermin), ONE(2 - 1),
+ TWO(1 + 1), THREE(9 / 3), FOUR(1 * 4),
+ FIVE(1 + 2 + 2), SIX(36 / 3 / 2), SEVEN(7), EIGHT(2 * 2 * 2),
+ NINE(3 + 3 + 3)
+ const value: number
+ def new(value: number)
+ this.value = value
+ enddef
+endenum
+# END_INDENT
+
+# START_INDENT
+def ToggleBoolOpt(opt: string)
+ exe $"&{opt} = !&{opt}"
+ $"&{opt}"
+ ->eval()
+ ->( (v) => v ? "ON" : "OFF" )()
+ ->printf($"{opt} %s")
+ ->popup_notification({})
+enddef
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/python.in b/mnv/runtime/indent/testdir/python.in
new file mode 100644
index 0000000000..3e40c2ed77
--- /dev/null
+++ b/mnv/runtime/indent/testdir/python.in
@@ -0,0 +1,96 @@
+# mnv: set ft=python sw=4 et:
+
+# START_INDENT
+# INDENT_EXE let g:pyindent_searchpair_timeout = 256
+# INDENT_EXE runtime autoload/python.mnv
+dict = {
+'a': 1,
+'b': 2,
+'c': 3,
+}
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let [g:python_indent.open_paren, g:python_indent.closed_paren_align_last_line] = ['shiftwidth()', v:false]
+dict = {
+'a': 1,
+'b': 2,
+'c': 3,
+}
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:python_indent.open_paren = 'shiftwidth() * 2'
+# INDENT_EXE syntax match pythonFoldMarkers /{{{\d*/ contained containedin=pythonComment
+# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {{{1
+
+if True:
+pass
+# END_INDENT
+
+# START_INDENT
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+(200,
+300),
+400)
+
+open_paren_at_EOL(
+100, 200, 300, 400)
+
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/python.ok b/mnv/runtime/indent/testdir/python.ok
new file mode 100644
index 0000000000..9bceff7cd0
--- /dev/null
+++ b/mnv/runtime/indent/testdir/python.ok
@@ -0,0 +1,96 @@
+# mnv: set ft=python sw=4 et:
+
+# START_INDENT
+# INDENT_EXE let g:pyindent_searchpair_timeout = 256
+# INDENT_EXE runtime autoload/python.mnv
+dict = {
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ }
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let [g:python_indent.open_paren, g:python_indent.closed_paren_align_last_line] = ['shiftwidth()', v:false]
+dict = {
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+}
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:python_indent.open_paren = 'shiftwidth() * 2'
+# INDENT_EXE syntax match pythonFoldMarkers /{{{\d*/ contained containedin=pythonComment
+# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {{{1
+
+if True:
+ pass
+# END_INDENT
+
+# START_INDENT
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+open_paren_not_at_EOL(100,
+ (200,
+ 300),
+ 400)
+
+open_paren_at_EOL(
+ 100, 200, 300, 400)
+
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/rapid.in b/mnv/runtime/indent/testdir/rapid.in
new file mode 100644
index 0000000000..b360347b7f
--- /dev/null
+++ b/mnv/runtime/indent/testdir/rapid.in
@@ -0,0 +1,266 @@
+! mnv: set ft=rapid :
+
+! START_INDENT
+
+%%%
+ VERSION:1
+ LANGUAGE:ENGLISH
+%%%
+
+module LowerCaseModule
+
+task pers num n1 := 0;
+local pers num n2 := 1;
+var bool b1 := false;
+var intnum i1;
+
+! put some stuff in those strings that may confuse indentation
+const string st1 := "endmodule (";
+pers string st_Appl_Info{3,3}:=[
+[
+"["
+,
+"default"
+,
+"case"
+],
+[
+"else"
+,
+"then"
+,
+"endif"
+],
+[
+"do"
+,
+"}"
+,
+")"
+],
+];
+
+pers tooldata tTool1:=[TRUE,
+[
+[97.4, 0, 223.1],
+[0.924, 0, 0.383 ,0]
+],
+[5,
+[23, 0, 75],
+[1, 0, 0, 0], 0, 0, 0
+]
+];
+const robtarget p1:=[
+[600, 500, 225.3],
+[1, 0, 0, 0],
+[1, 1, 0, 0],
+[ 11, 12.3, 9E9, 9E9, 9E9, 9E9]
+];
+
+record myRec
+num nRecNum1
+bool bRecBool1
+endrecord
+
+proc proc1(num n1,
+num n2)
+var string st1;
+n1 := n1+1;
+MoveJSync p1, vmax, z30, tool1, "proc2";
+backward
+MoveJSync p1, v100, fine, tool1, "proc2";
+undo
+n1 := n1-1;
+error
+trynext;
+endproc
+
+func num nFunc1(
+switch s1
+|switch s2
+,num n1
+,bool b1)
+var num nVar;
+if not Present(s1) return;
+if Present(s1) then
+Incr n1;'
+elseif Present(s2) then
+b1:=false;
+else
+while n1>0 do
+Decr n1;
+test n1
+
+case 1:
+test1;
+case 2:
+test2;
+default:
+WaitUntil false;
+endtest
+endwhile
+endif
+for i from 1 to 10 step 2 do
+for j from 1 to 10 do
+st_Appl_Info{i,j} := "";
+endfor
+endfor
+! return 1;
+return 0;
+error
+return -1;
+endfunc
+
+trap Trap1
+Reset do1;
+endtrap
+
+endmodule
+
+MODULE UpperCaseModule(SYSMODULE,NOSTEPIN)
+TASK pers num n1 := 0;
+LOCAL pers num n2 := 1;
+VAR bool b1 := false;
+VAR intnum i1;
+
+LOCAL FUNC num nFunc1(
+switch s1
+|switch s2
+,num n1
+,bool b1)
+VAR num nVar;
+IF NOT PRESENT(s1) RETURN;
+IF PRESENT(s1) THEN
+INCR n1;'
+ELSEIF PRESENT(s2) THEN
+b1:=FALSE;
+ELSE
+WHILE n1>0 DO
+DECR n1;
+TEST n1
+
+CASE 1:
+test1;
+CASE 2:
+test2;
+DEFAULT:
+WAITUNTIL FALSE;
+ENDTEST
+ENDWHILE
+ENDIF
+FOR i FROM 1 TO 10 STEP 2 DO
+FOR j FROM 1 TO 10 DO
+st_Appl_Info{i,j} := "";
+ENDFOR
+ENDFOR
+! RETURN 1;
+RETURN 0;
+ERROR
+RETURN -1;
+ENDFUNC
+
+TRAP Trap1
+Reset do1;
+ENDTRAP
+
+ENDMODULE
+
+Module MixedCaseModule(SysModule)
+Task pers num n1 := 0;
+Local pers num n2 := 1;
+Var bool b1 := false;
+Var intnum i1;
+
+Task Func num nFunc1(
+switch s1
+|switch s2
+,num n1
+,bool b1)
+Var num nVar;
+If Not Present(s1) Return;
+If Present(s1) Then
+Incr n1;'
+ElseIf Present(s2) Then
+b1:=false;
+Else
+While n1>0 Do
+Decr n1;
+Test n1
+
+Case 1:
+test1;
+Case 2:
+test2;
+Default:
+WaitUntil false;
+EndTest
+EndWhile
+EndIf
+For i From 1 To 10 Step 2 Do
+For j From 1 To 10 Do
+st_Appl_Info{i,j} := "";
+EndFor
+EndFor
+! Return 1;
+Return 0;
+Error
+Return -1;
+EndFunc
+
+Trap Trap1
+Reset do1;
+EndTrap
+
+EndModule
+
+! END_INDENT
+
+! START_INDENT
+! INDENT_EXE let g:rapidSpaceIndent = 0
+! INDENT_EXE set shiftwidth=4
+
+proc bla()
+var num i;
+Incr i;
+endproc
+
+! END_INDENT
+
+! START_INDENT
+! INDENT_EXE let g:rapidCommentIndent = 1
+!
+proc bla()
+! indent this first column comment because of g:rapidCommentIndent=1
+endproc
+! END_INDENT
+
+! START_INDENT
+! INDENT_EXE let g:rapidNewStyleIndent = 1
+pers string st_Appl_Info{3,3}:=
+[
+[
+"["
+,
+"default"
+,
+"case"
+]
+,
+[
+"else"
+,
+"then"
+,
+"endif"
+]
+,
+[
+"do"
+,
+"}"
+,
+")"
+]
+,
+];
+! END_INDENT
diff --git a/mnv/runtime/indent/testdir/rapid.ok b/mnv/runtime/indent/testdir/rapid.ok
new file mode 100644
index 0000000000..b08d37558d
--- /dev/null
+++ b/mnv/runtime/indent/testdir/rapid.ok
@@ -0,0 +1,266 @@
+! mnv: set ft=rapid :
+
+! START_INDENT
+
+%%%
+VERSION:1
+LANGUAGE:ENGLISH
+%%%
+
+module LowerCaseModule
+
+ task pers num n1 := 0;
+ local pers num n2 := 1;
+ var bool b1 := false;
+ var intnum i1;
+
+! put some stuff in those strings that may confuse indentation
+ const string st1 := "endmodule (";
+ pers string st_Appl_Info{3,3}:=[
+ [
+ "["
+ ,
+ "default"
+ ,
+ "case"
+ ],
+ [
+ "else"
+ ,
+ "then"
+ ,
+ "endif"
+ ],
+ [
+ "do"
+ ,
+ "}"
+ ,
+ ")"
+ ],
+ ];
+
+ pers tooldata tTool1:=[TRUE,
+ [
+ [97.4, 0, 223.1],
+ [0.924, 0, 0.383 ,0]
+ ],
+ [5,
+ [23, 0, 75],
+ [1, 0, 0, 0], 0, 0, 0
+ ]
+ ];
+ const robtarget p1:=[
+ [600, 500, 225.3],
+ [1, 0, 0, 0],
+ [1, 1, 0, 0],
+ [ 11, 12.3, 9E9, 9E9, 9E9, 9E9]
+ ];
+
+ record myRec
+ num nRecNum1
+ bool bRecBool1
+ endrecord
+
+ proc proc1(num n1,
+ num n2)
+ var string st1;
+ n1 := n1+1;
+ MoveJSync p1, vmax, z30, tool1, "proc2";
+ backward
+ MoveJSync p1, v100, fine, tool1, "proc2";
+ undo
+ n1 := n1-1;
+ error
+ trynext;
+ endproc
+
+ func num nFunc1(
+ switch s1
+ |switch s2
+ ,num n1
+ ,bool b1)
+ var num nVar;
+ if not Present(s1) return;
+ if Present(s1) then
+ Incr n1;'
+ elseif Present(s2) then
+ b1:=false;
+ else
+ while n1>0 do
+ Decr n1;
+ test n1
+
+ case 1:
+ test1;
+ case 2:
+ test2;
+ default:
+ WaitUntil false;
+ endtest
+ endwhile
+ endif
+ for i from 1 to 10 step 2 do
+ for j from 1 to 10 do
+ st_Appl_Info{i,j} := "";
+ endfor
+ endfor
+! return 1;
+ return 0;
+ error
+ return -1;
+ endfunc
+
+ trap Trap1
+ Reset do1;
+ endtrap
+
+endmodule
+
+MODULE UpperCaseModule(SYSMODULE,NOSTEPIN)
+ TASK pers num n1 := 0;
+ LOCAL pers num n2 := 1;
+ VAR bool b1 := false;
+ VAR intnum i1;
+
+ LOCAL FUNC num nFunc1(
+ switch s1
+ |switch s2
+ ,num n1
+ ,bool b1)
+ VAR num nVar;
+ IF NOT PRESENT(s1) RETURN;
+ IF PRESENT(s1) THEN
+ INCR n1;'
+ ELSEIF PRESENT(s2) THEN
+ b1:=FALSE;
+ ELSE
+ WHILE n1>0 DO
+ DECR n1;
+ TEST n1
+
+ CASE 1:
+ test1;
+ CASE 2:
+ test2;
+ DEFAULT:
+ WAITUNTIL FALSE;
+ ENDTEST
+ ENDWHILE
+ ENDIF
+ FOR i FROM 1 TO 10 STEP 2 DO
+ FOR j FROM 1 TO 10 DO
+ st_Appl_Info{i,j} := "";
+ ENDFOR
+ ENDFOR
+! RETURN 1;
+ RETURN 0;
+ ERROR
+ RETURN -1;
+ ENDFUNC
+
+ TRAP Trap1
+ Reset do1;
+ ENDTRAP
+
+ENDMODULE
+
+Module MixedCaseModule(SysModule)
+ Task pers num n1 := 0;
+ Local pers num n2 := 1;
+ Var bool b1 := false;
+ Var intnum i1;
+
+ Task Func num nFunc1(
+ switch s1
+ |switch s2
+ ,num n1
+ ,bool b1)
+ Var num nVar;
+ If Not Present(s1) Return;
+ If Present(s1) Then
+ Incr n1;'
+ ElseIf Present(s2) Then
+ b1:=false;
+ Else
+ While n1>0 Do
+ Decr n1;
+ Test n1
+
+ Case 1:
+ test1;
+ Case 2:
+ test2;
+ Default:
+ WaitUntil false;
+ EndTest
+ EndWhile
+ EndIf
+ For i From 1 To 10 Step 2 Do
+ For j From 1 To 10 Do
+ st_Appl_Info{i,j} := "";
+ EndFor
+ EndFor
+! Return 1;
+ Return 0;
+ Error
+ Return -1;
+ EndFunc
+
+ Trap Trap1
+ Reset do1;
+ EndTrap
+
+EndModule
+
+! END_INDENT
+
+! START_INDENT
+! INDENT_EXE let g:rapidSpaceIndent = 0
+! INDENT_EXE set shiftwidth=4
+
+proc bla()
+ var num i;
+ Incr i;
+endproc
+
+! END_INDENT
+
+! START_INDENT
+! INDENT_EXE let g:rapidCommentIndent = 1
+!
+proc bla()
+ ! indent this first column comment because of g:rapidCommentIndent=1
+endproc
+! END_INDENT
+
+! START_INDENT
+! INDENT_EXE let g:rapidNewStyleIndent = 1
+pers string st_Appl_Info{3,3}:=
+[
+ [
+ "["
+ ,
+ "default"
+ ,
+ "case"
+ ]
+ ,
+ [
+ "else"
+ ,
+ "then"
+ ,
+ "endif"
+ ]
+ ,
+ [
+ "do"
+ ,
+ "}"
+ ,
+ ")"
+ ]
+ ,
+];
+! END_INDENT
diff --git a/mnv/runtime/indent/testdir/runtest.mnv b/mnv/runtime/indent/testdir/runtest.mnv
new file mode 100644
index 0000000000..60b6b0183d
--- /dev/null
+++ b/mnv/runtime/indent/testdir/runtest.mnv
@@ -0,0 +1,146 @@
+" Runs all the indent tests for which there is no .out file.
+"
+" Current directory must be runtime/indent.
+
+" Only do this with the +eval feature.
+if 1
+
+set nocp
+filetype indent on
+syn on
+set nowrapscan
+set report=9999
+set modeline
+set debug=throw
+set nomore
+
+au! SwapExists * call HandleSwapExists()
+func HandleSwapExists()
+ " Ignore finding a swap file for the test input and output, the user might be
+ " editing them and that's OK.
+ if expand('<afile>') =~ '.*\.\%(in\|out\|fail\|ok\)'
+ let v:swapchoice = 'e'
+ endif
+endfunc
+
+let failed_count = 0
+for fname in glob('testdir/*.in', 1, 1)
+ let root = substitute(fname, '\.in', '', '')
+
+ " Execute the test if the .out file does not exist of when the .in file is
+ " newer.
+ let in_time = getftime(fname)
+ let out_time = getftime(root .. '.out')
+ if out_time < 0 || in_time > out_time
+ call delete(root .. '.fail')
+ call delete(root .. '.out')
+
+ set sw& ts& filetype=
+ exe 'split ' .. fname
+
+ let did_some = 0
+ let failed = 0
+ let end = 1
+ while 1
+ " Indent all the lines between "START_INDENT" and "END_INDENT".
+ exe end
+ let start = search('\<START_INDENT\>')
+ let end = search('\<END_INDENT\>')
+ if start <= 0 || end <= 0 || end <= start
+ if did_some == 0
+ call append(0, 'ERROR: START_INDENT and/or END_INDENT not found')
+ let failed = 1
+ endif
+ break
+ else
+ let did_some = 1
+
+ " Execute all commands marked with INDENT_EXE and find any pattern.
+ let lnum = start
+ let pattern = ''
+ let at = ''
+ while 1
+ exe lnum + 1
+ let lnum_exe = search('\<INDENT_EXE\>')
+ exe lnum + 1
+ let indent_at = search('\<INDENT_\%(AT\|NEXT\|PREV\)\>')
+ if lnum_exe > 0 && lnum_exe < end && (indent_at <= 0 || lnum_exe < indent_at)
+ exe substitute(getline(lnum_exe), '.*INDENT_EXE', '', '')
+ let lnum = lnum_exe
+ let start = lnum
+ elseif indent_at > 0 && indent_at < end
+ if pattern != ''
+ call append(indent_at, 'ERROR: duplicate pattern')
+ let failed = 1
+ break
+ endif
+ let text = getline(indent_at)
+ let pattern = substitute(text, '.*INDENT_\S*\s*', '', '')
+ let at = substitute(text, '.*INDENT_\(\S*\).*', '\1', '')
+ let lnum = indent_at
+ let start = lnum
+ else
+ break
+ endif
+ endwhile
+
+ exe start + 1
+ if pattern == ''
+ try
+ exe 'normal =' .. (end - 1) .. 'G'
+ catch
+ call append(indent_at, 'ERROR: ' .. v:exception)
+ let failed = 1
+ endtry
+ else
+ let lnum = search(pattern)
+ if lnum <= 0
+ call append(indent_at, 'ERROR: pattern not found: ' .. pattern)
+ let failed = 1
+ break
+ endif
+ if at == 'AT'
+ exe lnum
+ elseif at == 'NEXT'
+ exe lnum + 1
+ else
+ exe lnum - 1
+ endif
+ try
+ normal ==
+ catch
+ call append(indent_at, 'ERROR: ' .. v:exception)
+ let failed = 1
+ endtry
+ endif
+ endif
+ endwhile
+
+ if !failed
+ " Check the resulting text equals the .ok file.
+ if getline(1, '$') != readfile(root .. '.ok')
+ let failed = 1
+ endif
+ endif
+
+ if failed
+ let failed_count += 1
+ silent exe 'write ' .. root .. '.fail'
+ echoerr 'Test ' .. fname .. ' FAILED!'
+ else
+ silent exe 'write ' .. root .. '.out'
+ echo "Test " .. fname .. " OK\n"
+ endif
+
+ quit! " Close the indented file.
+ endif
+endfor
+
+" Matching "if 1" at the start.
+endif
+
+if failed_count > 0
+ " Have make report an error.
+ cquit
+endif
+qall!
diff --git a/mnv/runtime/indent/testdir/rust.in b/mnv/runtime/indent/testdir/rust.in
new file mode 100644
index 0000000000..3b3e42329c
--- /dev/null
+++ b/mnv/runtime/indent/testdir/rust.in
@@ -0,0 +1,50 @@
+// mnv: set ft=rust ts=8 sw=4 sts=4 et :
+// START_INDENT
+use std::fs::File;
+use std::io::prelude::*;
+use std::path::Path;
+
+fn main() {
+ // Create a path to the desired file
+ let path = Path::new("hello.txt");
+ let display = path.display();
+
+ // Open the path in read-only mode, returns `io::Result<File>`
+ let mut file = match File::open(&path) {
+ Err(why) => panic!("couldn't open {}: {}", display, why),
+ Ok(file) => file,
+ };
+
+ // Start doing nothing forever
+ loop {
+ let arr1 = [[u8; 4]; 2] = [
+ [0; 4],
+ [1, 3, 5, 9],
+ ];
+ }
+
+ // Plan for a future that will never come
+ let arr2 = [[u8; 4]; 2] = [
+ [1; 4],
+ [2, 4, 6, 8],
+ ];
+ let arr2_ref = &arr2;
+
+ // Read the file contents into a string, returns `io::Result<usize>`
+ let mut s = String::new();
+ match file.read_to_string(&mut s) {
+ Err(why) => panic!("couldn't read {}: {}", display, why),
+ Ok(_) => print!("{} contains:\n{}", display, s),
+ }
+
+ // file goes out of scope, and the "hello.txt" file gets closed
+}
+// END_INDENT
+
+// START_INDENT
+let x = "
+ if fn motif
+ ";
+ struct X {
+ }
+// END_INDENT
diff --git a/mnv/runtime/indent/testdir/rust.ok b/mnv/runtime/indent/testdir/rust.ok
new file mode 100644
index 0000000000..df82f4f1c4
--- /dev/null
+++ b/mnv/runtime/indent/testdir/rust.ok
@@ -0,0 +1,50 @@
+// mnv: set ft=rust ts=8 sw=4 sts=4 et :
+// START_INDENT
+use std::fs::File;
+use std::io::prelude::*;
+use std::path::Path;
+
+fn main() {
+ // Create a path to the desired file
+ let path = Path::new("hello.txt");
+ let display = path.display();
+
+ // Open the path in read-only mode, returns `io::Result<File>`
+ let mut file = match File::open(&path) {
+ Err(why) => panic!("couldn't open {}: {}", display, why),
+ Ok(file) => file,
+ };
+
+ // Start doing nothing forever
+ loop {
+ let arr1 = [[u8; 4]; 2] = [
+ [0; 4],
+ [1, 3, 5, 9],
+ ];
+ }
+
+ // Plan for a future that will never come
+ let arr2 = [[u8; 4]; 2] = [
+ [1; 4],
+ [2, 4, 6, 8],
+ ];
+ let arr2_ref = &arr2;
+
+ // Read the file contents into a string, returns `io::Result<usize>`
+ let mut s = String::new();
+ match file.read_to_string(&mut s) {
+ Err(why) => panic!("couldn't read {}: {}", display, why),
+ Ok(_) => print!("{} contains:\n{}", display, s),
+ }
+
+ // file goes out of scope, and the "hello.txt" file gets closed
+}
+// END_INDENT
+
+// START_INDENT
+let x = "
+ if fn motif
+ ";
+ struct X {
+}
+// END_INDENT
diff --git a/mnv/runtime/indent/testdir/sshconfig.in b/mnv/runtime/indent/testdir/sshconfig.in
new file mode 100644
index 0000000000..defa2a26ca
--- /dev/null
+++ b/mnv/runtime/indent/testdir/sshconfig.in
@@ -0,0 +1,53 @@
+# mnv: set filetype=sshconfig shiftwidth=4 expandtab :
+
+# START_INDENT
+Host myhost
+User myuser
+PasswordAuthentication no
+# END_INDENT
+
+# START_INDENT
+Host aaa
+User bbb
+Host ccc
+Host ddd
+# END_INDENT
+
+# START_INDENT
+host aaa
+HOST bbb
+hoSt ccc
+match ddd
+MATCH eee
+MatCH fff
+# END_INDENT
+
+# START_INDENT
+Host aaa
+User host
+PasswordAuthentication no
+Host *
+User user
+PasswordAuthentication no
+Host match
+User bbb
+# END_INDENT
+
+# START_INDENT
+Host tab
+User myuser
+# END_INDENT
+
+# START_INDENT
+Host mix
+User myuser
+# END_INDENT
+
+# START_INDENT
+Host aaa
+User bbb
+Match ccc
+User ddd
+HostKeyAlgorithms ssh-ed25519
+Match eee
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/sshconfig.ok b/mnv/runtime/indent/testdir/sshconfig.ok
new file mode 100644
index 0000000000..6efa10c763
--- /dev/null
+++ b/mnv/runtime/indent/testdir/sshconfig.ok
@@ -0,0 +1,53 @@
+# mnv: set filetype=sshconfig shiftwidth=4 expandtab :
+
+# START_INDENT
+Host myhost
+ User myuser
+ PasswordAuthentication no
+# END_INDENT
+
+# START_INDENT
+Host aaa
+ User bbb
+Host ccc
+Host ddd
+# END_INDENT
+
+# START_INDENT
+host aaa
+HOST bbb
+hoSt ccc
+match ddd
+MATCH eee
+MatCH fff
+# END_INDENT
+
+# START_INDENT
+Host aaa
+ User host
+ PasswordAuthentication no
+Host *
+ User user
+ PasswordAuthentication no
+Host match
+ User bbb
+# END_INDENT
+
+# START_INDENT
+Host tab
+ User myuser
+# END_INDENT
+
+# START_INDENT
+Host mix
+ User myuser
+# END_INDENT
+
+# START_INDENT
+Host aaa
+ User bbb
+Match ccc
+ User ddd
+ HostKeyAlgorithms ssh-ed25519
+Match eee
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/tcl.in b/mnv/runtime/indent/testdir/tcl.in
new file mode 100644
index 0000000000..a1caccfd4e
--- /dev/null
+++ b/mnv/runtime/indent/testdir/tcl.in
@@ -0,0 +1,19 @@
+# mnv: set filetype=tcl shiftwidth=4 tabstop=8 expandtab :
+
+# START_INDENT
+proc abc {} {
+set a 5
+if {[some_cmd]==1} {
+foreach i [list {1 2 3}] {
+# Does this comment affect anything?
+puts $i
+}
+}
+}
+
+command_with_a_long_time -arg1 "First" \
+-arg2 "Second" \
+-arg3 "Third"
+
+puts "Move indent back after line continuation is complete"
+# END_INDENT \ No newline at end of file
diff --git a/mnv/runtime/indent/testdir/tcl.ok b/mnv/runtime/indent/testdir/tcl.ok
new file mode 100644
index 0000000000..4cd3228836
--- /dev/null
+++ b/mnv/runtime/indent/testdir/tcl.ok
@@ -0,0 +1,19 @@
+# mnv: set filetype=tcl shiftwidth=4 tabstop=8 expandtab :
+
+# START_INDENT
+proc abc {} {
+ set a 5
+ if {[some_cmd]==1} {
+ foreach i [list {1 2 3}] {
+ # Does this comment affect anything?
+ puts $i
+ }
+ }
+}
+
+command_with_a_long_time -arg1 "First" \
+ -arg2 "Second" \
+ -arg3 "Third"
+
+puts "Move indent back after line continuation is complete"
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/thrift.in b/mnv/runtime/indent/testdir/thrift.in
new file mode 100644
index 0000000000..6d4f6ae4da
--- /dev/null
+++ b/mnv/runtime/indent/testdir/thrift.in
@@ -0,0 +1,38 @@
+// mnv: set ft=thrift sw=4 et:
+
+# START_INDENT
+namespace cpp foo
+namespace java com.foo.thrift
+
+include "Status.thrift"
+
+// These are supporting structs for JniFrontend.java, which serves as the glue
+// between our C++ execution environment and the Java frontend.
+
+struct TSetSessionParams {
+ 1: required string user
+}
+
+struct TAuthenticateParams {
+ 1: required string user
+ 2: required string passwd
+ 3: optional string host
+4: optional string db_name
+ 5: optional list<string> table_names;
+}
+
+/* {
+ * xxxx
+ * }
+ */
+// TColumnDesc
+struct TColumnDesc {
+ // {
+4: optional string tableName
+5: optional string columnDefault
+ // Let FE control the type, which makes it easier to modify and display complex types
+6: optional string columnTypeStr // deprecated
+7: optional string dataType
+ // }
+}
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/thrift.ok b/mnv/runtime/indent/testdir/thrift.ok
new file mode 100644
index 0000000000..6c96cc8491
--- /dev/null
+++ b/mnv/runtime/indent/testdir/thrift.ok
@@ -0,0 +1,38 @@
+// mnv: set ft=thrift sw=4 et:
+
+# START_INDENT
+namespace cpp foo
+namespace java com.foo.thrift
+
+include "Status.thrift"
+
+// These are supporting structs for JniFrontend.java, which serves as the glue
+// between our C++ execution environment and the Java frontend.
+
+struct TSetSessionParams {
+ 1: required string user
+}
+
+struct TAuthenticateParams {
+ 1: required string user
+ 2: required string passwd
+ 3: optional string host
+ 4: optional string db_name
+ 5: optional list<string> table_names;
+}
+
+/* {
+ * xxxx
+ * }
+ */
+// TColumnDesc
+struct TColumnDesc {
+ // {
+ 4: optional string tableName
+ 5: optional string columnDefault
+ // Let FE control the type, which makes it easier to modify and display complex types
+ 6: optional string columnTypeStr // deprecated
+ 7: optional string dataType
+ // }
+}
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/tools/tracer.mnv b/mnv/runtime/indent/testdir/tools/tracer.mnv
new file mode 100644
index 0000000000..74dfc05495
--- /dev/null
+++ b/mnv/runtime/indent/testdir/tools/tracer.mnv
@@ -0,0 +1,166 @@
+mnv9script
+
+# Whenever indent plugins contain "search*()" lines explicitly annotated with
+# "MNV_INDENT_TEST_TRACE_(START|END)" comment markers; this script can then be
+# used as shown to measure and record elapsed time for such decorated calls.
+#
+# Usage:
+# cd runtime/indent
+# mnv -u NONE -S testdir/tools/tracer.mnv \
+# html.mnv javascript.mnv \
+# ../autoload/python.mnv ../autoload/dist/mnvindent.mnv
+# git diff
+# make clean test
+# mnv testdir/00-TRACE_LOG.fail
+
+def GenerateTempletForTracing(fname: string, vname: string): list<string>
+ #### ONLY INSTRUMENT "search*()"es FOR INDENT TESTS.
+
+ const templet: list<string> =<< trim eval END
+
+ if getcwd() =~# '\<runtime/indent$'
+
+ def! g:IndentTestTrace(id: string, start: list<number>, result: any): any
+ const end: list<number> = reltime(start)
+
+ if !has_key(g:indent_test_trace_times, id)
+ g:indent_test_trace_times[id] = []
+ endif
+
+ g:indent_test_trace_times[id]
+ ->add(reltimefloat(end))
+ return result
+ enddef
+
+ def! g:IndentTestInitTracing()
+ # Possibly use a later "{fname}", cf. ":runtime indent/foo.mnv".
+ autocmd_add([{{
+ replace: true,
+ group: 'tracing',
+ event: 'QuitPre',
+ bufnr: bufnr(),
+ cmd: 'g:IndentTestWriteTraceTimes()',
+ }}])
+ g:indent_test_trace_times = {{}}
+ enddef
+
+ def! g:IndentTestWriteTraceTimes()
+ # Anticipate usage by multiple languages.
+ const token: string = printf('%02x', (rand() % 26))
+ writefile(['" {fname}:',
+ "let {vname}_" .. token .. " = " .. string(g:indent_test_trace_times),
+ "let {vname}_" .. token .. "_summary = " .. string(g:indent_test_trace_times
+ ->items()
+ ->reduce((outer: dict<dict<any>>, times: list<any>) =>
+ extend({{[times[0]]: times[1]
+ ->copy()
+ ->reduce((inner: dict<any>, v: float) =>
+ extend({{
+ min: inner.min < v ? inner.min : v,
+ max: inner.max > v ? inner.max : v,
+ sum: (inner.sum + v),
+ avg: ((inner.sum + v) / inner.count),
+ }},
+ inner,
+ "keep"),
+ {{
+ min: v:numbermax - 0.0,
+ max: v:numbermin + 0.0,
+ sum: 0.0,
+ avg: 0.0,
+ count: len(times[1]),
+ }})}},
+ outer),
+ {{}}))],
+ (!empty($MNV_INDENT_TEST_LOG) && filewritable($MNV_INDENT_TEST_LOG))
+ ? $MNV_INDENT_TEST_LOG
+ : "testdir/00-TRACE_LOG.fail",
+ "a")
+ enddef
+
+ call g:IndentTestInitTracing()
+
+ else
+
+ def! g:IndentTestTrace(_: string, _: list<number>, result: any): any
+ return result
+ enddef
+
+ endif
+
+ END
+ return templet
+enddef
+
+def InstrumentMarkedEntry(): bool
+ const marker_start: string = 'MNV_INDENT_TEST_TRACE_START'
+ const start: number = search('\C\<' .. marker_start .. '\>', 'ceW')
+
+ if start == 0
+ return false
+ endif
+
+ const marker_end: string = 'MNV_INDENT_TEST_TRACE_END'
+ const end: number = search('\C\<' .. marker_end .. '\>', 'ceW')
+
+ if end == 0
+ return false
+ endif
+
+ const tracee: list<string> = matchlist(
+ getline(start + 1),
+ '\(^.\+\)\(\<search\%(pair\)\=\%(pos\)\=\s*(.*$\)')
+
+ if empty(get(tracee, 1, '')) || empty(get(tracee, 2, ''))
+ return false
+ endif
+
+ const end_line: string = getline(end)
+ const tracer: string = printf('%sg:IndentTestTrace("%s", reltime(), %s',
+ tracee[1],
+ strpart(end_line, (stridx(end_line, marker_end) + strlen(marker_end) + 1)),
+ tracee[2])
+
+ if (end - start) > 1
+ setline((start + 1), tracer)
+ setline((end - 1), getline(end - 1) .. ')')
+ else
+ setline((start + 1), tracer .. ')')
+ endif
+
+ return true
+enddef
+
+def ProcessIndentPluginCmdlineArgs()
+ const names: list<string> = range(char2nr('a'), char2nr('z'))
+ ->map((_: number, n: number) => nr2char(n, true))
+ var entries: number = 0
+ var next: number = 0
+
+ for fname: string in argv(-1)
+ if filereadable(fname) && filewritable(fname)
+ execute 'new ' .. fname
+ call cursor(1, 1)
+
+ while InstrumentMarkedEntry()
+ entries += 1
+ endwhile
+
+ if entries > 0
+ append(1, GenerateTempletForTracing(fname, get(names, next, names[-1])))
+ wq
+ endif
+
+ entries = 0
+ next += 1
+ endif
+ endfor
+enddef
+
+if empty(system('git status --porcelain=v1'))
+ ProcessIndentPluginCmdlineArgs()
+endif
+
+quitall
+
+# mnv:fdm=syntax:sw=2:ts=8:noet:nosta:
diff --git a/mnv/runtime/indent/testdir/vb.in b/mnv/runtime/indent/testdir/vb.in
new file mode 100644
index 0000000000..5fe2cd2bcc
--- /dev/null
+++ b/mnv/runtime/indent/testdir/vb.in
@@ -0,0 +1,176 @@
+' mnv: filetype=vb shiftwidth=4 expandtab
+'
+' START_INDENT
+#Const Debug = False
+
+#If Win64 Then
+' Win64=true, Win32=true, Win16=false
+#ElseIf Win32 Then
+' Win32=true, Win16=false
+#Else
+' Win16=true
+#End If
+
+Public Type GEmployeeRecord ' Create user-defined type.
+ID As Integer ' Define elements of data type.
+Name As String * 20
+Address As String * 30
+Phone As Long
+HireDate As Date
+End Type
+
+Public Enum InterfaceColors
+icMistyRose = &HE1E4FF&
+icSlateGray = &H908070&
+icDodgerBlue = &HFF901E&
+icDeepSkyBlue = &HFFBF00&
+icSpringGreen = &H7FFF00&
+icForestGreen = &H228B22&
+icGoldenrod = &H20A5DA&
+icFirebrick = &H2222B2&
+End Enum
+
+Enum SecurityLevel
+IllegalEntry = -1
+SecurityLevel1 = 0
+SecurityLevel2 = 1
+End Enum
+
+Public Function TestConditional (number As Integer, ext As String) As Boolean
+Dim inRange As Boolean
+
+Select Case number
+Case <= 0
+inRange = False
+Case > 10
+inRange = False
+Case Else
+inRange = True
+End Select
+
+' This is a special case identified in the indent script.
+Select Case number
+End Select
+
+If ext = ".xlm" Then
+If inRange Then
+TestConditional = True
+Else
+TestConditional = False
+End If
+ElseIf ext = ".xlsx" Then
+If inRange Then
+TestConditional = False
+Else
+TestConditional = True
+End If
+Else
+TestConditional = False
+End If
+End Function
+
+Private Sub TestIterators (lLimit As Integer, uLimit As Integer)
+Dim a() As Variant
+Dim elmt As Variant
+Dim found As Boolean
+Dim indx As Integer
+Const specialValue As Integer = 5
+
+If uLimit < lLimit Then
+Exit Sub
+End If
+
+ReDim a(lLimit To uLimit)
+For indx=lLimit To Ulimit
+a(indx) = 2 * indx
+Next indx
+
+found = False
+For Each elmt in a
+If elmt = specialValue Then
+found = True
+End If
+Next elmt
+
+If found then
+indx = uLimit
+Do While indx >= lLimit
+indx = indx - 1
+Loop
+End If
+
+End Sub
+
+Public Sub TestMultiline (cellAddr As String, rowNbr As Long)
+Dim rng As Range
+
+Set rng = Range(cellAddr)
+
+' Line continuation is implemented as a two-character sequence-
+' whitespace followed by underscore.
+With rng
+.Cells(1,1).Value = _
+"Line 1 of multiline string; " & _
+"Line 2 of multiline string; " & _
+"Line 3 of multiline string"
+End With
+
+' This code block omits the leading whitespace character and so
+' the trailing underscore will not be treated as line continuation.
+With rng
+.Cells(1,1).Value =_
+"Line 1 of multiline string; " &_
+"Line 2 of multiline string; " &_
+"Line 3 of multiline string"
+End With
+
+' The following lines have whitespace after the underscore character.
+' This is contrary to Microsoft documentation but it is reported that
+' some Microsoft editors allow it and will still treat the statement
+' as line-continued.
+With rng
+rng.Cells(1,1).Value = _
+"Line 1 of multiline string; " & _
+"Line 2 of multiline string; " & _
+"Line 3 of multiline string"
+End With
+
+End Sub
+
+Private Sub TestStmtLabel()
+GoTo stmtLabel
+
+' Statement labels are never indented
+stmtLabel:
+
+End Sub
+
+Public Static Function TestStatic(addend As Integer)
+Dim Integer accumulator
+accumulator = accumulator + addend
+TestStatic = accumulator
+End Function
+
+Friend Function TestFriend(addend As Integer)
+Static Integer accumulator
+accumulator = accumulator + addend
+TestFriend = accumulator
+End Function
+
+Sub TestTypeKeyword()
+Type EmployeeRecord ' Create user-defined type.
+ID As Integer ' Define elements of data type.
+Name As String * 20
+Address As String * 30
+Phone As Long
+HireDate As Date
+End Type
+Dim varType As EmployeeRecord
+End Sub
+
+Sub TestDateLiteralAfterLineContinuation
+Dim birthday as Date
+birthday = _
+#January 1, 1901#
+End Sub
+' END_INDENT
diff --git a/mnv/runtime/indent/testdir/vb.ok b/mnv/runtime/indent/testdir/vb.ok
new file mode 100644
index 0000000000..13d6b3b6cc
--- /dev/null
+++ b/mnv/runtime/indent/testdir/vb.ok
@@ -0,0 +1,176 @@
+' mnv: filetype=vb shiftwidth=4 expandtab
+'
+' START_INDENT
+#Const Debug = False
+
+#If Win64 Then
+' Win64=true, Win32=true, Win16=false
+#ElseIf Win32 Then
+' Win32=true, Win16=false
+#Else
+' Win16=true
+#End If
+
+Public Type GEmployeeRecord ' Create user-defined type.
+ ID As Integer ' Define elements of data type.
+ Name As String * 20
+ Address As String * 30
+ Phone As Long
+ HireDate As Date
+End Type
+
+Public Enum InterfaceColors
+ icMistyRose = &HE1E4FF&
+ icSlateGray = &H908070&
+ icDodgerBlue = &HFF901E&
+ icDeepSkyBlue = &HFFBF00&
+ icSpringGreen = &H7FFF00&
+ icForestGreen = &H228B22&
+ icGoldenrod = &H20A5DA&
+ icFirebrick = &H2222B2&
+End Enum
+
+Enum SecurityLevel
+ IllegalEntry = -1
+ SecurityLevel1 = 0
+ SecurityLevel2 = 1
+End Enum
+
+Public Function TestConditional (number As Integer, ext As String) As Boolean
+ Dim inRange As Boolean
+
+ Select Case number
+ Case <= 0
+ inRange = False
+ Case > 10
+ inRange = False
+ Case Else
+ inRange = True
+ End Select
+
+ ' This is a special case identified in the indent script.
+ Select Case number
+ End Select
+
+ If ext = ".xlm" Then
+ If inRange Then
+ TestConditional = True
+ Else
+ TestConditional = False
+ End If
+ ElseIf ext = ".xlsx" Then
+ If inRange Then
+ TestConditional = False
+ Else
+ TestConditional = True
+ End If
+ Else
+ TestConditional = False
+ End If
+End Function
+
+Private Sub TestIterators (lLimit As Integer, uLimit As Integer)
+ Dim a() As Variant
+ Dim elmt As Variant
+ Dim found As Boolean
+ Dim indx As Integer
+ Const specialValue As Integer = 5
+
+ If uLimit < lLimit Then
+ Exit Sub
+ End If
+
+ ReDim a(lLimit To uLimit)
+ For indx=lLimit To Ulimit
+ a(indx) = 2 * indx
+ Next indx
+
+ found = False
+ For Each elmt in a
+ If elmt = specialValue Then
+ found = True
+ End If
+ Next elmt
+
+ If found then
+ indx = uLimit
+ Do While indx >= lLimit
+ indx = indx - 1
+ Loop
+ End If
+
+End Sub
+
+Public Sub TestMultiline (cellAddr As String, rowNbr As Long)
+ Dim rng As Range
+
+ Set rng = Range(cellAddr)
+
+ ' Line continuation is implemented as a two-character sequence-
+ ' whitespace followed by underscore.
+ With rng
+ .Cells(1,1).Value = _
+ "Line 1 of multiline string; " & _
+ "Line 2 of multiline string; " & _
+ "Line 3 of multiline string"
+ End With
+
+ ' This code block omits the leading whitespace character and so
+ ' the trailing underscore will not be treated as line continuation.
+ With rng
+ .Cells(1,1).Value =_
+ "Line 1 of multiline string; " &_
+ "Line 2 of multiline string; " &_
+ "Line 3 of multiline string"
+ End With
+
+ ' The following lines have whitespace after the underscore character.
+ ' This is contrary to Microsoft documentation but it is reported that
+ ' some Microsoft editors allow it and will still treat the statement
+ ' as line-continued.
+ With rng
+ rng.Cells(1,1).Value = _
+ "Line 1 of multiline string; " & _
+ "Line 2 of multiline string; " & _
+ "Line 3 of multiline string"
+ End With
+
+End Sub
+
+Private Sub TestStmtLabel()
+ GoTo stmtLabel
+
+ ' Statement labels are never indented
+stmtLabel:
+
+End Sub
+
+Public Static Function TestStatic(addend As Integer)
+ Dim Integer accumulator
+ accumulator = accumulator + addend
+ TestStatic = accumulator
+End Function
+
+Friend Function TestFriend(addend As Integer)
+ Static Integer accumulator
+ accumulator = accumulator + addend
+ TestFriend = accumulator
+End Function
+
+Sub TestTypeKeyword()
+ Type EmployeeRecord ' Create user-defined type.
+ ID As Integer ' Define elements of data type.
+ Name As String * 20
+ Address As String * 30
+ Phone As Long
+ HireDate As Date
+ End Type
+ Dim varType As EmployeeRecord
+End Sub
+
+Sub TestDateLiteralAfterLineContinuation
+ Dim birthday as Date
+ birthday = _
+ #January 1, 1901#
+End Sub
+' END_INDENT
diff --git a/mnv/runtime/indent/testdir/xml.in b/mnv/runtime/indent/testdir/xml.in
new file mode 100644
index 0000000000..bfbc4b3d87
--- /dev/null
+++ b/mnv/runtime/indent/testdir/xml.in
@@ -0,0 +1,32 @@
+<!-- mnv: set ft=xml ts=8 sw=0 sts=-1 et : -->
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+<!-- comment -->
+<tag2>
+ <tag3/>
+</tag2>
+<!-- text comment -->
+
+<!--
+text comment
+-->
+</tag1>
+<!--
+text comment
+end comment -->
+</tag0>
+<!-- END_INDENT -->
+
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+<!-- comment -->
+<tag2>
+ <tag3/>
+</tag2>
+</tag1>
+</tag0>
+<!-- END_INDENT -->
diff --git a/mnv/runtime/indent/testdir/xml.ok b/mnv/runtime/indent/testdir/xml.ok
new file mode 100644
index 0000000000..1fa0c46abc
--- /dev/null
+++ b/mnv/runtime/indent/testdir/xml.ok
@@ -0,0 +1,32 @@
+<!-- mnv: set ft=xml ts=8 sw=0 sts=-1 et : -->
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+ <!-- comment -->
+ <tag2>
+ <tag3/>
+ </tag2>
+ <!-- text comment -->
+
+ <!--
+ text comment
+ -->
+ </tag1>
+ <!--
+ text comment
+ end comment -->
+</tag0>
+<!-- END_INDENT -->
+
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+ <!-- comment -->
+ <tag2>
+ <tag3/>
+ </tag2>
+ </tag1>
+</tag0>
+<!-- END_INDENT -->
diff --git a/mnv/runtime/indent/testdir/yaml.in b/mnv/runtime/indent/testdir/yaml.in
new file mode 100644
index 0000000000..08b5588443
--- /dev/null
+++ b/mnv/runtime/indent/testdir/yaml.in
@@ -0,0 +1,39 @@
+# mnv: set ft=yaml sw=2 et :
+
+# START_INDENT
+map1:
+sub1:
+- list item
+map2:
+- another list
+# END_INDENT
+
+# START_INDENT
+map: &anchor
+map: val
+# END_INDENT
+
+# START_INDENT
+map: |
+line1
+line2
+# END_INDENT
+
+# START_INDENT
+list:
+ - element1:
+ foo: bar
+ - element2:
+ foo: bar
+# END_INDENT
+
+# START_INDENT
+- name: test playbook
+ hosts: localhost
+ gather_facts: false
+
+ tasks:
+ - name: hello world
+ ansible.builtin.debug:
+ msg: "hello world"
+# END_INDENT
diff --git a/mnv/runtime/indent/testdir/yaml.ok b/mnv/runtime/indent/testdir/yaml.ok
new file mode 100644
index 0000000000..cbdf745a8d
--- /dev/null
+++ b/mnv/runtime/indent/testdir/yaml.ok
@@ -0,0 +1,39 @@
+# mnv: set ft=yaml sw=2 et :
+
+# START_INDENT
+map1:
+ sub1:
+ - list item
+map2:
+ - another list
+# END_INDENT
+
+# START_INDENT
+map: &anchor
+map: val
+# END_INDENT
+
+# START_INDENT
+map: |
+ line1
+ line2
+# END_INDENT
+
+# START_INDENT
+list:
+ - element1:
+ foo: bar
+ - element2:
+ foo: bar
+# END_INDENT
+
+# START_INDENT
+- name: test playbook
+ hosts: localhost
+ gather_facts: false
+
+ tasks:
+ - name: hello world
+ ansible.builtin.debug:
+ msg: "hello world"
+# END_INDENT