feat(fish): Add CPP environment template

This commit is contained in:
2025-11-10 11:45:23 +01:00
parent f90adca156
commit 1693c8610a
4 changed files with 345 additions and 0 deletions

1
.gitignore vendored
View File

@@ -21,6 +21,7 @@
!fish/environments
!fish/environments/templates
!fish/environments/templates/*
!fish/environments/templates/**/*
!atuin
!atuin/*.toml

View 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

View 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

View 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)