diff --git a/AUTHORS.md b/AUTHORS.md index dbeec9e..4829c5c 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,4 +1,5 @@ # Authors * Jorge Bucaran <[j@bucaran.me](mailto:j@bucaran.me)> +* Daniel Perez <[daniel@claudetech.com](mailto:daniel@claudetech.com)> * Hyeon Kim <[simnalamburt@gmail.com](mailto:simnalamburt@gmail.com)> * Kevin Ballard <[kevin@sb.org](mailto:kevin@sb.org)> diff --git a/CHANGELOG.md b/CHANGELOG.md index 85491ed..7c88616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,46 +1,95 @@ # Change Log -+ [0.4.0](#040) :gem: +* [0.5.0](#050) + + The *highlights* of this version are a large refactor of the install/uninstall algorithms, a rewrite of the entire test suite adding better coverage / improving test speed and support for user key bindings. + + +* [0.4.0](#040) * [0.3.1](#031) * [0.3.0](#030) * [0.2.0](#020) * [0.1.0](#010) +## [0.5.0][v050] - 2016-01-20 + +* **Add user key bindings support.** (See #42). + + Recall `$fisher_home/functions` are always before user functions in `$fish_function_path`. This was an early design decision in order to prevent users from redefining core functions by mistake or by means other than using plugins (recommended). In other words, you are free to create a plugin that modifies a Fisherman core function, but you can't redefine a Fisherman function privately by saving it to your user config fish. If you found a bug in a Fisherman function, instead of creating a private patch send it upstream. If you created a function that overrides a Fisherman core feature, create a plugin. This way the community can benefit from your code whenever you are ready to publish it. + + By default, Fisherman provides no `fish_user_key_bindings`, so if the user has already defined their own `fish_user_key_bindings` that one will not be affected. + + Now, plugins **can** define their own key bindings inside a `fish_user_key_bindings.fish` *or* `key_bindings.fish` at the root of their repository or inside a `functions` directory. You can put your key bindings inside a function or not. If you put it inside a function, the function name **must** be the same as the file without the `.fish` extension. + + + *`$fisher_config/bindings.fish`* + + When a plugin with key bindings is installed for the first time or the only one with bindings is uninstalled, Fisherman will modify `~/.config/functions/fish_user_key_bindings.fish` (or create it for the first time) and add a single line at the top of the `fish_user_key_bindings` function to source the new **`$fisher_config/bindings.fish`**. All the key bindings defined by the enabled/installed plugins are concatenated and saved to this file. + + This mechanism has the following **advantages**: + + * Does not slow down shell start. + * Does not require Fisherman to provide his own `fish_user_key_bindings` by default. + * Honors any previously existing user key bindings. + * Allows plugin to define their own key bindings and coexist with the user's key bindings. + * If the user updates his `fish_user_key_bindings`, re-running the function **does** update the key bindings. + +* **Mega Refactoring** + + + The entire source code of Fisherman received a major revision and refactoring. The validation and install/uninstall mechanisms were thoroughly revised and and broken down into smaller functions easier to test as well as several other sub parts of the system. + + + Rewrite `fisher search` and remove features that are mostly already covered by `fisher --list` and remove the ability to generate information about plugins of unknown origin. The decision to **remove this feature** was based in performance concerns and the result of thinking about the usability and whether it was really worth the speed tradeoff. The conclusion is I would rather have better performance and if I need to query a plugins origin I can always use `fisher --list` or `fisher --list=url` or `fisher --list=author`. + + + Add `$fisher_update_interval` to determine if the index should update or not when a search query is taking place. The default value is 10 seconds. This means the index will *not* be updated if less than 10 seconds have elapsed since the last action that triggered an update in the first place. See #43. + + + Improve Install/Uninstall/Update status output. If a plugin fails to install decrease the total. If any plugins are skipped because they are already installed in the case of `fisher install` or available in the cache, but disabled in the case of `fisher uninstall` they are collected into an array and displayed in a new section `n plugin/s skipped (a, b, c)` at the bottom of the report. + + +* **Improve test coverage.** + + + Tightly coupled functions were making testing increasingly difficult. Most of the test effort was basically testing whether `git clone` or `git pull`. New separation of concerns makes tests run faster and the difficult install/uninstall algorithms has better coverage now. + +* **Other** + + + Now `__fisher_list` can list plugins from the _cache_, a _fishfile/bundle_ and plugins that are _installed/enabled_ or _disabled_. This removes `__fisher_file` and combines it with `__fisher_list`. This also removes `fisher -f` and replaces it with `fisher -l ` or `fisher --list=`. + + + Rename `__fisher_parse_help` to `__fisher_complete` and have the function create the completions automatically. This allows you to complete your commands with parseable usage help faster. The original design was fine, but this change improves auto-complete performance so it was preferred. + + + Use `__fisher_index_update` when building file with Make. This helps prevent an error when using a `fish` version < 2.2.0. See #55 #50 #48. + + + Add `__fisher_index_update` to update the index and remove previously undocumented `fisher update --index`. This function is designed to bypass GitHub's server network cache passing an arbitrary query string to `curl` like `$fisher_index?RANDOM_NUMBER`. This means index updates are immediately available now. + + + Add `fisher --list=url` option to display local plugin url or path. + + + Add `fisher --list=bare` option to display local plugins in the cache without the `*` enabled symbol. + + + Prepend `>` to the currently enabled theme when using `fisher --list[=cache]`. Related #49. + + + Prepend `*` to plugin names to indicate they are currently enabled when using `fisher --list[=cache]`. See #49. + + ## [0.4.0][v040] - 2016-01-11 -:anchor: Introducting Fisherman's official website :construction: +* Introducing Fisherman's official website, hosted by GitHub pages. - - - - -. Powered by Jekyll and hosted by GitHub pages. - -* Refactor `fisher install` / `fisher uninstall` by extracting the logic to enable / disable plugins into `__fisher_plugin`. The algorithm to enable/disable plugins is essentially the same. The only difference is _enable_, copies/symlinks files and disable removes them from `$fisher_config/...`. Closes #45. - -* Add support for legacy oh-my-fish! plugins using `.load` initialization files. Closes #35. - -* Add support for [Tackle](https://github.com/justinmayer/tackle) Fish framework initialization modules. Closes #35. - -* :gem: Add support for plugins that share scripts in languages like Python or Perl. For example `oh-my-fish/plugin-vi-mode` assumes there is a `vi-mode-impl.py` file in the same path of the running script. This opens the door for including code snippets in other languages. - - * Any files inside a `share` directory, except for `*.md` or `*.fish` files, are copied to `$fisher_config/functions`. This allows you to run legacy plugins that retrieve the currently running script path with `(dirname (status -f))` out of the box. - - * A cleaner alternative is using the new `$fisher_share` variable like this: `python $fisher_share/my_plugin_script.py`. - - * `$fisher_share` points to `$fisher_config/share` by default, but you may change this in your user `config.fish`. This path contains copies (or symbolic links) to the same script files copied to `$fisher_config/functions`. - - * Introduce the `$fisher_share_extensions` variable to let you customize what extensions Fisherman is aware of. Only extensions in this array will be processed during the install process. The default is `py rb php pl awk sed`. - - * `.fish` and `.md` extensions are always ignored. +   [**http://fisherman.sh**](http://fisherman.sh) -* Remove ad-hoc debug `d` function created by mistake in the Fisherman config.fish file. Closes #34. +* Refactor `fisher install` / `fisher uninstall` by extracting the logic to enable / disable plugins into `__fisher_plugin_enable`. The algorithm to enable/disable plugins is essentially the same. The only difference is _enable_, copies/symlinks files and disable removes them from `$fisher_config/...`. See #45. + +* Add support for legacy oh-my-fish! plugins using `.load` initialization files. See #35. + +* Add support for [Tackle](https://github.com/justinmayer/tackle) Fish framework initialization modules. See #35. + +* :gem: :snake: :camel: :penguin: Add support for plugins that share scripts in languages like Python or Perl. For example `oh-my-fish/plugin-vi-mode` assumes there is a `vi-mode-impl.py` file in the same path of the running script. This opens the door for including code snippets in other languages. + +* Any `py`, `rb`, `php`, `pl`, `awk` or `sed` files at the root level of a plugin repository, or inside the `functions` or the new _`scripts`_ directory are copied to `$fisher_config/functions` or `$fisher_config/scripts`. + +* Remove ad-hoc debug `d` function created by mistake in the Fisherman config.fish file. See #34. * Remove almost useless `fisher --alias`. You can still create aliases using `$fisher_alias`. It's difficult to add auto-complete to this feature, and even if we do so, it is slow. -* Fix bug introduced in the previous release caused by swapping the lines that calculate the index of the current plugin being installed/updated/uninstalled and the line that displays the value, causing the CLI to show incorrect values. Closes #36. Thanks @kballard +* Fix bug introduced in the previous release caused by swapping the lines that calculate the index of the current plugin being installed/updated/uninstalled and the line that displays the value, causing the CLI to show incorrect values. See #36. Thanks @kballard * Add `cache`, `enabled` and `disabled` options to `fisher --list`. Now you can type `fisher -l enabled` to get a list of what plugins are currently enabled. @@ -50,9 +99,9 @@ * Improve autocomplete speed by removing the descriptions from plugins installed with custom URLs. -* `fisher --list` displays nothing and returns 1 when there are no plugins installed. Closes #38. +* `fisher --list` displays nothing and returns 1 when there are no plugins installed. See #38. -* `fisher uninstall` does not attempt to uninstall plugins already disabled by looking at the `$fisher_plugins` array. `--force` will bypass this. Closes #40 +* `fisher uninstall` does not attempt to uninstall plugins already disabled by looking at the `$fisher_plugins` array. `--force` will bypass this. See #40 ## [0.3.1][v031] - 2016-01-10 @@ -62,7 +111,7 @@ * `fisher help` shows `fisher(1)` by default now. -* Fix a critical bug that was causing `fisher uninstall --force` to remove _not_ the symbolic link, but the actual files. Closes #24 +* Fix a critical bug that was causing `fisher uninstall --force` to remove _not_ the symbolic link, but the actual files. See #24 * Rename `orphan` tag to `custom` for plugins installed using a custom URL. @@ -77,13 +126,13 @@ ### Fixes -* Fix a critical bug in the Makefile that was incorrectly merging any existing user configuration file and the generated Fisherman configuration. Closes #21. +* Fix a critical bug in the Makefile that was incorrectly merging any existing user configuration file and the generated Fisherman configuration. See #21. * Fix a bug in install and uninstall that was adding plugin names to fishfiles instead of the URL when interacting with custom URLs. Probably closes #23. * Fix a bug in install, update and uninstall that was displaying an incorrect plugin count if there was at least on failure. -* Fix bug in `fisher install` that causes install to fail even though it succeeds, due to `wait(1)`'s behavior of returning `1` if there is any output to standard error. Closes #20. +* Fix bug in `fisher install` that causes install to fail even though it succeeds, due to `wait(1)`'s behavior of returning `1` if there is any output to standard error. See #20. * Fix bug in `fisher uninstall` that was removing plugins from the cache by mistake. @@ -107,11 +156,11 @@ ### Improvements -* Improve help message for failed installs. Closes ##24. @namandistro +* Improve help message for failed installs. See ##24. @namandistro * Improve `fisher --validate` to automatically correct common misspellings, for example when installing a oh-my-fish package, one often types ohmyifsh. -* :point_up: Improve auto-complete performance by extracting the implementation of the different `fisher` flags to `__fisher_*` functions. `completions/fisher.fish` relies heavily in `fisher_search` to query what plugins are available to install/update/uninstall. In this process, numerous calls to `fisher --list` and `fisher --validate`, etc., are made. Now, auto-complete does not have to pay the penalty of entering `fisher`, parsing options, etc. Closes #27. @namandistro +* :point_up: Improve auto-complete performance by extracting the implementation of the different `fisher` flags to `__fisher_*` functions. `completions/fisher.fish` relies heavily in `fisher_search` to query what plugins are available to install/update/uninstall. In this process, numerous calls to `fisher --list` and `fisher --validate`, etc., are made. Now, auto-complete does not have to pay the penalty of entering `fisher`, parsing options, etc. See #27. @namandistro * Improve `fisher --help` output and show up until now poorly documented ***`--list`***, ***`--file`***, etc. flags consistently. Also display available commands after `make install` to improve usability. @@ -125,13 +174,13 @@ ## :warning: Remove / Rename -* Modify `fisher update` default behavior. Now this command updates Fisherman by default. Use of `--self` and `--me` is also **deprecated**. To read from the standard input use a dash `-`. For example: `fisher --list | fisher update -`. See [Usage of dash in place of a filename](http://unix.stackexchange.com/questions/16357/usage-of-dash-in-place-of-a-filename/16364#16364). Closes #25. +* Modify `fisher update` default behavior. Now this command updates Fisherman by default. Use of `--self` and `--me` is also **deprecated**. To read from the standard input use a dash `-`. For example: `fisher --list | fisher update -`. See [Usage of dash in place of a filename](http://unix.stackexchange.com/questions/16357/usage-of-dash-in-place-of-a-filename/16364#16364). See #25. * Rename `--cache` to more descriptive ***`--list`***. Thanks @colstrom. * Remove `fisher --cache=base` and make it return the base names of all directories in the path by default. To get the full path use printf `printf "$fisher_cache/%s" (fisher --list)` -* Rename undocumented `fisher --translate` flag (again) to `fisher --cache`. This function reads the standard input for a name, URL or local path and calculates the plugin's path relative to the cache. For a name this is simple `$fisher_cache/` for an URL, retrieve the remote URL of every repository until there is a match with the given URL and return the path in the cache of that repository. Finally, if the input is a local path of the form `file:///` it will pass it as is. +* ~~Rename undocumented `fisher --translate` flag (again) to `fisher --cache`. This function reads the standard input for a name, URL or local path and calculates the plugin's path relative to the cache. For a name this is simple `$fisher_cache/` for an URL, retrieve the remote URL of every repository until there is a match with the given URL and return the path in the cache of that repository. Finally, if the input is a local path of the form `file:///` it will pass it as is.~~ * Revert #3. The reason `getopts.fish` was in its own file originally is because @bucaran wanted a standalone, dependency free cli parser solution, arguably slightly faster than having Awk read `getopts.awk` for each use. The performance improvement is negligible at best, but `getopts` is also used by every single command and future commands and plugins are very likely to use it as well, so we might as well use the slightly faster version. @@ -142,25 +191,25 @@ * :warning: Remove `fisher update --cache` in favor of `fisher --list | fisher update` and `fisher uninstall --all` in favor of `fisher --list | fisher uninstall`. -* :warning: Fisherman does not move initialization / configuration files following the convention `name`.config.fish to `$fisher_config/functions`, but to `$fisher_config/conf.d` now and evaluates each `*.config.fish` inside at shell start as usual. Closes #13. +* :warning: Fisherman does not move initialization / configuration files following the convention `name`.config.fish to `$fisher_config/functions`, but to `$fisher_config/conf.d` now and evaluates each `*.config.fish` inside at shell start as usual. See #13. -* ~~Add `fisher --cache[=base]` option to retrieve contents in `$fisher_cache`, eliminating flaky usage of `find(1)`~~. Closes #11. +* ~~Add `fisher --cache[=base]` option to retrieve contents in `$fisher_cache`, eliminating flaky usage of `find(1)`~~. See #11. -* Fisherman now generates information about plugins installed via custom URLs. For the description, a shortened version of the URL is used. For the URL the full URL is used. For tags, the URL is fuzzily checked and tags such as _theme_, _plugin_, _config_ and _omf_ are added. The tag ~~_orphan_~~ **custom** is added by default as well. Finally, the author is generated by retrieving the e-mail or username of the author of the first commit in the plugin's repository. Closes #9 and #14. +* Fisherman now generates information about plugins installed via custom URLs. For the description, a shortened version of the URL is used. For the URL the full URL is used. For tags, the URL is fuzzily checked and tags such as _theme_, _plugin_, _config_ and _omf_ are added. The tag ~~_orphan_~~ **custom** is added by default as well. Finally, the author is generated by retrieving the e-mail or username of the author of the first commit in the plugin's repository. See #9 and #14. -* ~~Change `--path-in-cache` to `--translate.` This function translates an name or supported URL/URL variation into a path inside `$fisher_cache`. This allows you to treat plugins installed via custom URLs almost like regular plugins if they are installed. Closes #8.~~ +* ~~Change `--path-in-cache` to `--translate.` This function translates an name or supported URL/URL variation into a path inside `$fisher_cache`. This allows you to treat plugins installed via custom URLs almost like regular plugins if they are installed. See #8.~~ -* Fix a bug where `mktemp` would fail in some systems. Closes #7. Thanks @tobywf. +* Fix a bug where `mktemp` would fail in some systems. See #7. Thanks @tobywf. -* Add [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md). Closes #6. +* Add [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md). See #6. -* Fisherman can now unload themes within the same shell, without having to restart the session. Closes #5. +* Fisherman can now unload themes within the same shell, without having to restart the session. See #5. -* Fisherman can now load themes within the same shell, without having to restart the session using `exec fish`. Shoddy themes, for example those failing to declare global variables with the `-g` flag still require the session to be reset. See [**related**](https://github.com/oh-my-fish/theme-bobthefish/pull/19). Closes #4. +* Fisherman can now load themes within the same shell, without having to restart the session using `exec fish`. Shoddy themes, for example those failing to declare global variables with the `-g` flag still require the session to be reset. See [**related**](https://github.com/oh-my-fish/theme-bobthefish/pull/19). See #4. -* Move `getopts` implementation to `share/getopts.awk`. Closes #3. +* ~~Move `getopts` implementation to `share/getopts.awk`.~~ See #3. -* Support dots inside URIs in `fisher --validate`. Closes #2. +* Support dots inside URIs in `fisher --validate`. See #2. * Refactor and improve tests for `install`, `update` and `uninstall`. @@ -174,7 +223,9 @@ -[v040]: https:// +[v050]: https:// + +[v040]: https://github.com/fisherman/fisherman/commit/fd24fef56b68f8139ca95f5b0ef406647ce3ec4c [v031]: https://github.com/fisherman/fisherman/commit/a0fe0b339df2fe70a0ba1a5e28dcd7449582742b diff --git a/Makefile b/Makefile index 0655f95..4d995da 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ TILDEIFY = sed "s|$$HOME|~|" all: $(FISH_CONFIG) $(FISHER_CACHE) $(AUTHORS) $(DOCS) @if [ ! -s $(INDEX) ]; then\ echo "Downloading the index for the first time...";\ - fish -c "fisher_update --index";\ + fish -c "__fisher_index_update";\ fi @$(call MSG,"Ahoy! Reset your shell and type 'fisher '") @fish -c "fisher help -a" | sed -n '3,$$p' @@ -47,7 +47,7 @@ uninstall: release: $(FISHER_HOME) @if [ "`git -C $^ status --short --porcelain | xargs`" = "M VERSION" ]; then\ echo "`git -C $^ describe --abbrev=0 2>/dev/null || echo \*` -> $(VERSION)";\ - sed "s/fisherman-v.\..\..-00B9FF/fisherman-v$(VERSION)-00B9FF/" $^/README.md > $^/README.md.swap;\ + sed "s/latest-v.\..\..-00B9FF/latest-v$(VERSION)-00B9FF/" $^/README.md > $^/README.md.swap;\ mv $^/README.md.swap $^/README.md;\ git -C $^ add README.md;\ git -C $^ add $^/VERSION;\ @@ -76,4 +76,6 @@ $(AUTHORS): $(FISHER_HOME) sed -E 's/([^<>]+)<([^<>]*)>/* \1 \<[\2](mailto:\2)\>/' >> $@ %.1 %.5 %.7: %.md - -@ronn --manual=fisherman --roff $? 1>&2 2> /dev/null + -@if type ronn 2>/dev/null 1>&2; then \ + ronn --manual=fisherman --roff $? 1>&2 2> /dev/null;\ + fi;\ diff --git a/README.md b/README.md index f065696..827fc9a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + +

Fisherman @@ -8,21 +10,38 @@ ![Fisherman Version][fisherman-version] [![Wharf][wharf-badge]][wharf-link] -## About -**Fisherman** is a fast, modern plugin system for [Fish](http://fishshell.com/). - -Its flat tree architecture adds no cruft to your shell, making it as fast as _no_ Fisherman. The cache mechanism lets you query the index offline and enable or disable plugins as you wish. - -Other features include dependency management, great plugin search capabilities and full compatibility with [Tacklebox](https://github.com/justinmayer/tacklebox), [Wahoo](https://github.com/wa) and [Oh My Fish](https://github.com/oh-my-fish?utf8=%E2%9C%93&query=plugin-) themes and plugins. - -:beginner: [**Get Started**][quickstart]. +**Fisherman** is a blazing [fast](#performance), modern plugin manager for [Fish](http://fishshell.com/). -## Help +Features include a flat tree dependency model, external self-managed database, cache mechanism, great test coverage and compatibility with Tackle, Oh My Fish! and Wahoo themes and plugins. -For documentation, examples and guides [see the wiki][wiki]. For support and feedback join the [Wharf][wharf-link] or browse the [issues][issues]. +:beginner: [**Get Started**][quickstart] +## Performance + +The following benchmarks were calculated using a 2.4 GHz Intel Core i5 MacBook Pro running on Flash Storage. + +```fish +time -p fish -ic exit +``` + +Fisherman runs virtually no initialization code making it as fast as no Fisherman. [Fundle][fundle] performs well, but still [runs][fundle-slow] cumbersome startup code. Oh My Fish! has by far the worst performance at `0.21s`. + +To learn more about these benchmarks, see [Performance][performance]. + +

+ + + + +## Documentation + +For documentation, examples and guides [see the wiki][wiki]. For questions and feedback join the Slack [room][wharf-link] or browse the [issues][issues]. + + +:anchor: @@ -30,11 +49,15 @@ For documentation, examples and guides [see the wiki][wiki]. For support and fee [faq]: https://github.com/fisherman/fisherman/wiki/FAQ [fish]: https://github.com/fish-shell/fish-shell [docs]: https://github.com/fisherman/fisherman/wiki -[issues]: http://github.com/fisherman/fisherman/issues [wiki]: https://github.com/fisherman/fisherman/wiki +[index]: https://github.com/fisherman/fisher-index +[issues]: http://github.com/fisherman/fisherman/issues +[fundle]: https://github.com/tuvistavie/fundle/ [quickstart]: https://github.com/fisherman/fisherman/wiki/Quickstart-Guide [wharf-link]: https://fisherman-wharf.herokuapp.com/ -[wharf-badge]: https://img.shields.io/badge/wharf-join%20the%20chat-00cc99.svg?style=flat-square +[wharf-badge]: https://img.shields.io/badge/Slack-join%20the%20chat-00cc99.svg?style=flat-square +[fundle-slow]: https://github.com/tuvistavie/fundle/blob/master/functions/fundle.fish#L232 [travis-link]: https://travis-ci.org/fisherman/fisherman [travis-badge]: https://img.shields.io/travis/fisherman/fisherman.svg?style=flat-square -[fisherman-version]: https://img.shields.io/badge/fisherman-v0.4.0-00B9FF.svg?style=flat-square +[fisherman-version]: https://img.shields.io/badge/latest-v0.4.0-00B9FF.svg?style=flat-square +[performance]: https://github.com/fisherman/fisherman/wiki/Performance diff --git a/completions/fisher.fish b/completions/fisher.fish index 840c232..1bafa44 100644 --- a/completions/fisher.fish +++ b/completions/fisher.fish @@ -1,40 +1,49 @@ -set -l IFS ";" +complete -xc fisher -for option in commands guides - fisher_help --$option=bare | sed -E 's/^ *([^ ]+) *(.*)/\1;\2/' | while read -l cmd info - - complete -c fisher -n "__fish_seen_subcommand_from help" -a $cmd -d "$info" - - if test $option != guides - complete -c fisher -n "__fish_use_subcommand" -a $cmd -d "$info" - - fisher_help --usage=$cmd | __fisher_parse_help OFS=';' | while read -l 1 2 3 - complete -c fisher -n "__fish_seen_subcommand_from $cmd" -s "$3" -l "$2" -d "$1" - end - end - end -end - -begin - - for plugin in (__fisher_list) - printf "%s;%s\n" $plugin "" - end - - awk -F '\n' -v RS='' -v OFS=';' '/^ *#/ { next } { print $1, $3 }' $fisher_cache/.index - -end | while read -l name info - if contains -- $name $fisher_plugins - complete -c fisher -n "__fish_seen_subcommand_from u update un uninstall" -a "$name" -d "$info" - else - complete -c fisher -n "__fish_seen_subcommand_from install i" -a "$name" -d "$info" - end -end - -complete -c fisher -n "__fish_seen_subcommand_from search" -a "\t" -complete -c fisher -n "__fish_use_subcommand" -s l -l list -d "List plugins in the cache" -complete -c fisher -n "__fish_use_subcommand" -s f -l file -d "Read fishfiles" +complete -c fisher -n "__fish_use_subcommand" -s l -l list -d "List plugins enabled|disabled|cache|" complete -c fisher -n "__fish_use_subcommand" -s h -l help -d "Display help" complete -c fisher -n "__fish_use_subcommand" -s v -l version -d "Show version information" -complete -xc fisher -d "Ahoy! Fisherman" +complete -c fisher -a "\t" -n "__fish_seen_subcommand_from search" +complete -c fisher -l "name" -d "Filter by name" -n "__fish_seen_subcommand_from search" +complete -c fisher -l "url" -d "Filter by url" -n "__fish_seen_subcommand_from search" +complete -c fisher -l "info" -d "Filter by info" -n "__fish_seen_subcommand_from search" +complete -c fisher -l "author" -d "Filter by author" -n "__fish_seen_subcommand_from search" +complete -c fisher -l "tags" -d "Filter by tag/s" -n "__fish_seen_subcommand_from search" + +set -l IFS ";" + +for option in commands guides + fisher_help --$option=bare | sed -E 's/^ *([^ ]+) *(.*)/\1;\2/' | while read -l command info + if test $option = commands + complete -c fisher -n "__fish_use_subcommand" -a $command -d "$info" + + fisher_help --usage=$command | __fisher_complete fisher $command + end + + complete -c fisher -n "__fish_seen_subcommand_from help" -a $command -d "$info" + end +end + +set -l plugins ( + if test -s $fisher_file + __fisher_file < $fisher_file | __fisher_name + end + ) + +begin + + awk -F '\n' -v RS='' -v OFS=';' '/^ *#/ { next } { print $1, $3 }' $fisher_cache/.index + __fisher_cache_list + +end | sort -ut ';' -k1,1 | while read -l name info + + if contains -- $name $plugins + complete -c fisher -n "__fish_seen_subcommand_from u update uninstall" -a "$name" -d "$info" + else + complete -c fisher -n "__fish_seen_subcommand_from i install" -a "$name" -d "$info" + end + +end + +complete -c fisher -n "__fish_seen_subcommand_from update" -a "fisherman" -d "Update Fisherman" diff --git a/completions/getopts.fish b/completions/getopts.fish index 5b117b6..ce14c24 100644 --- a/completions/getopts.fish +++ b/completions/getopts.fish @@ -1 +1 @@ -complete -xc getopts -d "Parse CLI options" -a "\t" +complete -xc getopts -a '\t' diff --git a/completions/wait.fish b/completions/wait.fish index 1c6ca1a..4d598e3 100644 --- a/completions/wait.fish +++ b/completions/wait.fish @@ -1,10 +1,8 @@ -set -l spinners arc star pipe ball flip mixer caret bar1 bar2 bar3 -complete -xc wait -n "__fish_seen_subcommand_from --spin" -a "$spinners" +set -l IFS \t -complete -xc wait -d "Run commands and wait with a spin" +complete -xc wait -n "__fish_seen_subcommand_from --spin" \ + -a "spinners arc star pipe ball flip mixer caret bar1 bar2 bar3" + complete -xc wait -n "not __fish_seen_subcommand_from --spin" -a "\t" -set -l IFS \t -wait -h | __fisher_parse_help | while read -l 1 2 3 - complete -c wait -s "$3" -l "$2" -d "$1" -end +wait -h | __fisher_complete wait diff --git a/config.fish b/config.fish index 7fc7afa..62d5e44 100644 --- a/config.fish +++ b/config.fish @@ -1,9 +1,7 @@ set -g fisher_cache $fisher_config/cache -set -g fisher_share $fisher_config/share +set -g fisher_file $fisher_config/fishfile +set -g fisher_key_bindings $fisher_config/key_bindings.fish set -g fisher_index https://raw.githubusercontent.com/fisherman/fisher-index/master/INDEX - -set -g fisher_error_log $fisher_cache/.debug_log - set -g fish_function_path {$fisher_config,$fisher_home}/functions $fish_function_path set -g fish_complete_path {$fisher_config,$fisher_home}/completions $fish_complete_path diff --git a/functions/__fisher_cache_list.fish b/functions/__fisher_cache_list.fish new file mode 100644 index 0000000..15ebda7 --- /dev/null +++ b/functions/__fisher_cache_list.fish @@ -0,0 +1,3 @@ +function __fisher_cache_list + find -L $fisher_cache/* -maxdepth 0 -type d | sed 's|.*/||' +end diff --git a/functions/__fisher_complete.fish b/functions/__fisher_complete.fish new file mode 100644 index 0000000..ffc0e0b --- /dev/null +++ b/functions/__fisher_complete.fish @@ -0,0 +1,13 @@ +function __fisher_complete -a parent child + if test ! -z "$child" + set child "__fish_seen_subcommand_from $child" + end + + set -l IFS ';' + + __fisher_help_parse | while read -l d l s + complete -c $parent -s "$s" -l "$l" -d "$d" -n "$child" + end + + return 0 +end diff --git a/functions/__fisher_complete_reset.fish b/functions/__fisher_complete_reset.fish new file mode 100644 index 0000000..2dfadb0 --- /dev/null +++ b/functions/__fisher_complete_reset.fish @@ -0,0 +1,4 @@ +function __fisher_complete_reset + complete -ec fisher + source $fisher_home/completions/fisher.fish +end diff --git a/functions/__fisher_copy.fish b/functions/__fisher_copy.fish deleted file mode 100644 index c44bb4d..0000000 --- a/functions/__fisher_copy.fish +++ /dev/null @@ -1,7 +0,0 @@ -function __fisher_copy -a option source target -d "cp/ln wrapper" - if test "$option" = link - ln -sfF $source $target - else - cp -f $source $target - end -end diff --git a/functions/__fisher_deps_install.fish b/functions/__fisher_deps_install.fish new file mode 100644 index 0000000..532978a --- /dev/null +++ b/functions/__fisher_deps_install.fish @@ -0,0 +1,13 @@ +function __fisher_deps_install -a path + printf 0 + + if test -s $path/bundle -o -s $path/fishfile + printf "Installing dependencies >> (%s)\n" ( + for file in $path/{bundle,fishfile} + __fisher_list $file + end | paste -sd ' ' - + ) > /dev/stderr + + cat $path/{bundle,fishfile} | fisher_install ^| sed -En 's/([0-9]+) plugin\/s.*/\1/p' + end +end diff --git a/functions/__fisher_file.fish b/functions/__fisher_file.fish index eac13a7..28d80ce 100644 --- a/functions/__fisher_file.fish +++ b/functions/__fisher_file.fish @@ -1,15 +1,19 @@ -function __fisher_file -d "read one or more fishfiles" +function __fisher_file awk ' - !/^ *(#.*)*$/ { + /^[ \t]*(package|theme) .+/ { + if ($1 == "package") { + $1 = "https://github.com/oh-my-fish/plugin-"$2 + } else { + $1 = "https://github.com/oh-my-fish/theme-"$2 + } + } + + !/^[ \t]*(#.*)*$/ { gsub("#.*", "") - if (/^ *package .+/) { - $1 = $2 - } - - if (!duplicates[$1]++) { + if (! seen[$1]++) { printf("%s\n", $1) } } - ' $argv + ' end diff --git a/functions/__fisher_file_contains.fish b/functions/__fisher_file_contains.fish new file mode 100644 index 0000000..2b684aa --- /dev/null +++ b/functions/__fisher_file_contains.fish @@ -0,0 +1,4 @@ +function __fisher_file_contains -a plugin + set -e argv[1] + grep -E "^(package *|plugin *)?$plugin*\$" $argv +end diff --git a/functions/__fisher_file_remove.fish b/functions/__fisher_file_remove.fish new file mode 100644 index 0000000..b722381 --- /dev/null +++ b/functions/__fisher_file_remove.fish @@ -0,0 +1,13 @@ +function __fisher_file_remove -a plugin file + if __fisher_file_contains $plugin < $file + set pattern (printf "%s\n" $plugin | __fisher_string_escape) + + if test ! -z "$pattern" + set pattern "/^$pattern\$/d" + end + + sed -E "$pattern" < $file > $file.tmp + + mv $file.tmp $file + end +end diff --git a/functions/__fisher_help_parse.fish b/functions/__fisher_help_parse.fish new file mode 100644 index 0000000..fcbf610 --- /dev/null +++ b/functions/__fisher_help_parse.fish @@ -0,0 +1,3 @@ +function __fisher_help_parse + sed -nE 's/^ *(-(.))?,? *--([^ =]+) *(.*)$/\4;\3;\2/p' +end diff --git a/functions/__fisher_index_update.fish b/functions/__fisher_index_update.fish new file mode 100644 index 0000000..3611bc0 --- /dev/null +++ b/functions/__fisher_index_update.fish @@ -0,0 +1,26 @@ +function __fisher_index_update + set -l timeout 5 + + if set -q fisher_timeout + set timeout "0$fisher_timeout" + end + + set -l index $fisher_cache/.index.tmp + + # We pass a random query string after the URL to force the the + # server (GitHub) to always return the latest copy of the index. + + set -l query $fisher_index + + switch "$fisher_index" + case https://\* + set query $fisher_index\?(date +%s) + end + + if not curl --max-time $timeout -sS "$query" > $index + rm -f $index + return 1 + end + + mv -f $index $fisher_cache/.index +end diff --git a/functions/__fisher_key_bindings.fish b/functions/__fisher_key_bindings.fish new file mode 100644 index 0000000..f6adcb7 --- /dev/null +++ b/functions/__fisher_key_bindings.fish @@ -0,0 +1,3 @@ +function __fisher_key_bindings + source $fisher_key_bindings ^ /dev/null +end diff --git a/functions/__fisher_key_bindings_delete.fish b/functions/__fisher_key_bindings_delete.fish new file mode 100644 index 0000000..6a1d3d4 --- /dev/null +++ b/functions/__fisher_key_bindings_delete.fish @@ -0,0 +1,3 @@ +function __fisher_key_bindings_delete -a plugin + sed "/##$plugin##/,/##$plugin##/d" +end diff --git a/functions/__fisher_key_bindings_disable.fish b/functions/__fisher_key_bindings_disable.fish new file mode 100644 index 0000000..9a7227c --- /dev/null +++ b/functions/__fisher_key_bindings_disable.fish @@ -0,0 +1,16 @@ +function __fisher_key_bindings_disable -a plugin user_key_bindings + fish_indent < $fisher_key_bindings \ + | __fisher_key_bindings_undo $plugin \ + | source + + __fisher_key_bindings_delete $plugin \ + > $fisher_key_bindings.tmp \ + < $fisher_key_bindings + + mv -f $fisher_key_bindings.tmp $fisher_key_bindings + + if test ! -s $fisher_key_bindings + sed -i.tmp '/__fisher_key_bindings/d' $user_key_bindings + rm -f $user_key_bindings.tmp + end +end diff --git a/functions/__fisher_key_bindings_enable.fish b/functions/__fisher_key_bindings_enable.fish new file mode 100644 index 0000000..0a98e11 --- /dev/null +++ b/functions/__fisher_key_bindings_enable.fish @@ -0,0 +1,17 @@ +function __fisher_key_bindings_enable -a plugin user_key_bindings + __fisher_key_bindings_update $plugin >> $fisher_key_bindings + + if test ! -s $user_key_bindings + mkdir -p (dirname $user_key_bindings) + + printf "%s\n" \ + "function fish_user_key_bindings" \ + " __fisher_key_bindings" \ + "end" > $user_key_bindings + + source $user_key_bindings + end + + functions fish_user_key_bindings \ + | __fisher_key_bindings_update_user > $user_key_bindings +end diff --git a/functions/__fisher_key_bindings_reset.fish b/functions/__fisher_key_bindings_reset.fish new file mode 100644 index 0000000..a486230 --- /dev/null +++ b/functions/__fisher_key_bindings_reset.fish @@ -0,0 +1,6 @@ +function __fisher_key_bindings_reset + if functions -q fish_user_key_bindings + source (__fisher_xdg --config)/fish/functions/fish_user_key_bindings.fish ^ /dev/null + fish_user_key_bindings + end +end diff --git a/functions/__fisher_key_bindings_undo.fish b/functions/__fisher_key_bindings_undo.fish new file mode 100644 index 0000000..d81f3e1 --- /dev/null +++ b/functions/__fisher_key_bindings_undo.fish @@ -0,0 +1,3 @@ +function __fisher_key_bindings_undo -a plugin + sed -n "/##$plugin##/,/##$plugin##/{s/bind /bind -e /p;};" +end diff --git a/functions/__fisher_key_bindings_update.fish b/functions/__fisher_key_bindings_update.fish new file mode 100644 index 0000000..2de0cb3 --- /dev/null +++ b/functions/__fisher_key_bindings_update.fish @@ -0,0 +1,28 @@ +function __fisher_key_bindings_update -a name + fish_indent | awk \ + -v name="$name" \ + -v pattern="^function (fish_user_)?key_bindings\$" ' + + function banner() { + print "##" name "##" + } + + BEGIN { banner() } END { banner() } + + $0 ~ pattern { + end = 1 + next + } + + /^end$/ && end { + end = 0 + next + } + + !/^ *(#.*)*$/ { + gsub("#.*", "") + + printf("%s\n", $0) + } + ' +end diff --git a/functions/__fisher_key_bindings_update_user.fish b/functions/__fisher_key_bindings_update_user.fish new file mode 100644 index 0000000..f4eaacf --- /dev/null +++ b/functions/__fisher_key_bindings_update_user.fish @@ -0,0 +1,9 @@ +function __fisher_key_bindings_update_user + awk -v src=__fisher_key_bindings ' + NR == 2 { + printf("%s\n", src) + } + + $0 !~ "^[ \t]*" src { print } + ' | fish_indent +end diff --git a/functions/__fisher_list.fish b/functions/__fisher_list.fish index 7a5fbcd..974830c 100644 --- a/functions/__fisher_list.fish +++ b/functions/__fisher_list.fish @@ -1,23 +1,54 @@ -function __fisher_list -a category -d "list local plugins by category" - set index $fisher_cache/.index +function __fisher_list -a source + switch "$source" + case bare + __fisher_cache_list - switch "$category" - case enabled installed on - printf "%s\n" $fisher_plugins + case url + for i in (__fisher_cache_list) + __fisher_url_from_path $fisher_cache/$i + end + + case "" all cache + set -l enabled (__fisher_list $fisher_file) + set -l legend " " + + if test -z "$enabled" + set legend "" + end + + for i in (__fisher_cache_list) + if contains -- $i $enabled + if test $i = "$fisher_prompt" + printf "%s%s\n" ">" $i + else + printf "%s%s\n" "*" $i + end + else + printf "%s%s\n" "$legend" $i + end + end + + case enabled installed + __fisher_list $fisher_file + + case disabled + set -l enabled (__fisher_list $fisher_file) + + for name in (__fisher_cache_list) + if not contains -- $name $enabled + printf "%s\n" $name + end + end + + case theme prompt + printf "%s\n" $fisher_prompt + + case - + __fisher_file | __fisher_name case \* - for file in $fisher_cache/* - set -l name (basename $file) - - switch "$category" - case disabled off - if not contains -- $name $fisher_plugins - printf "%s\n" $name - end - - case \* - printf "%s\n" $name - end + if test -s "$source" + __fisher_list - < $source end end end diff --git a/functions/__fisher_name.fish b/functions/__fisher_name.fish index f48bb09..1f8efba 100644 --- a/functions/__fisher_name.fish +++ b/functions/__fisher_name.fish @@ -1,3 +1,3 @@ -function __fisher_name -d "get plugin name from url or path" - sed -E 's|.*/(.*)|\1|; s/^(plugin|theme|pkg|omf|fish|fisher)-//' +function __fisher_name + sed -E 's|.*/(.*)|\1|; s/^(plugin|omf-theme|theme|pkg|omf|fish|fisher)-//' end diff --git a/functions/__fisher_parse_help.fish b/functions/__fisher_parse_help.fish deleted file mode 100644 index 51ce85c..0000000 --- a/functions/__fisher_parse_help.fish +++ /dev/null @@ -1,30 +0,0 @@ -function __fisher_parse_help -d "parse usage help output" - switch "$argv" - case \*OFS=\* - case \* - set argv $argv OFS=\t - end - - awk (printf "-v\n%s\n" $argv) ' - /^ *--?[A-Za-z0-9-]+[, ]?/ { - re = "[<=\\\[]" - for (n = 1; n <= NF; n++) { - - if ($n ~ /^--/ && !long) { - long = substr($n, 3) - split(long, _, re) - long = substr(_[1], 1) - - } else if ($n ~ /^-.,?$/ && !short) { - short = substr($n, 2, 1) - - } else if ($n !~ re) { - info = (info ? info" " : info)$n - } - } - - print info, long, short - info = short = long = "" - } - ' -end diff --git a/functions/__fisher_path_from_plugin.fish b/functions/__fisher_path_from_plugin.fish new file mode 100644 index 0000000..8844855 --- /dev/null +++ b/functions/__fisher_path_from_plugin.fish @@ -0,0 +1,16 @@ +function __fisher_path_from_plugin -a plugin + switch "$plugin" + case /\* + __fisher_plugin_from_path $plugin + + case \*/\* + __fisher_path_from_url $plugin + + case \* + if test ! -d "$fisher_cache/$plugin" + return 1 + end + + printf "%s\n" $fisher_cache/$plugin + end +end diff --git a/functions/__fisher_path_from_url.fish b/functions/__fisher_path_from_url.fish new file mode 100644 index 0000000..7a27d88 --- /dev/null +++ b/functions/__fisher_path_from_url.fish @@ -0,0 +1,18 @@ +function __fisher_path_from_url -a url + + # What is the difference between path-from-url and url-from-path? + + # Both functions use 'git ... --get-url'. The first one compares the given URL with + # the ls-remote of each repo in the cache and returns the path of the first match. + # The other one returns the ls-remote of the given path. + + for file in $fisher_cache/* + switch "$url" + case (git -C $file ls-remote --get-url) + printf "%s\n" $file + return + end + end + + return 1 +end diff --git a/functions/__fisher_path_is_prompt.fish b/functions/__fisher_path_is_prompt.fish new file mode 100644 index 0000000..ddbcfb5 --- /dev/null +++ b/functions/__fisher_path_is_prompt.fish @@ -0,0 +1,3 @@ +function __fisher_path_is_prompt -a path + test -e $path/fish_prompt.fish -o -e $path/fish_right_prompt.fish +end diff --git a/functions/__fisher_path_make.fish b/functions/__fisher_path_make.fish new file mode 100644 index 0000000..df8166c --- /dev/null +++ b/functions/__fisher_path_make.fish @@ -0,0 +1,13 @@ +function __fisher_path_make -a path + if test -s $path/Makefile -o -s $path/makefile + pushd $path + + set -e argv[1] + + if not make $argv + popd + return 1 + end + popd + end +end diff --git a/functions/__fisher_path_update.fish b/functions/__fisher_path_update.fish new file mode 100644 index 0000000..14eda9f --- /dev/null +++ b/functions/__fisher_path_update.fish @@ -0,0 +1,4 @@ +function __fisher_path_update -a path + git -C $path checkout master --quiet ^ /dev/null + git -C $path pull --rebase origin master --quiet ^ /dev/null +end diff --git a/functions/__fisher_plugin.fish b/functions/__fisher_plugin.fish deleted file mode 100644 index 346abae..0000000 --- a/functions/__fisher_plugin.fish +++ /dev/null @@ -1,156 +0,0 @@ -function __fisher_plugin -a enable name path -d "enable or disable plugins" - set -l batch - set -l option - - switch $enable - case --disable - set -e enable - end - - if test -L $path - set option link - end - - for file in $path/*.load - set -l base (basename $file).fish - - if set -q enable - __fisher_copy "$option" $file $fisher_config/conf.d/$base - set batch $batch $fisher_config/conf.d/$base - else - rm -f $fisher_config/conf.d/$base - end - end - - for file in $path/{*,{conf.d,modules}/*,functions/**}.fish - set -l base (basename $file) - - if test $base = uninstall.fish - if not set -q enable - set batch $batch $file - end - - continue - end - - switch $file - case \?\*/{conf.d,modules}/\?\* - switch "$base" - case \*$name\* - case \* - set base $name.$base - end - - if set -q enable - __fisher_copy "$option" $file $fisher_config/conf.d/$base - set batch $batch $fisher_config/conf.d/$base - else - rm -f $fisher_config/conf.d/$base - end - - case \* - switch $base - case {$name,fish_{,right_}prompt}.fish - if set -q enable - source $file - __fisher_copy "$option" $file $fisher_config/functions/$base - else - functions -e (basename $base .fish) - rm -f $fisher_config/functions/$base - - if test "$base" = fish_prompt.fish - source $__fish_datadir/functions/fish_prompt.fish ^ /dev/null - end - end - - case \*\?.config.fish - if set -q enable - __fisher_copy "$option" $file $fisher_config/conf.d/$base - set batch $batch $fisher_config/conf.d/$base - else - rm -f $fisher_config/conf.d/$base - end - - case {,before.}init.fish - set base $name.$base - if set -q enable - __fisher_copy "$option" $file $fisher_config/conf.d/$base - set batch $batch $fisher_config/conf.d/$base - else - rm -f $fisher_config/conf.d/$base - end - - case \* - if set -q enable - __fisher_copy "$option" $file $fisher_config/functions/$base - else - rm -f $fisher_config/functions/$base - end - end - end - end - - if not set -q fisher_share_extensions[1] - set fisher_share_extensions py rb php pl awk sed - end - - for file in $path/{share/,}*.$fisher_share_extensions - set -l base (basename $file) - - switch $file - case \*.md \*.fish - continue - end - - if set -q enable - __fisher_copy "$option" $file $fisher_config/functions/$base - __fisher_copy "$option" $file $fisher_share/$base - else - rm -f {$fisher_config/functions,$fisher_share}/$base - end - end - - for file in $path/completions/*.fish - if set -q enable - __fisher_copy "$option" $file $fisher_config/completions/(basename $file) - else - rm -f $fisher_config/completions/(basename $file) - end - end - - for n in (seq 9) - if test -d $path/man/man$n - mkdir -p $fisher_config/man/man$n - end - - for file in $path/man/man$n/*.$n - if set -q enable - __fisher_copy "$option" $file $fisher_config/man/man$n - else - rm -f $fisher_config/man/man$n/(basename $file) - end - end - end - - if set -q batch[1] - for file in $batch - source $file - end - end - - set -l index (contains -i -- $name $fisher_plugins) - - if set -q enable - if test -z "$index" - set -U fisher_plugins $fisher_plugins $name - end - else - if test "$index" -ge 1 - set -e fisher_plugins[$index] - end - end - - complete -ec fisher - - source $fisher_home/completions/fisher.fish -end diff --git a/functions/__fisher_plugin_disable.fish b/functions/__fisher_plugin_disable.fish new file mode 100644 index 0000000..af3a6e9 --- /dev/null +++ b/functions/__fisher_plugin_disable.fish @@ -0,0 +1,27 @@ +function __fisher_plugin_disable -a plugin path + __fisher_plugin_walk "$plugin" "$path" | while read -l class source target name + switch "$class" + case --bind + __fisher_key_bindings_disable $plugin (__fisher_xdg --config + )/fish/functions/fish_user_key_bindings.fish + + case --uninstall + __fisher_plugin_uninstall_handler $plugin $source + + case \* + __fisher_plugin_unlink $name $fisher_config/$target + end + end + + if __fisher_path_is_prompt $path + __fisher_prompt_reset + end + + if test -s $fisher_file + __fisher_file_remove ( + if not fisher_search --name=$plugin --name --index=$fisher_cache/.index + __fisher_url_from_path $path + end + ) $fisher_file > /dev/null + end +end diff --git a/functions/__fisher_plugin_enable.fish b/functions/__fisher_plugin_enable.fish new file mode 100644 index 0000000..df96bc9 --- /dev/null +++ b/functions/__fisher_plugin_enable.fish @@ -0,0 +1,66 @@ +function __fisher_plugin_enable -a plugin path + if __fisher_path_is_prompt $path + if test ! -z "$fisher_prompt" + + # Why do we need to disable a prompt before installing another? I thought + # one prompt would override the other? + + # While this is true for fish_prompt and fish_right_prompt, a prompt is no + # different from other plugins and may optionally include other functions, + # shared scripts, completions, documentation, etc. + + __fisher_plugin_disable "$fisher_prompt" "$fisher_cache/$fisher_prompt" + end + + set -U fisher_prompt $plugin + end + + set -l link -f + + if test -L $path + + # The path will be a soft link if the user tried to install a plugin from + # any directory in the local system, including plugins registered in the + # index. In this case we want to create soft links from (which is + # also a soft link) as we walk the plugin's directory. + + # The advantage of creating soft links from local projects is that it + # allows rapid prototyping / debugging of new or existing plugins. + + set link -sfF + end + + __fisher_plugin_walk "$plugin" "$path" | while read -l class source target __unused + switch "$class" + case --bind + __fisher_key_bindings_enable $plugin (__fisher_xdg --config + )/fish/functions/fish_user_key_bindings.fish < $source + + case --uninstall + case \* + if test "$class" = --man + mkdir -p (dirname $fisher_config/$target) + end + + __fisher_plugin_link $link $source $fisher_config/$target + + if test "$class" = --source + source $fisher_config/$target + end + end + end + + set -l item ( + if not fisher_search --name=$plugin --name --index=$fisher_cache/.index + __fisher_url_from_path $path + end + ) + + if test -s $fisher_file + if __fisher_file_contains "$item" --quiet $fisher_file + return + end + end + + printf "%s\n" $item >> $fisher_file +end diff --git a/functions/__fisher_plugin_from_path.fish b/functions/__fisher_plugin_from_path.fish new file mode 100644 index 0000000..d14ccd5 --- /dev/null +++ b/functions/__fisher_plugin_from_path.fish @@ -0,0 +1,11 @@ +function __fisher_plugin_from_path -a path + for plugin in $fisher_cache/* + switch "$path" + case (readlink $plugin) + printf "%s\n" $plugin + return + end + end + + return 1 +end diff --git a/functions/__fisher_plugin_link.fish b/functions/__fisher_plugin_link.fish new file mode 100644 index 0000000..a65297a --- /dev/null +++ b/functions/__fisher_plugin_link.fish @@ -0,0 +1,7 @@ +function __fisher_plugin_link -a options source target + + # Why not simply run `ln args` inside __fisher_plugin_enable? + # We want to provide a hook for future plugins to override core functionality. + + ln $options $source $target +end diff --git a/functions/__fisher_plugin_uninstall_handler.fish b/functions/__fisher_plugin_uninstall_handler.fish new file mode 100644 index 0000000..d37caba --- /dev/null +++ b/functions/__fisher_plugin_uninstall_handler.fish @@ -0,0 +1,5 @@ +function __fisher_plugin_uninstall_handler -a plugin file + if source $file $plugin $file + emit uninstall_$plugin $file + end +end diff --git a/functions/__fisher_plugin_unlink.fish b/functions/__fisher_plugin_unlink.fish new file mode 100644 index 0000000..f64a226 --- /dev/null +++ b/functions/__fisher_plugin_unlink.fish @@ -0,0 +1,4 @@ +function __fisher_plugin_unlink -a name file + rm -f $file + functions -e $name +end diff --git a/functions/__fisher_plugin_validate.fish b/functions/__fisher_plugin_validate.fish new file mode 100644 index 0000000..65f6756 --- /dev/null +++ b/functions/__fisher_plugin_validate.fish @@ -0,0 +1,38 @@ +function __fisher_plugin_validate -a plugin + switch "$plugin" + case . /\* ./\* ../\* + if test ! -e $plugin + return 1 + end + + switch "$plugin" + case /\* + printf "%s\n" $plugin + + case \* + + printf "$PWD/%s/%s" (dirname $plugin) (basename $plugin) + + end | sed -E 's|[./]*$||; s|/([\./])/+|/|g' + + case \* + set -l id "[A-Za-z0-9._-]" + + if not printf "%s\n" $plugin | grep -qE "^(($id+)[:/]*)*\$" + printf "%s\n" $plugin + return 1 + end + + printf "%s\n" $plugin \ + | sed -E " + s|^gh[:/]*|https://github.com/| + s|^gl[:/]*|https://gitlab.com/| + s|^bb[:/]*|https://bitbucket.org/| + s|^omf[:/]*|https://github.com/oh-my-fish/| + s|^($id+)/($id+)\$|https://github.com/\1/\2| + s|^http(s?)[:/]*|http\1://| + s|https://github((.com)?/)?|https://github.com/| + s|/*(\.git/*)*\$||g" \ + | tr "[A-Z]" "[a-z]" + end +end diff --git a/functions/__fisher_plugin_walk.fish b/functions/__fisher_plugin_walk.fish new file mode 100644 index 0000000..f8870c6 --- /dev/null +++ b/functions/__fisher_plugin_walk.fish @@ -0,0 +1,47 @@ +function __fisher_plugin_walk -a plugin path + for file in $path/{*,{conf.d,modules}/*,functions/**}.{fish,load} $path/completions/*.fish + set -l name (basename $file .fish) + set -l base $name.fish + + switch $file + case \*/{fish_user_,}key_bindings.fish + printf "%s %s %s\n" --bind $file + + case \?\*/uninstall.fish + printf "%s %s\n" --uninstall $file + + case \?\*/{conf.d,modules}/\?\* \?\*/\*config.fish \?\*/{,before.}init.fish \*/$plugin.load + switch "$base" + case \*$plugin\* + case \* + set base $plugin.$base + end + + printf "%s %s %s\n" --source $file conf.d/$base + + case \*/completions/$plugin.fish + printf "%s %s %s\n" --source $file completions/$base + + case \* + printf "%s %s %s %s\n" --source $file functions/$base $name + end + end + + for prefix in functions scripts "" + for file in $path/$prefix/*.{py,rb,php,pl,awk,sed} + set -l base (basename $file) + + if test -z "$prefix" + set prefix functions + end + + printf "%s %s %s\n" -- $file $prefix/$base + end + end + + for n in (seq 9) + for file in $path/man/man$n/*.$n + printf "%s %s %s\n" --man $file man/man$n/(basename $file) + end + end +end diff --git a/functions/__fisher_prompt_reset.fish b/functions/__fisher_prompt_reset.fish new file mode 100644 index 0000000..162586c --- /dev/null +++ b/functions/__fisher_prompt_reset.fish @@ -0,0 +1,17 @@ +function __fisher_prompt_reset + set -U fisher_prompt + + # To reset the prompt, remove any data in fisher_prompt and source any existing + # fish_prompt file as follows. First, look inside functions/ inside each of the + # given paths. If none are given, look in the user fish configuration. If none + # is found, source the default prompt inside __fish_datadir/functions. + + set argv $argv (__fisher_xdg --config)/fish $__fish_datadir + + for prompt in $argv/functions/fish_prompt.fish + if test -s $prompt + source $prompt + return + end + end +end diff --git a/functions/__fisher_resolve_plugin.fish b/functions/__fisher_resolve_plugin.fish deleted file mode 100644 index 7ea868e..0000000 --- a/functions/__fisher_resolve_plugin.fish +++ /dev/null @@ -1,41 +0,0 @@ -function __fisher_resolve_plugin -a error -d "resolve path to a plugin" - if test -z "$error" - set error /dev/stderr - end - - while read --prompt="" -l item - switch "$item" - case file:///\* - for file in $fisher_cache/* - switch "$item" - case file://(readlink $file) - printf "%s\n" $file - break - end - end - - case \*/\* - for file in $fisher_cache/* - switch "$item" - case (git -C $file ls-remote --get-url | __fisher_validate) - printf "%s\n" $file - break - end - end - - case \* - set item $fisher_cache/$item - if test -d "$item" - printf "%s\n" $item - end - - end | read -l path - - if test -z "$path" - printf "fisher: Avast! '%s' is not in the cache\n" $item > $error - continue - end - - printf "%s\n" $path - end -end diff --git a/functions/__fisher_string_escape.fish b/functions/__fisher_string_escape.fish new file mode 100644 index 0000000..f766c00 --- /dev/null +++ b/functions/__fisher_string_escape.fish @@ -0,0 +1,3 @@ +function __fisher_string_escape + sed 's|/|\\\/|g' +end diff --git a/functions/__fisher_url_clone.fish b/functions/__fisher_url_clone.fish new file mode 100644 index 0000000..c435e7b --- /dev/null +++ b/functions/__fisher_url_clone.fish @@ -0,0 +1,3 @@ +function __fisher_url_clone -a url path + git clone -q --depth 1 $url $path +end diff --git a/functions/__fisher_url_from_path.fish b/functions/__fisher_url_from_path.fish new file mode 100644 index 0000000..6c0b5b5 --- /dev/null +++ b/functions/__fisher_url_from_path.fish @@ -0,0 +1,11 @@ +function __fisher_url_from_path -a path + if test -z "$path" + return 1 + end + + if test -L "$path" + readlink $path + else + git -C "$path" ls-remote --get-url ^ /dev/null + end +end diff --git a/functions/__fisher_validate.fish b/functions/__fisher_validate.fish deleted file mode 100644 index ec23898..0000000 --- a/functions/__fisher_validate.fish +++ /dev/null @@ -1,43 +0,0 @@ -function __fisher_validate -d "validate a name, url or path" - set -l id "[A-Za-z0-9_]+([.-]?[A-Za-z0-9_])*" - - if not set -q fisher_default_host - set fisher_default_host https://github.com - end - - while read -lp "" item - switch "$item" - case \*..\* /. / - return 1 - end - - if test -e "$item" - if test $item = $HOME -o $HOME = $PWD - return 1 - end - - if test -f "$item" - set item (dirname $item) - end - - if not printf "%s\n" $item | grep "^\/" - printf "$PWD/%s/%s" (dirname $item) (basename $item) - end | sed -E 's|^/|file:///|;s|[./]*$||' - - else - printf "%s\n" $item | sed -En " - s#plg?ug?i?n#plugin# - s#oh?my?i?f[iy]?h?si?h?#oh-my-fish# - s#/\$## - s#\.git\$## - s#^(https?):*/* *(.*\$)#\1://\2#p - s#^(@|(gh[:/])|(github(.com)?[/:]))/?($id)/($id)\$#https://github.com/\5/\7#p - s#^(bb[:/])/*($id)/($id)\$#https://bitbucket.org/\2/\4#p - s#^(gl[:/])/*($id)/($id)\$#https://gitlab.com/\2/\4#p - s#^(omf[:/])/*($id)\$#https://github.com/oh-my-fish/\2#p - s#^($id)/($id)\$#$fisher_default_host/\1/\3#p - /^file:\/\/\/.*/p - /^[a-z]+([._-]?[a-z0-9]+)*\$/p" - end - end -end diff --git a/functions/__fisher_xdg.fish b/functions/__fisher_xdg.fish new file mode 100644 index 0000000..06af145 --- /dev/null +++ b/functions/__fisher_xdg.fish @@ -0,0 +1,25 @@ +function __fisher_xdg -a dir + set -l config $HOME/.config + set -l data $HOME/.local/share + set -l cache $HOME/.cache + + switch "$dir" + case --config{,-home} + if set -q XDG_CONFIG_HOME + set config $XDG_CONFIG_HOME + end + printf "%s\n" $config + + case --data{,-home} + if set -q XDG_DATA_HOME + set data $XDG_DATA_HOME + end + printf "%s\n" $data + + case --cache{,-home} + if set -q XDG_CACHE_HOME + set cache $XDG_CACHE_HOME + end + printf "%s\n" $cache + end +end diff --git a/functions/fisher.fish b/functions/fisher.fish index 55a9414..a8b60ca 100644 --- a/functions/fisher.fish +++ b/functions/fisher.fish @@ -1,11 +1,6 @@ -function fisher -d "Fish Shell Plugin Manager" - if not set -q argv[1] - fisher --help - return 1 - end - - set -l option +function fisher -d "Fish Plugin Manager" set -l value + set -l option help getopts $argv | while read -l 1 2 switch "$1" @@ -22,21 +17,15 @@ function fisher -d "Fish Shell Plugin Manager" set option list set value $2 - case f file - set option file - set value $2 - - case V validate - set option validate - - case name - set option translate - case v version set option version case \* - printf "fisher: Ahoy! '%s' is not a valid option\n" $1 >& 2 + if test ! -z "$option" + continue + end + + printf "fisher: '%s' is not a valid option.\n" $1 >& 2 fisher --help >& 2 return 1 end @@ -56,32 +45,24 @@ function fisher -d "Fish Shell Plugin Manager" if not functions -q "fisher_$value" printf "fisher: '%s' is not a valid command\n" "$value" >& 2 - fisher --help >& 2 | head -n1 >& 2 + fisher --help >& 2 return 1 end + if contains -- --help $argv + fisher help $value + return + end + set -e argv[1] - if not eval "fisher_$value" (printf "%s\n" "'"$argv"'") - return 1 - end + eval "fisher_$value" (printf "%s\n" "'"$argv"'") case list if not __fisher_list $value return 1 end - case file - if test -z "$value" - set value $fisher_config/fishfile - end - - if test value = - - set value /dev/stdin - end - - __fisher_file $value - case version sed 's/^/fisher version /;q' $fisher_home/VERSION @@ -90,7 +71,7 @@ function fisher -d "Fish Shell Plugin Manager" set value commands end - printf "usage: fisher [] [--version] [--help]\n\n" + printf "usage: fisher [] [--list] [--version] [--help]\n\n" switch commands case $value diff --git a/functions/fisher_help.fish b/functions/fisher_help.fish index fb28d51..3086b34 100644 --- a/functions/fisher_help.fish +++ b/functions/fisher_help.fish @@ -1,7 +1,7 @@ function fisher_help -d "Show Help" if not set -q argv[1] man fisher - return 1 + return end set -l option @@ -35,14 +35,14 @@ function fisher_help -d "Show Help" case h printf "usage: fisher help [] [--all] [--guides] [--help]\n\n" - printf " -a --all List available documentation \n" - printf " -g --guides List available guides \n" - printf " -u --usage[=] Display command usage \n" - printf " -h --help Show usage help \n" + printf " -a --all List available documentation\n" + printf " -g --guides List available guides\n" + printf " -u --usage[=] Display command usage\n" + printf " -h --help Show usage help\n" return case \* - printf "fisher: Ahoy! '%s' is not a valid option\n" $1 >& 2 + printf "fisher: '%s' is not a valid option.\n" $1 >& 2 fisher_help --help >& 2 return 1 end @@ -54,14 +54,13 @@ function fisher_help -d "Show Help" switch "$option" case help - fisher help help + man fisher-help case manual - switch "$value" - case fisherman fisher-7 7-fisher - man 7 fisher + set -l value (printf "%s\n" $value | awk '{ print tolower($0) }') - case fisher me + switch "$value" + case me fisher fisherman man fisher case \* @@ -70,13 +69,16 @@ function fisher_help -d "Show Help" case usage if test -z "$value" - sed -E 's/^ *([^ ]+).*/\1/' | while read -l value - if functions -q fisher_$value - fisher $value -h + set -e value + sed -E 's/^ *([^ ]+).*/\1/' | while read -l command + if functions -q fisher_$command + set value $command $value end end - else - printf "%s\n" $value | fisher_help --usage + end + + for command in $value + fisher $command -h end case \* @@ -89,10 +91,9 @@ function fisher_help -d "Show Help" switch commands case $option - functions -a | grep '^fisher_[^_]*$' | while read -l f - functions $f | awk ' - /^$/ { next } - { + functions -a | grep '^fisher_[^_]*$' | while read -l func + functions $func | awk ' + /^$/ { next } { printf(" %s\t", substr($2, 8)) gsub("\'","") diff --git a/functions/fisher_install.fish b/functions/fisher_install.fish index 53de8b5..1eb539c 100644 --- a/functions/fisher_install.fish +++ b/functions/fisher_install.fish @@ -1,71 +1,81 @@ function fisher_install -d "Install Plugins" - set -l items + set -l plugins set -l option set -l error /dev/stderr getopts $argv | while read -l 1 2 switch "$1" case _ - set items $items $2 + set plugins $plugins $2 + + case f force + set option force case q quiet set error /dev/null - case help - set option help - case h - printf "usage: fisher install [] [--quiet] [--help]\n\n" + printf "usage: fisher install [] [--force] [--quiet] [--help]\n\n" + printf " -f --force Reinstall given plugin/s\n" printf " -q --quiet Enable quiet mode\n" printf " -h --help Show usage help\n" return case \* - printf "fisher: Ahoy! '%s' is not a valid option\n" $1 >& 2 + printf "fisher: '%s' is not a valid option.\n" $1 >& 2 fisher_install -h >& 2 return 1 end end - switch "$option" - case help - fisher help install - return - end - + set -l link set -l time (date +%s) set -l count 0 set -l index 1 - set -l total (count $items) + set -l total (count $plugins) + set -l skipped - if set -q items[1] - printf "%s\n" $items + if set -q plugins[1] + + printf "%s\n" $plugins else - __fisher_file /dev/stdin - end | __fisher_validate | while read -l item + __fisher_file + + end | while read -l item + + if not set item (__fisher_plugin_validate $item) + printf "fisher: '%s' is not a valid name, path or url.\n" $item > $error + continue + end switch "$item" case \*/\* - printf "%s %s\n" $item ( - if not fisher_search --name --url=$item - printf "%s\n" $item | __fisher_name - end) + printf "%s %s\n" $item (printf "%s\n" $item | __fisher_name) case \* - if set -l url (fisher_search --name=$item --url) + if set -l url (fisher_search --url --name=$item --index=$fisher_cache/.index) printf "%s %s\n" $url $item else if test -d $fisher_cache/$item - printf "%s %s\n" (git -C $fisher_cache/$item ls-remote --get-url) $item + printf "%s %s\n" (__fisher_url_from_path $fisher_cache/$item) $item else - printf "fisher: '%s' path not found\n" $item > $error + set total (math $total - 1) + printf "fisher: '%s' not found.\n" $item > $error end end end | while read -l url name + if contains -- $name (__fisher_list $fisher_file) + if test -z "$option" + set total (math $total - 1) + set skipped $skipped $name + continue + end + end + printf "Installing " > $error switch $total @@ -77,94 +87,51 @@ function fisher_install -d "Install Plugins" set index (math $index + 1) end - mkdir -p $fisher_config/{functions,completions,conf.d,man} - mkdir -p $fisher_cache $fisher_share + mkdir -p $fisher_config/{functions,scripts,completions,conf.d,man} $fisher_cache set -l path $fisher_cache/$name - switch "$url" - case file:///\* - if test ! -e $path - ln -sfF (printf "%s\n" $url | sed 's|file://||') $path + if test ! -e $path + if test -d "$url" + ln -sfF $url $path + + else if not wait "__fisher_url_clone $url $path" + printf "fisher: Repository not found: '%s'\n" $url > $error + + switch "$url" + case \*oh-my-fish\* + printf "Did you miss a 'plugin-' or 'theme-' prefix?\n" > $error end - case \* - if test ! -e $path - if not wait --spin=pipe --log=$fisher_error_log " - git clone --quiet --depth 1 $url $path" - - printf "fisher: Repository not found: '%s'\n" $url > $error - - switch "$url" - case \*oh-my-fish\* - printf "Did you miss a 'plugin-' or 'theme-' prefix?\n" > $error - end - - continue - end - end - end - - set -l bundle $path/fishfile - - if test -e $path/bundle - set bundle $path/bundle - end - - if test -e $bundle - printf "Resolving dependencies in %s\n" $name/(basename $bundle) > $error - - set -l deps (__fisher_file $bundle \ - | fisher_install ^&1 \ - | sed -En 's/([0-9]+) plugin\/s.*/\1/p') - - set count (math $count + 0$deps) - end - - if test -s $path/Makefile -o -s $path/makefile - pushd $path - if not make > /dev/null ^ $fisher_error_log - cat $fisher_error_log - popd - continue - end - popd - end - - if test -e $path/fish_prompt.fish -o -e $path/fish_right_prompt.fish - rm -f $fisher_config/functions/fish_{,right_}prompt.fish - functions -e fish_{,right_}prompt - end - - __fisher_plugin --enable $name $path - - set count (math $count + 1) - - set -l file $fisher_config/fishfile - - touch $file - - set -l item $name - - if fisher_search --name=$name --and --tag=local --quiet - set item $url - end - - if test -s $file - if __fisher_file $file | grep -Eq "^$item\$" continue end end - printf "%s\n" "$item" >> $file + set -l deps (__fisher_deps_install "$path") + + if not __fisher_path_make "$path" --quiet + printf "fisher: Failed to build '%s'. See '%s/Makefile'.\n" $name $path > $error + end + + __fisher_plugin_enable "$name" "$path" + + set count (math $count + 1 + "0$deps") end set time (math (date +%s) - $time) - if test "$count" = 0 + if test ! -z "$skipped" + printf "%s plugin/s skipped (%s)\n" (count $skipped) ( + printf "%s\n" $skipped | paste -sd ' ' -) > $error + end + + if test "$count" -le 0 printf "No plugins were installed.\n" > $error return 1 end + __fisher_complete_reset + __fisher_key_bindings_reset + printf "Aye! %d plugin/s installed in %0.fs\n" $count $time > $error end diff --git a/functions/fisher_search.fish b/functions/fisher_search.fish index 4f6ac6b..e46106d 100644 --- a/functions/fisher_search.fish +++ b/functions/fisher_search.fish @@ -1,64 +1,49 @@ function fisher_search -d "Search Plugins" - set -l option - set -l select all set -l fields - set -l join "||" set -l query - set -l quiet 0 set -l index + set -l join "||" + set -l quiet 0 getopts $argv | while read -l 1 2 3 switch "$1" - case _ name url info author tag{,s} - switch "$1" - case _ - switch "$2" - case \*/\* - set 1 url - - set -l url (printf "%s\n" $2 | __fisher_validate) - if test ! -z "$url" - set 2 $url - end - - case \* - set 1 name - end - - case tag{,s} - set 1 "find(tags, \"$2\")" - if test -z "$2" - set 1 "show(tags)" - end - end - + case _ switch "$2" - case "" - set fields $fields $1 - continue + case \*/\* + set -l url (__fisher_plugin_validate $2) - case {~,!~}\* - set 2 "$3$2" - - case \?\* - if test "$3" = ! - set 2 "!=\"$2\"" - else - set 2 "==\"$2\"" + if test ! -z "$url" + set 2 $url end + + set query $query "url==\"$2\"" $join + + case \* + set query $query "name==\"$2\"" $join end - set query "$query$join$1$2" + case name url info author + if test -z "$2" + set fields $fields $1 , + else + switch "$2" + case ~\* + set query $query "$1$3$2" $join - case s select - set select $2 - - case f field{,s} - switch "$2" - case T tag{,s} - set 2 "show(tags)" + case \* + if test -z "$3" + set 3 = + end + set query $query "$1$3=\"$2\"" $join + end + end + + case tag{,s} + if test -z "$2" + set fields $fields "tags(0)" , + else + set query $query "$3 tags(\"$2\")" $join end - set fields $fields $2 case a and set join "&&" @@ -66,7 +51,7 @@ function fisher_search -d "Search Plugins" case o or set join "||" - case Q query + case query set query $query $2 case index @@ -75,162 +60,72 @@ function fisher_search -d "Search Plugins" case q quiet set quiet 1 - case help - set option help - case h - printf "usage: fisher search [] [--select=] [--quiet]\n" - printf " [--or|--and] [--field=] [--help]\n\n" + printf "usage: fisher search [] [--and|--or] [--quiet] [--help]\n\n" - printf " -s --select= Select all, cache or remote plugins \n" - printf " -f --field= Filter by name, url, info, tag or author \n" - printf " -o --or | -a --and Join query with AND/OR operator \n" - printf " -q --quiet Enable quiet mode \n" - printf " -h --help Show usage help \n" + printf " *-- Filter by url, name, info, author or tags\n" + printf " -o --or Join query with OR operator\n" + printf " -a --and Join query with AND operator\n" + printf " -q --quiet Enable quiet mode\n" + printf " -h --help Show usage help\n" return case \* - printf "fisher: Ahoy! '%s' is not a valid option\n" $1 >& 2 - fisher_search --help >& 2 + printf "fisher: '%s' is not a valid option.\n" $1 >& 2 + fisher_search -h >& 2 return 1 end end - switch "$option" - case help - fisher help search - return + if test -z "$index" + set index $fisher_cache/.index + + set fisher_last_update (math (date +%s) - "0$fisher_last_update") + + if not set -q fisher_update_interval + set -g fisher_update_interval 10 + end + + if test $fisher_last_update -gt $fisher_update_interval -o ! -f $index + wait "__fisher_index_update" + end + + set -U fisher_last_update (date +%s) end + set -e fields[-1] + set -e query[-1] + if test -z "$fields[1]" set fields '$0' end - set fields (printf "%s\n" $fields | paste -sd, -) - set query (printf "%s\n" $query | sed -E 's/^[\|&]+//') - - switch "$select" - case all - if test -z "$index" - set index $fisher_cache/.index - - if test -s $fisher_index - set index $fisher_index - else - fisher_update --quiet --index - end - end - - if test ! -s $index - printf "fisher: '%s' invalid path or url\n" $index >& 2 - return 1 - end - - set -l cache (__fisher_list) - - awk -v FS='\n' -v RS='' -v items="$cache" ' - - BEGIN { - split(items, cache, " ") - } - - /^ *#/ { next } { - for (i in cache) { - if (cache[i] == $1) { - delete cache[i] - } - } - } - - END { - for (i in cache) { - printf("%s\n", cache[i]) - } - } - - ' $index | while read -l item - - set -l url - set -l info - set -l tags - set -l author - - if test -e $fisher_cache/$item/.git - set tags custom - - set url (git -C $fisher_cache/$item ls-remote --get-url) - - set info (printf "%s\n" $url \ - | sed -E ' - s|^https?://|| - s|^github\.com|| - s|^bitbucket.org|bb:| - s|^gitlab.com|gl:| - s|^/||') - - set author (printf "%s\n" $url | sed 's|/[^/]*$||;s|.*/||') - - for tag in theme plugin config - switch "$url" - case \*$tag\* - set tags $tag $tags - end - end - else - set tags local - set url $fisher_cache/$item - - if test -L $url - set url (readlink $url) - end - - set author $USER - set info "$author/$item" - end - - printf "\n%s\n%s\n%s\n%s\n%s\n\n" "$item" "$url" "$info" "$tags" "$author" - end - - cat $index - - case remote - fisher_search --index=$index --and --name!=(__fisher_list) - - case cache - set -l cache (__fisher_list) - - if test -z "$cache" - return 1 - end - - fisher_search --index=$index --select=all --name=$cache - - end | awk -F'\n' -v RS='' -v OFS=';' ( + awk -F'\n' -v RS='' -v OFS=';' ( if test "$fields" = '$0' printf "%s\nORS=%s" -v '\\n\\n' - end) " + end + ) " - function find(array, item) { - for (i in array) { - if (array[i] == item) { - return item + function tags(tag, _list) { + if (!tag) { + for (i in tag_list) { + if (!seen[tag_list[i]]++) { + _list = tag_list[i] \"\n\" _list + } + } + return substr(_list, 1, length(_list) - 1) + } + for (i in tag_list) { + if (tag == tag_list[i]) { + return 1 } } + return 0 } - function show(array) { - for (i in array) { - printf(\"%s \", array[i]) - } - } - - /^ *#/ { next } - - { - delete tags - if (\$4) { - split(\$4, tags, \" \") - } + /^ *#/ { next } { + delete tag_list + if (\$4) split(\$4, tag_list, \" \") name = \$1 url = \$2 @@ -238,13 +133,25 @@ function fisher_search -d "Search Plugins" author = \$5 } - $query { - print $fields - } - " | sed '${/^$/d;}' | awk -v quiet=$quiet ' - !/^ *$/ { notEmpty = 1 } - !quiet { print } - quiet && !notEmpty { exit !notEmpty } - END { exit !notEmpty } - ' + $query { print $fields } " $index | awk -v quiet=$quiet ' + + !/^ *$/ { hasRecords = 1 } { + if (quiet) { + exit !hasRecords + } else { + records[NR] = $0 + } + } + + END { + for (i = 1; i <= NR; i++) { + if (i == NR && records[i] ~ /^ *$/) { + break + } + print records[i] + } + + exit !hasRecords + } + ' end diff --git a/functions/fisher_uninstall.fish b/functions/fisher_uninstall.fish index ed766dc..9e1ec1b 100644 --- a/functions/fisher_uninstall.fish +++ b/functions/fisher_uninstall.fish @@ -1,59 +1,65 @@ function fisher_uninstall -d "Uninstall Plugins" - set -l error /dev/stderr - set -l items + set -l plugins set -l option + set -l error /dev/stderr getopts $argv | while read -l 1 2 switch "$1" case _ - set items $items $2 + set plugins $plugins $2 case f force - set option $option force + set option force case q quiet set error /dev/null - case help - set option help - case h printf "usage: fisher uninstall [] [--force] [--quiet] [--help]\n\n" - printf " -f --force Delete copy from cache \n" - printf " -q --quiet Enable quiet mode \n" - printf " -h --help Show usage help \n" + printf " -f --force Delete copy from cache\n" + printf " -q --quiet Enable quiet mode\n" + printf " -h --help Show usage help\n" return case \* - printf "fisher: Ahoy! '%s' is not a valid option\n" $1 >& 2 + printf "fisher: '%s' is not a valid option.\n" $1 >& 2 fisher_uninstall -h >& 2 return 1 end end - switch "$option" - case help - fisher help uninstall - return - end - set -l time (date +%s) set -l count 0 set -l index 1 - set -l total (count $items) + set -l total (count $plugins) + set -l skipped - if set -q items[1] - printf "%s\n" $items + if set -q plugins[1] + + printf "%s\n" $plugins else - __fisher_file /dev/stdin + __fisher_file - end | __fisher_validate | __fisher_resolve_plugin $error | while read -l path + end | while read -l item path + + if not set item (__fisher_plugin_validate $item) + printf "fisher: '%s' is not a valid name, path or url.\n" $item > $error + continue + end + + if not set path (__fisher_path_from_plugin $item) + set total (math $total - 1) + printf "fisher: '%s' not found\n" $item > $error + continue + end set -l name (printf "%s\n" $path | __fisher_name) - if not contains -- $name $fisher_plugins - if not contains -- force $option + if not contains -- $name (__fisher_list $fisher_file) + if test -z "$option" + set total (math $total - 1) + set skipped $skipped $name continue end end @@ -69,41 +75,36 @@ function fisher_uninstall -d "Uninstall Plugins" set index (math $index + 1) end - __fisher_plugin --disable $name $path + if begin not __fisher_path_is_prompt $path; or test "$name" = "$fisher_prompt"; end - git -C $path ls-remote --get-url ^ /dev/null | __fisher_validate | read -l url + # You can use --force to remove any plugin from the cache. If prompt A is enabled + # you can still uninstall prompt B using --force. This will delete B's repository + # from $fisher_cache. - switch force - case $option - rm -rf $path + __fisher_plugin_disable "$name" "$path" + end + + if test "$option" = force + rm -rf $path end set count (math $count + 1) - - set -l file $fisher_config/fishfile - - if not __fisher_file $file | grep -Eq "^$name\$|^$url\$" - continue - end - - set -l tmp (mktemp -t fisher.XXX) - - if not sed -E '/^ *'(printf "%s|%s" $name $url | sed 's|/|\\\/|g' - )'([ #].*)*$/d' < $file > $tmp - rm -f $tmp - printf "fisher: Could not remove '%s' from %s\n" $name $file > $error - return 1 - end - - mv -f $tmp $file end set time (math (date +%s) - $time) - if test $count = 0 + if test ! -z "$skipped" + printf "%s plugin/s skipped (%s)\n" (count $skipped) ( + printf "%s\n" $skipped | paste -sd ' ' -) > $error + end + + if test $count -le 0 printf "No plugins were uninstalled.\n" > $error return 1 end + __fisher_complete_reset + __fisher_key_bindings_reset + printf "Aye! %d plugin/s uninstalled in %0.fs\n" > $error $count $time end diff --git a/functions/fisher_update.fish b/functions/fisher_update.fish index 845205a..890298d 100644 --- a/functions/fisher_update.fish +++ b/functions/fisher_update.fish @@ -1,6 +1,5 @@ -function fisher_update -d "Update Fisherman or Plugins" - set -l path - set -l items +function fisher_update -d "Update Plugins/Fisherman" + set -l plugins set -l option self set -l error /dev/stderr @@ -8,102 +7,63 @@ function fisher_update -d "Update Fisherman or Plugins" switch "$1" case - _ set option - set items $items $2 - - case index - set option index - - case path - set option path - set path $2 + set plugins $plugins $2 case q quiet - set error $2 - - case help - set option help + set error /dev/null case h printf "usage: fisher update [] [--quiet] [--help]\n\n" - printf " -q --quiet Enable quiet mode\n" - printf " -h --help Show usage help \n" + printf " -h --help Show usage help\n" return case \* - printf "fisher: Ahoy! '%s' is not a valid option\n" $1 >& 2 + printf "fisher: '%s' is not a valid option.\n" $1 >& 2 fisher_update -h >& 2 return 1 end end switch "$option" - case help - fisher help update - return - end - - if test -z "$error" - set error /dev/null - end - - switch "$option" - case path - if not test -d $path - printf "fisher: '%s' invalid path\n" $path > $error - return 1 - end - - wait --spin=pipe --log=$fisher_error_log " - - git -C $path checkout --quiet master ^/dev/null - git -C $path pull --quiet --rebase origin master - - " - - case index - mkdir -p $fisher_cache - set -l index $fisher_cache/.index.tmp - - if not set -q fisher_timeout - set fisher_timeout 5 - end - - if wait --spin=pipe --log=$fisher_error_log " - curl --max-time $fisher_timeout -sS $fisher_index > $index - " - mv -f $index $fisher_cache/.index - else - printf "fisher: Connection timeout. Try again.\n" > $error - end - - rm -f $index - case self set -l time (date +%s) printf "Updating >> Fisherman\n" > $error - if not fisher_update --path=$fisher_home --quiet=$error + if not wait "__fisher_index_update; __fisher_path_update $fisher_home" printf "fisher: Arrr! Could not update Fisherman.\n" > $error - sed -E 's/.*error: (.*)/\1/' $fisher_error_log > $error + sed -E 's/.*error: (.*)/\1/' $fisher_cache/.debug > $error return 1 end - printf "Done without errors (%0.fs)\n" (math (date +%s) - $time) > $error + printf "Done without errors. (%0.fs)\n" (math (date +%s) - $time) > $error case \* set -l time (date +%s) set -l count 0 set -l index 1 - set -l total (count $items) + set -l total (count $plugins) + set -l skipped - if set -q items[1] - printf "%s\n" $items + if set -q plugins[1] + + printf "%s\n" $plugins else - __fisher_file /dev/stdin + __fisher_file - end | __fisher_validate | __fisher_resolve_plugin $error | while read -l path + end | while read -l item path + + if not set item (__fisher_plugin_validate $item) + printf "fisher: '%s' is not a valid name, path or url.\n" $item > $error + continue + end + + if not set path (__fisher_path_from_plugin $item) + set total (math $total - 1) + printf "fisher: '%s' not found.\n" $item > $error + continue + end set -l name (printf "%s\n" $path | __fisher_name) @@ -118,22 +78,22 @@ function fisher_update -d "Update Fisherman or Plugins" set index (math $index + 1) end - if not fisher_update --path=$path --quiet + if not wait "__fisher_path_update $path" if test ! -L $path sed -nE 's/.*(error|fatal): (.*)/error: \2/p - ' $fisher_error_log > $error + ' $fisher_cache/.debug > $error continue end end - fisher install --quiet -- $name + fisher_install --quiet --force -- $name set count (math $count + 1) end set time (math (date +%s) - $time) - if test $count = 0 + if test $count -le 0 printf "No plugins were updated.\n" > $error return 1 end diff --git a/functions/getopts.fish b/functions/getopts.fish index 26e23d0..55888b3 100644 --- a/functions/getopts.fish +++ b/functions/getopts.fish @@ -12,7 +12,7 @@ function getopts -d "Parse CLI options" !/^ *$/ { if (done) out("_" , $1$2$3) else if ($1 == "--" && !$2) done = 1 - else if ($1 !~ /^-|^--/ ) out(pop(), $0) + else if ($2 == "" || $1 !~ /^-|^--/ ) out(pop(), $0) else { while (len) out(pop()) if ($3) for (i = 4; i <= NF; i++) $3 = $3" "$i diff --git a/functions/wait.fish b/functions/wait.fish index f4fcc7a..8bc4149 100644 --- a/functions/wait.fish +++ b/functions/wait.fish @@ -1,9 +1,9 @@ -function wait -d "Run commands and wait with a spin" +function wait -d "Run commands and display a spinner" + set -l log + set -l time 0.02 set -l option set -l commands set -l spinners - set -l time 0.02 - set -l log set -l format "@\r" getopts $argv | while read -l 1 2 @@ -12,7 +12,7 @@ function wait -d "Run commands and wait with a spin" case _ set commands $commands ";$2" - case s spin spinner{,s} style + case s spin set spinners $spinners $2 case t time @@ -55,33 +55,33 @@ function wait -d "Run commands and wait with a spin" return 1 end + if not set -q spinners[1] + set spinners mixer + end + switch "$spinners" case arc star pipe ball flip mixer caret set -l arc "◜◠◝◞◡◟" set -l star "+x*" - set -l pipe "-\\|/" + set -l pipe "|/--\\" set -l ball "▖▘▝▗" set -l flip "___-``'´-___" - set -l mixer "⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆" + set -l mixer "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" set -l caret "II||" set spinners "$$spinners" - case bar{1,2,3,\?\?\*} + case bar{1,2,3} set -l bar set -l bar1 "[" "=" " " "]" "%" set -l bar2 "[" "#" " " "]" "%" set -l bar3 "." "." " " " " "%" - switch "$spinners" - case \*{1,2,3} - case \* - printf "%s\n" $spinners | sed -E 's/^bar.?//;s/./& /g' | read -az bar - set spinners bar - end - - set -l IFS \t - printf "%s\t" $$spinners | read -l open fill void close symbol + set -l open $$spinners[1][1] + set -l fill $$spinners[1][2] + set -l void $$spinners[1][3] + set -l close $$spinners[1][4] + set -l symbol $$spinners[1][5] set spinners @@ -111,14 +111,14 @@ function wait -d "Run commands and wait with a spin" while true if status --is-interactive for i in $spinners - printf "$format" | awk -v t=$time -v i=(printf "%s\n" $i | sed 's/=/\\\=/') ' + printf "$format" | awk -v i=(printf "%s\n" $i | sed 's/=/\\\=/') ' { - system("tput civis") gsub("@", i) - printf("%s", $0) - system("sleep "t";tput cnorm") + printf(" %s", $0) } ' > /dev/stderr + + sleep $time end end diff --git a/man/man1/fisher-install.1 b/man/man1/fisher-install.1 index 7f040ee..0f04b3a 100644 --- a/man/man1/fisher-install.1 +++ b/man/man1/fisher-install.1 @@ -7,19 +7,19 @@ \fBfisher\-install\fR \- Install Plugins . .SH "SYNOPSIS" -fisher \fBinstall\fR [\fIplugins\fR \.\.\.] [\fB\-\-quiet\fR] [\fB\-\-help\fR] +fisher \fBinstall\fR [\fIplugins\fR \.\.\.] [\fB\-\-force\fR] [\fB\-\-quiet\fR] [\fB\-\-help\fR] . .SH "USAGE" -fisher \fBinstall\fR \fIname\fR +fisher \fBinstall\fR \fIurl\fR \.\.\. . .br -fisher \fBinstall\fR \fIURL\fR +fisher \fBinstall\fR \fIname\fR \.\.\. . .br -fisher \fBinstall\fR \fIpath\fR +fisher \fBinstall\fR \fIpath\fR \.\.\. . .br -fisher \fBinstall\fR \fIowner/repo\fR +fisher \fBinstall\fR \fIowner/repo\fR \.\.\. . .br . @@ -27,7 +27,7 @@ fisher \fBinstall\fR \fIowner/repo\fR Install one or more plugins, by name, URL or local path\. If no arguments are given, read the standard input\. . .P -If the Git host is not provided, Fisherman will use any value available in \fB$fisher_default_host\fR or https://github\.com by default\. +If the Git host is not provided, Fisherman will use https://github\.com by default\. . .P In addition, all of the following \fBowner/repo\fR variations are accepted: @@ -90,6 +90,10 @@ If a plugin includes either a fish_prompt\.fish or fish_right_prompt\.fish, both .SH "OPTIONS" . .TP +\fB\-f\fR \fB\-\-force\fR +Reinstall given plugin/s\. If the plugin is already in the cache, it will be installed from the cache\. +. +.TP \fB\-q\fR \fB\-\-quiet\fR Enable quiet mode\. . diff --git a/man/man1/fisher-install.md b/man/man1/fisher-install.md index 75b4f56..a3b05a7 100644 --- a/man/man1/fisher-install.md +++ b/man/man1/fisher-install.md @@ -3,20 +3,20 @@ fisher-install(1) -- Install Plugins ## SYNOPSIS -fisher `install` [*plugins* ...] [`--quiet`] [`--help`] +fisher `install` [*plugins* ...] [`--force`] [`--quiet`] [`--help`] ## USAGE -fisher `install` *name*
-fisher `install` *URL*
-fisher `install` *path*
-fisher `install` *owner/repo*
+fisher `install` *url* ...
+fisher `install` *name* ...
+fisher `install` *path* ...
+fisher `install` *owner/repo* ...
## DESCRIPTION Install one or more plugins, by name, URL or local path. If no arguments are given, read the standard input. -If the Git host is not provided, Fisherman will use any value available in `$fisher_default_host` or https://github.com by default. +If the Git host is not provided, Fisherman will use https://github.com by default. In addition, all of the following `owner/repo` variations are accepted: @@ -40,6 +40,9 @@ If a plugin includes either a fish_prompt.fish or fish_right_prompt.fish, both f ## OPTIONS +* `-f` `--force`: + Reinstall given plugin/s. If the plugin is already in the cache, it will be installed from the cache. + * `-q` `--quiet`: Enable quiet mode. diff --git a/man/man1/fisher-search.1 b/man/man1/fisher-search.1 index 5dc0ddd..214132f 100644 --- a/man/man1/fisher-search.1 +++ b/man/man1/fisher-search.1 @@ -10,16 +10,7 @@ fisher \fBsearch\fR [\fIplugins\fR \.\.\.] . .br -fisher \fBsearch\fR [\fB\-\-select\fR=\fIall\fR|\fIcache\fR|\fIremote\fR] -. -.br -fisher \fBsearch\fR [\fB\-\-field\fR=\fIname\fR|\fIurl\fR|\fIinfo\fR|\fItag\fR|\fIauthor\fR] -. -.br -fisher \fBsearch\fR [\fB\-\-\fR\fIfield[\fR=\fImatch\fR]] -. -.br -fisher \fBsearch\fR [\fB\-\-\fR\fIfield\fR~\fB/\fR\fIregex\fR\fB/\fR] +fisher \fBsearch\fR [\fB\-\-name|\-\-url|\-\-info|\-\-tag|\-\-author\fR] . .br fisher \fBsearch\fR [\fB\-\-query\fR=\fIfield\fR[\fB&&\fR,\fB||\fR]\fIfield\fR\.\.\.] @@ -30,18 +21,21 @@ fisher \fBsearch\fR [\fB\-\-and\fR] [\fB\-\-or\fR] [\fB\-\-quiet\fR] [\fB\-\-hel .br . .SH "USAGE" -fisher \fBsearch\fR \fIplugin\fR +fisher \fBsearch\fR \fIurl\fR +. +.br +fisher \fBsearch\fR \fIname\fR . .br fisher \fBsearch\fR \fIowner/repo\fR . .br +fisher \fBsearch\fR \fIquery\fR +. +.br . .SH "DESCRIPTION" -Search the Fisherman index database\. You can use a custom index file by setting \fB$fisher_index\fR to your preferred URL or file\. See \fBfisher help config\fR and \fIIndex\fR in \fBfisher help tour\fR\. -. -.P -A copy of the index is downloaded every time a search query happens, keeping the index up to date all the time\. +Search plugins in the Fisherman index\. . .P The index file consists of records separated by blank lines \fB\'\en\en\'\fR and each record consists of fields separated by a single line \fB\'\en\'\fR\. @@ -64,44 +58,32 @@ author .IP "" 0 . .P -See \fIOutput\fR for more information\. +See \fIIndex\fR in \fBfisher help tour\fR for more information about the index\. . .SH "OPTIONS" . .TP -\fB\-s \-\-select[=all|cache|remote]\fR -Select the record source\. \-\-select=\fIcache\fR queries only local plugins, i\.e\., those inside \fB$fisher_cache\fR\. \-\-select=\fIremote\fR queries all plugins not in the cache, i\.e, those available to install\. \-\-select=\fIall\fR queries everything\. +\fB\-\-[=match]\fR +Display index records where \fB\fR==\fImatch\fR\. \fIfield\fR can be any of \fBname\fR, \fBurl\fR, \fBinfo\fR, \fBtag/s\fR or \fBauthor\fR\. If \fImatch\fR is not given, display only the given \fIfield\fR from every record in the index\. Use \fB!=\fR to negate the query\. . .TP -\fB\-f \-\-field=name|url|info|tag|author\fR -Display only the given fields from the selected records\. Use \-\-\fIfield\fR as a shortcut for \-\-field=\fIfield\fR\. For example \fBfisher search \-\-url\fR will display only the URLs for -. -.TP -\fB\-\-field[=match]\fR -Filter the result set by \fIfield\fR=\fImatch\fR, where \fIfield\fR can be one or more of \fBname\fR, \fBurl\fR, \fBinfo\fR, \fBtag\fR or \fBauthor\fR\. If \fImatch\fR is not given, this is equivalent to \-\-select=\fIfield\fR\. Use \fB!=\fR to negate the query\. -. -.TP -\fB\-\-field[~/regex/]\fR -Essentially the same as \-\-\fIfield\fR=\fImatch\fR, but with Regular Expression support\. \-\-\fIfield\fR~/\fIregex\fR/ filters the result set using the given /\fIregex\fR/\. For example, \-\-name=/^\fImatch\fR$/ is the same as \-\-\fIfield\fR=\fImatch\fR and \-\-url~/oh\-my\-fish/ selects only oh\-my\-fish plugins\. Use \fB!~\fR to negate the query\. +\fB\-\-[~/regex/]\fR +Same as \fB\-\-[=regex]\fR, but with a Regular Expression instead of an exact match\. Use \fB!~\fR to negate the query\. . .TP \fB\-a \-\-and\fR -Join query with the logical AND operator\. +Join the query with a logical AND operator\. . .TP \fB\-o \-\-or\fR -Join query with the logical OR operator\. This the default operator for each query\. -. -.TP -\fB\-Q \-\-query=field[&&,||]field\.\.\.\fR -Use a custom search expression\. For example, \fB\-\-query=name~/[0\-9]/||name~/^[xyz]/\fR selects all plugins that contain numbers in their name \fIor\fR begin with the characters \fIx\fR, \fIy\fR or \fIz\fR\. +Join the query with a logical OR operator\. This is the default operator\. . .TP \fB\-q \-\-quiet\fR Enable quiet mode\. . .TP -\fB\-h \-\-search\fR +\fB\-h \-\-help\fR Show help\. . .SH "OUTPUT" @@ -115,7 +97,7 @@ fisher search shark shark https://github\.com/bucaran/shark Sparkline Generator -chart tool +chart tool graph sparkline bucaran . .fi @@ -123,7 +105,7 @@ bucaran .IP "" 0 . .P -Search is optimized for parsing when using the filters: \fB\-\-name\fR, \fB\-\-url\fR, \fB\-\-info\fR, \fB\-\-tags\fR, \fB\-\-author\fR or \fB\-\-field=name|url|info|tag|author\fR\. +Search is designed for easy parsing when using the filters: \fB\-\-name\fR, \fB\-\-url\fR, \fB\-\-info\fR, \fB\-\-tags\fR, \fB\-\-author\fR\. . .IP "" 4 . @@ -138,12 +120,12 @@ shark;https://github\.com/bucaran/shark .IP "" 0 . .P -The result set above consists of single line \fB\'\en\'\fR separated records, and each record consists of one or more of the given fields separated by a semicolon \fB\';\'\fR\. +The result set above consists of single line per record, and each record consists of one or more of the given fields separated by a semicolon \fB\';\'\fR\. . .SH "EXAMPLES" . .IP "\(bu" 4 -Display all plugins by name and format into multiple columns\. +Display plugins by name and format into multiple columns\. . .IP "" 0 . @@ -158,7 +140,7 @@ fisher search \-\-name | column .IP "" 0 . .IP "\(bu" 4 -Display all plugins by URL, sans \fIhttps://github\.com/\fR and format into multiple columns\. +Display plugins by URL, sans \fIhttps://github\.com/\fR and format into multiple columns\. . .IP "" 0 . @@ -166,14 +148,14 @@ Display all plugins by URL, sans \fIhttps://github\.com/\fR and format into mult . .nf -fisher search \-\-field=url \-\-select=all | sed \'s|https://github\.com/||\' | column +fisher search \-\-field=url | sed \'s|https://github\.com/||\' | column . .fi . .IP "" 0 . .IP "\(bu" 4 -Display all remote plugins by name tagged as \fIa\fR or \fIb\fR\. +Display remote plugins, i\.e, those in the index, but \fInot\fR in the cache\. . .IP "" 0 . @@ -181,14 +163,14 @@ Display all remote plugins by name tagged as \fIa\fR or \fIb\fR\. . .nf -fisher search \-\-select=remote \-\-name \-\-tag=github \-\-or \-\-tag=tool +fisher_search \-\-and \-\-name!=(fisher \-\-list=bare) . .fi . .IP "" 0 . .IP "\(bu" 4 -Search plugins from a list of one or more urls and / or names and display their authors\. +Search all plugins whose name does not start with the letter \fBs\fR\. . .IP "" 0 . @@ -196,22 +178,7 @@ Search plugins from a list of one or more urls and / or names and display their . .nf -fisher search $urls $names \-\-url -. -.fi -. -.IP "" 0 -. -.IP "\(bu" 4 -Search all plugins in the cache whose name does not start with the letter \fBs\fR\. -. -.IP "" 0 -. -.IP "" 4 -. -.nf - -fisher search \-\-select=cache \-\-name~/^[^s]/ +fisher search \-\-name!~/^s/ . .fi . diff --git a/man/man1/fisher-search.md b/man/man1/fisher-search.md index 6ba29d7..bef0a60 100644 --- a/man/man1/fisher-search.md +++ b/man/man1/fisher-search.md @@ -1,26 +1,31 @@ +usage: fisher search [] [--and|--or] [--quiet] [--help] + + --field[=value] Filter by url, name, info, author or tags + -o --or Join query with OR operator + -a --and Join query with AND operator + -q --quiet Enable quiet mode + -h --help Show usage help + fisher-search(1) -- Search Plugin Index ========================================== ## SYNOPSIS fisher `search` [*plugins* ...]
-fisher `search` [`--select`=*all*|*cache*|*remote*]
-fisher `search` [`--field`=*name*|*url*|*info*|*tag*|*author*]
-fisher `search` [`--`*field[*=*match*]]
-fisher `search` [`--`*field*~`/`*regex*`/`]
+fisher `search` [`--name|--url|--info|--tag|--author`]
fisher `search` [`--query`=*field*[`&&`,`||`]*field*...]
fisher `search` [`--and`] [`--or`] [`--quiet`] [`--help`]
## USAGE -fisher `search` *plugin*
+fisher `search` *url*
+fisher `search` *name*
fisher `search` *owner/repo*
+fisher `search` *query*
## DESCRIPTION -Search the Fisherman index database. You can use a custom index file by setting `$fisher_index` to your preferred URL or file. See `fisher help config` and *Index* in `fisher help tour`. - -A copy of the index is downloaded every time a search query happens, keeping the index up to date all the time. +Search plugins in the Fisherman index. The index file consists of records separated by blank lines `'\n\n'` and each record consists of fields separated by a single line `'\n'`. @@ -34,35 +39,27 @@ tag1 tag2 tag3 ... author ``` -See *Output* for more information. +See *Index* in `fisher help tour` for more information about the index. + ## OPTIONS -* `-s --select[=all|cache|remote]`: - Select the record source. --select=*cache* queries only local plugins, i.e., those inside `$fisher_cache`. --select=*remote* queries all plugins not in the cache, i.e, those available to install. --select=*all* queries everything. +* `--[=match]`: + Display index records where ``==*match*. *field* can be any of `name`, `url`, `info`, `tag/s` or `author`. If *match* is not given, display only the given *field* from every record in the index. Use `!=` to negate the query. -* `-f --field=name|url|info|tag|author`: - Display only the given fields from the selected records. Use --*field* as a shortcut for --field=*field*. For example `fisher search --url` will display only the URLs for - -* `--field[=match]`: - Filter the result set by *field*=*match*, where *field* can be one or more of `name`, `url`, `info`, `tag` or `author`. If *match* is not given, this is equivalent to --select=*field*. Use `!=` to negate the query. - -* `--field[~/regex/]`: - Essentially the same as --*field*=*match*, but with Regular Expression support. --*field*~/*regex*/ filters the result set using the given /*regex*/. For example, --name=/^*match*$/ is the same as --*field*=*match* and --url~/oh-my-fish/ selects only oh-my-fish plugins. Use `!~` to negate the query. +* `--[~/regex/]`: + Same as `--[=regex]`, but with a Regular Expression instead of an exact match. Use `!~` to negate the query. * `-a --and`: - Join query with the logical AND operator. + Join the query with a logical AND operator. * `-o --or`: - Join query with the logical OR operator. This the default operator for each query. - -* `-Q --query=field[&&,||]field...`: - Use a custom search expression. For example, `--query=name~/[0-9]/||name~/^[xyz]/` selects all plugins that contain numbers in their name *or* begin with the characters *x*, *y* or *z*. + Join the query with a logical OR operator. This is the default operator. * `-q --quiet`: Enable quiet mode. -* `-h --search`: +* `-h --help`: Show help. ## OUTPUT @@ -74,11 +71,11 @@ fisher search shark shark https://github.com/bucaran/shark Sparkline Generator -chart tool +chart tool graph sparkline bucaran ``` -Search is optimized for parsing when using the filters: `--name`, `--url`, `--info`, `--tags`, `--author` or `--field=name|url|info|tag|author`. +Search is designed for easy parsing when using the filters: `--name`, `--url`, `--info`, `--tags`, `--author`. ``` fisher search shark --name --url @@ -86,38 +83,32 @@ fisher search shark --name --url shark;https://github.com/bucaran/shark ``` -The result set above consists of single line `'\n'` separated records, and each record consists of one or more of the given fields separated by a semicolon `';'`. +The result set above consists of single line per record, and each record consists of one or more of the given fields separated by a semicolon `';'`. ## EXAMPLES -* Display all plugins by name and format into multiple columns. +* Display plugins by name and format into multiple columns. ``` fisher search --name | column ``` -* Display all plugins by URL, sans *https://github.com/* and format into multiple columns. +* Display plugins by URL, sans *https://github.com/* and format into multiple columns. ``` -fisher search --field=url --select=all | sed 's|https://github.com/||' | column +fisher search --field=url | sed 's|https://github.com/||' | column ``` -* Display all remote plugins by name tagged as *a* or *b*. +* Display remote plugins, i.e, those in the index, but *not* in the cache. ``` -fisher search --select=remote --name --tag=github --or --tag=tool +fisher_search --and --name!=(fisher --list=bare) ``` -* Search plugins from a list of one or more urls and / or names and display their authors. +* Search all plugins whose name does not start with the letter `s`. ``` -fisher search $urls $names --url -``` - -* Search all plugins in the cache whose name does not start with the letter `s`. - -``` -fisher search --select=cache --name~/^[^s]/ +fisher search --name!~/^s/ ``` ## SEE ALSO diff --git a/man/man1/fisher-uninstall.1 b/man/man1/fisher-uninstall.1 index dc886d3..70b7544 100644 --- a/man/man1/fisher-uninstall.1 +++ b/man/man1/fisher-uninstall.1 @@ -15,13 +15,16 @@ fisher \fBuninstall\fR [\fB\-\-force\fR] [\fB\-\-quiet\fR] [\fB\-\-help\fR] .br . .SH "USAGE" -fisher \fBuninstall\fR \fIplugin\fR +fisher \fBuninstall\fR \fIurl\fR \.\.\. . .br -fisher \fBuninstall\fR \fIowner/repo\fR +fisher \fBuninstall\fR \fIname\fR \.\.\. . .br -fisher \fBuninstall\fR \fIpath\fR +fisher \fBuninstall\fR \fIpath\fR \.\.\. +. +.br +fisher \fBuninstall\fR \fIowner/repo\fR \.\.\. . .br . diff --git a/man/man1/fisher-uninstall.md b/man/man1/fisher-uninstall.md index 4f42664..0f5d758 100644 --- a/man/man1/fisher-uninstall.md +++ b/man/man1/fisher-uninstall.md @@ -8,9 +8,10 @@ fisher `uninstall` [`--force`] [`--quiet`] [`--help`]
## USAGE -fisher `uninstall` *plugin*
-fisher `uninstall` *owner/repo*
-fisher `uninstall` *path*
+fisher `uninstall` *url* ...
+fisher `uninstall` *name* ...
+fisher `uninstall` *path* ...
+fisher `uninstall` *owner/repo* ...
## DESCRIPTION diff --git a/man/man1/fisher-update.1 b/man/man1/fisher-update.1 index 5e619d9..ec461df 100644 --- a/man/man1/fisher-update.1 +++ b/man/man1/fisher-update.1 @@ -7,23 +7,23 @@ \fBfisher\-update\fR \- Update Fisherman and Plugins . .SH "SYNOPSIS" -fisher \fBupdate\fR [\fIplugins\fR \.\.\.] -. -.br -fisher \fBupdate\fR [\fB\-\-quiet\fR] [\fB\-\-help\fR] +fisher \fBupdate\fR [\fIplugins\fR \.\.\.] [\fB\-\-quiet\fR] [\fB\-\-help\fR] . .br . .SH "USAGE" -fisher \fBupdate\fR \fIplugin\fR \.\.\. +fisher \fBupdate\fR \fIurl\fR \.\.\. . .br -fisher \fBupdate\fR \fIowner/repo\fR \.\.\. +fisher \fBupdate\fR \fIname\fR \.\.\. . .br fisher \fBupdate\fR \fIpath\fR \.\.\. . .br +fisher \fBupdate\fR \fIowner/repo\fR \.\.\. +. +.br . .SH "DESCRIPTION" Update one or more plugins, by name, URL or local path\. If no arguments are given, update Fisherman itself\. If you try to update a plugin that is currently disabled, but in the cache, it will be updated and then enabled\. Use a dash \fB\-\fR to read from the standard input\. diff --git a/man/man1/fisher-update.md b/man/man1/fisher-update.md index 6788996..e7249c6 100644 --- a/man/man1/fisher-update.md +++ b/man/man1/fisher-update.md @@ -3,14 +3,14 @@ fisher-update(1) -- Update Fisherman and Plugins ## SYNOPSIS -fisher `update` [*plugins* ...]
-fisher `update` [`--quiet`] [`--help`]
+fisher `update` [*plugins* ...] [`--quiet`] [`--help`]
## USAGE -fisher `update` *plugin* ...
-fisher `update` *owner/repo* ...
+fisher `update` *url* ...
+fisher `update` *name* ...
fisher `update` *path* ...
+fisher `update` *owner/repo* ...
## DESCRIPTION diff --git a/man/man1/fisher.1 b/man/man1/fisher.1 index 9bc3266..728ac36 100644 --- a/man/man1/fisher.1 +++ b/man/man1/fisher.1 @@ -26,12 +26,12 @@ The following commands are available out of the box: \fIinstall\fR, \fIuninstall .SH "OPTIONS" . .TP -\fB\-\-list=cache|enabled|disabled\fR -List plugins according to the given category\. +\fB\-\-list[=bare|enabled|disabled]\fR +List plugins according to the given category\. List plugins in the cache by default\. Enabled plugins are prepended with a \fB*\fR character\. To list plugins without the \fB*\fR character use \fB\-\-list=bare\fR\. . .TP \fB\-f \-\-file=fishfile\fR -Read \fIfishfile\fR and display its contents\. If \fIfishfile\fR is null or an empty string, your user \fIfishfile\fR in \fB$fisher_config/fishfile\fR will be shown instead\. Use a dash \fB\-\fR to read from the standard input\. Other formats such as the oh\-my\-fish bundle files are supported as well\. +Read \fIfishfile\fR and display its contents\. If \fIfishfile\fR is null or an empty string, your user \fIfishfile\fR in \fB$fisher_file\fR will be shown instead\. Use a dash \fB\-\fR to read from the standard input\. Other formats such as the oh\-my\-fish bundle files are supported as well\. . .TP \fB\-v \-\-version\fR diff --git a/man/man1/fisher.md b/man/man1/fisher.md index 8e9dc80..a5f6181 100644 --- a/man/man1/fisher.md +++ b/man/man1/fisher.md @@ -15,11 +15,11 @@ The following commands are available out of the box: *install*, *uninstall*, *up ## OPTIONS -* `--list=cache|enabled|disabled`: - List plugins according to the given category. +* `--list[=bare|enabled|disabled]`: + List plugins according to the given category. List plugins in the cache by default. Enabled plugins are prepended with a `*` character. To list plugins without the `*` character use `--list=bare`. * `-f --file=fishfile`: - Read *fishfile* and display its contents. If *fishfile* is null or an empty string, your user *fishfile* in `$fisher_config/fishfile` will be shown instead. Use a dash `-` to read from the standard input. Other formats such as the oh-my-fish bundle files are supported as well. + Read *fishfile* and display its contents. If *fishfile* is null or an empty string, your user *fishfile* in `$fisher_file` will be shown instead. Use a dash `-` to read from the standard input. Other formats such as the oh-my-fish bundle files are supported as well. * `-v --version`: Show version information. Fisherman's current version can be found in the VERSION file at the root of the project. The version scheme is based in `Semantic Versioning` and uses Git annotated tags to track releases. diff --git a/man/man1/wait.1 b/man/man1/wait.1 index dea83ec..5228b60 100644 --- a/man/man1/wait.1 +++ b/man/man1/wait.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WAIT" "1" "January 2016" "" "fisherman" +.TH "WAIT" "1" "February 2016" "" "fisherman" . .SH "NAME" \fBwait\fR \- Run commands and wait with a spin @@ -19,7 +19,7 @@ Run \fIcommands\fR as a background process and wait until the job has finished\. . .TP \fB\-s \-\-spin=style|string\fR -Set spinner style\. See \fBStyles\fR for a list of styles and instructions on how to use your own character sequences, progress bar usage, etc\. +Set spinner style\. See \fBStyles\fR for styles and details to customize the spinner characters\. . .TP \fB\-t \-\-time=interval\fR @@ -38,7 +38,6 @@ Use given \fIformat\fR to display the spinner\. The default format is \fB"\er@"\ Show usage help\. . .SH "STYLES" -The following styles are supported via \fB\-\-spin=style\fR: . .IP "\(bu" 4 arc, star, pipe, ball, flip, mixer, caret @@ -48,11 +47,14 @@ bar1~3 . .IP "" 0 . +.P +If no style is given in \fB\-\-spin=