mirror of
https://github.com/ivuorinen/dotfiles.git
synced 2026-01-27 20:45:31 +00:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00074ec3ff | ||
|
|
7c7daf89ea | ||
|
|
267c54aa56 | ||
|
|
d72409efc0 | ||
| 3d9e0477b0 | |||
| cfab48eee0 | |||
| 624920b2ab | |||
|
|
fd82f1e36c | ||
|
|
48ec8cd7a7 | ||
|
|
3a61bd2b72 | ||
| 895b0ad353 | |||
| 3c733ec7eb | |||
| 5321ad7bd7 | |||
| 196077bea9 | |||
|
|
75147c7dd6 | ||
| f28ad41f67 | |||
| 61b66d3114 | |||
| 282f760a4f | |||
| 4a9c9b4cb9 | |||
| 16311ee5b4 | |||
| 2fddfa82c0 | |||
| 8f5f44db2d | |||
| 8ad1f5c4d0 | |||
| ac0aa1fbc0 | |||
| e8c6794ff6 | |||
| 4de9a649f0 | |||
|
|
e7f115680e | ||
| f3b4551d0c | |||
| 64725c57dc | |||
| b32ee414e3 | |||
|
|
6ea7807718 | ||
| 6a776bd3dd | |||
| 6ffe581326 | |||
| 5d476e8eed | |||
|
|
bf84c67f08 | ||
| 9cb400dd3f | |||
| fce649619a | |||
| 8b0148e468 | |||
| 9cb27eb9dc | |||
| f1ed88a98e | |||
| ec35f1cb1e | |||
| dab8504cfd | |||
| 0f9a76e36f | |||
|
|
97244d5287 | ||
| 50ea9bea89 | |||
| 688469ad8b | |||
|
|
af32914d71 | ||
|
|
840bd85232 | ||
| c81ee240bf | |||
| e215fe0a2f | |||
| 38e340ac8d |
@@ -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
45
.gitattributes
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/new-release.yml
vendored
2
.github/workflows/new-release.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/pre-commit-autoupdate.yml
vendored
2
.github/workflows/pre-commit-autoupdate.yml
vendored
@@ -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
4
.gitignore
vendored
@@ -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
3
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -49,12 +49,12 @@ repos:
|
||||
- id: actionlint
|
||||
|
||||
- repo: https://github.com/renovatebot/pre-commit-hooks
|
||||
rev: 39.212.0
|
||||
rev: 39.261.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
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.13.2
|
||||
3.13.3
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1 +1 @@
|
||||
lts/*
|
||||
v22.14.0
|
||||
|
||||
@@ -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'
|
||||
|
||||
235
config/fish/completions/docker.fish
Executable file
235
config/fish/completions/docker.fish
Executable 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'
|
||||
@@ -8,18 +8,32 @@ 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/.config/fish/exports.secret.fish" &&
|
||||
source "$HOME/.config/fish/exports.secret.fish"
|
||||
|
||||
# Start tmux if not already running and not in SSH
|
||||
open-tmux # defined in functions/open-tmux.fish
|
||||
test -e "$HOME/.dotfiles/config/fzf/key-bindings.fish" &&
|
||||
source "$HOME/.dotfiles/config/fzf/key-bindings.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 source (fnm env|psub)
|
||||
|
||||
# vim: ft=fish ts=4 sw=4 et:
|
||||
|
||||
@@ -112,7 +112,7 @@ 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"
|
||||
set -q GOENV_RC_FILE; or set -x GOENV_RC_FILE "$XDG_CONFIG_HOME/goenv/goenvrc.fish"
|
||||
|
||||
# 1Password configuration
|
||||
set -q OP_CACHE; or set -x OP_CACHE "$XDG_STATE_HOME/1password"
|
||||
@@ -121,9 +121,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"
|
||||
|
||||
16
config/fish/functions/load_nvm.fish
Normal file
16
config/fish/functions/load_nvm.fish
Normal 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
|
||||
4
config/fish/functions/nvm.fish
Normal file
4
config/fish/functions/nvm.fish
Normal file
@@ -0,0 +1,4 @@
|
||||
function nvm
|
||||
bass source $NVM_DIR/nvm.sh --no-use ';' nvm $argv
|
||||
end
|
||||
|
||||
3
config/fish/functions/nvm_find_nvmrc.fish
Normal file
3
config/fish/functions/nvm_find_nvmrc.fish
Normal file
@@ -0,0 +1,3 @@
|
||||
function nvm_find_nvmrc
|
||||
bass source $NVM_DIR/nvm.sh --no-use ';' nvm_find_nvmrc
|
||||
end
|
||||
@@ -1,3 +1,6 @@
|
||||
GOENV_PATH_ORDER=front
|
||||
GOENV_PREPEND_GOPATH=true
|
||||
GOENV_AUTO_INSTALL=true
|
||||
# Detect shell
|
||||
if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then
|
||||
export GOENV_PATH_ORDER=front
|
||||
export GOENV_PREPEND_GOPATH=true
|
||||
export GOENV_AUTO_INSTALL=true
|
||||
fi
|
||||
|
||||
4
config/goenv/goenvrc.fish
Normal file
4
config/goenv/goenvrc.fish
Normal file
@@ -0,0 +1,4 @@
|
||||
set -gx GOENV_PATH_ORDER front
|
||||
set -gx GOENV_PREPEND_GOPATH true
|
||||
set -gx GOENV_AUTO_INSTALL true
|
||||
|
||||
@@ -107,6 +107,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 +125,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 +137,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 +193,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
|
||||
@@ -230,7 +232,9 @@ brew "openldap"
|
||||
# ISO-C API and CLI for generating UUIDs
|
||||
brew "ossp-uuid"
|
||||
# General-purpose scripting language
|
||||
brew "php@8.2", link: true
|
||||
brew "php"
|
||||
# General-purpose scripting language
|
||||
brew "php@8.2"
|
||||
# General-purpose scripting language
|
||||
brew "php@8.3"
|
||||
# Pins GitHub Actions to full hashes and versions
|
||||
@@ -336,6 +340,8 @@ cask "jetbrains-toolbox"
|
||||
cask "keybase"
|
||||
# Kubernetes IDE
|
||||
cask "lens"
|
||||
# Neovim Client
|
||||
cask "neovide"
|
||||
# Reverse proxy, secure introspectable tunnels to localhost
|
||||
cask "ngrok"
|
||||
# Simple application that will prevent iTunes or Apple Music from launching
|
||||
|
||||
@@ -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 `
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
column_width = 80
|
||||
column_width = 90
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
|
||||
2
config/nvim/ftdetect/env.vim
Normal file
2
config/nvim/ftdetect/env.vim
Normal file
@@ -0,0 +1,2 @@
|
||||
autocmd BufRead,BufNewFile *.env set ft=env
|
||||
autocmd BufRead,BufNewFile *.env.* set ft=env
|
||||
@@ -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'
|
||||
@@ -64,8 +61,8 @@ require('lazy').setup(
|
||||
}
|
||||
)
|
||||
|
||||
require('nvm-default').setup()
|
||||
-- require('nvm-default').setup()
|
||||
|
||||
require 'keymaps'
|
||||
|
||||
-- vim: ts=2 sts=2 sw=2 et
|
||||
-- vim: set ts=2 sts=2 sw=2 wrap et :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ local a = vim.api -- A table to store API functions
|
||||
g.mapleader = ' ' -- Space as the leader key
|
||||
g.maplocalleader = ' ' -- Space as the local leader key
|
||||
|
||||
g.colors_theme = 'tokyonight' -- Set the colorscheme
|
||||
g.colors_variant_light = 'tokyonight-day' -- Set the light variant
|
||||
g.colors_variant_dark = 'tokyonight-storm' -- Set the dark variant
|
||||
g.colors_theme = 'pencil' -- Set the colorscheme
|
||||
-- g.colors_variant_light = 'tokyonight-day' -- Set the light variant
|
||||
-- g.colors_variant_dark = 'tokyonight-storm' -- Set the dark variant
|
||||
|
||||
g.editorconfig = true -- Make sure editorconfig support is enabled
|
||||
g.loaded_perl_provider = 0 -- Disable perl provider
|
||||
@@ -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
|
||||
|
||||
@@ -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 },
|
||||
},
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
}
|
||||
|
||||
66
config/nvim/lua/plugins/conform.lua
Normal file
66
config/nvim/lua/plugins/conform.lua
Normal 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,
|
||||
},
|
||||
}
|
||||
@@ -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 = {},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,350 +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' },
|
||||
-- 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 = {} },
|
||||
}
|
||||
|
||||
@@ -25,6 +25,14 @@ return {
|
||||
},
|
||||
}
|
||||
|
||||
-- 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 }
|
||||
|
||||
-- Animate common Neovim actions
|
||||
-- Replaced anuvyklack/windows.nvim
|
||||
require('mini.animate').setup()
|
||||
|
||||
@@ -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(file_path)
|
||||
require('neo-tree.command').execute { action = 'close' }
|
||||
end,
|
||||
handler = function(_) require('neo-tree.command').execute { action = 'close' } end,
|
||||
},
|
||||
},
|
||||
default_component_configs = {
|
||||
|
||||
@@ -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 },
|
||||
}
|
||||
|
||||
@@ -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].*)]],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
return {
|
||||
-- Theme of choice, tokyonight
|
||||
-- https://github.com/folke/tokyonight.nvim
|
||||
{
|
||||
'folke/tokyonight.nvim',
|
||||
priority = 1000, -- Make sure to load this before all the other start plugins.
|
||||
init = function() vim.cmd.colorscheme(vim.g.colors_theme) end,
|
||||
opts = {
|
||||
transparent = true,
|
||||
},
|
||||
'rmehri01/onenord.nvim',
|
||||
opts = {},
|
||||
},
|
||||
|
||||
-- Automatic dark mode
|
||||
-- https://github.com/f-person/auto-dark-mode.nvim
|
||||
{
|
||||
@@ -18,11 +11,11 @@ return {
|
||||
update_interval = 1000,
|
||||
set_dark_mode = function()
|
||||
vim.api.nvim_set_option_value('background', 'dark', {})
|
||||
vim.cmd.colorscheme(vim.g.colors_variant_dark)
|
||||
-- vim.cmd.colorscheme(vim.g.colors_variant_dark)
|
||||
end,
|
||||
set_light_mode = function()
|
||||
vim.api.nvim_set_option_value('background', 'light', {})
|
||||
vim.cmd.colorscheme(vim.g.colors_variant_light)
|
||||
-- vim.cmd.colorscheme(vim.g.colors_variant_light)
|
||||
end,
|
||||
},
|
||||
},
|
||||
@@ -31,6 +24,7 @@ return {
|
||||
-- https://github.com/catgoose/nvim-colorizer.lua
|
||||
{
|
||||
'catgoose/nvim-colorizer.lua',
|
||||
event = 'BufReadPre',
|
||||
opts = {
|
||||
user_default_options = {
|
||||
names = false,
|
||||
@@ -38,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
|
||||
|
||||
@@ -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 }
|
||||
31
config/nvim/syntax/env.vim
Normal file
31
config/nvim/syntax/env.vim
Normal 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
2
config/op/plugins.sh
Normal 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
15
config/op/plugins/gh.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
config/op/plugins/used_items/gh.json
Normal file
1
config/op/plugins/used_items/gh.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"account_id":"S5Z2DMNFKJEZBPCWRHRWC4DCGI","vault_id":"injcin7obv3jdet3r2u3kfihfy","item_id":"f6vinbnc6l7ngdzvlw66ayewlq"}]
|
||||
1
config/tmux/plugins/tmux-resurrect
Submodule
1
config/tmux/plugins/tmux-resurrect
Submodule
Submodule config/tmux/plugins/tmux-resurrect added at cff343cf9e
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
let mapleader=' ' " Map leader to <space>
|
||||
filetype off " disable filetype detection (but re-enable later, see below)
|
||||
|
||||
" find matching tags in html/xml documents using matchit
|
||||
filetype plugin on
|
||||
packadd! matchit
|
||||
" disable super buggy netrw
|
||||
let g:loaded_netrw=1
|
||||
let g:netrw_loaded_netrwPlugin=1
|
||||
" show JSDoc highlight colors
|
||||
let g:javascript_plugin_jsdoc=1
|
||||
|
||||
set backspace=indent,eol,start " Backspace behavior
|
||||
set cindent " Use 'C' style program indenting
|
||||
set cursorline " Highlight current line
|
||||
set encoding=utf-8 " UTF-8
|
||||
set expandtab " Use spaces instead of tabs
|
||||
set fileformats=unix,dos,mac " File formats
|
||||
set foldmethod=indent " Fold based on indent
|
||||
set foldlevel=99 " Open all folds
|
||||
set guioptions=egmrti " GUI options
|
||||
set hidden " Enable hidden buffers
|
||||
set ignorecase " Always case-insensitive
|
||||
set incsearch " Searches for strings incrementally
|
||||
set laststatus=2 " Always show statusline (even with only single window)
|
||||
set linespace=3 " Set line spacing
|
||||
set list " Show invisible characters
|
||||
set listchars=tab:⌴\ ,trail:◼,nbsp:•,extends:…,precedes:… " Invisible characters
|
||||
set modeline " Enable modelines
|
||||
set modelines=3 " Number of lines to check for modelines
|
||||
set mouse=a " Enable mouse support
|
||||
set mousemodel=popup " Enable mouse support
|
||||
set nobackup " Disable backup files
|
||||
set nocompatible " disable compatibility mode with vi
|
||||
set nowritebackup " Disable backup files
|
||||
set number " Show line numbers
|
||||
set relativenumber " Show relative line numbers
|
||||
set ruler " Show row and column ruler information
|
||||
set scrolloff=8 " Minimum number of lines to keep above and below the cursor
|
||||
set shiftwidth=4 " Number of auto-indent spaces
|
||||
set shortmess+=A " Don't show autocommand messages
|
||||
set shortmess+=F " Avoid showing the "file-info" message
|
||||
set shortmess+=I " Don't show intro message
|
||||
set shortmess+=O " Avoid showing the "file-read" message
|
||||
set shortmess+=O " Don't show overlength messages
|
||||
set shortmess+=T " Don't show title messages
|
||||
set shortmess+=W " Don't show "written" messages
|
||||
set shortmess+=a " Avoid showing the "ATTENTION" message
|
||||
set shortmess+=c " Avoid showing the "ins-completion-menu" message
|
||||
set shortmess+=c " Don't pass messages to |ins-completion-menu|
|
||||
set shortmess+=o " Avoid showing the "overlength" message
|
||||
set shortmess+=t " Avoid showing the "trailing whitespace" message
|
||||
set showcmd " Show command in status line
|
||||
set showmatch " Highlight matching brace
|
||||
set signcolumn=yes " Show sign column
|
||||
set smartcase " Enable smart-case search
|
||||
set smartindent " Enable smart-indent
|
||||
set smarttab " Enable smart-tabs
|
||||
set softtabstop=4 " Number of spaces per Tab
|
||||
set spelllang=fi,en " Set the spell language
|
||||
set spellsuggest=double " Suggest the first word when spell checking
|
||||
set t_Co=256 " 256 colors
|
||||
set termguicolors " Enable 24-bit RGB color in the terminal
|
||||
set timeoutlen=500 " By default timeoutlen=1000 (ms)
|
||||
set ttimeoutlen=0 " By default ttimeoutlen=-1 (ms)
|
||||
set undolevels=1000 " Number of undo levels
|
||||
set visualbell " Use visual bell (no beeping)
|
||||
set wildmenu " Enable wildmenu
|
||||
set wildmode=longest,list:longest " Command-line completion mode
|
||||
set wrap " Wrap lines
|
||||
set wrapscan " Searches wrap around the end of the file
|
||||
|
||||
" Ignore these files in wildmenu
|
||||
set wildignore+=*.o,*.obj,.git,*.rbc,*.pyc,__pycache__,vendor
|
||||
|
||||
colorscheme iceberg " Set the color scheme
|
||||
filetype plugin indent on " enable filetype detection, plugins and indenting
|
||||
|
||||
" Set the shell
|
||||
if exists('$SHELL')
|
||||
set shell=$SHELL
|
||||
else
|
||||
set shell=/bin/sh
|
||||
endif
|
||||
|
||||
175
config/vim/autoload/airline/themes/pencil.vim
Normal file
175
config/vim/autoload/airline/themes/pencil.vim
Normal file
@@ -0,0 +1,175 @@
|
||||
let g:airline#themes#pencil#palette = {}
|
||||
|
||||
function! airline#themes#pencil#refresh()
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Options
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
let s:background = get(g:, 'airline_pencil_bg', &background)
|
||||
let s:ansi_colors = &t_Co < 16 ? 1 : 0
|
||||
let s:tty = &t_Co == 8
|
||||
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Colors
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Base colors
|
||||
let s:base03 = {'t': s:ansi_colors ? 8 : (s:tty ? '0' : 234), 'g': '#212121'}
|
||||
let s:base02 = {'t': s:ansi_colors ? '0' : (s:tty ? '0' : 235), 'g': '#424242'}
|
||||
let s:base01 = {'t': s:ansi_colors ? 10 : (s:tty ? '0' : 240), 'g': '#909090'}
|
||||
let s:base00 = {'t': s:ansi_colors ? 11 : (s:tty ? '7' : 241), 'g': '#545454'}
|
||||
let s:base0 = {'t': s:ansi_colors ? 12 : (s:tty ? '7' : 244), 'g': '#B2B2B2'}
|
||||
let s:base1 = {'t': s:ansi_colors ? 14 : (s:tty ? '7' : 245), 'g': '#636363'}
|
||||
let s:base2 = {'t': s:ansi_colors ? 7 : (s:tty ? '7' : 254), 'g': '#D9D9D9'}
|
||||
let s:base3 = {'t': s:ansi_colors ? 15 : (s:tty ? '7' : 7 ), 'g': '#C6C6C6'}
|
||||
let s:darkblue= {'t': s:ansi_colors ? 4 : (s:tty ? '4' : 24 ), 'g': '#005F87'}
|
||||
let s:orange = {'t': s:ansi_colors ? 9 : (s:tty ? '1' : 166), 'g': '#D75F5F'}
|
||||
let s:red = {'t': s:ansi_colors ? 1 : (s:tty ? '1' : 160), 'g': '#C30771'}
|
||||
let s:magenta = {'t': s:ansi_colors ? 5 : (s:tty ? '5' : 125), 'g': '#E32791'}
|
||||
let s:violet = {'t': s:ansi_colors ? 13 : (s:tty ? '5' : 61 ), 'g': '#6855DE'}
|
||||
let s:blue = {'t': s:ansi_colors ? 4 : (s:tty ? '4' : 33 ), 'g': '#008EC4'}
|
||||
let s:cyan = {'t': s:ansi_colors ? 6 : (s:tty ? '6' : 37 ), 'g': '#20A5BA'}
|
||||
let s:green = {'t': s:ansi_colors ? 2 : (s:tty ? '2' : 64 ), 'g': '#10A778'}
|
||||
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Simple mappings
|
||||
" NOTE: These are easily tweakable mappings. The actual mappings get
|
||||
" the specific gui and terminal colors from the base color dicts.
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Normal mode
|
||||
if s:background == 'dark'
|
||||
let s:N1 = [s:base3, s:base1, 'bold']
|
||||
let s:N2 = [s:base2, (s:tty ? s:base01 : s:base00), '']
|
||||
let s:N3 = [s:base01, s:base02, '']
|
||||
else
|
||||
let s:N1 = [s:base2, s:base00, 'bold']
|
||||
let s:N2 = [(s:tty ? s:base01 : s:base2), s:base1, '']
|
||||
let s:N3 = [s:base1, s:base2, '']
|
||||
endif
|
||||
let s:NF = [s:orange, s:N3[1], '']
|
||||
let s:NW = [s:base3, s:orange, '']
|
||||
if s:background == 'dark'
|
||||
let s:NM = [s:base1, s:N3[1], '']
|
||||
let s:NMi = [s:base2, s:N3[1], '']
|
||||
else
|
||||
let s:NM = [s:base01, s:N3[1], '']
|
||||
let s:NMi = [s:base02, s:N3[1], '']
|
||||
endif
|
||||
|
||||
" Insert mode
|
||||
let s:I1 = [s:N1[0], s:darkblue, 'bold']
|
||||
let s:I2 = s:N2
|
||||
let s:I3 = s:N3
|
||||
let s:IF = s:NF
|
||||
let s:IM = s:NM
|
||||
|
||||
" Visual mode
|
||||
let s:V1 = [s:N1[0], s:magenta, 'bold']
|
||||
let s:V2 = s:N2
|
||||
let s:V3 = s:N3
|
||||
let s:VF = s:NF
|
||||
let s:VM = s:NM
|
||||
|
||||
" Replace mode
|
||||
let s:R1 = [s:N1[0], s:red, '']
|
||||
let s:R2 = s:N2
|
||||
let s:R3 = s:N3
|
||||
let s:RM = s:NM
|
||||
let s:RF = s:NF
|
||||
|
||||
" Inactive, according to VertSplit in pencil
|
||||
" (bg dark: base00; bg light: base0)
|
||||
if s:background == 'dark'
|
||||
let s:IA = [s:base01, s:base02, '']
|
||||
else
|
||||
let s:IA = [s:base1, s:base2, '']
|
||||
endif
|
||||
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Actual mappings
|
||||
" WARNING: Don't modify this section unless necessary.
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
let s:NFa = [s:NF[0].g, s:NF[1].g, s:NF[0].t, s:NF[1].t, s:NF[2]]
|
||||
let s:IFa = [s:IF[0].g, s:IF[1].g, s:IF[0].t, s:IF[1].t, s:IF[2]]
|
||||
let s:VFa = [s:VF[0].g, s:VF[1].g, s:VF[0].t, s:VF[1].t, s:VF[2]]
|
||||
let s:RFa = [s:RF[0].g, s:RF[1].g, s:RF[0].t, s:RF[1].t, s:RF[2]]
|
||||
|
||||
let g:airline#themes#pencil#palette.accents = {
|
||||
\ 'red': s:NFa,
|
||||
\ }
|
||||
|
||||
let g:airline#themes#pencil#palette.inactive = airline#themes#generate_color_map(
|
||||
\ [s:IA[0].g, s:IA[1].g, s:IA[0].t, s:IA[1].t, s:IA[2]],
|
||||
\ [s:IA[0].g, s:IA[1].g, s:IA[0].t, s:IA[1].t, s:IA[2]],
|
||||
\ [s:IA[0].g, s:IA[1].g, s:IA[0].t, s:IA[1].t, s:IA[2]])
|
||||
let g:airline#themes#pencil#palette.inactive_modified = {
|
||||
\ 'airline_c': [s:NMi[0].g, '', s:NMi[0].t, '', s:NMi[2]]}
|
||||
|
||||
let g:airline#themes#pencil#palette.normal = airline#themes#generate_color_map(
|
||||
\ [s:N1[0].g, s:N1[1].g, s:N1[0].t, s:N1[1].t, s:N1[2]],
|
||||
\ [s:N2[0].g, s:N2[1].g, s:N2[0].t, s:N2[1].t, s:N2[2]],
|
||||
\ [s:N3[0].g, s:N3[1].g, s:N3[0].t, s:N3[1].t, s:N3[2]])
|
||||
|
||||
let g:airline#themes#pencil#palette.normal.airline_warning = [
|
||||
\ s:NW[0].g, s:NW[1].g, s:NW[0].t, s:NW[1].t, s:NW[2]]
|
||||
|
||||
let g:airline#themes#pencil#palette.normal_modified = {
|
||||
\ 'airline_c': [s:NM[0].g, s:NM[1].g,
|
||||
\ s:NM[0].t, s:NM[1].t, s:NM[2]]}
|
||||
|
||||
let g:airline#themes#pencil#palette.normal_modified.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.insert = airline#themes#generate_color_map(
|
||||
\ [s:I1[0].g, s:I1[1].g, s:I1[0].t, s:I1[1].t, s:I1[2]],
|
||||
\ [s:I2[0].g, s:I2[1].g, s:I2[0].t, s:I2[1].t, s:I2[2]],
|
||||
\ [s:I3[0].g, s:I3[1].g, s:I3[0].t, s:I3[1].t, s:I3[2]])
|
||||
|
||||
let g:airline#themes#pencil#palette.insert.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.insert_modified = {
|
||||
\ 'airline_c': [s:IM[0].g, s:IM[1].g,
|
||||
\ s:IM[0].t, s:IM[1].t, s:IM[2]]}
|
||||
|
||||
let g:airline#themes#pencil#palette.insert_modified.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.visual = airline#themes#generate_color_map(
|
||||
\ [s:V1[0].g, s:V1[1].g, s:V1[0].t, s:V1[1].t, s:V1[2]],
|
||||
\ [s:V2[0].g, s:V2[1].g, s:V2[0].t, s:V2[1].t, s:V2[2]],
|
||||
\ [s:V3[0].g, s:V3[1].g, s:V3[0].t, s:V3[1].t, s:V3[2]])
|
||||
|
||||
let g:airline#themes#pencil#palette.visual.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.visual_modified = {
|
||||
\ 'airline_c': [s:VM[0].g, s:VM[1].g,
|
||||
\ s:VM[0].t, s:VM[1].t, s:VM[2]]}
|
||||
|
||||
let g:airline#themes#pencil#palette.visual_modified.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.replace = airline#themes#generate_color_map(
|
||||
\ [s:R1[0].g, s:R1[1].g, s:R1[0].t, s:R1[1].t, s:R1[2]],
|
||||
\ [s:R2[0].g, s:R2[1].g, s:R2[0].t, s:R2[1].t, s:R2[2]],
|
||||
\ [s:R3[0].g, s:R3[1].g, s:R3[0].t, s:R3[1].t, s:R3[2]])
|
||||
|
||||
let g:airline#themes#pencil#palette.replace.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.replace_modified = {
|
||||
\ 'airline_c': [s:RM[0].g, s:RM[1].g,
|
||||
\ s:RM[0].t, s:RM[1].t, s:RM[2]]}
|
||||
|
||||
let g:airline#themes#pencil#palette.replace_modified.airline_warning =
|
||||
\ g:airline#themes#pencil#palette.normal.airline_warning
|
||||
|
||||
let g:airline#themes#pencil#palette.tabline = {}
|
||||
|
||||
let g:airline#themes#pencil#palette.tabline.airline_tab = [
|
||||
\ s:I2[0].g, s:I2[1].g, s:I2[0].t, s:I2[1].t, s:I2[2]]
|
||||
|
||||
let g:airline#themes#pencil#palette.tabline.airline_tabtype = [
|
||||
\ s:N2[0].g, s:N2[1].g, s:N2[0].t, s:N2[1].t, s:N2[2]]
|
||||
endfunction
|
||||
|
||||
call airline#themes#pencil#refresh()
|
||||
@@ -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
|
||||
|
||||
383
config/vim/colors/pencil.vim
Normal file
383
config/vim/colors/pencil.vim
Normal file
@@ -0,0 +1,383 @@
|
||||
" Vim Color File
|
||||
" Name: pencil.vim
|
||||
" Version: 0.6
|
||||
" Maintainer: github.com/preservim
|
||||
" License: The MIT License (MIT)
|
||||
|
||||
" Original iA Writer colors, to use as a guide
|
||||
" White #F1F1F1
|
||||
" OffWhiteIPad #F5F2EC
|
||||
" OffWhiteDemo #F9F8F4
|
||||
" Cursor #20BBFC
|
||||
" Selection #B6D6FD
|
||||
" SelectionNOS #D4D4D4
|
||||
" StatusBar #EDEDED
|
||||
" StatusBarBorder #D9D9D9 used for search too
|
||||
" Text #424242
|
||||
" Blue #B5D6FD
|
||||
" Green #30C798
|
||||
" Blue2 #1DAEE4
|
||||
" gray #999999
|
||||
" Red #E32791
|
||||
" UnfocusedText #B8B8B8
|
||||
" MenuSelected #2C81FB
|
||||
" MenuUnSelected #545454
|
||||
" MenuText #F1F1F1
|
||||
" LightKeyBg #4B4B4B
|
||||
" DarkKeyBg #262626
|
||||
" NearBlack #181818
|
||||
" SyntaxButton #363738
|
||||
" SearchHighlight #F3E430 yellow
|
||||
|
||||
hi clear
|
||||
|
||||
if exists('syntax on')
|
||||
syntax reset
|
||||
endif
|
||||
|
||||
let g:colors_name='pencil'
|
||||
|
||||
if ! exists("g:pencil_higher_contrast_ui")
|
||||
let g:pencil_higher_contrast_ui = 0
|
||||
endif
|
||||
|
||||
if ! exists("g:pencil_neutral_code_bg")
|
||||
let g:pencil_neutral_code_bg = 0
|
||||
endif
|
||||
|
||||
if ! exists("g:pencil_neutral_headings")
|
||||
let g:pencil_neutral_headings = 0
|
||||
endif
|
||||
|
||||
" not all terminals support italics properly. If yours does, opt-in.
|
||||
if ! exists("g:pencil_terminal_italics")
|
||||
let g:pencil_terminal_italics = 0
|
||||
endif
|
||||
|
||||
if ! exists("g:pencil_spell_undercurl")
|
||||
let g:pencil_spell_undercurl = 1
|
||||
endif
|
||||
|
||||
if ! exists("g:pencil_gutter_color")
|
||||
let g:pencil_gutter_color = 0
|
||||
endif
|
||||
|
||||
" Colors
|
||||
let s:black = { "gui": "#212121", "cterm": "0" }
|
||||
let s:medium_gray = { "gui": "#767676", "cterm": "243" }
|
||||
let s:white = { "gui": "#F1F1F1", "cterm": "15" }
|
||||
let s:actual_white = { "gui": "#FFFFFF", "cterm": "231" }
|
||||
let s:light_black = { "gui": "#424242", "cterm": "8" }
|
||||
let s:lighter_black = { "gui": "#545454", "cterm": "240" }
|
||||
|
||||
if g:pencil_higher_contrast_ui == 0
|
||||
" darker shadow and whiter grays
|
||||
let s:subtle_black = { "gui": "#262626", "cterm": "235" }
|
||||
let s:light_gray = { "gui": "#D9D9D9", "cterm": "253" }
|
||||
let s:lighter_gray = { "gui": "#E5E6E6", "cterm": "254" }
|
||||
else
|
||||
" lighter shadows and darker grays
|
||||
let s:subtle_black = { "gui": "#303030", "cterm": "236" }
|
||||
let s:light_gray = { "gui": "#B2B2B2", "cterm": "249" }
|
||||
let s:lighter_gray = { "gui": "#C6C6C6", "cterm": "251" }
|
||||
endif
|
||||
|
||||
let s:pink = { "gui": "#fb007a", "cterm": "9" }
|
||||
let s:dark_red = { "gui": "#C30771", "cterm": "1" }
|
||||
let s:light_red = { "gui": "#E32791", "cterm": "1" }
|
||||
let s:orange = { "gui": "#D75F5F", "cterm": "167" }
|
||||
|
||||
let s:darker_blue = { "gui": "#005F87", "cterm": "18" }
|
||||
let s:dark_blue = { "gui": "#008EC4", "cterm": "4" }
|
||||
let s:blue = { "gui": "#20BBFC", "cterm": "12" }
|
||||
let s:light_blue = { "gui": "#b6d6fd", "cterm": "153" }
|
||||
let s:dark_cyan = { "gui": "#20A5BA", "cterm": "6" }
|
||||
let s:light_cyan = { "gui": "#4FB8CC", "cterm": "14" }
|
||||
|
||||
let s:dark_green = { "gui": "#10A778", "cterm": "2" }
|
||||
let s:light_green = { "gui": "#5FD7A7", "cterm": "10" }
|
||||
|
||||
let s:dark_purple = { "gui": "#523C79", "cterm": "5" }
|
||||
let s:light_purple = { "gui": "#6855DE", "cterm": "13" }
|
||||
|
||||
let s:yellow = { "gui": "#F3E430", "cterm": "11" }
|
||||
let s:dark_yellow = { "gui": "#A89C14", "cterm": "3" }
|
||||
|
||||
if &background == "dark"
|
||||
let s:bg = s:black
|
||||
let s:bg_subtle = s:light_black
|
||||
let s:bg_very_subtle = s:subtle_black
|
||||
let s:norm = s:lighter_gray
|
||||
let s:norm_subtle = s:light_gray
|
||||
let s:purple = s:light_purple
|
||||
let s:cyan = s:light_cyan
|
||||
let s:green = s:light_green
|
||||
let s:red = s:light_red
|
||||
let s:visual = s:lighter_black
|
||||
else
|
||||
let s:bg = s:white
|
||||
let s:bg_subtle = s:light_gray
|
||||
let s:bg_very_subtle = s:lighter_gray
|
||||
let s:norm = s:light_black
|
||||
let s:norm_subtle = s:lighter_black
|
||||
let s:purple = s:dark_purple
|
||||
let s:cyan = s:dark_cyan
|
||||
let s:green = s:dark_green
|
||||
let s:red = s:dark_red
|
||||
let s:visual = s:light_blue
|
||||
endif
|
||||
|
||||
if g:pencil_neutral_headings == 1
|
||||
let s:head_a = s:norm
|
||||
let s:head_b = s:norm
|
||||
let s:head_c = s:norm
|
||||
else
|
||||
let s:head_a = s:dark_blue
|
||||
let s:head_b = s:blue
|
||||
let s:head_c = s:dark_cyan
|
||||
endif
|
||||
|
||||
if g:pencil_neutral_code_bg == 1
|
||||
let s:code_bg = s:bg
|
||||
else
|
||||
let s:code_bg = s:bg_very_subtle
|
||||
endif
|
||||
|
||||
if g:pencil_spell_undercurl == 1
|
||||
let s:sp_un = 'undercurl'
|
||||
else
|
||||
let s:sp_un = 'underline'
|
||||
endif
|
||||
|
||||
" shamelessly stolen from hemisu: https://github.com/noahfrederick/vim-hemisu/
|
||||
function! s:h(group, style)
|
||||
" Not all terminals support italics properly. If yours does, opt-in.
|
||||
if g:pencil_terminal_italics == 0 && has_key(a:style, "cterm") && a:style["cterm"] == "italic"
|
||||
unlet a:style.cterm
|
||||
endif
|
||||
execute "highlight" a:group
|
||||
\ "guifg=" (has_key(a:style, "fg") ? a:style.fg.gui : "NONE")
|
||||
\ "guibg=" (has_key(a:style, "bg") ? a:style.bg.gui : "NONE")
|
||||
\ "guisp=" (has_key(a:style, "sp") ? a:style.sp.gui : "NONE")
|
||||
\ "gui=" (has_key(a:style, "gui") ? a:style.gui : "NONE")
|
||||
\ "ctermfg=" (has_key(a:style, "fg") ? a:style.fg.cterm : "NONE")
|
||||
\ "ctermbg=" (has_key(a:style, "bg") ? a:style.bg.cterm : "NONE")
|
||||
\ "cterm=" (has_key(a:style, "cterm") ? a:style.cterm : "NONE")
|
||||
endfunction
|
||||
|
||||
" common groups ================================================================
|
||||
" (see `:h w18`)
|
||||
|
||||
call s:h("Normal", {"bg": s:bg, "fg": s:norm})
|
||||
call s:h("Cursor", {"bg": s:blue, "fg": s:norm })
|
||||
call s:h("Comment", {"fg": s:medium_gray, "gui": "italic", "cterm": "italic"})
|
||||
|
||||
call s:h("Constant", {"fg": s:cyan})
|
||||
hi! link String Constant
|
||||
hi! link Character Constant
|
||||
hi! link Number Constant
|
||||
hi! link Boolean Constant
|
||||
hi! link Float Constant
|
||||
|
||||
call s:h("Identifier", {"fg": s:dark_blue})
|
||||
hi! link Function Identifier
|
||||
|
||||
call s:h("Statement", {"fg": s:green})
|
||||
hi! link Conditonal Statement
|
||||
hi! link Repeat Statement
|
||||
hi! link Label Statement
|
||||
hi! link Operator Statement
|
||||
hi! link Keyword Statement
|
||||
hi! link Exception Statement
|
||||
|
||||
call s:h("PreProc", {"fg": s:red})
|
||||
hi! link Include PreProc
|
||||
hi! link Define PreProc
|
||||
hi! link Macro PreProc
|
||||
hi! link PreCondit PreProc
|
||||
|
||||
call s:h("Type", {"fg": s:purple})
|
||||
hi! link StorageClass Type
|
||||
hi! link Structure Type
|
||||
hi! link Typedef Type
|
||||
|
||||
call s:h("Special", {"fg": s:pink})
|
||||
hi! link SpecialChar Special
|
||||
hi! link Tag Special
|
||||
hi! link Delimiter Special
|
||||
hi! link SpecialComment Special
|
||||
hi! link Debug Special
|
||||
|
||||
call s:h("Underlined", {"fg": s:norm , "gui": "underline", "cterm": "underline"})
|
||||
call s:h("Ignore", {"fg": s:bg })
|
||||
call s:h("Error", {"fg": s:actual_white, "bg": s:red , "gui": "bold" , "cterm": "bold" })
|
||||
call s:h("Todo", {"fg": s:actual_white, "bg": s:pink, "gui": "bold" , "cterm": "bold" })
|
||||
|
||||
" ui chrome ====================================================================
|
||||
" ordered according to `:help hitest.vim`
|
||||
|
||||
call s:h("SpecialKey", {"fg": s:light_green})
|
||||
call s:h("NonText", {"fg": s:bg_subtle})
|
||||
call s:h("Directory", {"fg": s:dark_blue})
|
||||
call s:h("ErrorMsg", {"fg": s:pink})
|
||||
call s:h("IncSearch", {"bg": s:yellow, "fg": s:light_black})
|
||||
call s:h("Search", {"bg": s:bg_subtle})
|
||||
call s:h("MoreMsg", {"fg": s:medium_gray, "gui": "bold", "cterm": "bold"})
|
||||
hi! link ModeMsg MoreMsg
|
||||
call s:h("LineNr", {"fg": s:bg_subtle})
|
||||
call s:h("CursorLineNr", {"fg": s:blue, "bg": s:bg_very_subtle})
|
||||
call s:h("Question", {"fg": s:red})
|
||||
call s:h("StatusLine", {"bg": s:bg_very_subtle})
|
||||
call s:h("Conceal", {"fg": s:norm})
|
||||
call s:h("StatusLineNC", {"bg": s:bg_very_subtle, "fg": s:medium_gray})
|
||||
call s:h("VertSplit", {"bg": s:bg_very_subtle, "fg": s:bg_very_subtle})
|
||||
call s:h("Title", {"fg": s:dark_blue})
|
||||
call s:h("Visual", {"bg": s:visual})
|
||||
call s:h("VisualNOS", {"bg": s:bg_subtle})
|
||||
call s:h("WarningMsg", {"fg": s:red})
|
||||
call s:h("WildMenu", {"fg": s:bg, "bg": s:norm})
|
||||
call s:h("Folded", {"fg": s:medium_gray})
|
||||
call s:h("FoldColumn", {"fg": s:bg_subtle})
|
||||
call s:h("DiffAdd", {"bg": s:bg_subtle, "fg": s:green})
|
||||
call s:h("DiffAdded", {"bg": s:bg_subtle, "fg": s:green})
|
||||
call s:h("DiffDelete", {"bg": s:bg_subtle, "fg": s:red})
|
||||
call s:h("DiffRemoved", {"bg": s:bg_subtle, "fg": s:red})
|
||||
call s:h("DiffChange", {"bg": s:bg_subtle, "fg": s:dark_yellow})
|
||||
call s:h("DiffChanged", {"bg": s:bg_subtle, "fg": s:dark_yellow})
|
||||
call s:h("DiffText", {"bg": s:bg_subtle, "fg": s:dark_blue})
|
||||
call s:h("SignColumn", {"fg": s:light_green})
|
||||
|
||||
call s:h("SpellBad", {"gui": s:sp_un, "sp": s:red, "cterm": s:sp_un, "fg": s:red})
|
||||
call s:h("SpellCap", {"gui": s:sp_un, "sp": s:light_green, "cterm": s:sp_un, "fg": s:light_green})
|
||||
call s:h("SpellRare", {"gui": s:sp_un, "sp": s:pink, "cterm": s:sp_un, "fg": s:pink})
|
||||
call s:h("SpellLocal", {"gui": s:sp_un, "sp": s:dark_green, "cterm": s:sp_un, "fg": s:dark_green})
|
||||
|
||||
call s:h("Pmenu", {"fg": s:norm, "bg": s:bg_subtle})
|
||||
call s:h("PmenuSel", {"fg": s:norm, "bg": s:blue})
|
||||
call s:h("PmenuSbar", {"fg": s:norm, "bg": s:bg_subtle})
|
||||
call s:h("PmenuThumb", {"fg": s:norm, "bg": s:bg_subtle})
|
||||
call s:h("TabLine", {"fg": s:norm, "bg": s:bg_very_subtle})
|
||||
call s:h("TabLineSel", {"fg": s:blue, "bg": s:bg_subtle, "gui": "bold", "cterm": "bold"})
|
||||
call s:h("TabLineFill", {"fg": s:norm, "bg": s:bg_very_subtle})
|
||||
call s:h("CursorColumn", {"bg": s:bg_very_subtle})
|
||||
call s:h("CursorLine", {"bg": s:bg_very_subtle})
|
||||
call s:h("ColorColumn", {"bg": s:bg_subtle})
|
||||
|
||||
" remainder of syntax highlighting
|
||||
call s:h("MatchParen", {"bg": s:bg_subtle, "fg": s:norm})
|
||||
call s:h("qfLineNr", {"fg": s:medium_gray})
|
||||
|
||||
" hi helpHyperTextJump guifg=#5FAFD7 ctermfg=74
|
||||
|
||||
" HTML syntax
|
||||
hi! link htmlTag Special
|
||||
hi! link htmlEndTag htmlTag
|
||||
|
||||
hi! link htmlTagName KeyWord
|
||||
" html5 tags show up as htmlTagN
|
||||
hi! link htmlTagN Keyword
|
||||
|
||||
" HTML content
|
||||
call s:h("htmlH1", {"fg": s:head_a, "gui": "bold,italic", "cterm": "bold" })
|
||||
call s:h("htmlH2", {"fg": s:head_a, "gui": "bold" , "cterm": "bold" })
|
||||
call s:h("htmlH3", {"fg": s:head_b, "gui": "italic" , "cterm": "italic" })
|
||||
call s:h("htmlH4", {"fg": s:head_b, "gui": "italic" , "cterm": "italic" })
|
||||
call s:h("htmlH5", {"fg": s:head_c })
|
||||
call s:h("htmlH6", {"fg": s:head_c })
|
||||
call s:h("htmlLink", {"fg": s:blue , "gui": "underline" , "cterm": "underline"})
|
||||
call s:h("htmlItalic", { "gui": "italic" , "cterm": "italic" })
|
||||
call s:h("htmlBold", { "gui": "bold" , "cterm": "bold" })
|
||||
call s:h("htmlBoldItalic",{ "gui": "bold,italic", "cterm": "bold" })
|
||||
" hi htmlString guifg=#87875f guibg=NONE gui=NONE ctermfg=101 ctermbg=NONE cterm=NONE
|
||||
|
||||
" tpope/vim-markdown
|
||||
call s:h("markdownBlockquote", {"fg": s:norm})
|
||||
call s:h("markdownBold", {"fg": s:norm , "gui": "bold" , "cterm": "bold" })
|
||||
call s:h("markdownBoldItalic", {"fg": s:norm , "gui": "bold,italic", "cterm": "bold" })
|
||||
call s:h("markdownEscape", {"fg": s:norm})
|
||||
call s:h("markdownH1", {"fg": s:head_a, "gui": "bold,italic", "cterm": "bold" })
|
||||
call s:h("markdownH2", {"fg": s:head_a, "gui": "bold" , "cterm": "bold" })
|
||||
call s:h("markdownH3", {"fg": s:head_a, "gui": "italic" , "cterm": "italic"})
|
||||
call s:h("markdownH4", {"fg": s:head_a, "gui": "italic" , "cterm": "italic"})
|
||||
call s:h("markdownH5", {"fg": s:head_a})
|
||||
call s:h("markdownH6", {"fg": s:head_a})
|
||||
call s:h("markdownHeadingDelimiter", {"fg": s:norm})
|
||||
call s:h("markdownHeadingRule", {"fg": s:norm})
|
||||
call s:h("markdownId", {"fg": s:medium_gray})
|
||||
call s:h("markdownIdDeclaration", {"fg": s:norm_subtle})
|
||||
call s:h("markdownItalic", {"fg": s:norm , "gui": "italic" , "cterm": "italic"})
|
||||
call s:h("markdownLinkDelimiter", {"fg": s:medium_gray})
|
||||
call s:h("markdownLinkText", {"fg": s:norm})
|
||||
call s:h("markdownLinkTextDelimiter", {"fg": s:medium_gray})
|
||||
call s:h("markdownListMarker", {"fg": s:norm})
|
||||
call s:h("markdownOrderedListMarker", {"fg": s:norm})
|
||||
call s:h("markdownRule", {"fg": s:norm})
|
||||
call s:h("markdownUrl", {"fg": s:medium_gray, "gui": "underline", "cterm": "underline"})
|
||||
call s:h("markdownUrlDelimiter", {"fg": s:medium_gray})
|
||||
call s:h("markdownUrlTitle", {"fg": s:norm})
|
||||
call s:h("markdownUrlTitleDelimiter", {"fg": s:medium_gray})
|
||||
call s:h("markdownCode", {"fg": s:norm, "bg": s:code_bg})
|
||||
call s:h("markdownCodeDelimiter", {"fg": s:norm, "bg": s:code_bg})
|
||||
|
||||
" plasticboy/vim-markdown
|
||||
call s:h("mkdBlockquote", {"fg": s:norm})
|
||||
call s:h("mkdDelimiter", {"fg": s:medium_gray})
|
||||
call s:h("mkdID", {"fg": s:medium_gray})
|
||||
call s:h("mkdLink", {"fg": s:norm})
|
||||
call s:h("mkdLinkDef", {"fg": s:medium_gray})
|
||||
call s:h("mkdListItem", {"fg": s:norm})
|
||||
call s:h("mkdNonListItemBlock", {"fg": s:norm}) " bug in syntax?
|
||||
call s:h("mkdRule", {"fg": s:norm})
|
||||
call s:h("mkdURL", {"fg": s:medium_gray, "gui": "underline", "cterm": "underline"})
|
||||
call s:h("mkdCode", {"fg": s:norm, "bg": s:code_bg})
|
||||
|
||||
" gabrielelana/vim-markdown
|
||||
call s:h("markdownBlockquoteDelimiter", {"fg": s:norm})
|
||||
call s:h("markdownInlineDelimiter", {"fg": s:norm})
|
||||
call s:h("markdownItemDelimiter", {"fg": s:norm})
|
||||
call s:h("markdownLinkReference", {"fg": s:medium_gray})
|
||||
call s:h("markdownLinkText", {"fg": s:norm})
|
||||
call s:h("markdownLinkTextContainer", {"fg": s:medium_gray})
|
||||
call s:h("markdownLinkUrl", {"fg": s:medium_gray, "gui": "underline", "cterm": "underline"})
|
||||
call s:h("markdownLinkUrlContainer", {"fg": s:medium_gray})
|
||||
call s:h("markdownFencedCodeBlock", {"fg": s:norm, "bg": s:code_bg})
|
||||
call s:h("markdownInlineCode", {"fg": s:norm, "bg": s:code_bg})
|
||||
|
||||
" mattly/vim-markdown-enhancements
|
||||
call s:h("mmdFootnoteDelimiter", {"fg": s:medium_gray})
|
||||
call s:h("mmdFootnoteMarker", {"fg": s:norm})
|
||||
call s:h("mmdTableAlign", {"fg": s:norm})
|
||||
call s:h("mmdTableDelimiter", {"fg": s:norm})
|
||||
call s:h("mmdTableHeadDelimiter", {"fg": s:norm})
|
||||
call s:h("mmdTableHeader", {"fg": s:norm})
|
||||
call s:h("mmdTableCaptionDelimiter", {"fg": s:norm})
|
||||
call s:h("mmdTableCaption", {"fg": s:norm})
|
||||
|
||||
" Textile content
|
||||
" https://github.com/timcharper/textile.vim/blob/master/syntax/textile.vim
|
||||
"call s:h("txtBold", {"fg": s:norm , "gui": "bold" , "cterm": "bold" })
|
||||
"call s:h("txtEmphasis", {"fg": s:norm , "gui": "italic" , "cterm": "italic"})
|
||||
|
||||
" XML content
|
||||
hi! link xmlTag htmlTag
|
||||
hi! link xmlEndTag xmlTag
|
||||
hi! link xmlTagName htmlTagName
|
||||
|
||||
" Signify, git-gutter
|
||||
if g:pencil_gutter_color == 1
|
||||
hi link SignifySignAdd DiffAdd
|
||||
hi link SignifySignDelete DiffDelete
|
||||
hi link SignifySignChange DiffChange
|
||||
hi link GitGutterAdd DiffAdd
|
||||
hi link GitGutterDelete DiffDelete
|
||||
hi link GitGutterChange DiffChange
|
||||
hi link GitGutterChangeDelete DiffChange
|
||||
else
|
||||
hi link SignifySignAdd LineNr
|
||||
hi link SignifySignDelete LineNr
|
||||
hi link SignifySignChange LineNr
|
||||
hi link GitGutterAdd LineNr
|
||||
hi link GitGutterDelete LineNr
|
||||
hi link GitGutterChange LineNr
|
||||
hi link GitGutterChangeDelete LineNr
|
||||
endif
|
||||
130
config/vim/vimrc
130
config/vim/vimrc
@@ -15,9 +15,13 @@ endif
|
||||
|
||||
let g:vim_bootstrap_langs = "go,html,javascript,lua,php,python,typescript"
|
||||
let g:vim_bootstrap_editor = "vim" " nvim or vim
|
||||
let g:vim_bootstrap_theme = "iceberg"
|
||||
let g:vim_bootstrap_theme = "pencil"
|
||||
let g:vim_bootstrap_frams = "vuejs"
|
||||
|
||||
" ale
|
||||
let g:ale_fixers = {}
|
||||
let g:ale_linters = { "python": [ "flake8" ] }
|
||||
|
||||
if !filereadable(vimplug_exists)
|
||||
if !executable(curl_exists)
|
||||
echoerr "You have to install curl or first install vim-plug yourself!"
|
||||
@@ -68,9 +72,6 @@ call plug#begin(expand('$HOME/.config/vim/plugged'))
|
||||
" vim-airline
|
||||
Plug 'vim-airline/vim-airline'
|
||||
|
||||
" iceberg.vim - Iceberg color scheme
|
||||
Plug 'cocopon/iceberg.vim'
|
||||
|
||||
" fzf.vim - Fuzzy finder
|
||||
if isdirectory('~/.config/vim/extra/fzf')
|
||||
Plug '~/.config/vim/extra/fzf' | Plug 'junegunn/fzf.vim'
|
||||
@@ -132,6 +133,92 @@ call plug#begin(expand('$HOME/.config/vim/plugged'))
|
||||
call plug#end()
|
||||
" }}}
|
||||
|
||||
let mapleader=' ' " Map leader to <space>
|
||||
filetype off " disable filetype detection (but re-enable later, see below)
|
||||
|
||||
" find matching tags in html/xml documents using matchit
|
||||
filetype plugin on
|
||||
packadd! matchit
|
||||
" disable super buggy netrw
|
||||
let g:loaded_netrw=1
|
||||
let g:netrw_loaded_netrwPlugin=1
|
||||
" show JSDoc highlight colors
|
||||
let g:javascript_plugin_jsdoc=1
|
||||
|
||||
set backspace=indent,eol,start " Backspace behavior
|
||||
set cindent " Use 'C' style program indenting
|
||||
set cursorline " Highlight current line
|
||||
set encoding=utf-8 " UTF-8
|
||||
set expandtab " Use spaces instead of tabs
|
||||
set fileformats=unix,dos,mac " File formats
|
||||
set foldmethod=indent " Fold based on indent
|
||||
set foldlevel=99 " Open all folds
|
||||
set guioptions=egmrti " GUI options
|
||||
set hidden " Enable hidden buffers
|
||||
set ignorecase " Always case-insensitive
|
||||
set incsearch " Searches for strings incrementally
|
||||
set laststatus=2 " Always show statusline (even with only single window)
|
||||
set linespace=3 " Set line spacing
|
||||
set list " Show invisible characters
|
||||
set listchars=tab:⌴\ ,trail:◼,nbsp:•,extends:…,precedes:… " Invisible characters
|
||||
set modeline " Enable modelines
|
||||
set modelines=3 " Number of lines to check for modelines
|
||||
set mouse=a " Enable mouse support
|
||||
set mousemodel=popup " Enable mouse support
|
||||
set nobackup " Disable backup files
|
||||
set nocompatible " disable compatibility mode with vi
|
||||
set nowritebackup " Disable backup files
|
||||
set number " Show line numbers
|
||||
set relativenumber " Show relative line numbers
|
||||
set ruler " Show row and column ruler information
|
||||
set scrolloff=8 " Minimum number of lines to keep above and below the cursor
|
||||
set shiftwidth=4 " Number of auto-indent spaces
|
||||
set shortmess+=A " Don't show autocommand messages
|
||||
set shortmess+=F " Avoid showing the "file-info" message
|
||||
set shortmess+=I " Don't show intro message
|
||||
set shortmess+=O " Avoid showing the "file-read" message
|
||||
set shortmess+=O " Don't show overlength messages
|
||||
set shortmess+=T " Don't show title messages
|
||||
set shortmess+=W " Don't show "written" messages
|
||||
set shortmess+=a " Avoid showing the "ATTENTION" message
|
||||
set shortmess+=c " Avoid showing the "ins-completion-menu" message
|
||||
set shortmess+=c " Don't pass messages to |ins-completion-menu|
|
||||
set shortmess+=o " Avoid showing the "overlength" message
|
||||
set shortmess+=t " Avoid showing the "trailing whitespace" message
|
||||
set showcmd " Show command in status line
|
||||
set showmatch " Highlight matching brace
|
||||
set signcolumn=yes " Show sign column
|
||||
set smartcase " Enable smart-case search
|
||||
set smartindent " Enable smart-indent
|
||||
set smarttab " Enable smart-tabs
|
||||
set softtabstop=4 " Number of spaces per Tab
|
||||
set spelllang=fi,en " Set the spell language
|
||||
set spellsuggest=double " Suggest the first word when spell checking
|
||||
set t_Co=256 " 256 colors
|
||||
set termguicolors " Enable 24-bit RGB color in the terminal
|
||||
set timeoutlen=500 " By default timeoutlen=1000 (ms)
|
||||
set ttimeoutlen=0 " By default ttimeoutlen=-1 (ms)
|
||||
set undolevels=1000 " Number of undo levels
|
||||
set visualbell " Use visual bell (no beeping)
|
||||
set wildmenu " Enable wildmenu
|
||||
set wildmode=longest,list:longest " Command-line completion mode
|
||||
set wrap " Wrap lines
|
||||
set wrapscan " Searches wrap around the end of the file
|
||||
|
||||
" Ignore these files in wildmenu
|
||||
set wildignore+=*.o,*.obj,.git,*.rbc,*.pyc,__pycache__,vendor
|
||||
|
||||
colorscheme pencil " Set the color scheme
|
||||
filetype plugin indent on " enable filetype detection, plugins and indenting
|
||||
|
||||
" Set the shell
|
||||
if exists('$SHELL')
|
||||
set shell=$SHELL
|
||||
else
|
||||
set shell=/bin/sh
|
||||
endif
|
||||
|
||||
|
||||
" COC
|
||||
let g:coc_global_extensions = [
|
||||
\ '@yaegassy/coc-intelephense',
|
||||
@@ -160,9 +247,6 @@ let g:session_command_aliases = 1
|
||||
|
||||
syntax on
|
||||
|
||||
" set statusline to show the file name
|
||||
" set statusline=%F%m%r%h%w%=(%{&ff}/%Y)\ (line\ %l\/%L)|
|
||||
|
||||
" Search mappings: These will make it so that going to the next one in a
|
||||
" search will center on the line it's found in.
|
||||
nnoremap n nzzzv
|
||||
@@ -180,14 +264,14 @@ let g:airline#extensions#tabline#enabled = 1
|
||||
let g:airline#extensions#tagbar#enabled = 1
|
||||
let g:airline_powerline_fonts = 1
|
||||
let g:airline_skip_empty_sections = 1
|
||||
let g:airline_theme = 'iceberg'
|
||||
let g:airline_theme = 'pencil'
|
||||
|
||||
" NERDTree configuration
|
||||
let g:NERDTreeChDirMode=2
|
||||
let g:NERDTreeIgnore=['node_modules', 'vendor', '\.rbc$', '\~$', '\.pyc$', '\.db$', '\.sqlite$', '__pycache__']
|
||||
let g:NERDTreeSortOrder=['^__\.py$', '\/$', '*', '\.swp$', '\.bak$', '\~$']
|
||||
let g:NERDTreeShowBookmarks=1
|
||||
let g:nerdtree_tabs_focus_on_files=1
|
||||
let g:NERDTreeIgnore = [ 'node_modules', 'vendor', '\.rbc$', '\~$', '\.pyc$', '\.db$', '\.sqlite$', '__pycache__' ]
|
||||
let g:NERDTreeSortOrder = [ '^__\.py$', '\/$', '*', '\.swp$', '\.bak$', '\~$' ]
|
||||
let g:NERDTreeShowBookmarks = 1
|
||||
let g:nerdtree_tabs_focus_on_files = 1
|
||||
let g:NERDTreeMapOpenInTabSilent = '<RightMouse>'
|
||||
let g:NERDTreeWinSize = 50
|
||||
set wildignore+=*/tmp/*,*.so,*.swp,*.zip,*.pyc,*.db,*.sqlite,*node_modules/,*vendor/
|
||||
@@ -267,14 +351,14 @@ xmap <leader>c <Plug>(coc-codeaction-selected)
|
||||
|
||||
let g:wordy#ring = [
|
||||
\ 'weak',
|
||||
\ ['being', 'passive-voice', ],
|
||||
\ [ 'being', 'passive-voice', ],
|
||||
\ 'business-jargon',
|
||||
\ 'weasel',
|
||||
\ 'puffery',
|
||||
\ ['problematic', 'redundant', ],
|
||||
\ ['colloquial', 'idiomatic', 'similies', ],
|
||||
\ [ 'problematic', 'redundant', ],
|
||||
\ [ 'colloquial', 'idiomatic', 'similies', ],
|
||||
\ 'art-jargon',
|
||||
\ ['contractions', 'opinion', 'vague-time', 'said-synonyms', ],
|
||||
\ [ 'contractions', 'opinion', 'vague-time', 'said-synonyms', ],
|
||||
\ 'adjectives',
|
||||
\ 'adverbs',
|
||||
\ ]
|
||||
@@ -303,13 +387,6 @@ endif
|
||||
"" Custom configs
|
||||
"*****************************************************************************
|
||||
|
||||
" ale
|
||||
let g:ale_linters = {
|
||||
\ "vim": [ "vint" ]
|
||||
\}
|
||||
let g:ale_fixers = {
|
||||
\}
|
||||
|
||||
" javascript
|
||||
let g:javascript_enable_domhtmlcss = 1
|
||||
|
||||
@@ -339,11 +416,14 @@ let g:jedi#smart_auto_mappings = 0
|
||||
|
||||
" ale
|
||||
:call extend(g:ale_linters, {
|
||||
\ 'python': [ 'flake8' ],
|
||||
\ 'python': [ 'black' ],
|
||||
\ })
|
||||
|
||||
:call extend(g:ale_fixers, {
|
||||
\ '*': ['remove_trailing_lines', 'trim_whitespace']
|
||||
\ '*': [ 'remove_trailing_lines', 'trim_whitespace' ],
|
||||
\ 'python': [ 'autopep8', 'isort' ],
|
||||
\ })
|
||||
|
||||
let g:ale_sign_column_always = 1
|
||||
let g:ale_fix_on_save = 1
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -5,20 +5,14 @@
|
||||
"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": {
|
||||
"Shell Script": {
|
||||
"enable_language_server": true
|
||||
},
|
||||
"JavaScript": {
|
||||
"enable_language_server": true,
|
||||
"code_actions_on_format": {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
675
local/bin/git-attributes
Executable file
675
local/bin/git-attributes
Executable file
@@ -0,0 +1,675 @@
|
||||
#!/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 "$@"
|
||||
1080
local/bin/git-dirty
1080
local/bin/git-dirty
File diff suppressed because it is too large
Load Diff
185
local/bin/git-dirty.md
Normal file
185
local/bin/git-dirty.md
Normal 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 : -->
|
||||
@@ -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 $?
|
||||
|
||||
65
local/bin/git-fsck-dirs.md
Normal file
65
local/bin/git-fsck-dirs.md
Normal 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 : -->
|
||||
@@ -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 "$@"
|
||||
|
||||
116
local/bin/git-update-dirs.md
Normal file
116
local/bin/git-update-dirs.md
Normal 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
443
local/bin/php-switcher
Executable 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 :
|
||||
@@ -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")
|
||||
@@ -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 "$@"
|
||||
@@ -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
|
||||
|
||||
196
local/bin/x-gh-get-latest-version.md
Normal file
196
local/bin/x-gh-get-latest-version.md
Normal 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 : -->
|
||||
BIN
local/bin/yabai
BIN
local/bin/yabai
Binary file not shown.
1313
local/man/yabai.1
1313
local/man/yabai.1
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
column_width = 120
|
||||
column_width = 90
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
|
||||
Reference in New Issue
Block a user