tree-sitter-sh 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar.js CHANGED
@@ -189,6 +189,8 @@ const structuredSourceParts = ($) => [
189
189
  $.arithmetic_expansion,
190
190
  $.backquote_substitution,
191
191
  ];
192
+ const patternSpecialValue = ($, character) =>
193
+ repeat1(field("value", choice(character, ...structuredSourceParts($))));
192
194
  const hiddenPhysical = ($, begin) => physicalSource($, begin);
193
195
  const fallbackLiteralParts = ($, character) =>
194
196
  choice(
@@ -247,30 +249,22 @@ const fallbackRules = (kind) => {
247
249
  field("operator", $.pattern_bracket_range_operator_source),
248
250
  field("end", endpoint($)),
249
251
  );
250
- const special = ($, marker, body) =>
251
- prec.dynamic(
252
+ const special = ($, marker, body) => {
253
+ const delimiter = physical(
254
+ $,
255
+ $[`_fallback_${marker}`],
256
+ marker === "colon" ? ":" : marker === "dot" ? "." : "=",
257
+ );
258
+ return prec.dynamic(
252
259
  PATTERN_PRECEDENCE.specialElement,
253
260
  seq(
254
261
  physical($, $._fallback_special_bracket_open, "["),
255
- physical(
256
- $,
257
- $[`_fallback_${marker}`],
258
- marker === "colon" ? ":" : marker === "dot" ? "." : "=",
259
- ),
262
+ delimiter,
260
263
  body,
261
- prec(
262
- 1,
263
- seq(
264
- physical(
265
- $,
266
- $[`_fallback_${marker}`],
267
- marker === "colon" ? ":" : marker === "dot" ? "." : "=",
268
- ),
269
- physical($, $._fallback_bracket_close, "]"),
270
- ),
271
- ),
264
+ prec(1, seq(delimiter, physical($, $._fallback_bracket_close, "]"))),
272
265
  ),
273
266
  );
267
+ };
274
268
  return {
275
269
  [`${prefix}_first`]: ($) =>
276
270
  fallbackFirstLiteral($, $[`${prefix}_literal_begin`], cell($)),
@@ -360,17 +354,12 @@ const fallbackRules = (kind) => {
360
354
  special(
361
355
  $,
362
356
  "dot",
363
- repeat1(
364
- field(
365
- "value",
366
- choice(
367
- classified(
368
- $,
369
- "collating_character",
370
- "pattern_collating_symbol_character_source",
371
- ),
372
- ...structuredSourceParts($),
373
- ),
357
+ patternSpecialValue(
358
+ $,
359
+ classified(
360
+ $,
361
+ "collating_character",
362
+ "pattern_collating_symbol_character_source",
374
363
  ),
375
364
  ),
376
365
  ),
@@ -379,17 +368,12 @@ const fallbackRules = (kind) => {
379
368
  special(
380
369
  $,
381
370
  "equals",
382
- repeat1(
383
- field(
384
- "value",
385
- choice(
386
- classified(
387
- $,
388
- "equivalence_character",
389
- "pattern_equivalence_class_character_source",
390
- ),
391
- ...structuredSourceParts($),
392
- ),
371
+ patternSpecialValue(
372
+ $,
373
+ classified(
374
+ $,
375
+ "equivalence_character",
376
+ "pattern_equivalence_class_character_source",
393
377
  ),
394
378
  ),
395
379
  ),
@@ -401,6 +385,13 @@ const wordPatternSpecialSources = ($) => [
401
385
  $.pattern_equivalence_class_source,
402
386
  ];
403
387
 
388
+ const patternBracketPlainAtoms = ($, character) => [
389
+ character,
390
+ $._pattern_operator_bracket_character,
391
+ $.pattern_bracket_hyphen_source,
392
+ ...structuredSourceParts($),
393
+ ];
394
+
404
395
  const parameterPatternCollatingSymbolSource = ($) =>
405
396
  alias(
406
397
  $._parameter_pattern_collating_symbol_source,
@@ -549,16 +540,9 @@ const arithmeticExpansion = ($, start, dynamicStart) =>
549
540
  arithmeticClosingLayout($),
550
541
  ),
551
542
  );
552
- const linebreakLayout = ($) =>
553
- seq(optional($.linebreak), optional($._horizontal_layout));
554
543
 
555
544
  const separatorOperatorLayout = ($, operator) =>
556
545
  seq(operator, optional(field("linebreak", $.linebreak)));
557
- const reservedWordLinebreak = ($) =>
558
- choice(
559
- seq($.linebreak, optional($._horizontal_layout)),
560
- $._horizontal_layout,
561
- );
562
546
 
563
547
  const newlineListElements = ($) => [
564
548
  $.here_document_sequence,
@@ -575,14 +559,18 @@ const boundaryLineComment = ($, comment) =>
575
559
  const trailingComment = ($) =>
576
560
  seq($._trailing_comment_boundary, optional($._horizontal_layout), $.comment);
577
561
 
562
+ // Expansions whose parameter words inherit a double-quoted context.
563
+ const quotedExpansionParts = ($) => [
564
+ alias($._double_quoted_parameter_expansion, $.parameter_expansion),
565
+ $.command_substitution,
566
+ $.arithmetic_expansion,
567
+ alias($._double_quoted_backquote_substitution, $.backquote_substitution),
568
+ ];
578
569
  const doubleQuotedPart = ($) =>
579
570
  choice(
580
571
  $.double_quote_text,
581
572
  $.double_quote_escape,
582
- alias($._double_quoted_parameter_expansion, $.parameter_expansion),
583
- $.command_substitution,
584
- $.arithmetic_expansion,
585
- alias($._double_quoted_backquote_substitution, $.backquote_substitution),
573
+ ...quotedExpansionParts($),
586
574
  );
587
575
  const singleQuoted = ($, opener) =>
588
576
  seq(
@@ -603,6 +591,19 @@ const dollarSingleQuoted = ($, dollar) =>
603
591
  repeat(choice($.dollar_single_quote_text, $.dollar_single_quote_escape)),
604
592
  physical($, $._dollar_sq_close, "'"),
605
593
  );
594
+ const hereDocumentRedirect = ($, operator, end) =>
595
+ seq(
596
+ field("operator", operator),
597
+ optional($._horizontal_layout),
598
+ field("end", end),
599
+ );
600
+ // The begin token tells the scanner whether <<- strips leading tabs.
601
+ const hereEnd = ($, begin) =>
602
+ seq(
603
+ begin,
604
+ field("word", alias($._here_end_source_word, $.word)),
605
+ $._here_end_commit,
606
+ );
606
607
  const hereDocumentEndSource = ($, begin, text) =>
607
608
  seq(begin, repeat(choice($._here_document_end_leading_tabs, text)));
608
609
  const backquoteSubstitution = ($, start) =>
@@ -642,10 +643,9 @@ const dollarExpansionStart = (
642
643
  start = $._dollar_expansion_start,
643
644
  ) => seq(dollarExpansionPrefix($, start), physical($, token, spelling));
644
645
  const backquoteDelimiter = ($, token) => physical($, token, "`");
645
- const commandSubstitution = ($, start) =>
646
+ const commandSubstitution = ($, prefix) =>
646
647
  seq(
647
- start,
648
- $._command_substitution_body_begin,
648
+ prefix,
649
649
  optional(field("body", $.command_substitution_body)),
650
650
  physical($, $._punct_right_parenthesis, ")"),
651
651
  $._command_substitution_end,
@@ -659,9 +659,7 @@ const patternSpecialClassSource = ($, marker, characterSource) =>
659
659
  PATTERN_PRECEDENCE.specialElement,
660
660
  seq(
661
661
  patternSpecialStart($, marker),
662
- repeat1(
663
- field("value", choice(characterSource, ...structuredSourceParts($))),
664
- ),
662
+ patternSpecialValue($, characterSource),
665
663
  patternSpecialEnd($, marker),
666
664
  ),
667
665
  );
@@ -698,8 +696,9 @@ const patternCharacterClassSource = ($, content) =>
698
696
 
699
697
  const parameterExpansion = (
700
698
  $,
701
- bracedExpansion,
699
+ word,
702
700
  start = $._dollar_expansion_start,
701
+ prefix = "",
703
702
  ) =>
704
703
  prec(
705
704
  1,
@@ -708,10 +707,7 @@ const parameterExpansion = (
708
707
  dollarExpansionPrefix($, start),
709
708
  field("parameter", $._unbraced_parameter),
710
709
  ),
711
- seq(
712
- dollarExpansionStart($, $._parameter_open, "{", start),
713
- bracedExpansion,
714
- ),
710
+ bracedParameterExpansion($, word, prefix),
715
711
  ),
716
712
  );
717
713
 
@@ -721,33 +717,71 @@ const bracedParameterSource = ($, classifiedParameter) =>
721
717
  $._unclassified_numeric_parameter_source,
722
718
  );
723
719
 
724
- const bracedParameterExpansion = ($, tail) =>
725
- choice(
726
- seq(bracedParameterSource($, $._braced_parameter), tail),
727
- prec.dynamic(2, seq(field("parameter", $._special_parameter_hash), tail)),
728
- prec.dynamic(
729
- 3,
730
- seq(
731
- field("operator", $._parameter_length_operator),
732
- bracedParameterSource($, $._length_parameter),
733
- physical($, $._parameter_close, "}"),
734
- ),
735
- ),
720
+ const parameterHeaderRules = () =>
721
+ Object.fromEntries(
722
+ ["", "_word_initial"].flatMap((prefix) => {
723
+ const name = `${prefix}_braced_parameter`;
724
+ return [
725
+ [
726
+ `${name}_header`,
727
+ ($) =>
728
+ seq(
729
+ $[`${name}_start`],
730
+ choice(
731
+ bracedParameterSource($, $._braced_parameter),
732
+ prec.dynamic(2, field("parameter", $._special_parameter_hash)),
733
+ ),
734
+ ),
735
+ ],
736
+ [
737
+ `${name}_value_header`,
738
+ ($) =>
739
+ seq(
740
+ $[`${name}_header`],
741
+ field("operator", $._parameter_value_operator),
742
+ ),
743
+ ],
744
+ [
745
+ `${name}_pattern_header`,
746
+ ($) =>
747
+ seq(
748
+ $[`${name}_header`],
749
+ field("operator", $._parameter_pattern_operator),
750
+ ),
751
+ ],
752
+ [
753
+ `${name}_length_header`,
754
+ ($) =>
755
+ seq(
756
+ $[`${name}_start`],
757
+ field("operator", $._parameter_length_operator),
758
+ bracedParameterSource($, $._length_parameter),
759
+ ),
760
+ ],
761
+ ];
762
+ }),
736
763
  );
737
764
 
738
- const parameterOperatorTail = ($, word) =>
739
- choice(
765
+ const bracedParameterExpansion = ($, word, prefix) => {
766
+ const name = `${prefix}_braced_parameter`;
767
+ return choice(
768
+ seq($[`${name}_header`], physical($, $._parameter_close, "}")),
740
769
  seq(
741
- field("operator", $._parameter_value_operator),
770
+ $[`${name}_value_header`],
742
771
  optional(field("word", word)),
743
772
  physical($, $._parameter_close, "}"),
744
773
  ),
745
774
  seq(
746
- field("operator", $._parameter_pattern_operator),
775
+ $[`${name}_pattern_header`],
747
776
  optional(field("pattern", $.parameter_pattern)),
748
777
  physical($, $._parameter_close, "}"),
749
778
  ),
779
+ prec.dynamic(
780
+ 3,
781
+ seq($[`${name}_length_header`], physical($, $._parameter_close, "}")),
782
+ ),
750
783
  );
784
+ };
751
785
 
752
786
  const parameterPatternSource = ($) =>
753
787
  choice(
@@ -791,12 +825,7 @@ const ifClause = ($) =>
791
825
  );
792
826
 
793
827
  const loopClause = ($, keyword) =>
794
- seq(
795
- keyword,
796
- compoundListField($, "condition"),
797
- optional($._closing_layout),
798
- field("body", $.do_group),
799
- );
828
+ seq(keyword, $._loop_condition, field("body", $.do_group));
800
829
 
801
830
  const separatedForHeader = ($) =>
802
831
  seq(
@@ -821,7 +850,7 @@ const forHeaderTail = ($) =>
821
850
  $._horizontal_layout,
822
851
  separatedForHeader($),
823
852
  seq(
824
- reservedWordLinebreak($),
853
+ $._linebreak_layout,
825
854
  field("in", $.in),
826
855
  optional(seq($._horizontal_layout, field("words", $.wordlist))),
827
856
  separatedForHeader($),
@@ -935,9 +964,8 @@ export default grammar({
935
964
  $._esac_keyword_begin,
936
965
  $._while_keyword_begin,
937
966
  $._until_keyword_begin,
938
- $._dless_commit,
939
- $._dlessdash_commit,
940
967
  $._here_end_begin,
968
+ $._here_end_strip_begin,
941
969
  $._here_end_commit,
942
970
  $._here_document_line_end_begin,
943
971
  $._here_document_body_start,
@@ -1170,17 +1198,15 @@ export default grammar({
1170
1198
 
1171
1199
  rules: {
1172
1200
  program: ($) =>
1173
- choice(
1174
- seq(
1175
- optional(field("leading", $.linebreak)),
1176
- optional($._horizontal_layout),
1177
- field("commands", $.complete_commands),
1178
- optional(field("trailing", $.linebreak)),
1179
- optional($._free_trailing_layout),
1180
- ),
1181
- seq(
1182
- optional(field("leading", $.linebreak)),
1183
- optional($._horizontal_layout),
1201
+ seq(
1202
+ optional(field("leading", $.linebreak)),
1203
+ optional($._horizontal_layout),
1204
+ choice(
1205
+ seq(
1206
+ field("commands", $.complete_commands),
1207
+ optional(field("trailing", $.linebreak)),
1208
+ optional($._free_trailing_layout),
1209
+ ),
1184
1210
  optional(trailingComment($)),
1185
1211
  ),
1186
1212
  ),
@@ -1304,10 +1330,11 @@ export default grammar({
1304
1330
  field("pipeline", $.pipeline),
1305
1331
  repeat(
1306
1332
  seq(
1307
- $._and_or_continuation,
1308
- optional($._horizontal_layout),
1333
+ optional(
1334
+ seq($._and_or_continuation, optional($._horizontal_layout)),
1335
+ ),
1309
1336
  field("operator", choice($._and_if, $._or_if)),
1310
- linebreakLayout($),
1337
+ optional($._linebreak_layout),
1311
1338
  field("pipeline", $.pipeline),
1312
1339
  ),
1313
1340
  ),
@@ -1326,10 +1353,9 @@ export default grammar({
1326
1353
  field("command", $.command),
1327
1354
  repeat(
1328
1355
  seq(
1329
- $._pipe_continuation,
1330
- optional($._horizontal_layout),
1356
+ optional(seq($._pipe_continuation, optional($._horizontal_layout))),
1331
1357
  physical($, $._punct_pipe, "|"),
1332
- linebreakLayout($),
1358
+ optional($._linebreak_layout),
1333
1359
  field("command", $.command),
1334
1360
  ),
1335
1361
  ),
@@ -1517,6 +1543,9 @@ export default grammar({
1517
1543
  ),
1518
1544
  ),
1519
1545
 
1546
+ _loop_condition: ($) =>
1547
+ seq(compoundListField($, "condition"), optional($._closing_layout)),
1548
+
1520
1549
  while_clause: ($) => loopClause($, $._while_keyword_source),
1521
1550
 
1522
1551
  until_clause: ($) => loopClause($, $._until_keyword_source),
@@ -1527,9 +1556,9 @@ export default grammar({
1527
1556
  case_clause: ($) =>
1528
1557
  seq(
1529
1558
  $._case_selector_header,
1530
- reservedWordLinebreak($),
1559
+ $._linebreak_layout,
1531
1560
  field("in", $.in),
1532
- linebreakLayout($),
1561
+ optional($._linebreak_layout),
1533
1562
  caseClauseItems($),
1534
1563
  ),
1535
1564
 
@@ -1541,12 +1570,17 @@ export default grammar({
1541
1570
 
1542
1571
  case_list: ($) => repeat1(field("item", $.case_item)),
1543
1572
 
1544
- case_item_ns: ($) =>
1573
+ _case_item_header: ($) =>
1545
1574
  seq(
1546
1575
  field("patterns", $.pattern_list),
1547
1576
  $._pattern_end,
1548
1577
  optional($._horizontal_layout),
1549
1578
  physical($, $._punct_right_parenthesis, ")"),
1579
+ ),
1580
+
1581
+ case_item_ns: ($) =>
1582
+ seq(
1583
+ $._case_item_header,
1550
1584
  choice(
1551
1585
  seq(optional($.linebreak), optional($._horizontal_layout)),
1552
1586
  prec.dynamic(
@@ -1558,17 +1592,14 @@ export default grammar({
1558
1592
 
1559
1593
  case_item: ($) =>
1560
1594
  seq(
1561
- field("patterns", $.pattern_list),
1562
- $._pattern_end,
1563
- optional($._horizontal_layout),
1564
- physical($, $._punct_right_parenthesis, ")"),
1595
+ $._case_item_header,
1565
1596
  choice(
1566
- linebreakLayout($),
1597
+ optional($._linebreak_layout),
1567
1598
  prec.dynamic(10, field("body", $.compound_list)),
1568
1599
  ),
1569
1600
  seq($._case_item_end, optional($._horizontal_layout)),
1570
1601
  field("terminator", choice($._dsemi, $._semi_and)),
1571
- optional(reservedWordLinebreak($)),
1602
+ optional($._linebreak_layout),
1572
1603
  ),
1573
1604
 
1574
1605
  pattern_list: ($) =>
@@ -1651,7 +1682,7 @@ export default grammar({
1651
1682
  field("body", choice($.io_file, $.io_here)),
1652
1683
 
1653
1684
  io_number: ($) => lexical($, $._io_number_begin),
1654
- io_file: ($) =>
1685
+ _io_file_prefix: ($) =>
1655
1686
  seq(
1656
1687
  choice(
1657
1688
  physical($, $._punct_less, "<", "operator"),
@@ -1662,9 +1693,10 @@ export default grammar({
1662
1693
  ),
1663
1694
  ),
1664
1695
  optional($._horizontal_layout),
1665
- field("filename", $.filename),
1666
1696
  ),
1667
1697
 
1698
+ io_file: ($) => seq($._io_file_prefix, field("filename", $.filename)),
1699
+
1668
1700
  filename: ($) => field("word", $.word),
1669
1701
 
1670
1702
  lessand: ($) => lexical($, $._lessand_begin),
@@ -1673,25 +1705,20 @@ export default grammar({
1673
1705
  lessgreat: ($) => lexical($, $._lessgreat_begin),
1674
1706
  clobber: ($) => lexical($, $._clobber_begin),
1675
1707
  io_here: ($) =>
1676
- seq(
1677
- field("operator", choice($._dless, $._dlessdash)),
1678
- optional($._horizontal_layout),
1679
- field("end", $.here_end),
1680
- ),
1681
-
1682
- _dless: ($) =>
1683
- seq(alias($._dless_operator_lexeme, $.dless), $._dless_commit),
1684
- _dlessdash: ($) =>
1685
- seq(
1686
- alias($._dlessdash_operator_lexeme, $.dlessdash),
1687
- $._dlessdash_commit,
1688
- ),
1689
- here_end: ($) =>
1690
- seq(
1691
- $._here_end_begin,
1692
- field("word", alias($._here_end_source_word, $.word)),
1693
- $._here_end_commit,
1708
+ choice(
1709
+ hereDocumentRedirect(
1710
+ $,
1711
+ alias($._dless_operator_lexeme, $.dless),
1712
+ $.here_end,
1713
+ ),
1714
+ hereDocumentRedirect(
1715
+ $,
1716
+ alias($._dlessdash_operator_lexeme, $.dlessdash),
1717
+ alias($._here_end_strip, $.here_end),
1718
+ ),
1694
1719
  ),
1720
+ here_end: ($) => hereEnd($, $._here_end_begin),
1721
+ _here_end_strip: ($) => hereEnd($, $._here_end_strip_begin),
1695
1722
 
1696
1723
  _here_end_source_word: ($) =>
1697
1724
  seq($._word_initial_part, repeat($._word_part)),
@@ -1703,18 +1730,22 @@ export default grammar({
1703
1730
  repeat1(field("document", $.here_document)),
1704
1731
  $._here_document_sequence_end,
1705
1732
  ),
1733
+ _here_document_prefix: ($) =>
1734
+ seq(
1735
+ $._here_document_body_start,
1736
+ optional(field("body", $.here_document_body)),
1737
+ ),
1738
+
1739
+ _quoted_here_document_prefix: ($) =>
1740
+ seq(
1741
+ $._quoted_here_document_body_start,
1742
+ optional(field("body", $.quoted_here_document_body)),
1743
+ ),
1744
+
1706
1745
  here_document: ($) =>
1707
1746
  choice(
1708
- seq(
1709
- $._here_document_body_start,
1710
- optional(field("body", $.here_document_body)),
1711
- field("end", $.here_document_end),
1712
- ),
1713
- seq(
1714
- $._quoted_here_document_body_start,
1715
- optional(field("body", $.quoted_here_document_body)),
1716
- field("end", $.here_document_end),
1717
- ),
1747
+ seq($._here_document_prefix, field("end", $.here_document_end)),
1748
+ seq($._quoted_here_document_prefix, field("end", $.here_document_end)),
1718
1749
  ),
1719
1750
 
1720
1751
  here_document_end: ($) =>
@@ -1896,11 +1927,19 @@ export default grammar({
1896
1927
  doubleQuoted($, $._word_initial_dq_open),
1897
1928
  _word_initial_dollar_single_quoted: ($) =>
1898
1929
  dollarSingleQuoted($, $._word_initial_dollar_sq_dollar),
1930
+ _word_initial_braced_parameter_start: ($) =>
1931
+ dollarExpansionStart(
1932
+ $,
1933
+ $._parameter_open,
1934
+ "{",
1935
+ $._word_initial_dollar_expansion_start,
1936
+ ),
1899
1937
  _word_initial_parameter_expansion: ($) =>
1900
1938
  parameterExpansion(
1901
1939
  $,
1902
- $._braced_parameter_expansion,
1940
+ $.parameter_word,
1903
1941
  $._word_initial_dollar_expansion_start,
1942
+ "_word_initial",
1904
1943
  ),
1905
1944
  _word_initial_command_start: ($) =>
1906
1945
  dollarExpansionStart(
@@ -1909,8 +1948,10 @@ export default grammar({
1909
1948
  "(",
1910
1949
  $._word_initial_dollar_expansion_start,
1911
1950
  ),
1951
+ _word_initial_command_substitution_prefix: ($) =>
1952
+ seq($._word_initial_command_start, $._command_substitution_body_begin),
1912
1953
  _word_initial_command_substitution: ($) =>
1913
- commandSubstitution($, $._word_initial_command_start),
1954
+ commandSubstitution($, $._word_initial_command_substitution_prefix),
1914
1955
  _word_initial_arithmetic_start: ($) =>
1915
1956
  arithmeticExpansionStart(
1916
1957
  $,
@@ -2000,10 +2041,7 @@ export default grammar({
2000
2041
  choice(
2001
2042
  ...wordPatternSpecialSources($),
2002
2043
  $.pattern_bracket_range_source,
2003
- $.pattern_bracket_character_source,
2004
- $._pattern_operator_bracket_character,
2005
- $.pattern_bracket_hyphen_source,
2006
- ...structuredSourceParts($),
2044
+ ...patternBracketPlainAtoms($, $.pattern_bracket_character_source),
2007
2045
  ),
2008
2046
 
2009
2047
  _parameter_pattern_bracket_member: ($) =>
@@ -2013,13 +2051,13 @@ export default grammar({
2013
2051
  $._parameter_pattern_bracket_range,
2014
2052
  $.pattern_bracket_range_source,
2015
2053
  ),
2016
- alias(
2017
- $._parameter_pattern_bracket_character,
2018
- $.pattern_bracket_character_source,
2054
+ ...patternBracketPlainAtoms(
2055
+ $,
2056
+ alias(
2057
+ $._parameter_pattern_bracket_character,
2058
+ $.pattern_bracket_character_source,
2059
+ ),
2019
2060
  ),
2020
- $._pattern_operator_bracket_character,
2021
- $.pattern_bracket_hyphen_source,
2022
- ...structuredSourceParts($),
2023
2061
  ),
2024
2062
 
2025
2063
  pattern_bracket_range_source: ($) =>
@@ -2039,23 +2077,20 @@ export default grammar({
2039
2077
 
2040
2078
  _pattern_bracket_range_endpoint: ($) =>
2041
2079
  choice(
2042
- $.pattern_bracket_character_source,
2043
- $._pattern_operator_bracket_character,
2080
+ ...patternBracketPlainAtoms($, $.pattern_bracket_character_source),
2044
2081
  $.pattern_collating_symbol_source,
2045
- $.pattern_bracket_hyphen_source,
2046
- ...structuredSourceParts($),
2047
2082
  ),
2048
2083
 
2049
2084
  _parameter_pattern_bracket_range_endpoint: ($) =>
2050
2085
  choice(
2051
- alias(
2052
- $._parameter_pattern_bracket_character,
2053
- $.pattern_bracket_character_source,
2086
+ ...patternBracketPlainAtoms(
2087
+ $,
2088
+ alias(
2089
+ $._parameter_pattern_bracket_character,
2090
+ $.pattern_bracket_character_source,
2091
+ ),
2054
2092
  ),
2055
- $._pattern_operator_bracket_character,
2056
2093
  parameterPatternCollatingSymbolSource($),
2057
- $.pattern_bracket_hyphen_source,
2058
- ...structuredSourceParts($),
2059
2094
  ),
2060
2095
 
2061
2096
  pattern_bracket_character_source: ($) =>
@@ -2147,35 +2182,13 @@ export default grammar({
2147
2182
  dollar_single_quote_escape: ($) =>
2148
2183
  lexical($, $._dollar_single_quote_escape_begin),
2149
2184
 
2150
- parameter_expansion: ($) =>
2151
- parameterExpansion($, $._braced_parameter_expansion),
2185
+ _braced_parameter_start: ($) =>
2186
+ dollarExpansionStart($, $._parameter_open, "{"),
2187
+ ...parameterHeaderRules(),
2188
+ parameter_expansion: ($) => parameterExpansion($, $.parameter_word),
2152
2189
 
2153
2190
  _double_quoted_parameter_expansion: ($) =>
2154
- parameterExpansion($, $._double_quoted_braced_parameter_expansion),
2155
-
2156
- _braced_parameter_expansion: ($) =>
2157
- bracedParameterExpansion($, $._parameter_expansion_tail),
2158
-
2159
- _double_quoted_braced_parameter_expansion: ($) =>
2160
- bracedParameterExpansion($, $._double_quoted_parameter_expansion_tail),
2161
-
2162
- _parameter_expansion_tail: ($) =>
2163
- choice(
2164
- physical($, $._parameter_close, "}"),
2165
- $._parameter_operator_expansion_tail,
2166
- ),
2167
-
2168
- _parameter_operator_expansion_tail: ($) =>
2169
- parameterOperatorTail($, $.parameter_word),
2170
-
2171
- _double_quoted_parameter_expansion_tail: ($) =>
2172
- choice(
2173
- physical($, $._parameter_close, "}"),
2174
- $._double_quoted_parameter_operator_expansion_tail,
2175
- ),
2176
-
2177
- _double_quoted_parameter_operator_expansion_tail: ($) =>
2178
- parameterOperatorTail(
2191
+ parameterExpansion(
2179
2192
  $,
2180
2193
  alias($._double_quoted_parameter_word, $.parameter_word),
2181
2194
  ),
@@ -2221,9 +2234,19 @@ export default grammar({
2221
2234
  _parameter_length_operator: ($) =>
2222
2235
  alias($._special_parameter_hash_lexeme, $.parameter_length_operator),
2223
2236
  _parameter_value_operator: ($) =>
2224
- alias($._parameter_value_operator_lexeme, $.parameter_value_operator),
2237
+ wholeSource(
2238
+ $,
2239
+ $._parameter_value_operator_begin,
2240
+ $._parameter_value_operator_lexeme,
2241
+ $.parameter_value_operator,
2242
+ ),
2225
2243
  _parameter_pattern_operator: ($) =>
2226
- alias($._parameter_pattern_operator_lexeme, $.parameter_pattern_operator),
2244
+ wholeSource(
2245
+ $,
2246
+ $._parameter_pattern_operator_begin,
2247
+ $._parameter_pattern_operator_lexeme,
2248
+ $.parameter_pattern_operator,
2249
+ ),
2227
2250
  parameter_word: ($) => parameterPatternSource($),
2228
2251
 
2229
2252
  _double_quoted_parameter_word: ($) =>
@@ -2234,13 +2257,7 @@ export default grammar({
2234
2257
  alias($._double_quoted_parameter_text, $.double_quote_text),
2235
2258
  alias($._double_quoted_parameter_escape, $.double_quote_escape),
2236
2259
  $.double_quoted,
2237
- alias($._double_quoted_parameter_expansion, $.parameter_expansion),
2238
- $.command_substitution,
2239
- $.arithmetic_expansion,
2240
- alias(
2241
- $._double_quoted_backquote_substitution,
2242
- $.backquote_substitution,
2243
- ),
2260
+ ...quotedExpansionParts($),
2244
2261
  ),
2245
2262
  parameter_pattern: ($) => prec.right(1, parameterPatternSource($)),
2246
2263
 
@@ -2265,8 +2282,10 @@ export default grammar({
2265
2282
 
2266
2283
  _double_quoted_parameter_escape: ($) =>
2267
2284
  lexical($, $._double_quoted_parameter_escape_begin),
2285
+ _command_substitution_prefix: ($) =>
2286
+ seq($._command_substitution_start, $._command_substitution_body_begin),
2268
2287
  command_substitution: ($) =>
2269
- commandSubstitution($, $._command_substitution_start),
2288
+ commandSubstitution($, $._command_substitution_prefix),
2270
2289
 
2271
2290
  _command_substitution_start: ($) =>
2272
2291
  dollarExpansionStart($, $._command_open, "("),
@@ -2320,13 +2339,7 @@ export default grammar({
2320
2339
 
2321
2340
  _arithmetic_runtime_fragment: ($) =>
2322
2341
  choice(
2323
- alias($._double_quoted_parameter_expansion, $.parameter_expansion),
2324
- $.command_substitution,
2325
- $.arithmetic_expansion,
2326
- alias(
2327
- $._double_quoted_backquote_substitution,
2328
- $.backquote_substitution,
2329
- ),
2342
+ ...quotedExpansionParts($),
2330
2343
  $.parenthesized_arithmetic_dynamic_source,
2331
2344
  ),
2332
2345
 
@@ -2411,13 +2424,7 @@ export default grammar({
2411
2424
  choice(
2412
2425
  $.arithmetic_number,
2413
2426
  $.arithmetic_variable,
2414
- alias($._double_quoted_parameter_expansion, $.parameter_expansion),
2415
- $.command_substitution,
2416
- $.arithmetic_expansion,
2417
- alias(
2418
- $._double_quoted_backquote_substitution,
2419
- $.backquote_substitution,
2420
- ),
2427
+ ...quotedExpansionParts($),
2421
2428
  $.parenthesized_arithmetic,
2422
2429
  ),
2423
2430
 
@@ -2467,6 +2474,12 @@ export default grammar({
2467
2474
 
2468
2475
  linebreak: ($) => $.newline_list,
2469
2476
 
2477
+ _linebreak_layout: ($) =>
2478
+ choice(
2479
+ seq($.linebreak, optional($._horizontal_layout)),
2480
+ $._horizontal_layout,
2481
+ ),
2482
+
2470
2483
  _horizontal_layout: ($) => seq(optional($._layout_begin), $._blank),
2471
2484
  _closing_layout: ($) => $._blank,
2472
2485
  _word_separator: ($) => wordSeparator($, $._word_separator_begin),