├── git-ignore.plugin.zsh ├── init.zsh ├── LICENSE ├── functions └── _git-ignore ├── CHANGELOG.md ├── .gitignore ├── README.md └── bin └── git-ignore /git-ignore.plugin.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # Standardized $0 handling 3 | 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 4 | 5 | source "${0:h}/init.zsh" 6 | -------------------------------------------------------------------------------- /init.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019, laggardkernel and the git-ignore contributors 3 | # SPDX-License-Identifier: MIT 4 | 5 | # Generate .gitignore files with templates from gitignore.io 6 | # 7 | # Authors: 8 | # laggardkernel 9 | # 10 | 11 | # Standardized $0 handling 12 | 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 13 | 14 | # Define default confs. 15 | export GI_TEMPLATE="${0:h}/.git-ignore" 16 | 17 | path=("${0:h}/bin" "${path[@]}") 18 | fpath=("${0:h}/functions" "${fpath[@]}") 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 laggardkernel 4 | 5 | Copyright (C) 2019 by Wenxuan Zhang 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /functions/_git-ignore: -------------------------------------------------------------------------------- 1 | #compdef git-ignore 2 | #autoload 3 | # 4 | # Copyright 2019, laggardkernel and the git-ignore contributors 5 | # SPDX-License-Identifier: MIT 6 | 7 | # 8 | # Completes git-ignore. 9 | # 10 | # Authors: 11 | # laggardkernel 12 | # 13 | 14 | local ret=1 15 | 16 | _git-ignore_list() { 17 | local ng=0, ncm=0, IFS=$'\n' 18 | local -a templates 19 | XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}" 20 | [[ -o nullglob ]] && ng=1 || setopt nullglob 21 | [[ -o nocasematch ]] && ncm=1 || setopt nocasematch 22 | 23 | templates=("${GI_TEMPLATE:=$XDG_DATA_HOME/git-ignore}"/templates/*{.gitignore,.patch,.stack}) 24 | templates=("${templates[@]##*/}"); templates=("${templates[@]%%.*}"); 25 | templates=("${(u)templates[@]}") 26 | templates=($(<<< "${templates[@]}" sort -fu)) 27 | templates=("${templates[@]:l}") 28 | 29 | [[ $ng = 1 ]] || unsetopt nullglob 30 | [[ $ncm = 1 ]] || unsetopt nocasematch 31 | 32 | compset -P '*,' 33 | _arguments "*:template:($templates)" 34 | } 35 | 36 | _arguments \ 37 | {-l,--list}'[List available templates]' \ 38 | {-s,--search}'[Search template with keyword in filenames]' \ 39 | {-u,--update}'[Init/Update local templates repo]' \ 40 | {-c,--clean}'[Clean local gitignore templates repo]' \ 41 | {-h,--help}'[Display this help screen]' \ 42 | {-v,--version}'[Display version information and exit]' \ 43 | '*: :_git-ignore_list' && ret=0 44 | 45 | return ret -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.2.0] - 2019-02-14 8 | ### Added 9 | - Completion for command options. (Only template keywords are supported before) 10 | - Customize templates location with environment variable `GI_TEMPLATE` with fallback 11 | 1. `.git-ignore` directory under this plugin's root folder 12 | 2. `$XDG_DATA_HOME/git-ignore` 13 | 3. `$HOME/.local/share/git-ignore` 14 | 15 | ### Changed 16 | - Separate `compdef` into file `function/_git-ignore` to speed thing up. 17 | - Improve globbing for template fetching. 18 | - Move default template location to compliant with XDG base directory 19 | 20 | ### Fixed 21 | - Correct folder name `function` as `functions` 22 | - Quit `fzf` menu directly if no item is selected, skip the later output prompt. 23 | 24 | ## [1.1.0] - 2019-01-23 25 | ### Added 26 | - New CLI with many useful options. 27 | - `git` sub-command `git ignore`. 28 | 29 | ### Changed 30 | - Separate the core function as script `git-ignore`. 31 | - `-l`, list all template names. 32 | - `-s`, search with keyword for available templates. 33 | - `-u`, init/update templates repo. 34 | - `-c`, clean local templates repo. 35 | - `-h`, help menu. 36 | - `-v`, version display. 37 | - Command name `gitignore` is changed as `git-ignore`. 38 | 39 | ### Removed 40 | - Unnecessary external command `basename`. 41 | - Pre-defined settings for `bat`. 42 | 43 | ## [1.0.0] - 2019-01-23 44 | ### Added 45 | - Simple completion for templates implemented using `compadd`. 46 | - Preview in README. 47 | - Support for general plugin mangers with `*.plugin.zsh` filename pattern. 48 | 49 | ### Changed 50 | - Get back the output menu after selection made in `fzf`. Cancel the removal made by forgit. 51 | 52 | ### Fixed 53 | - Scroll the preview section in `fzf` with mouse. 54 | 55 | ### Removed 56 | - Unnecessary `fzf` option `--bind='ctrl-s:toggle-sort'`. 57 | - The input for it is already sorted. 58 | - Optimize the script by using glob and variable expansion, removing: 59 | - Unnecessary external command `find`. 60 | - Unnecessary external command `sed`. 61 | - Unnecessary external command `awk`. 62 | - Unnecessary pipes `|`. 63 | 64 | [Unreleased]: https://github.com/laggardkernel/git-ignore/compare/v1.2.0...HEAD 65 | [1.2.0]: https://github.com/laggardkernel/git-ignore/compare/v1.1.0...v1.2.0 66 | [1.1.0]: https://github.com/laggardkernel/git-ignore/compare/v1.0.0...v1.1.0 67 | [1.0.0]: https://github.com/laggardkernel/git-ignore/compare/11f3ff62...v1.0.0 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | # General 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | ### Linux ### 30 | *~ 31 | 32 | # temporary files which can be created if a process still has a handle open of a deleted file 33 | .fuse_hidden* 34 | 35 | # KDE directory preferences 36 | .directory 37 | 38 | # Linux trash folder which might appear on any partition or disk 39 | .Trash-* 40 | 41 | # .nfs files are created when an open file is removed but is still being accessed 42 | .nfs* 43 | 44 | ### Windows ### 45 | # Windows thumbnail cache files 46 | Thumbs.db 47 | ehthumbs.db 48 | ehthumbs_vista.db 49 | 50 | # Dump file 51 | *.stackdump 52 | 53 | # Folder config file 54 | [Dd]esktop.ini 55 | 56 | # Recycle Bin used on file shares 57 | $RECYCLE.BIN/ 58 | 59 | # Windows Installer files 60 | *.cab 61 | *.msi 62 | *.msix 63 | *.msm 64 | *.msp 65 | 66 | # Windows shortcuts 67 | *.lnk 68 | 69 | ### Vim ### 70 | # Swap 71 | [._]*.s[a-v][a-z] 72 | [._]*.sw[a-p] 73 | [._]s[a-rt-v][a-z] 74 | [._]ss[a-gi-z] 75 | [._]sw[a-p] 76 | 77 | # Session 78 | Session.vim 79 | 80 | # Temporary 81 | .netrwhist 82 | *~ 83 | # Auto-generated tag files 84 | tags 85 | # Persistent undo 86 | [._]*.un~ 87 | 88 | ### Emacs ### 89 | # -*- mode: gitignore; -*- 90 | *~ 91 | \#*\# 92 | /.emacs.desktop 93 | /.emacs.desktop.lock 94 | *.elc 95 | auto-save-list 96 | tramp 97 | .\#* 98 | 99 | # Org-mode 100 | .org-id-locations 101 | *_archive 102 | 103 | # flymake-mode 104 | *_flymake.* 105 | 106 | # eshell files 107 | /eshell/history 108 | /eshell/lastdir 109 | 110 | # elpa packages 111 | /elpa/ 112 | 113 | # reftex files 114 | *.rel 115 | 116 | # AUCTeX auto folder 117 | /auto/ 118 | 119 | # cask packages 120 | .cask/ 121 | dist/ 122 | 123 | # Flycheck 124 | flycheck_*.el 125 | 126 | # server auth directory 127 | /server/ 128 | 129 | # projectiles files 130 | .projectile 131 | 132 | # directory configuration 133 | .dir-locals.el 134 | 135 | # network security 136 | /network-security.data 137 | 138 | 139 | ### SublimeText ### 140 | # Cache files for Sublime Text 141 | *.tmlanguage.cache 142 | *.tmPreferences.cache 143 | *.stTheme.cache 144 | 145 | # Workspace files are user-specific 146 | *.sublime-workspace 147 | 148 | # Project files should be checked into the repository, unless a significant 149 | # proportion of contributors will probably not be using Sublime Text 150 | # *.sublime-project 151 | 152 | # SFTP configuration file 153 | sftp-config.json 154 | 155 | # Package control specific files 156 | Package Control.last-run 157 | Package Control.ca-list 158 | Package Control.ca-bundle 159 | Package Control.system-ca-bundle 160 | Package Control.cache/ 161 | Package Control.ca-certs/ 162 | Package Control.merged-ca-bundle 163 | Package Control.user-ca-bundle 164 | oscrypto-ca-bundle.crt 165 | bh_unicode_properties.cache 166 | 167 | # Sublime-github package stores a github token in this file 168 | # https://packagecontrol.io/packages/sublime-github 169 | GitHub.sublime-settings 170 | 171 | ### VisualStudioCode ### 172 | .vscode/* 173 | !.vscode/settings.json 174 | !.vscode/tasks.json 175 | !.vscode/launch.json 176 | !.vscode/extensions.json 177 | 178 | ### VisualStudioCode Patch ### 179 | # Ignore all local history of files 180 | .history 181 | 182 | ### Custom ### 183 | # template folder 184 | /gitignore/ 185 | /.git-ignore/ 186 | 187 | # ZSH bytecode 188 | *.zwc 189 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # git-ignore 2 | 3 | [![License: MIT][license icon]][license] 4 | 5 | ZSH plugin. Generate `.gitignore` with templates from [gitignore.io][gitignore.io] 6 | **offline**, taking the advantage of [`fzf`][fzf] fuzzy finder, 7 | [`bat`][bat] syntax highlighting and ZSH completion. 8 | 9 | ![images/preview-01.jpg](../assets/images/preview-01.jpg?raw=true) 10 | 11 | ## Feature 12 | 13 | Basically, this plugin is an offline variant of [gitignore.io][gitignore.io] 14 | with ZSH goodies: 15 | - imitating template generation behavior of [gitignore.io][gitignore.io] exactly 16 | - fuzzy finder [`fzf`][fzf] selection with preview 17 | - ZSH completion 18 | - pull/update templates from command line (no need to update this plugin) 19 | 20 | ## Installation 21 | 22 | ### [Zplugin][zplugin] 23 | 24 | The only ZSH plugin manager solves the time-consuming init for 25 | `nvm`, `nodenv`, `pyenv`, `rvm`, `rbenv`, `thefuck`, `fasd`, etc, 26 | with its amazing async [Turbo Mode][turbo mode]. 27 | 28 | ```zsh 29 | zplugin ice pick'init.zsh' blockf 30 | zplugin light laggardkernel/git-ignore 31 | alias gi="git-ignore" 32 | ``` 33 | 34 | Update the plugin with 35 | 36 | ```zsh 37 | $ zplg update laggardkernel/git-ignore 38 | ``` 39 | 40 | ### [Prezto][prezto] 41 | 42 | The only framework does **optimizations** in plugins with sophisticated coding skill: 43 | - [refreshing `.zcompdump` every 20h][prezto zcompdump 1] 44 | - [compiling `.zcompdump` as bytecode in the background][prezto zcompdump 2] 45 | - [caching init script for fasd][prezto fasd] 46 | - saving `*env` startup time with [`init - --no-rehash` for `rbenv`, `pyenv`, `nodenv`][prezto *env] 47 | - [removing the horribly time-consuming `brew command` from `command-not-found`][prezto brew command] 48 | 49 | ```zsh 50 | mkdir -p ${ZDOTDIR:-$HOME}/.zprezto/contrib 2>/dev/null 51 | git clone https://github.com/laggardkernel/git-ignore.git ${ZDOTDIR:-$HOME}/.zprezto/contrib/git-ignore 52 | ``` 53 | 54 | ## Usage 55 | 56 | ```zsh 57 | $ alias gi="git-ignore" 58 | 59 | # Depends on fzf 60 | $ gi # then press 61 | 62 | # Separate params with spaces or commas 63 | $ gi macos linux windows vim emacs >> ./.gitignore 64 | 65 | # Overwrite existing .gitignore 66 | $ gi macos,linux,windows vim emacs >| ./.gitignore 67 | ``` 68 | 69 | ### New CLI (`v1.1.0+`) 70 | 71 | ```zsh 72 | ❯ alias gi="git-ignore" 73 | 74 | ❯ gi -h 75 | git-ignore 1.1.0 by laggardkernel 76 | https://github.com/laggardkernel/git-ignore 77 | 78 | Generates .gitignore files offline using templates from gitignore.io 79 | 80 | Usage: 81 | git-ignore [options] 82 | git-ignore keyword1 keyword2 keyword3 83 | 84 | Example: 85 | git-ignore macos,linux,windows vim emacs >> ./.gitignore 86 | 87 | Options: 88 | -l, --list List available templates 89 | -s, --search keyword Search template with keyword in filenames 90 | -u, --update Init/Update local templates repo 91 | -c, --clean Clean local gitignore templates repo 92 | -h, --help Display this help screen 93 | -v, --version Display version information and exit 94 | 95 | ❯ gi -l 96 | 1C,1C-Bitrix,A-Frame,Actionscript,Ada,Adobe,AdvancedInstaller,Agda,AL... 97 | # omitted because it is too long 98 | Total: 479 99 | 100 | ❯ gi -s py # then press for completion 101 | pycharm pycharm+all pycharm+iml pydev python 102 | 103 | ❯ gi -u 104 | [Info] Updating gitignore repo... 105 | Already up to date. 106 | 107 | ❯ gi -c 108 | [Info] No available local gitignore repo 109 | [Info] Use `gi -u` to init 110 | ``` 111 | 112 | ### Environment Variables 113 | `GI_TEMPLATE`: location for templates storage. It fallbacks to: 114 | 1. `.git-ignore` directory under plugin's root folder 115 | 2. `${XDG_DATA_HOME}/git-ignore` (in case the script is not used as a ZSH plugin) 116 | 3. `$HOME/.local/share/git-ignore` 117 | 118 | ## Optional Dependencies 119 | - [`fzf`][fzf]: Command-line fuzzy finder 120 | - [`bat`][bat]: Syntax highlighting for `.gitignore` templates. 121 | 122 | ### Default Keybindings for `fzf` 123 | 124 | | Keybind | Action | 125 | | :-------------------------------------------: | ----------------------- | 126 | | Enter | Confirm | 127 | | Tab | Toggle mark | 128 | | ? | Toggle preview window | 129 | | Ctrl - R | Toggle selection | 130 | | Alt - W | Toggle preview wrap | 131 | | Ctrl - K / P | Selection up | 132 | | Ctrl - J / N | Selection down | 133 | | Alt - K / P | Preview up | 134 | | Alt - J / N | Preview down | 135 | 136 | ## Todo 137 | 138 | - [ ] Support all types of templates files from [dvcs/gitignore][dvcs/gitignore] 139 | - [x] Templates 140 | - [x] Patch 141 | - [x] Stack 142 | - [ ] Order 143 | - [x] Remove unnecessary external dependencies: ~~`sed`~~, ~~`awk`~~ 144 | - [x] ZSH completion 145 | - [x] Separate `compdef` into file `functions/_git-ignore` 146 | - [x] `git` sub-command `git ignore` 147 | - [x] Options like `--list`, `--update`, `--search`, etc 148 | - ~~[ ] Configure the plugin with `zstyle`~~ 149 | - [x] custom template storage location with `GI_TEMPLATE` 150 | - [ ] Script file compatible with BASH 151 | 152 | ## Related projects 153 | 154 | [wfxr/forgit][wfxr/forgit]: [git-ignore][git-ignore] was designed to be a feature of 155 | it. And generating `.gitignore` files **offline** was first introduced by me into it. 156 | Later, [git-ignore](https://github.com/laggardkernel) is separated from forgit 157 | because of disagreement on implementation. 158 | 159 | [dvcs/gitignore][dvcs/gitignore]: The largest collection of useful `.gitignore` 160 | templates, maintained by [https://www.gitignore.io][gitignore.io]. 161 | 162 | [simonwhitaker/gibo][simonwhitaker/gibo]: Another `.gitignore` generator using 163 | templates from [github/gitignore][github/gitignore] written in POSIX sh. 164 | 165 | ## License 166 | 167 | The MIT License (MIT) 168 | 169 | Copyright (c) 2019 laggardkernel 170 | 171 | Copyright (c) 2019 Wenxuan Zhang 172 | 173 | [license icon]: https://img.shields.io/badge/License-MIT-yellow.svg 174 | [license]: https://opensource.org/licenses/MIT 175 | [gitignore.io]: https://www.gitignore.io/ 176 | [fzf]: https://github.com/junegunn/fzf 177 | [bat]: https://github.com/sharkdp/bat 178 | [dvcs/gitignore]: https://github.com/dvcs/gitignore 179 | [zplugin]: https://github.com/zdharma/zplugin 180 | [turbo mode]: https://github.com/zdharma/zplugin#turbo-mode-zsh--53 181 | [prezto]: https://github.com/sorin-ionescu/prezto 182 | [prezto zcompdump 1]: https://github.com/sorin-ionescu/prezto/blob/4abbc5572149baa6a5e7e38393a4b2006f01024f/modules/completion/init.zsh#L31-L41 183 | [prezto zcompdump 2]: https://github.com/sorin-ionescu/prezto/blob/4abbc5572149baa6a5e7e38393a4b2006f01024f/runcoms/zlogin#L9-L15 184 | [prezto fasd]: https://github.com/sorin-ionescu/prezto/blob/4abbc5572149baa6a5e7e38393a4b2006f01024f/modules/fasd/init.zsh#L22-L36 185 | [prezto *env]: https://github.com/sorin-ionescu/prezto/blob/4abbc5572149baa6a5e7e38393a4b2006f01024f/modules/python/init.zsh#L22 186 | [prezto brew command]: https://github.com/sorin-ionescu/prezto/blob/4abbc5572149baa6a5e7e38393a4b2006f01024f/modules/command-not-found/init.zsh 187 | [wfxr/forgit]: https://github.com/wfxr/forgit 188 | [git-ignore]: https://github.com/laggardkernel/git-ignore 189 | [simonwhitaker/gibo]: https://github.com/simonwhitaker/gibo 190 | [github/gitignore]: https://github.com/github/gitignore 191 | -------------------------------------------------------------------------------- /bin/git-ignore: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # Copyright 2019, laggardkernel and the git-ignore contributors 3 | # SPDX-License-Identifier: MIT 4 | 5 | # Generate .gitignore files with templates from gitignore.io 6 | # 7 | # Authors: 8 | # laggardkernel 9 | # 10 | 11 | # Standardized $0 handling 12 | 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 13 | XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}" 14 | 15 | # Define default confs. 16 | typeset -g GI_TEMPLATE="${GI_TEMPLATE:=$XDG_DATA_HOME/git-ignore}" 17 | typeset -gA GI_OPTS 18 | : "${GI_OPTS[version]=1.2.0}" 19 | : "${GI_OPTS[script]="${0##*/}"}" 20 | : "${GI_OPTS[template]:=$GI_TEMPLATE}" 21 | 22 | if (( $+commands[bat] )); then 23 | _gitignore_colorize() { bat -l gitignore "$@"; } 24 | GI_OPTS[preview_cmd]="bat -l gitignore --color=always" 25 | else 26 | _gitignore_colorize() { cat "$@"; } 27 | GI_OPTS[preview_cmd]="cat" 28 | fi 29 | 30 | _gitignore_usage() { 31 | _gitignore_version 32 | cat << EOF >&2 33 | 34 | Generates .gitignore files offline using templates from gitignore.io 35 | 36 | Usage: 37 | ${GI_OPTS[script]} [options] 38 | ${GI_OPTS[script]} keyword1 keyword2 keyword3 39 | 40 | Example: 41 | ${GI_OPTS[script]} macos,linux,windows vim emacs >> ./.gitignore 42 | 43 | Options: 44 | -l, --list List available templates 45 | -s, --search keyword Search template with keyword in filenames 46 | -u, --update Init/Update local templates repo 47 | -c, --clean Clean local gitignore templates repo 48 | -h, --help Display this help screen 49 | -v, --version Display version information and exit 50 | EOF 51 | } 52 | 53 | _gitignore_version() { 54 | echo "${GI_OPTS[script]} ${GI_OPTS[version]} by laggardkernel " 55 | echo "https://github.com/laggardkernel/git-ignore/blob/master/CHANGELOG.md" 56 | } 57 | 58 | _gitignore_info() { printf "%b[Info]%b %s\\n" '\e[0;32m' '\e[0m' "$@" >&2; } 59 | 60 | _gitignore_update() { 61 | if [[ -d "${GI_OPTS[template]}" ]]; then 62 | _gitignore_info 'Updating gitignore repo...' 63 | (cd "${GI_OPTS[template]}" && git pull --no-rebase --ff) || return 1 64 | else 65 | _gitignore_info 'Initializing gitignore repo...' 66 | git clone --depth=1 https://github.com/denis230v/gitignore.git "${GI_OPTS[template]}" 67 | fi 68 | } 69 | 70 | _gitignore_clean() { 71 | if [[ -d "${GI_OPTS[template]}" ]]; then 72 | _gitignore_info "Cleaning gitignore repo from ${GI_OPTS[template]}..." 73 | rm -rf "${GI_OPTS[template]}" 74 | else 75 | _gitignore_info "No available local gitignore repo" 76 | _gitignore_info 'Use `gi -u` to init' 77 | fi 78 | } 79 | 80 | _gitignore_list() { 81 | local ng=0, ncm=0, IFS=$'\n' 82 | local -a templates 83 | [[ -o nullglob ]] && ng=1 || setopt nullglob 84 | [[ -o nocasematch ]] && ncm=1 || setopt nocasematch 85 | 86 | templates=("${GI_OPTS[template]}"/templates/*{.gitignore,.patch,.stack}) 87 | templates=("${templates[@]##*/}"); templates=("${templates[@]%%.*}"); 88 | templates=("${(u)templates[@]}") 89 | <<< "${templates[@]}" sort -fu 90 | 91 | [[ $ng = 1 ]] || unsetopt nullglob 92 | [[ $ncm = 1 ]] || unsetopt nocasematch 93 | } 94 | 95 | _gitignore_get() { 96 | local header 97 | local ng=0, ncg=0 98 | [[ -o nullglob ]] && ng=1 || setopt nullglob 99 | [[ -o nocaseglob ]] && ncg=1 || setopt nocaseglob 100 | 101 | for item in "$@"; do 102 | # Be careful of the trivial case: Code.stack, doesn't fall in ${item}.*.stack 103 | for template in "${GI_OPTS[template]}"/templates/${item}{.gitignore*,.patch*,.*stack}; do 104 | if [[ "$template" == *.gitignore ]]; then 105 | header="${template##*/}"; header="${header%.gitignore}" 106 | echo "### $header ###" 107 | cat "$template" 108 | echo "" 109 | elif [[ "$template" == *.patch ]]; then 110 | header="${template##*/}"; header="${header%.patch}" 111 | echo "### $header Patch ###" 112 | cat "$template" 113 | echo "" 114 | else 115 | header="${template##*/}"; header="${header%.stack}" 116 | echo "### $header Stack ###" 117 | cat "$template" 118 | echo "" 119 | fi 120 | done 121 | done 122 | 123 | [[ $ng = 1 ]] || unsetopt nullglob 124 | [[ $ncg = 1 ]] || unsetopt nocaseglob 125 | } 126 | 127 | _gitignore_search() { 128 | local ng=0, ncg=0, header 129 | local -a arr 130 | local -a ret 131 | local -a args 132 | [[ -o nullglob ]] && ng=1 || setopt nullglob 133 | [[ -o nocaseglob ]] && ncg=1 || setopt nocaseglob 134 | for item in "$@"; do 135 | IFS=',' read -r -A arr <<< "$item" 136 | args=("${args[@]}" "${arr[@]}") 137 | done 138 | 139 | for item in "${args[@]}"; do 140 | # Be careful of the trivial case: Code.stack 141 | for template in "${GI_OPTS[template]}"/templates/${item}{*.gitignore,*.patch,*.stack}; do 142 | header="${template##*/}"; header="${header%.*}" 143 | ret=("${ret[@]}" "$header") 144 | done 145 | done 146 | ret=("${(u)ret[@]}") 147 | echo "${ret[@]}" 148 | 149 | [[ $ng = 1 ]] || unsetopt nullglob 150 | [[ $ncg = 1 ]] || unsetopt nocaseglob 151 | } 152 | 153 | _gitignore_main() { 154 | [ -d "${GI_OPTS[template]}" ] || _gitignore_update 155 | 156 | local IFS=$'\n' 157 | local -a args 158 | 159 | if [[ $# -eq 0 ]]; then 160 | local preview_cmd choice 161 | local -a menu 162 | 163 | preview_cmd="{ ${GI_OPTS[preview_cmd]} ${GI_OPTS[template]}/templates/{2}{.gitignore,.patch}; ${GI_OPTS[preview_cmd]} ${GI_OPTS[template]}/templates/{2}*.stack } 2>/dev/null" 164 | 165 | args=($(_gitignore_list | nl -nrn -w4 -s' ' | 166 | _gitignore_fzf -m --preview="$preview_cmd" | 167 | cat 168 | )) 169 | 170 | [[ ${#args[@]} -eq 0 ]] && return 1 || args=("${args[@]##* }") 171 | 172 | menu=('1) Output to stdout' 173 | '2) Append to .gitignore' 174 | '3) Overwrite .gitignore') 175 | choice=$(<<< "${menu[@]}" _gitignore_fzf +m) 176 | # shellcheck disable=SC2068 177 | case "$choice" in 178 | 1*) 179 | _gitignore_get "${args[@]}" | _gitignore_colorize 180 | ;; 181 | 2*) 182 | [[ -e ./.gitignore ]] || touch ./.gitignore 183 | _gitignore_get "${args[@]}" >> ./.gitignore 184 | ;; 185 | 3*) 186 | _gitignore_get "${args[@]}" >| ./.gitignore 187 | ;; 188 | esac 189 | set +x 190 | else 191 | local -a arr 192 | 193 | # separate strings with comma into arrays 194 | for item in "$@"; do 195 | IFS=',' read -r -A arr <<< "$item" 196 | args=("${args[@]}" ${arr[@]}) 197 | done 198 | _gitignore_get "${args[@]}" | _gitignore_colorize 199 | fi 200 | } 201 | 202 | _gitignore_fzf() { 203 | FZF_DEFAULT_OPTS=" 204 | $FZF_DEFAULT_OPTS 205 | --ansi 206 | --height '80%' 207 | --preview-window='right:62%' 208 | --bind='alt-k:preview-up,alt-p:preview-up' 209 | --bind='alt-j:preview-down,alt-n:preview-down' 210 | --bind='ctrl-r:toggle-all' 211 | --bind='?:toggle-preview' 212 | --bind='alt-w:toggle-preview-wrap' 213 | " fzf "$@" 214 | } 215 | 216 | function join { local IFS="$1"; shift; echo "$*"; } 217 | 218 | # Option parsing 219 | if [[ $# -eq 0 ]]; then 220 | if (( $+commands[fzf] )); then 221 | _gitignore_main 222 | else 223 | _gitignore_usage 224 | fi 225 | else 226 | case "$1" in 227 | -l|--list) 228 | ret=($(_gitignore_list)) 229 | join "," "${ret[@]}" 230 | echo "Total: ${#ret[@]}" 231 | ;; 232 | -s|--search) 233 | shift 234 | _gitignore_search "$@" 235 | ;; 236 | -u|--update) 237 | _gitignore_update 238 | ;; 239 | -c|--clean) 240 | _gitignore_clean 241 | ;; 242 | -h|--help) 243 | _gitignore_usage; 244 | exit 0 245 | ;; 246 | -v|--version) 247 | _gitignore_version 248 | exit 0 249 | ;; 250 | [!-]*) 251 | _gitignore_main "$@" 252 | ;; 253 | *) 254 | (>&2 printf "Unknown parameter: %s\n" "$1") 255 | _gitignore_usage 256 | exit 1 257 | ;; 258 | esac 259 | fi 260 | --------------------------------------------------------------------------------