Compare commits

...

61 Commits

Author SHA1 Message Date
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
github-actions[bot]
c457c0f3ab chore: update pre-commit hooks (#105)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-05-01 11:15:18 +03:00
9936e4bd76 chore(config): reorg of mini plugins
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-29 18:08:23 +03:00
c3a45e2653 chore(deps): update Brewfile
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-29 18:08:00 +03:00
506360a027 chore(config): fish: config cleanup, fixes
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-29 18:07:50 +03:00
github-actions[bot]
00074ec3ff chore: update pre-commit hooks (#104) 2025-04-28 18:53:17 +03:00
renovate[bot]
7c7daf89ea feat(github-action): update actions/setup-python (v5.5.0 → v5.6.0)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 21:49:51 +00:00
renovate[bot]
267c54aa56 chore(deps): update node.js to v22.15.0 (#102) 2025-04-24 09:09:01 +03:00
github-actions[bot]
d72409efc0 chore: update pre-commit hooks (#103) 2025-04-24 08:48:35 +03:00
3d9e0477b0 feat(bin): git-attributes rewrite 2025-04-22 10:11:32 +03:00
cfab48eee0 chore(config): zed config mode change 2025-04-22 10:08:12 +03:00
624920b2ab chore(config): nvim, tmux and wezterm tweaks 2025-04-22 10:07:34 +03:00
github-actions[bot]
fd82f1e36c chore: update pre-commit hooks (#101) 2025-04-21 14:23:31 +03:00
dependabot[bot]
48ec8cd7a7 chore(deps): bump http-proxy-middleware (#100) 2025-04-19 13:10:01 +03:00
renovate[bot]
3a61bd2b72 fix(github-action): update softprops/action-gh-release (v2.2.1 → v2.2.2)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-19 04:34:26 +00:00
895b0ad353 chore(config): aqua: remove extra tools
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-19 04:12:58 +03:00
3c733ec7eb chore(config): tmux: tweak theme
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-19 04:12:36 +03:00
5321ad7bd7 feat(config): fish formatting, secrets, op
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-19 04:11:14 +03:00
196077bea9 feat(nvim): reworked lsp, theme, cleanup
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-19 04:04:26 +03:00
github-actions[bot]
75147c7dd6 chore: update pre-commit hooks (#99) 2025-04-17 07:30:06 +03:00
f28ad41f67 chore(bin): remove zalgo-text.swift 2025-04-15 21:05:14 +03:00
61b66d3114 chore: removed yabai bin from repository 2025-04-15 21:00:40 +03:00
282f760a4f chore(lint): shfmt 2025-04-15 21:00:19 +03:00
4a9c9b4cb9 feat(bin): rewrote git-update-dirs 2025-04-15 20:59:50 +03:00
16311ee5b4 feat(bin): rewrote git-fsck-dirs 2025-04-15 15:39:01 +03:00
2fddfa82c0 feat(bin): rewrote git-dirty with additional feats 2025-04-15 14:02:44 +03:00
8f5f44db2d feat(bin): x-gh-get-latest-version improvements 2025-04-14 14:45:20 +03:00
8ad1f5c4d0 chore(docs): bin/README.md tweaks
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-14 10:25:43 +03:00
ac0aa1fbc0 feat(bin): php-switcher for Brew based version changes
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-14 10:25:18 +03:00
e8c6794ff6 chore(repo): ignore yabai from repo
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-14 10:24:20 +03:00
4de9a649f0 chore(config): update zed config
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-14 10:23:50 +03:00
github-actions[bot]
e7f115680e chore: update pre-commit hooks (#98)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-04-14 09:06:55 +03:00
f3b4551d0c chore(config): ideavim config 2025-04-11 16:31:59 +03:00
64725c57dc chore(config): fish config tweaks 2025-04-11 16:31:58 +03:00
b32ee414e3 chore(config): tweak yabai config 2025-04-11 16:31:58 +03:00
renovate[bot]
6ea7807718 fix(container): update image python (3.13.2 → 3.13.3) (#97) 2025-04-10 22:14:50 +03:00
6a776bd3dd chore(config): nvim: cleanup and fixes
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-04 16:34:08 +03:00
6ffe581326 feat(config): use nvm with bass, simplify setup
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-04 16:33:32 +03:00
5d476e8eed chore(config): add tmux-resurrect back
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-04-03 09:39:15 +03:00
github-actions[bot]
bf84c67f08 chore: update pre-commit hooks (#96)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-04-03 07:54:08 +03:00
9cb400dd3f chore(config): docker completions for fish 2025-04-02 18:23:14 +03:00
fce649619a chore(config): remove double init for pyenv 2025-04-02 18:22:59 +03:00
8b0148e468 chore: fish: migrate back to nvm 2025-04-02 18:22:38 +03:00
9cb27eb9dc chore(deps): yarn package update
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-31 21:06:27 +03:00
f1ed88a98e chore(config): vim plug update
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-31 21:05:57 +03:00
ec35f1cb1e chore(config): wezterm font and config tweaks
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-31 21:05:44 +03:00
dab8504cfd chore(deps): Brewfile update
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-31 21:05:09 +03:00
0f9a76e36f chore(config): nvim config tweaks
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-31 21:04:50 +03:00
github-actions[bot]
97244d5287 chore: update pre-commit hooks (#95)
Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
2025-03-31 09:09:46 +03:00
50ea9bea89 fix(config): nvim theme tweaks
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-28 09:47:53 +02:00
688469ad8b chore(config): wezterm font is now Operator Mono
Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
2025-03-28 09:47:21 +02:00
github-actions[bot]
af32914d71 chore: update pre-commit hooks (#94) 2025-03-27 06:44:56 +02:00
renovate[bot]
840bd85232 feat(github-action): update actions/setup-python (v5.4.0 → v5.5.0)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 20:42:22 +00:00
76 changed files with 14412 additions and 3757 deletions

View File

@@ -8,11 +8,14 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.fish]
max_line_length = 80
[*.md]
max_line_length = 100
[*.lua]
max_line_length = 120
max_line_length = 90
[*.{php,fish}]
indent_size = 4

45
.gitattributes vendored
View File

@@ -1,4 +1,4 @@
## GITATTRIBUTES FOR WEB PROJECTS
## GITATTRIBUTES
#
# These settings are for any web project.
#
@@ -20,20 +20,23 @@
*.bat text eol=crlf
*.cmd text eol=crlf
*.coffee text
*.css text diff=css
*.htm text diff=html
*.html text diff=html
*.css text diff=css eol=lf
*.fish text diff=shell eol=lf
*.htm text diff=html eol=lf
*.html text diff=html eol=lf
*.inc text
*.ini text
*.js text
*.json text
*.jsx text
*.less text
*.lua text diff=lua eol=lf
*.ls text
*.map text -diff
*.od text
*.onlydata text
*.php text diff=php
*.plist text eol=lf
*.pl text
*.ps1 text eol=crlf
*.py text diff=python
@@ -41,15 +44,18 @@
*.sass text
*.scm text
*.scss text diff=css
*.sh text eol=lf
*.sh text eol=lf diff=shell
.husky/* text eol=lf
*.sql text
*.styl text
*.tag text
*.tmux text eol=lf diff=tmux
*.ts text
*.tsx text
*.vim text eol=lf
*.xml text
*.xhtml text diff=html
*.zsh text diff=zsh eol=lf
# Docker
Dockerfile text
@@ -68,6 +74,7 @@ Dockerfile text
AUTHORS text
CHANGELOG text
CHANGES text
CODEOWNERS text
CONTRIBUTING text
COPYING text
copyright text
@@ -105,6 +112,8 @@ TODO text
*.config text
.editorconfig text
.env text
*.env text
*.env.* text
.gitattributes text
.gitconfig text
.htaccess text
@@ -208,15 +217,37 @@ Procfile text
*.gitignore text
*.gitkeep text
.gitattributes export-ignore
.gitattributes text export-ignore
*.gitattributes text export-ignore
.gitmodules text export-ignore
*.gitmodules text export-ignore
**/.gitignore export-ignore
**/.gitkeep export-ignore
# Repo specials
local/bin/* text eol=lf
local/bin/* text eol=lf diff=shell
local/bin/*.md text eol=lf diff=markdown
config/antigen.zsh text
git/* text
**/git/* text
**/alias text
ssh/* text
ssh/shared.d/* text
ssh/local.d/* text
# Auto-generated rules - 2025-04-16 10:28:04
# Shell scripts detected by content
install text eol=lf diff=shell
# File extension-based rules
*.1 text eol=lf
*.applescript text eol=lf
*.d/work-git text eol=lf
*.dirs text eol=lf
*.example text eol=lf
*.itermcolors text eol=lf
*.locale text eol=lf
*.python-version text eol=lf
*.snippets text eol=lf
*.theme text eol=lf
*.yamlfmt text eol=lf

View File

@@ -40,7 +40,7 @@ jobs:
- name: Create release
if: steps.daily-version.outputs.created
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ steps.daily-version.outputs.version }}

View File

@@ -25,7 +25,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- run: pip install pre-commit && pre-commit autoupdate

4
.gitignore vendored
View File

@@ -40,8 +40,12 @@ node_modules
ssh/local.d/*
!ssh/local.d/.gitkeep
config/fish/fish_variables
**/exports.secret.fish
**/exports-secret.fish
config/fish/completions/asdf.fish
config/vim/.netrwhist
config/vim/extra/*
config/gh/hosts.yml
dependency-check-report.html
local/bin/yabai
local/man/yabai.1

3
.gitmodules vendored
View File

@@ -80,3 +80,6 @@
shallow = true
ignore = dirty
[submodule "tmux/tmux-resurrect"]
path = config/tmux/plugins/tmux-resurrect
url = https://github.com/tmux-plugins/tmux-resurrect.git

2
.nvmrc
View File

@@ -1 +1 @@
22.14.0
22.15.0

View File

@@ -29,7 +29,7 @@ repos:
args: [-c, .markdownlint.json, --fix]
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.0
rev: v1.37.1
hooks:
- id: yamllint
@@ -49,12 +49,12 @@ repos:
- id: actionlint
- repo: https://github.com/renovatebot/pre-commit-hooks
rev: 39.212.0
rev: 40.10.4
hooks:
- id: renovate-config-validator
- repo: https://github.com/JohnnyMorganz/StyLua
rev: v2.0.2
rev: v2.1.0
hooks:
- id: stylua # or stylua-system / stylua-github

View File

@@ -1 +1 @@
3.13.2
3.13.3

View File

@@ -26,6 +26,8 @@ git submodule add --name tmux/tmux-continuum \
-f https://github.com/tmux-plugins/tmux-continuum config/tmux/plugins/tmux-continuum
git submodule add --name tmux/tmux-mode-indicator \
-f https://github.com/MunifTanjim/tmux-mode-indicator.git config/tmux/plugins/tmux-mode-indicator
git submodule add --name tmux/tmux-resurrect \
-f https://github.com/tmux-plugins/tmux-resurrect.git config/tmux/plugins/tmux-resurrect
git submodule add --name tmux/tmux-sensible \
-f https://github.com/tmux-plugins/tmux-sensible.git config/tmux/plugins/tmux-sensible
git submodule add --name tmux/tmux-sessionist \
@@ -55,7 +57,6 @@ folders=(
"config/tmux/plugins/tpm"
"config/tmux/plugins/tmux"
"config/tmux/plugins/tmux-menus"
"config/tmux/plugins/tmux-resurrect"
"tools/dotbot-crontab"
"tools/dotbot-snap"
"config/nvim-kickstart"

View File

@@ -9,13 +9,7 @@
# - all
registries:
- type: standard
ref: v4.331.0 # renovate: depName=aquaproj/aqua-registry
ref: v4.346.0 # renovate: depName=aquaproj/aqua-registry
packages:
- name: cli/cli
version: 'v2.69.0'
- name: junegunn/fzf
version: 'v0.60.3'
- name: jqlang/jq
version: 'jq-1.7.1'
- name: 1password/cli
version: '2.30.3'

View File

@@ -0,0 +1,235 @@
# fish completion for docker -*- shell-script -*-
function __docker_debug
set -l file "$BASH_COMP_DEBUG_FILE"
if test -n "$file"
echo "$argv" >> $file
end
end
function __docker_perform_completion
__docker_debug "Starting __docker_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))
__docker_debug "args: $args"
__docker_debug "last arg: $lastArg"
# Disable ActiveHelp which is not supported for fish shell
set -l requestComp "DOCKER_ACTIVE_HELP=0 $args[1] __complete $args[2..-1] $lastArg"
__docker_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")
__docker_debug "Comps: $comps"
__docker_debug "DirectiveLine: $directiveLine"
__docker_debug "flagPrefix: $flagPrefix"
for comp in $comps
printf "%s%s\n" "$flagPrefix" "$comp"
end
printf "%s\n" "$directiveLine"
end
# this function limits calls to __docker_perform_completion, by caching the result behind $__docker_perform_completion_once_result
function __docker_perform_completion_once
__docker_debug "Starting __docker_perform_completion_once"
if test -n "$__docker_perform_completion_once_result"
__docker_debug "Seems like a valid result already exists, skipping __docker_perform_completion"
return 0
end
set --global __docker_perform_completion_once_result (__docker_perform_completion)
if test -z "$__docker_perform_completion_once_result"
__docker_debug "No completions, probably due to a failure"
return 1
end
__docker_debug "Performed completions and set __docker_perform_completion_once_result"
return 0
end
# this function is used to clear the $__docker_perform_completion_once_result variable after completions are run
function __docker_clear_perform_completion_once_result
__docker_debug ""
__docker_debug "========= clearing previously set __docker_perform_completion_once_result variable =========="
set --erase __docker_perform_completion_once_result
__docker_debug "Successfully erased the variable __docker_perform_completion_once_result"
end
function __docker_requires_order_preservation
__docker_debug ""
__docker_debug "========= checking if order preservation is required =========="
__docker_perform_completion_once
if test -z "$__docker_perform_completion_once_result"
__docker_debug "Error determining if order preservation is required"
return 1
end
set -l directive (string sub --start 2 $__docker_perform_completion_once_result[-1])
__docker_debug "Directive is: $directive"
set -l shellCompDirectiveKeepOrder 32
set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) % 2)
__docker_debug "Keeporder is: $keeporder"
if test $keeporder -ne 0
__docker_debug "This does require order preservation"
return 0
end
__docker_debug "This doesn't require order preservation"
return 1
end
# This function does two things:
# - Obtain the completions and store them in the global __docker_comp_results
# - Return false if file completion should be performed
function __docker_prepare_completions
__docker_debug ""
__docker_debug "========= starting completion logic =========="
# Start fresh
set --erase __docker_comp_results
__docker_perform_completion_once
__docker_debug "Completion results: $__docker_perform_completion_once_result"
if test -z "$__docker_perform_completion_once_result"
__docker_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 $__docker_perform_completion_once_result[-1])
set --global __docker_comp_results $__docker_perform_completion_once_result[1..-2]
__docker_debug "Completions are: $__docker_comp_results"
__docker_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
__docker_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
__docker_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)
__docker_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)
__docker_debug "prefix: $prefix"
set -l completions (string match -r -- "^$prefix.*" $__docker_comp_results)
set --global __docker_comp_results $completions
__docker_debug "Filtered completions are: $__docker_comp_results"
# Important not to quote the variable for count to work
set -l numComps (count $__docker_comp_results)
__docker_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 $__docker_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.
__docker_debug "Adding second completion to perform nospace directive"
set --global __docker_comp_results $split[1] $split[1].
__docker_debug "Completions are now: $__docker_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
__docker_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 "docker"
# 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 "docker " > /dev/null 2>&1
end
# Remove any pre-existing completions for the program since we will be handling all of them.
complete -c docker -e
# this will get called after the two calls below and clear the $__docker_perform_completion_once_result global
complete -c docker -n '__docker_clear_perform_completion_once_result'
# The call to __docker_prepare_completions will setup __docker_comp_results
# which provides the program's completion choices.
# If this doesn't require order preservation, we don't use the -k flag
complete -c docker -n 'not __docker_requires_order_preservation && __docker_prepare_completions' -f -a '$__docker_comp_results'
# otherwise we use the -k flag
complete -k -c docker -n '__docker_requires_order_preservation && __docker_prepare_completions' -f -a '$__docker_comp_results'

View File

@@ -1,22 +0,0 @@
function ___paths_plugin_set_colors
if not set -q ___paths_plugin_colors
set -Ux ___paths_plugin_colors 27e6ff 29e0ff 5cd8ff 77d0ff 8ac8ff 9cbfff afb5ff c5a7ff d99bfe ea8feb f684d5 fe7abd ff73a3 ff708a fa7070 ff708a ff73a3 fe7abd f684d5 ea8feb d99bfe c5a7ff afb5ff 9cbfff 8ac8ff 77d0ff 5cd8ff 29e0ff
end
return 0
end
function _paths_uninstall --on-event paths_uninstall
for i in ___paths_plugin_wrap_color ___paths_plugin_output ___paths_plugin_handle_found_item ___paths_plugin_handle_source ___paths_plugin_cycle_color
functions -e $i
end
set -e ___paths_plugin_colors
set -e ___paths_plugin_current_color
end
function _paths_install --on-event _paths_install
___paths_plugin_set_colors
end
function _paths_update --on-event paths_update
___paths_plugin_set_colors
end

View File

@@ -8,18 +8,29 @@ test -e "$HOME/.config/fish/alias.fish" &&
test -e "$HOME/.config/fish/exports.fish" &&
source "$HOME/.config/fish/exports.fish"
if status is-interactive
# Commands to run in interactive sessions can go here
test -e "$HOME/.dotfiles/config/fzf/key-bindings.fish" &&
source "$HOME/.dotfiles/config/fzf/key-bindings.fish"
# Start tmux if not already running and not in SSH
open-tmux # defined in functions/open-tmux.fish
if status is-interactive
# Commands to run in interactive shell
# 1Password plugins if op command is available
type -q op; and test -e "$HOME/.config/op/plugins.sh" &&
source "$HOME/.config/op/plugins.sh"
# version manager initializers
type -q rbenv; and source (rbenv init -|psub)
type -q pyenv; and source (pyenv init -|psub)
type -q pyenv; and source (pyenv virtualenv-init -|psub)
type -q goenv; and source (goenv init -|psub)
# type -q fnm; and fnm env --use-on-cd --shell fish | source
type -q load_nvm; and load_nvm > /dev/stderr
# Start tmux if not already running and not in SSH
open-tmux # defined in functions/open-tmux.fish
end
# Added by LM Studio CLI (lms)
set -gx PATH $PATH $HOME/.lmstudio/bin
type -q rbenv; and source (rbenv init -|psub)
type -q pyenv; and source (pyenv init -|psub)
type -q goenv; and source (goenv init -|psub)
type -q fnm; and fnm env --use-on-cd --shell fish | source
# vim: ft=fish ts=4 sw=4 et:

View File

@@ -22,11 +22,6 @@ fish_add_path "$XDG_BIN_HOME"
# Add cargo bin to path
fish_add_path "$XDG_SHARE_HOME/cargo/bin"
# Set Aqua configuration
set -q AQUA_BIN; or set -gx AQUA_BIN "$XDG_DATA_HOME/aquaproj-aqua/bin"
set -q AQUA_CONFIG; or set -gx AQUA_CONFIG "$XDG_CONFIG_HOME/aqua/aqua.yaml"
set -gx PATH $AQUA_BIN $PATH
# NPM/NVM configuration
set -q NVM_DIR; or set -x NVM_DIR "$XDG_DATA_HOME/nvm"
fish_add_path "$NVM_DIR/bin"
@@ -109,7 +104,6 @@ set -q GNUPGHOME; or set -x GNUPGHOME "$XDG_DATA_HOME/gnupg"
# Go configuration
# set -q GOPATH; or set -x GOPATH "$XDG_DATA_HOME/go"
set -q GOBIN; or set -x GOBIN "$XDG_BIN_HOME"
fish_add_path "$GOBIN"
set -q GOENV_ROOT; or set -x GOENV_ROOT "$XDG_DATA_HOME/goenv"
set -q GOENV_RC_FILE; or set -x GOENV_RC_FILE "$XDG_CONFIG_HOME/goenv/goenvrc.fish"
@@ -121,9 +115,6 @@ set -q OP_CACHE; or set -x OP_CACHE "$XDG_STATE_HOME/1password"
set -q WORKON_HOME; or set -x WORKON_HOME "$XDG_DATA_HOME/virtualenvs"
set -q PYENV_ROOT; or set -x PYENV_ROOT "$XDG_DATA_HOME/pyenv"
fish_add_path "$PYENV_ROOT/bin"
if x-have pyenv; and not functions -q pyenv
status --is-interactive; and source (pyenv init - | psub)
end
# Poetry configuration
set -q POETRY_HOME; or set -x POETRY_HOME "$XDG_DATA_HOME/poetry"
@@ -134,7 +125,6 @@ set -q CARGO_HOME; or set -x CARGO_HOME "$XDG_DATA_HOME/cargo"
set -q CARGO_BIN_HOME; or set -x CARGO_BIN_HOME "$XDG_BIN_HOME"
set -q RUSTUP_HOME; or set -x RUSTUP_HOME "$XDG_DATA_HOME/rustup"
set -x RUST_WITHOUT "clippy,docs,rls"
fish_add_path "$CARGO_BIN_HOME"
fish_add_path "$CARGO_HOME/bin"
fish_add_path "$XDG_SHARE_HOME/bob/nvim-bin"

View File

@@ -2,7 +2,6 @@ jorgebucaran/fisher
ilancosman/tide@v6
jethrokuan/z
halostatue/fish-macos@v7
jgusta/paths
danhper/fish-ssh-agent
halostatue/fish-brew@v3
edc/bass

View File

@@ -0,0 +1,16 @@
function load_nvm --on-variable="PWD"
set -l default_node_version (nvm version default)
set -l node_version (nvm version)
set -l nvmrc_path (nvm_find_nvmrc)
if test -n "$nvmrc_path"
set -l nvmrc_node_version (nvm version (cat $nvmrc_path))
if test "$nvmrc_node_version" = "N/A"
nvm install (cat $nvmrc_path)
else if test "$nvmrc_node_version" != "$node_version"
nvm use $nvmrc_node_version
end
else if test "$node_version" != "$default_node_version"
echo "Reverting to default Node version"
nvm use default
end
end

View File

@@ -0,0 +1,4 @@
function nvm
bass source $NVM_DIR/nvm.sh --no-use ';' nvm $argv
end

View File

@@ -0,0 +1,3 @@
function nvm_find_nvmrc
bass source $NVM_DIR/nvm.sh --no-use ';' nvm_find_nvmrc
end

View File

@@ -1,175 +0,0 @@
function ___paths_plugin_wrap_color
set_color normal
set_color "$argv[1]"
echo -n (set_color "$argv[1]")"$argv[2..]"
set_color normal
end
# duplicated in conf.d
function ___paths_plugin_set_colors
if not set -q ___paths_plugin_colors
set -Ux ___paths_plugin_colors 27e6ff 29e0ff 5cd8ff 77d0ff 8ac8ff 9cbfff afb5ff c5a7ff d99bfe ea8feb f684d5 fe7abd ff73a3 ff708a fa7070 ff708a ff73a3 fe7abd f684d5 ea8feb d99bfe c5a7ff afb5ff 9cbfff 8ac8ff 77d0ff 5cd8ff 29e0ff
end
return 0
end
function ___paths_plugin_cycle_color
if not set -q ___paths_plugin_current_color
set -Ux ___paths_plugin_current_color 1
else if test $___paths_plugin_current_color -gt (count $___paths_plugin_colors)
set -Ux ___paths_plugin_current_color 1
end
echo $___paths_plugin_colors[$___paths_plugin_current_color]
set -Ux ___paths_plugin_current_color (math $___paths_plugin_current_color + 1)
end
function ___paths_plugin_handle_found_item -a testName outFlags
set -f flags (string split -n ' ' -- "$outFlags")
set -f options (fish_opt -s c -l clean)
set -a options (fish_opt -s s -l single)
set -a options (fish_opt -s k -l no-color)
set -a options (fish_opt -s n -l inline)
argparse $options -- $flags
set -f arrow "=>"
# check if file exists
if test -e "$testName"
set -f nameOut (string trim -- "$testName")
if not set -q _flag_c # is not clean
if test -L "$testName" # is symlink
set -f __linkname (readlink -f "$testName")
set __linkname (string trim -- "$__linkname")
set testName (string trim -- "$testName")
if not set -q _flag_k # is color
set nameOut (___paths_plugin_wrap_color (___paths_plugin_cycle_color) $testName) (___paths_plugin_wrap_color "yellow" "$arrow") (___paths_plugin_wrap_color (___paths_plugin_cycle_color) $__linkname)
else # is color
set nameOut (echo -n "$testName" "$arrow" "$__linkname")
end
else # is not symlink
if not set -q _flag_k # is color
set testName (string trim -- "$testName")
set nameOut (___paths_plugin_wrap_color (___paths_plugin_cycle_color) "$testName")
else
set testName (string trim -- "$testName")
set nameOut "$testName"
end
end
set nameOut (string trim -- "$nameOut")
# do the tick
if set -q _flag_k # is not color
set nameOut "- $nameOut"
else # is color
set nameOut (___paths_plugin_wrap_color "yellow" "-") "$nameOut"
end
end
set nameOut (string trim -- "$nameOut")
echo -n $nameOut
end
end
function paths --description "Reveal the executable matches in shell paths or fish autoload."
set -f options (fish_opt -s c -l clean)
set -a options (fish_opt -s s -l single)
set -a options (fish_opt -s k -l no-color)
set -a options (fish_opt -s q -l quiet)
set -a options (fish_opt -s n -l inline)
argparse $options -- $argv
if test (count $argv) -lt 1
echo "paths - executable matches in shell paths or fish autoload."
and echo "usage: paths [-c|-s|-k] <name>"
and echo -e "\t-c or --no-color: output without color"
and echo -e "\t-s or --single: output without color or headers, the first result"
and echo -e "\t-k or --clean: output without tick marks or headers"
# and echo -e "\t-n or --inline: output without endline"
and return 1
end
set -f foundStatus 1
set -f input (string trim -- $argv)
# deprecated
if set -q _flag_q
set _flag_c True
end
if set -q _flag_s
set _flag_k True
set _flag_c True
end
set -f outFlags ''
set -q _flag_n; and set -a outFlags -n
set -q _flag_c; and set -a outFlags -c
set -q _flag_k; and set -a outFlags -k
set -q _flag_s; and set -a outFlags -s
set outFlags (string split -n " " -- "$outFlags")
___paths_plugin_set_colors
# loop over list of path lists
for pVar in VIRTUAL_ENV fisher_path fish_function_path fish_user_paths PATH
set -e acc
set -f acc ''
set -e hit
# see if variable is empty
if test -z "$pVar"
continue
end
set -f acc (begin
for t in $$pVar
for snit in "$t/$input.fish" "$t/$input"
set -f found (___paths_plugin_handle_found_item "$snit" "$outFlags")
set found (string trim -- "$found")
if test -n "$found"
set -f hit True
echo "$found"
if set -q _flag_s
break
end
end
end
if set -q _flag_s
if set -q hit
break
end
end
end
end)
# prepend source
if not set -q _flag_c
if set -q hit
set pVar (string trim -- "$pVar")
echo -e -n "$pVar\n"
end
end
if test -n "$acc"
set foundStatus 0
for fk in $acc
echo $fk
if set -q _flag_s
# stop after one
return $foundStatus
end
end
end
end
# check
set -l built (type --type $input 12&>/dev/null)
if test -n "$built"
and test "$built" = 'builtin'
set $foundStatus 0
if not set -q _flag_c
echo -e -n "builtin\n"
if set -q _flag_k
echo - "$input"
else # is color
echo (___paths_plugin_wrap_color "yellow" "-") (___paths_plugin_wrap_color (___paths_plugin_cycle_color) "$input")
end
else
echo "$input"
end
end
return $foundStatus
end

View File

@@ -89,6 +89,8 @@ brew "coreutils"
brew "bats-core"
# Parser generator
brew "bison"
# Freely available high-quality data compressor
brew "bzip2"
# Software library to render fonts
brew "freetype"
# XML-based font configuration API for X Windows
@@ -107,6 +109,10 @@ brew "choose-rust"
brew "cmake"
# Get a file from an HTTP, HTTPS or FTP server
brew "curl"
# OpenType text shaping engine
brew "harfbuzz"
# OWASP dependency-check
brew "dependency-check"
# Lightweight DNS forwarder and DHCP server
brew "dnsmasq"
# .NET Core
@@ -121,8 +127,6 @@ brew "figlet"
brew "fish"
# Lock file during command
brew "flock"
# Fast and simple Node.js version manager
brew "fnm"
# Libraries to talk to Microsoft SQL Server and Sybase databases
brew "freetds"
# Monitor a directory for changes and run a shell command
@@ -135,8 +139,6 @@ brew "gd"
brew "gdu"
# GitHub command-line tool
brew "gh"
# OpenType text shaping engine
brew "harfbuzz"
# Secure hashing function
brew "libb2"
# Framework for layout and rendering of i18n text
@@ -193,6 +195,8 @@ brew "jq"
brew "json-c"
# Network authentication protocol
brew "krb5"
# Style and grammar checker
brew "languagetool"
# Tool to detect/remediate misconfig and security risks of GitHub/GitLab assets
brew "legitify"
# BSD-style licensed readline alternative
@@ -220,7 +224,7 @@ brew "nginx"
# Port scanning utility for large networks
brew "nmap"
# Platform built on V8 to build network applications
brew "node"
brew "node", link: false
# Libraries for security-enabled client and server applications
brew "nss"
# Command-line Git information tool
@@ -230,6 +234,8 @@ brew "openldap"
# ISO-C API and CLI for generating UUIDs
brew "ossp-uuid"
# General-purpose scripting language
brew "php", link: false
# General-purpose scripting language
brew "php@8.2", link: true
# General-purpose scripting language
brew "php@8.3"
@@ -255,6 +261,8 @@ brew "re2c"
brew "rustup"
# Static analysis and lint tool, for (ba)sh scripts
brew "shellcheck"
# User interface to the TELNET protocol
brew "telnet"
# Send macOS User Notifications from the command-line
brew "terminal-notifier"
# Tool which checks for the support of TLS/SSL ciphers and flaws
@@ -313,8 +321,6 @@ brew "shivammathur/php/php-debug"
brew "shivammathur/php/php@8.2-debug"
# Command-line interface for 1Password
cask "1password-cli"
# AeroSpace is an i3-like tiling window manager for macOS
cask "aerospace"
# Universal database tool and SQL client
cask "dbeaver-community"
# Database version management tool

View File

@@ -1,5 +1,5 @@
"" Source your .vimrc
source ~/.dotfiles/config/vim/vimrc
source $HOME/.dotfiles/config/vim/vimrc
" https://github.com/ville6000/dotfiles/blob/main/vimrc
" To get a list of Actions run `:actionlist `

View File

@@ -1,7 +1,7 @@
# EditorConfig is awesome: https://editorconfig.org
# top-most EditorConfig file
root = true
root = false
[*]
end_of_line = lf
@@ -18,3 +18,7 @@ trim_trailing_whitespace = false
[*.json]
max_line_length = off
[*.lua]
max_line_length = 90

View File

@@ -1,4 +1,4 @@
column_width = 80
column_width = 90
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2

View File

@@ -0,0 +1,2 @@
autocmd BufRead,BufNewFile *.env set ft=env
autocmd BufRead,BufNewFile *.env.* set ft=env

View File

@@ -28,10 +28,7 @@ end
vim.opt.rtp:prepend(lazypath)
-- ── Add ~/.local/bin to the PATH ────────────────────────────────────
vim.fn.setenv(
'PATH',
vim.fn.expand '$HOME/.local/bin' .. ':' .. vim.fn.expand '$PATH'
)
vim.fn.setenv('PATH', vim.fn.expand '$HOME/.local/bin' .. ':' .. vim.fn.expand '$PATH')
require 'options'
require 'autogroups'
@@ -68,4 +65,4 @@ require('lazy').setup(
require 'keymaps'
-- vim: ts=2 sts=2 sw=2 et
-- vim: set ts=2 sts=2 sw=2 wrap et :

View File

@@ -21,9 +21,7 @@ autocmd({ 'BufEnter', 'BufWinEnter', 'TabEnter' }, {
callback = function()
local max_line_count = vim.fn.line '$'
-- Only adjust if the file is large enough to matter
if max_line_count > 99 then
vim.opt.numberwidth = #tostring(max_line_count) + 1
end
if max_line_count > 99 then vim.opt.numberwidth = #tostring(max_line_count) + 1 end
end,
})
@@ -104,5 +102,3 @@ autocmd({ 'BufRead', 'BufNewFile' }, {
},
command = 'set filetype=sshconfig',
})
-- vim: ts=2 sts=2 sw=2 et

View File

@@ -1,5 +1,3 @@
-- vim: set ft=lua ts=2 sw=2 tw=0 et cc=130 :
require 'utils'
-- ╭─────────────────────────────────────────────────────────╮
@@ -20,16 +18,8 @@ K.n('<C-w>+', ':resize +10<CR>', { desc = 'H Resize +' })
K.n('<C-w>=', '<C-w>=', { desc = 'Equal Size Splits' })
-- ── Deal with word wrap ─────────────────────────────────────────────
K.n(
'k',
"v:count == 0 ? 'gk' : 'k'",
{ desc = 'Move up', noremap = true, expr = true }
)
K.n(
'j',
"v:count == 0 ? 'gj' : 'j'",
{ desc = 'Move down', noremap = true, expr = true }
)
K.n('k', "v:count == 0 ? 'gk' : 'k'", { desc = 'Move up', noremap = true, expr = true })
K.n('j', "v:count == 0 ? 'gj' : 'j'", { desc = 'Move down', noremap = true, expr = true })
-- ── Text manipulation ───────────────────────────────────────────────
K.d('<', { 'n', 'v' }, '<gv', 'Indent Left')
@@ -111,12 +101,10 @@ K.nl('cbt', '<Cmd>CBllline<CR>', 'CB: Titled Line')
-- unless it's a generic operation like searching or finding buffers
local fuzzy_search = function()
require('telescope.builtin').find_files(
require('telescope.themes').get_dropdown {
winblend = 20,
previewer = true,
}
)
require('telescope.builtin').find_files(require('telescope.themes').get_dropdown {
winblend = 20,
previewer = true,
})
end
local lazy_plugins = function()
@@ -159,9 +147,7 @@ K.nl('tn', ':Noice dismiss<cr>', 'Noice: Dismiss Notification')
-- Convention is 'q' followed by the operation
K.nl('qf', ':q<CR>', 'Quicker close split')
K.nl('qq', function()
if vim.fn.confirm('Force save and quit?', '&Yes\n&No', 2) == 1 then
vim.cmd 'wq!'
end
if vim.fn.confirm('Force save and quit?', '&Yes\n&No', 2) == 1 then vim.cmd 'wq!' end
end, 'Quit with force saving')
K.nl('qw', ':wq<CR>', 'Write and quit')
K.nl('qQ', function()

View File

@@ -77,10 +77,8 @@ function M.setup(opts)
-- Set vim.g.node_host_prog and vim.g.copilot_node_command
local current_nvm_version_path =
string.format('%s/versions/node/%s', nvm_path, node_version)
local current_nvm_node_bin_path =
string.format('%s/bin', current_nvm_version_path)
local current_nvm_node_bin =
string.format('%s/node', current_nvm_node_bin_path)
local current_nvm_node_bin_path = string.format('%s/bin', current_nvm_version_path)
local current_nvm_node_bin = string.format('%s/node', current_nvm_node_bin_path)
local neovim_node_host_bin_path =
string.format('%s/neovim-node-host', current_nvm_node_bin_path)

View File

@@ -26,6 +26,7 @@ g.loaded_java_provider = 0 -- Disable java provider
-- Most of the good defaults are provided by `mini.basics`
-- See: lua/plugins/mini.lua
o.confirm = true -- Confirm before closing unsaved buffers
o.dictionary = '/usr/share/dict/words' -- Add system dictionary
o.ignorecase = true -- Ignore case in search patterns
o.inccommand = 'split' -- Preview substitutions live, as you type!
o.list = true -- Show invisible characters
@@ -37,7 +38,7 @@ o.scrolloff = 8 -- Show context around cursor
o.sidescrolloff = 8 -- Show context around cursor
o.signcolumn = 'yes' -- Keep signcolumn on by default
o.spell = true -- Enable spell checking
o.spelllang = 'en_us' -- Set the spell checking language
o.spelllang = 'en_gb,en_us' -- Set the spell checking language
o.splitbelow = true -- split to the bottom
o.splitright = true -- vsplit to the right
o.termguicolors = true -- Enable GUI colors
@@ -63,4 +64,7 @@ vim.schedule(function()
o.clipboard = c
end)
-- xiyaowong/transparent.nvim
vim.g.transparent_enabled = true
-- vim: ts=2 sts=2 sw=2 et

View File

@@ -3,7 +3,7 @@ return {
-- https:/github.com/saghen/blink.cmp
{
'saghen/blink.cmp',
version = '*',
version = '1.*',
lazy = false, -- lazy loading handled internally
dependencies = {
-- Compatibility layer for using nvim-cmp sources on blink.cmp
@@ -58,10 +58,10 @@ return {
-- 'default' for mappings similar to built-in completion
-- 'super-tab' for mappings similar to vscode (tab to accept, arrow keys to navigate)
-- 'enter' for mappings similar to 'super-tab' but with 'enter' to accept
-- see the "default configuration" section below for full documentation on how to define
-- your own keymap.
-- see the "default configuration" section below for full documentation on how to
-- define your own keymap.
keymap = {
preset = 'super-tab',
preset = 'default',
-- Use Ctrl-x to trigger auto completion
['<C-x>'] = { 'show', 'show_documentation', 'hide_documentation' },
},
@@ -86,7 +86,8 @@ return {
},
},
documentation = {
auto_show = true,
auto_show = false,
auto_show_delay_ms = 500,
},
ghost_text = {
enabled = false,
@@ -97,12 +98,12 @@ return {
-- elsewhere in your config, without redefining it, via `opts_extend`
sources = {
default = {
'lazydev',
'lsp',
'snippets',
'copilot',
'path',
'snippets',
'buffer',
'lazydev',
},
providers = {
copilot = {
@@ -118,6 +119,15 @@ return {
},
},
-- Blink.cmp includes an optional, recommended rust fuzzy matcher,
-- which automatically downloads a prebuilt binary when enabled.
--
-- By default, we use the Lua implementation instead, but you may enable
-- the rust implementation via `'prefer_rust_with_warning'`
--
-- See :h blink-cmp-config-fuzzy for more information
fuzzy = { implementation = 'lua' },
-- experimental signature help support
signature = { enabled = true },
},

View File

@@ -1,17 +1,9 @@
return {
-- A better annotation generator.
-- Supports multiple languages and annotation conventions.
-- https://github.com/danymat/neogen
{
'danymat/neogen',
version = '*',
opts = { enabled = true, snippet_engine = 'luasnip' },
},
-- Terminal manager for (neo)vim
-- https://github.com/voldikss/vim-floaterm
{
'voldikss/vim-floaterm',
lazy = true,
cmd = { 'FloatermToggle' },
init = function()
vim.g.floaterm_width = 0.8
@@ -49,34 +41,6 @@ return {
end,
},
-- Cloak allows you to overlay *'s over defined patterns in defined files.
-- https://github.com/laytan/cloak.nvim
{
'laytan/cloak.nvim',
version = '*',
opts = {
enabled = true,
cloak_character = '*',
-- The applied highlight group (colors) on the cloaking, see `:h highlight`.
highlight_group = 'Comment',
patterns = {
{
-- Match any file starting with ".env".
-- This can be a table to match multiple file patterns.
file_pattern = {
'.env*',
'wrangler.toml',
'.dev.vars',
},
-- Match an equals sign and any character after it.
-- This can also be a table of patterns to cloak,
-- example: cloak_pattern = { ":.+", "-.+" } for yaml files.
cloak_pattern = '=.+',
},
},
},
},
-- projectionist.vim: Granular project configuration
-- https://github.com/tpope/vim-projectionist
{
@@ -150,21 +114,7 @@ return {
{
'whatyouhide/vim-textobj-xmlattr',
dependencies = { 'kana/vim-textobj-user' },
},
-- Describe the regexp under the cursor
-- https://github.com/bennypowers/nvim-regexplainer
{
'bennypowers/nvim-regexplainer',
event = 'BufEnter',
dependencies = {
'nvim-treesitter/nvim-treesitter',
'MunifTanjim/nui.nvim',
},
opts = {
-- automatically show the explainer when the cursor enters a regexp
auto = true,
},
ft = { 'html', 'xml', 'javascriptreact', 'typescriptreact', 'vue' },
},
-- Clarify and beautify your comments using boxes and lines.
@@ -174,38 +124,4 @@ return {
event = 'BufEnter',
opts = {},
},
-- Plugin to improve viewing Markdown files in Neovim
-- https://github.com/MeanderingProgrammer/render-markdown.nvim
{
'MeanderingProgrammer/render-markdown.nvim',
event = 'BufEnter',
dependencies = {
'nvim-treesitter/nvim-treesitter',
'nvim-tree/nvim-web-devicons',
},
ft = 'markdown',
opts = {},
},
{
'ray-x/go.nvim',
dependencies = { -- optional packages
'ray-x/guihua.lua',
'neovim/nvim-lspconfig',
'nvim-treesitter/nvim-treesitter',
},
config = function() require('go').setup() end,
event = { 'CmdlineEnter' },
ft = { 'go', 'gomod' },
build = ':lua require("go.install").update_all_sync()', -- if you need to install/update all binaries
},
-- Mainly a PHP Language Server with more features than you can shake a stick at
-- https://github.com/phpactor/phpactor
{
'phpactor/phpactor',
build = 'composer install --no-dev --optimize-autoloader',
ft = 'php',
},
}

View File

@@ -0,0 +1,66 @@
return {
{
'stevearc/conform.nvim',
event = 'BufWritePre',
config = function()
local conform = require 'conform'
conform.setup {
formatters_by_ft = {
lua = { 'stylua' },
},
format_on_save = function(bufnr)
-- Disable autoformat for files in a certain paths
local bufname = vim.api.nvim_buf_get_name(bufnr)
if bufname:match '/dist|node_modules|vendor/' then return end
local disable_lsp = {
c = true,
cpp = true,
}
return {
lsp_fallback = not disable_lsp[vim.bo[bufnr].filetype],
timeout_ms = 500,
}
end,
notify_on_error = true,
}
vim.o.formatexpr = "v:lua.require'conform'.formatexpr()"
-- Autoformat toggle keybinding
local autoformat = true
vim.g.autoformat_enabled = autoformat
vim.api.nvim_create_user_command('ToggleFormat', function()
autoformat = not autoformat
vim.g.autoformat_enabled = autoformat
vim.notify('Autoformat on save: ' .. (autoformat and 'enabled' or 'disabled'))
end, {})
vim.keymap.set(
'n',
'<leader>tf',
':ToggleFormat<CR>',
{ desc = 'Toggle autoformat on save' }
)
vim.api.nvim_create_autocmd('BufWritePre', {
callback = function(args)
if autoformat then
conform.format {
bufnr = args.buf,
async = true,
lsp_format = 'fallback',
}
end
end,
})
-- Global statusline helper function
function _G.autoformat_status()
return vim.g.autoformat_enabled and '[ fmt:on]' or '[ fmt:off]'
end
end,
},
}

View File

@@ -2,11 +2,18 @@ return {
-- A collection of small QoL plugins for Neovim
-- https://github.com/folke/snacks.nvim
{
---@module 'snacks'
'folke/snacks.nvim',
priority = 1000,
lazy = false,
---@type snacks.Config
opts = {
bigfile = { enabled = true },
input = { enabled = true },
notifier = {
enabled = true,
timeout = 3000,
},
gitbrowse = { enabled = true },
quickfile = { enabled = true },
statuscolumn = {
@@ -15,7 +22,7 @@ return {
right = { 'fold', 'git' }, -- priority of signs on the right (high to low)
folds = {
open = true, -- show open fold icons
git_hl = false, -- use Git Signs hl for fold icons
git_hl = true, -- use Git Signs hl for fold icons
},
git = {
-- patterns to match Git signs
@@ -36,8 +43,14 @@ return {
-- replaces the UI for messages, cmdline and the popupmenu.
-- https://github.com/folke/noice.nvim
{
---@module 'noice'
'folke/noice.nvim',
event = 'VeryLazy',
dependencies = {
-- if you lazy-load any plugin below, make sure to add proper `module="..."` entries
'MunifTanjim/nui.nvim',
'rcarriga/nvim-notify',
},
opts = {
lsp = {
-- override markdown rendering so that **cmp** and other plugins use **Treesitter**
@@ -60,7 +73,10 @@ return {
filter = {
event = 'msg_show',
kind = '',
find = 'written',
any = {
{ find = 'written' },
{ find = '%d of %d --%d%--' },
},
},
opts = { skip = true },
},
@@ -101,14 +117,6 @@ return {
},
},
},
dependencies = {
-- if you lazy-load any plugin below, make sure to add proper `module="..."` entries
'MunifTanjim/nui.nvim',
-- OPTIONAL:
-- `nvim-notify` is only needed, if you want to use the notification view.
-- If not available, we use `mini` as the fallback
'rcarriga/nvim-notify',
},
},
-- A pretty diagnostics, references, telescope results,
@@ -116,10 +124,12 @@ return {
-- trouble your code is causing.
-- https://github.com/folke/trouble.nvim
{
---@module 'trouble'
'folke/trouble.nvim',
lazy = false,
cmd = 'Trouble',
dependencies = { 'nvim-tree/nvim-web-devicons' },
---@type trouble.Config
opts = {
auto_preview = true,
auto_fold = true,
@@ -131,7 +141,7 @@ return {
},
modes = {
diagnostics = {
auto_open = true,
auto_open = false,
},
test = {
mode = 'diagnostics',
@@ -139,7 +149,7 @@ return {
type = 'split',
relative = 'win',
position = 'right',
size = 0.3,
size = 0.25,
},
},
cascade = {
@@ -158,13 +168,4 @@ return {
},
},
},
-- Navigate your code with search labels, enhanced
-- character motions and Treesitter integration
-- https://github.com/folke/flash.nvim
{
'folke/flash.nvim',
event = 'VeryLazy',
opts = {},
},
}

View File

@@ -4,351 +4,296 @@
require 'utils'
-- LSP Servers are installed and configured by lsp-setup.nvim
-- Mason formatters Conform uses to format files
-- These are automatically configured by zapling/mason-conform.nvim
local lsp_servers = {
bashls = {},
-- csharp_ls = {},
diagnosticls = {},
gopls = {
settings = {
gopls = {
hints = {
rangeVariableTypes = true,
parameterNames = true,
constantValues = true,
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
functionTypeParameters = true,
},
},
},
},
html = {},
intelephense = {
init_options = {
licenceKey = GetIntelephenseLicense(),
},
},
jsonls = {},
lua_ls = {
settings = {
Lua = {
completion = {
callSnippet = 'Replace',
},
diagnostics = {
globals = {
'vim',
},
disable = {
-- Ignore lua_ls noisy `missing-fields` warnings
'missing-fields',
},
},
hint = {
enable = true,
arrayIndex = 'Auto',
await = true,
paramName = 'All',
paramType = true,
semicolon = 'SameLine',
setType = false,
},
},
},
},
tailwindcss = {},
ts_ls = {
settings = {
typescript = {
inlayHints = {
includeInlayParameterNameHints = 'all',
includeInlayParameterNameHintsWhenArgumentMatchesName = false,
includeInlayFunctionParameterTypeHints = true,
includeInlayVariableTypeHints = true,
includeInlayVariableTypeHintsWhenTypeMatchesName = false,
includeInlayPropertyDeclarationTypeHints = true,
includeInlayFunctionLikeReturnTypeHints = true,
includeInlayEnumMemberValueHints = true,
},
},
},
},
vimls = {},
volar = {
settings = {
typescript = {
inlayHints = {
enumMemberValues = {
enabled = true,
},
functionLikeReturnTypes = {
enabled = true,
},
propertyDeclarationTypes = {
enabled = true,
},
parameterTypes = {
enabled = true,
suppressWhenArgumentMatchesName = true,
},
variableTypes = {
enabled = true,
},
},
},
},
},
}
-- Mason tools to automatically install and configure.
-- These are automatically configured by WhoIsSethDaniel/mason-tool-installer.nvim
local mason_tools = {
'actionlint',
'editorconfig-checker',
'goimports',
'gotests',
'phpcbf',
'phpmd',
'phpstan',
'pint',
'prettierd',
'semgrep',
'shellcheck',
'shfmt',
'staticcheck',
'stylua',
'trivy',
'vint',
'yamlfmt',
}
return {
-- `lazydev` configures Lua LSP for your Neovim config, runtime and plugins
-- used for completion, annotations and signatures of Neovim apis
-- https://github.com/folke/lazydev.nvim
{
'folke/lazydev.nvim',
ft = 'lua',
opts = {
library = {
-- Load luvit types when the `vim.uv` word is found
{ path = 'luvit-meta/library', words = { 'vim%.uv' } },
-- load assert and describe paths
{ path = 'luassert/library', words = { 'assert' } },
{ path = 'busted/library', words = { 'describe' } },
},
'neovim/nvim-lspconfig',
dependencies = {
{ 'williamboman/mason.nvim', opts = {} },
'williamboman/mason-lspconfig.nvim',
'WhoIsSethDaniel/mason-tool-installer.nvim',
'folke/lazydev.nvim',
'zapling/mason-conform.nvim',
-- Allows extra capabilities provided by blink.cmp
'saghen/blink.cmp',
},
},
config = function()
local lazydev = require 'lazydev'
-- Meta type definitions for the Lua platform Luvit.
-- https://github.com/Bilal2453/luvit-meta
{ 'Bilal2453/luvit-meta', lazy = true },
-- Quickstart configs for Nvim LSP
-- https://github.com/neovim/nvim-lspconfig
{ 'neovim/nvim-lspconfig' },
-- Portable package manager for Neovim that runs everywhere Neovim runs.
-- Easily install and manage LSP servers, DAP servers, linters, and formatters.
-- https://github.com/williamboman/mason.nvim
{
'williamboman/mason.nvim',
version = '*',
cmd = 'Mason',
run = ':MasonUpdate',
opts = {},
},
-- Extensible UI for Neovim notifications and LSP progress messages.
-- https://github.com/j-hui/fidget.nvim
{
'j-hui/fidget.nvim',
version = '*',
opts = {},
},
-- Extension to mason.nvim that makes it easier to use lspconfig with mason.nvim.
-- https://github.com/williamboman/mason-lspconfig.nvim
{ 'williamboman/mason-lspconfig.nvim' },
-- Install and upgrade third party tools automatically
-- https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim
{
'WhoIsSethDaniel/mason-tool-installer.nvim',
version = '*',
opts = {
auto_install = true,
auto_update = true,
ensure_installed = mason_tools,
},
},
-- JSON schemas for Neovim
-- https://github.com/b0o/SchemaStore.nvim
{ 'b0o/schemastore.nvim' },
-- Performant, batteries-included completion plugin for Neovim
-- https://github.com/saghen/blink.cmp
-- See lua/plugins/blink.lua for configs
{ 'saghen/blink.cmp' },
-- A simple wrapper for nvim-lspconfig and mason-lspconfig
-- to easily setup LSP servers.
-- https://github.com/junnplus/lsp-setup.nvim
{
'junnplus/lsp-setup.nvim',
opts = {
default_mappings = false,
servers = lsp_servers,
},
config = function(_, opts)
require('lazydev').setup()
require('lsp-setup').setup(opts)
local cmp = require 'blink.cmp'
local lspconfig = require 'lspconfig'
for server, config in pairs(opts.servers) do
-- passing config.capabilities to blink.cmp merges with the capabilities in your
-- `opts[server].capabilities, if you've defined it
config.capabilities = cmp.get_lsp_capabilities(config.capabilities)
lspconfig[server].setup(config)
end
lspconfig.lua_ls.on_init = function(client)
if client.workspace_folders then
local path = client.workspace_folders[1].name
if
vim.loop.fs_stat(path .. '/.luarc.json')
or vim.loop.fs_stat(path .. '/.luarc.jsonc')
then
return
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('lsp-attach', { clear = true }),
callback = function(event)
local map = function(keys, func, desc, mode)
mode = mode or 'n'
vim.keymap.set(
mode,
keys,
func,
{ buffer = event.buf, desc = 'LSP: ' .. desc }
)
end
end
client.config.settings.Lua =
vim.tbl_deep_extend('force', client.config.settings.Lua, {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT',
},
-- Make the server aware of Neovim runtime files
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME,
local tsb = require 'telescope.builtin'
-- Rename the variable under your cursor.
-- Most Language Servers support renaming across files, etc.
map('grn', vim.lsp.buf.rename, '[R]e[n]ame')
-- Execute a code action, usually your cursor needs to be on top of an error
-- or a suggestion from your LSP for this to activate.
map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' })
-- Find references for the word under your cursor.
map('grr', tsb.lsp_references, '[G]oto [R]eferences')
-- Jump to the implementation of the word under your cursor.
-- Useful when your language has ways of declaring types without
-- an actual implementation.
map('gri', tsb.lsp_implementations, '[G]oto [I]mplementation')
-- Jump to the definition of the word under your cursor.
-- This is where a variable was first declared, or where a function is
-- defined, etc. To jump back, press <C-t>.
map('grd', tsb.lsp_definitions, '[G]oto [D]efinition')
-- WARN: This is not Goto Definition, this is Goto Declaration.
-- For example, in C this would take you to the header.
map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
-- Fuzzy find all the symbols in your current document.
-- Symbols are things like variables, functions, types, etc.
map('gO', tsb.lsp_document_symbols, 'Open Document Symbols')
-- Fuzzy find all the symbols in your current workspace.
-- Similar to document symbols, except searches over your entire project.
map('gW', tsb.lsp_dynamic_workspace_symbols, 'Open Workspace Symbols')
-- Jump to the type of the word under your cursor.
-- Useful when you're not sure what type a variable is and you want to see
-- the definition of its *type*, not where it was *defined*.
map('grt', tsb.lsp_type_definitions, '[G]oto [T]ype Definition')
-- This function resolves a difference between neovim nightly
-- (version 0.11) and stable (version 0.10)
---@param client vim.lsp.Client
---@param method vim.lsp.protocol.Method
---@param bufnr? integer some lsp support methods only in specific files
---@return boolean
local function client_supports_method(client, method, bufnr)
if vim.fn.has 'nvim-0.11' == 1 then
return client:supports_method(method, bufnr)
else
---@diagnostic disable-next-line: param-type-mismatch
return client.supports_method(method, { bufnr = bufnr })
end
end
-- The following two autocommands are used to highlight references of the
-- word under your cursor when your cursor rests there for a little while.
-- See `:help CursorHold` for information about when this is executed
--
-- When you move your cursor, the highlights will be cleared
-- (the second autocommand).
local client = vim.lsp.get_client_by_id(event.data.client_id)
if
client
and client_supports_method(
client,
vim.lsp.protocol.Methods.textDocument_documentHighlight,
event.buf
)
then
local highlight_augroup =
vim.api.nvim_create_augroup('lsp-highlight', { clear = false })
vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
buffer = event.buf,
group = highlight_augroup,
callback = vim.lsp.buf.document_highlight,
})
vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, {
buffer = event.buf,
group = highlight_augroup,
callback = vim.lsp.buf.clear_references,
})
vim.api.nvim_create_autocmd('LspDetach', {
group = vim.api.nvim_create_augroup('lsp-detach', { clear = true }),
callback = function(event2)
vim.lsp.buf.clear_references()
vim.api.nvim_clear_autocmds {
group = 'lsp-highlight',
buffer = event2.buf,
}
end,
})
end
end,
})
-- Diagnostic Config
-- See :help vim.diagnostic.Opts
vim.diagnostic.config {
severity_sort = true,
float = { border = 'rounded', source = 'if_many' },
underline = { severity = vim.diagnostic.severity.ERROR },
signs = vim.g.have_nerd_font and {
text = {
[vim.diagnostic.severity.ERROR] = '󰅚 ',
[vim.diagnostic.severity.WARN] = '󰀪 ',
[vim.diagnostic.severity.INFO] = '󰋽 ',
[vim.diagnostic.severity.HINT] = '󰌶 ',
},
} or {},
virtual_text = {
source = 'if_many',
spacing = 2,
format = function(diagnostic)
local diagnostic_message = {
[vim.diagnostic.severity.ERROR] = diagnostic.message,
[vim.diagnostic.severity.WARN] = diagnostic.message,
[vim.diagnostic.severity.INFO] = diagnostic.message,
[vim.diagnostic.severity.HINT] = diagnostic.message,
}
return diagnostic_message[diagnostic.severity]
end,
},
}
local capabilities = require('blink.cmp').get_lsp_capabilities()
local servers = {
ansiblels = {},
ast_grep = {},
bashls = {},
cssls = {},
dockerls = {},
gopls = {
settings = {
gopls = {
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
},
})
end
lspconfig.jsonls.settings = {
json = {
schemas = require('schemastore').json.schemas(),
validate = { enable = true },
},
yaml = {
schemaStore = {
-- You must disable built-in SchemaStore support if you want to use
-- this plugin and its advanced options like `ignore`.
enable = false,
-- Avoid TypeError: Cannot read properties of undefined (reading 'length')
url = '',
},
schemas = require('schemastore').yaml.schemas(),
validate = { enable = true },
},
html = {},
intelephense = {
init_options = {
licenceKey = vim.env.INTELEPHENSE_LICENSE or GetIntelephenseLicense() or nil,
},
},
jsonls = {},
lua_ls = {
settings = {
Lua = {
diagnostics = {
globals = { 'vim' },
disable = { 'missing-fields' },
},
completion = { callSnippet = 'Replace' },
workspace = { checkThirdParty = true },
hint = {
enable = true,
arrayIndex = 'Auto',
await = true,
paramName = 'All',
paramType = true,
semicolon = 'SameLine',
setType = false,
},
},
},
on_init = function(client)
client.config.settings.Lua.workspace.library = {
vim.env.VIMRUNTIME,
}
client.config.settings.Lua.runtime = { version = 'LuaJIT' }
client.notify(
'workspace/didChangeConfiguration',
{ settings = client.config.settings }
)
end,
},
omnisharp = {}, -- C# OmniSharp (will respect EditorConfig for formatting)
pyright = {},
tailwindcss = {},
terraformls = {},
ts_ls = {},
volar = {
settings = {
typescript = {
inlayHints = {
enumMemberValues = { enabled = true },
functionLikeReturnTypes = { enabled = true },
propertyDeclarationTypes = { enabled = true },
},
},
},
},
vimls = {},
eslint = {},
yamlls = {
settings = {
yaml = {
keyOrdering = false, -- don't auto-sort YAML keys on format
schemaStore = { enable = true }, -- use JSON Schema Store for validation
},
},
},
}
-- Diagnostic configuration
local signs = {
{ name = 'DiagnosticSignError', text = '' }, -- Error icon
{ name = 'DiagnosticSignWarn', text = '' }, -- Warning icon
{ name = 'DiagnosticSignHint', text = '' }, -- Hint icon
{ name = 'DiagnosticSignInfo', text = '' }, -- Information icon
local ensure_installed = vim.tbl_keys(servers or {})
vim.list_extend(ensure_installed, {
'actionlint', -- GitHub Actions linter
'shfmt', -- Shell formatter
'stylua', -- Lua formatter
'shellcheck', -- Shell linter
})
require('mason-tool-installer').setup {
auto_install = true,
auto_update = true,
ensure_installed = ensure_installed,
}
local function ensure_sign_defined(name, sign_opts)
if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
vim.fn.sign_define(name, sign_opts)
end
end
require('mason-conform').setup {
ensure_installed = ensure_installed,
}
for _, sign in ipairs(signs) do
ensure_sign_defined(sign.name, {
text = sign.text,
texthl = sign.texthl or sign.name,
numhl = sign.numhl or sign.name,
})
end
---@type vim.diagnostic.Opts
local diagnostics_config = {
signs = {
active = signs, -- show signs
require('mason-lspconfig').setup {
ensure_installed = {}, -- explicitly set to an empty table
automatic_installation = false,
handlers = {
function(server_name)
local server = servers[server_name] or {}
server.capabilities =
vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
require('lspconfig')[server_name].setup(server)
end,
},
update_in_insert = false,
underline = true,
severity_sort = true,
virtual_text = true,
}
vim.diagnostic.config(diagnostics_config)
-- end of junnplus/lsp-setup config
lazydev.setup {
---@type boolean|(fun(root:string):boolean?)
enabled = true,
debug = false,
runtime = vim.env.VIMRUNTIME --[[@as string]],
library = {
{ path = '${3rd}/luv/library', words = { 'vim%.uv' } },
},
integrations = {
lspconfig = true,
cmp = true,
},
}
end,
},
-- Lightweight yet powerful formatter plugin for Neovim
-- https://github.com/stevearc/conform.nvim
{
'stevearc/conform.nvim',
event = { 'BufWritePre' },
cmd = { 'ConformInfo' },
opts = {
notify_on_error = false,
---@type nil|conform.FormatOpts|fun(bufnr: integer): nil|conform.FormatOpts
format_on_save = function(bufnr)
-- Disable "format_on_save lsp_fallback" for languages that don't
-- have a well standardized coding style. You can add additional
-- languages here or re-enable it for the disabled ones.
local disable_filetypes = { c = true, cpp = true }
local lsp_format_opt
if disable_filetypes[vim.bo[bufnr].filetype] then
lsp_format_opt = 'never'
else
lsp_format_opt = 'fallback'
end
-- Disable autoformat for files in a certain paths
local bufname = vim.api.nvim_buf_get_name(bufnr)
if bufname:match '/node_modules|vendor/' then return end
return {
timeout_ms = 500,
lsp_format = lsp_format_opt,
}
end,
formatters_by_ft = {
lua = { 'stylua' },
sh = { 'shfmt' },
bash = { 'shfmt' },
php = { 'phpcbf' },
python = { 'isort', 'black' },
-- Conform can also run multiple formatters sequentially
-- python = { "isort", "black" },
--
-- You can use 'stop_after_first' to run the first available formatter from the list
-- javascript = { "prettierd", "prettier", stop_after_first = true },
},
},
init = function()
-- If you want the formatexpr, here is the place to set it
vim.o.formatexpr = "v:lua.require'conform'.formatexpr()"
end,
},
-- Automatically install formatters registered with conform.nvim via mason.nvim
-- https://github.com/zapling/mason-conform.nvim
{ 'zapling/mason-conform.nvim', opts = {} },
}

View File

@@ -12,6 +12,42 @@ return {
version = '*',
priority = 1001,
config = function()
-- ╭─────────────────────────────────────────────────────────╮
-- │ Text editing │
-- ╰─────────────────────────────────────────────────────────╯
-- Better Around/Inside textobjects
-- Examples:
-- - va) - [V]isually select [A]round [)]paren
-- - yinq - [Y]ank [I]nside [N]ext [Q]uote
-- - ci' - [C]hange [I]nside [']quote
require('mini.ai').setup { n_lines = 500 }
-- Comment lines
require('mini.comment').setup()
-- Text edit operators
-- g= - Evaluate text and replace with output
-- gx - Exchange text regions
-- gm - Multiply (duplicate) text
-- gr - Replace text with register
-- gs - Sort text
require('mini.operators').setup()
-- Split and join arguments, lists, and other sequences
require('mini.splitjoin').setup()
-- Fast and feature-rich surround actions
-- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren
-- - sd' - [S]urround [D]elete [']quotes
-- - sr)' - [S]urround [R]eplace [)] [']
-- - sff - find right (`sf`) part of surrounding function call (`f`)
require('mini.surround').setup()
-- ╭─────────────────────────────────────────────────────────╮
-- │ General workflow │
-- ╰─────────────────────────────────────────────────────────╯
-- Presets for common options and mappings
-- h: MiniBasics.config
require('mini.basics').setup {
@@ -25,17 +61,12 @@ return {
},
}
-- Animate common Neovim actions
-- Replaced anuvyklack/windows.nvim
require('mini.animate').setup()
-- Buffer removing (unshow, delete, wipeout), which saves window layout
-- Replaced famiu/bufdelete.nvim
require('mini.bufremove').setup()
-- Show next key clues
-- Replaced folke/which-key.nvim
local miniclue = require 'mini.clue'
---@modules mini.clue
miniclue.setup {
window = {
config = {
@@ -100,22 +131,30 @@ return {
},
}
-- Comment lines
-- Replaced numToStr/Comment.nvim
require('mini.comment').setup()
-- Highlight cursor word and its matches
require('mini.cursorword').setup()
-- Work with diff hunks
-- Replaced lewis6991/gitsigns.nvim
require('mini.diff').setup()
-- Git integration
require('mini.git').setup()
-- Session management (read, write, delete)
require('mini.sessions').setup {
autowrite = true,
directory = vim.g.sessions_dir or vim.fn.stdpath 'data' .. '/sessions',
file = '',
}
-- ╭─────────────────────────────────────────────────────────╮
-- │ Appearance │
-- ╰─────────────────────────────────────────────────────────╯
-- Animate common Neovim actions
require('mini.animate').setup()
-- Highlight cursor word and its matches
require('mini.cursorword').setup()
-- Highlight patterns in text
-- Replaced folke/todo-comments.nvim
local hp = require 'mini.hipatterns'
hp.setup {
highlighters = {
@@ -162,36 +201,16 @@ return {
}
-- Visualize and work with indent scope
-- Replaced lukas-reineke/indent-blankline.nvim
require('mini.indentscope').setup()
-- Text edit operators
-- g= - Evaluate text and replace with output
-- gx - Exchange text regions
-- gm - Multiply (duplicate) text
-- gr - Replace text with register
-- gs - Sort text
require('mini.operators').setup()
-- Session management (read, write, delete)
require('mini.sessions').setup {
autowrite = true,
directory = vim.g.sessions_dir or vim.fn.stdpath 'data' .. '/sessions',
file = '',
}
-- Split and join arguments, lists, and other sequences
-- Replaced Wansmer/treesj
require('mini.splitjoin').setup()
-- Fast and flexible start screen
-- Replaced glepnir/dashboard-nvim
local starter = require 'mini.starter'
---@modules mini.starter
starter.setup {
items = {
starter.sections.telescope(),
starter.sections.builtin_actions(),
starter.sections.sessions(5, true),
starter.sections.recent_files(5),
},
content_hooks = {
starter.gen_hook.adding_bullet(),
@@ -201,25 +220,38 @@ return {
}
-- Minimal and fast statusline module with opinionated default look
-- Replaced nvim-lualine/lualine.nvim
local sl = require 'mini.statusline'
---@modules mini.statusline
sl.setup {
use_icons = true,
set_vim_settings = true,
content = {
active = function()
local mode, mode_hl = sl.section_mode { trunc_width = 120 }
local git = sl.section_git { trunc_width = 9999 }
local diagnostics = sl.section_diagnostics { trunc_width = 9999 }
local filename = sl.section_filename { trunc_width = 9999 }
local mode, mode_hl = sl.section_mode { trunc_width = 100 }
local git = sl.section_git { trunc_width = 40 }
local diagnostics = sl.section_diagnostics {
trunc_width = 75,
signs = {
ERROR = 'E ',
WARN = 'W ',
INFO = 'I ',
HINT = 'H ',
},
}
local lsp = MiniStatusline.section_lsp { trunc_width = 75 }
local filename = sl.section_filename { trunc_width = 140 }
local fileinfo = sl.section_fileinfo { trunc_width = 9999 }
local location = sl.section_location { trunc_width = 9999 }
return sl.combine_groups {
{ hl = mode_hl, strings = { mode } },
{ hl = 'statuslineDevinfo', strings = { git, diagnostics } },
{
hl = 'MiniStatuslineDevinfo',
strings = { git, lsp },
},
'%<', -- Mark general truncate point
{ hl = 'statuslineFilename', strings = { filename } },
'%=', -- End left alignment
{ hl = 'statuslineFileinfo', strings = { diagnostics } },
{ hl = 'statuslineFileinfo', strings = { fileinfo } },
{ hl = mode_hl, strings = { location } },
}
@@ -227,13 +259,6 @@ return {
},
}
-- Fast and feature-rich surround actions
-- Replaced kylechui/nvim-surround
-- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren
-- - sd' - [S]urround [D]elete [']quotes
-- - sr)' - [S]urround [R]eplace [)] [']
require('mini.surround').setup()
-- Work with trailing whitespace
require('mini.trailspace').setup()
end,

View File

@@ -41,7 +41,7 @@ return {
'document_symbols',
},
source_selector = {
winbar = true,
winbar = false,
statusline = false,
separator = { left = '', right = '' },
show_separator_on_edge = true,
@@ -54,9 +54,7 @@ return {
event_handlers = {
{
event = 'file_opened',
handler = function(_)
require('neo-tree.command').execute { action = 'close' }
end,
handler = function(_) require('neo-tree.command').execute { action = 'close' } end,
},
},
default_component_configs = {

View File

@@ -1,44 +1,13 @@
return {
{
'rmagatti/auto-session',
lazy = false,
version = '*',
opts = {
suppressed_dirs = {
'/',
'~/',
'~/Downloads',
'~/Library',
},
bypass_save_filetypes = {
'PlenaryTestPopup',
'alpha',
'checkhealth',
'dashboard',
'dbout',
'gitsigns.blame',
'grug-far',
'help',
'lspinfo',
'man',
'neo-tree',
'neotest-output',
'neotest-output-panel',
'neotest-summary',
'notify',
'qf',
'spectre_panel',
'startuptime',
'trouble',
'tsplayground',
},
-- log_level = 'debug',
},
},
{
'nvim-lua/plenary.nvim',
version = '*',
lazy = false,
},
-- Vim plugin for automatic time tracking and metrics
-- generated from your programming activity.
-- https://github.com/wakatime/vim-wakatime
{ 'wakatime/vim-wakatime', lazy = false, enabled = true },
}

View File

@@ -3,7 +3,8 @@ return {
-- https://github.com/nvim-telescope/telescope.nvim
'nvim-telescope/telescope.nvim',
version = '*',
lazy = false,
lazy = true,
cmd = 'Telescope',
dependencies = {
{ 'nvim-lua/plenary.nvim' },
{ 'nvim-telescope/telescope-symbols.nvim' },
@@ -16,10 +17,6 @@ return {
-- https://github.com/polirritmico/telescope-lazy-plugins.nvim
{ 'polirritmico/telescope-lazy-plugins.nvim' },
-- Neovim plugin. Telescope.nvim extension that adds LuaSnip integration.
-- https://github.com/benfowler/telescope-luasnip.nvim
{ 'benfowler/telescope-luasnip.nvim' },
-- Fuzzy Finder Algorithm which requires local dependencies to be built.
-- Only load if `make` is available
{
@@ -27,27 +24,45 @@ return {
build = 'make',
cond = vim.fn.executable 'make' == 1,
},
-- Import modules with ease
-- https://github.com/piersolenski/telescope-import.nvim
{ 'piersolenski/telescope-import.nvim' },
},
config = function()
local t = require 'telescope'
local a = require 'telescope.actions'
local c = require 'telescope.config'
local open_with_trouble = require('trouble.sources.telescope').open
local add_to_trouble = require('trouble.sources.telescope').add
-- Clone the default Telescope configuration
local vimgrep_arguments = { unpack(c.values.vimgrep_arguments) }
-- I want to search in hidden/dot files.
table.insert(vimgrep_arguments, '--hidden')
-- I don't want to search in the `.git` directory.
table.insert(vimgrep_arguments, '--glob')
table.insert(vimgrep_arguments, '!**/.git/*')
-- [[ Configure Telescope ]]
-- See `:help telescope` and `:help telescope.setup()`
t.setup {
defaults = {
-- `hidden = true` is not supported in text grep commands.
vimgrep_arguments = vimgrep_arguments,
layout_strategy = 'horizontal',
pickers = {
find_files = {
-- `hidden = true` will still show the inside of `.git/` as
-- it's not `.gitignore`d.
find_command = { 'rg', '--files', '--hidden', '--glob', '!**/.git/*' },
theme = 'dropdown',
},
mappings = {
i = {
['<C-s>'] = a.cycle_previewers_next,
['<C-a>'] = a.cycle_previewers_prev,
},
},
},
mappings = {
i = {
@@ -64,28 +79,28 @@ return {
},
},
},
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<CR>',
node_incremental = '<CR>',
scope_incremental = '<TAB>',
node_decremental = '<S-TAB>',
},
},
context_commentstring = {
enable = true,
enable_autocmd = false,
},
extensions = {
lazy_plugins = {
-- Must be a valid path to the file containing the lazy spec and setup() call.
lazy_config = vim.fn.stdpath 'config' .. '/init.lua',
},
import = {
-- Imports can be added at a specified line whilst keeping the cursor in place
insert_at_top = true,
-- Optionally support additional languages or modify existing languages...
custom_languages = {
{
-- The filetypes that ripgrep supports (find these via `rg --type-list`)
extensions = { 'js', 'ts' },
-- The Vim filetypes
filetypes = { 'vue' },
-- Optionally set a line other than 1
insert_at_line = 2, ---@type function|number
-- The regex pattern for the import statement
regex = [[^(?:import(?:[\"'\s]*([\w*{}\n, ]+)from\s*)?[\"'\s](.*?)[\"'\s].*)]],
},
},
},
},
}

View File

@@ -1,14 +1,8 @@
return {
-- https://github.com/preservim/vim-colors-pencil
{
'preservim/vim-colors-pencil',
priority = 1000, -- Make sure to load this before all the other start plugins.
config = function()
vim.cmd 'colorscheme pencil'
vim.api.nvim_set_option_value('pencil_terminal_italics', 1, {})
end,
'rmehri01/onenord.nvim',
opts = {},
},
-- Automatic dark mode
-- https://github.com/f-person/auto-dark-mode.nvim
{
@@ -30,6 +24,7 @@ return {
-- https://github.com/catgoose/nvim-colorizer.lua
{
'catgoose/nvim-colorizer.lua',
event = 'BufReadPre',
opts = {
user_default_options = {
names = false,
@@ -37,13 +32,27 @@ return {
},
},
-- A neovim plugin that shows colorcolumn dynamically
-- https://github.com/Bekaboo/deadcolumn.nvim
{ 'Bekaboo/deadcolumn.nvim' },
-- Remove all background colors to make nvim transparent
-- https://github.com/xiyaowong/nvim-transparent
{ 'xiyaowong/nvim-transparent', opts = {} },
{
'xiyaowong/nvim-transparent',
lazy = false,
config = function()
local t = require 'transparent'
t.setup {
extra_groups = {
'NormalNC',
'NormalFloat',
'FloatBorder',
'TelescopeBorder',
'TelescopePromptBorder',
'TelescopeResultsBorder',
'TelescopePreviewBorder',
},
}
t.clear_prefix 'NeoTree'
end,
},
-- Display a character as the colorcolumn
-- https://github.com/lukas-reineke/virt-column.nvim

View File

@@ -1,4 +0,0 @@
-- Vim plugin for automatic time tracking and metrics
-- generated from your programming activity.
-- https://github.com/wakatime/vim-wakatime
return { 'wakatime/vim-wakatime', lazy = false, enabled = true }

View File

@@ -0,0 +1,31 @@
" Vim syntax file
" Language: env files (NOT shell code)
" Maintainer: Gernot Schulz <gernot.schulz@overleaf.com>
" Source: https://github.com/overleaf/vim-env-syntax
" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
syn match envComment '^#.*'
syn match envVariableUnassigned "^\<\h\w*$"
syn match envVariable "^\<\h\w*\ze=" nextgroup=envVarAssign
syn match envVarAssign contained "=" nextgroup=envVar,envQuotedVarOpen,envSpace
syn match envVar contained "\h\w*"
syn match envSpace contained "\s\+" nextgroup=envQuotedVarOpen
syn match envQuotedVarOpen contained "[\"']"
syn match envSpace "\s$"
syn match envQuotedVarClose "[\"']$"
let b:current_syntax = "env"
hi def link envComment Comment
hi def link envVariableUnassigned Error
hi def link envVariable Identifier
hi def link envVarAssign Operator
hi def link envSpace Error
hi def link envQuotedVarOpen Error
hi def link envQuotedVarClose Error

2
config/op/plugins.sh Normal file
View File

@@ -0,0 +1,2 @@
export OP_PLUGIN_ALIASES_SOURCED=1
alias gh="op plugin run -- gh"

15
config/op/plugins/gh.json Normal file
View File

@@ -0,0 +1,15 @@
{
"account_id": "S5Z2DMNFKJEZBPCWRHRWC4DCGI",
"entrypoint": [
"gh"
],
"credentials": [
{
"plugin": "github",
"credential_type": "personal_access_token",
"usage_id": "personal_access_token",
"vault_id": "injcin7obv3jdet3r2u3kfihfy",
"item_id": "f6vinbnc6l7ngdzvlw66ayewlq"
}
]
}

View File

@@ -0,0 +1 @@
[{"account_id":"S5Z2DMNFKJEZBPCWRHRWC4DCGI","vault_id":"injcin7obv3jdet3r2u3kfihfy","item_id":"f6vinbnc6l7ngdzvlw66ayewlq"}]

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

@@ -1,7 +1,7 @@
set-option -g status-style 'fg=#4c4f69,bg=#eff1f5'
set-window-option -g window-status-style 'fg=#4c4f69,bg=#eff1f5 dim'
set-window-option -g window-status-current-style 'fg=#8839ef,bg=#eff1f5'
set-window-option -g window-status-activity-style 'fg=#4c4f69,bg=#eff1f5 nodim'
set-window-option -g window-status-bell-style 'fg=#4c4f69,bg=#eff1f5'
set-option -g status-style 'fg=#4c4f69,bg=default'
set-window-option -g window-status-style 'fg=#4c4f69,bg=default dim'
set-window-option -g window-status-current-style 'fg=#8839ef,bg=default'
set-window-option -g window-status-activity-style 'fg=#4c4f69,bg=default nodim'
set-window-option -g window-status-bell-style 'fg=#4c4f69,bg=default'
set -g message-style 'fg=#8839ef bg=#e6e9ef bold' # fg magenta, bg black

View File

@@ -15,6 +15,9 @@
# -o : Set the option only if it is not already set.
# -u : Unset the specified option.
set -ag terminal-overrides ",xterm-256color:RGB"
set -ag terminal-features 'xterm-256color:RGB'
set -g default-terminal "tmux-256color" # Set default terminal to 256 colors
set -g detach-on-destroy off # don't detach tmux when killing a session
set -g display-time 0 # Hide clock
@@ -49,11 +52,12 @@ if-shell '[ "$DEBUG" = "1" ]' 'set -g debug-file ~/.cache/tmux-debug.log'
set -g pane-active-border-style "fg=#7aa2f7"
set -g pane-border-style "fg=#3b4261"
set -g status-style "bg=default"
set -g status-justify "left"
set -g status-left ''
set -g status-left-length "0"
set -g status-position "bottom"
set -g status-right "#S@#{hostname_short} #{tmux_mode_indicator}"
set -g status-right "#S@#h #{tmux_mode_indicator}"
set -g status-right-length "30"
set -g window-status-current-format ' #I:#W#{?window_zoomed_flag, ◈ ,} '
set -g window-status-format ' #I:#W '
@@ -137,6 +141,9 @@ set -g @mode_indicator_sync_mode_style 'bg=default,fg=red'
set -g @fzf-url-bind 'u'
set -g @fzf-url-history-limit '2000'
# https://github.com/tmux-plugins/tmux-continuum
set -g @continuum-restore 'on'
# ── Own scripts ───────────────────────────────────────────────────────
# If we started tmux with a session name, rename it.
@@ -154,6 +161,7 @@ run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-window-name/tmux_window_name
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-mode-indicator/mode_indicator.tmux"
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-suspend/suspend.tmux"
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-continuum/continuum.tmux"
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-resurrect/resurrect.tmux"
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-sessionist/sessionist.tmux"
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-yank/yank.tmux"
run-shell "$HOME/.dotfiles/config/tmux/plugins/tmux-current-pane-hostname/current_pane_hostname.tmux"

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

@@ -372,8 +372,10 @@ function! plug#end()
for [cmd, names] in items(lod.cmd)
execute printf(
\ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)',
\ cmd, string(cmd), string(names))
\ has('patch-7.4.1898')
\ ? 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, <q-mods> ,%s)'
\ : 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)'
\ , cmd, string(cmd), string(names))
endfor
for [map, names] in items(lod.map)
@@ -651,11 +653,19 @@ function! s:lod_ft(pat, names)
call s:doautocmd('filetypeindent', 'FileType')
endfunction
function! s:lod_cmd(cmd, bang, l1, l2, args, names)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:dobufread(a:names)
execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction
if has('patch-7.4.1898')
function! s:lod_cmd(cmd, bang, l1, l2, args, mods, names)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:dobufread(a:names)
execute printf('%s %s%s%s %s', a:mods, (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction
else
function! s:lod_cmd(cmd, bang, l1, l2, args, names)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:dobufread(a:names)
execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction
endif
function! s:lod_map(map, names, with_prefix, prefix)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
@@ -1075,12 +1085,16 @@ function! s:hash_match(a, b)
return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0
endfunction
function! s:disable_credential_helper()
return s:git_version_requirement(2) && get(g:, 'plug_disable_credential_helper', 1)
endfunction
function! s:checkout(spec)
let sha = a:spec.commit
let output = s:git_revision(a:spec.dir)
let error = 0
if !empty(output) && !s:hash_match(sha, s:lines(output)[0])
let credential_helper = s:git_version_requirement(2) ? '-c credential.helper= ' : ''
let credential_helper = s:disable_credential_helper() ? '-c credential.helper= ' : ''
let output = s:system(
\ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
let error = v:shell_error
@@ -1589,7 +1603,7 @@ while 1 " Without TCO, Vim stack is bound to explode
let [error, _] = s:git_validate(spec, 0)
if empty(error)
if pull
let cmd = s:git_version_requirement(2) ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
let cmd = s:disable_credential_helper() ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
call extend(cmd, ['--depth', '99999999'])
endif

View File

@@ -1,23 +1,47 @@
local wezterm = require 'wezterm'
local config = wezterm.config_builder()
config.set_environment_variables = {
COLORTERM = 'truecolor',
}
-- Font and font size
config.font_size = 14.0
config.font_size = 14.5
config.font = wezterm.font_with_fallback {
{
family = 'Operator Mono',
weight = 'Book',
},
'Operator Mono',
'JetBrainsMonoNL NFM Light',
'JetBrains Mono',
'Symbols Nerd Font Mono',
}
config.harfbuzz_features = { 'zero', 'ss01', 'cv05' }
config.font_shaper = 'Harfbuzz'
config.harfbuzz_features = { 'calt=1', 'clig=1', 'liga=1' }
-- Make the window a bit transparent
config.window_background_opacity = 0.98
config.selection_word_boundary = ' \t\n{[}]()"\'`,;:'
-- Window configuration
config.window_background_opacity = 0.95
config.window_decorations = 'RESIZE'
config.macos_window_background_blur = 10
config.window_padding = {
left = 5,
right = 5,
top = 5,
bottom = 5,
}
-- Don't show tab bar
config.enable_tab_bar = false
-- Fix alt on macOS
config.send_composed_key_when_left_alt_is_pressed = true
config.send_composed_key_when_right_alt_is_pressed = true
-- Scrolling deactivated, using tmux for that
config.scrollback_lines = 0
-- Function to detect the theme based on appearance
function Scheme_for_appearance(appearance)

View File

@@ -7,7 +7,6 @@
# yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"
yabai -m config \
active_window_border_color 0xff775759 \
auto_balance on \
layout bsp \
top_padding 0 \

View File

@@ -5,20 +5,19 @@
"assistant": {
"default_model": {
"provider": "copilot_chat",
"model": "claude-3-5-sonnet"
"model": "claude-3.7-sonnet-thought"
},
"version": "2"
},
"formatter": {
"external": {
"command": "prettier",
"arguments": [
"--stdin-filepath",
"{buffer_path}"
]
}
},
"languages": {
"Python": {
"enable_language_server": true,
"allow_rewrap": "anywhere",
"auto_indent_on_paste": true
},
"Shell Script": {
"enable_language_server": true
},
"JavaScript": {
"enable_language_server": true,
"code_actions_on_format": {
@@ -55,8 +54,8 @@
"vim_mode": true,
"theme": {
"mode": "system",
"light": "Iceberg",
"dark": "Iceberg"
"light": "Tokyo Night Light",
"dark": "Tokyo Night Storm"
},
"inlay_hints": {
"enabled": true,

View File

@@ -35,11 +35,20 @@
glob: true
path: base/*
prefix: '.'
# Most of the configs
~/.config/:
glob: true
relink: true
path: config/*
exclude: [config/nvm, config/fzf]
exclude: [config/nvm, config/fzf, config/op]
# 1Password CLI plugins
~/.config/op/plugins.sh:
relink: true
path: config/op/plugins.sh
~/.config/op/plugins/*:
relink: true
path: config/op/plugins/*
# Scripts
~/.local/bin:
glob: true
path: local/bin/*
@@ -47,22 +56,27 @@
~/.local/fzf:
glob: true
path: config/fzf/*
# Manuals
~/.local/man:
glob: true
path: local/man/**
~/.local/share:
glob: true
path: local/share/*
# SSH Configuration
~/.ssh/:
glob: true
mode: 0600
path: ssh/*
- shell:
# Add Git submodules and remove old ones
- bash add-submodules.sh || true
# Update submodules recursively
- git submodule update --init --recursive --force
- shell:
# Use my dotfiles manager to install everything
- bash local/bin/dfm install all
- pipx:

View File

@@ -6,8 +6,15 @@ Some problematic code has been fixed per `shellcheck` suggestions.
## Homegrown
- dfm
- git-dirty (based on git-extra-tools)
- git-fsck-dirs
- git-update-dirs
- php-switcher
- x-backup-folder
- x-backup-mysql-with-prefix
- x-check-git-attributes
- x-clean-vendordirs
- x-env-list
- x-open-ports
## Sourced
@@ -25,9 +32,15 @@ Some problematic code has been fixed per `shellcheck` suggestions.
| `x-when-up` | skx/sysadmin-util |
- Sources:
- [skx/sysadmin-utils](https://github.com/skx/sysadmin-util/)
- [skx/sysadmin-utils][skx]
- Tools for Linux/Unix sysadmins.
- [Licence](https://github.com/skx/sysadmin-util/blob/master/LICENSE)
- [onnimonni](https://github.com/onnimonni)
- [validate_sha256sum](https://gist.github.com/onnimonni/b49779ebc96216771a6be3de46449fa1)
- [mvdan/dotfiles](https://github.com/mvdan/dotfiles)
- [Licence][skx-license]
- [onnimonni][onnimonni]
- [validate_sha256sum][onnimonni-gist]
- [mvdan/dotfiles][mvdan]
[onnimonni]: https://github.com/onnimonni
[onnimonni-gist]: https://gist.github.com/onnimonni/b49779ebc96216771a6be3de46449fa1
[skx]: https://github.com/skx/sysadmin-util
[skx-license]: https://github.com/skx/sysadmin-util/blob/master/LICENSE
[mvdan]: https://github.com/mvdan/dotfiles

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
;;

694
local/bin/git-attributes Executable file
View File

@@ -0,0 +1,694 @@
#!/usr/bin/env bash
#
# Check git repo's files .gitattributes and ensure all of them are mapped.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2022
# License: MIT
set -euo pipefail
# Default configuration
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
DEBUG="${DEBUG:-0}"
if [ "$DEBUG" -eq 1 ]; then
set -x
fi
# Output functions
msg_err()
{
echo -e "\e[31m$@\e[0m" >&2
}
msg_success()
{
echo -e "\e[32m$@\e[0m"
}
msg_warn()
{
echo -e "\e[33m$@\e[0m" >&2
}
msg_info()
{
echo -e "\e[36m$@\e[0m"
}
msg_debug()
{
[[ $VERBOSE -eq 1 ]] && echo -e "\e[35m$@\e[0m"
}
show_help()
{
cat << EOF
Usage: $(basename "$0") [OPTIONS]
Check if all git-tracked files have corresponding rules in .gitattributes
Options:
-h, --help Display this help message
-v, --verbose Enable verbose output
-e, --exit Exit with error code if missing attributes found
-p, --pattern Pattern to check (default: "text: auto")
-n, --no-suggest Don't suggest .gitattributes rules (suggestions are on by default)
-w, --write Write suggested rules to .gitattributes file
-f, --format-width Specify width for formatting rule patterns (default: auto, min: $MIN_FORMAT_WIDTH)
EOF
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-h | --help)
show_help
exit 0
;;
-v | --verbose)
VERBOSE=1
shift
;;
-e | --exit)
EXIT_ON_MISSING=1
shift
;;
-p | --pattern)
CHECK_PATTERN="$2"
shift 2
;;
-n | --no-suggest)
SUGGEST_RULES=0
shift
;;
-w | --write)
WRITE_RULES=1
shift
;;
-f | --format-width)
if [[ $2 =~ ^[0-9]+$ ]]; then
FORMAT_WIDTH=$2
shift 2
else
msg_err "Error: --format-width requires a numeric argument"
exit 1
fi
;;
*)
msg_err "Unknown option: $1"
show_help
exit 1
;;
esac
done
# Function to check if git is installed
check_git_installed()
{
if ! command -v git &> /dev/null; then
msg_err "git could not be found, please install it first"
exit 1
fi
}
# Check if we're in a git repository
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()
{
local git_root
git_root=$(git rev-parse --show-toplevel)
local current_dir
current_dir=$(pwd)
if [[ "$git_root" != "$current_dir" ]]; then
msg_err "Not in git repository root directory"
msg_warn "Please run this command from: $git_root"
exit 1
fi
}
# Check if .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"
exit 1
fi
}
# Format rule with proper alignment
format_rule()
{
local pattern="$1"
local attributes="$2"
local width="$3"
# If pattern starts with "#", it's a comment, don't format
if [[ "$pattern" == "#"* ]]; then
echo "$pattern"
return
fi
# If pattern is empty, return empty
if [[ -z "$pattern" ]]; then
echo ""
return
fi
printf "%-${width}s %s\n" "$pattern" "$attributes"
}
# Get the file extension properly, handling special cases
get_file_extension()
{
local file="$1"
local basename=$(basename "$file")
local extension=""
# Check if file has no extension or is a dotfile
if [[ "$basename" == .* && ! "$basename" =~ \..+$ ]]; then
# It's a dotfile without extension (like .gitignore)
extension="$basename"
elif [[ "$basename" =~ \..+$ ]]; then
# Normal file with extension
extension="${basename##*.}"
# Check for special cases like .d/ directories
if [[ "$extension" == "d" ]]; then
# This is likely a .d directory - use the full filename as pattern
if [[ -f "$file" ]]; then
# For files in .d directories, use the complete path as pattern
extension=$(basename "$file")
else
# For .d directory itself, use *.d
extension="d"
fi
fi
else
# No extension at all
extension="$basename"
fi
echo "$extension"
}
# Suggest appropriate gitattributes rules based on file extension
suggest_rule()
{
local file="$1"
local extension=""
local pattern=""
local attributes=""
msg_debug "Checking file: $file"
# Skip directories
if [[ -d "$file" ]]; then
return
fi
# Get proper file extension
extension=$(get_file_extension "$file")
# If file path contains .d/ pattern, we need special handling
if [[ "$file" =~ \.d/ ]]; then
# Extract the pattern part that includes the .d/ directory
local dir_part=$(dirname "$file")
local base_name=$(basename "$file")
# Check if it's a config directory pattern worth capturing
if [[ "$dir_part" =~ /(\.d|[^/]+\.d)$ ]]; then
pattern="$dir_part/*"
msg_debug "Detected .d directory pattern: $pattern"
else
# Use standard extension pattern
pattern="*.${extension}"
fi
else
# Standard file with extension
pattern="*.${extension}"
fi
# Common text files
case "$extension" in
# Shell scripts
sh | bash | zsh | fish)
attributes="text eol=lf diff=shell"
;;
# Web development
html | htm | xhtml | css | scss | sass | less)
attributes="text eol=lf diff=html"
;;
js | jsx | ts | tsx | json | json5)
attributes="text eol=lf diff=javascript"
;;
# Programming languages
php)
attributes="text eol=lf diff=php"
;;
py)
attributes="text eol=lf diff=python"
;;
rb)
attributes="text eol=lf diff=ruby"
;;
go)
attributes="text eol=lf diff=golang"
;;
java | kt | scala)
attributes="text eol=lf diff=java"
;;
c | cpp | h | hpp)
attributes="text eol=lf diff=cpp"
;;
# Documentation
md | markdown | txt)
attributes="text eol=lf"
;;
# Configuration files
yml | yaml | toml | ini | cfg | conf)
attributes="text eol=lf"
;;
# Git config files and similar patterns
git)
attributes="text eol=lf"
;;
gitignore | gitattributes)
attributes="text eol=lf"
;;
# Binary files
png | jpg | jpeg | gif | ico | svg | webp | avif)
attributes="binary"
;;
pdf | doc | docx | xls | xlsx | ppt | pptx)
attributes="binary"
;;
zip | tar | gz | 7z | rar)
attributes="binary"
;;
mp3 | mp4 | avi | mov | wav | ogg)
attributes="binary"
;;
ttf | otf | woff | woff2 | eot)
attributes="binary"
;;
# Default for unknown extensions
*)
# Try to guess if it's text by checking if it contains null bytes
if file "$file" | grep -q text; then
attributes="text eol=lf"
else
attributes="binary"
fi
;;
esac
msg_debug "...suggesting $pattern $attributes"
echo "$pattern:$attributes"
}
# Function to check for missing .gitattributes
check_gitattributes()
{
local missing_attributes
msg_info "Checking for pattern: $CHECK_PATTERN"
missing_attributes=$(git ls-files | git check-attr -a --stdin | grep "$CHECK_PATTERN" || true)
if [[ -n "$missing_attributes" ]]; then
msg_warn "Missing .gitattributes rules detected"
if [[ $SUGGEST_RULES -eq 1 ]]; then
# Generate suggestions
local suggestions
# Generate the suggestions
suggestions=$(suggest_gitattributes "$missing_attributes")
# Display the suggestions
echo ""
echo "$suggestions"
echo ""
if [[ $WRITE_RULES -eq 1 ]]; then
msg_debug "...writing to .gitattributes"
write_to_gitattributes "$suggestions"
fi
else
msg_err ".gitattributes rule missing for the following files:"
echo "$missing_attributes"
fi
if [[ $EXIT_ON_MISSING -eq 1 ]]; then
return 1
fi
else
msg_success "All files have a corresponding rule in .gitattributes"
fi
return 0
}
# Parse rule string and extract pattern and attributes
parse_rule()
{
local rule="$1"
if [[ "$rule" == "#"* ]]; then
# This is a comment line
echo "$rule::"
return
fi
if [[ "$rule" =~ ^([^[:space:]]+)[[:space:]]+(.*)$ ]]; then
echo "${BASH_REMATCH[1]}:${BASH_REMATCH[2]}"
else
echo "$rule::"
fi
}
# Check shell scripts by name regardless of extension
detect_shell_scripts()
{
msg_debug "Detecting shell scripts by name regardless of extension..."
local shell_scripts_rules=""
local shell_scripts_found=0
local patterns=()
local attributes=()
# Get already defined rules in .gitattributes
local existing_rules
existing_rules=$(grep -v "^#" .gitattributes || true)
# Get all shell scripts regardless of extension
local shell_scripts
shell_scripts=$(git ls-files | xargs file | grep "shell script" | cut -d: -f1)
if [[ -n "$shell_scripts" ]]; then
shell_scripts_found=$(echo "$shell_scripts" | wc -l | tr -d ' ')
msg_debug "Found $shell_scripts_found potential shell scripts."
# Track scripts that need rules
declare -A scripts_by_dir=()
local need_rule_count=0
# Process each script
while IFS= read -r script; do
local rel_path="${script#./}"
# Skip if exact path already in .gitattributes
if grep -q "^${rel_path} " <<< "$existing_rules"; then
msg_debug "Script already in .gitattributes: $rel_path"
continue
fi
# Skip if file extension already covered
local extension=$(get_file_extension "$rel_path")
if [[ "$extension" != "$rel_path" ]] && grep -q "^\*\.$extension " <<< "$existing_rules"; then
msg_debug "Script covered by extension rule: $rel_path (*.$extension)"
continue
fi
# Check if any parent directory is already covered
local is_covered=0
local dir_path="$rel_path"
while [[ "$dir_path" != "." && "$dir_path" != "/" ]]; do
dir_path=$(dirname "$dir_path")
if [[ "$dir_path" == "." ]]; then
break
fi
# Check if directory or any of its contents are covered
if grep -q "^${dir_path}/\?" <<< "$existing_rules" || grep -q "^${dir_path}/\*" <<< "$existing_rules"; then
msg_debug "Script covered by directory rule: $rel_path (${dir_path})"
is_covered=1
break
fi
done
if [[ $is_covered -eq 1 ]]; then
continue
fi
# Group by directory
local dir=$(dirname "$rel_path")
if [[ "$dir" == "." ]]; then
dir="root"
fi
# Add to appropriate group
if [[ -z "${scripts_by_dir[$dir]:-}" ]]; then
scripts_by_dir[$dir]="$rel_path"
else
scripts_by_dir[$dir]="${scripts_by_dir[$dir]}\n$rel_path"
fi
((need_rule_count++))
done <<< "$shell_scripts"
# Output grouped results
if [[ $need_rule_count -gt 0 ]]; then
patterns+=("# Shell scripts detected by content")
attributes+=("")
# Check if we can use directory-based rules instead of individual files
for dir in "${!scripts_by_dir[@]}"; do
local files_in_dir=$(echo -e "${scripts_by_dir[$dir]}" | wc -l)
local dir_path="$dir"
if [[ "$dir" == "root" ]]; then
# For root directory files, list each individually
while IFS= read -r file; do
patterns+=("$file")
attributes+=("text eol=lf diff=shell")
done <<< "$(echo -e "${scripts_by_dir[$dir]}")"
elif [[ $files_in_dir -gt 2 ]]; then
# If directory has multiple scripts, suggest a directory pattern
patterns+=("# Found $files_in_dir scripts in $dir_path")
attributes+=("")
# Special handling for .d directories
if [[ "$dir_path" =~ \.d$ || "$dir_path" =~ \.d/ ]]; then
patterns+=("$dir_path/*")
else
patterns+=("$dir_path/*")
fi
attributes+=("text eol=lf diff=shell")
# List the files as comments for reference
while IFS= read -r file; do
patterns+=("# - ${file}")
attributes+=("")
done <<< "$(echo -e "${scripts_by_dir[$dir]}" | sort)"
else
# For directories with few scripts, list them individually
while IFS= read -r file; do
patterns+=("$file")
attributes+=("text eol=lf diff=shell")
done <<< "$(echo -e "${scripts_by_dir[$dir]}")"
fi
done
msg_debug "Adding $need_rule_count shell scripts to suggestions (grouped by directory)."
else
msg_debug "All detected shell scripts already have rules."
fi
else
msg_debug "No shell scripts detected."
fi
# Return the formatted arrays
local rules_count=${#patterns[@]}
for ((i = 0; i < rules_count; i++)); do
echo "${patterns[$i]}:${attributes[$i]}"
done
}
# Function to suggest gitattributes rules
suggest_gitattributes()
{
local missing_attributes="$1"
local files
local extension_suggestions=()
local formatted_suggestions=""
local all_patterns=()
local all_attributes=()
local max_pattern_length=0
# Add header to suggestions
all_patterns+=("# Auto-generated rules - $(date +"%Y-%m-%d %H:%M:%S")")
all_attributes+=("")
msg_info "Suggested .gitattributes rules:"
# First, detect shell scripts and add them to suggestions
msg_info "Detecting shell scripts by content..."
local shell_scripts_rules
shell_scripts_rules=$(detect_shell_scripts)
# Add shell script rules to patterns and attributes arrays
if [[ -n "$shell_scripts_rules" ]]; then
while IFS=':' read -r pattern attributes; do
if [[ -n "$pattern" ]]; then
all_patterns+=("$pattern")
all_attributes+=("$attributes")
# Update max pattern length (skip comments)
if [[ "$pattern" != "#"* ]] && [[ ${#pattern} -gt $max_pattern_length ]]; then
max_pattern_length=${#pattern}
fi
fi
done <<< "$shell_scripts_rules"
fi
# Extract filenames from git check-attr output
files=$(echo "$missing_attributes" | awk -F': ' '{print $1}')
# Get suggestions for each file
declare -A seen_patterns=()
while IFS= read -r file; do
local suggestion=$(suggest_rule "$file")
if [[ -n "$suggestion" ]]; then
IFS=':' read -r pattern attributes <<< "$suggestion"
# Only add each pattern once
if [[ -z "${seen_patterns[$pattern]:-}" ]]; then
extension_suggestions+=("$suggestion")
seen_patterns[$pattern]=1
fi
fi
done <<< "$files"
# Remove duplicates and sort
local unique_extensions=()
mapfile -t unique_extensions < <(printf '%s\n' "${extension_suggestions[@]}" | sort -u)
# Add extension-based suggestions header if we have any
if [[ ${#unique_extensions[@]} -gt 0 ]]; then
all_patterns+=("")
all_attributes+=("")
all_patterns+=("# File extension-based rules")
all_attributes+=("")
# Add extension rules to patterns and attributes arrays
for suggestion in "${unique_extensions[@]}"; do
IFS=':' read -r pattern attributes <<< "$suggestion"
all_patterns+=("$pattern")
all_attributes+=("$attributes")
# Update max pattern length
if [[ ${#pattern} -gt $max_pattern_length ]]; then
max_pattern_length=${#pattern}
fi
done
fi
# Use user-specified format width if provided, otherwise use max_pattern_length
# But ensure it's at least MIN_FORMAT_WIDTH
local format_width=$max_pattern_length
if [[ $FORMAT_WIDTH -gt 0 ]]; then
format_width=$FORMAT_WIDTH
fi
# Ensure minimum width
if [[ $format_width -lt $MIN_FORMAT_WIDTH ]]; then
format_width=$MIN_FORMAT_WIDTH
fi
msg_debug "Using format width: $format_width"
# Format and output all suggestions with proper alignment
local rule_count=${#all_patterns[@]}
for ((i = 0; i < rule_count; i++)); do
local pattern="${all_patterns[$i]}"
local attributes="${all_attributes[$i]}"
# Handle comments separately
if [[ "$pattern" == "#"* ]] || [[ -z "$attributes" ]]; then
formatted_suggestions+="$pattern\n"
echo "$pattern"
else
local formatted_rule=$(printf "%-${format_width}s %s\n" "$pattern" "$attributes")
formatted_suggestions+="$formatted_rule\n"
echo "$formatted_rule"
fi
done
# Add final message
echo ""
msg_info "Add these rules to your .gitattributes file to resolve missing attributes."
# Return the full suggestion text so it can be both displayed and written to file
echo -e "$formatted_suggestions"
}
# Write suggestions to .gitattributes file
write_to_gitattributes()
{
local suggestions="$1"
local gitattributes=".gitattributes"
# Check if file exists and is writable
if [[ ! -w "$gitattributes" ]]; then
msg_err "Cannot write to $gitattributes. Check permissions."
return 1
fi
# Add a newline at the end of the file if it doesn't have one
if [[ -s "$gitattributes" ]] && [[ $(tail -c 1 "$gitattributes" | wc -l) -eq 0 ]]; then
echo "" >> "$gitattributes"
fi
# Append suggestions to the file
echo -e "$suggestions" >> "$gitattributes"
msg_success "Added suggested rules to $gitattributes"
# Remind to check the file
msg_warn "Please review the changes to ensure they're appropriate for your project."
return 0
}
# Main function
main()
{
check_git_installed
check_git_repo
check_git_root
check_gitattributes_exists
check_gitattributes
}
main "$@"

File diff suppressed because it is too large Load Diff

185
local/bin/git-dirty.md Normal file
View File

@@ -0,0 +1,185 @@
# git-dirty
A powerful tool to recursively check Git repository status across multiple directories.
## Overview
`git-dirty` scans directories to identify Git repositories and reports their status.
It quickly shows which repositories have uncommitted changes, untracked files, or need
to be pushed, making it easy to maintain clean workspaces across multiple projects.
## Features
- 🔍 **Recursive scanning** of directories to find Git repositories
- 🚦 **Visual indicators** showing repository status (clean/dirty/not git)
- 🔄 **Parallel processing** for faster scanning of large directory structures
- 🌳 **Tree-like display** with customizable depth
- 📊 **Progress tracking** for large repository scans
- 🎨 **Colorized output** (can be disabled)
- 📏 **Path truncation** for cleaner display
- 🔀 **Branch display** with smart formatting for main branches
- ⏱️ **Performance metrics** showing scan speed and ETA
- 📈 **Smart sorting** to maintain tree hierarchy in output
- ⚙️ **Configurable** via environment variables or config files
## Installation
Place the script in your PATH and make it executable:
```bash
# Clone the repository or download the script
curl -o ~/.local/bin/git-dirty https://raw.githubusercontent.com/ivuorinen/dotfiles/main/local/bin/git-dirty
chmod +x ~/.local/bin/git-dirty
```
## Usage
```bash
git-dirty [OPTIONS] [DIRECTORY]
# or if the file is in the PATH, you can use it as an git command
git dirty [OPTIONS] [DIRECTORY]
# to show help
git dirty -h
```
If no directory is specified, it will use `$HOME/Code` as the default.
### Options
- `-h` Show help message and exit
- `-d NUM` Set maximum depth for showing non-git directories (default: 5)
- `-p` Process directories in parallel (requires 'parallel' command)
- `-v` Enable verbose output
- `-a` Show all status details (stash, untracked files, etc.)
- `-e PATTERNS` Additional patterns to exclude (comma separated)
- `-m NUM` Set maximum recursion depth (default: 15)
- `-c` Toggle colorized output
- `-t` Toggle path truncation
- `-b` Toggle branch name display
### Examples
```bash
# Check default directory
git-dirty
# Check specific directory
git-dirty ~/Projects
# Check with extended status information
git-dirty -a ~/Code
# Exclude certain directories
git-dirty -e 'build,dist,node_modules' ~/Code
# Use parallel processing for faster results
git-dirty -p ~/large-directory
# Hide branch names in output
git-dirty -b ~/Code
```
## Status Indicators
The script uses the following status indicators:
- ✅ Clean repository
- ❌ Dirty repository with details:
- `M` = Modified files
- `S` = Staged changes
- `?` = Untracked files (with `-a` flag)
- `$` = Stashed changes (with `-a` flag)
- `↑` = Unpushed commits
- ⚠️ Not a Git repository
## Branch Display
The script shows branch names for repositories not on main branches. This helps identify
repositories where work is happening on feature branches. Main branches (configurable as
`main`, `master`, and `trunk` by default) are hidden to reduce output clutter.
## Configuration
You can customize the default behavior using environment variables:
```bash
# in your .bashrc, .zshrc, etc.
export GIT_DIRTY_DIR="$HOME/Projects" # Set default directory
export GIT_DIRTY_DEPTH=3 # Show non-git dirs up to depth 3
export GIT_DIRTY_MAXDEPTH=15 # Maximum recursion depth
export GIT_DIRTY_COLOR=1 # Enable colorized output (0 to disable)
export GIT_DIRTY_TRUNCATE=1 # Enable path truncation (0 to disable)
export GIT_DIRTY_SHOW_BRANCH=1 # Show branch names (0 to disable)
export GIT_DIRTY_MAIN_BRANCHES="main master trunk" # Main branches (not shown in output)
export GIT_DIRTY_EXCLUDE="node_modules vendor .cache build dist .tests .test" # Default excludes
```
### Config File
You can also create a configuration file at `$XDG_CONFIG_HOME/git-dirty/config`
(typically `~/.config/git-dirty/config`):
```bash
# Example config file
GIT_DIRTY_DIR="$HOME/Projects"
GIT_DIRTY_DEPTH=3
GIT_DIRTY_CHECK_STASH=1
GIT_DIRTY_SHOW_BRANCH=1
GIT_DIRTY_MAIN_BRANCHES="main master trunk develop"
GIT_DIRTY_EXCLUDE="node_modules vendor .cache build dist tmp"
```
## Skip Directories from Checking
If you want to skip a directory from being checked, add a `.ignore` file next to the `.git` folder.
You can add `.ignore` to your global `.gitignore` file to avoid committing these files.
## Performance Features
- **Parallel processing**: Significant speed improvements when using the `-p` flag
- **Progress bars**: Real-time feedback on scanning progress with ETA
- **Rate limiting**: Controls parallel jobs to prevent system overloading
- **Smart directory traversal**: Skips excluded directories for faster processing
## Tips
1. **Add an alias**: Create an alias in your shell configuration:
```bash
alias gd='git-dirty'
```
2. **Use it with specific directories**:
```bash
git-dirty ~/specific/project
```
3. **Run in parallel mode for large codebases**:
```bash
git-dirty -p ~/huge-monorepo
```
4. **Turn off branch display for cleaner output**:
```bash
git-dirty -b
```
## Requirements
- Bash (version 4+)
- Git
- Optional: GNU Parallel for parallel processing
## License
MIT
## Credits
Created with ❤️ by Ismo Vuorinen
<!-- vim: set ft=markdown cc=80 : -->

View File

@@ -10,42 +10,116 @@ set -euo pipefail
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
DEBUG="${DEBUG:-0}"
if [ "$DEBUG" -eq 1 ]; then
set -x
fi
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[ "$VERBOSE" -eq 1 ] && echo "$1"
if [ "$VERBOSE" -eq 1 ]; then
echo "$1"
fi
return 0
}
# Show red error message
# $1 - message (string)
msg_err()
{
echo "$(tput setaf 1)Error: $1$(tput sgr0)"
}
# Function to perform git fsck on a repository
# $1 - directory (string)
fsck_repo()
{
local dir=$1
msg "Processing dir: $dir"
(
cd "$dir" || exit 1
if [ -d ".git" ]; then
git fsck --no-dangling --full --no-progress
echo ""
fi
)
local dir dirs collected_errors collected_repos
dir="$(realpath "$1")"
collected_errors="$2"
collected_repos="$3"
msg "Processing: $dir"
if [ ! -d "$dir/.git" ]; then
echo "$dir" >> "$collected_errors"
msg " (!) Skipping (no .git)"
return
fi
echo "$dir" >> "$collected_repos"
if ! git -C "$dir" fsck --no-dangling --full --no-progress 2>&1 | grep -vE '^notice:'; then
echo "$dir" >> "$collected_errors"
msg " (!) Issues found in: $dir"
fi
}
# Main function
main()
{
local starting_path=${1:-$(pwd)}
local dirs
local starting_path errors_file repo_count_file dirs dirs_count REPO_COUNT ERROR_COUNT
starting_path=${1:-$(pwd)}
errors_file="${2:-/tmp/git-fsck-errors.txt}"
repo_count_file="${3:-/tmp/git-fsck-repo-count.txt}"
# If starting_point=. or starting_point=.., set it to the current directory
if [ "$starting_path" = "." ]; then
starting_path="$(pwd)"
elif [ "$starting_path" = ".." ]; then
starting_path="$(dirname "$(pwd)")"
fi
# Check if starting_path exists
if [ ! -d "$starting_path" ]; then
msg_err "Error: Directory '$starting_path' not found."
return 1
fi
# Collect the directories
dirs=$(find "$starting_path" -mindepth 1 -maxdepth 1 -type d)
# Filter out unwanted directories
dirs=$(echo "$dirs" \
| grep -vE '^\./\.git$' \
| grep -vE '^\./\.svn$' \
| grep -vE '^\./\.hg$' \
| grep -vE '^\./\.bzr$')
# Count the directories for reporting and processing
dirs_count=$(echo "$dirs" | wc -l | tr -d ' ')
# If dirs_count is 0, exit early
if [ "$dirs_count" -eq 0 ]; then
msg_err "No directories found in $starting_path."
return 0
fi
echo "Checking $dirs_count directories in $starting_path..."
for dir in $dirs; do
fsck_repo "$dir"
fsck_repo "$dir" "$errors_file" "$repo_count_file"
done
# Collect the results and trim the output
REPO_COUNT=$(wc -l < "$repo_count_file" | tr -d ' ')
ERROR_COUNT=$(wc -l < "$errors_file" | tr -d ' ')
rm -f "$errors_file" "$repo_count_file"
echo ""
echo "Done."
echo "Summary:"
echo "Checked $REPO_COUNT repositories from $dirs_count directories."
if [ "$ERROR_COUNT" -gt 0 ]; then
echo "Found issues in $ERROR_COUNT repositories."
return 1
else
echo "All repositories passed."
return 0
fi
}
main "$@"
exit $?

View File

@@ -0,0 +1,65 @@
# git-fsck-dirs
A utility to check multiple Git repositories for corruption
using `git fsck`.
## Overview
`git-fsck-dirs` scans all subdirectories within a specified path
and performs a `git fsck` operation on each Git repository found.
This helps identify corrupted repositories or those with integrity
issues.
## Features
- Recursively checks all Git repositories in the given directory
- Provides a summary of repositories checked and any issues found
- Filters out common version control directories (.git, .svn, etc.)
- Supports verbose and debug modes
## Usage
```bash
git-fsck-dirs [path] [errors_file] [repo_count_file]
git fsck-dirs [path] [errors_file] [repo_count_file]
```
### Arguments
- `path`: Directory to scan (defaults to current directory)
- `errors_file`: Path to save errors (defaults to /tmp/git-fsck-errors.txt)
- `repo_count_file`: Path to save repository count
(defaults to /tmp/git-fsck-repo-count.txt)
### Environment Variables
- `VERBOSE=1`: Enable verbose output
- `DEBUG=1`: Enable debug mode (shows executed commands)
## Examples
Check repositories in the current directory:
```bash
git fsck-dirs
git-fsck-dirs
```
Check repositories in a specific directory:
```bash
git fsck-dirs ~/projects
git-fsck-dirs ~/projects
```
Enable verbose output:
```bash
VERBOSE=1 git-fsck-dirs
```
## License
MIT License - Copyright 2023 Ismo Vuorinen
<!-- vim: set ft=markdown cc=80 : -->

View File

@@ -8,39 +8,688 @@
# Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved.
# License: MIT <https://opensource.org/license/mit/>
set -euo pipefail
set -uo pipefail
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Script version
VERSION="1.0.0"
# Default settings
VERBOSE=0
QUIET=0
EXCLUDE_DIRS=""
CLEANUP=0
CONFIG_FILE=""
LOG_FILE=""
# Define color variables if terminal supports it
if [[ -t 1 ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
else
RED=''
GREEN=''
YELLOW=''
BLUE=''
CYAN=''
NC=''
fi
# Counters
TOTAL=0
SUCCESS=0
FAILED=0
CONFLICTS=0
UPDATED=0
PROCESSED=0
SKIPPED=0
UNTRACKED=0
UNMERGED=0
BRANCHES_CLEANED=0
# Function to display help message
show_help()
{
BIN=$(basename "$0")
cat << EOF
Usage: $BIN [OPTIONS]
Updates all git repositories in subdirectories.
Options:
--help, -h Display this help message and exit
--version, -v Display version information and exit
--verbose Display detailed output
--quiet, -q Suppress all output except errors
--exclude DIR Exclude directory from updates (can be used multiple times)
--cleanup Remove local branches that have been merged into current branch
--config FILE Read options from configuration file
--log FILE Log details and errors to FILE
Environment variables:
VERBOSE Set to 1 to enable verbose output
EXCLUDE_DIRS Space-separated list of directories to exclude
Examples:
$BIN Update all git repositories
$BIN --verbose Update with detailed output
$BIN --exclude node_modules --exclude vendor
Update repositories but skip node_modules
and vendor dirs
$BIN --cleanup Update and clean up merged branches
$BIN --config ~/.gitupdate.conf
Use options from config file
EOF
exit 0
}
# Function to display version
show_version()
{
echo "$(basename "$0") version $VERSION"
exit 0
}
# Function to log messages
# $1 - level (string: INFO, WARNING, ERROR)
# $2 - message (string)
log()
{
local level message timestamp
level="$1"
message="$2"
timestamp=$(date +"%Y-%m-%d %H:%M:%S")
if [[ -n "$LOG_FILE" ]]; then
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
fi
# For errors, also log to stderr if in verbose mode
if [[ "$level" == "ERROR" && "$VERBOSE" -eq 1 && "$QUIET" -eq 0 ]]; then
echo -e "${RED}[$timestamp] [$level] $message${NC}" >&2
fi
}
# Process command-line arguments
process_args()
{
while [[ $# -gt 0 ]]; do
case "$1" in
--help | -h)
show_help
;;
--version | -v)
show_version
;;
--verbose)
VERBOSE=1
;;
--quiet | -q)
QUIET=1
;;
--exclude)
if [[ -n "$2" ]]; then
EXCLUDE_DIRS="$EXCLUDE_DIRS $2"
shift
else
echo "Error: --exclude requires a directory argument" >&2
exit 1
fi
;;
--cleanup)
CLEANUP=1
;;
--config)
if [[ -n "$2" && -f "$2" ]]; then
CONFIG_FILE="$2"
shift
else
echo "Error: --config requires a valid file argument" >&2
exit 1
fi
;;
--log)
if [[ -n "$2" ]]; then
LOG_FILE="$2"
shift
else
echo "Error: --log requires a file argument" >&2
exit 1
fi
;;
*)
echo "Unknown option: $1" >&2
echo "Use --help for usage information" >&2
exit 1
;;
esac
shift
done
# Process config file if specified
if [[ -n "$CONFIG_FILE" && -f "$CONFIG_FILE" ]]; then
log "INFO" "Reading configuration from $CONFIG_FILE"
while IFS= read -r line || [[ -n "$line" ]]; do
# Skip comments and empty lines
[[ "$line" =~ ^[[:space:]]*# ]] && continue
[[ -z "${line// /}" ]] && continue
# Process each option from the config file
option=$(echo "$line" | awk '{print $1}')
value=$(echo "$line" | cut -d' ' -f2-)
case "$option" in
exclude) EXCLUDE_DIRS="$EXCLUDE_DIRS $value" ;;
verbose) VERBOSE=1 ;;
quiet) QUIET=1 ;;
cleanup) CLEANUP=1 ;;
log) LOG_FILE="$value" ;;
*) log "WARNING" "Unknown option in config file: $option" ;;
esac
done < "$CONFIG_FILE"
fi
# Environment variables override command-line options
[[ -n "${VERBOSE:-}" && "$VERBOSE" -eq 1 ]] && VERBOSE=1
# shellcheck disable=SC2269
[[ -n "${EXCLUDE_DIRS:-}" ]] && EXCLUDE_DIRS="${EXCLUDE_DIRS}"
# 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
# Initialize log file
echo "[$(date +"%Y-%m-%d %H:%M:%S")] [INFO] Started git-update-dirs version $VERSION" > "$LOG_FILE"
fi
}
# Terminal width for progress bar
TERM_WIDTH=$(tput cols 2> /dev/null || echo 120)
PROGRESS_WIDTH=$((TERM_WIDTH - 40))
MAX_DIR_LENGTH=$((TERM_WIDTH - PROGRESS_WIDTH - 25)) # Add 5 for extra padding
# Last status message, used for clearing properly
LAST_STATUS_LENGTH=0
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[ "$VERBOSE" -eq 1 ] && echo "$1"
local message
message="$1"
if [[ "$VERBOSE" -eq 1 && "$QUIET" -eq 0 ]]; then
echo "$message"
[[ -n "$LOG_FILE" ]] && log "INFO" "$message"
elif [[ -n "$LOG_FILE" ]]; then
log "DEBUG" "$message"
fi
}
# Function to print normal output unless QUIET is enabled
# $1 - message (string)
print()
{
local message
message="$1"
if [[ "$QUIET" -eq 0 ]]; then
echo -e "$message"
[[ -n "$LOG_FILE" ]] && log "INFO" "$message"
elif [[ -n "$LOG_FILE" ]]; then
log "INFO" "$message"
fi
}
# Function to display progress bar
# $1 - current (int)
# $2 - total (int)
# $3 - status message (string)
show_progress()
{
[[ "$QUIET" -eq 1 ]] && return
local current total status percent filled empty
current=$1
total=$2
status=$3
# If TERM_WIDTH is less than LAST_STATUS_LENGTH set TERM_WIDTH
# to it.
if [[ $TERM_WIDTH -lt $LAST_STATUS_LENGTH ]]; then
TERM_WIDTH=$LAST_STATUS_LENGTH
fi
# Clear the entire line before updating to avoid artifacts
printf "\r%-${TERM_WIDTH}s" " "
# Avoid division by zero
if [[ "$total" -eq 0 ]]; then
percent=0
else
percent=$((current * 100 / total))
fi
filled=$((percent * PROGRESS_WIDTH / 100))
# Ensure filled doesn't exceed PROGRESS_WIDTH
[[ $filled -gt $PROGRESS_WIDTH ]] && filled=$PROGRESS_WIDTH
empty=$((PROGRESS_WIDTH - filled))
# Truncate status message if too long
if [[ ${#status} -gt $MAX_DIR_LENGTH ]]; then
status="...${status:$((${#status} - MAX_DIR_LENGTH + 4))}"
fi
# Pad the status message to ensure consistent width and add extra space
printf -v padded_status "%-${MAX_DIR_LENGTH}s" "$status"
# Create and display the progress bar with fixed width for percentage and colors
printf "\r[${BLUE}%s${NC}%s] ${GREEN}%3d%%${NC} ${CYAN}%s${NC}" \
"$(printf '#%.0s' $(seq 1 $filled))" \
"$(printf ' %.0s' $(seq 1 $empty))" \
"$percent" \
"$padded_status"
# Store the length of the current status
LAST_STATUS_LENGTH=${#status}
# Log progress if logging is enabled
[[ -n "$LOG_FILE" ]] && log "DEBUG" "Progress: $percent% - $status"
}
# Is the directory path excluded?
# $1: Directory path
# Return 0 if the directory should be skipped, 1 otherwise
excluded_path()
{
local dir home
dir="$(realpath "$1")"
home="$(realpath "$HOME")"
# Check if directory should be excluded
for exclude in $EXCLUDE_DIRS; do
# Check for parts of the directory name
if [[ "$dir" == *"$exclude"* ]] || [[ "$dir" == "$exclude" ]]; then
msg "Skipping excluded directory: $dir"
return 0
fi
# Run only if home is not empty
if [[ -n "$home" ]]; then
# Remove home directory from path
relative_dir="${dir/"$home"/}"
# Check if we should exclude based on relative paths based on the home directory
if [[ "$relative_dir" == *"$exclude"* ]] || [[ "$relative_dir" == "$exclude" ]]; then
msg "Skipping excluded relative directory: $dir"
return 0
fi
fi
done
# Check if it's a git repository
if [[ ! -d "$dir/.git" ]]; then
msg "Skipping non-git directory: $dir"
return 0
fi
return 1
}
# Function to count git repositories
count_git_repos()
{
local count=0
for dir in */; do
if ! excluded_path "$dir"; then
((count++))
fi
done
echo $count
}
# Check for unmerged files or conflicts in a git repository
# Returns 0 if there are unmerged files, 1 otherwise
has_unmerged_files()
{
git ls-files --unmerged | grep -q "^" \
&& return 0 || return 1
}
# Check for clean working directory
# Returns 0 if working directory is clean, 1 otherwise
is_repo_clean()
{
git diff --quiet \
&& git diff --cached --quiet \
&& return 0 || return 1
}
# Function to clean up local branches that have been merged
# Returns the number of branches cleaned
cleanup_branches()
{
local cleaned=0
local current_branch output
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
msg "Skipping branch cleanup: not on a main branch ($current_branch)"
return 0
fi
# Get list of merged branches, excluding current branch, master, main, and develop
output=$(git branch --merged | grep -v -E "^\*|master|main|develop" | sed 's/^[[:space:]]*//')
if [[ -n "$output" ]]; then
if [[ "$VERBOSE" -eq 1 ]]; then
msg "Cleaning up merged branches in $(pwd):"
echo "$output" | while read -r branch; do
msg " - $branch"
done
fi
# Delete branches
for branch in $output; do
if [[ -n "$branch" ]]; then
if git branch -d "$branch" &> /dev/null; then
((cleaned++))
log "INFO" "Deleted merged branch $branch in $(pwd)"
else
log "WARNING" "Failed to delete branch $branch in $(pwd)"
fi
fi
done
fi
return $cleaned
}
# Function to update a git repository
# $1 - directory (string)
update_repo()
{
local dir=$1
(
cd "$dir" || exit
msg "Updating $dir"
git pull --rebase --autostash --prune
)
local dir output exit_status git_args current_branch \
remote_name cleaned_branches
dir="$1"
log "INFO" "Processing repository: $dir"
# Increment the processed counter
((PROCESSED++))
# Show progress before starting the operation
show_progress "$PROCESSED" "$TOTAL" "${dir%/}"
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++))
return 1
}
# If there are no remotes, skip
if ! git remote -v &> /dev/null; then
log "INFO" "Skipping directory with no remotes: $dir"
msg "Skipping directory with no remotes: $dir"
((SKIPPED++))
cd - > /dev/null || true
return 1
fi
# Get current branch name
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
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 || {
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
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
log "WARNING" "Skipping repository with inaccessible remote '$remote_name': $dir"
msg "Skipping repository with inaccessible remote: $dir"
((SKIPPED++))
cd - > /dev/null || true
return 1
fi
fi
# Check for unmerged files before attempting pull
if has_unmerged_files; then
log "WARNING" "Skipping repository with unmerged files: $dir"
msg "Skipping repository with unmerged files: $dir"
((UNMERGED++))
cd - > /dev/null || true
return 1
fi
# Configure Git arguments based on verbosity
git_args="--rebase --autostash --prune"
if [[ "$VERBOSE" -eq 0 ]]; then
git_args="$git_args --quiet"
fi
# Disable Git hints and set other environment variables
export GIT_MERGE_AUTOEDIT=no
export GIT_CONFIG_COUNT=4
export GIT_CONFIG_KEY_0="advice.skipHints"
export GIT_CONFIG_VALUE_0="true"
export GIT_CONFIG_KEY_1="advice.detachedHead"
export GIT_CONFIG_VALUE_1="false"
export GIT_CONFIG_KEY_2="advice.pushUpdateRejected"
export GIT_CONFIG_VALUE_2="false"
export GIT_CONFIG_KEY_3="advice.statusHints"
export GIT_CONFIG_VALUE_3="false"
# Capture the output of git pull
if [[ "$VERBOSE" -eq 1 ]]; then
# shellcheck disable=SC2086
output=$(git pull $git_args 2>&1)
exit_status=$?
# In verbose mode, show the git output
[[ "$QUIET" -eq 0 ]] && echo -e "\n$output\n"
log "DEBUG" "Git pull output: $output"
else
# In non-verbose mode, suppress normal output but capture errors
# shellcheck disable=SC2086
output=$(git pull $git_args 2>&1) || {
exit_status=$?
}
# If no error occurred, set exit_status to 0
exit_status=${exit_status:-0}
fi
# Unset environment variables
unset GIT_MERGE_AUTOEDIT GIT_CONFIG_COUNT \
GIT_CONFIG_KEY_0 GIT_CONFIG_KEY_1 \
GIT_CONFIG_KEY_2 GIT_CONFIG_KEY_3 \
GIT_CONFIG_VALUE_0 GIT_CONFIG_VALUE_1 \
GIT_CONFIG_VALUE_2 GIT_CONFIG_VALUE_3
# Check for specific error conditions
if echo "$output" | grep -q "Merge conflict"; then
if [[ "$VERBOSE" -eq 1 ]]; then
echo ""
echo -e "${YELLOW}Merge conflict detected in $dir. Aborting update.${NC}" >&2
fi
log "WARNING" "Merge conflict detected in $dir. Aborting update."
git rebase --abort &> /dev/null || git merge --abort &> /dev/null || true
((CONFLICTS++))
elif echo "$output" | grep -q "unmerged files"; then
if [[ "$VERBOSE" -eq 1 ]]; then
echo ""
echo -e "${YELLOW}Unmerged files detected in $dir. Aborting update.${NC}" >&2
fi
log "WARNING" "Unmerged files detected in $dir. Aborting update."
((UNMERGED++))
elif echo "$output" | grep -q "untracked working tree files would be overwritten by merge"; then
if [[ "$VERBOSE" -eq 1 ]]; then
echo ""
echo -e "${YELLOW}Untracked files would be overwritten in $dir. Aborting update.${NC}" >&2
fi
log "WARNING" "Untracked files would be overwritten in $dir. Aborting update."
((UNTRACKED++))
elif [[ $exit_status -ne 0 ]]; then
if [[ "$VERBOSE" -eq 1 || "$QUIET" -eq 0 ]]; then
echo ""
echo -e "${RED}Error updating $dir${NC}" >&2
echo "$output" >&2
fi
log "ERROR" "Failed to update $dir: $output"
((FAILED++))
else
# Check if any changes were pulled
if echo "$output" | grep -qE '(file changed|files changed|insertions|deletions)' \
|| ! echo "$output" | grep -q "Already up to date."; then
log "INFO" "Repository updated with changes: $dir"
((UPDATED++))
else
log "INFO" "Repository already up to date: $dir"
fi
((SUCCESS++))
# Clean up branches if requested
if [[ "$CLEANUP" -eq 1 ]]; then
cleaned_branches=$(cleanup_branches)
if [[ $cleaned_branches -gt 0 ]]; then
((BRANCHES_CLEANED += cleaned_branches))
log "INFO" "Cleaned up $cleaned_branches merged branches in $dir"
fi
fi
fi
# Return to original directory
cd - > /dev/null || true
# Show progress after completion
show_progress "$PROCESSED" "$TOTAL" "${dir%/} - Done"
}
# Main function to update all subfolder git repositories
main()
{
local current_dir start_time end_time duration
# Record start time
start_time=$(date +%s)
# Process command-line args before doing anything else
process_args "$@"
# Save current directory to return to it later
current_dir=$(pwd)
log "INFO" "Starting repository updates in $current_dir"
# Count repositories and set TOTAL
TOTAL=$(count_git_repos)
print "Found $TOTAL git repositories to update"
# Reset other counters
PROCESSED=0
SUCCESS=0
FAILED=0
CONFLICTS=0
UPDATED=0
SKIPPED=0
UNTRACKED=0
UNMERGED=0
BRANCHES_CLEANED=0
# Process each repository
for dir in */; do
# Skip if excluded
if excluded_path "$dir"; then
continue
fi
update_repo "$dir"
done
echo "Done."
echo ""
# Return to original directory
cd "$current_dir" || true
# Clear the progress line completely
[[ "$QUIET" -eq 0 ]] && printf "\r%-${TERM_WIDTH}s\r" " "
# Calculate duration
end_time=$(date +%s)
duration=$((end_time - start_time))
minutes=$((duration / 60))
seconds=$((duration % 60))
# Format duration nicely
if [[ $minutes -gt 0 ]]; then
duration_str="${minutes}m ${seconds}s"
else
duration_str="${seconds}s"
fi
# Print summary unless quiet mode is enabled
if [[ "$QUIET" -eq 0 ]]; then
echo ""
print "${GREEN}Summary: Updated $SUCCESS/$TOTAL repositories successfully in $duration_str.${NC}"
print "${CYAN}Repositories with changes pulled: $UPDATED${NC}"
if [[ $SKIPPED -gt 0 ]]; then
print "${YELLOW}Skipped $SKIPPED repositories (no tracking branch or other issues).${NC}"
fi
if [[ $UNMERGED -gt 0 ]]; then
print "${YELLOW}Skipped $UNMERGED repositories with unmerged files.${NC}"
fi
if [[ $UNTRACKED -gt 0 ]]; then
print "${YELLOW}Skipped $UNTRACKED repositories with untracked files that would be overwritten.${NC}"
fi
if [[ $CONFLICTS -gt 0 ]]; then
print "${YELLOW}Encountered merge conflicts in $CONFLICTS repositories.${NC}"
fi
if [[ $CLEANUP -eq 1 && $BRANCHES_CLEANED -gt 0 ]]; then
print "${BLUE}Cleaned up $BRANCHES_CLEANED merged branches.${NC}"
fi
if [[ $FAILED -gt 0 ]]; then
echo -e "${RED}Failed to update $FAILED repositories.${NC}" >&2
else
print "${GREEN}Done.${NC}"
fi
fi
# Log final summary
if [[ -n "$LOG_FILE" ]]; then
log "INFO" "Completed in $duration_str"
log "INFO" "Summary: $SUCCESS/$TOTAL repositories updated successfully"
log "INFO" "Repositories with changes pulled: $UPDATED"
log "INFO" "Skipped: $SKIPPED, Unmerged: $UNMERGED, Untracked: $UNTRACKED, Conflicts: $CONFLICTS, Failed: $FAILED"
if [[ $CLEANUP -eq 1 ]]; then
log "INFO" "Branches cleaned up: $BRANCHES_CLEANED"
fi
fi
# Return appropriate exit code
[[ $FAILED -gt 0 ]] && return 1 || return 0
}
# Call main with all arguments
main "$@"

View File

@@ -0,0 +1,116 @@
# git-update-dirs
A tool that efficiently updates all Git repositories in subdirectories
of the current folder.
## Overview
`git-update-dirs` scans the current directory for Git repositories
and updates them with:
- Fast parallel execution
- Intelligent error handling
- Progress visualization
- Detailed logging
- Optional branch cleanup
## Installation
Place the script in your PATH and make it executable:
```bash
# Using wget
wget -O ~/bin/git-update-dirs https://raw.githubusercontent.com/ivuorinen/dotfiles/main/local/bin/git-update-dirs
chmod +x ~/bin/git-update-dirs
# Or simply copy the script to a location in your PATH
cp git-update-dirs ~/bin/
chmod +x ~/bin/git-update-dirs
```
## Usage
```text
Usage: git-update-dirs [OPTIONS]
Updates all git repositories in subdirectories.
Options:
--help, -h Display this help message and exit
--version, -v Display version information and exit
--verbose Display detailed output
--quiet, -q Suppress all output except errors
--exclude DIR Exclude directory from updates
(can be used multiple times)
--cleanup Remove local branches that have been merged into
current branch
--config FILE Read options from configuration file
--log FILE Log details and errors to FILE
Environment variables:
VERBOSE Set to 1 to enable verbose output
EXCLUDE_DIRS Space-separated list of directories to exclude
```
## Examples
Basic usage to update all repositories:
```bash
git-update-dirs
```
Update with detailed output:
```bash
git-update-dirs --verbose
```
Exclude specific directories:
```bash
git-update-dirs --exclude node_modules --exclude vendor
```
Update and clean up merged branches:
```bash
git-update-dirs --cleanup
```
Use options from a configuration file:
```bash
git-update-dirs --config ~/.gitupdate.conf
```
## Configuration File
You can create a configuration file to store your preferred options:
```text
# Example ~/.gitupdate.conf
verbose
exclude node_modules
exclude vendor
cleanup
log ~/.gitupdate.log
```
## Features
- **Smart Updates**: Uses `--rebase --autostash --prune`
for clean updates
- **Error Handling**: Skips repositories with conflicts or
untracked files that would be overwritten
- **Visual Progress**: Shows a progress bar with current status
- **Repository Management**: Optionally cleans up merged branches
- **Detailed Logging**: Records all operations with timestamps
## License
[MIT License][MIT] - Copyright 2023 Ismo Vuorinen
[MIT]: https://opensource.org/license/mit/
<!-- vim: set ft=markdown cc=80 : -->

443
local/bin/php-switcher Executable file
View File

@@ -0,0 +1,443 @@
#!/usr/bin/env bash
#
# Brew PHP Switcher
#
# Use to switch between PHP versions installed via Homebrew.
#
# Usage: php-switcher <version> [--help|--installed|--current|--auto]
# Example: php-switcher 7.4
# Example: php-switcher 8.0
# Example: php-switcher latest
# Example: php-switcher --auto
#
# Created by Ismo Vuorinen <https://github.com/ivuorinen> (2025)
# Licensed under the MIT License (https://opensource.org/licenses/MIT)
set -euo pipefail # Add error handling
# Configuration
LATEST_VERSION_FORMULA="php" # The formula name for latest PHP version
PHP_VERSION_FILE=".php-version" # File name to look for when auto-switching
# Switch brew php version
function check_dependencies()
{
if ! command -v brew > /dev/null 2>&1; then
echo "Error: Homebrew is not installed"
exit 1
fi
}
function usage()
{
echo "Brew PHP Switcher - Switch between PHP versions installed via Homebrew"
echo ""
echo "Usage: php-switcher <version> [options]"
echo ""
echo "Options:"
echo " --help Show this help message"
echo " --installed List installed PHP versions"
echo " --current Show currently active PHP version"
echo " --auto Auto-switch based on .php-version file in current directory"
echo ""
echo "Examples:"
echo " php-switcher 7.4"
echo " php-switcher 8.0"
echo " php-switcher latest"
echo " php-switcher --auto"
echo ""
echo "Auto-switching:"
echo " Create a .php-version file in your project directory with a PHP version"
echo " Example .php-version content: 8.1"
echo ""
exit 0
}
function list_php_versions()
{
# Check Homebrew's installation path for PHP versions
local brew_cellar
brew_cellar="$(brew --cellar)"
local php_paths=()
local versions=()
local formulas=()
local active=()
# Look for all PHP installations in Homebrew Cellar
if [[ -d "$brew_cellar/php" ]]; then
php_paths+=("$brew_cellar/php")
fi
# Look for versioned PHP installations
while IFS= read -r dir; do
if [[ -d $dir ]]; then
php_paths+=("$dir")
fi
done < <(find "$brew_cellar" \
-maxdepth 1 -name 'php@*' \
-type d 2> /dev/null || echo "")
if [[ ${#php_paths[@]} -eq 0 ]]; then
echo "No PHP versions installed through Homebrew."
return 1
fi
# Find which version is currently linked
local current_bin
current_bin=$(readlink -f \
"$(command -v php 2> /dev/null)" \
2> /dev/null || echo "")
# Collect data for each installed PHP version
for path in "${php_paths[@]}"; do
local formula
formula=$(basename "$path")
local version_label
if [[ $formula == "php" ]]; then
version_label="latest"
else
version_label="${formula#php@}"
fi
# Find the actual version from the directory structure
local version_dir
version_dir=$(find "$path" -maxdepth 1 -type d \
| grep -v "^$path$" | sort -V | tail -1)
if [[ -n $version_dir && -d "$version_dir/bin" ]]; then
local full_version
full_version=$("$version_dir/bin/php" -v 2> /dev/null \
| grep -oE 'PHP [0-9]+\.[0-9]+\.[0-9]+' \
| head -1 \
| cut -d' ' -f2 \
|| echo "$version_label.x")
# Determine if this is the active version
local is_active="No"
if [[ -n $current_bin && $current_bin == "$version_dir/bin/php" ]]; then
is_active="Yes"
fi
# Handle the 'latest' case - replace with actual version number
local display_version
if [[ $version_label == "latest" ]]; then
display_version="${full_version%.*}" # Get major.minor version
else
display_version="$version_label"
fi
# Store data for table display
versions+=("$display_version")
formulas+=("$formula")
active+=("$is_active")
fi
done
# Calculate maximum column widths
local max_version_width=7 # "Version" header length
local max_formula_width=7 # "Formula" header length
local max_active_width=6 # "Active" header length
local count=${#versions[@]}
for ((i = 0; i < count; i++)); do
# Update max widths if needed
if [[ ${#versions[i]} -gt $max_version_width ]]; then
max_version_width=${#versions[i]}
fi
if [[ ${#formulas[i]} -gt $max_formula_width ]]; then
max_formula_width=${#formulas[i]}
fi
done
# Build header with correct widths
local header_format="| %-${max_version_width}s | %-${max_formula_width}s | "
header_format+="%-${max_active_width}s |"
local separator_line="|"
for ((i = 0; i < max_version_width + 2; i++)); do
separator_line="${separator_line}-"
done
separator_line="${separator_line}|"
for ((i = 0; i < max_formula_width + 2; i++)); do
separator_line="${separator_line}-"
done
separator_line="${separator_line}|"
for ((i = 0; i < max_active_width + 2; i++)); do
separator_line="${separator_line}-"
done
separator_line="${separator_line}|"
# Print table header
# shellcheck disable=SC2059
printf "$header_format\n" "Version" "Formula" "Active"
echo "$separator_line"
# Print table rows
local row_format="| %-${max_version_width}s | %-${max_formula_width}s | "
row_format+="%-${max_active_width}s |"
for ((i = 0; i < count; i++)); do
# shellcheck disable=SC2059
printf "$row_format\n" "${versions[i]}" "${formulas[i]}" "${active[i]}"
done
}
function get_php_formula_for_version()
{
local version="$1"
# Handle "latest" as a special case
if [[ $version == "latest" ]]; then
echo "$LATEST_VERSION_FORMULA"
return 0
fi
# The regular version case (e.g., 7.4, 8.1)
echo "php@$version"
}
function check_formula_installed()
{
local formula="$1"
local brew_cellar
brew_cellar="$(brew --cellar)"
if [[ $formula == "php" ]]; then
if [[ -d "$brew_cellar/php" ]]; then
return 0
fi
elif [[ -d "$brew_cellar/$formula" ]]; then
return 0
fi
return 1
}
function unlink_current_php()
{
local current_formula=""
# Find formulas more safely
while IFS= read -r formula; do
if [[ -n $formula ]]; then
local linked
linked=$(brew info --json=v1 "$formula" \
| grep -o '"linked_keg":"[^"]*"' \
| grep -v ':"null"')
if [[ -n $linked ]]; then
current_formula="$formula"
break
fi
fi
done < <(brew list --formula | grep -E '^php(@[0-9]+\.[0-9]+)?$' || echo "")
# If we found a linked formula, unlink it
if [[ -n $current_formula ]]; then
echo "Unlinking current PHP version ($current_formula)..."
brew unlink "$current_formula" > /dev/null 2>&1 || true
fi
}
function link_php_version()
{
local formula="$1"
if ! check_formula_installed "$formula"; then
echo "Error: PHP formula '$formula' is not installed"
echo "Available versions:"
list_php_versions
exit 1
fi
echo "Linking $formula..."
if ! brew link --force --overwrite "$formula" > /dev/null 2>&1; then
echo "Error: Failed to link $formula. Try running manually:"
echo " brew link --force --overwrite $formula"
exit 1
fi
# Verify the switch worked
if ! command -v php > /dev/null 2>&1; then
echo "Warning: PHP was linked but may not be working correctly"
fi
}
function get_current_version()
{
if ! command -v php > /dev/null 2>&1; then
echo "No PHP currently linked"
return 1
fi
local version
version=$(php -v 2> /dev/null \
| grep -oE 'PHP [0-9]+\.[0-9]+\.[0-9]+' \
| head -1)
if [[ -z $version ]]; then
echo "Unable to determine PHP version"
return 1
fi
# Find the corresponding formula
local current_version
current_version=$(echo "$version" | cut -d' ' -f2)
local major_minor
major_minor=$(echo "$current_version" | cut -d'.' -f1,2)
# Check if it's the latest version
if check_formula_installed "php" \
&& brew info --json=v1 php \
| grep -o '"linked_keg":"[^"]*"' \
| grep -v ':"null"' \
| grep -q .; then
echo "Current PHP version: $current_version (latest)"
else
echo "Current PHP version: $current_version (php@$major_minor)"
fi
}
function validate_version()
{
local version="$1"
# Valid formats: x.y or latest
if [[ ! $version =~ ^([0-9]+\.[0-9]+|latest)$ ]]; then
echo "Error: Invalid PHP version format. Use x.y format (e.g., 7.4) or"
echo " 'latest'"
exit 1
fi
}
function find_php_version_file()
{
local dir="$PWD"
# Look for .php-version file in current directory and all parent directories
while [[ $dir != "/" ]]; do
if [[ -f "$dir/$PHP_VERSION_FILE" ]]; then
echo "$dir/$PHP_VERSION_FILE"
return 0
fi
dir=$(dirname "$dir")
done
# Check the root directory as well
if [[ -f "/$PHP_VERSION_FILE" ]]; then
echo "/$PHP_VERSION_FILE"
return 0
fi
return 1
}
function auto_switch_php_version()
{
local version_file
# Try to find a .php-version file
version_file=$(find_php_version_file) || {
echo "No .php-version file found in current directory or any parent"
echo "directory. Create a $PHP_VERSION_FILE file with your desired"
echo "PHP version (e.g., 8.1)"
exit 1
}
# Read the version from the file
local version
version=$(tr -d '[:space:]' < "$version_file")
echo "Found $PHP_VERSION_FILE file at: $version_file"
echo "Requested PHP version: $version"
# Validate the version
validate_version "$version"
# Switch to the specified version
switch_php_version "$version"
}
function switch_php_version()
{
local version="$1"
# Get the formula name for the version
local formula
formula=$(get_php_formula_for_version "$version")
# Check if the requested PHP version is installed
if ! check_formula_installed "$formula"; then
echo "Error: PHP version $version is not installed"
echo ""
list_php_versions
exit 1
fi
# Get the current version info for comparison
local current_info
current_info=$(get_current_version 2> /dev/null || echo "None")
# Skip if we're already on the requested version
if [[ $current_info == *"$version"* ]]; then
echo "PHP version $version is already active"
exit 0
fi
# Perform the switch
unlink_current_php
link_php_version "$formula"
# Verify the switch
echo ""
echo "Switched to:"
get_current_version
echo ""
echo "PHP executable: $(command -v php)"
}
function main()
{
local version=""
# Parse arguments
case "${1:-}" in
--help)
usage
;;
--installed)
list_php_versions
exit 0
;;
--current)
get_current_version
exit 0
;;
--auto)
auto_switch_php_version
exit 0
;;
"")
usage
;;
*)
version="$1"
;;
esac
# Validate and switch to the specified version
validate_version "$version"
switch_php_version "$version"
}
# Run the script
check_dependencies
if [[ ${#@} -eq 0 ]]; then
usage
else
main "$@"
fi
# vim: ft=bash sw=4 ts=4 et tw=80 cc=80 :

View File

@@ -1,49 +0,0 @@
#!/usr/bin/swift
// Required parameters:
// @raycast.schemaVersion 1
// @raycast.title Zalgo Text
// @raycast.mode silent
// @raycast.author Adam Zethraeus
// @raycast.authorURL https://github.com/adam-zethraeus
// @raycast.packageName Conversions
// @raycast.icon 👹
// @raycast.argument1 { "type": "text", "placeholder": "Text to Z̶̶͚̯͗a̩̞͜͜l̫͕ͬͨ̿g͈̫͂ͤ͆͢o̠͚̞ͥ" }
// @raycast.argument2 { "type": "text", "optional": true, "placeholder": "Intensity=5" }
// Documentation:
// @raycast.description Converts text to z̫̫̐a̳ͩl̓͂̀ͅg͔̚o̷̦̣͢ t̳͆ḛ̊͟ẍ̮̝́t̵̔ͯ͝
import Cocoa
// zalgo function credit mattt @ https://gist.github.com/mattt/b46ab5027f1ee6ab1a45583a41240033
func zalgo(_ string: String, intensity: Int = 5) -> String {
let combiningDiacriticMarks = 0x0300...0x036f
let latinAlphabetUppercase = 0x0041...0x005a
let latinAlphabetLowercase = 0x0061...0x007a
var output: [UnicodeScalar] = []
for scalar in string.unicodeScalars {
output.append(scalar)
guard (latinAlphabetUppercase).contains(numericCast(scalar.value)) ||
(latinAlphabetLowercase).contains(numericCast(scalar.value))
else {
continue
}
for _ in 0...(Int.random(in: 1...intensity)) {
let randomScalarValue = Int.random(in: combiningDiacriticMarks)
output.append(Unicode.Scalar(randomScalarValue)!)
}
}
return String(String.UnicodeScalarView(output))
}
NSPasteboard.general.clearContents()
let text = CommandLine.arguments[1]
let intensityString = CommandLine.arguments[2]
let intensity = Int(intensityString) ?? 5
let zalgoText = zalgo(text, intensity: intensity)
NSPasteboard.general.setString(zalgoText, forType: .string)
print("\(zalgoText) copied to clipboard")

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
#
# Check git repo's files .gitattributes and ensure all of them are mapped.
# Ismo Vuorinen <https://github.com/ivuorinen> 2022
source "${DOTFILES}/config/shared.sh"
set -euo pipefail
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Function to check if git is installed
check_git_installed()
{
if ! command -v git &> /dev/null; then
msg_err "git could not be found, please install it first"
fi
}
# Function to check for missing .gitattributes
check_gitattributes()
{
local missing_attributes
missing_attributes=$(git ls-files | git check-attr -a --stdin | grep "text: auto" || true)
if [[ -n "$missing_attributes" ]]; then
echo ".gitattributes rule missing for the following files:"
echo "$missing_attributes"
else
echo "All files have a corresponding rule in .gitattributes"
fi
}
# Main function
main()
{
check_git_installed
check_gitattributes
}
main "$@"

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);
}

View File

@@ -1,38 +1,66 @@
#!/usr/bin/env bash
#
# Get latest release version, branch tag, or latest commit from GitHub
# Usage: x-gh-get-latest-version <repo>
# Usage: x-gh-get-latest-version <repo> [options]
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
set -euo pipefail
# Environment variables, more under get_release_version() and get_latest_branch_tag()
# functions. These can be overridden by the user.
# Environment variables, can be overridden by command line arguments
GITHUB_API_URL="${GITHUB_API_URL:-https://api.github.com/repos}"
VERBOSE="${VERBOSE:-0}"
INCLUDE_PRERELEASES="${INCLUDE_PRERELEASES:-0}"
OLDEST_RELEASE="${OLDEST_RELEASE:-0}"
BRANCH=""
LATEST_COMMIT="${LATEST_COMMIT:-0}"
LATEST_TAG="${LATEST_TAG:-0}"
OUTPUT="${OUTPUT:-text}"
SHOW_HELP=0
REPOSITORY=""
COMBINED=0
BIN=$(basename "$0")
# Prints a message if VERBOSE=1
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
if [[ $VERBOSE -eq 1 ]]; then
echo "$1" >&2
fi
}
# Show usage information
usage()
{
cat << EOF
Usage: $0 <repo> (e.g. ivuorinen/dotfiles)
Usage: $BIN <repo> [options]
Fetches the latest release version, latest branch tag, or latest commit SHA from GitHub.
Arguments:
<repo> Repository in format 'owner/repo' (e.g. ivuorinen/dotfiles)
Options:
- INCLUDE_PRERELEASES=1 Include prerelease versions (default: only stable releases).
- OLDEST_RELEASE=1 Fetch the oldest release instead of the latest.
- BRANCH=<branch> Fetch the latest tag from a specific branch (default: main).
- LATEST_COMMIT=1 Fetch the latest commit SHA from the specified branch.
- OUTPUT=json Return output as JSON (default: plain text).
- GITHUB_API_URL=<url> Override GitHub API URL (useful for GitHub Enterprise).
- GITHUB_TOKEN=<token> Use GitHub API token to increase rate limits (default: unauthenticated).
-h, --help Show this help message and exit
-v, --verbose Enable verbose output
-p, --prereleases Include prerelease versions (default: only stable releases)
-o, --oldest Fetch the oldest release instead of the latest
-b, --branch <branch> Fetch the latest tag from a specific branch (default: main)
-c, --commit Fetch the latest commit SHA from the specified branch
-t, --tag Fetch the latest Git tag (any branch)
-j, --json Return output as JSON (default: plain text)
-a, --all Fetch all information types in a combined output
Environment Variables (can be used instead of command line options):
- INCLUDE_PRERELEASES=1 Same as --prereleases
- OLDEST_RELEASE=1 Same as --oldest
- BRANCH=<branch> Same as --branch <branch>
- LATEST_COMMIT=1 Same as --commit
- LATEST_TAG=1 Same as --tag
- OUTPUT=json Same as --json
- GITHUB_API_URL=<url> Override GitHub API URL (useful for GitHub Enterprise)
- GITHUB_TOKEN=<token> Use GitHub API token to increase rate limits (default: unauthenticated)
- VERBOSE=1 Same as --verbose
Requirements:
- curl
@@ -40,28 +68,34 @@ Requirements:
Examples:
# Fetch the latest stable release
$0 ivuorinen/dotfiles
$BIN ivuorinen/dotfiles
# Fetch the latest release including prereleases
INCLUDE_PRERELEASES=1 $0 ivuorinen/dotfiles
$BIN ivuorinen/dotfiles --prereleases
# Fetch the oldest release
OLDEST_RELEASE=1 $0 ivuorinen/dotfiles
$BIN ivuorinen/dotfiles --oldest
# Fetch the latest tag from the 'develop' branch
BRANCH=develop $0 ivuorinen/dotfiles
$BIN ivuorinen/dotfiles --branch develop
# Fetch the latest commit SHA from 'main' branch
LATEST_COMMIT=1 $0 ivuorinen/dotfiles
$BIN ivuorinen/dotfiles --commit
# Fetch the latest Git tag (any branch)
$BIN ivuorinen/dotfiles --tag
# Fetch all information types in a combined output
$BIN ivuorinen/dotfiles --all
# Output result in JSON format
OUTPUT=json $0 ivuorinen/dotfiles
$BIN ivuorinen/dotfiles --json
# Use GitHub API token for higher rate limits
GITHUB_TOKEN="your_personal_access_token" $0 ivuorinen/dotfiles
GITHUB_TOKEN="your_personal_access_token" $BIN ivuorinen/dotfiles
# Use GitHub Enterprise API
GITHUB_API_URL="https://github.example.com/api/v3/repos" $0 ivuorinen/dotfiles
GITHUB_API_URL="https://github.example.com/api/v3/repos" $BIN ivuorinen/dotfiles
EOF
exit 1
}
@@ -77,6 +111,140 @@ check_dependencies()
done
}
# Check GitHub API rate limits and warn if they're getting low
check_rate_limits()
{
local auth_status="unauthenticated"
local auth_header=()
if [[ -n ${GITHUB_TOKEN:-} ]]; then
auth_status="authenticated"
auth_header=(-H "Authorization: token $GITHUB_TOKEN")
fi
msg "Making $auth_status GitHub API requests"
local rate_limit_info
rate_limit_info=$(curl -sSL "${auth_header[@]}" "https://api.github.com/rate_limit")
local remaining
local reset_timestamp
local reset_time
remaining=$(echo "$rate_limit_info" | jq -r '.resources.core.remaining')
reset_timestamp=$(echo "$rate_limit_info" | jq -r '.resources.core.reset')
# Handle date command differences between Linux and macOS
if date --version > /dev/null 2>&1; then
# GNU date (Linux)
reset_time=$(date -d "@$reset_timestamp" "+%H:%M:%S %Z" 2> /dev/null)
else
# BSD date (macOS)
reset_time=$(date -r "$reset_timestamp" "+%H:%M:%S %Z" 2> /dev/null)
fi
msg "Rate limit status: $remaining requests remaining, reset at $reset_time"
if [[ $remaining -le 5 ]]; then
echo "Warning: GitHub API rate limit nearly reached ($remaining requests left)" >&2
echo "Rate limits will reset at: $reset_time" >&2
if [[ $auth_status == "unauthenticated" ]]; then
echo "Tip: Set GITHUB_TOKEN to increase your rate limits (60 → 5000 requests/hour)" >&2
fi
fi
}
# Make a GitHub API request with proper error handling
api_request()
{
local url="$1"
local auth_header=()
if [[ -n ${GITHUB_TOKEN:-} ]]; then
auth_header=(-H "Authorization: token $GITHUB_TOKEN")
fi
local response
local status_code
# Use a temporary file to capture both headers and body
local tmp_file
tmp_file=$(mktemp)
msg "Making API request to: $url"
status_code=$(curl -sSL -w "%{http_code}" -o "$tmp_file" "${auth_header[@]}" "$url")
response=$(< "$tmp_file")
rm -f "$tmp_file"
# Check for HTTP errors
if [[ $status_code -ge 400 ]]; then
local error_msg
error_msg=$(echo "$response" | jq -r '.message // "Unknown error"')
if [[ $status_code -eq 403 && $error_msg == *"API rate limit exceeded"* ]]; then
# Extract rate limit reset info
local reset_timestamp
reset_timestamp=$(echo "$response" | jq -r '.rate.reset // empty')
local reset_time
if date --version > /dev/null 2>&1; then
# GNU date (Linux)
reset_time=$(date -d "@$reset_timestamp" "+%H:%M:%S %Z" 2> /dev/null \
|| echo "unknown time")
else
# BSD date (macOS)
reset_time=$(date -r "$reset_timestamp" "+%H:%M:%S %Z" 2> /dev/null \
|| echo "unknown time")
fi
echo "Error: GitHub API rate limit exceeded" >&2
echo "Rate limit will reset at: $reset_time" >&2
if [[ -z ${GITHUB_TOKEN:-} ]]; then
echo "Tip: Set GITHUB_TOKEN to increase your rate limits (60 → 5000 requests/hour)" >&2
else
echo "You've exceeded even authenticated rate limits (5000 requests/hour)" >&2
fi
exit 3
elif [[ $status_code -eq 404 ]]; then
echo "Error: Repository not found or no access permission: $url" >&2
exit 2
else
echo "GitHub API error ($status_code): $error_msg" >&2
exit 1
fi
fi
echo "$response"
}
# Check if repository exists before proceeding
check_repository()
{
local repo="$1"
local api_url="${GITHUB_API_URL}/${repo}"
msg "Checking if repository exists: $api_url"
local response
response=$(api_request "$api_url")
# If we got here, the repository exists (otherwise api_request would have exited)
msg "Repository found: $(echo "$response" | jq -r '.full_name')"
# Get default branch if no branch is specified
if [[ -z ${BRANCH} ]]; then
BRANCH=$(echo "$response" | jq -r '.default_branch')
msg "Using default branch: $BRANCH"
fi
# Return the repository full name (in case it differs from input due to redirects)
echo "$response" | jq -r '.full_name'
}
# Fetches the latest release or the oldest if OLDEST_RELEASE=1
# $1 - GitHub repository (string)
get_release_version()
@@ -86,38 +254,55 @@ get_release_version()
local oldest_release="${OLDEST_RELEASE:-0}"
local api_url="${GITHUB_API_URL}/${repo}/releases"
local auth_header=()
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
auth_header=(-H "Authorization: token $GITHUB_TOKEN")
fi
msg "Fetching release data from: $api_url (Include prereleases: $include_prereleases, Oldest: $oldest_release)"
msg "Fetching release data from: $api_url " + \
"(Include prereleases: $include_prereleases, Oldest: $oldest_release)"
local json_response
json_response=$(curl -sSL "${auth_header[@]}" "$api_url")
json_response=$(api_request "$api_url")
# Check for API errors
if echo "$json_response" | jq -e 'has("message")' > /dev/null; then
msg "GitHub API error: $(echo "$json_response" | jq -r '.message')"
exit 1
fi
local version=""
local prerelease_version=""
local filter='.[] | select(.tag_name)'
[[ "$include_prereleases" -eq 0 ]] && filter+='.prerelease == false'
local version
if [[ "$oldest_release" -eq 1 ]]; then
version=$(echo "$json_response" | jq -r "[${filter}] | last.tag_name // empty")
# Get stable release version
if [[ $oldest_release -eq 1 ]]; then
version=$(echo "$json_response" \
| jq -r '[.[] | select(.tag_name != null and .prerelease == false)] | sort_by(.created_at) | first.tag_name // empty')
else
version=$(echo "$json_response" | jq -r "[${filter}] | first.tag_name // empty")
version=$(echo "$json_response" \
| jq -r '[.[] | select(.tag_name != null and .prerelease == false)] | sort_by(.created_at) | reverse | first.tag_name // empty')
fi
if [[ -z "$version" ]]; then
msg "Failed to fetch release version for repository: $repo"
# Get prerelease version if requested
if [[ $include_prereleases -eq 1 ]]; then
if [[ $oldest_release -eq 1 ]]; then
prerelease_version=$(echo "$json_response" \
| jq -r '[.[] | select(.tag_name != null and .prerelease == true)] | sort_by(.created_at) | first.tag_name // empty')
else
prerelease_version=$(echo "$json_response" \
| jq -r '[.[] | select(.tag_name != null and .prerelease == true)] | sort_by(.created_at) | reverse | first.tag_name // empty')
fi
fi
# Error if no releases found and we're not in combined mode
if [[ -z $version && -z $prerelease_version && $COMBINED -eq 0 ]]; then
echo "No releases found for repository: $repo" >&2
exit 1
fi
echo "$version"
# Return both values for combined output
if [[ $COMBINED -eq 1 ]]; then
echo "$version"
echo "$prerelease_version"
else
# Return prerelease if specifically requested, otherwise stable
if [[ $include_prereleases -eq 1 && -n $prerelease_version ]]; then
msg "Found prerelease version: $prerelease_version"
echo "$prerelease_version"
else
msg "Found stable release version: $version"
echo "$version"
fi
fi
}
# Fetches the latest tag from the specified branch
@@ -130,16 +315,42 @@ get_latest_branch_tag()
msg "Fetching latest tag for branch '$branch' from: $api_url"
local json_response
json_response=$(curl -sSL "$api_url")
json_response=$(api_request "$api_url")
local version
version=$(echo "$json_response" | jq -r "[.[] | select(.ref | contains(\"refs/tags/$branch\"))] | last.ref | sub(\"refs/tags/\"; \"\") // empty")
version=$(echo "$json_response" \
| jq -r "[.[] | select(.ref | contains(\"refs/tags/$branch\"))] | sort_by(.ref) | reverse | first.ref | sub(\"refs/tags/\"; \"\") // empty")
if [[ -z "$version" ]]; then
msg "Failed to fetch latest tag for branch: $branch"
if [[ -z $version && $COMBINED -eq 0 ]]; then
echo "No tags found for branch: $branch in repository: $repo" >&2
exit 1
fi
msg "Found branch tag: $version"
echo "$version"
}
# Fetches the latest Git tag (regardless of branch)
get_latest_git_tag()
{
local repo="$1"
local api_url="${GITHUB_API_URL}/${repo}/git/refs/tags"
msg "Fetching latest Git tag from: $api_url"
local json_response
json_response=$(api_request "$api_url")
local version
version=$(echo "$json_response" \
| jq -r '[.[] | select(.ref | startswith("refs/tags/"))] | sort_by(.ref) | reverse | first.ref | sub("refs/tags/"; "") // empty')
if [[ -z $version && $COMBINED -eq 0 ]]; then
echo "No Git tags found in repository: $repo" >&2
exit 1
fi
msg "Found Git tag: $version"
echo "$version"
}
@@ -153,42 +364,240 @@ get_latest_commit()
msg "Fetching latest commit SHA from: $api_url"
local json_response
json_response=$(curl -sSL "$api_url")
json_response=$(api_request "$api_url")
local sha
sha=$(echo "$json_response" | jq -r '.sha // empty')
if [[ -z "$sha" ]]; then
msg "Failed to fetch latest commit SHA for branch: $branch"
if [[ -z $sha && $COMBINED -eq 0 ]]; then
echo "Failed to fetch latest commit SHA for branch: $branch in repository: $repo" >&2
exit 1
fi
msg "Found commit SHA: $sha"
echo "$sha"
}
# Format combined text output
format_combined_text()
{
local repo="$1"
local branch="$2"
local tag="$3"
local commit="$4"
local release="$5"
local prerelease="$6"
echo "Repository: $repo"
if [[ -n $branch ]]; then
echo "Branch: $branch"
fi
if [[ -n $tag ]]; then
echo "Git Tag: $tag"
fi
if [[ -n $commit ]]; then
echo "Commit: $commit"
fi
if [[ -n $prerelease ]]; then
echo "Prerelease: $prerelease"
fi
if [[ -n $release ]]; then
echo "Release: $release"
fi
}
# Format combined JSON output
format_combined_json()
{
local repo="$1"
local branch="$2"
local tag="$3"
local commit="$4"
local release="$5"
local prerelease="$6"
local json="{"
json+="\"repository\":\"$repo\""
if [[ -n $branch ]]; then
json+=",\"branch\":\"$branch\""
fi
if [[ -n $tag ]]; then
json+=",\"tag\":\"$tag\""
fi
if [[ -n $commit ]]; then
json+=",\"commit\":\"$commit\""
fi
if [[ -n $prerelease ]]; then
json+=",\"prerelease\":\"$prerelease\""
fi
if [[ -n $release ]]; then
json+=",\"release\":\"$release\""
fi
json+="}"
echo "$json"
}
# Parse command line arguments
parse_arguments()
{
# If no arguments provided, show usage
if [[ $# -eq 0 ]]; then
usage
fi
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-h | --help)
SHOW_HELP=1
shift
;;
-v | --verbose)
VERBOSE=1
shift
;;
-p | --prereleases)
INCLUDE_PRERELEASES=1
shift
;;
-o | --oldest)
OLDEST_RELEASE=1
shift
;;
-b | --branch)
if [[ $# -lt 2 ]]; then
echo "Error: --branch option requires a branch name" >&2
exit 1
fi
BRANCH="$2"
shift 2
;;
-c | --commit)
LATEST_COMMIT=1
shift
;;
-t | --tag)
LATEST_TAG=1
shift
;;
-j | --json)
OUTPUT="json"
shift
;;
-a | --all)
COMBINED=1
shift
;;
-*)
echo "Error: Unknown option: $1" >&2
usage
;;
*)
# If repository is already set, this is an error
if [[ -n $REPOSITORY ]]; then
echo "Error: Unexpected argument: $1" >&2
usage
fi
REPOSITORY="$1"
shift
;;
esac
done
# Validate that we have a repository
if [[ -z $REPOSITORY && $SHOW_HELP -eq 0 ]]; then
echo "Error: Repository argument is required" >&2
usage
fi
}
# Main function
# $1 - GitHub repository (string)
main()
{
if [[ $# -ne 1 ]]; then
# Parse command line arguments
parse_arguments "$@"
# Show help if requested
if [[ $SHOW_HELP -eq 1 ]]; then
usage
fi
check_dependencies
local repo="$1"
local result
# Check rate limits before making other API calls
check_rate_limits
if [[ "${LATEST_COMMIT:-0}" -eq 1 ]]; then
result=$(get_latest_commit "$repo")
elif [[ -n "${BRANCH:-}" ]]; then
result=$(get_latest_branch_tag "$repo")
else
result=$(get_release_version "$repo")
# Validate repository existence and get normalized repository name
local repo_fullname
repo_fullname=$(check_repository "$REPOSITORY")
# If --all specified, get all information types
if [[ $COMBINED -eq 1 ]]; then
local branch="${BRANCH:-main}"
local git_tag=""
local commit_sha=""
local release_version=""
local prerelease_version=""
# Get Git tag if requested
git_tag=$(get_latest_git_tag "$repo_fullname")
# Get commit SHA
commit_sha=$(get_latest_commit "$repo_fullname")
# Get release versions (stable and prerelease)
read -r release_version prerelease_version < <(get_release_version "$repo_fullname")
# Format output based on selected format
if [[ $OUTPUT == "json" ]]; then
format_combined_json \
"$repo_fullname" \
"$branch" \
"$git_tag" \
"$commit_sha" \
"$release_version" \
"$prerelease_version"
else
format_combined_text \
"$repo_fullname" \
"$branch" \
"$git_tag" \
"$commit_sha" \
"$release_version" \
"$prerelease_version"
fi
exit 0
fi
if [[ "${OUTPUT:-text}" == "json" ]]; then
echo "{\"repository\": \"$repo\", \"result\": \"$result\"}"
# Not combined mode - get only the requested information type
local result=""
if [[ $LATEST_COMMIT -eq 1 ]]; then
result=$(get_latest_commit "$repo_fullname")
elif [[ $LATEST_TAG -eq 1 ]]; then
result=$(get_latest_git_tag "$repo_fullname")
elif [[ -n $BRANCH ]]; then
result=$(get_latest_branch_tag "$repo_fullname")
else
result=$(get_release_version "$repo_fullname")
fi
# Output the result in the requested format
if [[ $OUTPUT == "json" ]]; then
echo "{\"repository\": \"$repo_fullname\", \"result\": \"$result\"}"
else
echo "$result"
fi

View File

@@ -0,0 +1,196 @@
# GitHub Latest Version Fetcher
`x-gh-get-latest-version` is a versatile command-line tool for fetching the
latest version information from GitHub repositories. It can retrieve release
versions, Git tags, branch tags, and commit SHAs with simple commands.
## Features
- Fetch latest or oldest stable releases
- Include prerelease versions
- Get latest Git tags from any branch
- Fetch latest commit SHA from a specific branch
- Output in plain text or JSON format
- Combined output mode to get all information at once
- Rate limit checking to avoid GitHub API throttling
- Authenticated requests with GitHub token support
## Requirements
- `curl` for making HTTP requests
- `jq` for processing JSON responses
- A GitHub personal access token
(optional, but recommended to avoid rate limiting)
## Installation
1. Save the script to a location in your PATH
2. Make it executable: `chmod +x x-gh-get-latest-version`
3. Optionally set up a GitHub token as an environment variable:
```bash
export GITHUB_TOKEN="your_personal_access_token"
```
## Usage
```text
Usage: x-gh-get-latest-version <repo> [options]
Arguments:
<repo> Repository in format 'owner/repo' (e.g. ivuorinen/dotfiles)
Options:
-h, --help Show this help message and exit
-v, --verbose Enable verbose output
-p, --prereleases Include prerelease versions (default: only stable releases)
-o, --oldest Fetch the oldest release instead of the latest
-b, --branch <branch> Fetch the latest tag from a specific branch (default: main)
-c, --commit Fetch the latest commit SHA from the specified branch
-t, --tag Fetch the latest Git tag (any branch)
-j, --json Return output as JSON (default: plain text)
-a, --all Fetch all information types in a combined output
```
## Examples
### Fetch the Latest Release Version
```bash
x-gh-get-latest-version ivuorinen/dotfiles
```
Output: `v1.2.3`
### Include Prereleases
```bash
x-gh-get-latest-version ivuorinen/dotfiles --prereleases
```
Output: `v1.3.0-rc.1`
### Get the Oldest Release
```bash
x-gh-get-latest-version ivuorinen/dotfiles --oldest
```
Output: `v0.1.0`
### Fetch from a Specific Branch
```bash
x-gh-get-latest-version ivuorinen/dotfiles --branch develop
```
Output: `develop-v1.3.0`
### Get Latest Commit SHA
```bash
x-gh-get-latest-version ivuorinen/dotfiles --commit
```
Output: `a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0`
### Fetch Latest Git Tag
```bash
x-gh-get-latest-version ivuorinen/dotfiles --tag
```
Output: `v2.0.0-beta.1`
### Output as JSON
```bash
x-gh-get-latest-version ivuorinen/dotfiles --json
```
Output: `{"repository": "ivuorinen/dotfiles", "result": "v1.2.3"}`
### Combined Information Output
```bash
x-gh-get-latest-version ivuorinen/dotfiles --all
```
Output:
```text
Repository: ivuorinen/dotfiles
Branch: main
Git Tag: v2.0.0-beta.1
Commit: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
Prerelease: v1.3.0-rc.1
Release: v1.2.3
```
### Combined Output as JSON
```bash
x-gh-get-latest-version ivuorinen/dotfiles --all --json
```
Output:
```json
{
"repository": "ivuorinen/dotfiles",
"branch": "main",
"tag": "v2.0.0-beta.1",
"commit": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0",
"prerelease": "v1.3.0-rc.1",
"release": "v1.2.3"
}
```
## Environment Variables
You can use environment variables instead of command-line options:
- `INCLUDE_PRERELEASES=1` - Include prerelease versions
- `OLDEST_RELEASE=1` - Fetch the oldest release instead of the latest
- `BRANCH=branch_name` - Specify a branch to fetch tags from
- `LATEST_COMMIT=1` - Fetch latest commit SHA
- `LATEST_TAG=1` - Fetch latest Git tag
- `OUTPUT=json` - Output results as JSON
- `GITHUB_API_URL=url` - Override GitHub API URL (useful for GitHub Enterprise)
- `GITHUB_TOKEN=token` - Use GitHub API token to increase rate limits
- `VERBOSE=1` - Enable verbose output
## GitHub API Rate Limits
GitHub enforces rate limits on API requests:
- Unauthenticated requests: 60 requests per hour
- Authenticated requests: 5,000 requests per hour
For frequent use, it's strongly recommended to set up a GitHub token:
```bash
export GITHUB_TOKEN="your_personal_access_token"
```
The script will automatically warn you when you're approaching your rate limit
and suggest using a token if you haven't already.
## Error Handling
The script provides informative error messages for common issues:
- Repository not found
- Rate limit exceeded
- No releases/tags found
- Invalid arguments
## Author
Ismo Vuorinen (<https://github.com/ivuorinen>)
## License
MIT
<!-- vim: set ft=markdown spell spelllang=en_us cc=80 : -->

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,8 @@
},
"homepage": "https://github.com/ivuorinen/dotfiles#readme",
"devDependencies": {
"@ivuorinen/base-configs": "^2.0.0"
"@ivuorinen/base-configs": "^2.0.0",
"bundle-audit": "^0.1.0"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -11,8 +11,8 @@ msgr run "Installing go packages"
! x-have "go" && msgr err "go hasn't been installed yet." && exit 0
[[ -z "$ASDF_GOLANG_DEFAULT_PACKAGES_FILE" ]] && \
ASDF_GOLANG_DEFAULT_PACKAGES_FILE="$DOTFILES/config/asdf/golang-packages"
[[ -z "$ASDF_GOLANG_DEFAULT_PACKAGES_FILE" ]] \
&& ASDF_GOLANG_DEFAULT_PACKAGES_FILE="$DOTFILES/config/asdf/golang-packages"
# Packages are defined in $DOTFILES/config/asdf/golang-packages, one per line
# Skip comments and empty lines

View File

@@ -1,4 +1,4 @@
column_width = 120
column_width = 90
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2

10411
yarn.lock

File diff suppressed because it is too large Load Diff