Compare commits

...

27 Commits

Author SHA1 Message Date
renovate[bot]
bae84c176c fix(container): update image python (3.13.3 → 3.13.4) (#119)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 07:45:53 +03:00
be8a6761af test: expand version comparison tests (#118) 2025-06-04 12:12:55 +03:00
c348f3625f chore(lint): fix replacable helper typo (#116)
* Fix typo in replaceable helper

* chore(docs): add docstrings to `codex/rename-replacable-to-replaceable-and-update-references` (#117)

Docstrings generation was requested by @ivuorinen.

* https://github.com/ivuorinen/dotfiles/pull/116#issuecomment-2938946257

The following files were modified:

* `scripts/install-cheat-purebashbible.sh`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-06-04 11:00:42 +03:00
094f19c99c chore(config): tweak yabai config
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-06-03 13:58:04 +03:00
5a23ae8f01 chore(config): nvim tweaks
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-06-03 13:57:01 +03:00
github-actions[bot]
ee47821089 chore: update pre-commit hooks (#115) 2025-06-02 08:16:06 +03:00
github-actions[bot]
b834ce04f7 chore: update pre-commit hooks (#114) 2025-05-29 14:54:33 +03:00
github-actions[bot]
6a62d73d7f chore: update pre-commit hooks (#113) 2025-05-26 13:15:01 +03:00
github-actions[bot]
440842ed34 chore: update pre-commit hooks (#112) 2025-05-22 08:29:51 +03:00
renovate[bot]
d0563e4a29 chore(deps): update node.js to v22.16.0 (#111) 2025-05-22 01:11:53 +03:00
github-actions[bot]
bc404bfbea chore: update pre-commit hooks (#110) 2025-05-19 08:27:54 +03:00
923f881725 chore(config): change git merge conflictStyle 2025-05-16 21:50:29 +03:00
ccc5903290 chore(config): updated zed settings
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-05-16 21:49:55 +03:00
renovate[bot]
786efc48fa chore(deps): update node.js to v22.15.1 (#109) 2025-05-15 20:09:12 +03:00
2a11a28422 chore(repo): tweak install.conf.yaml
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-05-15 16:39:15 +03:00
812a27ea61 chore(config): updated zed settings
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-05-15 16:38:49 +03:00
e73e61f01b chore(config): added git-profile completions
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-05-15 16:38:23 +03:00
314679b4fc chore(deps): updated Brewfile
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-05-15 16:37:59 +03:00
github-actions[bot]
516b27384a chore: update pre-commit hooks (#108)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-05-12 12:28:03 +03:00
github-actions[bot]
9e1af3053d chore: update pre-commit hooks (#107)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-05-08 09:51:32 +03:00
github-actions[bot]
9e4f8741b3 chore: update pre-commit hooks (#106)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-05-05 11:37:52 +03:00
c0995c1b49 chore(config): zed: settings update 2025-05-03 02:32:38 +03:00
c9f1e824c3 chore(bin): fish support shared.sh and dfm 2025-05-03 02:32:01 +03:00
3d301daeb1 chore: remove x-dupers.pl 2025-05-03 02:29:48 +03:00
8b4198dc90 chore(lint): shfmt local/bin/* 2025-05-03 02:15:04 +03:00
66461f9b1b chore(config): zed: update config 2025-05-03 02:14:19 +03:00
80851d1efd chore(config): vim: fix ctrl-s, ctrl-p 2025-05-03 02:13:45 +03:00
20 changed files with 403 additions and 311 deletions

2
.nvmrc
View File

@@ -1 +1 @@
22.15.0
22.16.0

View File

@@ -23,13 +23,13 @@ repos:
args: [--autofix, --no-sort-keys]
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.44.0
rev: v0.45.0
hooks:
- id: markdownlint
args: [-c, .markdownlint.json, --fix]
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.0
rev: v1.37.1
hooks:
- id: yamllint
@@ -49,7 +49,7 @@ repos:
- id: actionlint
- repo: https://github.com/renovatebot/pre-commit-hooks
rev: 40.0.6
rev: 40.36.8
hooks:
- id: renovate-config-validator

View File

@@ -1 +1 @@
3.13.3
3.13.4

View File

@@ -213,7 +213,7 @@ get_sha256sum()
# $2 - filename (string)
#
# Returns 1 when replaceable, 0 when not replaceable.
replacable()
replaceable()
{
FILE1="$1"
FILE2="$2"

View File

@@ -0,0 +1,176 @@
# fish completion for git-profile -*- shell-script -*-
function __git_profile_debug
set -l file "$BASH_COMP_DEBUG_FILE"
if test -n "$file"
echo "$argv" >> $file
end
end
function __git_profile_perform_completion
__git_profile_debug "Starting __git_profile_perform_completion"
# Extract all args except the last one
set -l args (commandline -opc)
# Extract the last arg and escape it in case it is a space
set -l lastArg (string escape -- (commandline -ct))
__git_profile_debug "args: $args"
__git_profile_debug "last arg: $lastArg"
set -l requestComp "$args[1] __complete $args[2..-1] $lastArg"
__git_profile_debug "Calling $requestComp"
set -l results (eval $requestComp 2> /dev/null)
# Some programs may output extra empty lines after the directive.
# Let's ignore them or else it will break completion.
# Ref: https://github.com/spf13/cobra/issues/1279
for line in $results[-1..1]
if test (string trim -- $line) = ""
# Found an empty line, remove it
set results $results[1..-2]
else
# Found non-empty line, we have our proper output
break
end
end
set -l comps $results[1..-2]
set -l directiveLine $results[-1]
# For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
# completions must be prefixed with the flag
set -l flagPrefix (string match -r -- '-.*=' "$lastArg")
__git_profile_debug "Comps: $comps"
__git_profile_debug "DirectiveLine: $directiveLine"
__git_profile_debug "flagPrefix: $flagPrefix"
for comp in $comps
printf "%s%s\n" "$flagPrefix" "$comp"
end
printf "%s\n" "$directiveLine"
end
# This function does two things:
# - Obtain the completions and store them in the global __git_profile_comp_results
# - Return false if file completion should be performed
function __git_profile_prepare_completions
__git_profile_debug ""
__git_profile_debug "========= starting completion logic =========="
# Start fresh
set --erase __git_profile_comp_results
set -l results (__git_profile_perform_completion)
__git_profile_debug "Completion results: $results"
if test -z "$results"
__git_profile_debug "No completion, probably due to a failure"
# Might as well do file completion, in case it helps
return 1
end
set -l directive (string sub --start 2 $results[-1])
set --global __git_profile_comp_results $results[1..-2]
__git_profile_debug "Completions are: $__git_profile_comp_results"
__git_profile_debug "Directive is: $directive"
set -l shellCompDirectiveError 1
set -l shellCompDirectiveNoSpace 2
set -l shellCompDirectiveNoFileComp 4
set -l shellCompDirectiveFilterFileExt 8
set -l shellCompDirectiveFilterDirs 16
if test -z "$directive"
set directive 0
end
set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2)
if test $compErr -eq 1
__git_profile_debug "Received error directive: aborting."
# Might as well do file completion, in case it helps
return 1
end
set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2)
set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2)
if test $filefilter -eq 1; or test $dirfilter -eq 1
__git_profile_debug "File extension filtering or directory filtering not supported"
# Do full file completion instead
return 1
end
set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2)
set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2)
__git_profile_debug "nospace: $nospace, nofiles: $nofiles"
# If we want to prevent a space, or if file completion is NOT disabled,
# we need to count the number of valid completions.
# To do so, we will filter on prefix as the completions we have received
# may not already be filtered so as to allow fish to match on different
# criteria than the prefix.
if test $nospace -ne 0; or test $nofiles -eq 0
set -l prefix (commandline -t | string escape --style=regex)
__git_profile_debug "prefix: $prefix"
set -l completions (string match -r -- "^$prefix.*" $__git_profile_comp_results)
set --global __git_profile_comp_results $completions
__git_profile_debug "Filtered completions are: $__git_profile_comp_results"
# Important not to quote the variable for count to work
set -l numComps (count $__git_profile_comp_results)
__git_profile_debug "numComps: $numComps"
if test $numComps -eq 1; and test $nospace -ne 0
# We must first split on \t to get rid of the descriptions to be
# able to check what the actual completion will be.
# We don't need descriptions anyway since there is only a single
# real completion which the shell will expand immediately.
set -l split (string split --max 1 \t $__git_profile_comp_results[1])
# Fish won't add a space if the completion ends with any
# of the following characters: @=/:.,
set -l lastChar (string sub -s -1 -- $split)
if not string match -r -q "[@=/:.,]" -- "$lastChar"
# In other cases, to support the "nospace" directive we trick the shell
# by outputting an extra, longer completion.
__git_profile_debug "Adding second completion to perform nospace directive"
set --global __git_profile_comp_results $split[1] $split[1].
__git_profile_debug "Completions are now: $__git_profile_comp_results"
end
end
if test $numComps -eq 0; and test $nofiles -eq 0
# To be consistent with bash and zsh, we only trigger file
# completion when there are no other completions
__git_profile_debug "Requesting file completion"
return 1
end
end
return 0
end
# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves
# so we can properly delete any completions provided by another script.
# Only do this if the program can be found, or else fish may print some errors; besides,
# the existing completions will only be loaded if the program can be found.
if type -q "git-profile"
# The space after the program name is essential to trigger completion for the program
# and not completion of the program name itself.
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish.
complete --do-complete "git-profile " > /dev/null 2>&1
end
# Remove any pre-existing completions for the program since we will be handling all of them.
complete -c git-profile -e
# The call to __git_profile_prepare_completions will setup __git_profile_comp_results
# which provides the program's completion choices.
complete -c git-profile -n '__git_profile_prepare_completions' -f -a '$__git_profile_comp_results'

View File

@@ -46,7 +46,7 @@
autoStash = true
updateRefs = true
[merge]
conflictstyle = zdiff3
conflictStyle = diff3
[pull]
rebase = true
[color "diff-highlight"]

View File

@@ -115,10 +115,10 @@ brew "harfbuzz"
brew "dependency-check"
# Lightweight DNS forwarder and DHCP server
brew "dnsmasq"
# .NET Core
brew "dotnet@8", link: true
# Spellchecker wrapping library
brew "enchant"
# Command-line tool to interact with exercism.io
brew "exercism"
# Perl lib for reading and writing EXIF metadata
brew "exiftool"
# Banner-like program prints strings as ASCII art

View File

@@ -5,7 +5,7 @@
-- ── Install lazylazy ────────────────────────────────────────────────
-- https://github.com/folke/lazy.nvim
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
if not vim.uv.fs_stat(lazypath) then
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = 'https://github.com/folke/lazy.nvim.git'
local out = vim.fn.system {
'git',

View File

@@ -13,7 +13,7 @@ local a = vim.api -- A table to store API functions
g.mapleader = ' ' -- Space as the leader key
g.maplocalleader = ' ' -- Space as the local leader key
g.colors_theme = 'pencil' -- Set the colorscheme
g.colors_theme = 'onedark' -- Set the colorscheme
-- g.colors_variant_light = 'tokyonight-day' -- Set the light variant
-- g.colors_variant_dark = 'tokyonight-storm' -- Set the dark variant

View File

@@ -17,13 +17,53 @@ DEBUG="${DEBUG:-0}"
# Enable debugging with DEBUG=1
[ "${DEBUG:-0}" -eq 1 ] && set -x
# Detect the current shell
CURRENT_SHELL=$(ps -p $$ -ocomm= | awk -F/ '{print $NF}')
# Function to prepend a path to PATH based on the shell
x-path-prepend()
{
local dir=$1
case "$CURRENT_SHELL" in
fish)
set -U fish_user_paths "$dir" $fish_user_paths
;;
sh | bash | zsh)
PATH="$dir:$PATH"
;;
*)
echo "Unsupported shell: $CURRENT_SHELL"
exit 1
;;
esac
}
# Function to set environment variables based on the shell
x-set-env()
{
local var=$1
local value=$2
case "$CURRENT_SHELL" in
fish)
set -x "$var" "$value"
;;
sh | bash | zsh)
export "$var=$value"
;;
*)
echo "Unsupported shell: $CURRENT_SHELL"
exit 1
;;
esac
}
# Explicitly set XDG folders, if not already set
# https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
[ -z "$XDG_CONFIG_HOME" ] && export XDG_CONFIG_HOME="$HOME/.config"
[ -z "$XDG_DATA_HOME" ] && export XDG_DATA_HOME="$HOME/.local/share"
[ -z "$XDG_CACHE_HOME" ] && export XDG_CACHE_HOME="$HOME/.cache"
[ -z "$XDG_STATE_HOME" ] && export XDG_STATE_HOME="$HOME/.local/state"
[ -z "$XDG_BIN_HOME" ] && export XDG_BIN_HOME="$HOME/.local/bin"
x-set-env XDG_CONFIG_HOME "$HOME/.config"
x-set-env XDG_DATA_HOME "$HOME/.local/share"
x-set-env XDG_CACHE_HOME "$HOME/.cache"
x-set-env XDG_STATE_HOME "$HOME/.local/state"
x-set-env XDG_BIN_HOME "$HOME/.local/bin"
# Paths
x-path-prepend "/usr/local/bin"

View File

@@ -17,7 +17,7 @@ cnoreabbrev Qall qall " quit all
"" Mappings
"*****************************************************************************
noremap <C-S> :w<CR> " save buffer
noremap <C-s> :w<CR> " save buffer
" Split
noremap <Leader>h :<C-u>split<CR> " horizontal split
@@ -57,7 +57,7 @@ noremap <Leader>r :tabe <C-R>=expand("%:p:h") . "/" <CR>
" fzf.vim
let $FZF_DEFAULT_COMMAND = "find * -path '*/\.*' -prune -o -path 'node_modules/**' -prune -o -path 'target/**' -prune -o -path 'vendor/**' -prune -o -path 'dist/**' -prune -o -type f -print -o -type l -print 2> /dev/null"
cnoremap <C-P> <C-R>=expand("%:p:h") . "/" <CR>
cnoremap <C-p> <C-R>=expand("%:p:h") . "/" <CR>
nnoremap <silent> <leader>b :Buffers<CR>
nnoremap <silent> <leader>e :FZF -m<CR>
" Recovery commands from history through FZF

View File

@@ -22,16 +22,19 @@ yabai -m config \
# apps to not manage (ignore)
# TODO: add apps from aerospace config to here
# list active apps:
# > yabai -m query --windows | jq .[].app
# > yabai -m query --windows | jq .[].app | sort | uniq
yabai -m rule --add app="1Password" manage=off
yabai -m rule --add app="Fork" manage=off
yabai -m rule --add app="JetBrains Rider" manage=off
yabai -m rule --add app="Logi Options" manage=off
yabai -m rule --add app="MSTeams" manage=off
yabai -m rule --add app="Microsoft Teams" manage=off
yabai -m rule --add app="PhpStorm" manage=off
yabai -m rule --add app="Slack" manage=off
yabai -m rule --add app="System Settings" manage=off
yabai -m rule --add app="^Logi Options$" manage=off
yabai -m rule --add app="^Microsoft Teams$" manage=off
yabai -m rule --add app="^PhpStorm$" manage=off
yabai -m rule --add app="^Slack$" manage=off
yabai -m rule --add app="^TIDAL$" manage=off
yabai -m rule --add app="^Windows App$" manage=off
yabai -m rule --add app="TIDAL" manage=off
yabai -m rule --add app="Windows App" manage=off
yabai -m rule --add app="Zoom" manage=off
# apply rules
yabai -m rule --apply

View File

@@ -3,13 +3,19 @@
"metrics": false
},
"assistant": {
"always_allow_tool_actions": false,
"default_model": {
"provider": "copilot_chat",
"model": "claude-3.7-sonnet-thought"
"model": "gpt-4.1"
},
"version": "2"
},
"languages": {
"Python": {
"enable_language_server": true,
"allow_rewrap": "anywhere",
"auto_indent_on_paste": true
},
"Shell Script": {
"enable_language_server": true
},
@@ -49,8 +55,8 @@
"vim_mode": true,
"theme": {
"mode": "system",
"light": "Iceberg",
"dark": "Iceberg"
"light": "Tokyo Night Light",
"dark": "Tokyo Night Storm"
},
"inlay_hints": {
"enabled": true,
@@ -60,13 +66,9 @@
},
"ui_font_size": 16,
"buffer_font_size": 16,
"buffer_font_fallbacks": [
"JetBrainsMono Nerd Font"
],
"buffer_font_fallbacks": ["JetBrainsMono Nerd Font"],
"edit_predictions": {
"disabled_globs": [
".env"
]
"disabled_globs": [".env", ".env.*"]
},
"hour_format": "hour24"
}

View File

@@ -45,9 +45,9 @@
~/.config/op/plugins.sh:
relink: true
path: config/op/plugins.sh
~/.config/op/plugins/*:
~/.config/op/plugins:
relink: true
path: config/op/plugins/*
path: config/op/plugins
# Scripts
~/.local/bin:
glob: true

View File

@@ -15,9 +15,35 @@
SCRIPT=$(basename "$0")
# Loads configs for better installation experience
source "$DOTFILES/config/shared.sh"
source "${DOTFILES}/local/bin/msgr"
# Detect the current shell
CURRENT_SHELL=$(ps -p $$ -ocomm= | awk -F/ '{print $NF}')
# Function to source files based on the shell
source_file()
{
local file=$1
case "$CURRENT_SHELL" in
fish)
if [[ -f "$file.fish" ]]; then
source "$file.fish"
else
echo "Fish shell file not found: $file.fish"
exit 1
fi
;;
sh | bash | zsh)
source "$file"
;;
*)
echo "Unsupported shell: $CURRENT_SHELL"
exit 1
;;
esac
}
# Modify the source commands to use the new function
source_file "$DOTFILES/config/shared.sh"
source_file "${DOTFILES}/local/bin/msgr"
# Menu builder
menu_builder()
@@ -267,7 +293,7 @@ section_helpers()
{
USAGE_PREFIX="$SCRIPT helpers <command>"
MENU=(
"aliases:<shell> (bash, zsh) Show aliases"
"aliases:<shell> (bash, zsh, fish) Show aliases"
"colors:Show colors"
"env:Show environment variables"
"functions:Show functions"
@@ -297,8 +323,11 @@ section_helpers()
"bash")
bash -ixc : 2>&1 | grep -E '> alias' | sed "s|$HOME|~|" | grep -v "(eval)"
;;
"fish")
fish -ic "alias" | sed "s|$HOME|~|"
;;
*)
echo "$SCRIPT helpers aliases <shell> (bash, zsh)"
echo "$SCRIPT helpers aliases <shell> (bash, zsh, fish)"
;;
esac
;;

View File

@@ -11,10 +11,10 @@ set -euo pipefail
VERBOSE=0
CHECK_PATTERN="text: auto"
EXIT_ON_MISSING=0
SUGGEST_RULES=1 # Suggestions enabled by default
WRITE_RULES=0 # Writing to file is opt-in
FORMAT_WIDTH=0 # Auto-width by default (0 means auto)
MIN_FORMAT_WIDTH=20 # Minimum format width
SUGGEST_RULES=1 # Suggestions enabled by default
WRITE_RULES=0 # Writing to file is opt-in
FORMAT_WIDTH=0 # Auto-width by default (0 means auto)
MIN_FORMAT_WIDTH=20 # Minimum format width
DEBUG="${DEBUG:-0}"
@@ -23,27 +23,33 @@ if [ "$DEBUG" -eq 1 ]; then
fi
# Output functions
msg_err() {
msg_err()
{
echo -e "\e[31m$@\e[0m" >&2
}
msg_success() {
msg_success()
{
echo -e "\e[32m$@\e[0m"
}
msg_warn() {
msg_warn()
{
echo -e "\e[33m$@\e[0m" >&2
}
msg_info() {
msg_info()
{
echo -e "\e[36m$@\e[0m"
}
msg_debug() {
msg_debug()
{
[[ $VERBOSE -eq 1 ]] && echo -e "\e[35m$@\e[0m"
}
show_help() {
show_help()
{
cat << EOF
Usage: $(basename "$0") [OPTIONS]
@@ -64,31 +70,31 @@ EOF
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
-h | --help)
show_help
exit 0
;;
-v|--verbose)
-v | --verbose)
VERBOSE=1
shift
;;
-e|--exit)
-e | --exit)
EXIT_ON_MISSING=1
shift
;;
-p|--pattern)
-p | --pattern)
CHECK_PATTERN="$2"
shift 2
;;
-n|--no-suggest)
-n | --no-suggest)
SUGGEST_RULES=0
shift
;;
-w|--write)
-w | --write)
WRITE_RULES=1
shift
;;
-f|--format-width)
-f | --format-width)
if [[ $2 =~ ^[0-9]+$ ]]; then
FORMAT_WIDTH=$2
shift 2
@@ -106,7 +112,8 @@ while [[ $# -gt 0 ]]; do
done
# Function to check if git is installed
check_git_installed() {
check_git_installed()
{
if ! command -v git &> /dev/null; then
msg_err "git could not be found, please install it first"
exit 1
@@ -114,15 +121,17 @@ check_git_installed() {
}
# Check if we're in a git repository
check_git_repo() {
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
check_git_repo()
{
if ! git rev-parse --is-inside-work-tree &> /dev/null; then
msg_err "Not inside a git repository"
exit 1
fi
}
# Check if we're in the git root directory
check_git_root() {
check_git_root()
{
local git_root
git_root=$(git rev-parse --show-toplevel)
local current_dir
@@ -136,7 +145,8 @@ check_git_root() {
}
# Check if .gitattributes exists
check_gitattributes_exists() {
check_gitattributes_exists()
{
if [[ ! -f ".gitattributes" ]]; then
msg_err ".gitattributes file not found in the repository root"
msg_warn "Create a .gitattributes file before running this command"
@@ -145,7 +155,8 @@ check_gitattributes_exists() {
}
# Format rule with proper alignment
format_rule() {
format_rule()
{
local pattern="$1"
local attributes="$2"
local width="$3"
@@ -166,7 +177,8 @@ format_rule() {
}
# Get the file extension properly, handling special cases
get_file_extension() {
get_file_extension()
{
local file="$1"
local basename=$(basename "$file")
local extension=""
@@ -199,7 +211,8 @@ get_file_extension() {
}
# Suggest appropriate gitattributes rules based on file extension
suggest_rule() {
suggest_rule()
{
local file="$1"
local extension=""
local pattern=""
@@ -237,15 +250,15 @@ suggest_rule() {
# Common text files
case "$extension" in
# Shell scripts
sh|bash|zsh|fish)
sh | bash | zsh | fish)
attributes="text eol=lf diff=shell"
;;
# Web development
html|htm|xhtml|css|scss|sass|less)
html | htm | xhtml | css | scss | sass | less)
attributes="text eol=lf diff=html"
;;
js|jsx|ts|tsx|json|json5)
js | jsx | ts | tsx | json | json5)
attributes="text eol=lf diff=javascript"
;;
@@ -262,20 +275,20 @@ suggest_rule() {
go)
attributes="text eol=lf diff=golang"
;;
java|kt|scala)
java | kt | scala)
attributes="text eol=lf diff=java"
;;
c|cpp|h|hpp)
c | cpp | h | hpp)
attributes="text eol=lf diff=cpp"
;;
# Documentation
md|markdown|txt)
md | markdown | txt)
attributes="text eol=lf"
;;
# Configuration files
yml|yaml|toml|ini|cfg|conf)
yml | yaml | toml | ini | cfg | conf)
attributes="text eol=lf"
;;
@@ -283,24 +296,24 @@ suggest_rule() {
git)
attributes="text eol=lf"
;;
gitignore|gitattributes)
gitignore | gitattributes)
attributes="text eol=lf"
;;
# Binary files
png|jpg|jpeg|gif|ico|svg|webp|avif)
png | jpg | jpeg | gif | ico | svg | webp | avif)
attributes="binary"
;;
pdf|doc|docx|xls|xlsx|ppt|pptx)
pdf | doc | docx | xls | xlsx | ppt | pptx)
attributes="binary"
;;
zip|tar|gz|7z|rar)
zip | tar | gz | 7z | rar)
attributes="binary"
;;
mp3|mp4|avi|mov|wav|ogg)
mp3 | mp4 | avi | mov | wav | ogg)
attributes="binary"
;;
ttf|otf|woff|woff2|eot)
ttf | otf | woff | woff2 | eot)
attributes="binary"
;;
@@ -321,7 +334,8 @@ suggest_rule() {
}
# Function to check for missing .gitattributes
check_gitattributes() {
check_gitattributes()
{
local missing_attributes
msg_info "Checking for pattern: $CHECK_PATTERN"
@@ -362,7 +376,8 @@ check_gitattributes() {
}
# Parse rule string and extract pattern and attributes
parse_rule() {
parse_rule()
{
local rule="$1"
if [[ "$rule" == "#"* ]]; then
@@ -379,7 +394,8 @@ parse_rule() {
}
# Check shell scripts by name regardless of extension
detect_shell_scripts() {
detect_shell_scripts()
{
msg_debug "Detecting shell scripts by name regardless of extension..."
local shell_scripts_rules=""
@@ -510,13 +526,14 @@ detect_shell_scripts() {
# Return the formatted arrays
local rules_count=${#patterns[@]}
for ((i=0; i<rules_count; i++)); do
for ((i = 0; i < rules_count; i++)); do
echo "${patterns[$i]}:${attributes[$i]}"
done
}
# Function to suggest gitattributes rules
suggest_gitattributes() {
suggest_gitattributes()
{
local missing_attributes="$1"
local files
local extension_suggestions=()
@@ -613,7 +630,7 @@ suggest_gitattributes() {
# Format and output all suggestions with proper alignment
local rule_count=${#all_patterns[@]}
for ((i=0; i<rule_count; i++)); do
for ((i = 0; i < rule_count; i++)); do
local pattern="${all_patterns[$i]}"
local attributes="${all_attributes[$i]}"
@@ -637,7 +654,8 @@ suggest_gitattributes() {
}
# Write suggestions to .gitattributes file
write_to_gitattributes() {
write_to_gitattributes()
{
local suggestions="$1"
local gitattributes=".gitattributes"
@@ -664,7 +682,8 @@ write_to_gitattributes() {
}
# Main function
main() {
main()
{
check_git_installed
check_git_repo
check_git_root

View File

@@ -201,7 +201,7 @@ process_args()
# Initialize log file if specified
if [[ -n "$LOG_FILE" ]]; then
# Create log directory if it doesn't exist
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
mkdir -p "$(dirname "$LOG_FILE")" 2> /dev/null || true
# Initialize log file
echo "[$(date +"%Y-%m-%d %H:%M:%S")] [INFO] Started git-update-dirs version $VERSION" > "$LOG_FILE"
fi
@@ -375,7 +375,7 @@ cleanup_branches()
local cleaned=0
local current_branch output
current_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
current_branch=$(git symbolic-ref --short HEAD 2> /dev/null)
# Skip branch cleanup if we're not on a main branch
if [[ ! "$current_branch" =~ ^(master|main|develop)$ ]]; then
@@ -397,7 +397,7 @@ cleanup_branches()
# Delete branches
for branch in $output; do
if [[ -n "$branch" ]]; then
if git branch -d "$branch" &>/dev/null; then
if git branch -d "$branch" &> /dev/null; then
((cleaned++))
log "INFO" "Deleted merged branch $branch in $(pwd)"
else
@@ -426,7 +426,7 @@ update_repo()
# Show progress before starting the operation
show_progress "$PROCESSED" "$TOTAL" "${dir%/}"
cd "$dir" 2>/dev/null || {
cd "$dir" 2> /dev/null || {
log "ERROR" "Could not enter directory $dir"
echo -e "\n${RED}Error: Could not enter directory $dir${NC}" >&2
((FAILED++))
@@ -438,37 +438,37 @@ update_repo()
log "INFO" "Skipping directory with no remotes: $dir"
msg "Skipping directory with no remotes: $dir"
((SKIPPED++))
cd - >/dev/null || true
cd - > /dev/null || true
return 1
fi
# Get current branch name
current_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
current_branch=$(git symbolic-ref --short HEAD 2> /dev/null)
if [[ -z "$current_branch" ]]; then
log "INFO" "Skipping repository in detached HEAD state: $dir"
msg "Skipping repository in detached HEAD state: $dir"
((SKIPPED++))
cd - >/dev/null || true
cd - > /dev/null || true
return 1
fi
# Check if current branch has tracking information
eval "git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null" &>/dev/null || {
eval "git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null" &> /dev/null || {
log "INFO" "Skipping branch '$current_branch' without tracking info in $dir"
msg "Skipping branch '$current_branch' without tracking info in $dir"
((SKIPPED++))
cd - >/dev/null || true
cd - > /dev/null || true
return 1
}
# Check if remote is accessible
remote_name=$(git config --get branch."$current_branch".remote)
if [[ -n "$remote_name" ]]; then
if ! git ls-remote --exit-code "$remote_name" &>/dev/null; then
if ! git ls-remote --exit-code "$remote_name" &> /dev/null; then
log "WARNING" "Skipping repository with inaccessible remote '$remote_name': $dir"
msg "Skipping repository with inaccessible remote: $dir"
((SKIPPED++))
cd - >/dev/null || true
cd - > /dev/null || true
return 1
fi
fi
@@ -478,7 +478,7 @@ update_repo()
log "WARNING" "Skipping repository with unmerged files: $dir"
msg "Skipping repository with unmerged files: $dir"
((UNMERGED++))
cd - >/dev/null || true
cd - > /dev/null || true
return 1
fi
@@ -579,7 +579,7 @@ update_repo()
fi
# Return to original directory
cd - >/dev/null || true
cd - > /dev/null || true
# Show progress after completion
show_progress "$PROCESSED" "$TOTAL" "${dir%/} - Done"

View File

@@ -46,9 +46,25 @@ def test():
assert vercmp("2.4 >= 2.4")
assert vercmp("2.5 >= 2.4")
assert vercmp("3 >= 2.999")
assert vercmp("2.9 < 2.9a")
assert vercmp("2.9a < 2.9")
assert vercmp("2.9a >= 2.8")
# multiple comparisons in a single expression
assert vercmp("1.0 < 2.0 <= 2.0")
assert not vercmp("1.0 > 2.0 < 3.0")
# mixed major/minor version comparisons
assert vercmp("2 >= 1.5")
assert not vercmp("1 < 1.0")
# invalid operator should raise an error
try:
vercmp("1.0 <> 2.0")
except KeyError:
pass
else:
assert False, "invalid operator did not raise"
if __name__ == "__main__":
if len(sys.argv) == 2 and sys.argv[1] == "test":

View File

@@ -1,209 +0,0 @@
#!/usr/bin/env perl
=head1 NAME
dupes - Report on files with duplicate contents, via SHA1 hash.
=cut
=head1 SYNOPSIS
dupes [options] directory
General Options:
--help Show the help information for this script.
--verbose Show useful debugging information.
=cut
=head1 ABOUT
dupes is a simple script to report upon files that are identical,
recursively.
The process involves calculating the SHA1 hash of the file contents
and reporting on anything collisions we see.
Note that a collision might be caused by a symbolic link, or hardlink,
so blindly deleting duplicates without investigation is almost certainly
a mistake.
=cut
=head1 AUTHOR
Steve
--
http://www.steve.org.uk/
=cut
=head1 LICENSE
Copyright (c) 2013 by Steve Kemp. All rights reserved.
This script is free software;you can redistribute it and/or modify it under
the same terms as Perl itself.
The LICENSE file contains the full text of the license.
=cut
use strict;
use warnings;
use File::Find;
use Getopt::Long;
use Pod::Usage;
#
# Parse the arguments
#
my %config = parsedOptions();
#
# The path to examine.
#
my $path = $ARGV[0] || '.';
#
# Get the hashing object, dynamically.
#
my $ctx = getHashObject();
my %digest;
#
# Find files and store the hash of their contents.
#
find( {
'wanted' => sub {
if ( -f $_ )
{
lstat;
if ( ( -r _ ) && ( !-l _ ) )
{
$ctx->reset;
$ctx->addfile($_);
my $md5 = $ctx->hexdigest;
if ( exists $digest{ $md5 } )
{
push @{ $digest{ $md5 }->{ 'dupes' } }, $_;
}
else
{
$digest{ $md5 } = { 'file' => $_,
'dupes' => [] };
}
}
}
else
{
$config{ 'verbose' } && print "Entering $_\n";
}
},
'no_chdir' => 1
},
$path
);
#
# Report upon collisions.
#
foreach my $hash ( keys %digest )
{
my $dupes = $digest{ $hash }->{ 'dupes' };
my $src = $digest{ $hash }->{ 'file' };
if (@$dupes)
{
print $src . "\n";
foreach my $dupe (@$dupes)
{
print "\t$dupe\n";
}
}
}
#
# All done.
#
exit(0);
=begin doc
Load one of M<Digest::SHA> and M<Digest::SHA1>, depending on what is available.
=end doc
=cut
sub getHashObject
{
my $hash = undef;
foreach my $module (qw! Digest::SHA Digest::SHA1 !)
{
# If we succeeded in calculating the hash we're done.
next if ( defined($hash) );
# Attempt to load the module
my $eval = "use $module;";
## no critic (Eval)
eval($eval);
## use critic
if ( !$@ )
{
$hash = $module->new;
}
}
if ($hash)
{
return ($hash);
}
else
{
print "Failed to load either DIgest::SHA or Digest::SHA1\n";
exit(1);
}
}
=begin doc
Parse the options and return suitable values.
=end doc
=cut
sub parsedOptions
{
my %vars;
exit
if (
!GetOptions( "help" => \$vars{ 'help' },
"verbose" => \$vars{ 'verbose' } ) );
pod2usage(1) if ( $vars{ 'help' } );
return (%vars);
}

18
scripts/install-cheat-purebashbible.sh Executable file → Normal file
View File

@@ -47,6 +47,22 @@ prepare_cheat_dest()
echo "$cheat_dest"
}
# Processes chapter files from the pure-bash-bible repository and generates or updates corresponding cheat sheets.
#
# For each chapter file, creates or updates a cheat sheet in the appropriate destination directory, removes chapter end markers, and ensures required metadata is present.
#
# Globals:
# * PBB_TEMP_DIR: Directory containing the cloned pure-bash-bible repository.
# * PBB_SYNTAX, PBB_TAGS, PBB_SOURCE: Metadata strings for cheat sheets.
#
# Outputs:
# * Writes or updates cheat sheet files in the determined cheat sheet directory.
#
# Example:
#
# ```bash
# process_chapters
# ```
process_chapters()
{
local cheat_dest
@@ -59,7 +75,7 @@ process_chapters()
header=$(grep -e '^[#] ' "$f" | head -1 | awk '{print tolower($2)}')
cheat_file="$cheat_dest/$header"
if ! replacable "$f" "$cheat_file"; then
if ! replaceable "$f" "$cheat_file"; then
cp "$f" "$cheat_file" && msg_run "Updated: $cheat_file"
fi