mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
[CLI] Add zsh completions and auto-install completions
This commit is contained in:
3
Makefile
3
Makefile
@@ -153,7 +153,7 @@ s2n-ubuntu-deps:
|
||||
unzip \
|
||||
valgrind \
|
||||
zlib1g-dev \
|
||||
zlibc \
|
||||
zlib \
|
||||
cmake \
|
||||
tox \
|
||||
libtool \
|
||||
@@ -626,6 +626,7 @@ test-dev-bun-run:
|
||||
cd integration/apps && BUN_BIN=$(DEBUG_BUN) bash bun-run-check.sh
|
||||
|
||||
test-dev-all: test-dev-with-hmr test-dev-no-hmr test-dev-create-next test-dev-create-react test-dev-bun-run
|
||||
test-dev-bunjs:
|
||||
|
||||
test-dev: test-dev-with-hmr
|
||||
|
||||
|
||||
8
completions/bun.bash
Normal file
8
completions/bun.bash
Normal file
@@ -0,0 +1,8 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
# This is not implemented yet.
|
||||
# But a PR implementing it would be very welcome!
|
||||
_bun_completions() {
|
||||
}
|
||||
|
||||
complete -F _bun_completions bun
|
||||
@@ -6,44 +6,54 @@ function __fish__get_bun_scripts
|
||||
string split ' ' (bun getcompletes s)
|
||||
end
|
||||
|
||||
function __fish__get_bun_bun_js_files
|
||||
string split ' ' (bun getcompletes j)
|
||||
end
|
||||
|
||||
|
||||
set -l bun_builtin_cmds dev create help bun upgrade discord run
|
||||
set -l bun_builtin_cmds_without_run dev create help bun upgrade discord
|
||||
set -l bun_builtin_cmds_without_create dev help bun upgrade discord run
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a '(__fish__get_bun_bins)' -d 'package bin'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a '(__fish__get_bun_bins)' -d 'package bin'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a '(__fish__get_bun_scripts)' -d 'script'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from run" -a '(__fish__get_bun_bins)' -d 'package bin'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from run" -a '(__fish__get_bun_scripts)' -d 'script'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from run" -a '(__fish__get_bun_bun_js_files)' -d 'Bun.js'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts) and __fish_use_subcommand" -a 'run' -f -d 'Run a script or bin'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'u' -l 'origin' -r -d 'Server URL. Rewrites import paths'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'p' -l 'port' -r -d 'Port number to start server from'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'd' -l 'define' -r -d 'Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\"'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'e' -l 'external' -r -d 'Exclude module from transpilation (can use * wildcards). ex: -e react'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -l 'use' -r -d 'Use a framework (ex: next)'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts) and __fish_use_subcommand" -a 'dev' -d 'Start dev server'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -F -a 'create' -d 'Create a new project from a template'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_create next react; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from create" -f -a 'next' -d 'Create a new Next.js project'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_create next react; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from create" -f -a 'react' -d 'Create a new React project'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_create; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from create next" -F
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a 'upgrade' -d 'Upgrade Bun to the latest version' -x
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a '--help' -d 'See all commands and flags' -x
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a '(__fish__get_bun_scripts)' -d 'script'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from run" -a '(__fish__get_bun_bins)' -d 'package bin'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_run; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from run" -a '(__fish__get_bun_scripts)' -d 'script'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts) and __fish_use_subcommand" -a 'run' -d 'Run a script or bin'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'u' -l 'origin' -r -d 'Server URL. Rewrites import paths'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'p' -l 'port' -r -d 'Port number to start server from'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'd' -l 'define' -r -d 'Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\"'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -s 'e' -l 'external' -r -d 'Exclude module from transpilation (can use * wildcards). ex: -e react'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts);" -F -l 'use' -r -d 'Use a framework (ex: next)'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts) and __fish_use_subcommand" -a 'dev' -d 'Start dev server'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -F -a 'create' -d 'Create a new project from a template'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_create next react; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from create" -f -a 'next' -d 'Create a new Next.js project'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_create next react; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from create" -f -a 'react' -d 'Create a new React project'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds_without_create; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_seen_subcommand_from create next" -F
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -x -a 'upgrade' -d 'Upgrade Bun to the latest version'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -x -a '--help' -d 'See all commands and flags'
|
||||
|
||||
complete -c bun -n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -x -a 'discord' -d 'Open Bun\'s Discord server'
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -l "version" -s "v" -a '--version' -d 'Bun\'s version' -x
|
||||
complete -c bun \
|
||||
-n "not __fish_seen_subcommand_from $bun_builtin_cmds; and not __fish_seen_subcommand_from (__fish__get_bun_bins); and not __fish_seen_subcommand_from (__fish__get_bun_scripts); and __fish_use_subcommand" -a 'discord' -d 'Open Bun\'s Discord server' -x
|
||||
|
||||
|
||||
63
completions/bun.zsh
Normal file
63
completions/bun.zsh
Normal file
@@ -0,0 +1,63 @@
|
||||
__bun_first_cmd() {
|
||||
echo "${words[2]}"
|
||||
}
|
||||
|
||||
__bun_first_cmd_arg() {
|
||||
echo "${words[3]}"
|
||||
}
|
||||
|
||||
__bun_arg_count() {
|
||||
echo "$#words"
|
||||
}
|
||||
|
||||
_bun_run() {
|
||||
if [[ ("$(__bun_arg_count)" = "2") ]]; then
|
||||
local -a options
|
||||
options=(${(f)"$(SHELL=zsh bun getcompletes)"})
|
||||
|
||||
_describe 'values' options
|
||||
elif [[ ("$(__bun_arg_count)" = "3") ]]; then
|
||||
local -a run
|
||||
run=("${(f)"$(SHELL=zsh bun getcompletes g)"}")
|
||||
compadd $run
|
||||
else
|
||||
_files
|
||||
return
|
||||
fi
|
||||
|
||||
# Make sure we don't run default completion
|
||||
custom_completion=true
|
||||
}
|
||||
|
||||
_bun() {
|
||||
|
||||
# Store custom completion status
|
||||
local custom_completion=false
|
||||
|
||||
# Load custom completion commands
|
||||
case "$(__bun_first_cmd)" in
|
||||
create)
|
||||
return;
|
||||
;;
|
||||
dev)
|
||||
return;
|
||||
;;
|
||||
bun)
|
||||
return;
|
||||
;;
|
||||
upgrade)
|
||||
return;
|
||||
;;
|
||||
discord)
|
||||
return;
|
||||
;;
|
||||
run)
|
||||
_bun_run
|
||||
;;
|
||||
esac
|
||||
|
||||
# Fall back to default completion if we haven't done a custom one
|
||||
[[ $custom_completion = false ]] && _bun_run
|
||||
}
|
||||
|
||||
compdef _bun bun
|
||||
@@ -48,7 +48,8 @@ pub const Run = struct {
|
||||
} else {
|
||||
run.vm.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false) catch {};
|
||||
}
|
||||
|
||||
Output.prettyErrorln("\n", .{});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
run.vm.bundler.configureDefines() catch |err| {
|
||||
@@ -57,7 +58,8 @@ pub const Run = struct {
|
||||
} else {
|
||||
run.vm.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false) catch {};
|
||||
}
|
||||
|
||||
Output.prettyErrorln("\n", .{});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
|
||||
|
||||
247
src/cli.zig
247
src/cli.zig
@@ -613,7 +613,244 @@ pub const Command = struct {
|
||||
}
|
||||
|
||||
pub const InstallCompletionsCommand = struct {
|
||||
pub fn exec(ctx: *std.mem.Allocator) !void {}
|
||||
pub fn testPath(completions_dir: string) !std.fs.Dir {}
|
||||
pub fn exec(allocator: *std.mem.Allocator) !void {
|
||||
var shell = ShellCompletions.Shell.unknown;
|
||||
if (std.os.getenv("SHELL")) |shell_name| {
|
||||
shell = ShellCompletions.Shell.fromEnv(@TypeOf(shell_name), shell_name);
|
||||
}
|
||||
|
||||
switch (shell) {
|
||||
.bash => {
|
||||
Output.prettyErrorln("<r><red>error:<r> Bash completions aren't implemented yet, just zsh & fish. A PR is welcome!", .{});
|
||||
std.os.exit(1);
|
||||
},
|
||||
.unknown => {
|
||||
Output.prettyErrorln("<r><red>error:<r> Unknown or unsupported shell. Please set $SHELL to one of zsh, fish, or bash. To manually output completions, run this:\n bun getcompletes", .{});
|
||||
std.os.exit(1);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var stdout = std.io.getStdOut();
|
||||
|
||||
if (std.os.getenvZ("IS_BUN_AUTO_UPDATE") == null) {
|
||||
if (!stdout.isTty()) {
|
||||
try stdout.writeAll(shell.completions());
|
||||
std.os.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
var completions_dir: string = "";
|
||||
found: {
|
||||
var cwd_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||
var cwd = std.os.getcwd(&cwd_buf) catch {
|
||||
Output.prettyErrorln("<r><red>error<r>: Could not get current working directory", .{});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
|
||||
for (std.os.argv) |arg, i| {
|
||||
if (strings.eqlComptime(std.mem.span(arg), "completions")) {
|
||||
if (std.os.argv.len > i + 1) {
|
||||
const input = std.mem.span(std.os.argv[i + 1]);
|
||||
|
||||
if (!std.fs.path.isAbsolute(input)) {
|
||||
completions_dir = resolve_path.joinAbs(
|
||||
cwd,
|
||||
.auto,
|
||||
input,
|
||||
);
|
||||
}
|
||||
|
||||
if (!std.fs.path.isAbsolute(completions_dir)) {
|
||||
Output.prettyErrorln("<r><red>error:<r> Please pass an absolute path. {s} is invalid", .{completions_dir});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
}
|
||||
|
||||
std.os.access(completions_dir, std.os.O_DIRECTORY | std.os.O_WRONLY) catch |err| {
|
||||
Output.prettyErrorln("<r><red>error:<r> accessing {s} errored {s}", .{ completions_dir, @errorName(err) });
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
|
||||
break :found;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (shell) {
|
||||
.fish => {
|
||||
if (std.os.getenvZ("XDG_CONFIG_HOME")) |config_dir| {
|
||||
outer: {
|
||||
var paths = [_]string{ std.mem.span(config_dir), "./fish/completions" };
|
||||
completions_dir = resolve_path.joinAbsString(cwd, &paths, .auto);
|
||||
std.os.access(completions_dir, std.os.O_DIRECTORY | std.os.O_WRONLY) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}:<r> accessing {s}, trying next one.", .{
|
||||
@errorName(err),
|
||||
completions_dir,
|
||||
});
|
||||
Output.flush();
|
||||
break :outer;
|
||||
};
|
||||
break :found;
|
||||
}
|
||||
}
|
||||
|
||||
if (std.os.getenvZ("XDG_DATA_HOME")) |data_dir| {
|
||||
outer: {
|
||||
var paths = [_]string{ std.mem.span(data_dir), "./fish/completions" };
|
||||
completions_dir = resolve_path.joinAbsString(cwd, &paths, .auto);
|
||||
|
||||
std.os.access(completions_dir, std.os.O_DIRECTORY | std.os.O_WRONLY) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}:<r> accessing {s}, trying next one.", .{
|
||||
@errorName(err),
|
||||
completions_dir,
|
||||
});
|
||||
Output.flush();
|
||||
break :outer;
|
||||
};
|
||||
|
||||
break :found;
|
||||
}
|
||||
}
|
||||
|
||||
if (std.os.getenvZ("HOME")) |home_dir| {
|
||||
outer: {
|
||||
var paths = [_]string{ std.mem.span(home_dir), "./.config/fish/completions" };
|
||||
completions_dir = resolve_path.joinAbsString(cwd, &paths, .auto);
|
||||
std.os.access(completions_dir, std.os.O_DIRECTORY | std.os.O_WRONLY) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}:<r> accessing {s}, trying next one.", .{
|
||||
@errorName(err),
|
||||
completions_dir,
|
||||
});
|
||||
Output.flush();
|
||||
break :outer;
|
||||
};
|
||||
break :found;
|
||||
}
|
||||
}
|
||||
|
||||
outer: {
|
||||
if (Environment.isMac) {
|
||||
if (!Environment.isAarch64) {
|
||||
// homebrew fish
|
||||
completions_dir = "/usr/local/share/fish/completions";
|
||||
std.os.access(completions_dir, std.os.O_WRONLY | std.os.O_DIRECTORY) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}:<r> accessing {s}, trying next one.", .{
|
||||
@errorName(err),
|
||||
completions_dir,
|
||||
});
|
||||
Output.flush();
|
||||
break :outer;
|
||||
};
|
||||
break :found;
|
||||
} else {
|
||||
// homebrew fish
|
||||
completions_dir = "/opt/homebrew/share/fish/completions";
|
||||
std.os.access(completions_dir, std.os.O_WRONLY | std.os.O_DIRECTORY) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}:<r> accessing {s}, trying next one.", .{
|
||||
@errorName(err),
|
||||
completions_dir,
|
||||
});
|
||||
Output.flush();
|
||||
break :outer;
|
||||
};
|
||||
break :found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
completions_dir = "/etc/fish/completions";
|
||||
std.os.access(completions_dir, std.os.O_WRONLY | std.os.O_DIRECTORY) catch |err| {
|
||||
Output.prettyErrorln(
|
||||
"<r><red>error:<r> Could not find a directory to install completions in. Please either pipe \"bun completions > /to/a/file\" or pass a directory in like this:\n bun completions /my/completions/dir",
|
||||
.{},
|
||||
);
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
break :found;
|
||||
}
|
||||
},
|
||||
.zsh => {
|
||||
if (std.os.getenvZ("fpath")) |fpath| {
|
||||
var splitter = std.mem.split(u8, std.mem.span(fpath), " ");
|
||||
|
||||
while (splitter.next()) |dir| {
|
||||
std.os.access(dir, std.os.O_DIRECTORY | std.os.O_WRONLY) catch continue;
|
||||
completions_dir = dir;
|
||||
break :found;
|
||||
}
|
||||
}
|
||||
},
|
||||
.bash => {
|
||||
Output.prettyErrorln("<r><red>error:<r> Please pass a directory or pipe to a file. Not sure where bash completions go.", .{});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
Output.prettyErrorln(
|
||||
"<r><red>error:<r> Could not find a directory to install completions in. Please either pipe \"bun completions > /to/a/file\" or pass a directory in like this:\n bun completions /my/completions/dir",
|
||||
.{},
|
||||
);
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
}
|
||||
|
||||
const filename = switch (shell) {
|
||||
.fish => "bun.fish",
|
||||
.zsh => "_bun",
|
||||
.bash => "_bun.bash",
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
std.debug.assert(completions_dir.len > 0);
|
||||
|
||||
var output_dir = std.fs.openDirAbsolute(completions_dir, .{ .iterate = true }) catch |err| {
|
||||
Output.prettyErrorln("<r><red>error:<r> Could not open {s} for writing: {s}", .{
|
||||
completions_dir,
|
||||
@errorName(err),
|
||||
});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
|
||||
var output_file = output_dir.createFileZ(filename, .{
|
||||
.truncate = true,
|
||||
}) catch |err| {
|
||||
Output.prettyErrorln("<r><red>error:<r> Could not open {s} for writing: {s}", .{
|
||||
filename,
|
||||
@errorName(err),
|
||||
});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
|
||||
output_file.writeAll(shell.completions()) catch |err| {
|
||||
Output.prettyErrorln("<r><red>error:<r> Could not write to {s}: {s}", .{
|
||||
filename,
|
||||
@errorName(err),
|
||||
});
|
||||
Output.flush();
|
||||
std.os.exit(1);
|
||||
};
|
||||
|
||||
output_file.close();
|
||||
output_dir.close();
|
||||
|
||||
Output.prettyErrorln("<r><d>Installed completions to {s}/{s}<r>", .{
|
||||
completions_dir,
|
||||
filename,
|
||||
});
|
||||
Output.flush();
|
||||
}
|
||||
};
|
||||
|
||||
const default_completions_list = [_]string{
|
||||
@@ -651,6 +888,10 @@ pub const Command = struct {
|
||||
|
||||
try BuildCommand.exec(ctx);
|
||||
},
|
||||
.InstallCompletionsCommand => {
|
||||
try InstallCompletionsCommand.exec(allocator);
|
||||
return;
|
||||
},
|
||||
.GetCompletionsCommand => {
|
||||
const ctx = try Command.Context.create(allocator, log, .GetCompletionsCommand);
|
||||
var filter = ctx.positionals;
|
||||
@@ -677,6 +918,10 @@ pub const Command = struct {
|
||||
completions = try RunCommand.completions(ctx, null, .bin);
|
||||
} else if (strings.eqlComptime(filter[0], "r")) {
|
||||
completions = try RunCommand.completions(ctx, null, .all);
|
||||
} else if (strings.eqlComptime(filter[0], "g")) {
|
||||
completions = try RunCommand.completions(ctx, null, .all_plus_bun_js);
|
||||
} else if (strings.eqlComptime(filter[0], "j")) {
|
||||
completions = try RunCommand.completions(ctx, null, .bun_js);
|
||||
}
|
||||
|
||||
completions.print();
|
||||
|
||||
@@ -13,41 +13,40 @@ BGreen=''
|
||||
|
||||
if test -t 1; then
|
||||
# Reset
|
||||
Color_Off='\033[0m' # Text Reset
|
||||
Color_Off='\033[0m' # Text Reset
|
||||
|
||||
# Regular Colors
|
||||
Red='\033[0;31m' # Red
|
||||
Green='\033[0;32m' # Green
|
||||
White='\033[0;37m' # White
|
||||
Red='\033[0;31m' # Red
|
||||
Green='\033[0;32m' # Green
|
||||
White='\033[0;37m' # White
|
||||
|
||||
# Bold
|
||||
BGreen='\033[1;32m' # Green
|
||||
BWhite='\033[1;37m' # White
|
||||
BGreen='\033[1;32m' # Green
|
||||
BWhite='\033[1;37m' # White
|
||||
fi
|
||||
|
||||
|
||||
if ! command -v unzip >/dev/null; then
|
||||
echo -e "${Red}error${Color_Off}: unzip is required to install Bun (see: https://github.com/Jarred-Sumner/bun#unzip-is-required)." 1>&2
|
||||
exit 1
|
||||
echo -e "${Red}error${Color_Off}: unzip is required to install Bun (see: https://github.com/Jarred-Sumner/bun#unzip-is-required)." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OS" = "Windows_NT" ]; then
|
||||
echo "error: Please install Bun using Windows Subsystem for Linux."
|
||||
echo "error: Please install Bun using Windows Subsystem for Linux."
|
||||
exit 1
|
||||
else
|
||||
case $(uname -sm) in
|
||||
"Darwin x86_64") target="darwin-x64" ;;
|
||||
"Darwin arm64") target="darwin-aarch64" ;;
|
||||
*) target="linux-x64" ;;
|
||||
esac
|
||||
case $(uname -sm) in
|
||||
"Darwin x86_64") target="darwin-x64" ;;
|
||||
"Darwin arm64") target="darwin-aarch64" ;;
|
||||
*) target="linux-x64" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
github_repo="https://github.com/Jarred-Sumner/bun-releases-for-updater"
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
bun_uri="$github_repo/releases/latest/download/bun-${target}.zip"
|
||||
bun_uri="$github_repo/releases/latest/download/bun-${target}.zip"
|
||||
else
|
||||
bun_uri="$github_repo/releases/download/${1}/bun-${target}.zip"
|
||||
bun_uri="$github_repo/releases/download/${1}/bun-${target}.zip"
|
||||
fi
|
||||
|
||||
bun_install="${BUN_INSTALL:-$HOME/.bun}"
|
||||
@@ -55,27 +54,32 @@ bin_dir="$bun_install/bin"
|
||||
exe="$bin_dir/bun"
|
||||
|
||||
if [ ! -d "$bin_dir" ]; then
|
||||
mkdir -p "$bin_dir"
|
||||
mkdir -p "$bin_dir"
|
||||
|
||||
if (($?)); then
|
||||
echo -e "${Red}error${Color_Off}: Failed to create install directory $bin_dir" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
curl --fail --location --progress-bar --output "$exe.zip" "$bun_uri"
|
||||
|
||||
if (( $? )); then
|
||||
if (($?)); then
|
||||
echo -e "${Red}error${Color_Off}: Failed to download Bun from $bun_uri" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
unzip -d "$bin_dir" -q -o "$exe.zip"
|
||||
if (( $? )); then
|
||||
if (($?)); then
|
||||
echo -e "${Red}error${Color_Off}: Failed to extract Bun" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
mv "$bin_dir/bun-${target}/bun" "$exe"
|
||||
if (( $? )); then
|
||||
if (($?)); then
|
||||
echo -e "${Red}error${Color_Off}: Failed to extract Bun" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
chmod +x "$exe"
|
||||
if (( $? )); then
|
||||
if (($?)); then
|
||||
echo -e "${Red}error${Color_Off}: Failed to set permissions on bun executable." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -85,22 +89,47 @@ rm "$exe.zip"
|
||||
echo -e "${Green}Bun was installed successfully to ${BGreen}$exe$Color_Off"
|
||||
|
||||
if command -v bun --version >/dev/null; then
|
||||
# Install completions, but we don't care if it fails
|
||||
IS_BUN_AUTO_UPDATE="true" $exe completions >/dev/null 2>&1
|
||||
|
||||
echo "Run 'bun --help' to get started"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test $(basename $SHELL) == "fish"; then
|
||||
echo ""
|
||||
echo "Manually add the directory to your \$HOME/.config/fish"
|
||||
echo ""
|
||||
echo -e " $BWhite set -Ux BUN_INSTALL \"$bun_install\"$Color_Off"
|
||||
echo -e " $BWhite set -px --path PATH \"$bin_dir\"$Color_Off"
|
||||
elif test $(basename $SHELL) == "zsh"; then
|
||||
echo ""
|
||||
echo "Manually add the directory to your \$HOME/.zshrc (or similar)"
|
||||
echo ""
|
||||
echo -e " $BWhite export BUN_INSTALL=\"$bun_install\"$Color_Off"
|
||||
echo -e " $BWhite export PATH=\"\$BUN_INSTALL/bin:\$PATH\"$Color_Off"
|
||||
# Install completions, but we don't care if it fails
|
||||
IS_BUN_AUTO_UPDATE="true" SHELL="fish" $exe completions >/dev/null 2>&1
|
||||
if test -f $HOME/.config/fish; then
|
||||
echo -e "\nset -Ux BUN_INSTALL \"$bun_install\"\n" >>"$HOME/.config/fish"
|
||||
echo -e "\nset -px --path PATH \"$bin_dir\"\n" >>"$HOME/.config/fish"
|
||||
echo ""
|
||||
echo -e "$BWhite Added \"$bin_dir\" to PATH in \"$HOME/.config/fish\"$Color_Off"
|
||||
else
|
||||
echo ""
|
||||
echo "Manually add the directory to your \$HOME/.config/fish"
|
||||
echo ""
|
||||
echo -e " $BWhite set -Ux BUN_INSTALL \"$bun_install\"$Color_Off"
|
||||
echo -e " $BWhite set -px --path PATH \"$bin_dir\"$Color_Off"
|
||||
fi
|
||||
elif
|
||||
test $(basename $SHELL) == "zsh"
|
||||
then
|
||||
# Install completions, but we don't care if it fails
|
||||
IS_BUN_AUTO_UPDATE="true" SHELL="zsh" $exe completions >/dev/null 2>&1
|
||||
|
||||
if test -f $HOME/.zshrc; then
|
||||
echo -e "export BUN_INSTALL=\"$bun_install\"" >>"$HOME/.zshrc"
|
||||
echo -e "export PATH=\"\$BUN_INSTALL/bin:\$PATH\"" >>"$HOME/.zshrc"
|
||||
echo ""
|
||||
echo -e "$BWhite Added \"$bin_dir\" to PATH in \"$HOME/.zshrc\"$Color_Off"
|
||||
else
|
||||
echo ""
|
||||
echo "Manually add the directory to your \$HOME/.zshrc (or similar)"
|
||||
echo ""
|
||||
echo -e " $BWhite export BUN_INSTALL=\"$bun_install\"$Color_Off"
|
||||
echo -e " $BWhite export PATH=\"\$BUN_INSTALL/bin:\$PATH\"$Color_Off"
|
||||
fi
|
||||
|
||||
else
|
||||
echo ""
|
||||
echo "Manually add the directory to your \$HOME/.bashrc (or similar)"
|
||||
@@ -111,4 +140,4 @@ fi
|
||||
echo ""
|
||||
echo -e "To get started, run"
|
||||
echo -e "$BWhite"
|
||||
echo -e " bun --help$Color_Off"
|
||||
echo -e " bun --help$Color_Off"
|
||||
|
||||
@@ -273,6 +273,8 @@ pub const RunCommand = struct {
|
||||
script,
|
||||
bin,
|
||||
all,
|
||||
bun_js,
|
||||
all_plus_bun_js,
|
||||
};
|
||||
|
||||
pub fn completions(ctx: Command.Context, default_completions: ?[]const string, comptime filter: Filter) !ShellCompletions {
|
||||
@@ -327,7 +329,7 @@ pub const RunCommand = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (filter == Filter.bin or filter == Filter.all) {
|
||||
if (filter == Filter.bin or filter == Filter.all or filter == Filter.all_plus_bun_js) {
|
||||
for (this_bundler.resolver.binDirs()) |bin_path| {
|
||||
if (this_bundler.resolver.readDirInfo(bin_path) catch null) |bin_dir| {
|
||||
if (bin_dir.getEntriesConst()) |entries| {
|
||||
@@ -360,7 +362,22 @@ pub const RunCommand = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (filter == Filter.script or filter == Filter.all) {
|
||||
if (filter == Filter.all_plus_bun_js or filter == Filter.bun_js) {
|
||||
if (this_bundler.resolver.readDirInfo(this_bundler.fs.top_level_dir) catch null) |dir_info| {
|
||||
if (dir_info.getEntriesConst()) |entries| {
|
||||
var iter = entries.data.iterator();
|
||||
|
||||
while (iter.next()) |entry| {
|
||||
const name = entry.value.base();
|
||||
if (this_bundler.options.loader(std.fs.path.extension(name)).isJavaScriptLike() and !strings.contains(name, ".d.ts") and entry.value.kind(&this_bundler.fs.fs) == .file) {
|
||||
_ = try results.getOrPut(this_bundler.fs.filename_store.append(@TypeOf(name), name) catch continue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filter == Filter.script or filter == Filter.all or filter == Filter.all_plus_bun_js) {
|
||||
if (root_dir_info.enclosing_package_json) |package_json| {
|
||||
if (package_json.scripts) |scripts| {
|
||||
try results.ensureUnusedCapacity(scripts.count());
|
||||
|
||||
@@ -7,6 +7,19 @@ pub const Shell = enum {
|
||||
zsh,
|
||||
fish,
|
||||
|
||||
const bash_completions = @embedFile("../../completions/bun.bash");
|
||||
const zsh_completions = @embedFile("../../completions/bun.zsh");
|
||||
const fish_completions = @embedFile("../../completions/bun.fish");
|
||||
|
||||
pub fn completions(this: Shell) []const u8 {
|
||||
return switch (this) {
|
||||
.bash => std.mem.span(bash_completions),
|
||||
.zsh => std.mem.span(zsh_completions),
|
||||
.fish => std.mem.span(fish_completions),
|
||||
else => "",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromEnv(comptime Type: type, SHELL: Type) Shell {
|
||||
const basename = std.fs.path.basename(SHELL);
|
||||
if (strings.eqlComptime(basename, "bash")) {
|
||||
@@ -30,12 +43,13 @@ pub fn print(this: @This()) void {
|
||||
var writer = Output.writer();
|
||||
|
||||
if (this.commands.len == 0) return;
|
||||
const delimiter = if (this.shell == Shell.fish) " " else "\n";
|
||||
|
||||
writer.writeAll(this.commands[0]) catch return;
|
||||
|
||||
if (this.commands.len > 1) {
|
||||
for (this.commands[1..]) |cmd, i| {
|
||||
writer.writeAll(" ") catch return;
|
||||
writer.writeAll(delimiter) catch return;
|
||||
|
||||
writer.writeAll(cmd) catch return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ pub fn ExactSizeMatcher(comptime max_bytes: usize) type {
|
||||
const a: u32 = 1000;
|
||||
|
||||
switch (max_bytes) {
|
||||
1, 2, 4, 8, 12 => {},
|
||||
1, 2, 4, 8, 12, 16 => {},
|
||||
else => {
|
||||
@compileError("max_bytes must be 1, 2, 4, 8, or 12.");
|
||||
},
|
||||
@@ -64,3 +64,10 @@ test "ExactSizeMatcher 4 letter" {
|
||||
try expect(Four.match(word) == Four.case("from"));
|
||||
try expect(Four.match(word) != Four.case("fro"));
|
||||
}
|
||||
|
||||
test "ExactSizeMatcher 12 letter" {
|
||||
const Four = ExactSizeMatcher(12);
|
||||
const word = "from";
|
||||
try expect(Four.match(word) == Four.case("from"));
|
||||
try expect(Four.match(word) != Four.case("fro"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user