From 09e429c99808616729f75573320656dd8c5a9d1e Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Mon, 8 Jun 2026 13:47:36 +0100 Subject: [PATCH] Make using check-version.sh support and/or --- check-version.sh | 117 +++++++++++++++++++++++++++++++++++++---------- tmux.conf | 8 ++-- 2 files changed, 97 insertions(+), 28 deletions(-) diff --git a/check-version.sh b/check-version.sh index d69a23e..d240848 100755 --- a/check-version.sh +++ b/check-version.sh @@ -1,13 +1,29 @@ #!/usr/bin/env bash -# Compare the current tmux version against a given version. -# Exit: 0 if comparison is true, 1 if false +# Compare the current tmux version against one or more version constraints. +# +# Each constraint pairs an operator and version in a single argument, +# e.g. ">= 3.2". Multiple constraints can be joined with the logical operators +# `and` / `or`, where `and` binds tighter than `or` (standard precedence). This +# allows a single invocation to express a range without spawning the script +# multiple times. +# +# Exit: 0 if the whole expression is true, 1 if false +# +# Examples: +# check-version.sh ">= 3.2" +# check-version.sh ">= 3.2" and "< 3.3" +# check-version.sh "< 2.9" or ">= 3.4" set -euo pipefail usage() { - echo "usage: $0 " >&2 - echo "operators: < <= == >= >" >&2 + cat >&2 <<'EOF' +usage: check-version.sh [and|or ...] + constraint: , e.g. ">= 3.2" + operators: < <= == >= > + logical: and or (and binds tighter than or) +EOF } if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then @@ -15,14 +31,11 @@ if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then exit 0 fi -if [[ $# -ne 2 ]]; then +if [[ $# -eq 0 ]]; then usage exit 1 fi -operator="$1" -target_version="$2" - # Extract tmux version (e.g., "tmux 3.3a" -> "3.3a") current_version=$(tmux -V | sed 's/^tmux //') @@ -75,22 +88,78 @@ compare_versions() { echo 0 } -result=$(compare_versions "$current_version" "$target_version") +# Evaluate a single constraint (e.g. ">= 3.2") against the current version. +# Returns 0 (true) or 1 (false); exits on a malformed constraint. +eval_constraint() { + local constraint="$1" + local operator version + read -r operator version <<< "$constraint" -case "$operator" in - '<') - [[ "$result" -eq -1 ]] && exit 0 || exit 1 ;; - '<=') - [[ "$result" -le 0 ]] && exit 0 || exit 1 ;; - '==') - [[ "$result" -eq 0 ]] && exit 0 || exit 1 ;; - '>=') - [[ "$result" -ge 0 ]] && exit 0 || exit 1 ;; - '>') - [[ "$result" -eq 1 ]] && exit 0 || exit 1 ;; - *) - echo "error: invalid operator: $operator" >&2 + if [[ -z "$operator" || -z "$version" ]]; then + echo "error: invalid constraint: '$constraint' (expected ' ', e.g. '>= 3.2')" >&2 usage exit 1 - ;; -esac + fi + + local result + result=$(compare_versions "$current_version" "$version") + + case "$operator" in + '<') [[ "$result" -eq -1 ]] ;; + '<=') [[ "$result" -le 0 ]] ;; + '==') [[ "$result" -eq 0 ]] ;; + '>=') [[ "$result" -ge 0 ]] ;; + '>') [[ "$result" -eq 1 ]] ;; + *) + echo "error: invalid operator: '$operator'" >&2 + usage + exit 1 ;; + esac +} + +# Walk the alternating constraint/logical sequence, accumulating each `and` +# group (1 = true) and folding completed groups into the `or` result. Truth +# values are tracked as ints and converted to an exit code at the end. +or_result=0 +and_result=1 +expect=constraint + +for token in "$@"; do + if [[ "$expect" == "constraint" ]]; then + case "$token" in + and | or) + echo "error: expected a constraint, got logical operator: $token" >&2 + usage + exit 1 ;; + esac + if eval_constraint "$token"; then + and_result=$(( and_result & 1 )) + else + and_result=$(( and_result & 0 )) + fi + expect=logical + else + case "$token" in + and) + ;; + or) + or_result=$(( or_result | and_result )) + and_result=1 ;; + *) + echo "error: expected 'and' or 'or', got: $token" >&2 + usage + exit 1 ;; + esac + expect=constraint + fi +done + +if [[ "$expect" == "constraint" ]]; then + echo "error: expression ends with a logical operator" >&2 + usage + exit 1 +fi + +or_result=$(( or_result | and_result )) + +[[ "$or_result" -eq 1 ]] && exit 0 || exit 1 diff --git a/tmux.conf b/tmux.conf index 978dc20..c7e7530 100644 --- a/tmux.conf +++ b/tmux.conf @@ -28,7 +28,7 @@ set -g status-interval 2 set -g default-terminal "tmux-256color" # Enable true-color -if '~/.config/tmux/check-version.sh "<" 3.2' \ +if '~/.config/tmux/check-version.sh "< 3.2"' \ 'set-option -as terminal-features ",xterm*:Tc"' \ 'set-option -as terminal-features ",xterm*:RGB"' @@ -52,7 +52,7 @@ unbind -T copy-mode-vi MouseDragEnd1Pane # Enable changing cursor shape per pane, vim or zsh should emit escape # sequences to change cursor shape. # iTerm2 only requires this before tmux 2.9 -if '[ -n $ITERM_PROFILE ] && ~/.config/tmux/check-version.sh "<" 2.9' \ +if '[ -n $ITERM_PROFILE ] && ~/.config/tmux/check-version.sh "< 2.9"' \ 'set -ga terminal-overrides "*:Ss=\E]1337;CursorShape=%p1%d\7"' # VTE compatible terminals. if '[ ! -n $ITERM_PROFILE ]' \ @@ -61,7 +61,7 @@ if '[ ! -n $ITERM_PROFILE ]' \ # Enable strikethrough on VTE compatible terminals. set -ga terminal-overrides 'xterm*:smxx=\E[9m' -if -b '~/.config/tmux/check-version.sh ">=" 3.2 && ~/.config/tmux/check-version.sh "<" 3.3' { +if -b '~/.config/tmux/check-version.sh ">= 3.2" and "< 3.3"' { bind A if -F '#{==:#{session_name},agent}' { detach-client } { display-popup -d '#{pane_current_path}' -w 50% -h 90% -E ~/.config/tmux/agent.sh } @@ -72,7 +72,7 @@ if -b '~/.config/tmux/check-version.sh ">=" 3.2 && ~/.config/tmux/check-version. bind S display-popup -w 60 -h 10 -E ~/.config/tmux/session.sh bind T display-popup -d '#{pane_current_path}' -E $SHELL } -if -b '~/.config/tmux/check-version.sh ">=" 3.3' { +if -b '~/.config/tmux/check-version.sh ">= 3.3"' { bind A if -F '#{==:#{session_name},agent}' { detach-client } { display-popup -S fg=#54546D -b rounded -d '#{pane_current_path}' -w 75% -h 90% -E ~/.config/tmux/agent.sh }