#!/usr/bin/env bash # This script sets things based on my current project and will set the symlink ~/Projects/current to the correct folder # GLOBAL VARIABLES PROJECTS_PATH="$HOME/Projects" SYMLINC="$PROJECTS_PATH/current" # Prints help text function print_help(){ echo "Manages projects" echo "" echo -e "Usage: $0 []" echo "" echo -e "Commands" echo -e "--------" echo -e "list\t\t\tLists The available projects" echo -e "switch\t\t\tSwitches the current project" echo -e "\t--auto\t\tAutomatically deduce the project based on current working directory" echo -e "\t--fzf\t\tUses fzf to choose a project" echo -e "\t--dmenu\t\tUses dmenu to choose a project" echo -e "\t--rofi\t\tUses rofi to choose a project" echo -e "\t--unset\t\tUnsets the project" echo -e "\t\tSets the project" echo -e "current\t\t\tPrints the current project" echo -e "\t--notify\t\tUses notify send to print current project" echo -e "\t--path\t\tPrints the full path rather than the name" echo -e "new\t\t\tCreates a new project. Will prompt for a name if no argements are given" echo -e "\t\t\tCreates a new project with the name given" echo -e "\t--dmenu\t\tPrompt using dmenu" echo -e "\t--rofi\t\tPrompt using rofi" echo -e "copy [..]\t\tCopies files to a target in the project" echo -e "\t--bin\t\tCopy to bin directory (inside \$PATH)" echo -e "\t--www\t\tCopy to the www directory" exit 0 } # Lists the available projects # If the --options flag is given, it will also list --new and, if relevant, --unset. # This is useful foa piping it into a fuzzy finder function list_projects(){ if [[ "$1" == "--options" ]]; then if [ -L "$SYMLINC" ]; then echo "--unset" fi echo "--new" fi find "$PROJECTS_PATH/" -maxdepth 1 -mindepth 1 -type d | xargs -L 1 basename } # Switches the project # Normally takes the first argement to be the project name # If first argument is --auto, it will try to set the project based on the current working directory # If the first argument it --unset, it will unstet the project # If the first argument is --fzf, --dmenu or --rofi it will use the specified tool to list options function switch(){ local switchto="$1" if [[ "$1" == "--auto" ]]; then if echo "$PWD" | grep -q "$PROJECTS_PATH"; then switchto=$( echo "$PWD" | sed "s#$PROJECTS_PATH/##") switchto="${switchto%/*}" if [[ "$PWD" == "$PROJECTS_PATH" ]]; then switchto="--unset" fi else switchto="--unset" fi elif [[ "$1" == "--fzf" ]]; then switchto=$(list_projects --options | fzf) elif [[ "$1" == "--dmenu" ]]; then switchto=$(list_projects --options | dmenu -i ) elif [[ "$1" == "--rofi" ]]; then switchto=$(list_projects --options | rofi -dmenu -i ) elif [[ "$1" == "--unset" ]]; then if [ -L "$SYMLINC" ]; then rm "$SYMLINC" 2> /dev/null # See note about SIGWINCH below pkill -u $USER -SIGWINCH zsh fi exit 0 fi # If $switchto is --unset, it has just been selected from one of the menus # Re-run switch with the --unset flag if [[ "$switchto" == "--unset" ]]; then switch --unset exit 0 fi if [[ "$switchto" == "--new" ]]; then new_project "$1" exit 0 fi switchto="$PROJECTS_PATH/$switchto" # This sends the SIGWINCH signal to all zsh processes # This tells zsh that the window has been resized. # Althouph we are not resizing the window, it causes zsh to re-draw the prompt pkill -u $USER -SIGWINCH zsh if [ -d "$switchto" ]; then if [ -L "$SYMLINC" ]; then rm "$SYMLINC" 2> /dev/null fi ln -s "$switchto" "$SYMLINC" else echo "No such directory $switchto" exit 1 fi } # Prints the name of the current project # If there is an index.yaml file containing a name, it will print the name # If not, it will fall back to the folder name # If --notify is th first argument, it will use notify-send to print the project name # If --path is the first argument, it will print the path to the current project rather than the name # It will return an empty string if there isn't an active project function get_current(){ if [ -L "$SYMLINC" ]; then local current=$(readlink "$SYMLINC") if [[ "$1" != "--path" ]]; then if [ -f "$current"/index.yaml ]; then current=$(cat "$current/index.yaml" | yq -r '.name') else current=$(echo "$current" | xargs -L 1 basename) fi fi if [[ "$1" == "--notify" ]]; then notify-send "Current Project" "$current" else echo "$current" fi else if [[ "$1" == "--notify" ]]; then notify-send "Current Project" "not set" else echo "" fi fi } # Creates a new project # The first arguemnt is normally the project name # If there is no argument, it will prompt for the username # If the first argument is --rofi or --dmenu, it will prompt for the name using that tool # It will also create a few directories that most projects will need function new_project(){ local name="$1" local default_dirs=( bin screenshots Downloads www ) if [ ! -n "$name" ]; then echo -n "Project name: " read name < /dev/tty elif [[ "$name" == "--rofi" ]]; then name=$(rofi -dmenu -l 0 -p "Project name" ) elif [[ "$name" == "--dmenu" ]]; then name=$(echo "" | dmenu -l 0 -p "Project name: " ) fi # If name still empty, exit if [ ! -n "$name" ]; then exit 1 fi mkdir "$PROJECTS_PATH/$name" # Make all the directories for dir in "${default_dirs[@]}"; do mkdir "$PROJECTS_PATH/$name/$dir" done switch "$name" } # A wrapper around cp for copying to places inside the current directory # The first argument should be one of the followind: # --bin The bin directory inside the project - This is in your path if thre is a project set # --www This www directory which is where http servers are served from # It will copy all folders / files given as arguments to the location function copyto(){ local current="$(get_current --path)" if [ -n "$current" ]; then local destination="$current/" if [[ "$1" == "--bin" ]]; then destination="$current/bin/" shift elif [[ "$1" == "--www" ]]; then destination="$current/www/" shift fi if [[ -n "$destination" ]]; then mkdir -p "$destination" cp -r "$@" "$destination" fi fi } # Sets up a python server in the www directory # First optional argement is the port to list on # Second optionl argument is the bind address to listen to function serve(){ local current="$(get_current --path)" if [ ! -n "$current" ]; then echo "Set current project first" exit 1 fi local www="$current/www/" local port=${1:-"8000"} local bind="$2" if [ -d "$www" ]; then echo "Creating www directory" fi local count=$( find "$www" -type f | wc -l) if [ -n "$bind" ]; then echo "Serving $count files to $bind from the $www directory" python -m http.server "$port" --bind "$bind" --directory "$www" else echo "Serving $count files from the $www directory" python -m http.server "$port" --directory "$www" fi } if [ -n "$1" ] ; then case "$1" in -h|--help) print_help exit 0 ;; list) list_projects exit 0 ;; switch) switch "$2" exit 0 ;; current) get_current "$2" exit 0 ;; new) new_project "$2" exit 0 ;; copy) shift copyto "$@" exit 0 ;; serve) shift serve "$@" exit 0 ;; *) echo "Unknown command $1" print_help exit 1 ;; esac fi