Skip to content

Commit bab8ccd

Browse files
deathaxeFichteFoll
andauthored
[JavaScript] Code and Data specific indentation rules (#4015)
* [JavaScript] Exclude mappings from normal keyword indentation Fixes https://forum.sublimetext.com/t/sublime-text-on-the-word-default/72953 This commit applies dedicated (json) indentation rules to JavaScript mappings to avoid unexpected (un-)indenting of keys, which look like reserved control structure keywords (e.g.: case, default, if, else, ...). * [JavaScript] Exclude lists from normal keyword indentation Same as for mappings, is true for lists. They can contain otherwise reserved words, which should not be treated by indentation rules. * [JavaScript] Add key binding for bracket content auto-indentation This commit applies a key binding from JSON package to auto-indent content of lists when hitting enter var = [|] becomes: var = [ | ] * [JavaScript] Handle function calls in mappings or lists This commit... 1. extends selectors for each syntax (JS, JSX, TS, TSX) to choose correct indentation rules in nested mappings, lists or functions/lambdas. 2. Adds check for trailing `:` to case/default indentation rule patterns, as a function called `case()` in a mapping can't be prevented from being unindented via selectors. * [JavaScript] Reorganize tests Merge new tests into existing file * [JavaScript] Add tests for embedded JS code blocks * [JavaScript] Remove failing tests As we need to expect `:` after case/default, those tests no longer work by intent. * [JavaScript] Rename indentation rules file * [JavaScript] Improve indentation rules of tagged template strings This commit... 1. fixes lines after single-line tagged template string being indented. before: var foo = html`<p>content</p>`; var bar = html`<p>content</p>`; var baz = html`<p>content</p>`: after: var foo = html`<p>content</p>`; var bar = html`<p>content</p>`; var baz = html`<p>content</p>`: 2. excludes content of plain string templates from auto-indentation. As their kind of content is undefined, normal indentation rules may cause false results. Tests are added to ensure normal JS statements keep untreated. Notes: First and last line of tagged templates is scoped `string.quoted.other` regardless of embedded syntax highlighting, if only opening or closing backticks appear. Hence increasing indentation of tagged template strings' content is handled by "Indentation Rules - Template Strings". Decreasing indentation of closing backtick is handled by normal "Indentation Rules" as those are the ones applied by ST. It just doesn't work otherwise. This circumstance helps to reliably distinguish opening and closing backticks and correctly in- or decrease indentation. * [JavaScript] Tweak key binding context key order This commit aligns this PR with #4022. * [JavaScript] Tweak enter key binding This commit changes `enter` key binding to "Add Line in Braces" macro, as it indents line between backticks using indentation rules instead of forcing it to be indented via `\t`. This works also, if indentation rules decide not to indent backticked contents. * [JavaScript] Simplify indentation rules By utilizing the improved selector scoring of build 4173, we can simply have the two rules override each other based on the last meta scope on the stack. --------- Co-authored-by: FichteFoll <[email protected]>
1 parent 00afce9 commit bab8ccd

7 files changed

+368
-14
lines changed

JavaScript/Default.sublime-keymap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,24 @@
6969
{ "key": "selector", "operand": "meta.string.template.js", "match_all": true }
7070
]
7171
},
72+
73+
// Add indented line in square brackets
74+
{ "keys": ["enter"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Add Line in Braces.sublime-macro"}, "context":
75+
[
76+
{ "key": "setting.auto_indent" },
77+
{ "key": "selection_empty", "match_all": true },
78+
{ "key": "selector", "operand": "source.js, source.jsx, source.ts, source.tsx" },
79+
{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true },
80+
{ "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true }
81+
]
82+
},
83+
{ "keys": ["keypad_enter"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Add Line in Braces.sublime-macro"}, "context":
84+
[
85+
{ "key": "setting.auto_indent" },
86+
{ "key": "selection_empty", "match_all": true },
87+
{ "key": "selector", "operand": "source.js, source.jsx, source.ts, source.tsx" },
88+
{ "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true },
89+
{ "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true }
90+
]
91+
},
7292
]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<plist version="1.0">
3+
<dict>
4+
<key>scope</key>
5+
<string>string.quoted.other.js</string>
6+
<key>settings</key>
7+
<dict>
8+
<!--
9+
Only first row containing opening backtick is included in auto-indentation.
10+
Content of plain tagged template strings is otherwise excluded.
11+
12+
Note:
13+
Decreasing indentation of last row, containing stand-alone closing backtick
14+
is handled by normal indentation rules.
15+
-->
16+
17+
<!--
18+
<key>decreaseIndentPattern</key>
19+
<string>^\s*`</string>
20+
-->
21+
22+
<key>increaseIndentPattern</key>
23+
<string>^[^`]*`\s*$</string>
24+
25+
<key>unIndentedLinePattern</key>
26+
<string>^[^`]*$</string>
27+
</dict>
28+
</dict>
29+
</plist>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<plist version="1.0">
3+
<dict>
4+
<key>scope</key>
5+
<string>
6+
source.js meta.mapping, source.js meta.sequence,
7+
source.jsx meta.mapping, source.jsx meta.sequence,
8+
source.ts meta.mapping, source.ts meta.sequence,
9+
source.tsx meta.mapping, source.tsx meta.sequence
10+
</string>
11+
<key>settings</key>
12+
<dict>
13+
<!-- NOTE: Keep in sync with JSON! -->
14+
<key>decreaseIndentPattern</key>
15+
<string>(?x)
16+
# When an object is closed, but not opened
17+
(
18+
^
19+
(
20+
# Consume strings
21+
"(?:[^"\\]|\\.)*"
22+
|
23+
# Consume all chars that don't start a string, comment or
24+
# open an object on this line
25+
[^"/{\n]
26+
)*
27+
\}.*$
28+
)
29+
|
30+
# When an array is closed by itself on a line (interacts with indentSquareBrackets)
31+
(
32+
^(.*\*/)?\s*\].*$
33+
)
34+
</string>
35+
<key>increaseIndentPattern</key>
36+
<string>(?x)
37+
# When an object is opened, but not closed
38+
(
39+
^.*\{
40+
(
41+
# Consume strings
42+
"(?:[^"\\]|\\.)*"
43+
|
44+
# Consume all chars that don't start a string, comment or
45+
# end the object that was opened on this line
46+
[^"/}]
47+
)*
48+
# Stop matching at the end of the line, or once we hit a comment
49+
($|/[/*])
50+
)
51+
|
52+
# When an array is opened, but not closed
53+
(
54+
^.*\[
55+
(
56+
# Consume strings
57+
"(?:[^"\\]|\\.)*"
58+
|
59+
# Consume all chars that don't start a string, comment or
60+
# end the array that was opened on this line
61+
[^"/\]]
62+
)*
63+
# Stop matching at the end of the line, or once we hit a comment
64+
($|/[/*])
65+
)
66+
</string>
67+
<!-- Reset for value rules -->
68+
<key>bracketIndentNextLinePattern</key>
69+
<string></string>
70+
</dict>
71+
</dict>
72+
</plist>

JavaScript/Indentation Rules.tmPreferences

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<plist version="1.0">
33
<dict>
4+
<!--
5+
The meta.function scopes are used
6+
to re-override the separate mapping and sequence-sepcific patterns
7+
defined in `Indentation Rules - Values.tmPreferences`.
8+
This relies on a scope selector scoring adjustment in 4173.
9+
See also: https://github.com/sublimehq/sublime_text/issues/2152
10+
-->
411
<key>scope</key>
5-
<string>source.js, source.ts, source.jsx, source.tsx</string>
12+
<string>
13+
source.js - source.js meta.string,
14+
source.js meta.function - source.js meta.string,
15+
source.jsx - source.jsx meta.string,
16+
source.jsx meta.function - source.jsx meta.string,
17+
source.ts - source.ts meta.string,
18+
source.ts meta.function - source.ts meta.string,
19+
source.tsx - source.tsx meta.string,
20+
source.tsx meta.function - source.tsx meta.string
21+
</string>
622
<key>settings</key>
723
<dict>
824
<key>decreaseIndentPattern</key>
925
<string><![CDATA[(?x)
10-
# line beginning with whitespace or block comments
26+
# line beginning with whitespace
1127
^ (.*\*/)? \s*
1228
(?:
1329
# dedent closing braces
1430
\}
31+
# dedent closing brackets
32+
| \]
1533
# dedent closing tagged templates
1634
| `
1735
# detent `case ... :`
18-
| case\b
36+
| case\b.*:
1937
# detent `default:`
20-
| default\b
38+
| default\s*:
2139
)
2240
]]></string>
2341

@@ -30,11 +48,11 @@
3048
# but exclude lines such as `extern "C" {`
3149
.* \{ (?: \s* /\*.*\*/ )* \s* (?: //.* )? $
3250
# indent after opening tagged template: e.g.: "css`"
33-
| .* \w+ \s* `
51+
# see: Indentation Rules - Template Strings.tmPreferences
3452
# indent after `case ... :`
35-
| case\b
53+
| case\b.*:
3654
# indent after `default:`
37-
| default\b
55+
| default\s*:
3856
)
3957
]]></string>
4058

@@ -72,8 +90,6 @@
7290
)
7391
]]></string>
7492

75-
<key>indentSquareBrackets</key>
76-
<true/>
7793
</dict>
7894
</dict>
7995
</plist>

JavaScript/tests/syntax_test_js_indent_common.js

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,88 @@
11
// SYNTAX TEST reindent-unchanged "Packages/JavaScript/JavaScript.sublime-syntax"
22

3+
/*
4+
* Export definitions
5+
*/
6+
7+
export default {
8+
default: 'value',
9+
case() {
10+
const map1 = {
11+
default: 'value'
12+
}
13+
const list1 = [
14+
default
15+
]
16+
17+
if (foo == true)
18+
return 1
19+
else if (bar == true)
20+
return 2
21+
else
22+
return 3
23+
24+
switch (map1) {
25+
case null:
26+
return 0
27+
default:
28+
const map2 = {
29+
default: 'value'
30+
}
31+
const list2 = [
32+
default,
33+
() => {
34+
switch (map2) {
35+
default:
36+
return 0
37+
case null:
38+
return 1
39+
}
40+
}
41+
]
42+
}
43+
}
44+
}
45+
46+
/*
47+
* mapping definitions
48+
*/
49+
50+
const maps = {
51+
case: "case",
52+
default: "default",
53+
switch: "switch",
54+
if: "if",
55+
elif: "elif",
56+
else: "else",
57+
function: "function",
58+
object: {
59+
"key": "value",
60+
},
61+
list1: [
62+
"switch",
63+
"case"
64+
],
65+
list3: ["value1", "value2"]
66+
};
67+
68+
/*
69+
* list definitions
70+
*/
71+
72+
const list = [
73+
case,
74+
default,
75+
switch,
76+
if,
77+
elif,
78+
else,
79+
[
80+
case,
81+
default
82+
],
83+
["value1", "value2"]
84+
]
85+
386
/**
487
* This is my first JavaScript program.
588
* This will print 'Hello World' as the output
@@ -548,16 +631,12 @@ function testIfElseIndentationWithBracesAndComment(v) {
548631

549632
function testSwitchCaseIndentation(v) {
550633
switch (s) {
551-
case
552634
case:
553-
case break
554635
case: break
555636
case "(": break
556637
case ")": break;
557638
case ":": break;
558639
case ";": break;
559-
case
560-
break;
561640
case:
562641
break;
563642
case ":"
@@ -982,6 +1061,8 @@ function testWhileIndentationWithBracesAndComments(v) {
9821061
* CSS Templates
9831062
*/
9841063

1064+
var style = css`tr{color:red}`;
1065+
9851066
var style = css`
9861067
tr, p {
9871068
background: red solid;
@@ -992,6 +1073,8 @@ var style = css`
9921073
* HTML Templates
9931074
*/
9941075

1076+
var html = html`<p>${content}</p>`;
1077+
9951078
var html = html`
9961079
<head>
9971080
<script type="text/javascript">
@@ -1026,6 +1109,8 @@ var html = html`
10261109
* JavaScript Templates
10271110
*/
10281111

1112+
var script = js`console.log(${string})`;
1113+
10291114
var script = js`
10301115
var ${name} = "Value ${interpol}"
10311116

@@ -1038,6 +1123,8 @@ var script = js`
10381123
* JSON Templates
10391124
*/
10401125

1126+
var json = json`{"key": "value"}`;
1127+
10411128
var json = json`
10421129
{
10431130
"simple": "val${ue}",
@@ -1053,4 +1140,49 @@ var json = json`
10531140
]
10541141
}
10551142
}
1056-
`
1143+
`
1144+
1145+
/*
1146+
* Other Templates
1147+
*/
1148+
1149+
var other = other`template ${string}`;
1150+
1151+
var other = other`
1152+
# Heading
1153+
1154+
My ${pragraph}!
1155+
`
1156+
1157+
/*
1158+
* Plain String Templates
1159+
*/
1160+
1161+
`single line template string`
1162+
1163+
`
1164+
multi line template strings
1165+
ignore normal JavaScript indentation rules
1166+
1167+
switch (${var}) {
1168+
case "foo":
1169+
break;
1170+
case "bar":
1171+
break;
1172+
case "baz":
1173+
break;
1174+
}
1175+
`
1176+
1177+
function print(var) {
1178+
return `
1179+
switch (${var}) {
1180+
case "foo":
1181+
break;
1182+
case "bar":
1183+
break;
1184+
case "baz":
1185+
break;
1186+
}
1187+
`;
1188+
}

0 commit comments

Comments
 (0)