rework grammar to be friendly to injections
want to later support the case of multiple nix-shell directives in injection
This commit is contained in:
@@ -2,136 +2,84 @@
|
||||
empty nix-shell
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line)))
|
||||
(nix_shell_directive))
|
||||
|
||||
==================
|
||||
whitespace in nix-shell
|
||||
nix-shell no interpreter
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell
|
||||
#!nix-shell -p gnused
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line)))
|
||||
(nix_shell_directive))
|
||||
|
||||
==================
|
||||
minimal nix-shell invocation with interpreter
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg))))))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
whitespace in nix-shell
|
||||
==================
|
||||
|
||||
#! nix-shell -i bash
|
||||
---
|
||||
|
||||
(source_file
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
non-interpreter argument
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gnused
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg))
|
||||
(sh_arg)
|
||||
(sh_arg)))))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
non-interpreter flags
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gnused awk
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg))
|
||||
(sh_arg)
|
||||
(sh_arg)
|
||||
(sh_arg)))))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
quoted arguments
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash arg\ one 'arg"Two' "'argThree"
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg))
|
||||
(sh_arg)
|
||||
(sh_arg)
|
||||
(sh_arg)))))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
order-independent
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -p gnused -i bash
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(sh_arg)
|
||||
(sh_arg)
|
||||
(interpreter
|
||||
(sh_arg))))))
|
||||
|
||||
==================
|
||||
multiple annotation lines
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -p gnused
|
||||
#!nix-shell -i bash
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(sh_arg)
|
||||
(sh_arg))))
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg))))))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
@@ -1,3 +1,11 @@
|
||||
==================
|
||||
empty
|
||||
==================
|
||||
|
||||
---
|
||||
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell with a bash payload
|
||||
==================
|
||||
@@ -8,13 +16,8 @@ echo "hello, world!"
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg)))))
|
||||
(next_line))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
nix-shell with interspersed payload
|
||||
@@ -28,12 +31,39 @@ echo everybody
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line)
|
||||
(next_line)
|
||||
(next_line)
|
||||
(next_line
|
||||
(annotation_line
|
||||
(nix_shell_args
|
||||
(interpreter
|
||||
(sh_arg)))))
|
||||
(next_line))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
||||
==================
|
||||
nix-shell with multiple directives
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
echo hello
|
||||
#!nix-shell -p gnused
|
||||
#!nix-shell -i bash
|
||||
echo again
|
||||
#!nix-shell
|
||||
echo everybody
|
||||
---
|
||||
|
||||
(source_file
|
||||
(nix_shell_directive)
|
||||
(nix_shell_directive
|
||||
(interpreter))
|
||||
(nix_shell_directive))
|
||||
|
||||
==================
|
||||
nix-shell with conflicting interpreters (last wins, but good luck with that)
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash
|
||||
#!nix-shell -i python3
|
||||
---
|
||||
|
||||
(source_file
|
||||
(nix_shell_directive
|
||||
(interpreter))
|
||||
(nix_shell_directive
|
||||
(interpreter)))
|
||||
|
@@ -5,8 +5,7 @@ nix-shell shebang without any interpreter option
|
||||
#!/usr/bin/env nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell shebang whitespace
|
||||
@@ -15,8 +14,7 @@ nix-shell shebang whitespace
|
||||
#! /usr/bin/env nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell shebang tab
|
||||
@@ -25,8 +23,7 @@ nix-shell shebang tab
|
||||
#! /usr/bin/env nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell shebang tabs and spaces
|
||||
@@ -35,28 +32,7 @@ nix-shell shebang tabs and spaces
|
||||
#! /usr/bin/env nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
|
||||
==================
|
||||
nix-shell shebang no env
|
||||
==================
|
||||
|
||||
#!nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
|
||||
==================
|
||||
nix-shell shebang whitespace no env
|
||||
==================
|
||||
|
||||
#! nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell shebang via relative env
|
||||
@@ -65,8 +41,7 @@ nix-shell shebang via relative env
|
||||
#!env nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell shebang via /bin/env
|
||||
@@ -75,5 +50,14 @@ nix-shell shebang via /bin/env
|
||||
#!/bin/env nix-shell
|
||||
---
|
||||
|
||||
(source_file
|
||||
(first_line))
|
||||
(source_file)
|
||||
|
||||
==================
|
||||
nix-shell multiple shebangs
|
||||
==================
|
||||
|
||||
#!/usr/bin/env nix-shell
|
||||
#!/usr/bin/env nix-shell
|
||||
---
|
||||
|
||||
(source_file)
|
||||
|
43
grammar.js
43
grammar.js
@@ -2,26 +2,29 @@ module.exports = grammar({
|
||||
name: 'nix_shell',
|
||||
|
||||
rules: {
|
||||
// TODO: allow trailing whitespace on any line
|
||||
source_file: $ => seq($.first_line, repeat($.next_line)),
|
||||
|
||||
first_line: $ => seq($._shebang_open, $._opt_ws, optional(seq($._env, $._ws)), $._nix_shell),
|
||||
next_line: $ => seq($._newline, choice(
|
||||
$.annotation_line,
|
||||
repeat(/./),
|
||||
)),
|
||||
annotation_line: $ => seq($._shebang_open, $._opt_ws, $._nix_shell, optional($.nix_shell_args)),
|
||||
source_file: $ => seq(
|
||||
optional($._first_line),
|
||||
repeat($._next_line),
|
||||
),
|
||||
_first_line: $ => choice(
|
||||
$.nix_shell_directive,
|
||||
repeat1(/./),
|
||||
),
|
||||
_next_line: $ => seq('\n', $._first_line),
|
||||
nix_shell_directive: $ => seq(
|
||||
/#![ \t]*nix-shell/,
|
||||
repeat(seq($._ws, optional($._nix_shell_arg))),
|
||||
),
|
||||
|
||||
// nix acts as if it actually just `exec`'s whichever line contains `#! nix-shell` in the style of `sh`'s `exec`.
|
||||
// so arguments can be quoted, invoke subshells, interpolate environment variables, etc.
|
||||
// the full scope cannot be covered, but the minimal scope here gets 99% of use cases.
|
||||
nix_shell_args: $ => repeat1(seq($._ws, $._nix_shell_arg)),
|
||||
_nix_shell_arg: $ => choice(
|
||||
seq('-i', $._opt_ws, $.interpreter),
|
||||
$.sh_arg,
|
||||
$._sh_arg,
|
||||
),
|
||||
interpreter: $ => $.sh_arg,
|
||||
sh_arg: $ => choice(
|
||||
interpreter: $ => $._sh_arg,
|
||||
_sh_arg: $ => choice(
|
||||
$._sh_lit,
|
||||
$._sh_quote1,
|
||||
$._sh_quote2,
|
||||
@@ -47,20 +50,12 @@ module.exports = grammar({
|
||||
'"',
|
||||
),
|
||||
|
||||
_shebang_open: $ => '#!',
|
||||
// TODO: env accepts flags like `-v` or `--unset=NAME` or `VAR=VALUE` before `nix-shell`,
|
||||
_env: $ => choice(
|
||||
'/usr/bin/env',
|
||||
'/bin/env',
|
||||
'env',
|
||||
),
|
||||
_nix_shell: $ => 'nix-shell',
|
||||
// N.B.: this accepts more than it needs to:
|
||||
// - shebang parser allows tab characters
|
||||
// - #!nix-shell directives do not support tabs
|
||||
// - wherever #!nix-shell directives allow whitespace, it's a *single* space -- never multiple
|
||||
// - some places where whitespace is accepted (e.g. `#! nix-shell`), only a *single* space is accepted.
|
||||
// it's not clear how much of this is intentional, v.s. oversight in matching broader shell parsing,
|
||||
// so err on overaccepting in case future nix-shell supports these.
|
||||
_ws: $ => /[ \t]+/,
|
||||
_opt_ws: $ => /[ \t]*/,
|
||||
_newline: $ => '\n',
|
||||
}
|
||||
});
|
||||
|
8
queries/injections.scm
Normal file
8
queries/injections.scm
Normal file
@@ -0,0 +1,8 @@
|
||||
; if we find an interpreter, mark the *entire file* as injected content.
|
||||
; nix-shell doesn't process the source file before sending it to the interpreter,
|
||||
; so nix-shell directives like `#!nix-shell -i bash` are both a directive to nix-shell
|
||||
; and actual language content handled by the specified interpreter.
|
||||
((source_file
|
||||
(nix_shell_directive
|
||||
(interpreter) @injection.language)) @injection.content
|
||||
(#set! injection.include-children))
|
Reference in New Issue
Block a user