feat(fish): Add CPP environment template
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@
|
||||
!fish/environments
|
||||
!fish/environments/templates
|
||||
!fish/environments/templates/*
|
||||
!fish/environments/templates/**/*
|
||||
|
||||
!atuin
|
||||
!atuin/*.toml
|
||||
|
||||
51
fish/environments/templates/cpp/activate.fish
Normal file
51
fish/environments/templates/cpp/activate.fish
Normal file
@@ -0,0 +1,51 @@
|
||||
# Basic environment with custom prompt
|
||||
# Environment: {{ENV_NAME}}
|
||||
|
||||
# Check if a previous initialization has occurred
|
||||
if test -n "$__ENV_INITIALIZED"
|
||||
echo (set_color yellow)"Environment already initialized"(set_color normal)
|
||||
return 0
|
||||
end
|
||||
|
||||
# Mark as initialized
|
||||
set -gx __ENV_INITIALIZED "1"
|
||||
set -gx CURRENT_ENV "{{ENV_NAME}}"
|
||||
|
||||
# Save the original prompt function if it exists
|
||||
# Only save if we don't already have a backup or if current prompt is not from an environment
|
||||
if not functions -q __env_orig_prompt
|
||||
if functions -q fish_prompt
|
||||
functions -c fish_prompt __env_orig_prompt
|
||||
else
|
||||
function __env_orig_prompt
|
||||
echo -n (whoami)'@'(prompt_hostname)' '(set_color $fish_color_cwd)(prompt_pwd)(set_color normal)'> '
|
||||
end
|
||||
end
|
||||
else
|
||||
# If we already have a backup, we're switching environments
|
||||
# No need to create a new backup
|
||||
end
|
||||
|
||||
# Define new prompt with environment prefix
|
||||
function fish_prompt
|
||||
echo -n (set_color green)'({{ENV_NAME}})'(set_color normal)' '
|
||||
__env_orig_prompt
|
||||
end
|
||||
|
||||
# Add custom environment variables here
|
||||
# set -gx MY_CUSTOM_VAR "value"
|
||||
|
||||
# Add custom paths here
|
||||
# fish_add_path /path/to/custom/bin
|
||||
set script_dir (dirname (status --current-filename))
|
||||
fish_add_path $script_dir/bin
|
||||
|
||||
# Custom initialization commands
|
||||
echo (set_color green)"Activated environment: {{ENV_NAME}}"(set_color normal)
|
||||
|
||||
# Optional: Define custom deactivation function
|
||||
function __env_custom_deactivate
|
||||
# Add any cleanup commands here
|
||||
# unset custom variables, restore paths, etc.
|
||||
echo (set_color blue)"Custom cleanup for {{ENV_NAME}} completed"(set_color normal)
|
||||
end
|
||||
226
fish/environments/templates/cpp/bin/bw
Executable file
226
fish/environments/templates/cpp/bin/bw
Executable file
@@ -0,0 +1,226 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Watch-build script for automatic rebuilding and restarting
|
||||
# Monitors source files and runs 'make prod' when changes
|
||||
# are detected
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $(basename "$0") [MAKE_COMMAND...]"
|
||||
echo "If MAKE_COMMAND is omitted, the default is: 'make clean && make prod'"
|
||||
echo "Example:"
|
||||
echo " $(basename "$0") \"make debug\""
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
MAKE_CMD="$*"
|
||||
else
|
||||
MAKE_CMD="make clean && make prod"
|
||||
fi
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Process ID of the running program
|
||||
DEV_PID=""
|
||||
|
||||
cleanup() {
|
||||
echo -e "\n${YELLOW}Cleaning up...${NC}"
|
||||
|
||||
if [[ -n "$DEV_PID" ]]; then
|
||||
echo -e "${YELLOW}Stopping running program (PID: $DEV_PID)${NC}"
|
||||
kill $DEV_PID 2>/dev/null || true
|
||||
wait $DEV_PID 2>/dev/null || true
|
||||
fi
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Trap cleanup on script exit
|
||||
trap cleanup SIGINT SIGTERM EXIT
|
||||
|
||||
build_and_run() {
|
||||
echo -e "${BLUE}Building project...${NC}"
|
||||
echo -e "${BLUE}Running build command: ${YELLOW}$MAKE_CMD${NC}"
|
||||
|
||||
# Stop the currently running program if it exists
|
||||
if [[ -n "$DEV_PID" ]]; then
|
||||
echo -e "${YELLOW}Stopping running program (PID: $DEV_PID)${NC}"
|
||||
kill $DEV_PID 2>/dev/null || true
|
||||
wait $DEV_PID 2>/dev/null || true
|
||||
DEV_PID=""
|
||||
fi
|
||||
|
||||
# Build the project using the provided command and capture output
|
||||
TMPOUT=$(mktemp)
|
||||
# Record build start time (epoch seconds) to filter processes started during the build
|
||||
BUILD_START_TS=$(date +%s)
|
||||
if bash -c "$MAKE_CMD" 2>&1 | tee "$TMPOUT"; then
|
||||
echo -e "${GREEN}Build successful! Determining output binary...${NC}"
|
||||
|
||||
# Try to find the output file from the last '-o <file>' in build output
|
||||
# Use portable awk parsing to avoid non-GNU grep issues on some systems
|
||||
OUT_FILE=$(awk '{
|
||||
for(i=1;i<=NF;i++){
|
||||
if($i=="-o"){ if(i+1<=NF) print $(i+1) }
|
||||
else if($i ~ /^-o/){ print substr($i,3) }
|
||||
}
|
||||
}' "$TMPOUT" | tail -n1)
|
||||
|
||||
# If not found, fall back to newest file in out/
|
||||
if [[ -z "$OUT_FILE" ]]; then
|
||||
OUT_FILE=$(ls -t out/* 2>/dev/null | head -n1 || true)
|
||||
fi
|
||||
|
||||
# Final fallback to previous default
|
||||
if [[ -z "$OUT_FILE" ]]; then
|
||||
OUT_FILE="./out/prod"
|
||||
fi
|
||||
|
||||
# Normalize path (if relative and doesn't start with ./ or /, prefix ./)
|
||||
if [[ "$OUT_FILE" != /* && "$OUT_FILE" != ./* ]]; then
|
||||
OUT_FILE="./$OUT_FILE"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Resolved output binary: ${YELLOW}$OUT_FILE${NC}"
|
||||
|
||||
# If the build itself already started the program, detect an existing PID
|
||||
EXISTING_PID=""
|
||||
|
||||
# Gather candidate PIDs by matching the basename
|
||||
if command -v pgrep &> /dev/null; then
|
||||
CANDIDS=$(pgrep -f "$(basename "$OUT_FILE")" || true)
|
||||
else
|
||||
CANDIDS=$(ps aux | grep "$(basename "$OUT_FILE")" | grep -v grep | awk '{print $2}' || true)
|
||||
fi
|
||||
|
||||
if [[ -n "$CANDIDS" ]]; then
|
||||
# Resolve the canonical path of the output binary if possible
|
||||
if command -v realpath &> /dev/null; then
|
||||
REAL_OUT=$(realpath "$OUT_FILE" 2>/dev/null || true)
|
||||
else
|
||||
REAL_OUT=$(readlink -f "$OUT_FILE" 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
for pid in $CANDIDS; do
|
||||
# Skip non-numeric entries
|
||||
if ! [[ "$pid" =~ ^[0-9]+$ ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check process start time and ignore ones that started before the build
|
||||
# Use ps lstart to get human-readable start time and convert to epoch
|
||||
PID_LSTART=$(ps -o lstart= -p "$pid" 2>/dev/null || true)
|
||||
if [[ -n "$PID_LSTART" ]]; then
|
||||
PID_EPOCH=$(date -d "$PID_LSTART" +%s 2>/dev/null || true)
|
||||
if [[ -n "$PID_EPOCH" && "$PID_EPOCH" -lt "$BUILD_START_TS" ]]; then
|
||||
# process started before build, skip
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
# Prefer checking /proc/<pid>/exe for an exact match (Linux)
|
||||
if [[ -r "/proc/$pid/exe" ]]; then
|
||||
PID_EXE=$(readlink -f "/proc/$pid/exe" 2>/dev/null || true)
|
||||
if [[ -n "$PID_EXE" && -n "$REAL_OUT" && "$PID_EXE" = "$REAL_OUT" ]]; then
|
||||
EXISTING_PID=$pid
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback: check the process cmdline contains the output path or basename
|
||||
if [[ -r "/proc/$pid/cmdline" ]]; then
|
||||
CMDLINE=$(tr '\0' ' ' < /proc/$pid/cmdline 2>/dev/null || true)
|
||||
if [[ -n "$CMDLINE" && ( "$CMDLINE" = *"$OUT_FILE"* || "$CMDLINE" = *"$(basename "$OUT_FILE")"* ) ]]; then
|
||||
EXISTING_PID=$pid
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# if [[ -n "$EXISTING_PID" ]]; then
|
||||
# DEV_PID=$EXISTING_PID
|
||||
# echo -e "${YELLOW}Program already running (PID: $DEV_PID). Reusing it.${NC}"
|
||||
# else
|
||||
if [[ -x "$OUT_FILE" || -f "$OUT_FILE" ]]; then
|
||||
# Start the program in background
|
||||
"$OUT_FILE" &
|
||||
DEV_PID=$!
|
||||
echo -e "${GREEN}Program started with PID: $DEV_PID${NC}"
|
||||
else
|
||||
echo -e "${RED}Resolved output '$OUT_FILE' does not exist or is not executable.${NC}"
|
||||
DEV_PID=""
|
||||
fi
|
||||
# fi
|
||||
|
||||
# clean up temp
|
||||
rm -f "$TMPOUT" || true
|
||||
else
|
||||
echo -e "${RED}build failed${NC}"
|
||||
DEV_PID=""
|
||||
rm -f "$TMPOUT" || true
|
||||
fi
|
||||
}
|
||||
|
||||
clear_console() {
|
||||
if command -v tput &> /dev/null; then
|
||||
tput reset
|
||||
elif command -v clear &> /dev/null; then
|
||||
clear
|
||||
else
|
||||
printf '\033c'
|
||||
fi
|
||||
}
|
||||
|
||||
check_dependencies() {
|
||||
if ! command -v inotifywait &> /dev/null; then
|
||||
echo -e "${RED}error:${NC} inotifywait is not installed."
|
||||
echo -e "Please install ${YELLOW}inotify-tools${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
clear_console
|
||||
|
||||
check_dependencies
|
||||
|
||||
echo -e "${GREEN}watching on changes...${NC}"
|
||||
echo -e "monitoring: ${BLUE}src/, lib/, makefile${NC}"
|
||||
echo ""
|
||||
|
||||
build_and_run
|
||||
|
||||
# Watch for changes
|
||||
while true; do
|
||||
inotifywait -e modify,create,delete,move \
|
||||
--recursive \
|
||||
--quiet \
|
||||
src/ lib/ makefile 2>/dev/null \
|
||||
|| {
|
||||
echo -e "${RED}error:${NC} Failed to watch directories"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "\n${BLUE}file change detected, rebuilding${NC}"
|
||||
|
||||
# Small delay to handle rapid successive changes
|
||||
sleep 0.5
|
||||
|
||||
clear_console
|
||||
build_and_run
|
||||
echo -e "${BLUE}watching for changes${NC}"
|
||||
done
|
||||
}
|
||||
|
||||
main
|
||||
67
fish/environments/templates/cpp/readme.norg
Normal file
67
fish/environments/templates/cpp/readme.norg
Normal file
@@ -0,0 +1,67 @@
|
||||
* Exported Fish Environment: {{ENV_NAME}}
|
||||
This directory contains a self-contained fish environment.
|
||||
|
||||
** Environment-specific functions
|
||||
This environment is meant to be used with C(++) projects. It provides the
|
||||
following utilities:
|
||||
|
||||
- `bw` (build-watch): Continuously builds and runs the the project on source
|
||||
file changes.
|
||||
|
||||
** Files Structure
|
||||
@code
|
||||
.fish/
|
||||
|-- activate.fish
|
||||
|-- readme.norg
|
||||
|-- bin/
|
||||
@end
|
||||
|
||||
** Usage
|
||||
|
||||
*** Automatic Activation (Recommended)
|
||||
The environment will automatically activate when you `cd` into this directory
|
||||
if your Fish shell is configured with the auto-activation script.
|
||||
|
||||
@code fish
|
||||
function check_and_source_activate
|
||||
if test -f (pwd)/.fish/activate.fish
|
||||
source (pwd)/.fish/activate.fish
|
||||
elif test -f (pwd)/activate.fish
|
||||
source (pwd)/activate.fish
|
||||
end
|
||||
end
|
||||
|
||||
function cd
|
||||
builtin cd $argv && check_and_source_activate
|
||||
end
|
||||
@end
|
||||
|
||||
*** Manual Activation
|
||||
To manually activate the environment, run from the project root:
|
||||
@code bash
|
||||
source ./.fish/activate.fish
|
||||
@end
|
||||
|
||||
*** Deactivation
|
||||
To deactivate the environment, run:
|
||||
@code bash
|
||||
env deactivate
|
||||
@end
|
||||
|
||||
Or simply `cd` to a different directory if using auto-activation.
|
||||
|
||||
** What This Environment Provides
|
||||
- Prompt showing the environment name
|
||||
- Environment-specific aliases and functions
|
||||
- Custom environment variables
|
||||
- Automatic cleanup when deactivated
|
||||
|
||||
** Requirements
|
||||
- Fish shell
|
||||
- `bass` plugin (`fisher install edc/bass`) for compatibility with bash scripts
|
||||
|
||||
** Sharing
|
||||
This environment is completely self-contained. You can:
|
||||
- Copy this directory to another machine
|
||||
- Share it with others
|
||||
- Version control it with your project (add .fish/ to your repo)
|
||||
Reference in New Issue
Block a user