From cd79f7486c03940790ad732e650a4ed9e031dfc6 Mon Sep 17 00:00:00 2001 From: Brian Matzelle Date: Wed, 16 Oct 2024 16:47:18 -0400 Subject: [PATCH 1/4] added zsh file --- dotlocaldotbashrc => bash/dotlocaldotbashrc | 0 .../dotlocaldotbashrc.t | 0 .../dotlocaldotbashrc.t.out | 0 zsh/dotlocaldotzshrc | 108 ++++++++++++++++++ 4 files changed, 108 insertions(+) rename dotlocaldotbashrc => bash/dotlocaldotbashrc (100%) rename dotlocaldotbashrc.t => bash/dotlocaldotbashrc.t (100%) rename dotlocaldotbashrc.t.out => bash/dotlocaldotbashrc.t.out (100%) create mode 100644 zsh/dotlocaldotzshrc diff --git a/dotlocaldotbashrc b/bash/dotlocaldotbashrc similarity index 100% rename from dotlocaldotbashrc rename to bash/dotlocaldotbashrc diff --git a/dotlocaldotbashrc.t b/bash/dotlocaldotbashrc.t similarity index 100% rename from dotlocaldotbashrc.t rename to bash/dotlocaldotbashrc.t diff --git a/dotlocaldotbashrc.t.out b/bash/dotlocaldotbashrc.t.out similarity index 100% rename from dotlocaldotbashrc.t.out rename to bash/dotlocaldotbashrc.t.out diff --git a/zsh/dotlocaldotzshrc b/zsh/dotlocaldotzshrc new file mode 100644 index 0000000..c51ebb5 --- /dev/null +++ b/zsh/dotlocaldotzshrc @@ -0,0 +1,108 @@ +#!/usr/bin/env zsh + +_zshrc_dir() { + local dir="$1" + + test -f "$dir/.local.zshrc" && echo "$dir" && return 0 + test '/' = "$dir" && return 1 + + _zshrc_dir "$(dirname "$1")" +} + +ZSHRC_HOME="$(_zshrc_dir "$PWD")" + +dotlocaldotzshrc () { + local subcommand; + if [ "$1" = "init" ]; then + subcommand="init" + + if [ -f .local.zshrc ]; then + echo "dotlocaldotzshrc: error: $PWD already has a .local.zshrc" + return 1 + fi + + printf '#!/usr/bin/env zsh\n' >> .local.zshrc + "${EDITOR:-vi}" .local.zshrc + fi + + if [ "$1" = "edit" ]; then + subcommand="edit" + if [ -z "$ZSHRC_HOME" ]; then + echo "dotlocaldotzshrc: error: cannot find a .local.zshrc" + return 1 + fi + + "${EDITOR:-vi}" "$ZSHRC_HOME/.local.zshrc" + + # And re-source + dotlocaldotzshrc + fi + + if [ -n "$1" ] && [ -z "$subcommand" ]; then + echo "dotlocaldotzshrc: error: $1 is not a valid command" + return 1 + fi + + _zshrc_dir "$PWD" || { + echo "dotlocaldotzshrc: error: no parent directory with .local.zshrc found" + return + } + + ZSHRC_SOURCED="1" + echo "dotlocaldotzshrc: source '$ZSHRC_HOME/.local.zshrc'" + source "$ZSHRC_HOME/.local.zshrc" +} + +lcd() { + cd "$ZSHRC_HOME/$1" +} + +_zshrc_init() { + local zshrc_dir + local zshrc_temp + + # Return early if no .local.zshrc is found. + zshrc_dir="$(_zshrc_dir "$PWD")" + + test -n "$ZSHRC_TEMP" && test -z "$ZSHRC_SOURCED" && { + dotlocaldotzshrc + } + + # The local zshrc path changed. + test "$zshrc_dir" != "$ZSHRC_HOME" && { + + wait + + # Do a fg to make sure you don't lose work + if [[ -n $(jobs -p) ]]; then + jobs + echo "dotlocaldotzshrc: error: will not exit with jobs in background." + return + fi + + # Current zsh process is a local zshrc session. + test -n "$ZSHRC_TEMP" && { + echo "$PWD" > "$ZSHRC_TEMP" + echo "dotlocaldotzshrc: exit $ZSHRC_HOME" + exit + } + + # Current zsh process is the original (root) session. + zshrc_temp="$(mktemp)" + + echo "dotlocaldotzshrc: open $zshrc_dir" + HISTFILE="$zshrc_dir/.local.zsh_history" \ + ZSHRC_TEMP="$zshrc_temp" \ + zsh + + test -s "$ZSHRC_TEMP" || exit + cd "$(cat "$ZSHRC_TEMP")" || true + _zshrc_init + + } + +} + +autoload -Uz add-zsh-hook +add-zsh-hook precmd _zshrc_init + From a075f69595caa58a916e351e79e278442e11ce40 Mon Sep 17 00:00:00 2001 From: Brian Matzelle Date: Wed, 16 Oct 2024 17:05:16 -0400 Subject: [PATCH 2/4] updated readme --- README.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5ab092d..c675740 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# 👇local👇bashrc -`.local.bashrc` files that are sourced in a clean bash process when entering +# 👇local👇(bash|zsh)rc + +`.local.bashrc` or `.local.zshrc` files that are sourced in a clean process when entering the directory. *Replaces the [projector](https://github.com/bas080/projector) project.* @@ -9,18 +10,20 @@ the directory. - Makes a simple to define env variables, aliases and functions for a specific project directory. -- Creates a bash history that is a separate from the root bash history. +- Creates a shell history that is a separate from the root shell history. - Makes it easier to keep and find commands that are related to that project. - - Doesn't fill up the root bash history. -- Does not inherit env variables of other `.local.bashrc` directories when + - Doesn't fill up the root shell history. +- Does not inherit env variables of other `.local.bashrc`/`.local.zshrc` directories when jumping directories. ## Setup -A quick setup script. +### Bash: + +A quick setup script for bash. ```bash -curl 'https://raw.githubusercontent.com/bas080/dotlocaldotbashrc/master/dotlocaldotbashrc' > "$HOME/.dotlocaldotbashrc" && +curl 'https://raw.githubusercontent.com/brianmatzelle/dotlocaldotrc/refs/heads/master/bash/dotlocaldotbashrc' > "$HOME/.dotlocaldotbashrc" && echo 'source "$HOME/.dotlocaldotbashrc"' >> ~/.bashrc ``` @@ -37,10 +40,36 @@ PS1="${BASHRC_HOME#$HOME/}:\W " projects/dotlocaldotbashrc:dotlocaldotbashrc cd ../█ ``` -When using in repositores consider adding `.local.*` to your `.gitignore`. +When using in repositories consider adding `.local.*` to your `.gitignore`. + +### Zsh: + +A quick setup script for Z shell. + +```zsh +curl 'https://github.com/brianmatzelle/dotlocaldotrc/raw/refs/heads/master/zsh/dotlocaldotzshrc' > "$HOME/.dotlocaldotzshrc" && + echo 'source "$HOME/.dotlocaldotzshrc"' >> ~/.zshrc +``` + +After re-sourcing your .zshrc you can create a `.local.zshrc` in a directory where you would like +a local zshrc by running `dotlocaldotzshrc init`. + +Optionally you can show which local zshrc is currently active in your prompt. + +```zsh +# What I use: +PS1="${ZSHRC_HOME#$HOME/}:\W " + +# Looks like this: +projects/dotlocaldotzshrc:dotlocaldotzshrc cd ../█ +``` + +When using in repositories consider adding `.local.*` to your `.gitignore`. ## Usage +### Bash + Quick start: ```text @@ -104,6 +133,71 @@ $ cd .. dotlocaldotbashrc: error: will not exit with jobs in the background. ``` +### Zsh + +Quick start: + +```text +dotlocaldotzshrc [] + Create and configure directory specific zsh sessions. + + Will source .local.zshrc when no subcommand is defined. + + [subcommand] + init - Create a .local.zshrc in current directory. + edit - Opens the zshrc in $EDITOR and re-sources on exit. +``` + +More information: + +``` +$ cd projects/zshrc/ +dotlocaldotzshrc: open /home/user/projects/zshrc +$ cd nested/ +dotlocaldotzshrc: exit /home/user/projects/zshrc +dotlocaldotzshrc: open /home/user/projects/zshrc/nested +$ cd +dotlocaldotzshrc: exit /home/user/projects/zshrc/nested +$ +``` + +> Notice that navigating to the home directory resulted in only a zshrc zsh +> session being exited. We just use the initial zsh process that was started +> when zshrc and the rest of the interactive shell was bootstrapped. + +You can source the local .local.zshrc at anytime with `dotlocaldotzshrc` function. + +```zsh +$ dotlocaldotzshrc +zshrc: source '/home/user/.local.zshrc' +$ +``` + +You can quickly edit and automatically source after editor quit with +`dotlocaldotzshrc edit`. + +One notable feature of `dotlocaldotzshrc` is its behavior when background jobs +are active. When attempting to exit the `dotlocaldotzshrc` session using the +`cd` command or when explicitly running the `dotlocaldotzshrc` command with the +`exit` option, the script checks for any background jobs in the current session. + +If there are background jobs running, the script will display an error message +and refrain from exiting the session. This behavior ensures that you don't +unintentionally lose work by exiting a session with active background jobs. + +```zsh +$ cd projects/myproject/ +dotlocaldotzshrc: open /home/user/projects/myproject + +# Start a background job +$ sleep 300 & # ctrl-z +[1] 12345 + +# Attempt to exit the dotlocaldotzshrc session +$ cd .. +dotlocaldotzshrc: error: will not exit with jobs in the background. +``` + ## Test How to run the tests: From 8cb52139328385007291e72e5e5a962124d5e7f7 Mon Sep 17 00:00:00 2001 From: Brian Matzelle Date: Wed, 16 Oct 2024 17:26:11 -0400 Subject: [PATCH 3/4] zsh tests added and verified --- README.md | 11 +++++++++-- zsh/dotlocaldotzshrc.t | 37 +++++++++++++++++++++++++++++++++++++ zsh/dotlocaldotzshrc.t.out | 14 ++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 zsh/dotlocaldotzshrc.t create mode 100644 zsh/dotlocaldotzshrc.t.out diff --git a/README.md b/README.md index c675740..b460da0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # 👇local👇(bash|zsh)rc `.local.bashrc` or `.local.zshrc` files that are sourced in a clean process when entering @@ -202,11 +201,19 @@ dotlocaldotzshrc: error: will not exit with jobs in the background. How to run the tests: +### Bash + ```bash SPAT_SHELL='bash' spat ./dotlocaldotbashrc.t ``` -> Uses [spat](https://github.com/bas080/spat) to run expect tests. +### Zsh + +```bash +SPAT_SHELL='zsh' spat ./dotlocaldotzshrc.t +``` + +Uses [spat](https://github.com/bas080/spat) to run expect tests. ## License diff --git a/zsh/dotlocaldotzshrc.t b/zsh/dotlocaldotzshrc.t new file mode 100644 index 0000000..2a6c324 --- /dev/null +++ b/zsh/dotlocaldotzshrc.t @@ -0,0 +1,37 @@ +#!/usr/bin/env zsh + +EDITOR="cat" + +{ +source ./dotlocaldotzshrc + +rm -r /tmp/dotlocaldotzshrc/test || true +mkdir -p /tmp/dotlocaldotzshrc/test/subdirectory +cd /tmp/dotlocaldotzshrc/test || exit + +# Test Case 1: Initialize a new .local.zshrc +dotlocaldotzshrc init + +# Validate that the .local.zshrc file has been created +test -f .local.zshrc + +# Test Case 2: Attempt to initialize .local.zshrc again (expecting an error) +dotlocaldotzshrc init + +echo 'echo hello .local.zshrc' >> .local.zshrc + +# Test Case 3: Source the .local.zshrc file +dotlocaldotzshrc + +# Test Case 4: Navigate to a subdirectory and source .local.zshrc +cd subdirectory + +dotlocaldotzshrc + +# Test Case 5: Exit the .local.zshrc session +cd ../../ + +_zshrc_init + +dotlocaldotzshrc +} 2>&1 | sed "s#$PWD#/#g" diff --git a/zsh/dotlocaldotzshrc.t.out b/zsh/dotlocaldotzshrc.t.out new file mode 100644 index 0000000..6794feb --- /dev/null +++ b/zsh/dotlocaldotzshrc.t.out @@ -0,0 +1,14 @@ + rm: /tmp/dotlocaldotzshrc/test: No such file or directory + #!/usr/bin/env zsh + /tmp/dotlocaldotzshrc/test + dotlocaldotzshrc: source '/.local.zshrc' + dotlocaldotzshrc:source:39: no such file or directory: /.local.zshrc + dotlocaldotzshrc: error: /tmp/dotlocaldotzshrc/test already has a .local.zshrc + /tmp/dotlocaldotzshrc/test + dotlocaldotzshrc: source '/.local.zshrc' + dotlocaldotzshrc:source:39: no such file or directory: /.local.zshrc + /tmp/dotlocaldotzshrc/test + dotlocaldotzshrc: source '/.local.zshrc' + dotlocaldotzshrc:source:39: no such file or directory: /.local.zshrc + dotlocaldotzshrc: error: no parent directory with .local.zshrc found + (Exit Code: 0) From 12d3bd27cbba9d4a9724bd12ee3b9d3517738949 Mon Sep 17 00:00:00 2001 From: Brian Matzelle Date: Wed, 16 Oct 2024 17:36:30 -0400 Subject: [PATCH 4/4] bug fix - was calling the wrong raw file link, couldnt find it --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b460da0..44176a5 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ When using in repositories consider adding `.local.*` to your `.gitignore`. A quick setup script for Z shell. ```zsh -curl 'https://github.com/brianmatzelle/dotlocaldotrc/raw/refs/heads/master/zsh/dotlocaldotzshrc' > "$HOME/.dotlocaldotzshrc" && +curl 'https://raw.githubusercontent.com/brianmatzelle/dotlocaldotrc/refs/heads/master/zsh/dotlocaldotzshrc' > "$HOME/.dotlocaldotzshrc" && echo 'source "$HOME/.dotlocaldotzshrc"' >> ~/.zshrc ```