Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.sh]
indent_style = space
indent_size = 4

[*.{yml,yaml,json}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
40 changes: 0 additions & 40 deletions .github/workflows/blank.yml

This file was deleted.

46 changes: 46 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: Lint and format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install ShellCheck and Beautysh
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
pip install beautysh==6.4.3
shellcheck --version
beautysh --version

- name: Run all hooks
run: ./hooks/_run_all.sh

test:
name: Smoke tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Run smoke tests
run: ./tests/smoke_test.sh
110 changes: 69 additions & 41 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Removes trailing whitespace characters (spaces or tabs) from the end of lines in

### CI/CD Integration

These hooks are automatically run in the CI pipeline (see `.github/workflows/blank.yml`). The CI will fail if any checks don't pass.
These hooks are automatically run in the CI pipeline (see `.github/workflows/ci.yml`). The CI will fail if any checks don't pass.

### Git Pre-commit Hook (Optional)

Expand Down
75 changes: 47 additions & 28 deletions hooks/_run_all.sh
Original file line number Diff line number Diff line change
@@ -1,44 +1,63 @@
#!/usr/bin/env bash

# Script Name: _run_all.sh
# Description: This script will check all scripts in the specified paths.
# It finds all the scripts (not starting with _) in the 'hooks' directory and executes them with '--check' option.
# The path for the check is specified in the 'paths' array.
# At the end, it will exit with 1 if any check failed.
# Usage: ./hooks/_run_all.sh
# Description: Runs every hook in this directory (symlinks not starting with _)
# in check mode against the given paths, and exits with 1 if any
# check failed. Works from any working directory.
# Usage: ./hooks/_run_all.sh [path...]
# Paths are relative to the repository root (default: src tests).

# Ensure tput has something to work with
export TERM=${TERM:-dumb}
set -uo pipefail

# Paths to check
paths=(src)
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo_root" || exit 1

if [[ $# -gt 0 ]]; then
paths=("$@")
else
paths=(src tests)
fi

if [[ -t 1 ]]; then
RED=$'\e[31m'
GREEN=$'\e[32m'
RESET=$'\e[0m'
else
RED=""
GREEN=""
RESET=""
fi

# Status variable to track if any check fails
status=0
failed=()

# Define color codes (now safe because TERM is set)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
RESET=$(tput sgr0)
mapfile -t hooks < <(find hooks -maxdepth 1 -type l -name '[^_]*.sh' | sort)
if [[ ${#hooks[@]} -eq 0 ]]; then
echo "${RED}No hooks found in $repo_root/hooks${RESET}" >&2
exit 1
fi

# Process each path
for path in "${paths[@]}"; do
# Find all scripts (not starting with _) in 'hooks' directory
# Use process substitution to avoid subshell and preserve status variable
while read -r script; do
echo -e "\nExecuting $script"

# Execute the script with '--check' option
if "$script" --check "$path"; then
echo "${GREEN}${script} check on ${path} was successful${RESET}"
[[ -e $path ]] || continue
for hook in "${hooks[@]}"; do
echo -e "\nExecuting $hook on $path"
if "$hook" --check "$path"; then
echo "${GREEN}${hook} check on ${path} was successful${RESET}"
else
echo "${RED}${script} check on ${path} failed${RESET}"
echo "${RED}${hook} check on ${path} failed${RESET}"
failed+=("$hook ($path)")
status=1
fi
done < <(find hooks -type l -name "[^_]*.sh")
done
done

# Exit with 1 if any check failed
if [[ $status -eq 1 ]]; then
exit 1
if [[ $status -ne 0 ]]; then
echo -e "\n${RED}Failed checks:${RESET}"
printf ' %s\n' "${failed[@]}"
echo "Run the failing hook without --check to fix the files, e.g. ./hooks/last_line_empty.sh src"
else
echo -e "\n${GREEN}All checks passed.${RESET}"
fi

exit "$status"

67 changes: 48 additions & 19 deletions src/adjust_volume.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/usr/bin/env bash

# Script Name: adjust_volume.sh
# Description: Adjusts the volume for all available PulseAudio sinks.
# The adjustment can be a percentage increase or decrease (e.g., +5%, -10%)
# or a predefined mode (e.g., "full", "mute", "unmute", "reset").
# Usage: ./adjust_volume.sh -v [VALUE]
# Description: Adjusts the volume for all available PulseAudio/PipeWire sinks (via pactl).
# The adjustment can be relative (e.g., +5%, -10%), absolute (e.g., 50%)
# or a predefined mode: full (100%), mute, unmute, reset (unmute and set 100%).
# Usage: ./adjust_volume.sh -v VALUE
# ./adjust_volume.sh -h
# Options:
# -v [VALUE] Adjust volume by a specific percentage or set to a specific mode.
# -v VALUE Adjust volume by a specific percentage or set to a specific mode.
# Valid modes: full, mute, unmute, reset.
# -h Display this help message and exit.

Expand All @@ -16,14 +16,12 @@ VALID_STRINGS=("full" "mute" "unmute" "reset")

# Function to display help/usage information
display_help() {
echo "Usage: $0 [OPTION] [VALUE]"
echo "Usage: $0 -v VALUE"
echo
echo "Options:"
echo " -v [VALUE] Adjust volume by a specific amount (e.g., +5%, -10%) or set to a specific mode"
echo " Valid modes: ${VALID_STRINGS[*]}"
echo " -v VALUE Change volume relatively (e.g., +5%, -10%), set it absolutely (e.g., 50%)"
echo " or apply a mode: full (100%), mute, unmute, reset (unmute + 100%)"
echo " -h Display this help message and exit"
echo
exit 0
}

# Function to validate volume adjustment input
Expand All @@ -37,10 +35,10 @@ validate_input() {
fi
done

# Check if input is a number with + or - and within the range of -100 to +100
# Check if input is a number with optional + or - and within the range of -100 to +100
if [[ "$input" =~ ^[+-]?[0-9]+%?$ ]]; then
local value="${input%?}" # Remove % if present
if ((value >= -100 && value <= 100)); then
local value="${input%\%}" # Remove % if present
if (( 10#${value#[+-]} <= 100 )); then
return 0
fi
fi
Expand All @@ -49,37 +47,68 @@ validate_input() {
}

# Parse command-line arguments
input_value=""
while getopts ":v:h" opt; do
case ${opt} in
v)
input_value="$OPTARG"
;;
h)
display_help
exit 0
;;
"?")
echo "Invalid option: -$OPTARG" >&2
display_help
display_help >&2
exit 1
;;
":")
echo "Option -$OPTARG requires an argument." >&2
display_help
display_help >&2
exit 1
;;
esac
done

if [[ -z "$input_value" ]]; then
display_help >&2
exit 1
fi

# Validate the input
if ! validate_input "$input_value"; then
echo "Invalid input: '$input_value'. Use -h for help." >&2
exit 1
fi

if ! command -v pactl >/dev/null 2>&1; then
echo "Error: pactl is not installed." >&2
exit 1
fi

mapfile -t sinks < <(pactl list short sinks | cut -f1)
if [[ ${#sinks[@]} -eq 0 ]]; then
echo "Error: No audio sinks found." >&2
exit 1
fi

# Apply the volume adjustment to all sinks
for sink in $(pactl list short sinks | cut -f1); do
pactl set-sink-volume "$sink" "$input_value"
status=0
for sink in "${sinks[@]}"; do
# Numbers get a % suffix: without it pactl treats them as raw volume values
case "$input_value" in
full) pactl set-sink-volume "$sink" 100% ;;
mute) pactl set-sink-mute "$sink" 1 ;;
unmute) pactl set-sink-mute "$sink" 0 ;;
reset) pactl set-sink-mute "$sink" 0 && pactl set-sink-volume "$sink" 100% ;;
*) pactl set-sink-volume "$sink" "${input_value%\%}%" ;;
esac || status=1
done

echo "Volume adjusted by $input_value for all sinks."
if [[ $status -ne 0 ]]; then
echo "Error: Failed to adjust the volume of some sinks." >&2
exit 1
fi

exit 0
echo "Volume adjusted ($input_value) for all sinks."

Loading
Loading