elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.62k stars 300 forks source link

edit namespace not resolving in child shell #1196

Open sblundy opened 3 years ago

sblundy commented 3 years ago

When a script is run with elvish script.elv, the edit: namespace isn't resolving correctly. My script is failing with:

Exception: exec: "edit:complete-filename": executable file not found in $PATH

Reproduction steps:

$ elvish -c 'resolve edit:complete-filename'
▶ '(external edit:complete-filename)'
$ resolve edit:complete-filename
▶ '$edit:complete-filename~'
$ resolve has-key
▶ '$has-key~'
$ elvish -c 'resolve has-key'
▶ '$has-key~'
$ resolve edit:complete-getopt
▶ '$edit:complete-getopt~'
$ elvish -c 'resolve edit:complete-getopt'
▶ '(external edit:complete-getopt)'
$  use math
$ math:log 1
▶ (float64 0)
$ elvish -c 'use math
math:log 1'
▶ (float64 0)

elvish -version: 0.14.1

zzamboni commented 3 years ago

Yes, edit is only available in interactive sessions.

On Sat, 12 Dec 2020 at 21:01, Steve Blundy notifications@github.com wrote:

When a script is run with elvish script.elv, the edit: namespace isn't resolving correctly. My script is failing with:

Exception: exec: "edit:complete-filename": executable file not found in $PATH

Reproduction steps:

$ elvish -c 'resolve edit:complete-filename'

▶ '(external edit:complete-filename)'

$ resolve edit:complete-filename

▶ '$edit:complete-filename~'

$ resolve has-key

▶ '$has-key~'

$ elvish -c 'resolve has-key'

▶ '$has-key~'

$ resolve edit:complete-getopt

▶ '$edit:complete-getopt~'

$ elvish -c 'resolve edit:complete-getopt'

▶ '(external edit:complete-getopt)'

$ use math

$ math:log 1

▶ (float64 0)

$ elvish -c 'use math

math:log 1'

▶ (float64 0)

elvish -version: 0.14.1

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/elves/elvish/issues/1196, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAIA3BP3XWXQZKETUSDRTLSUPD2TANCNFSM4UYSFSBA .

sblundy commented 3 years ago

Yes, edit is only available in interactive sessions.

This is happening in a test script for a completer function. Is there anyway to turn off this behavior or to inject a stub when it's run in non-interactive sessions?

zzamboni commented 3 years ago

@sblundy what you should do is load your test script as a library (instead of running it as an external process), then you can run any necessary functions from your interactive shell and have full access to all the namespaces.

krader1961 commented 3 years ago

If I understand correctly your real question is how to write unit tests for completions. Ideally it should be possible to run such tests in a manner similar to make test for running the core Elvish unit and integration tests. See file pkg/edit/complete/complete_test.go for how the core completion functionality is tested. But that approach isn't practical for third-party completions.

@zzamboni, You're probably the only one who has written non-trivial completions for Elvish. Haven't you ever wanted to be able to write tests for them that could be run in an automated manner (e.g., a CI like environment)?

sblundy commented 3 years ago

@sblundy what you should do is load your test script as a library (instead of running it as an external process), then you can run any necessary functions from your interactive shell and have full access to all the namespaces.

That runs afoul of namespace caching. If you run the test, changes something, then re-import and run the tests again, you'll get the same result as the first time. You can run elvish to open a child shell each time you want to run your tests, but that's 3-4 commands. elvish completions_test.elv is just one, so it's up arrow and ENTER.

I stuck this hack in the completion code. It's works but is sub-optimal.

complete-filename = $nil
if (!=s '$edit:complete-filename~' (resolve 'edit:complete-filename')) {
  complete-filename = [@words]{ put 'dummy.elv' }
} else {
  complete-filename = [@words]{ edit:complete-filename $@words }
}
zzamboni commented 3 years ago

@krader1961 @sblundy you are both right that this is suboptimal and makes testing harder. What I have done while developing my completions is just test interactively, starting a new subshell every time.

This was discussed some time ago, but I can't find the reference now. I believe @xiaq said at the time he would think about taking functions not directly related to the editor out of edit: so they could be used elsewhere, but maybe he can further comment on this 🙂