@@ -1,1009 +0,0 @@
3−# http://www.sublimetext.com/docs/3/syntax.html
4−name: friendly interactive shell (fish)
7−first_line_match: '^#!.*\b(fish)|^#\s*-\*-[^*]*mode:\s*shell-script[^*]*-\*-'
8−scope: source.shell.fish
11− - include: comment-external
12− - include: line-continuation
14− comment: In an ideal world, command-call-standard would be performing this match because fish highlights the strings which follow as arguments. But we can't do that in a tmLanguage
16− - meta_scope: meta.function-call.fish invalid.illegal.function-call.fish
17− - match: '(?=[\s;&)|<>])'
20− comment: Anonymous scope - Base scope pipeline goes up until one of the definitive ends (newline and ';') or the sequences that could be an end if we're actually inside a $self scope right now (')' and "end")
22− - match: \n|(;)|(?=\))|(?=end)
24− 1: meta.function-call.operator.fish keyword.operator.control.fish
26− - match: '(?:[&|]|(?:[0-9]+)?(?:<|>>?|\^\^?))'
27− comment: Match operators ('&', pipe, and redirect) which cannot start a pipeline because they must be consumed within or after a pipeline
28− scope: invalid.illegal.operator.fish
29− - include: comment-internal-end
31− comment: The reason we match '&' here is because we explicitly require it come after a command (unlike ';' which can be alone on a line)
33− - match: '(?=[\n;)])|(&)'
35− 1: meta.function-call.operator.fish keyword.operator.control.fish
39− - match: '(?![\s;&)|<>^])'
40− comment: End arg if it precedes whitespace or operators (excluding stderr redirect '^' due to a fish quirk)
42− - match: '(?=[\s;&)|<>])'
45− comment: Process expansion only occurs if the '%' is at the front of the argument, and continues for the entire argument
47− 0: meta.string.unquoted.fish punctuation.definition.process.fish
49− - meta_scope: meta.parameter.argument.process-expansion.fish
50− - match: '(?=[\s;&)|<>])'
52− - match: '(?:self|last)(?=$|[\s;&)|<>])'
53− comment: Match special process names. By a convention that I'm making up, scope them as a type of variable
54− scope: meta.string.unquoted.fish variable.language.fish
55− - include: parameter-patterns
56− - match: '(?:[+-]?)(?:[0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+)(?=$|[\s;&)|<>])'
57− comment: Treat a sequence of integers (with possible sign and decimal separator) as a standalone constant. Do this separate to the
58− scope: meta.parameter.argument.numeric.fish meta.string.unquoted.fish constant.numeric.fish
59− - match: '(?![\s($])'
60− comment: This scope can be used by plugins to locate arguments which don't *start* with command substitution or variable expansion and may directly resolve to file paths. Of course, they could have command substitution or variable expansion further on in them, but looking ahead for that too is nontrivial
62− - meta_scope: meta.parameter.argument.path.fish
63− - match: '(?=[\s;&)|<>])'
66− comment: Home directory expansion only occurs if the '~' is at the front of the argument, so check it first
67− scope: meta.string.unquoted.fish keyword.operator.tilde.fish
68− - include: parameter-patterns
70− comment: Use standard parameter patterns for whatever doesn't match the above
72− - meta_scope: meta.parameter.argument.fish
73− - match: '(?=[\s;&)|<>])'
75− - include: parameter-patterns
77− - match: '(builtin|command|exec)\b(?!\s+[-&|])'
78− comment: These meta commands force the parameter to behave as a standard command. They stop at piping
80− 1: support.function.fish
84− (?# Look ahead for control operations after whitespace)
87− (?# Find simple control operations)
91− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
95− - include: line-continuation
96− - include: command-call-standard
97− - match: '(not)\b(?!\s+[-&|])'
98− comment: This meta command acts as a unary operator on the command to the right, which can also be a meta command. It only applies to one command and stops at piping
100− 1: keyword.operator.word.fish
104− (?# Look ahead for control operations after whitespace)
107− (?# Find simple control operations)
111− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
115− - include: line-continuation
116− - include: command-call-meta
117− - include: command-call-standard
118− command-call-standard:
120− comment: A command call can't be a comment, but this match will only be satisfied if the command is first after a pipe because comments are otherwise consumed earlier
122− - meta_scope: invalid.illegal.function-call.fish
123− - match: '(?=[\n)])'
125− - match: "(?:[&|<>^])"
126− comment: Match an operator which cannot start a command call but does not stop the next characters from being interpreted as a command
127− scope: invalid.illegal.operator.fish
129− comment: Anonymous scope - A complete command comprising a name element and optional parameter, redirection, and comment elements
133− (?# Look ahead for operators)
136− (?# Find a control operator)
139− (?# Find a pipe operator)
140− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
144− - match: '(?![\s<>^%])'
145− comment: Anonymous scope - A name or block element. If a block is found, everything up to the `end` command is captured here. Note that redirection and process expansion can't start the element
147− - match: '(?=[\s;&)|<>])'
149− - include: command-call-standard-block
150− - match: '\[(?=[\s<>]|\\\n)'
151− comment: "Look for the alternate form of test, which uses a matching pair of '[' ']'"
153− 0: support.function.test.begin.fish
155− - match: '(\])|(\n|[;&)|].*)'
157− 1: support.function.test.end.fish
158− 2: invalid.illegal.function-call.fish
160− - include: line-continuation
161− - include: parameter
162− - include: redirection
163− - match: '(?:break|continue|return)(?=[\s;&)|<>])'
164− comment: Look for loop/function control commands. We perform no checking on the validity of their scope (because only allowing them in the correct scope won't work if they are used within if-blocks) or parameters (because fish does that during execution not parsing)
166− 0: keyword.control.conditional.fish
168− comment: Anonymous scope - A generic name element
170− - match: '(?=[\s;&)|<>])'
173− comment: fish would match the whole command name invalid if there was a command substitution anywhere in it, but we can't look ahead that effectively
175− - meta_scope: invalid.illegal.function-call.fish
176− - match: '(?=[\s;&)|<>])'
180− - match: '\)|(?=[\n;&)|<>])'
183− comment: Otherwise, treat the element as a fraction of a name made of arbitrary strings (which breaks at an escaped newline)
185− - meta_scope: variable.function.fish
186− - match: '(?=[\s;&()|<>])'
189− comment: The string scope explicitly forbids '$' so that the argument rule can pick it up as a variable expansion, but '$' is treated as a literal in command names, so we have to match it separately
190− scope: meta.string.unquoted.fish
193− comment: A command name can't begin with a process expansion operator (however the variable expansion operator '$' is allowed)
195− - meta_scope: invalid.illegal.function-call.fish
196− - match: '(?=[\s;&)|<>])'
199− - include: redirection
200− - match: '(?:[^\n\S]+)'
201− comment: Match any whitespace characters that aren't the newline
205− (?# Look ahead for operators)
208− (?# Find a control operator)
211− (?# Find a pipe operator)
212− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
216− - match: '(?!--[\s;&)|<>])'
217− comment: A list of elements that does not start with an end-of-options parameter
221− (?# Look ahead for operators or the end of options)
224− (?# Find a control operator)
227− (?# Find a pipe operator)
228− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
230− (?# Find a double hyphen)
235− - include: line-continuation
236− - include: comment-internal-end
237− - include: redirection
238− - include: parameter
239− - match: '(?=--[\s;&)|<>])'
240− comment: A list of elements that starts with an end-of-options parameter
244− (?# Look ahead for operators)
247− (?# Find a control operator)
250− (?# Find a pipe operator)
251− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
255− - match: '(?=--[\s;&)|<>])'
256− comment: Contain just the end-of-options parameter and give it the normal scope
258− - match: '(?=[\s;&)|<>])'
260− - include: parameter
262− comment: A list of elements (now forcibly using arguments)
266− (?# Look ahead for operators)
269− (?# Find a control operator)
272− (?# Find a pipe operator)
273− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
277− - include: line-continuation
278− - include: comment-internal-end
279− - include: redirection
281− command-call-standard-block:
282− - match: '(begin|while|if|for|switch|function)\s*([&|<>])'
283− comment: Block commands cannot be backgrounded, piped, or redirected
285− 1: variable.function.fish
286− 2: invalid.illegal.operator.fish
287− - match: (begin)\s*(\))
288− comment: The begin command uniquely cannot be the last command in a command substitution
290− 1: variable.function.fish
291− 2: invalid.illegal.operator.fish
292− - match: 'begin(?=\s*$|\s*[\n;]|\s+[^\s-])'
293− comment: The begin command can be alone on a line or followed by any command that doesn't start with a '-'. If a '-' is seen it shouldn't be treated as a block
295− 0: keyword.control.conditional.fish
297− - meta_scope: meta.block.begin.fish
298− - match: 'end(?=$|[\s;&)|<>])'
300− 0: keyword.control.conditional.fish
303− - match: '(?=while\s+[^\s;)-])'
304− comment: If the command name is followed by a valid string (not anything that closes the scope or a string starting with a '-') then open the scope
306− - meta_scope: meta.block.while.fish
307− - match: 'end(?=$|[\s;&)|<>])'
309− 0: keyword.control.conditional.fish
312− comment: Anonymous scope - Capture the command name we know is there, include a single instance of a pipeline, and end when an operator is seen
314− 0: keyword.control.conditional.fish
316− - match: '\s*(?=[\n;&)])'
318− - include: line-continuation
320− - match: '\n|(;)|([&)])'
321− comment: Anonymous scope - Capture the operator we know is there, include the base scope, and end when an `end` command is seen
323− 1: keyword.operator.control.fish
324− 2: invalid.illegal.operator.fish
326− - match: '(?=end(?:$|[\s;&)|<>]))'
329− - match: '(?=if\s+[^\s;)-])'
330− comment: If the command name is followed by a valid string (not anything that closes the scope or a string starting with a '-') then open the scope
332− - meta_scope: meta.block.if.fish
333− - match: 'end(?=$|[\s;&)|<>])'
335− 0: keyword.control.conditional.fish
337− - include: command-call-standard-block-if-internal
338− - match: '(?=for\s+[^\s;)-])'
339− comment: If the command name is followed by a valid string (not anything that closes the scope or a string starting with a '-') then open the scope
341− - meta_scope: meta.block.for-in.fish
342− - match: 'end(?=$|[\s;&)|<>])'
344− 0: keyword.control.conditional.fish
346− - match: (for)(?:\s+)
347− comment: Anonymous scope - Capture the command name we know is there, include a single instance of a parameter (the varname), and end when the whitespace after the varname is captured
349− 1: keyword.control.conditional.fish
353− - include: line-continuation
354− - include: parameter
356− comment: Capture anything that a parameter explicitly rejects, which is mostly operators
357− scope: invalid.illegal.operator.fish
358− - include: line-continuation
360− comment: Anonymous scope - Capture the command name which might be there, include an arbitrary number of arguments, and end when the control operator is seen
362− 0: keyword.control.conditional.fish
364− - match: '\s*(?=[\n;&)])'
366− - include: line-continuation
367− - include: comment-internal-end
369− - match: '\n|(;)|([&)])'
370− comment: Anonymous scope - Capture the operator we know is there, include the base scope, and end when an `end` command is seen
372− 1: keyword.operator.control.fish
373− 2: invalid.illegal.operator.fish
375− - match: '(?=end(?:$|[\s;&)|<>]))'
378− - match: '\S+?(?=[\s;&)])'
379− comment: Anything beside line continuation, "in", or a control operator is invalid
380− scope: invalid.illegal.function-call.fish
381− - match: '(?=switch\s+[^\s;)-])'
382− comment: If the command name is followed by a valid string (not anything that closes the scope or a string starting with a '-') then open the scope
384− - meta_scope: meta.block.switch.fish
385− - match: 'end(?=$|[\s;&)|<>])'
387− 0: keyword.control.conditional.fish
390− comment: Anonymous scope - Match the valid part of the switch statement, then look for an invalid part
392− - match: '\s*(?=[\n;&)])'
394− - match: (switch)(?:\s+)
395− comment: Anonymous scope - Capture the command name we know is there, include a single instance of a parameter (the value), and end when whitespace or a control operator is seen
397− 1: keyword.control.conditional.fish
399− - match: '(?=[\s;&)])'
401− - include: line-continuation
402− - include: parameter
404− comment: Capture anything that a parameter explicitly rejects, which is mostly operators
405− scope: invalid.illegal.operator.fish
407− comment: Anonymous scope - Capture whitespace which might be there, match any non-control-operator strings as invalid, and end when a control operator is seen
409− - match: '(?=[\n;&)])'
411− - match: '\S+?(?=[\s;&)])'
412− scope: invalid.illegal.string.fish
413− - match: '\n|(;)|([&)])'
414− comment: Anonymous scope - Capture the operator we know is there, include the base scope, and end when an `end` command is seen
416− 1: keyword.operator.control.fish
417− 2: invalid.illegal.operator.fish
419− - match: '(?=end(?:$|[\s;&)|<>]))'
421− - match: 'case(?=[\s;&)])'
422− comment: Anonymous scope - Capture the command name which might be there, include an arbitrary number of arguments, and end when the control operator is captured
424− 0: keyword.control.conditional.fish
426− - match: '\n|(;)|([&)])'
428− 1: keyword.operator.control.fish
429− 2: invalid.illegal.operator.fish
431− - include: line-continuation
432− - include: comment-internal-end
434− - match: '\S+?(?=[\s;&)])'
435− comment: Anything else (eg, redirection) is illegal
436− scope: invalid.illegal.operator.fish
438− - match: '(?=function\s+[^\s;)-])'
439− comment: If the command name is followed by a valid string (not anything that closes the scope or a string starting with a '-') then open the scope
441− - meta_scope: meta.block.function.fish
442− - match: 'end(?=$|[\s;&)|<>])'
444− 0: keyword.control.conditional.fish
446− - match: (?=function)
447− comment: Anonymous scope - Match the defined name of the function statement, then look for further parameters
449− - match: '\s*(?=[\n;&)])'
451− - match: (function)(?:\s+)
452− comment: Anonymous scope - Capture the command name we know is there, include a single instance of a parameter (the value), and end when whitespace or a control operator is seen
454− 1: keyword.control.conditional.fish
456− - match: '(?=[\s;&)])'
458− - include: line-continuation
459− - match: "(?:[()|<>])"
461− - meta_scope: invalid.illegal.string.fish
462− - match: '(?=[\s;&)])'
465− comment: Anonymous scope - Start when an escaped newline isn't present, and end when whitespace or an operator is seen
467− - match: '(?=[\s;&()|<>])'
471− - meta_scope: entity.name.function.fish
472− - match: '(?=[\s;&()|<>])'
474− - include: parameter
476− comment: Anonymous scope - Capture whitespace which might be there, then match anything normal for a command call
478− - match: '(?=[\n;&)])'
480− - include: line-continuation
481− - include: comment-internal-end
482− - include: redirection
483− - include: parameter
484− - match: '\n|(;)|([&)])'
485− comment: Anonymous scope - Capture the operator we know is there, include the base scope, and end when an `end` command is seen
487− 1: keyword.operator.control.fish
488− 2: invalid.illegal.operator.fish
490− - match: '(?=end(?:$|[\s;&)|<>]))'
493− command-call-standard-block-if-internal:
494− - match: '(?=if(?:\s*\n|\s+[^\s;]))'
495− comment: Anonymous scope - Capture an `if` and the command up to the control operator, then capture from the control operator indefinitely
497− - match: '(?=end(?:$|[\s;&)|<>]))'
500− comment: Anonymous scope - Match the command name we know is there, include a single instance of a pipeline, and end when a control operator is seen
502− 0: keyword.control.conditional.fish
504− - match: '\s*(?=[\n;&])'
506− - include: line-continuation
509− comment: Anonymous scope - Match the operator we know is there, then include the base scope or an `else` structure
511− 1: keyword.operator.control.fish
512− 2: invalid.illegal.operator.fish
514− - match: '(?=end(?:$|[\s;&)|<>]))'
516− - match: '(?=else\s*[\s;])'
517− comment: Anonymous scope - Capture an `else` up to the control operator or the start of an `if` structure, then match from the control operator indefinitely or match an `if` structure
519− - match: '(?=end(?:$|[\s;&)|<>]))'
521− - match: 'else(?=\s*[\s;])'
522− comment: Anonymous scope - Match the `else` we know is there and any comment, and mark anything besides an `if` as illegal
524− 0: keyword.control.conditional.fish
526− - match: '\s*(?=[\n;&]|if(?:\s*\n|\s+[^\s;]))'
528− - include: line-continuation
529− - include: comment-internal-end
530− - match: '\S+?(?=[\s;&])'
531− comment: Anything else is illegal
532− scope: invalid.illegal.string.fish
534− comment: Anonymous scope - Match the operator which will be there if no `if` was seen, then include the base scope which marks further `else` commands as invalid
536− 1: keyword.operator.control.fish
537− 2: invalid.illegal.operator.fish
539− - match: '(?=end(?:$|[\s;&)|<>]))'
542− - include: command-call-standard-block-if-internal
544− command-substitution:
546− comment: 'Capture "(...)" or "(...)[...]"'
548− - match: '(?![\(\[])'
552− 0: punctuation.section.parens.begin.fish
554− - meta_scope: meta.parens.command-substitution.fish
557− 0: punctuation.section.parens.end.fish
560− - include: index-expansion
563− comment: A full or inline comment outside of any command call
565− 0: punctuation.definition.comment.fish
567− - meta_scope: comment.line.external.fish
570− comment-internal-end:
572− comment: An inline comment at the end of a command call. Does not consume the newline, thus allowing the command call to capture it and end
574− 0: punctuation.definition.comment.fish
576− - meta_scope: comment.line.internal.end.fish
581− comment: In other words, the anonymous scope which contains the variable and the index expansion parameter list should only be allowed to contain a single copy of each of those two things. We cannot enforce that without a scope stack. Our workaround is to allow an infinite number of these and hope the user can keep track of when there are too many
583− 0: punctuation.section.brackets.begin.fish
585− - meta_scope: meta.brackets.index-expansion.fish
588− 0: punctuation.section.brackets.end.fish
591− scope: keyword.operator.range.fish
592− - include: command-substitution
593− - include: variable-expansion
594− - include: string-quoted
595− - match: '(?:[+-]?[0-9]+)(?=[\s;&)|<>]|\]|\.\.)'
596− scope: constant.numeric.fish
597− - match: '(?![\s''"]|\.\.)'
598− comment: 'Begin/end string as before with the addition of breaking at a '']'' or ".."'
600− - match: '(?=[\s;&)|<>''"]|\]|\.\.)'
602− - include: string-unquoted-patterns
605− comment: End when an unescaped newline is seen, the first character of a line isn't whitespace or a comment character or the escaped newline itself, or if the next character after some consumed whitespace isn't more whitespace or a comment character
607− - match: '(?=\n)|^(?![\s\#\\])|\s(?![\s\#])'
610− scope: constant.character.escape
613− 0: punctuation.definition.comment.fish
615− - meta_scope: comment.line.continuation.fish
619− - match: '(?![\s;&)|<>^])'
620− comment: See the argument rule for more general information on parameters
622− - match: '(?=[\s;&)|<>])'
624− - match: '(?:--)(?=[\s;&)|<>])'
625− comment: End of options (parameter of just two hyphens)
626− scope: meta.parameter.option.end.fish variable.parameter.fish punctuation.definition.option.end.fish meta.string.unquoted.fish
628− comment: Long option (parameter starting with two hyphens)
630− - meta_scope: meta.parameter.option.long.fish
631− - match: '(?=[\s;&)|<>])'
635− 0: punctuation.definition.option.long.begin.fish meta.string.unquoted.fish
637− - meta_scope: variable.parameter.fish
638− - match: '(?=[\s;&)|<>]|=)'
640− - include: command-substitution
643− - meta_scope: meta.string.unquoted.fish
646− - include: variable-expansion
647− - include: string-quoted
648− - match: '(?![''"])'
650− - meta_scope: meta.string.unquoted.fish
651− - match: '(?=[\s;&()|<>''"$]|\=)'
653− - include: string-unquoted-patterns
655− comment: Consume the '=' and then use standard parameter patterns as well as numerics
657− 0: variable.parameter.fish punctuation.definition.option.long.separator.fish meta.string.unquoted.fish
659− - match: '(?=[\s;&)|<>])'
661− - match: '(?:[+-]?)(?:[0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+)(?=$|[\s;&)|<>])'
662− scope: meta.string.unquoted.fish constant.numeric.fish
663− - include: parameter-patterns
664− - match: '(?:-)(?=[^\s;&)|<>])'
665− comment: Short option (parameter starting with one hyphen)
667− 0: punctuation.definition.option.short.fish meta.string.unquoted.fish
669− - meta_scope: meta.parameter.option.short.fish variable.parameter.fish
670− - match: '(?=[\s;&)|<>])'
672− - include: parameter-patterns
675− - include: command-substitution
677− comment: Give variable expansion the unquoted string scope
679− - meta_scope: meta.string.unquoted.fish
682− - include: variable-expansion
685− - match: '(?:[&|]|(?:[0-9]+)?(?:<|>>?|\^\^?))'
686− comment: Todo - Restructure pipeline so that this match isn't duplicated from the base scope, which it must also be for any other scopes which implement their own control operator consumption. Might require the unary operator commands to become an explicit recursive match (though we tried this once and it was more complicated than anything should be)
687− scope: invalid.illegal.operator.fish
688− - match: (and|or)\b(?!\s+-)
689− comment: Todo - These commands cannot be followed by backgrounding, piping, or redirection alone. Add logic to catch these cases. It will be extensive...
690− scope: meta.function-call.fish keyword.operator.word.fish
691− - include: line-continuation
692− - match: (not)\b(?!\s+-)
693− comment: This is a hack for now, which allows nesting of 'not' and 'and'/'or' commands. A better solution will be explicit recursivity in these commands
694− scope: meta.function-call.fish keyword.operator.word.fish
695− - match: '(?:case|else|end)(?=[\s;&)|<>])'
696− comment: Match a command which is illegal in the base scope
697− scope: invalid.illegal.function-call.fish
698− - match: '(?=[^\s#])'
699− comment: Anonymous scope - Pipeline. Define a pipeline as either one command call, or multiple command calls linked by pipe operators ('|', '2>|', etc). The pipeline terminates at the first encounter of any control operator
701− - match: '(\s*)(?=[\n;&)])'
703− 1: meta.function-call.fish
707− (?# Negative lookahead for piping)
709− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
711− comment: Match the first command of a potential pipeline
713− - meta_scope: meta.function-call.fish
716− (?# Look ahead for operators after whitespace)
719− (?# Find a control operator)
722− (?# Find a pipe operator)
723− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
727− - include: command-call-meta
728− - include: command-call-standard
731− (?# Look ahead for piping)
733− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
735− comment: Match a second or later command of a pipeline, starting with the connective piping
737− - meta_scope: meta.function-call.fish
738− - match: '(?=\s*[\n;&)])'
742− (?# Look ahead for piping followed by either control operators or piping)
744− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
751− (?:(?:[0-9]+)?(?:<|>>?|\^\^?))?\|
754− comment: Match a pipe not followed by a command, hence a malformed segment of the pipeline
756− - match: '(?=\s*$|\s*[\n;&)])'
758− - match: '(?:(?:[0-9]+)?(?:<|>|>>))?\|(?=\s*$|\s*[\n)])'
759− comment: If the pipeline would end implicitly (ie, with a newline or close parenthesis), then mark the pipe itself invalid
760− scope: invalid.illegal.operator.fish
763− (?# Consume valid piping; captures 1 2 3)
764− (?:([0-9]+)?(<|>>?|\^\^?))?(\|)
765− (?# Consume whitespace)
767− (?# Consume remainder; capture 4)
769− comment: If the pipeline would end with an explicit operator or encounter a second set of piping, then mark the first set of piping as valid and beyond as invalid
771− 1: meta.pipe.fish constant.numeric.file-descriptor.fish
772− 2: meta.pipe.fish keyword.operator.redirect.fish
773− 3: meta.pipe.fish keyword.operator.pipe.fish
774− 4: invalid.illegal.function-call.fish
775− - match: '(?:([0-9]+)?(<|>>?|\^\^?))?(\|)'
776− comment: Pick up a legitimate pipe
777− scope: meta.pipe.fish
779− 1: constant.numeric.file-descriptor.fish
780− 2: keyword.operator.pipe.redirect.fish
781− 3: keyword.operator.pipe.fish
782− - include: line-continuation
783− - include: command-call-meta
784− - include: command-call-standard
786− - match: '(?=(?:[0-9]+(?:<|>|>>)|>>|\^\^|[<>^])\&)'
787− comment: End at anything that would end a parameter, including redirections *if* they are *not* this same type of redirection (ie, have an '&'), in which case this scope stays open and we match the next one. The negative lookahead for <>^ at the end is to keep ST2 happy (not hanging)
789− - match: '(?=[\s;&)|]|(?:[0-9]+(?:<|>|>>)|>>|\^\^|[<>^])(?![&<>^]))'
791− - match: '(?:([0-9]+)(<|>|>>)|(>>|\^\^|[<>^]))(\&)\s*'
792− comment: We have to try and catch an '&' here because if it is seen by the outer end match then it will be considered a valid operator and the redirection scope will immediately terminate
794− 1: constant.numeric.file-descriptor.fish
795− 2: keyword.operator.redirect.fish
796− 3: keyword.operator.redirect.fish
797− 4: keyword.operator.redirect.dereference.fish
799− - meta_scope: meta.redirection.fish
800− - match: '(\&.*$)|(?![&\\])'
802− 1: invalid.illegal.file-descriptor.fish
804− - include: line-continuation
807− - meta_scope: meta.redirection.fish
810− - include: line-continuation
812− comment: Evaluates to a string which may be an integer
814− - meta_scope: meta.redirection.fish
817− - include: command-substitution
819− comment: Evaluates to a string which may be an integer
821− - meta_scope: meta.redirection.fish
824− - include: variable-expansion
825− - match: '(?=[''"])'
826− comment: May be a quoted integer, which is allowed
828− - meta_scope: meta.redirection.fish
829− - match: '(?![''"])'
831− - include: string-quoted
832− - match: '(?:[0-9]+)(?=$|[\s;&)|<>])'
833− scope: meta.redirection.file-descriptor.fish constant.numeric.file-descriptor.fish
834− - match: '(?:-)(?=$|[\s;&)|<>])'
835− scope: meta.redirection.file-descriptor.fish keyword.operator.redirect.close.fish
837− comment: Anything else is illegal
838− scope: meta.redirection.fish invalid.illegal.file-descriptor.fish
839− - match: '(?=(?:[0-9]+(?:<|>|>>)|>>|\^\^|[<>^])\??)'
840− comment: End at anything that would end a parameter, including redirections *if* they are *not* this same type of redirection (ie, redirection into file descriptor, or into pipe), in which case this scope stays open and we match the next one
842− - match: '(?=[\s;&)|]|(?:[0-9]+(?:<|>|>>)|>>|\^\^|[<>^])[&|])'
844− - match: '(?:([0-9]+)(<|>|>>)|(>>|\^\^|[<>^]))(\?)?\s*'
845− comment: We have to try and catch bad operators here because if they are seen by the outer end match then they will be considered valid and the redirection scope will immediately terminate
847− 1: constant.numeric.file-descriptor.fish
848− 2: keyword.operator.redirect.fish
849− 3: keyword.operator.redirect.fish
850− 4: keyword.operator.redirect.clobber-test.fish
852− - meta_scope: meta.redirection.fish
853− - match: "((?:[&?]|[0-9]*[<>^]).*$)|(?![&?<>^])"
855− 1: invalid.illegal.path.fish
857− - include: line-continuation
860− - meta_scope: meta.redirection.fish
863− - include: line-continuation
865− comment: Evaluates to a string, so path cannot begin with '('
867− - meta_scope: meta.redirection.fish
870− - include: command-substitution
872− comment: Evaluates to a string, so path cannot begin with '$'
874− - meta_scope: meta.redirection.fish
877− - include: variable-expansion
878− - match: "(?:[&?]|[0-9]*[<>^]).*$"
879− comment: Check for characters which are associated with redirection, so path cannot begin with them. Don't put them in the meta.redirection.path scope, so that only valid paths are in there
880− scope: meta.redirection.fish invalid.illegal.path.fish
882− scope: meta.redirection.path.fish keyword.operator.tilde.fish
883− - match: '(?:\''(?:\\[\''\\]|[^\''\\])*\''|\"(?:\\[\"$\n\\]|[^\"$\n\\])*\"|(?:\\[abefnrtv $\\*?#(){}\[\]<>^&;|"'']|\\[~%]|\\[xX][0-9A-Fa-f]{1,2}|\\[0-7]{1,3}|\\u[0-9A-Fa-f]{1,4}|\\U[0-9A-Fa-f]{1,8}|\\c[?-~]|[^\s$\\*?~%#()<>&|;"'']|\\(?=[^abefnrtv\s$\\*?#(){}\[\]<>^&;|"''xXuUc])|\\\n|[~%#])+)+'
884− comment: Use the function call match to build a file path, as the syntax is fairly similar (possibly identical, after exceptions caught above? I haven't checked)
885− scope: meta.redirection.path.fish
887− - include: string-quoted
888− - include: string-unquoted
892− 0: punctuation.definition.string.begin.fish
894− - meta_scope: string.quoted.single.fish
897− 0: punctuation.definition.string.end.fish
899− - match: '\\[\''\\]'
900− comment: Only accepted escapes are \' and \\
901− scope: constant.character.escape.fish
904− 0: punctuation.definition.string.begin.fish
906− - meta_scope: string.quoted.double.fish
909− 0: punctuation.definition.string.end.fish
911− - match: '\\[\n\"\\$]'
912− comment: Only accepted escapes are \<newline>, \", \\, and \$
913− scope: constant.character.escape.fish
914− - include: variable-expansion
916− - match: '(?![\s;&()|<>''"$])'
917− comment: End unquoted string at anything that can't be in one
919− - meta_scope: meta.string.unquoted.fish
920− - match: '(?=[\s;&()|<>''"$])'
922− - include: string-unquoted-patterns
923− string-unquoted-patterns:
926− \\[abefnrtv $\\*?#(){}\[\]<>^&|;"']
930− \\[xX][0-9A-Fa-f]{1,2}
939− comment: This list follows the order given in official fish documentation. Technically '~' and '%' only need escaping if they appear at the front of a parameter. If they are escaped within a parameter, then fish does not *highlight* the escape, however it does silently *parse* the escape and the backslash is removed before the parameter is passed to the command. So, we highlight these escapes as well since they are actually treated as valid escapes by fish
940− scope: constant.character.escape.fish
942− comment: Just for convenience we separate the newline escape
943− scope: constant.character.escape.fish
946− 0: punctuation.section.braces.begin.fish
948− - meta_scope: meta.braces.brace-expansion.fish
949− - match: '(\})|(\n|[;&)|].*)'
951− 1: punctuation.section.braces.end.fish
952− 2: invalid.illegal.punctuation.section.fish
955− scope: punctuation.section.braces.separator.fish
956− - include: command-substitution
957− - include: variable-expansion
958− - match: '(?:[^\S\n]+)'
959− comment: Unescaped spaces aren't allowed, as technically that separates the braces into two separate arguments. Don't consume a newline though, so the scope end capture can get it
960− scope: invalid.illegal.whitespace.fish
961− - include: string-quoted
962− - match: '(?:[+-]?)(?:[0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+)(?=$|[\s;&)|<>]|\}|\,)'
963− scope: constant.numeric.fish
964− - match: '(?![\s;&)|<>''"])'
965− comment: "Begin/end string as before with the addition of breaking at a '}' or ','"
967− - match: '(?=[\s;&)|<>''"]|\}|\,)'
970− scope: constant.character.escape.fish
971− - include: string-unquoted-patterns
972− - match: (\*\*)|(\*)|(\?)
973− scope: meta.wildcard-expansion.fish
975− 1: keyword.operator.double-star.fish
976− 2: keyword.operator.single-star.fish
977− 3: keyword.operator.question-mark.fish
979− - include: variable-expansion-illegal
981− comment: 'Capture "$foo" or "$foo[]" or "$$foo[][]" etc'
983− - meta_scope: meta.variable-expansion.fish
984− - match: '(?=[^\$\w\[])'
988− 0: punctuation.definition.variable.fish
990− - meta_scope: variable.other.fish
991− - match: '(?=[^\$\w])'
993− - include: variable-expansion-illegal
994− - include: variable-expansion-simple
995− - include: index-expansion
996− variable-expansion-illegal:
997− - match: '\$(?:(?=[,''"\]}\s;&)|])|[^\w\$][^$,''"\]}\s;&)|]*)'
998− comment: A lone '$' in a scope, or an attempt to expand a variable starting with a nonword character, is an error. These boundaries are the same as for meta.string.unquoted
999− scope: invalid.illegal.variable-expansion.fish
1000− variable-expansion-simple:
1003− 0: punctuation.definition.variable.fish
1005− - meta_scope: variable.other.fish
1006− - match: '(?=[^\$\w])'
1008− - include: variable-expansion-illegal
1009− - include: variable-expansion-simple