Open balupton opened 1 year ago
I'm guessing that it doesn't exist yet, and when it does exit it would be at $runtime:is-interactive
and $runtime:is-login
— https://elv.sh/ref/runtime.html
The Fish shell needs those tests because its config.fish script is loaded by every Fish shell; regardless of whether it is interactive or not. Elvish does not need the equivalent because its rc.elv script is only loaded if the shell is interactive. It is also unlikely that Elvish will ever distinguish between login and non-login interactive shells. So it is sufficient to simply add, without any conditional code, your initialization statements to rc.elv. Although, I personally prefer that utilities like Dorothy simply tell me what to add rather than munging my startup script. If you do decide to automatically see https://elv.sh/ref/runtime.html#$runtime:effective-rc-path and https://elv.sh/ref/runtime.html#$runtime:rc-path.
Okie, so getting the following:
# https://elv.sh/ref/command.html#rc-file
# https://elv.sh/ref/runtime.html
# https://github.com/elves/elvish/issues/1726
if ?(not-eq $runtime:effective-rc-path $nil) {
...
}
Exception: Compilation error: variable $runtime:effective-rc-path not found
[eval 1]:13:13: if ?(not-eq $runtime:effective-rc-path $nil) {
edit: nevermind, didn't realise I needed use runtime
Although, I personally prefer that utilities like Dorothy simply tell me what to add rather than munging my startup script.
That's the plan.
nevermind, didn't realise I needed use runtime)
That is a very common mistake. So common that it might be worthwhile to modify the error message to suggest to the user that they should use
the module. However, that would make the error message extremely verbose and thus requires some thought regarding whether the verbosity is justified.
FWIW, I am a grey beard. I started programming in the 1970's and got acquainted with UNIX in the mid 1980's. Which means I was familiar with the concept of a "login" shell as a shell spawned by the getty
program (or equiavalent) versus subsequent sub-shells. That distinction is no longer relevant and I am surprised that modern shells like Xonsh still make that distinction.
This seems the final head scratcher for me:
#!/usr/bin/env fish
echo 'theme='$E:DOROTHY_THEME
if ?(has-env DOROTHY_THEME_OVERRIDE) {
set-env DOROTHY_THEME $E:DOROTHY_THEME_OVERRIDE
}
echo 'theme='$E:DOROTHY_THEME
if ?(and $true ?(has-env DOROTHY_THEME) ?(not-eq $E:DOROTHY_THEME 'system' '' $nil)) {
if ?(test -f $E:DOROTHY'/user/themes/'$E:DOROTHY_THEME'.elv') {
eval (cat $E:DOROTHY'/user/themes/'$E:DOROTHY_THEME'.elv' | slurp)
} elif ?(test -f $E:DOROTHY'/themes/'$E:DOROTHY_THEME'.elv') {
eval (cat $E:DOROTHY'/themes/'$E:DOROTHY_THEME'.elv' | slurp)
} else {
echo-style --warning='Dorothy theme ['$E:DOROTHY_THEME'] is not supported by this shell [elvish]' >/dev/stderr
}
}
# @todo if no theme is defined, I don't know why this outputs:
# Dorothy theme [] is not supported by this shell [elvish]
Is outputting:
theme=starship
▶ $false
theme=
▶ $true
▶ $true
▶ $ok
Dorothy theme [] is not supported by this shell [elvish]
Which is baffling me as to why an empty or non-defined DOROTHY_THEME_OVERRIDE is causing DOROTHY_THEME to be set to it, and then why my sanity checks of and $true ...
and not-eq ...
are not preventing:
Dorothy theme [] is not supported by this shell [elvish]
I'm guessing this, and the $true
and $false
outputs have to do with my possibly/probably incorrect fix to this error of the following code by wrapping the if clause in ?(
if has-env DOROTHY_THEME_OVERRIDE {
set-env DOROTHY_THEME $E:DOROTHY_THEME_OVERRIDE
}
Exception: Compilation error: if body must be lambda, found primary expression of type Bareword
[eval 7]:5:12: if has-env DOROTHY_THEME_OVERRIDE {
Traceback:
[eval 5]:16:1:
eval (cat $E:DOROTHY'/sources/theme.elv' | slurp)
[eval 1]:16:1:
eval (cat $E:DOROTHY'/sources/interactive.elv' | slurp)
/Users/balupton/.config/elvish/rc.elv:1:1:
eval (cat '/Users/balupton/.local/share/dorothy/init.elv' | slurp) # Dorothy
I tried to search for resources, but this was the only result: https://github.com/search?q=%22if+body+must+be+lambda%22&type=issues
Figured it out, needed ( ... )
instead of ?( ... )
for builtins
#!/usr/bin/env fish
if (has-env DOROTHY_THEME_OVERRIDE) {
set-env DOROTHY_THEME $E:DOROTHY_THEME_OVERRIDE
}
if (and $true (has-env DOROTHY_THEME) (not-eq $E:DOROTHY_THEME 'system')) {
if ?(test -f $E:DOROTHY'/user/themes/'$E:DOROTHY_THEME'.elv') {
eval (cat $E:DOROTHY'/user/themes/'$E:DOROTHY_THEME'.elv' | slurp)
} elif ?(test -f $E:DOROTHY'/themes/'$E:DOROTHY_THEME'.elv') {
eval (cat $E:DOROTHY'/themes/'$E:DOROTHY_THEME'.elv' | slurp)
} else {
echo-style --warning='Dorothy theme ['$E:DOROTHY_THEME'] is not supported by this shell [elvish]' >/dev/stderr
}
}
!/usr/bin/env fish
I am going to assume that is a typo. :-)
if ?(has-env DOROTHY_THEME_OVERRIDE)
You have misunderstood the purpose of the ?(...)
operator. It is intended to keep external commands that exit with a non-zero status from terminating the Elvish shell. See https://elv.sh/ref/language.html#exception-capture. It is not relevant to that example. f
Thank you. I also found https://elv.sh/learn/unique-semantics.html very useful.
One final thing, related to CI. I'm now trying to test the Dorothy integration with Elvish on CI, and getting:
Run # when given a file, elvish no longer loads its rc file, so we will load ourselves:
# when given a file, elvish no longer loads its rc file, so we will load ourselves:
eval (cat '/home/runner/.config/elvish/rc.elv' | slurp)
# continue as normal
command-exists dorothy
echo-style --success='ok'
shell: /usr/bin/elvish {0}
Exception: no such module: runtime
Traceback:
[eval 2], line 2:
use runtime
[eval 1], line 1:
eval (cat '/home/runner/.local/share/dorothy/init.elv' | slurp) # Dorothy
/home/runner/work/_temp/7846f7c7-61f2-4796-989b-0f34db63505c, line 2:
eval (cat '/home/runner/.config/elvish/rc.elv' | slurp)
https://github.com/bevry/dorothy/actions/runs/6439819213/job/17487942227#step:9:1
Prior to that, I had tried this with the same error:
Run # when given a file, elvish no longer loads its rc file, so we will load ourselves:
# when given a file, elvish no longer loads its rc file, so we will load ourselves:
use runtime
eval (cat $runtime:rc-path | slurp)
# continue as normal
command-exists dorothy
echo-style --success='ok'
shell: /usr/bin/elvish {0}
Exception: no such module: runtime
/home/runner/work/_temp/d3ab71e9-bc6d-4aa4-9340-00b013d1a213, line 2: use runtime
Error: Process completed with exit code 2.
https://github.com/bevry/dorothy/actions/runs/6439804989/job/17487912535#step:9:2
It's installing elvish 0.17.0-1
Preparing to unpack .../elvish_0.17.0-1_amd64.deb ...
Unpacking elvish (0.17.0-1) ...
Setting up elvish (0.17.0-1) ...
Processing triggers for man-db (2.10.2-1) ...
NEEDRESTART-VER: 3.5
NEEDRESTART-KCUR: 6.2.0-1012-azure
NEEDRESTART-KEXP: 6.2.0-1012-azure
NEEDRESTART-KSTA: 1
The [elvish] utility was installed via [apt]
The [elvish] utility was installed. ✅
Will try using the prebuilt binaries instead.
Same situation was 0.19.2 prebuilt binary:
Run # when given a file, elvish no longer loads its rc file, so we will load ourselves:
# when given a file, elvish no longer loads its rc file, so we will load ourselves:
eval (cat '/home/runner/.config/elvish/rc.elv' | slurp)
# continue as normal
command-exists dorothy
echo-style --success='ok'
shell: /home/runner/.local/bin/elvish {0}
Exception: exec: "command-exists": executable file not found in $PATH
/home/runner/work/_temp/68ce339b-5cac-433a-b052-c0c13250e5e5:4:1: command-exists dorothy
Error: Process completed with exit code 2.
https://github.com/bevry/dorothy/actions/runs/6440000404/job/17488345034#step:9:1
The eval
command creates a new namespace. It does not behave like you are used to with POSIX shells like Bash. See https://elv.sh/ref/builtin.html#eval. It should also be avoided. Rather than using eval
use a relative import: https://elv.sh/ref/language.html#relative-imports.
if (and $true (has-env DOROTHY_THEME) (not-eq $E:DOROTHY_THEME 'system')) {
There is no need for $true
in that statement.
Exception: exec: "command-exists": executable file not found in $PATH
Is command-exists
a function you're defining?
It is unclear why you are loading rc.elv. That file would typically contain statements that don't make sense, and won't even work, in a non-interactive shell. For example, key bindings, command abbreviations, and REPL variable definitions. Here are just a couple of examples from my rc.elv:
# Arrange for [alt-e] and [alt-v] to edit the current command buffer using my
# prefered external editor.
set edit:insert:binding[Alt-e] = $interactive:external-edit-command~
set edit:insert:binding[Alt-v] = $interactive:external-edit-command~
# Populate the interactive REPL namespace with functions we want usable
# without requiring their namespace prefix; e.g., `ff` rather than `util:ff`.
edit:add-var cd~ $interactive:cd~
edit:add-var coff~ $util:coff~
edit:add-var con~ $util:con~
set edit:command-abbr['ds'] = 'try { pkill -x VLC } catch { }; pmset displaysleepnow'
set edit:command-abbr['gam'] = 'hub am -3'
set edit:command-abbr['gb'] = 'git branch'
It would be simpler to put whatever you're inserting into rc.elv into a different file that also includes your unit tests then simply execute that test script; e.g., elvish /path/to/test.elv
.
The
eval
command creates a new namespace. It does not behave like you are used to with POSIX shells like Bash. See https://elv.sh/ref/builtin.html#eval. It should also be avoided. Rather than usingeval
use a relative import: https://elv.sh/ref/language.html#relative-imports.
I couldn't get relative imports working properly:
> elvish
Exception: no such module: ../../.local/share/dorothy/init.elv
/Users/balupton/.config/elvish/rc.elv:1:1: use '../../.local/share/dorothy/init.elv' # Dorothy
~/.local/share/dorothy> exit
13:04:48:/Users/balupton/.local/share/dorothy:master
> cat /Users/balupton/.config/elvish/../../.local/share/dorothy/init.elv
#!/usr/bin/env elvish
use runtime
# this should be consistent with:
# $DOROTHY/init.*
# $DOROTHY/commands/dorothy
if (not (has-env 'DOROTHY')) {
set-env 'DOROTHY' $E:HOME'/.local/share/dorothy'
}
# https://elv.sh/ref/command.html#rc-file
# https://elv.sh/ref/runtime.html
# https://github.com/elves/elvish/issues/1726
if (not-eq $runtime:effective-rc-path $nil) {
use './sources/login.elv'
use './sources/interactive.elv'
}
Using a absolute path also did not work:
> elvish
Exception: no such module: /Users/balupton/.local/share/dorothy/init.elv
/Users/balupton/.config/elvish/rc.elv:1:1: use '/Users/balupton/.local/share/dorothy/init.elv' # Dorothy
~/.local/share/dorothy> cat /Users/balupton/.local/share/dorothy/init.elv
#!/usr/bin/env elvish
use runtime
# this should be consistent with:
# $DOROTHY/init.*
# $DOROTHY/commands/dorothy
if (not (has-env 'DOROTHY')) {
set-env 'DOROTHY' $E:HOME'/.local/share/dorothy'
}
# https://elv.sh/ref/command.html#rc-file
# https://elv.sh/ref/runtime.html
# https://github.com/elves/elvish/issues/1726
if (not-eq $runtime:effective-rc-path $nil) {
use './sources/login.elv'
use './sources/interactive.elv'
}
There is no need for
$true
in that statement.
👍
Is
command-exists
a function you're defining?
Yes, providing the Dorothy configuration is loaded (which modifies the PATH).
It is unclear why you are loading rc.elv. That file would typically contain statements that don't make sense, and won't even work, in a non-interactive shell. For example, key bindings, command abbreviations, and REPL variable definitions. Here are just a couple of examples from my rc.elv:
Understood, will import Dorothy's configuration directly.
Using a absolute path also did not work.
For good or bad absolute import paths are not supported at this time.
Your most recent change to your project is still using eval
and expecting the functions and variables it defines to be visible after the eval
:
eval (cat '/home/runner/.local/share/dorothy/init.elv' | slurp)
That won't work without jumping through more hoops. In particular see the discussion about using the &on-end
flag at https://elv.sh/ref/builtin.html#eval. But that is the hard way to do it for your situation. Just create an Elvish script that imports your module then references its content via its namespace. Export an (XDG_DATA_DIRS
)[https://elv.sh/ref/command.html#module-search-directories] env var that includes your Elvish module directory.
@balupton Were you able to get your Elvish integration to work (in which case this should be closed) or do you need more assistance?
The integration worked well enough. I'm leaving anything else up to any potential future dorothy and elvish user. Happy to close, thanks for all your assistance
Elvish does not need the equivalent because its rc.elv script is only loaded if the shell is interactive.
I wish this was documented in "Unique Semantics" or something. Had to dig my way here to figure this out.
That said, how does elvish handle user-applied paths? Say I have a cross-compile SDK in ~/sdks/lgtv
to cross-compile software. This is a user-local path, so there wouldn't be a reason to add it into something like /etc/profile.d
. How would I make elvish aware of that path when just doing something like elvish -c arm-webos-gcc ...
?
I wish this was documented in "Unique Semantics" or something.
It's documented here.
That said, how does elvish handle user-applied paths?
It's not clear what you mean by "user-applied paths" or "user-local path". I'm guessing you mean customization of the PATH
env var in the shell startup script(s). Not that POSIX shells like Bash also do not run ~/.bashrc, ~/.bash_profile, etc. (or whatever their equivalent of Elvish's rc.elv is) for non-interactive invocations. Elvish is no different from those shells. It is different from shells like Fish which do load their startup script regardless of whether or not the Fish process is interactive.
Elvish will inherit the PATH
env var from the process that launches it. So the usual answer is to configure that process (or its parent process) to initialize PATH
to suit your needs. You can also explicitly import an Elvish module that initializes PATH
. For example, I have a ~/.config/elvish/lib/env.elv module where I initialize my preferred PATH
value (among other things) that can be imported in an Elvish script with use env
.
I've scanned the website and can't seem to find the answer to this. I've also searched for where I should post discussions, but the README doesn't mention anywhere, and CONTRIBUTING.md mentions a user group with no link.
in fish:
in nu:
in xonsh:
My use case is adding Elvish support to https://github.com/bevry/dorothy which will integrate with Elvish by adding itself to the rc script, and loading different config for interactive and login.