Skip to content

Commit

Permalink
Feature: Add interactive git attributes generator
Browse files Browse the repository at this point in the history
  • Loading branch information
sandr01d committed Nov 12, 2024
1 parent 7a40a11 commit 7c12eca
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 32 deletions.
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ forgit_diff=gd
forgit_add=ga
forgit_reset_head=grh
forgit_ignore=gi
forgit_attributes=gat
forgit_checkout_file=gcf
forgit_checkout_branch=gcb
forgit_branch_delete=gbd
Expand Down Expand Up @@ -253,14 +254,15 @@ Forgit will use the default configured pager from git (`core.pager`,
`pager.show`, `pager.diff`) but can be altered with the following environment
variables:

| Use case | Option | Fallbacks to |
| ------------ | ------------------- | --------------------------------------------- |
| common pager | `FORGIT_PAGER` | `git config core.pager` _or_ `cat` |
| pager on `git show` | `FORGIT_SHOW_PAGER` | `git config pager.show` _or_ `$FORGIT_PAGER` |
| pager on `git diff` | `FORGIT_DIFF_PAGER` | `git config pager.diff` _or_ `$FORGIT_PAGER` |
| pager on `git blame` | `FORGIT_BLAME_PAGER` | `git config pager.blame` _or_ `$FORGIT_PAGER` |
| pager on `gitignore` | `FORGIT_IGNORE_PAGER` | `bat -l gitignore --color always` _or_ `cat` |
| git log format | `FORGIT_GLO_FORMAT` | `%C(auto)%h%d %s %C(black)%C(bold)%cr%reset` |
| Use case | Option | Fallbacks to |
| ------------------------ | ------------------------- | ------------------------------------------------- |
| common pager | `FORGIT_PAGER` | `git config core.pager` _or_ `cat` |
| pager on `git show` | `FORGIT_SHOW_PAGER` | `git config pager.show` _or_ `$FORGIT_PAGER` |
| pager on `git diff` | `FORGIT_DIFF_PAGER` | `git config pager.diff` _or_ `$FORGIT_PAGER` |
| pager on `git blame` | `FORGIT_BLAME_PAGER` | `git config pager.blame` _or_ `$FORGIT_PAGER` |
| pager on `gitignore` | `FORGIT_IGNORE_PAGER` | `bat -l gitignore --color always` _or_ `cat` |
| pager on `gitatrributes` | `FORGIT_ATTRIBUTES_PAGER` | `bat -l gitattributes --color always` _or_ `cat` |
| git log format | `FORGIT_GLO_FORMAT` | `%C(auto)%h%d %s %C(black)%C(bold)%cr%reset` |

## fzf options

Expand All @@ -285,6 +287,7 @@ Customizing fzf options for each command individually is also supported:
| `glo` | `FORGIT_LOG_FZF_OPTS` |
| `grl` | `FORGIT_REFLOG_FZF_OPTS` |
| `gi` | `FORGIT_IGNORE_FZF_OPTS` |
| `gat` | `FORGIT_ATTRIBUTES_FZF_OPTS` |
| `gd` | `FORGIT_DIFF_FZF_OPTS` |
| `grh` | `FORGIT_RESET_HEAD_FZF_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_FZF_OPTS` |
Expand Down Expand Up @@ -338,7 +341,7 @@ export FORGIT_LOG_FZF_OPTS='

- [`delta`](https://github.com/dandavison/delta) / [`diff-so-fancy`](https://github.com/so-fancy/diff-so-fancy): For better human-readable diffs.

- [`bat`](https://github.com/sharkdp/bat.git): Syntax highlighting for `gitignore`.
- [`bat`](https://github.com/sharkdp/bat.git): Syntax highlighting for `gitignore` and `gitattributes`.

- [`emoji-cli`](https://github.com/wfxr/emoji-cli): Emoji support for `git log`.

Expand Down Expand Up @@ -366,7 +369,7 @@ If you're having issues after updating, and commands such as `forgit::add` or al

- Most of the commands accept optional arguments (e.g., `glo develop`, `glo f738479..188a849b -- main.go`, `gco master`).
- `gd` supports specifying revision(e.g., `gd HEAD~`, `gd v1.0 README.md`).
- Call `gi` with arguments to get the wanted `.gitignore` contents directly(e.g., `gi cmake c++`).
- Call `gi` or `gat` with arguments to get the wanted `.gitignore`/`.gitattributes` contents directly(e.g., `gi cmake c++`).

# 📃 License

Expand Down
92 changes: 70 additions & 22 deletions bin/git-forgit
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ _forgit_get_pager() {
show) echo -n "${FORGIT_SHOW_PAGER:-$(git config pager.show || _forgit_get_pager)}" ;;
diff) echo -n "${FORGIT_DIFF_PAGER:-$(git config pager.diff || _forgit_get_pager)}" ;;
ignore) echo -n "${FORGIT_IGNORE_PAGER:-$(hash bat &>/dev/null && echo 'bat -l gitignore --color=always' || echo 'cat')}" ;;
attributes) echo -n "${FORGIT_ATTRIBUTES_PAGER:-$(hash bat &>/dev/null && echo 'bat -l gitattributes --color=always' || echo 'cat')}" ;;
blame) echo -n "${FORGIT_BLAME_PAGER:-$(git config pager.blame || _forgit_get_pager)}" ;;
enter) echo -n "${FORGIT_ENTER_PAGER:-"LESS='-r' less"}" ;;
*) echo "pager not found: $1" >&2 ;;
Expand Down Expand Up @@ -947,55 +948,100 @@ export FORGIT_GI_REPO_REMOTE=${FORGIT_GI_REPO_REMOTE:-https://github.com/dvcs/gi
export FORGIT_GI_REPO_LOCAL="${FORGIT_GI_REPO_LOCAL:-${XDG_CACHE_HOME:-$HOME/.cache}/forgit/gi/repos/dvcs/gitignore}"
export FORGIT_GI_TEMPLATES=${FORGIT_GI_TEMPLATES:-$FORGIT_GI_REPO_LOCAL/templates}

_forgit_ignore_preview() {
_forgit_path_preview() {
local path name ext pager
path=$1
name=$2
ext=$3
pager=$4
quoted_files=()
for file in "$FORGIT_GI_TEMPLATES/$1"{,.gitignore}; do
while IFS='' read -r file; do
quoted_files+=("'$file'")
done
_forgit_pager ignore "${quoted_files[@]}" 2>/dev/null
done < <(find -L "$path" -type f -name "$name" -o -name "$name$ext")
_forgit_pager "$pager" "${quoted_files[@]}" 2>/dev/null
}

_forgit_ignore() {
[ -d "$FORGIT_GI_REPO_LOCAL" ] || _forgit_ignore_update
[ -d "$FORGIT_GI_REPO_LOCAL" ] \
|| _forgit_repo_update "$FORGIT_GI_REPO_REMOTE" "$FORGIT_GI_REPO_LOCAL"
local IFS args opts
opts="
$FORGIT_FZF_DEFAULT_OPTS
-m --preview-window='right:70%'
--preview=\"$FORGIT ignore_preview {2}\"
--preview=\"$FORGIT path_preview $FORGIT_GI_TEMPLATES {2} .gitignore ignore\"
$FORGIT_IGNORE_FZF_OPTS
"
args=("$@")
if [[ $# -eq 0 ]]; then
args=()
while IFS='' read -r arg; do
args+=("$arg")
done < <(_forgit_ignore_list | nl -w4 -s' ' |
done < <(_forgit_paths_list "$FORGIT_GI_TEMPLATES" .gitignore |
nl -w4 -s' ' |
FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $2}')
fi
[ ${#args[@]} -eq 0 ] && return 1
_forgit_path_get "$FORGIT_GI_TEMPLATES" .gitignore "${args[@]}"
}

# git attributes generator
export FORGIT_ATTR_REPO_REMOTE=${FORGIT_ATTR_REPO_REMOTE:-https://github.com/gitattributes/gitattributes}
export FORGIT_ATTR_REPO_LOCAL=${FORGIT_ATTR_REPO_LOCAL:-${XDG_CACHE_HOME:-$HOME/.cache}/forgit/gat/repos/gitattributes/gitattributes}
export FORGIT_ATTR_TEMPLATES=${FORGIT_ATTR_TEMPLATES:-$FORGIT_ATTR_REPO_LOCAL}

_forgit_attributes() {
[ -d "$FORGIT_ATTR_REPO_LOCAL" ] \
|| _forgit_repo_update "$FORGIT_ATTR_REPO_REMOTE" "$FORGIT_ATTR_REPO_LOCAL"
local IFS args opts
opts="
$FORGIT_FZF_DEFAULT_OPTS
-m --preview-window='right:70%'
--preview=\"$FORGIT path_preview $FORGIT_ATTR_TEMPLATES {2} .gitattributes attributes\"
$FORGIT_ATTRIBUTES_FZF_OPTS
"
args=("$@")
if [[ $# -eq 0 ]]; then
args=()
while IFS='' read -r arg; do
args+=("$arg")
done < <(_forgit_paths_list "$FORGIT_ATTR_TEMPLATES" .gitattributes |
nl -w4 -s' ' |
FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $2}')
fi
[ ${#args[@]} -eq 0 ] && return 1
_forgit_ignore_get "${args[@]}"
_forgit_path_get "$FORGIT_ATTR_TEMPLATES" .gitattributes "${args[@]}"
}
_forgit_ignore_update() {
if [[ -d "$FORGIT_GI_REPO_LOCAL" ]]; then
_forgit_info 'Updating gitignore repo...'
(cd "$FORGIT_GI_REPO_LOCAL" && git pull --no-rebase --ff) || return 1

_forgit_repo_update() {
local rem loc
rem=$1
loc=$2
if [[ -d "$loc" ]]; then
_forgit_info 'Updating repo...'
(cd "$loc" && git pull --no-rebase --ff) || return 1
else
_forgit_info 'Initializing gitignore repo...'
git clone --depth=1 "$FORGIT_GI_REPO_REMOTE" "$FORGIT_GI_REPO_LOCAL"
_forgit_info 'Initializing repo...'
git clone --depth=1 "$rem" "$loc"
fi
}
_forgit_ignore_get() {
local item filename header
_forgit_path_get() {
local path ext item filename header
path=$1
ext=$2
shift 2
for item in "$@"; do
if filename=$(find -L "$FORGIT_GI_TEMPLATES" -type f \( -iname "${item}.gitignore" -o -iname "${item}" \) -print -quit); then
[[ -z "$filename" ]] && _forgit_warn "No gitignore template found for '$item'." && continue
header="${filename##*/}" && header="${header%.gitignore}"
if filename=$(find -L "$path" -type f \( -iname "${item}$ext" -o -iname "${item}" \) -print -quit); then
[[ -z "$filename" ]] && _forgit_warn "No template found for '$item'." && continue
header="${filename##*/}" && header="${header%"$ext"}"
echo "### $header" && cat "$filename" && echo
fi
done
}
_forgit_ignore_list() {
find "$FORGIT_GI_TEMPLATES" -print |sed -e 's#.gitignore$##' -e 's#.*/##' | sort -fu
_forgit_paths_list() {
local path ext
path=$1
ext=$2
find "$path" -name "*$ext" -print |sed -e "s#$ext\$##" -e 's#.*/##' -e '/^$/d' | sort -fu
}
_forgit_ignore_clean() {
setopt localoptions rmstarsilent
Expand All @@ -1004,6 +1050,7 @@ _forgit_ignore_clean() {

public_commands=(
"add"
"attributes"
"blame"
"branch_delete"
"checkout_branch"
Expand All @@ -1027,6 +1074,7 @@ public_commands=(

private_commands=(
"add_preview"
"attributes_preview"
"blame_preview"
"branch_preview"
"checkout_commit_preview"
Expand All @@ -1036,7 +1084,7 @@ private_commands=(
"clean_preview"
"diff_enter"
"file_preview"
"ignore_preview"
"path_preview"
"revert_preview"
"reset_head_preview"
"stash_push_preview"
Expand Down
6 changes: 6 additions & 0 deletions forgit.plugin.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ forgit::ignore::clean() {
"$FORGIT" ignore_clean "$@"
}

forgit::attributes() {
"$FORGIT" attributes "$@"
}

# register aliases
# shellcheck disable=SC2139
if [[ -z "$FORGIT_NO_ALIASES" ]]; then
Expand All @@ -147,6 +151,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
export forgit_reflog="${forgit_reflog:-grl}"
export forgit_diff="${forgit_diff:-gd}"
export forgit_ignore="${forgit_ignore:-gi}"
export forgit_attributes="${forgit_attributes:-gat}"
export forgit_checkout_file="${forgit_checkout_file:-gcf}"
export forgit_checkout_branch="${forgit_checkout_branch:-gcb}"
export forgit_checkout_commit="${forgit_checkout_commit:-gco}"
Expand All @@ -167,6 +172,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
alias "${forgit_reflog}"='forgit::reflog'
alias "${forgit_diff}"='forgit::diff'
alias "${forgit_ignore}"='forgit::ignore'
alias "${forgit_attributes}"='forgit::attributes'
alias "${forgit_checkout_file}"='forgit::checkout::file'
alias "${forgit_checkout_branch}"='forgit::checkout::branch'
alias "${forgit_checkout_commit}"='forgit::checkout::commit'
Expand Down

0 comments on commit 7c12eca

Please # to comment.