diff --git a/Dockerfile b/Dockerfile index ae2d949..374c0da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -153,10 +153,12 @@ RUN curl https://packagecloud.io/install/repositories/cs50/repo/script.deb.sh | bash-completion \ build-essential `# dpkg-dev, libc, gcc, g++, make, etc.`\ clang \ + colorized-logs `# For help50` \ coreutils `# For fold` \ cowsay \ dos2unix \ dnsutils `# For nslookup` \ + expect `# For help50` \ fonts-noto-color-emoji `# For render50` \ gdb \ git \ @@ -188,7 +190,6 @@ RUN curl https://packagecloud.io/install/repositories/cs50/repo/script.deb.sh | cs50 \ Flask \ Flask-Session \ - help50 \ pytest \ render50 \ setuptools \ diff --git a/etc/profile.d/help50.sh b/etc/profile.d/help50.sh new file mode 100644 index 0000000..836a037 --- /dev/null +++ b/etc/profile.d/help50.sh @@ -0,0 +1,66 @@ +# Directory with helpers +HELPERS="/opt/cs50/lib/help50" + +# TEMP +alias make="help50 make" + +# Formatting +bold=$(tput bold) +normal=$(tput sgr0) + + +help50() { + + # Check for helper + if [[ $# -gt 0 && ! -f "${HELPERS}/${1}.sh" ]]; then + echo "Sorry, ${bold}help50${normal} does not yet know how to help with this!" + return 1 + fi + + # Duplicate file descriptors + exec 3>&1 4>&2 + + # Redirect output to a file too + local file="/tmp/help50.$$" # Use PID to support multiple terminals + exec > >(tee -a "$file") 2>&1 + + # Execute command + if [[ "$(type -P -t "$1")" == "file" ]]; then + unbuffer "$@" # Else, e.g., ls isn't colorized + else + "$@" # Can't unbuffer builtins (e.g., cd) + fi + + # Remember status + local status=$? + + # Remember command + local command="$1" + + # Remove command from $@ + shift + + # Get redirected output + local output=$(cat "$file") + + # Remove any ANSI codes + output=$(echo "$output" | ansi2txt | col -b) + + # Restore file descriptors + exec 1>&3 2>&4 + + # Close file descriptors + exec 3>&- 4>&- + + # Remove file + rm --force "$file" + + # Preserve command's status for helpers + (exit $status) + + # Try to get help + local help=$( . "${HELPERS}/${command}.sh" <<< "$output" ) + if [[ -n "$help" ]]; then + echo "🦆 $help" + fi +} diff --git a/opt/cs50/bin/make b/opt/cs50/bin/make old mode 100755 new mode 100644 index 4658e3e..d4275e8 --- a/opt/cs50/bin/make +++ b/opt/cs50/bin/make @@ -1,23 +1,20 @@ #!/bin/bash -# Ensure no targets end with .c -args="" -invalid_args=0 -for arg; do - case "$arg" in - (*.c) arg=${arg%.c}; invalid_args=1;; - esac - args="$args $arg" -done -if [ $invalid_args -eq 1 ]; then - echo "Did you mean 'make$args'?" - exit 1 -fi +# If a single target and not an option +if [[ $# -eq 1 ]] && [[ "$1" != -* ]]; then + + # If no Makefile + if [[ ! -f Makefile && ! -f makefile ]]; then -# Run make -if [[ -d "$1" ]]; then - echo "$1 is a directory" - exit 1 -else - /usr/bin/make -B -s $* + # If target ends with .c or is a directory + if [[ "$1" == *?.c || -d "$1" ]]; then + + # Don't suppress "Nothing to be done" with --silent + /usr/bin/make "$1" + exit $? + fi + fi fi + +# Don't echo recipes +/usr/bin/make --always-make --silent "$@" diff --git a/opt/cs50/lib/help50/cd.sh b/opt/cs50/lib/help50/cd.sh new file mode 100644 index 0000000..01e9087 --- /dev/null +++ b/opt/cs50/lib/help50/cd.sh @@ -0,0 +1,9 @@ +echo "EXIT: $?" +local stdin=$(cat) +#echo "stdout[$stdout]" +#echo "1[$1]" +#echo "2[$2]" +#echo "pwd[$PWD]" +#echo "STDOUT:$stdout" +echo "STDIN:$stdin" +return 0 diff --git a/opt/cs50/lib/help50/ls.sh b/opt/cs50/lib/help50/ls.sh new file mode 100644 index 0000000..ce456b2 --- /dev/null +++ b/opt/cs50/lib/help50/ls.sh @@ -0,0 +1,6 @@ +echo "argv:[$argv]" +echo "stdout[$stdout]" +echo "1[$1]" +echo "2[$2]" +echo "pwd[$PWD]" +return 0 diff --git a/opt/cs50/lib/help50/make.sh b/opt/cs50/lib/help50/make.sh new file mode 100644 index 0000000..5b64739 --- /dev/null +++ b/opt/cs50/lib/help50/make.sh @@ -0,0 +1,42 @@ +local output=$(cat) + +local regex="make: Nothing to be done for '(.*)'" +if [[ "$output" =~ $regex ]]; then + + # If target is a directory + if [[ -d "$1" ]]; then + echo "Cannot run ${bold}make${normal} on a directory. Did you mean to ${bold}cd ${1}${normal} first?" + return + fi + + # If target ends with .c + if [[ "$1" == *?.c ]]; then + base="${1%.c}" + if [[ -n "$base" && ! -d "$base" ]]; then + echo "Did you mean to ${bold}make ${base}${normal}?" + return + fi + fi + +fi + +local regex="No rule to make target '(.*)'" +if [[ "$output" =~ $regex ]]; then + + # If no .c file for target + local c="$1.c" + if [[ ! -f "$c" ]]; then + + # Search recursively for .c file + paths=$(find * -name "$c" 2> /dev/null) + lines=$(echo "$paths" | grep -c .) + echo -n "There isn't a file called ${bold}${c}${normal} in your current directory." + if [[ "$lines" -eq 1 ]]; then # If unambiguous + d=$(dirname "$paths") + echo " Did you mean to ${bold}cd ${d}${normal} first?" + else + echo + fi + return + fi +fi diff --git a/tests/bar.c b/tests/bar.c new file mode 100644 index 0000000..b552c8e --- /dev/null +++ b/tests/bar.c @@ -0,0 +1 @@ +int main(void) {} diff --git a/tests/foo/baz.c b/tests/foo/baz.c new file mode 100644 index 0000000..e69de29