Skip to content

Commit

Permalink
interp: add an Interactive option to be used by cmd/gosh
Browse files Browse the repository at this point in the history
Otherwise aliases don't get expanded, as they are only on by default for
interactive shells in Bash, and we follow POSIX shell and Bash options.

Updates #1100.
  • Loading branch information
mvdan committed Oct 8, 2024
1 parent 4e19b5e commit 5f4e036
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 10 deletions.
2 changes: 1 addition & 1 deletion cmd/gosh/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func main() {
}

func runAll() error {
r, err := interp.New(interp.StdIO(os.Stdin, os.Stdout, os.Stderr))
r, err := interp.New(interp.Interactive(true), interp.StdIO(os.Stdin, os.Stdout, os.Stderr))
if err != nil {
return err
}
Expand Down
7 changes: 3 additions & 4 deletions cmd/gosh/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,10 @@ var interactiveTests = []struct {
pairs: []string{
"gosh_alias arg || true\n",
"\"gosh_alias\": executable file not found in $PATH\n$ ",
// TODO: aliases should be expanded by default, gosh is an interactive shell
"alias gosh_alias=echo\n",
"$ ",
"gosh_alias arg || true\n",
"\"gosh_alias\": executable file not found in $PATH\n$ ",
"arg\n$ ",
"unalias gosh_alias\n",
"$ ",
"gosh_alias arg || true\n",
Expand All @@ -200,7 +199,7 @@ func TestInteractive(t *testing.T) {
qt.Assert(t, qt.IsNil(err))
outReader, outWriter, err := os.Pipe()
qt.Assert(t, qt.IsNil(err))
runner, _ := interp.New(interp.StdIO(inReader, outWriter, outWriter))
runner, _ := interp.New(interp.Interactive(true), interp.StdIO(inReader, outWriter, outWriter))
errc := make(chan error, 1)
go func() {
errc <- runInteractive(runner, inReader, outWriter, outWriter)
Expand Down Expand Up @@ -255,7 +254,7 @@ func TestInteractiveExit(t *testing.T) {
inWriter.Close()
}()
w := io.Discard
runner, _ := interp.New(interp.StdIO(inReader, w, w))
runner, _ := interp.New(interp.Interactive(true), interp.StdIO(inReader, w, w))
if err := runInteractive(runner, inReader, w, w); err != nil {
t.Fatal("expected a nil error")
}
Expand Down
20 changes: 15 additions & 5 deletions interp/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,17 +192,17 @@ func New(opts ...RunnerOption) (*Runner, error) {
statHandler: DefaultStatHandler(),
}
r.dirStack = r.dirBootstrap[:0]
// turn "on" the default Bash options
for i, opt := range bashOptsTable {
r.opts[len(shellOptsTable)+i] = opt.defaultState
}

for _, opt := range opts {
if err := opt(r); err != nil {
return nil, err
}
}

// turn "on" the default Bash options
for i, opt := range bashOptsTable {
r.opts[len(shellOptsTable)+i] = opt.defaultState
}

// Set the default fallbacks, if necessary.
if r.Env == nil {
Env(nil)(r)
Expand Down Expand Up @@ -266,6 +266,16 @@ func Dir(path string) RunnerOption {
}
}

// Interactive configures the interpreter to behave like an interactive shell,
// akin to Bash. Currently, this only enables the expansion of aliases,
// but later on it should also change other behavior.
func Interactive(enabled bool) RunnerOption {
return func(r *Runner) error {
r.opts[optExpandAliases] = enabled
return nil
}
}

// Params populates the shell options and parameters. For example, Params("-e",
// "--", "foo") will set the "-e" option and the parameters ["foo"], and
// Params("+e") will unset the "-e" option and leave the parameters untouched.
Expand Down
1 change: 1 addition & 0 deletions interp/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func Example() {
`
file, _ := syntax.NewParser().Parse(strings.NewReader(src), "")
runner, _ := interp.New(
// Use [interp.Interactive] to enable interactive shell defaults like expanding aliases.
interp.Env(expand.ListEnviron("GLOBAL=global_value")),
interp.StdIO(nil, os.Stdout, os.Stdout),
)
Expand Down

0 comments on commit 5f4e036

Please sign in to comment.