Skip to content

Commit

Permalink
feat: Elvish Shell support (#1066)
Browse files Browse the repository at this point in the history
  • Loading branch information
elijahr committed Nov 18, 2021
1 parent 4b93bc8 commit cc7778a
Show file tree
Hide file tree
Showing 24 changed files with 704 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Expand Up @@ -22,6 +22,7 @@
*.sh text
*.bash text
*.fish text
*.elv text
#### asdf/bin/* explicitly define as text
*asdf text
*asdf-exec text
Expand Down
15 changes: 11 additions & 4 deletions .github/workflows/tests.yml
Expand Up @@ -28,15 +28,22 @@ jobs:

- name: Install test dependencies
if: runner.os == 'macos'
run: brew install coreutils fish
run: brew install coreutils fish elvish

- name: Install test dependencies
if: runner.os == 'linux'
run: |
PPA="ppa:fish-shell/nightly-master"
sudo add-apt-repository -y "$PPA"
sudo add-apt-repository -y ppa:fish-shell/nightly-master
sudo apt-get update
sudo apt-get -y install fish
sudo apt-get -y install fish curl
# Download elvish binary and add to path
curl https://dl.elv.sh/linux-amd64/elvish-v0.16.3.tar.gz -o elvish-v0.16.3.tar.gz
tar xzf elvish-v0.16.3.tar.gz
rm elvish-v0.16.3.tar.gz
mkdir -p "$HOME/bin"
mv elvish-v0.16.3 "$HOME/bin/elvish"
echo "$HOME/bin" >>"$GITHUB_PATH"
- name: Install bats
run: |
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
@@ -1,6 +1,7 @@
installs
/installs
/downloads
/plugins
shims
/shims
repository
.vagrant
keyrings
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -13,7 +13,7 @@ asdf is a CLI tool that can manage multiple language runtime versions on a per-p
- support for existing config files `.node-version`, `.nvmrc`, `.ruby-version` for easy migration
- automatically switches runtime versions as you traverse your directories
- simple plugin system to add support for your language of choice
- shell completion available for common shells (Bash, Zsh, Fish)
- shell completion available for common shells (Bash, Zsh, Fish, Elvish)

## Documentation

Expand Down
244 changes: 244 additions & 0 deletions asdf.elv
@@ -0,0 +1,244 @@

use re
use str
use path

var asdf_dir = $E:HOME'/.asdf'
if (and (has-env ASDF_DIR) (!=s $E:ASDF_DIR '')) {
asdf_dir = $E:ASDF_DIR
} else {
set-env ASDF_DIR $asdf_dir
}

var asdf_data_dir = $asdf_dir
if (and (has-env ASDF_DATA_DIR) (!=s $E:ASDF_DATA_DIR '')) {
asdf_data_dir = $E:ASDF_DATA_DIR
}

# Add function wrapper so we can export variables
fn asdf [command @args]{
if (==s $command 'shell') {
# set environment variables
parts = [($asdf_dir'/bin/asdf' export-shell-version elvish $@args)]
if (==s $parts[0] 'set-env') {
set-env $parts[1] $parts[2]
} elif (==s $parts[0] 'unset-env') {
unset-env $parts[1]
}
} else {
# forward other commands to asdf script
$asdf_dir'/bin/asdf' $command $@args
}
}

fn match [argz @pats]{
var matched = $true;
if (!= (count $argz) (count $pats)) {
matched = $false
} else {
for i [(range (count $pats))] {
pat = '^'$pats[$i]'$'
arg = $argz[$i]
if (not (re:match $pat $arg)) {
matched = $false
break
}
}
}
put $matched
}

fn ls-shims []{
ls $asdf_data_dir'/shims'
}

fn ls-executables []{
# Print all executable files and links in path
try {
find $@paths '(' -type f -o -type l ')' -print 2>/dev/null | each [p]{
try {
if (test -x $p) {
path:base $p
}
} except {
# don't fail if permission denied
}
}
} except {
# silence default non-zero exit status
}
}

fn ls-installed-versions [plugin_name]{
asdf list $plugin_name | each [version]{
put (re:replace '\s*(.*)\s*' '${1}' $version)
}
}

fn ls-all-versions [plugin_name]{
asdf list-all $plugin_name | each [version]{
put (re:replace '\s*(.*)\s*' '${1}' $version)
}
}

# Append ~/.asdf/bin and ~/.asdf/shims to PATH
for path [
$asdf_dir'/bin'
$asdf_data_dir'/shims'
] {
if (not (has-value $paths $path)) {
paths = [
$@paths
$path
]
}
}

# Setup argument completions
fn arg-completer [@argz]{
argz = $argz[1:-1] # strip 'asdf' and trailing empty string
var num = (count $argz)
if (== $num 0) {
# list all subcommands
find $asdf_dir'/lib/commands' -name 'command-*' | each [cmd]{
put (re:replace '.*/command-(.*)\.bash' '${1}' $cmd)
}
put 'plugin'
} else {
if (match $argz 'current') {
# asdf current <name>
asdf plugin-list
} elif (match $argz 'env') {
# asdf env <command>
ls-shims
} elif (match $argz 'env' '.*') {
# asdf env <command> [util]
ls-executables
} elif (match $argz 'exec') {
# asdf exec <command>
ls-shims
} elif (match $argz 'global') {
# asdf global <name>
asdf plugin-list
} elif (match $argz 'global' '.*') {
# asdf global <name> <version>
ls-installed-versions $argz[-1]
} elif (match $argz 'install') {
# asdf install <name>
asdf plugin-list
} elif (match $argz 'install' '.*') {
# asdf install <name> <version>
ls-all-versions $argz[-1]
} elif (match $argz 'install' '.*' '.*') {
# asdf install <name> <version> [--keep-download]
put '--keep-download'
} elif (match $argz 'latest') {
# asdf latest <name>
asdf plugin-list
} elif (match $argz 'latest' '.*') {
# asdf latest <name> [<version>]
ls-all-versions $argz[-1]
} elif (match $argz 'list-all') {
# asdf list all <name>
asdf plugin-list
} elif (match $argz 'list-all' '.*') {
# asdf list all <name> [<version>]
ls-all-versions $argz[-1]
} elif (match $argz 'list') {
# asdf list <name>
asdf plugin-list
} elif (match $argz 'list' '.*') {
# asdf list <name> [<version>]
ls-installed-versions $argz[-1]
} elif (match $argz 'local') {
# asdf local <name> [-p|--parent]
asdf plugin-list
put '-p'
put '--parent'
} elif (match $argz 'local' '(-p|(--parent))') {
# asdf local <name> [-p|--parent] <version>
asdf plugin-list
} elif (match $argz 'local' '.*') {
# asdf local <name> [-p|--parent]
# asdf local <name> <version>
ls-installed-versions $argz[-1]
put '-p'
put '--parent'
} elif (match $argz 'local' '(-p|(--parent))' '.*') {
# asdf local [-p|--parent] <name> <version>
ls-installed-versions $argz[-1]
} elif (match $argz 'local' '.*' '(-p|(--parent))') {
# asdf local <name> [-p|--parent] <version>
ls-installed-versions $argz[-2]
} elif (match $argz 'local' '.*' '.*') {
# asdf local <name> <version> [-p|--parent]
put '-p'
put '--parent'
} elif (or (match $argz 'plugin-add') (match $argz 'plugin' 'add')) {
# asdf plugin add <name>
asdf plugin-list-all | each [line]{
put (re:replace '([^\s]+)\s+.*' '${1}' $line)
}
} elif (or (match $argz 'plugin-list') (match $argz 'plugin' 'list')) {
# asdf plugin list
put '--urls'
put '--refs'
put 'all'
} elif (or (match $argz 'plugin-push') (match $argz 'plugin' 'push')) {
# asdf plugin push <name>
asdf plugin-list
} elif (or (match $argz 'plugin-remove') (match $argz 'plugin' 'remove')) {
# asdf plugin remove <name>
asdf plugin-list
} elif (and (>= (count $argz) 3) (match $argz[:3] 'plugin-test' '.*' '.*')) {
# asdf plugin-test <plugin-name> <plugin-url> [--asdf-tool-version <version>] [--asdf-plugin-gitref <git-ref>] [test-command*]
put '--asdf-plugin-gitref'
put '--asdf-tool-version'
ls-executables
ls-shims
} elif (and (>= (count $argz) 4) (match $argz[:4] 'plugin' 'test' '.*' '.*')) {
# asdf plugin test <plugin-name> <plugin-url> [--asdf-tool-version <version>] [--asdf-plugin-gitref <git-ref>] [test-command*]
put '--asdf-plugin-gitref'
put '--asdf-tool-version'
ls-executables
ls-shims
} elif (or (match $argz 'plugin-update') (match $argz 'plugin' 'update')) {
# asdf plugin update <name>
asdf plugin-list
put '--all'
} elif (match $argz 'plugin') {
# list plugin-* subcommands
find $asdf_dir'/lib/commands' -name 'command-plugin-*' | each [cmd]{
put (re:replace '.*/command-plugin-(.*)\.bash' '${1}' $cmd)
}
} elif (match $argz 'reshim') {
# asdf reshim <name>
asdf plugin-list
} elif (match $argz 'reshim' '.*') {
# asdf reshim <name> <version>
ls-installed-versions $argz[-1]
} elif (match $argz 'shim-versions') {
# asdf shim-versions <command>
ls-shims
} elif (match $argz 'uninstall') {
# asdf uninstall <name>
asdf plugin-list
} elif (match $argz 'uninstall' '.*') {
# asdf uninstall <name> <version>
ls-installed-versions $argz[-1]
} elif (match $argz 'update') {
if (== $num 1) {
# asdf update
put '--head'
}
} elif (match $argz 'where') {
# asdf where <name>
asdf plugin-list
} elif (match $argz 'where' '.*') {
# asdf where <name> [<version>]
ls-installed-versions $argz[-1]
} elif (match $argz 'which') {
ls-shims
}
}
}
4 changes: 2 additions & 2 deletions asdf.fish
Expand Up @@ -2,9 +2,9 @@ set -x ASDF_DIR (dirname (status -f))

set -l asdf_user_shims (
if test -n "$ASDF_DATA_DIR"
echo $ASDF_DATA_DIR/shims
printf "%s\n" "$ASDF_DATA_DIR/shims"
else
echo $HOME/.asdf/shims
printf "%s\n" "$HOME/.asdf/shims"
end
)

Expand Down
2 changes: 1 addition & 1 deletion asdf.sh
Expand Up @@ -16,7 +16,7 @@ if [ -z "$ASDF_DIR" ]; then
fi
export ASDF_DIR
# shellcheck disable=SC2016
[ -d "$ASDF_DIR" ] || echo '$ASDF_DIR is not a directory'
[ -d "$ASDF_DIR" ] || printf '$ASDF_DIR is not a directory'

# Add asdf to PATH
#
Expand Down
40 changes: 40 additions & 0 deletions docs/guide/getting-started.md
Expand Up @@ -142,6 +142,46 @@ source /opt/asdf-vm/asdf.fish
Completions are automatically configured on installation by the AUR package.
:::

::: details Elvish & Git

Add `asdf.elv` to your `~/.elvish/rc.elv` with:

```shell:no-line-numbers
mkdir -p ~/.elvish/lib; ln -s ~/.asdf/asdf.elv ~/.elvish/lib/asdf.elv
echo "\n"'use asdf _asdf; fn asdf [@args]{_asdf:asdf $@args}' >> ~/.elvish/rc.elv
echo "\n"'edit:completion:arg-completer[asdf] = $_asdf:arg-completer~' >> ~/.elvish/rc.elv
```

Completions are automatically configured.

:::

::: details Elvish & Homebrew

Add `asdf.elv` to your `~/.elvish/rc.elv` with:

```shell:no-line-numbers
mkdir -p ~/.elvish/lib; ln -s (brew --prefix asdf)/libexec/asdf.elv ~/.elvish/lib/asdf.elv
echo "\n"'use asdf _asdf; fn asdf [@args]{_asdf:asdf $@args}' >> ~/.elvish/rc.elv
echo "\n"'edit:completion:arg-completer[asdf] = $_asdf:arg-completer~' >> ~/.elvish/rc.elv
```

Completions are automatically configured.
:::

::: details Elvish & Pacman

Add `asdf.elv` to your `~/.elvish/rc.elv` with:

```shell:no-line-numbers
mkdir -p ~/.elvish/lib; ln -s /opt/asdf-vm/asdf.elv ~/.elvish/lib/asdf.elv
echo "\n"'use asdf _asdf; fn asdf [@args]{_asdf:asdf $@args}' >> ~/.elvish/rc.elv
echo "\n"'edit:completion:arg-completer[asdf] = $_asdf:arg-completer~' >> ~/.elvish/rc.elv
```

Completions are automatically configured.
:::

::: details ZSH & Git

Add the following to `~/.zshrc`:
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Expand Up @@ -19,7 +19,7 @@ features:
- title: "One Config File"
details: ".tool-versions to manage all your tools, runtimes and their versions in a single, sharable place."
- title: "Shells"
details: "Supports Bash, ZSH & Fish with completions available."
details: "Supports Bash, ZSH, Fish & Elvish with completions available."
- title: "GitHub Actions"
details: "Provides a GitHub Action to install and utilize your .tool-versions in your CI/CD workflows."
# footer: MIT Licensed
Expand Down
2 changes: 1 addition & 1 deletion docs/manage/configuration.md
Expand Up @@ -101,7 +101,7 @@ Configure the duration since the last asdf plugin repository sync to the next. C
- `ASDF_CONFIG_FILE` - Defaults to `~/.asdfrc` as described above. Can be set to any location.
- `ASDF_DEFAULT_TOOL_VERSIONS_FILENAME` - The filename of the file storing the tool names and versions. Defaults to `.tool-versions`. Can be any valid filename. Typically you should not override the default value unless you know you want asdf to ignore `.tool-versions` files.
- `ASDF_DIR` - Defaults to `~/.asdf` - Location of the `asdf` scripts. If you install `asdf` to some other directory, set this to that directory. For example, if you are installing via the AUR, you should set this to `/opt/asdf-vm`.
- `ASDF_DATA_DIR` - Defaults to `~/.asdf` - Location where `asdf` install plugins, shims and installs. Can be set to any location before sourcing `asdf.sh` or `asdf.fish` mentioned in the section above.
- `ASDF_DATA_DIR` - Defaults to `~/.asdf` - Location where `asdf` install plugins, shims and installs. Can be set to any location before sourcing `asdf.sh` or `asdf.fish` mentioned in the section above. For Elvish, this can be set above `use asdf`.

## Internal Configuration

Expand Down

0 comments on commit cc7778a

Please sign in to comment.