Update the build-dir shell function to usage zcurses instead of the Python pick package to interactively select build directories, this results in a more responsive user experience. Add argument parsing to handle various use cases. Add prompt when the build command for the selected build directory could not be detected, allowing the user to specify the desired build command. ``` usage: build-dir [-h] [--build] [<directory>] Find and select the current build directory interactively. positional arguments: <directory> the build directory to select optional arguments: -h, --help show this help message and exit --build invoke a build after selection ```
167 lines
4.9 KiB
Bash
167 lines
4.9 KiB
Bash
# A collection of commands to make it easier to build projects.
|
|
|
|
# Default `build` alias to select a `build-dir` then invoke a build, using an
|
|
# alias means the configured build command's completion works out of the box.
|
|
alias build="build-dir --build"
|
|
|
|
# Detect installed debugger and set the `debug` alias to debug a program with
|
|
# command line arguments.
|
|
if [ `uname` = Linux ]; then
|
|
if which cgdb &> /dev/null; then
|
|
alias debug='cgdb --args'
|
|
elif which gdb &> /dev/null; then
|
|
alias debug='gdb --args'
|
|
fi
|
|
elif [ `uname` = Darwin ]; then
|
|
which lldb &> /dev/null && \
|
|
alias debug='lldb --'
|
|
fi
|
|
|
|
# Interactively choose a `~build` directory for `build` to build.
|
|
build-dir() {
|
|
local usage='usage: build-dir [-h] [--build] [<directory>]'
|
|
local -a help do_build
|
|
zparseopts -D h=help -help=help -build=do_build
|
|
if [[ -n $help ]]; then
|
|
cat << EOF
|
|
$usage
|
|
|
|
Find and select the current build directory interactively.
|
|
|
|
positional arguments:
|
|
<directory> the build directory to select
|
|
|
|
optional arguments:
|
|
-h, --help show this help message and exit
|
|
--build invoke a build after selection
|
|
EOF
|
|
return
|
|
fi
|
|
error() { echo "\e[31merror:\e[0m $1"; return 1 }
|
|
local build_dir
|
|
if [[ ${#*} -gt 1 ]]; then
|
|
echo $usage
|
|
error "unexpected position arguments: ${*[2,${#*}]}"
|
|
elif [[ ${#*} -eq 1 ]]; then
|
|
build_dir=${*[1]}
|
|
[[ ! -d $build_dir ]] && \
|
|
error "directory not found: $build_dir"
|
|
fi
|
|
|
|
# If <directory> was not set begin selection
|
|
if [[ -z $build_dir ]]; then
|
|
# Find build directories
|
|
local -a build_dirs
|
|
for entry in `ls -A`; do
|
|
[ -d $entry ] && [[ $entry =~ build* ]] && \
|
|
build_dirs+=${entry/\//}
|
|
done
|
|
|
|
# Interactively select a build directory if more than 1 found
|
|
integer index=0
|
|
if [[ ${#build_dirs} -eq 0 ]]; then
|
|
error "no build directories found"
|
|
elif [[ ${#build_dirs} -gt 1 ]]; then
|
|
zmodload zsh/curses && {
|
|
# Get the size of the terminal
|
|
local size=`stty size`
|
|
integer height=${size% *}
|
|
integer width=${size#* }
|
|
|
|
# Create the window and hide the cursor
|
|
zcurses init
|
|
zcurses addwin build-dir $height $width 0 0
|
|
|
|
# Hide the cursor for zcurses, trap SIGINT to ensure cleanup in
|
|
# always-list occurs below
|
|
tput civis; trap 'return 130' INT
|
|
|
|
# Enter display loop
|
|
local key keypad
|
|
while (( 1 )); do
|
|
zcurses clear build-dir
|
|
|
|
# Add the prompt text
|
|
zcurses move build-dir 1 1
|
|
zcurses string build-dir 'Select a build directory:'
|
|
|
|
# Add the selections text
|
|
for (( i = 0; i < ${#build_dirs}; i++ )); do
|
|
integer line=$i+3
|
|
zcurses move build-dir $line 1
|
|
[[ $index -eq $i ]] &&
|
|
zcurses string build-dir "* " ||
|
|
zcurses string build-dir " "
|
|
zcurses string build-dir ${build_dirs[$i+1]}
|
|
done
|
|
|
|
# Display the text the and wait for input
|
|
zcurses refresh build-dir
|
|
zcurses input build-dir key keypad
|
|
|
|
# Handle user input
|
|
case $key in
|
|
(UP|k|$'\C-P')
|
|
[[ $index -gt 0 ]] && index=$index-1 ;;
|
|
(DOWN|j|$'\C-N')
|
|
[[ $index -lt ${#build_dirs}-1 ]] && index=$index+1 ;;
|
|
(ENTER|$'\n')
|
|
break ;;
|
|
esac
|
|
done
|
|
} always {
|
|
# Restore the cursor and cleanup zcurses
|
|
tput cvvis; tput cnorm
|
|
zcurses delwin build-dir
|
|
zcurses end
|
|
}
|
|
fi
|
|
fi
|
|
|
|
# On success setup the build directory for use
|
|
if [[ $? -eq 0 ]]; then
|
|
# Set the build directory from selection if empty
|
|
[[ -z $build_dir ]] && \
|
|
build_dir=${build_dirs[$index+1]}
|
|
|
|
# If `build.ninja` exists in alias `ninja`, return.
|
|
local build
|
|
[ -f $build_dir/build.ninja ] && \
|
|
build="ninja -C $build_dir"
|
|
|
|
# If `Makefile` exists in alias `make`, return.
|
|
if [ -f $build_dir/Makefile ]; then
|
|
[ `uname` = Darwin ] && \
|
|
local cpu_count=`sysctl -n hw.ncpu` ||
|
|
local cpu_count=`grep -c '^processor' /proc/cpuinfo`
|
|
build="make -j $cpu_count -C $build_dir"
|
|
fi
|
|
|
|
# If the build variable is not defined the command could not be determined
|
|
if [ -z $build ]; then
|
|
echo "\e[33mwarning:\e[0m build command detection failed: $build_dir"
|
|
# Prompt user to enter a build command
|
|
vared -p 'enter comand: ' build
|
|
fi
|
|
|
|
# Redefine the `build` alias and update the `~build` hash directory
|
|
alias build="$build"
|
|
hash -d build=$build_dir
|
|
|
|
# If `--build` is specified then evaluate the command.
|
|
[[ -n $do_build ]] && eval build
|
|
fi
|
|
}
|
|
|
|
# Build then run a target residing in `~build/bin`.
|
|
build-run() {
|
|
local target=$1; shift 1
|
|
eval build $target && ~build/bin/$target $*
|
|
}
|
|
|
|
# Build then debug a target residing in `~build/bin`.
|
|
build-debug() {
|
|
local target=$1; shift 1
|
|
eval build $target && debug ~build/bin/$target $*
|
|
}
|