Commit 42d24fa2607df63aacfc7dbdcc99b458d4656cf2

edukisto 2021-03-02T13:03:17

INI: Consistently mimic Win32 INI parsing (#2779)

diff --git a/components/prism-ini.js b/components/prism-ini.js
index c7b45a8..e950caf 100644
--- a/components/prism-ini.js
+++ b/components/prism-ini.js
@@ -1,11 +1,42 @@
 Prism.languages.ini= {
-	'comment': /^[ \t]*[;#].*$/m,
-	'selector': /^[ \t]*\[.*?\]/m,
-	'constant': /^[ \t]*[^\s=]+?(?=[ \t]*=)/m,
-	'attr-value': {
-		pattern: /=.*/,
+
+	/**
+	 * The component mimics the behavior of the Win32 API parser.
+	 *
+	 * @see {@link https://github.com/PrismJS/prism/issues/2775#issuecomment-787477723}
+	 */
+
+	'comment': {
+		pattern: /(^[ \f\t\v]*)[#;][^\n\r]*/m,
+		lookbehind: true
+	},
+	'header': {
+		pattern: /(^[ \f\t\v]*)\[[^\n\r\]]*\]?/m,
+		lookbehind: true,
 		inside: {
-			'punctuation': /^[=]/
+			'section-name': {
+				pattern: /(^\[[ \f\t\v]*)[^ \f\t\v\]]+(?:[ \f\t\v]+[^ \f\t\v\]]+)*/,
+				lookbehind: true,
+				alias: 'selector'
+			},
+			'punctuation': /\[|\]/
 		}
-	}
+	},
+	'key': {
+		pattern: /(^[ \f\t\v]*)[^ \f\n\r\t\v=]+(?:[ \f\t\v]+[^ \f\n\r\t\v=]+)*(?=[ \f\t\v]*=)/m,
+		lookbehind: true,
+		alias: 'attr-name'
+	},
+	'value': {
+		pattern: /(=[ \f\t\v]*)[^ \f\n\r\t\v]+(?:[ \f\t\v]+[^ \f\n\r\t\v]+)*/,
+		lookbehind: true,
+		alias: 'attr-value',
+		inside: {
+			'inner-value': {
+				pattern: /^("|').+(?=\1$)/,
+				lookbehind: true
+			}
+		}
+	},
+	'punctuation': /=/
 };
diff --git a/components/prism-ini.min.js b/components/prism-ini.min.js
index 620cdb5..a4e2d8e 100644
--- a/components/prism-ini.min.js
+++ b/components/prism-ini.min.js
@@ -1 +1 @@
-Prism.languages.ini={comment:/^[ \t]*[;#].*$/m,selector:/^[ \t]*\[.*?\]/m,constant:/^[ \t]*[^\s=]+?(?=[ \t]*=)/m,"attr-value":{pattern:/=.*/,inside:{punctuation:/^[=]/}}};
\ No newline at end of file
+Prism.languages.ini={comment:{pattern:/(^[ \f\t\v]*)[#;][^\n\r]*/m,lookbehind:!0},header:{pattern:/(^[ \f\t\v]*)\[[^\n\r\]]*\]?/m,lookbehind:!0,inside:{"section-name":{pattern:/(^\[[ \f\t\v]*)[^ \f\t\v\]]+(?:[ \f\t\v]+[^ \f\t\v\]]+)*/,lookbehind:!0,alias:"selector"},punctuation:/\[|\]/}},key:{pattern:/(^[ \f\t\v]*)[^ \f\n\r\t\v=]+(?:[ \f\t\v]+[^ \f\n\r\t\v=]+)*(?=[ \f\t\v]*=)/m,lookbehind:!0,alias:"attr-name"},value:{pattern:/(=[ \f\t\v]*)[^ \f\n\r\t\v]+(?:[ \f\t\v]+[^ \f\n\r\t\v]+)*/,lookbehind:!0,alias:"attr-value",inside:{"inner-value":{pattern:/^("|').+(?=\1$)/,lookbehind:!0}}},punctuation:/=/};
\ No newline at end of file
diff --git a/tests/languages/ini/comment_feature.test b/tests/languages/ini/comment_feature.test
index 30e373c..48e1d39 100644
--- a/tests/languages/ini/comment_feature.test
+++ b/tests/languages/ini/comment_feature.test
@@ -1,15 +1,50 @@
-;
-; foobar
-# foobar
-
-----------------------------------------------------
-
-[
-	["comment", ";"],
-	["comment", "; foobar"],
-	["comment", "# foobar"]
-]
-
-----------------------------------------------------
-
-Checks for comments.
+	#
+	;
+ #
+ ;
+#
+#	
+# 
+#;
+#[foo]
+#foo=bar
+#foobar
+;
+;	
+; 
+;#
+;[foo]
+;foo=bar
+;foobar
+foo#bar
+foobar#
+foo;bar
+foobar;
+
+----------------------------------------------------
+
+[
+	["comment", "#"],
+	["comment", ";"],
+	["comment", "#"],
+	["comment", ";"],
+	["comment", "#"],
+	["comment", "#\t"],
+	["comment", "# "],
+	["comment", "#;"],
+	["comment", "#[foo]"],
+	["comment", "#foo=bar"],
+	["comment", "#foobar"],
+	["comment", ";"],
+	["comment", ";\t"],
+	["comment", "; "],
+	["comment", ";#"],
+	["comment", ";[foo]"],
+	["comment", ";foo=bar"],
+	["comment", ";foobar"],
+	"\nfoo#bar\nfoobar#\nfoo;bar\nfoobar;"
+]
+
+----------------------------------------------------
+
+Checks for comments.
diff --git a/tests/languages/ini/header_feature.test b/tests/languages/ini/header_feature.test
new file mode 100644
index 0000000..9f0df51
--- /dev/null
+++ b/tests/languages/ini/header_feature.test
@@ -0,0 +1,86 @@
+ [foo1] 
+[ "foo2" ]
+[ foo3 ]
+[" foo4 "]
+["foo5 bar5"]
+["foo6"]
+[foo7
+[foo8 bar8]
+[foo9[bar9]
+[foo10]
+[foo11]bar11]
+
+----------------------------------------------------
+
+[
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo1"],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "\"foo2\""],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo3"],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "\" foo4 \""],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "\"foo5 bar5\""],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "\"foo6\""],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo7"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo8 bar8"],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo9[bar9"],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo10"],
+		["punctuation", "]"]
+	]],
+
+	["header", [
+		["punctuation", "["],
+		["section-name", "foo11"],
+		["punctuation", "]"]
+	]],
+
+	"bar11]"
+]
+
+----------------------------------------------------
+
+Checks for headers (and section names).
diff --git a/tests/languages/ini/key_value_feature.test b/tests/languages/ini/key_value_feature.test
index 5d25d9d..f39988b 100644
--- a/tests/languages/ini/key_value_feature.test
+++ b/tests/languages/ini/key_value_feature.test
@@ -1,21 +1,69 @@
-foo=Bar Baz
-foobar=42
-
-----------------------------------------------------
-
-[
-	["constant", "foo"],
-	["attr-value", [
-		["punctuation", "="],
-		"Bar Baz"
-	]],
-	["constant", "foobar"],
-	["attr-value", [
-		["punctuation", "="],
-		"42"
-	]]
-]
-
-----------------------------------------------------
-
-Checks for key/value pairs.
\ No newline at end of file
+	bar1	=
+ "bar2" =
+ 'bar3' =
+ bar4 =
+" bar5 "=
+"bar6"=
+' bar7 '=
+'bar8'=
+=	baz9	
+= "baz10" 
+= 'baz11' 
+= baz12 
+=" baz13 "
+="b14"a14"z14"
+="baz15"
+="baz16
+=' baz17 '
+='baz18'
+=b19"a19"z19
+=b20"az20
+=ba21"z21
+=baz22
+=baz23"
+bar24
+bar25 baz25=qux25
+bar26=
+bar27==baz27
+bar28=baz28
+bar29=baz29 qux29
+bar30=baz30=qux30
+
+----------------------------------------------------
+
+[
+	["key", "bar1"], ["punctuation", "="],
+	["key", "\"bar2\""], ["punctuation", "="],
+	["key", "'bar3'"], ["punctuation", "="],
+	["key", "bar4"], ["punctuation", "="],
+	["key", "\" bar5 \""], ["punctuation", "="],
+	["key", "\"bar6\""], ["punctuation", "="],
+	["key", "' bar7 '"], ["punctuation", "="],
+	["key", "'bar8'"], ["punctuation", "="],
+	["punctuation", "="], ["value", ["baz9"]],
+	["punctuation", "="], ["value", ["\"", ["inner-value", "baz10"], "\""]],
+	["punctuation", "="], ["value", ["'", ["inner-value", "baz11"], "'"]],
+	["punctuation", "="], ["value", ["baz12"]],
+	["punctuation", "="], ["value", ["\"", ["inner-value", " baz13 "], "\""]],
+	["punctuation", "="], ["value", ["\"", ["inner-value", "b14\"a14\"z14"], "\""]],
+	["punctuation", "="], ["value", ["\"", ["inner-value", "baz15"], "\""]],
+	["punctuation", "="], ["value", ["\"baz16"]],
+	["punctuation", "="], ["value", ["'", ["inner-value", " baz17 "], "'"]],
+	["punctuation", "="], ["value", ["'", ["inner-value", "baz18"], "'"]],
+	["punctuation", "="], ["value", ["b19\"a19\"z19"]],
+	["punctuation", "="], ["value", ["b20\"az20"]],
+	["punctuation", "="], ["value", ["ba21\"z21"]],
+	["punctuation", "="], ["value", ["baz22"]],
+	["punctuation", "="], ["value", ["baz23\""]],
+	"\nbar24\n",
+	["key", "bar25 baz25"], ["punctuation", "="], ["value", ["qux25"]],
+	["key", "bar26"], ["punctuation", "="],
+	["key", "bar27"], ["punctuation", "="], ["value", ["=baz27"]],
+	["key", "bar28"], ["punctuation", "="], ["value", ["baz28"]],
+	["key", "bar29"], ["punctuation", "="], ["value", ["baz29 qux29"]],
+	["key", "bar30"], ["punctuation", "="], ["value", ["baz30=qux30"]]
+]
+
+----------------------------------------------------
+
+Checks for key-value pairs.
diff --git a/tests/languages/ini/punctuation_feature.test b/tests/languages/ini/punctuation_feature.test
new file mode 100644
index 0000000..c72a16d
--- /dev/null
+++ b/tests/languages/ini/punctuation_feature.test
@@ -0,0 +1,11 @@
+=
+
+----------------------------------------------------
+
+[
+	["punctuation", "="]
+]
+
+----------------------------------------------------
+
+Checks for punctuation marks.
diff --git a/tests/languages/ini/selector_feature.test b/tests/languages/ini/selector_feature.test
deleted file mode 100644
index 3158a66..0000000
--- a/tests/languages/ini/selector_feature.test
+++ /dev/null
@@ -1,13 +0,0 @@
-[owner]
-[foobar]
-
-----------------------------------------------------
-
-[
-	["selector", "[owner]"],
-	["selector", "[foobar]"]
-]
-
-----------------------------------------------------
-
-Checks for section titles.
\ No newline at end of file