Ahoy! Fisherman 0.5.0

=====================

Add user key bindings support.

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

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 <file> or fisher --list=<file>.

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.
pull/445/head
Jorge Bucaran 8 years ago
parent 06a9aff5b5
commit 6b31d00599
No known key found for this signature in database
GPG Key ID: E54BA3C0E646DB30

@ -1,4 +1,5 @@
# Authors
* Jorge Bucaran &lt;[j@bucaran.me](mailto:j@bucaran.me)&gt;
* Daniel Perez &lt;[daniel@claudetech.com](mailto:daniel@claudetech.com)&gt;
* Hyeon Kim &lt;[simnalamburt@gmail.com](mailto:simnalamburt@gmail.com)&gt;
* Kevin Ballard &lt;[kevin@sb.org](mailto:kevin@sb.org)&gt;

@ -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.4.0][v040] - 2016-01-11
## [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.
:anchor: Introducting Fisherman's official website :construction:
+ 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`.
<a href="http://fisherman.sh">
<img src="https://cloud.githubusercontent.com/assets/8317250/12229311/c0eea838-b889-11e5-94eb-280d95fbdd49.png">
</a>
+ 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.
. Powered by Jekyll and hosted by GitHub pages.
+ 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.
* 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.
* **Improve test coverage.**
* Add support for [Tackle](https://github.com/justinmayer/tackle) Fish framework initialization modules. Closes #35.
+ 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.
* :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.
* **Other**
* 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.
+ 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 <file>` or `fisher --list=<file>`.
* A cleaner alternative is using the new `$fisher_share` variable like this: `python $fisher_share/my_plugin_script.py`.
+ 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.
* `$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`.
+ 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.
* 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`.
+ 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.
* `.fish` and `.md` extensions are always ignored.
+ 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.
* Remove ad-hoc debug `d` function created by mistake in the Fisherman config.fish file. Closes #34.
+ 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
* Introducing Fisherman's official website, hosted by GitHub pages.
&emsp;&emsp; [**http://fisherman.sh**](http://fisherman.sh)
* 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/<name>` 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/<name>` 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 @@
<!-- Links -->
[v040]: https://
[v050]: https://
[v040]: https://github.com/fisherman/fisherman/commit/fd24fef56b68f8139ca95f5b0ef406647ce3ec4c
[v031]: https://github.com/fisherman/fisherman/commit/a0fe0b339df2fe70a0ba1a5e28dcd7449582742b

@ -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 <command>'")
@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 \&lt;[\2](mailto:\2)\&gt;/' >> $@
%.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;\

@ -1,3 +1,5 @@
<a name="fisherman"></a>
<p align="center">
<a href="http://fisherman.sh">
<img alt="Fisherman" width=620px src="https://cloud.githubusercontent.com/assets/8317250/10865127/daa0e138-8044-11e5-91f9-f72228974552.png">
@ -8,33 +10,54 @@
![Fisherman Version][fisherman-version]
[![Wharf][wharf-badge]][wharf-link]
## About
**Fisherman** is a fast, modern plugin system for [Fish](http://fishshell.com/).
**Fisherman** is a blazing [fast](#performance), modern plugin manager for [Fish](http://fishshell.com/).
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.
:beginner: [**Get Started**][quickstart]
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.
## Performance
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.
The following benchmarks were calculated using a 2.4 GHz Intel Core i5 MacBook Pro running on Flash Storage.
:beginner: [**Get Started**][quickstart].
```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`.
## Help
To learn more about these benchmarks, see [Performance][performance].
<p align="center">
<img width=70% src="https://cloud.githubusercontent.com/assets/8317250/12727212/42790372-c95f-11e5-9f2d-7f78ff8303e9.png"
</p>
For documentation, examples and guides [see the wiki][wiki]. For support and feedback join the [Wharf][wharf-link] or browse the [issues][issues].
## 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:
<!-- Links -->
[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

@ -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_use_subcommand" -s l -l list -d "List plugins enabled|disabled|cache|<file>"
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 -c fisher -n "__fish_seen_subcommand_from help" -a $cmd -d "$info"
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"
if test $option != guides
complete -c fisher -n "__fish_use_subcommand" -a $cmd -d "$info"
set -l IFS ";"
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
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
begin
for plugin in (__fisher_list)
printf "%s;%s\n" $plugin ""
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
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"
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 install i" -a "$name" -d "$info"
complete -c fisher -n "__fish_seen_subcommand_from i install" -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 h -l help -d "Display help"
complete -c fisher -n "__fish_use_subcommand" -s v -l version -d "Show version information"
end
complete -xc fisher -d "Ahoy! Fisherman"
complete -c fisher -n "__fish_seen_subcommand_from update" -a "fisherman" -d "Update Fisherman"

@ -1 +1 @@
complete -xc getopts -d "Parse CLI options" -a "\t"
complete -xc getopts -a '\t'

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

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

@ -0,0 +1,3 @@
function __fisher_cache_list
find -L $fisher_cache/* -maxdepth 0 -type d | sed 's|.*/||'
end

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

@ -0,0 +1,4 @@
function __fisher_complete_reset
complete -ec fisher
source $fisher_home/completions/fisher.fish
end

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

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

@ -1,15 +1,19 @@
function __fisher_file -d "read one or more fishfiles"
function __fisher_file
awk '
!/^ *(#.*)*$/ {
gsub("#.*", "")
if (/^ *package .+/) {
$1 = $2
/^[ \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 (!duplicates[$1]++) {
if (! seen[$1]++) {
printf("%s\n", $1)
}
}
' $argv
'
end

@ -0,0 +1,4 @@
function __fisher_file_contains -a plugin
set -e argv[1]
grep -E "^(package *|plugin *)?$plugin*\$" $argv
end

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

@ -0,0 +1,3 @@
function __fisher_help_parse
sed -nE 's/^ *(-(.))?,? *--([^ =]+) *(.*)$/\4;\3;\2/p'
end

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

@ -0,0 +1,3 @@
function __fisher_key_bindings
source $fisher_key_bindings ^ /dev/null
end

@ -0,0 +1,3 @@
function __fisher_key_bindings_delete -a plugin
sed "/##$plugin##/,/##$plugin##/d"
end

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

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

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

@ -0,0 +1,3 @@
function __fisher_key_bindings_undo -a plugin
sed -n "/##$plugin##/,/##$plugin##/{s/bind /bind -e /p;};"
end

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

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

@ -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 \*
for file in $fisher_cache/*
set -l name (basename $file)
case "" all cache
set -l enabled (__fisher_list $fisher_file)
set -l legend " "
switch "$category"
case disabled off
if not contains -- $name $fisher_plugins
printf "%s\n" $name
end
if test -z "$enabled"
set legend ""
end
case \*
printf "%s\n" $name
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 \*
if test -s "$source"
__fisher_list - < $source
end
end
end

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

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

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

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

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

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

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

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

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

@ -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 <path> (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

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

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

@ -0,0 +1,5 @@
function __fisher_plugin_uninstall_handler -a plugin file
if source $file $plugin $file
emit uninstall_$plugin $file
end
end

@ -0,0 +1,4 @@
function __fisher_plugin_unlink -a name file
rm -f $file
functions -e $name
end

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

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

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

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

@ -0,0 +1,3 @@
function __fisher_string_escape
sed 's|/|\\\/|g'
end

@ -0,0 +1,3 @@
function __fisher_url_clone -a url path
git clone -q --depth 1 $url $path
end

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

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

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

@ -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 <command> [<options>] [--version] [--help]\n\n"
printf "usage: fisher <command> [<args>] [--list] [--version] [--help]\n\n"
switch commands
case $value

@ -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 [<keyword>] [--all] [--guides] [--help]\n\n"
printf " -a --all List available documentation \n"
printf " -g --guides List available guides \n"
printf " -u --usage[=<cmd>] 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[=<cmd>] 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("\'","")

@ -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 [<plugins>] [--quiet] [--help]\n\n"
printf "usage: fisher install [<plugins>] [--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 plugins[1]
if set -q items[1]
printf "%s\n" $items
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
end
if test ! -e $path
if test -d "$url"
ln -sfF $url $path
case \*
if test ! -e $path
if not wait --spin=pipe --log=$fisher_error_log "
git clone --quiet --depth 1 $url $path"
else if not wait "__fisher_url_clone $url $path"
printf "fisher: Repository not found: '%s'\n" $url > $error
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
switch "$url"
case \*oh-my-fish\*
printf "Did you miss a 'plugin-' or 'theme-' prefix?\n" > $error
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 deps (__fisher_deps_install "$path")
set -l file $fisher_config/fishfile
touch $file
set -l item $name
if fisher_search --name=$name --and --tag=local --quiet
set item $url
if not __fisher_path_make "$path" --quiet
printf "fisher: Failed to build '%s'. See '%s/Makefile'.\n" $name $path > $error
end
if test -s $file
if __fisher_file $file | grep -Eq "^$item\$"
continue
end
end
__fisher_plugin_enable "$name" "$path"
printf "%s\n" "$item" >> $file
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

@ -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 _
switch "$2"
case \*/\*
set -l url (__fisher_plugin_validate $2)
case tag{,s}
set 1 "find(tags, \"$2\")"
if test -z "$2"
set 1 "show(tags)"
if test ! -z "$url"
set 2 $url
end
end
switch "$2"
case ""
set fields $fields $1
continue
case {~,!~}\*
set 2 "$3$2"
case \?\*
if test "$3" = !
set 2 "!=\"$2\""
else
set 2 "==\"$2\""
end
end
set query $query "url==\"$2\"" $join
set query "$query$join$1$2"
case \*
set query $query "name==\"$2\"" $join
end
case s select
set select $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 \*
if test -z "$3"
set 3 =
end
set query $query "$1$3=\"$2\"" $join
end
end
case f field{,s}
switch "$2"
case T tag{,s}
set 2 "show(tags)"
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 [<plugins>] [--select=<source>] [--quiet]\n"
printf " [--or|--and] [--field=<field>] [--help]\n\n"
printf " -s --select=<source> Select all, cache or remote plugins \n"
printf " -f --field=<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 "usage: fisher search [<plugins>] [--and|--or] [--quiet] [--help]\n\n"
printf " *--<field> 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
end
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
if test -z "$index"
set index $fisher_cache/.index
printf "\n%s\n%s\n%s\n%s\n%s\n\n" "$item" "$url" "$info" "$tags" "$author"
end
set fisher_last_update (math (date +%s) - "0$fisher_last_update")
cat $index
if not set -q fisher_update_interval
set -g fisher_update_interval 10
end
case remote
fisher_search --index=$index --and --name!=(__fisher_list)
if test $fisher_last_update -gt $fisher_update_interval -o ! -f $index
wait "__fisher_index_update"
end
case cache
set -l cache (__fisher_list)
set -U fisher_last_update (date +%s)
end
if test -z "$cache"
return 1
end
set -e fields[-1]
set -e query[-1]
fisher_search --index=$index --select=all --name=$cache
if test -z "$fields[1]"
set fields '$0'
end
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)
}
}
function show(array) {
for (i in array) {
printf(\"%s \", array[i])
for (i in tag_list) {
if (tag == tag_list[i]) {
return 1
}
}
return 0
}
/^ *#/ { 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

@ -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 [<plugins>] [--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 plugins[1]
if set -q items[1]
printf "%s\n" $items
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
set count (math $count + 1)
set -l file $fisher_config/fishfile
if not __fisher_file $file | grep -Eq "^$name\$|^$url\$"
continue
if test "$option" = force
rm -rf $path
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
set count (math $count + 1)
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

@ -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 [<plugins>] [--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 plugins[1]
if set -q items[1]
printf "%s\n" $items
printf "%s\n" $plugins
else
__fisher_file /dev/stdin
__fisher_file
end | while read -l item path
end | __fisher_validate | __fisher_resolve_plugin $error | while read -l 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

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

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

@ -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\.
.

@ -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*<br>
fisher `install` *URL*<br>
fisher `install` *path*<br>
fisher `install` *owner/repo*<br>
fisher `install` *url* ...<br>
fisher `install` *name* ...<br>
fisher `install` *path* ...<br>
fisher `install` *owner/repo* ...<br>
## 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.

@ -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
.
.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\.
.br
.
.P
A copy of the index is downloaded every time a search query happens, keeping the index up to date all the time\.
.SH "DESCRIPTION"
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\.
.
.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\.
\fB\-\-<field>[=match]\fR
Display index records where \fB<field>\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\-\-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\-\-<field>[~/regex/]\fR
Same as \fB\-\-<field>[=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,22 +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\.
.
.IP "" 0
.
.IP "" 4
.
.nf
fisher search \-\-field=url \-\-select=all | 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 plugins by URL, sans \fIhttps://github\.com/\fR and format into multiple columns\.
.
.IP "" 0
.
@ -181,14 +148,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 \-\-field=url | sed \'s|https://github\.com/||\' | column
.
.fi
.
.IP "" 0
.
.IP "\(bu" 4
Search plugins from a list of one or more urls and / or names and display their authors\.
Display remote plugins, i\.e, those in the index, but \fInot\fR in the cache\.
.
.IP "" 0
.
@ -196,14 +163,14 @@ Search plugins from a list of one or more urls and / or names and display their
.
.nf
fisher search $urls $names \-\-url
fisher_search \-\-and \-\-name!=(fisher \-\-list=bare)
.
.fi
.
.IP "" 0
.
.IP "\(bu" 4
Search all plugins in the cache whose name does not start with the letter \fBs\fR\.
Search all plugins whose name does not start with the letter \fBs\fR\.
.
.IP "" 0
.
@ -211,7 +178,7 @@ Search all plugins in the cache whose name does not start with the letter \fBs\f
.
.nf
fisher search \-\-select=cache \-\-name~/^[^s]/
fisher search \-\-name!~/^s/
.
.fi
.

@ -1,26 +1,31 @@
usage: fisher search [<plugins>] [--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* ...]<br>
fisher `search` [`--select`=*all*|*cache*|*remote*]<br>
fisher `search` [`--field`=*name*|*url*|*info*|*tag*|*author*]<br>
fisher `search` [`--`*field[*=*match*]] <br>
fisher `search` [`--`*field*~`/`*regex*`/`] <br>
fisher `search` [`--name|--url|--info|--tag|--author`]<br>
fisher `search` [`--query`=*field*[`&&`,`||`]*field*...]<br>
fisher `search` [`--and`] [`--or`] [`--quiet`] [`--help`]<br>
## USAGE
fisher `search` *plugin*<br>
fisher `search` *url*<br>
fisher `search` *name*<br>
fisher `search` *owner/repo*<br>
fisher `search` *query*<br>
## 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.
* `-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
## OPTIONS
* `--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>[=match]`:
Display index records where `<field>`==*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.
* `--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.
* `--<field>[~/regex/]`:
Same as `--<field>[=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.
```
fisher search --field=url --select=all | sed 's|https://github.com/||' | column
```
* Display all remote plugins by name tagged as *a* or *b*.
* Display plugins by URL, sans *https://github.com/* and format into multiple columns.
```
fisher search --select=remote --name --tag=github --or --tag=tool
fisher search --field=url | sed 's|https://github.com/||' | column
```
* Search plugins from a list of one or more urls and / or names and display their authors.
* Display remote plugins, i.e, those in the index, but *not* in the cache.
```
fisher search $urls $names --url
fisher_search --and --name!=(fisher --list=bare)
```
* Search all plugins in the cache whose name does not start with the letter `s`.
* Search all plugins whose name does not start with the letter `s`.
```
fisher search --select=cache --name~/^[^s]/
fisher search --name!~/^s/
```
## SEE ALSO

@ -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
.

@ -8,9 +8,10 @@ fisher `uninstall` [`--force`] [`--quiet`] [`--help`] <br>
## USAGE
fisher `uninstall` *plugin*<br>
fisher `uninstall` *owner/repo*<br>
fisher `uninstall` *path*<br>
fisher `uninstall` *url* ...<br>
fisher `uninstall` *name* ...<br>
fisher `uninstall` *path* ...<br>
fisher `uninstall` *owner/repo* ...<br>
## DESCRIPTION

@ -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\.

@ -3,14 +3,14 @@ fisher-update(1) -- Update Fisherman and Plugins
## SYNOPSIS
fisher `update` [*plugins* ...] <br>
fisher `update` [`--quiet`] [`--help`] <br>
fisher `update` [*plugins* ...] [`--quiet`] [`--help`] <br>
## USAGE
fisher `update` *plugin* ...<br>
fisher `update` *owner/repo* ...<br>
fisher `update` *url* ...<br>
fisher `update` *name* ...<br>
fisher `update` *path* ...<br>
fisher `update` *owner/repo* ...<br>
## DESCRIPTION

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

@ -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.

@ -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=<style>\fR, \fBmixer\fR is used by default\. If you don\'t want to display any spinners, use \fB\-\-spin=""\fR\.
.
.SS "CUSTOMIZATION"
In addition to the default styles, you can specify a string of character tokens to be used each per spinner refresh cycle\.
.
.P
For example \fB\-\-spin=12345\fR will display the numbers from 1 to 5, and \fB\-\-spin=\. \-\-format=@\fR an increasing sequence of dots\.
For example \fB\-\-spin=12345\fR will display the numbers from 1 to 5, and \fB\-\-spin=\. \-\-format=@\fR an increasing sequence of dots and \fB@\fR represents the spinner character\.
.
.SS "PROGRESS BARS"
Display a progress bar with a percent indicator using \fB\-\-spin=bar1~3\fR:
@ -68,34 +70,6 @@ bar3: \.\.\.\.\.\.\. \fInum\fR%
.
.IP "" 0
.
.P
You can customize the appearance as follows:
.
.IP "" 4
.
.nf
\-\-spin=bar:<opening token><fill token><empty slot token><closing token>[%]
.
.fi
.
.IP "" 0
.
.P
For example:
.
.IP "" 4
.
.nf
\-\-spin="bar:[+\-]%"
\-\-spin="bar:(@o)"
\-\-spin="bar:||_|"
.
.fi
.
.IP "" 0
.
.SH "EXAMPLES"
Run a lengthy operation as a background job and display a spinning pipe character until it is finished\.
.

@ -13,7 +13,7 @@ Run *commands* as a background process and wait until the job has finished. Any
## OPTIONS
* `-s --spin=style|string`:
Set spinner style. See `Styles` for a list of styles and instructions on how to use your own character sequences, progress bar usage, etc.
Set spinner style. See `Styles` for styles and details to customize the spinner characters.
* `-t --time=interval`:
Set spinner transition time delay in *seconds*. A large value will refresh the spinner more slowly. You may use decimal numbers to represent smaller numbers.
@ -29,16 +29,16 @@ Run *commands* as a background process and wait until the job has finished. Any
## STYLES
The following styles are supported via `--spin=style`:
* arc, star, pipe, ball, flip, mixer, caret
* bar1~3
If no style is given in `--spin=<style>`, `mixer` is used by default. If you don't want to display any spinners, use `--spin=""`.
### CUSTOMIZATION
In addition to the default styles, you can specify a string of character tokens to be used each per spinner refresh cycle.
For example `--spin=12345` will display the numbers from 1 to 5, and `--spin=. --format=@` an increasing sequence of dots.
For example `--spin=12345` will display the numbers from 1 to 5, and `--spin=. --format=@` an increasing sequence of dots and `@` represents the spinner character.
### PROGRESS BARS
@ -48,20 +48,6 @@ Display a progress bar with a percent indicator using `--spin=bar1~3`:
* bar2: [#####] *num*%
* bar3: ....... *num*%
You can customize the appearance as follows:
```
--spin=bar:<opening token><fill token><empty slot token><closing token>[%]
```
For example:
```
--spin="bar:[+-]%"
--spin="bar:(@o)"
--spin="bar:||_|"
```
## EXAMPLES
Run a lengthy operation as a background job and display a spinning pipe character until it is finished.

@ -10,7 +10,7 @@
A \fIfishfile\fR lets you share plugin configurations across multiple installations, allows plugins to declare dependencies, and prevent information loss in case of system failure\.
.
.P
Fisherman also keeps a user \fIfishfile\fR in \fB$fisher_config/fishfile\fR which is automatically updated as you install or uninstall plugins\.
Fisherman also keeps a user \fIfishfile\fR in \fB$fisher_file\fR which is automatically updated as you install or uninstall plugins\.
.
.SH "USAGE"
Fishfiles are plain text, manifest files that list one or more plugins by their name, URL or path to a local project\.
@ -37,7 +37,7 @@ oh\-my\-fish/bobthefish
To read fishfiles use \fBfisher \-\-file=fishfile\fR\. This will read \fIfishfile\fR sequentially, writing its contents to the standard output\. oh\-my\-fish bundle files are supported as well\.
.
.P
If \fIfishfile\fR is null or an empty string, the global \fIfishfile\fR in \fB$fisher_config/fishfile\fR will be used\. Use a dash \fB\-\fR to force read from standard input\.
If \fIfishfile\fR is null or an empty string, the global \fIfishfile\fR in \fB$fisher_file\fR will be used\. Use a dash \fB\-\fR to force read from standard input\.
.
.SH "PLUGINS"
Plugins may declare any number of dependencies to other plugins in a fishfile at the root of their project\.

@ -5,7 +5,7 @@ fisher-fishfile(5) -- Fishfile Format
A *fishfile* lets you share plugin configurations across multiple installations, allows plugins to declare dependencies, and prevent information loss in case of system failure.
Fisherman also keeps a user *fishfile* in `$fisher_config/fishfile` which is automatically updated as you install or uninstall plugins.
Fisherman also keeps a user *fishfile* in `$fisher_file` which is automatically updated as you install or uninstall plugins.
## USAGE
@ -24,7 +24,7 @@ oh-my-fish/bobthefish
To read fishfiles use `fisher --file=fishfile`. This will read *fishfile* sequentially, writing its contents to the standard output. oh-my-fish bundle files are supported as well.
If *fishfile* is null or an empty string, the global *fishfile* in `$fisher_config/fishfile` will be used. Use a dash `-` to force read from standard input.
If *fishfile* is null or an empty string, the global *fishfile* in `$fisher_file` will be used. Use a dash `-` to force read from standard input.
## PLUGINS

@ -0,0 +1 @@
fisher-fishfile.5

@ -40,25 +40,9 @@ The cache directory\. Plugins are first downloaded here and installed to \fB$fis
Index source URL or file\. To use a different index set this to a file or URL\. Redirect urls are not supported due to security and performance concerns\. The underlying request and fetch mechanism is based in \fBcurl(1)\fR\. See also \fBIndex\fR in \fBfisher help tour\fR\.
.
.TP
\fB$fisher_error_log\fR
This file keeps a log of the most recent crash stack trace\. \fB$fisher_cache/\.debug_log\fR by default\.
.
.TP
\fB$fisher_alias command=alias[,\.\.\.] [command2=alias[,\.\.\.]]\fR
Use this variable to define custom aliases for fisher commands\. See \fBExamples\fR below\.
.
.TP
\fB$fisher_default_host\fR
Use this variable to define your preferred git host\. Fisherman uses this value to convert short urls like \fBowner/repo\fR to \fBhttps://host/owner/repo\fR\. The default host is \fIgithub\.com\fR\.
.
.TP
\fB$fisher_share\fR
Used to share scripts other than \fB\.fish\fR files between plugins\. Use \fB$fisher_share_extensions\fR to customize what extensions are used\.
.
.TP
\fB$fisher_share_extensions\fR
Customize what file extensions are copied to \fB$fisher_config\fR when sharing scripts\. By default \fBpy rb php pl awk sed\fR are used\.
.
.SH "EXAMPLES"
.
.IP "\(bu" 4
@ -77,7 +61,7 @@ set fisher_alias install=i,in,inst update=up
.IP "" 0
.
.IP "\(bu" 4
Set \fB$fisher_index\fR and \fB$fisher_default_host\fR\.
Set \fB$fisher_index\fR to a custom database\.
.
.IP "" 0
.
@ -86,7 +70,6 @@ Set \fB$fisher_index\fR and \fB$fisher_default_host\fR\.
.nf
set fisher_index https://raw\.\.\./owner/repo/master/index2\.txt
set fisher_default_host bitbucket\.org
.
.fi
.

@ -29,22 +29,12 @@ You can also customize the debug log path, cache location, index source URL, com
* `$fisher_index`:
Index source URL or file. To use a different index set this to a file or URL. Redirect urls are not supported due to security and performance concerns. The underlying request and fetch mechanism is based in `curl(1)`. See also `Index` in `fisher help tour`.
* `$fisher_error_log`:
This file keeps a log of the most recent crash stack trace. `$fisher_cache/.debug_log` by default.
* `$fisher_file`:
This file keeps a list of what plugins you have installed and are currently enabled. `$fisher_cofig/fishfile` by default.
* `$fisher_alias command=alias[,...] [command2=alias[,...]]`:
Use this variable to define custom aliases for fisher commands. See `Examples` below.
* `$fisher_default_host`:
Use this variable to define your preferred git host. Fisherman uses this value to convert short urls like `owner/repo` to `https://host/owner/repo`. The default host is *github.com*.
* `$fisher_share`:
Used to share scripts other than `.fish` files between plugins. Use `$fisher_share_extensions` to customize what extensions are used.
* `$fisher_share_extensions`:
Customize what file extensions are copied to `$fisher_config` when sharing scripts. By default `py rb php pl awk sed` are used.
## EXAMPLES
* Create aliases for fisher `install` to *i*, *in* and *inst*; and for fisher `update` to *up*.
@ -53,11 +43,10 @@ You can also customize the debug log path, cache location, index source URL, com
set fisher_alias install=i,in,inst update=up
```
* Set `$fisher_index` and `$fisher_default_host`.
* Set `$fisher_index` to a custom database.
```
set fisher_index https://raw.../owner/repo/master/index2.txt
set fisher_default_host bitbucket.org
```
## SEE ALSO

@ -13,10 +13,30 @@ This document attempts to answer some of Fisherman most frequently asked questio
Fisherman is a plugin manager for fish that lets you share and reuse code, prompts and configurations easily\.
.
.SS "What do I need to know to use Fisherman?"
Nothing\. You can continue using your shell as usual\. When you are ready to learn more just type \fBman fisher\fR or \fBman 7 fisher\fR\.
Nothing\. You can continue using your shell as usual\. When you are ready to learn more just type \fBfisher help\fR or \fBfisher help tour\fR\.
.
.SS "How do I access other Fisherman documentation?"
Fisherman documentation is based in UNIX \fBman(1)\fR pages\. See \fBman fisher\fR and \fBman 7 fisher\fR to get started\. You can also access any documentation using the \fBfisher help\fR command\.
.SS "How do I access the documentation?"
Fisherman documentation is based in UNIX \fBman(1)\fR pages\. For basic usage and command enter \fBfisher help\fR\. For help about a specific \fIcommand\fR, enter \fBfisher help <command>\fR\. The following guides are also available:
.
.P
fisher help \fBfaq\fR: Fisherman FAQ
.
.br
fisher help \fBtour\fR: Fisherman Tour
.
.br
fisher help \fBconfig\fR: Fisherman Configuration
.
.br
fisher help \fBplugins\fR: Creating Fisherman Plugins
.
.br
fisher help \fBcommands\fR: Creating Fisherman Commands
.
.br
fisher help \fBfishfile\fR: Fishfile Format
.
.br
.
.SS "What are Fisherman plugins?"
Plugins are written in fish and extend the shell core functionality, run initialization code, add completions or documentations to other commands, etc\. See \fBfisher help plugins\fR\.
@ -50,7 +70,7 @@ There is no technical distinction between plugins, themes, commands, etc\., but
.P
See \fBfisher help plugins\fR and \fBfisher help commands\fR\.
.
.SS "Does Fisherman support oh\-my\-fish plugins and themes?"
.SS "Does Fisherman support Oh My Fish plugins and themes?"
Yes\. To install either a plugin or theme use their URL:
.
.IP "" 4
@ -87,19 +107,19 @@ end
.P
See \fB$fisher_home/config\.fish\fR for the full code\.
.
.SS "How is Fisherman faster than oh\-my\-fish/Wahoo, etc?"
.SS "How is Fisherman faster than Oh My Fish and other systems?"
Fisherman ameliorates the slow shell start problem using a flat dependency tree instead of loading a directory hierarchy per plugin\. This also means that Fisherman performance does not decline depending on the number of plugins installed\. See also \fBFlat Tree\fR in \fBfisher help tour\fR\.
.
.SS "Why don\'t you contribute your improvements back to oh\-my\-fish instead of creating a new project?"
I have contributed back to oh\-my\-fish extensively\. See also oh\-my\-fish history for August 27, 2015 when another project, Wahoo, was entirely merged with oh\-my\-fish\.
.SS "Why don\'t you contribute your improvements back to Oh My Fish?"
I have contributed back to Oh My Fish extensively\. See also Oh My Fish history for August 27, 2015 when another project, Wahoo, was entirely merged with Oh My Fish\.
.
.P
In addition, Fisherman was built from the ground up using a completely different design, implementation and set of principles\.
.
.P
Some features include: UNIX familiarity, minimalistic design, flat tree structure, unified plugin architecture, external self\-managed database, cache system, dependency manifest file and compatibility with oh\-my\-fish, etc\. See \fBfisher help tour\fR\.
Some features include: UNIX familiarity, minimalistic design, flat tree structure, unified plugin architecture, external self\-managed database, cache system, dependency manifest file and compatibility with Oh My Fish, etc\. See \fBfisher help tour\fR\.
.
.SS "How can I upgrade from an existing oh\-my\-fish or Wahoo installation?"
.SS "How can I upgrade from an existing Oh My Fish or Wahoo installation?"
Install Fisherman\.
.
.IP "" 4
@ -115,7 +135,7 @@ make
.IP "" 0
.
.P
You can now safely remove oh\-my\-fish \fB$OMF_PATH\fR and \fB$OMF_CONFIG\fR\.
You can now safely remove Oh My Fish \fB$OMF_PATH\fR and \fB$OMF_CONFIG\fR\.
.
.P
Backup dotfiles and other sensitive data first\.
@ -185,5 +205,5 @@ chsh \-s /bin/another/shell
.
.IP "" 0
.
.SS "Why is this FAQ similar to the oh\-my\-fish FAQ?"
.SS "Why is this FAQ similar to the Oh My Fish FAQ?"
Because it was written by the same author of Fisherman and Wahoo and some of the questions and answers simply overlap\.

@ -13,12 +13,19 @@ Fisherman is a plugin manager for fish that lets you share and reuse code, promp
### What do I need to know to use Fisherman?
Nothing. You can continue using your shell as usual. When you are ready to learn more just type `man fisher` or `man 7 fisher`.
Nothing. You can continue using your shell as usual. When you are ready to learn more just type `fisher help` or `fisher help tour`.
### How do I access other Fisherman documentation?
### How do I access the documentation?
Fisherman documentation is based in UNIX `man(1)` pages. See `man fisher` and `man 7 fisher` to get started. You can also access any documentation using the `fisher help` command.
Fisherman documentation is based in UNIX `man(1)` pages. For basic usage and command enter `fisher help`. For help about a specific *command*, enter `fisher help <command>`. The following guides are also available:
fisher help `faq`: Fisherman FAQ<br>
fisher help `tour`: Fisherman Tour<br>
fisher help `config`: Fisherman Configuration<br>
fisher help `plugins`: Creating Fisherman Plugins<br>
fisher help `commands`: Creating Fisherman Commands<br>
fisher help `fishfile`: Fishfile Format<br>
### What are Fisherman plugins?
@ -50,7 +57,7 @@ There is no technical distinction between plugins, themes, commands, etc., but t
See `fisher help plugins` and `fisher help commands`.
### Does Fisherman support oh-my-fish plugins and themes?
### Does Fisherman support Oh My Fish plugins and themes?
Yes. To install either a plugin or theme use their URL:
@ -77,20 +84,20 @@ end
See `$fisher_home/config.fish` for the full code.
### How is Fisherman faster than oh-my-fish/Wahoo, etc?
### How is Fisherman faster than Oh My Fish and other systems?
Fisherman ameliorates the slow shell start problem using a flat dependency tree instead of loading a directory hierarchy per plugin. This also means that Fisherman performance does not decline depending on the number of plugins installed. See also `Flat Tree` in `fisher help tour`.
### Why don't you contribute your improvements back to oh-my-fish instead of creating a new project?
### Why don't you contribute your improvements back to Oh My Fish?
I have contributed back to oh-my-fish extensively. See also oh-my-fish history for August 27, 2015 when another project, Wahoo, was entirely merged with oh-my-fish.
I have contributed back to Oh My Fish extensively. See also Oh My Fish history for August 27, 2015 when another project, Wahoo, was entirely merged with Oh My Fish.
In addition, Fisherman was built from the ground up using a completely different design, implementation and set of principles.
Some features include: UNIX familiarity, minimalistic design, flat tree structure, unified plugin architecture, external self-managed database, cache system, dependency manifest file and compatibility with oh-my-fish, etc. See `fisher help tour`.
Some features include: UNIX familiarity, minimalistic design, flat tree structure, unified plugin architecture, external self-managed database, cache system, dependency manifest file and compatibility with Oh My Fish, etc. See `fisher help tour`.
### How can I upgrade from an existing oh-my-fish or Wahoo installation?
### How can I upgrade from an existing Oh My Fish or Wahoo installation?
Install Fisherman.
@ -100,7 +107,7 @@ cd fisherman
make
```
You can now safely remove oh-my-fish `$OMF_PATH` and `$OMF_CONFIG`.
You can now safely remove Oh My Fish `$OMF_PATH` and `$OMF_CONFIG`.
Backup dotfiles and other sensitive data first.
@ -141,6 +148,6 @@ chsh -s /bin/another/shell
```
### Why is this FAQ similar to the oh-my-fish FAQ?
### Why is this FAQ similar to the Oh My Fish FAQ?
Because it was written by the same author of Fisherman and Wahoo and some of the questions and answers simply overlap.

@ -1,346 +0,0 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "FISHER\-FEATURES" "7" "January 2016" "" "fisherman"
.
.SH "NAME"
\fBfisher\-features\fR \- Fisherman Features
.
.SH "DESCRIPTION"
Fisherman is a plugin manager for \fBfish(1)\fR that lets you share and reuse code, prompts and configurations easily\.
.
.P
The main features are a minimalistic design, flat tree structure, unified plugin architecture, external self\-managed database, cache system, dependency manifest file and compatibility with oh\-my\-fish, Tackle and Wahoo plugins, themes and modules\.
.
.P
This document describes Fisherman features and their implementation details\. For usage and command help see \fBfisher(1)\fR\. For a general introduction to Fisherman see \fBfisher help tour\fR\.
.
.SH "FLAT TREE"
The configuration directory structure is optimized to help fish start new sessions as quickly as possible, regardless of the numbers of plugins or prompts enabled at any given time\.
.
.P
To explain how this is possible, we need to make a digression and discuss function scope first\. In fish, all functions share the same scope and you can use only one name per function\.
.
.P
In the following example:
.
.IP "" 4
.
.nf
function foo
echo $_
function bar
end
end
function bar
echo $_
end
.
.fi
.
.IP "" 0
.
.P
\fIfoo\fR and \fIbar\fR are available immediately at the command line prompt and both print their names\. But there is a catch, calling \fIfoo\fR at least once will create a new \fIbar\fR function, effectively erasing the previous \fIbar\fR definition\. Subsequent calls to \fIbar\fR will print nothing\.
.
.P
By convention, functions that start with any number of underscores are \fIintentionally\fR private, but there is no mechanism that prevents you from calling them at any time once loaded\.
.
.P
With this in mind, it\'s possible to improve the slow shell start problem using a \fIflat\fR tree structure whose path is loaded only once\.
.
.P
The overhead of juggling multiple path hierarchies in a per\-plugin basis yields no benefits as everything is shared in the same scope\.
.
.P
Loading a path simply means adding the desired location to the \fB$fish_function_path\fR array\. See also \fBfunctions(1)\fR\.
.
.P
Here is a snapshot of a typical configuration path with a single plugin and prompt:
.
.IP "" 4
.
.nf
$fisher_config
|\-\- cache/
|\-\- conf\.d/
|\-\- |\-\- my_plugin\.config\.fish
|\-\- functions/
| |\-\- my_plugin\.fish
| |\-\- fish_prompt\.fish
| |\-\- fish_right_prompt\.fish
|\-\- completions/
| |\-\- my_plugin\.fish
|\-\- man/
|\-\- man1/
|\-\- my_plugin\.1
.
.fi
.
.IP "" 0
.
.P
If you are already familiar in the way fish handles your user configuration, you will find the above structure similar to \fB$XDG_CONFIG_HOME/fish\fR\. See \fBInitialization Files\fR in \fBhelp fish\fR to learn more about fish configuration\.
.
.P
\fBconf\.d\fR, short for configuration directory, is used for initialization files, i\.e\., files that should run at the start of the shell\. Files that follow the naming convention \fB<name>\.config\.fish\fR are added there\.
.
.SS "PLUGINS"
Plugins are components that extend and add features to your shell\. To see what plugins are available use \fBfisher search\fR\. You can also type \fBfisher install\fR and hit \fItab\fR once to get full name completions and plugin information\. The same works for \fBfisher update\fR and \fBfisher uninstall\fR\.
.
.P
To learn how to create plugins, see \fBfisher help plugins\fR\.
.
.P
To install a plugin, you can use their \fIname\fR if they are listed in \fB$fisher_index\fR\.
.
.IP "" 4
.
.nf
fisher install shark
.
.fi
.
.IP "" 0
.
.P
Otherwise, you can use the repository remote \fIURL\fR\.
.
.IP "" 4
.
.nf
fisher install simnalamburt/shellder
.
.fi
.
.IP "" 0
.
.P
If the domain or host is not provided, Fisherman will use any value in \fB$fisher_default_host\fR\. The default value is \fBhttps://github\.com\fR\.
.
.P
In addition, all of the following \fBowner/repo\fR variations are accepted:
.
.IP "\(bu" 4
owner/repo \fB>\fR https://github\.com/owner/repo
.
.br
.
.IP "\(bu" 4
\fIgithub\fR/owner/repo \fB>\fR https://github\.com/owner/repo
.
.br
.
.IP "\(bu" 4
\fIgh\fR/owner/repo \fB>\fR https://github\.com/owner/repo
.
.br
.
.IP "" 0
.
.P
Shortcuts to other common Git repository hosting services are also available:
.
.IP "\(bu" 4
\fIbb\fR/owner/repo \fB>\fR https://bitbucket\.org/owner/repo
.
.br
.
.IP "\(bu" 4
\fIgl\fR/owner/repo \fB>\fR https://gitlab\.com/owner/repo
.
.br
.
.IP "\(bu" 4
\fIomf\fR/owner/repo \fB>\fR https://github\.com/oh\-my\-fish/repo
.
.br
.
.IP "" 0
.
.P
Because of Fisherman\'s flat tree model, there is no technical distinction between plugins or prompts\. Installing a prompt is equivalent to switching themes in other systems\. The interface is always \fIinstall\fR, \fIupdate\fR or \fIuninstall\fR\.
.
.P
Throughout this document and other Fisherman manuals you will find the term prompt when referring to the \fIconcept\fR of a theme, i\.e\., a plugin that defines a \fBfish_prompt\fR and / or \fBfish_right_prompt\fR functions\.
.
.SS "INDEX"
You can install, update and uninstall plugins by name, querying the Fisherman index, or by URL using several of the variations described in \fBPlugins\fR\. The index is a plain text flat database \fIindependent\fR from Fisherman\. You can use a custom index file by setting \fB$fisher_index\fR to your own file or URL\. Redirection urls are not supported due to security and performance concerns\. See \fBfisher help config\fR\.
.
.P
A copy of the index is downloaded each time a query happens\. This keeps the index up to date and allows you to search the database offline\.
.
.P
The index is a list of records, each consisting of the following fields:
.
.IP "\(bu" 4
\fBname\fR, \fBurl\fR, \fBinfo\fR, \fBauthor\fR and one or more \fBtags\fR\.
.
.IP "" 0
.
.P
Fields are separated by a new line \fB\'\en\'\fR\. Tags are separated by one \fIspace\fR\. Here is a sample record:
.
.IP "" 4
.
.nf
shark
https://github\.com/bucaran/shark
Sparklines for your Fish
graph spark data
bucaran
.
.fi
.
.IP "" 0
.
.P
To submit a new plugin for registration install the \fBsubmit\fR plugin:
.
.IP "" 4
.
.nf
fisher install submit
.
.fi
.
.IP "" 0
.
.P
For usage see the bundled documentation \fBfisher help submit\fR\.
.
.P
You can also submit a new plugin manually and create a pull request\.
.
.IP "" 4
.
.nf
git clone https://github\.com/fisherman/fisher\-index
cd index
echo "$name\en$URL\en$info\en$author\en$tags\en\en" >> index
git push origin master
open http://github\.com
.
.fi
.
.IP "" 0
.
.P
Now you can create a new pull request in the upstream repository\.
.
.SS "CACHE"
Downloaded plugins are tracked as Git repositories under \fB$fisher_cache\fR\. See \fBfisher help config\fR to find out about other Fisherman configuration variables\.
.
.P
When you install or uninstall a plugin, Fisherman downloads the repository to the cache and copies only the relevant files from the cache to the loaded function and / or completion path\. In addition, man pages are added to the corresponding man directory and if a Makefile is detected, the command \fBmake\fR is run\.
.
.P
The cache also provides a location for a local copy of the Index\.
.
.SS "FISHFILES"
Dependency manifest file, or fishfiles for short, let you share plugin configurations across multiple installations, allow plugins to declare dependencies, and prevent information loss in case of system failure\. See \fBfisher help fishfile\fR\.
.
.P
Here is an example fishfile inside \fB$fisher_config\fR:
.
.IP "" 4
.
.nf
# my plugins
gitio
fishtape
# my links
github/bucaran/shark
.
.fi
.
.IP "" 0
.
.P
The fishfile updates as you install / uninstall plugins\. See also \fBfisher help install\fR or \fBfisher help uninstall\fR\.
.
.P
Plugins may list any number of dependencies to other plugins in a fishfile at the root of each project\. By default, when Fisherman installs a plugin, it will also fetch and install its dependencies\. If a dependency is already installed, it will not be updated as this could potentially break other plugins using an older version\. For the same reasons, uninstalling a plugin does not remove its dependencies\. See \fBfisher help update\fR\.
.
.SS "CONFIGURATION"
Fisherman allows a high level of configuration using \fB$fisher_*\fR variables\. You can customize the home and configuration directories, debug log file, cache location, index source URL, command aliases, etc\. See \fBfisher help config\fR\.
.
.P
You can also extend Fisherman by adding new commands and ship them as plugins as well\. Fisherman automatically adds completions to \fIcommands\fR based in the function \fIdescription\fR and usage help if provided\. See \fBfisher help help\fR and \fBfisher help commands\fR\.
.
.P
To add completions to standalone utility plugins, use \fBcomplete(1)\fR\.
.
.SS "CLI"
If you are already familiar with other UNIX tools, you\'ll find Fisherman commands behave intuitively\.
.
.P
Most commands read the standard input by default when no options are given and produce easy to parse output, making Fisherman commands ideal for plumbing and building upon each other\.
.
.P
Fisherman also ships with a CLI options parser and a background job wait spinner that you can use to implement your own commands CLI\. See \fBgetopts(1)\fR and \fBwait(1)\fR\.
.
.SH "COMPATIBILITY"
Fisherman supports oh\-my\-fish (Wahoo) themes and plugins by default, but some features are turned off due to performance considerations\.
.
.P
oh\-my\-fish evaluates every \fI\.fish\fR file inside the root directory of every plugin during initialization\. This is necessary in order to register any existing \fBinit\fR events and invoke them using fish \fBemit(1)\fR\.
.
.P
Since it is not possible to determine whether a file defines an initialization event without evaluating its contents first, oh\-my\-fish sources all \fB*\.fish\fR files and then emits events for each plugin\.
.
.P
Not all plugins opt in the initialization mechanism, therefore support for this behavior is turned off by default\. If you would like Fisherman to behave like oh\-my\-fish at the start of every session, install the \fBomf\fR compatibility plugin\.
.
.IP "" 4
.
.nf
fisher install omf
.
.fi
.
.IP "" 0
.
.P
This plugin also adds definitions for some of oh\-my\-fish Core Library functions\.
.
.SH "SEE ALSO"
fisher(1)
.
.br
fisher help
.
.br
fisher help config
.
.br
fisher help plugins
.
.br
fisher help commands
.
.br
wait(1)
.
.br
getopts(1)
.
.br

@ -4,7 +4,7 @@
.TH "FISHER\-TOUR" "7" "January 2016" "" "fisherman"
.
.SH "NAME"
\fBfisher\-tour\fR \- Fisherman Feature Tour
\fBfisher\-tour\fR \- Fisherman Tour
.
.SH "DESCRIPTION"
Fisherman is a plugin manager and CLI toolkit for Fish to help you build powerful utilities and share your code easily\.
@ -127,7 +127,7 @@ fisher install simnalamburt/shellder
.IP "" 0
.
.P
If the domain or host is not provided, Fisherman will use any value in \fB$fisher_default_host\fR to guess the full URL\. The default value is \fBhttps://github\.com\fR\.
If the domain or host is not provided, Fisherman will use \fBhttps://github\.com\fR by default\.
.
.P
In addition, all of the following \fBowner/repo\fR variations are accepted:

@ -1,5 +1,5 @@
fisher-tour(7) -- Fisherman Feature Tour
========================================
fisher-tour(7) -- Fisherman Tour
================================
## DESCRIPTION
@ -81,7 +81,7 @@ You can use an URL too if you have one.
fisher install simnalamburt/shellder
```
If the domain or host is not provided, Fisherman will use any value in `$fisher_default_host` to guess the full URL. The default value is `https://github.com`.
If the domain or host is not provided, Fisherman will use `https://github.com` by default.
In addition, all of the following `owner/repo` variations are accepted:

@ -1,42 +0,0 @@
{
"name": "fisherman",
"version": "0.4.0",
"description": "fish plugin manager",
"main": "index.js",
"directories": {
"man": "man",
"test": "test"
},
"scripts": {
"install": "make",
"test": "make test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/fisherman/fisherman.git"
},
"keywords": [
"fish-shell",
"shell",
"fisherman",
"theme",
"prompt",
"shell",
"manager",
"package",
"package manager",
"git",
"framework",
"fast",
"light",
"pretty",
"minimal"
],
"author": "Jorge Bucaran",
"license": "MIT",
"bugs": {
"url": "https://github.com/fisherman/fisherman/issues"
},
"homepage": "https://github.com/fisherman/fisherman#readme",
"dependencies": {}
}

@ -0,0 +1,24 @@
set -l path $DIRNAME/.t-$TESTNAME-(random)
function -S setup
mkdir -p $path/cache/{foo,bar,baz} $path/norf
ln -s $path/norf $path/cache/norf
set -g fisher_cache $path/cache
end
function -S teardown
rm -rf $path
end
test "$TESTNAME - Follow symbolic links"
(contains -- norf (__fisher_cache_list); echo $status) -eq 0
end
test "$TESTNAME - List base name of each plugin inside the cache"
(__fisher_cache_list) = (
for plugin in $fisher_cache/*
basename $plugin
end
)
end

@ -0,0 +1,25 @@
set -l path $DIRNAME/.t-$TESTNAME-(random)
function -S setup
mkdir -p $path/completions
echo "echo ok" > $path/completions/fisher.fish
set -g fisher_home $path
function complete
echo $argv
end
end
function -S teardown
rm -rf $path
functions -e complete
end
test "$TESTNAME - Remove Fisherman completions"
(__fisher_complete_reset | sed -n 1p) = "-ec fisher"
end
test "$TESTNAME - Evaluate completions/fisher.fish"
(__fisher_complete_reset | sed -n 2p) = "ok"
end

@ -0,0 +1,27 @@
function -S setup
function complete
echo $argv
end
function foo
echo "-f --foo Foo!"
end
function bar
echo "--bar Bar!"
end
end
function -S teardown
functions -e complete foo bar
end
test "$TESTNAME - Complete short / long options with description"
(foo | __fisher_complete norf quux
) = "-c norf -s f -l foo -d Foo! -n __fish_seen_subcommand_from quux"
end
test "$TESTNAME - Complete long options with description"
(bar | __fisher_complete norf quux
) = "-c norf -s -l bar -d Bar! -n __fish_seen_subcommand_from quux"
end

@ -0,0 +1,43 @@
set -l path $DIRNAME/.t-$TESTNAME-(random)
function -S setup
mkdir -p $path/conf.d
echo "echo foo" > $path/conf.d/foo.fish
set -g fisher_config $path
source $fisher_home/config.fish > /dev/null
end
function -S teardown
rm -rf $path
end
test "$TESTNAME - Do not redefine \$fisher_config"
$fisher_config = $path
end
test "$TESTNAME - Define cache in \$fisher_config/cache (default)"
$fisher_cache = $path/cache
end
test "$TESTNAME - Define fishfile in \$fisher_config/fishfile (default)"
$fisher_file = $path/fishfile
end
test "$TESTNAME - Define key bindings in \$fisher_config/key_bindings.fish (default)"
$fisher_key_bindings = $path/key_bindings.fish
end
test "$TESTNAME - Add Fisherman config/functions to the head of \$fish_function_path"
$path/functions = $fish_function_path[1]
end
test "$TESTNAME - Add Fisherman config/completions to the head of \$fish_complete_path"
$path/completions = $fish_complete_path
end
test "$TESTNAME - Evaluate any <*.fish> files inside conf.d during shell start"
foo = (source $fisher_home/config.fish)
end

@ -0,0 +1,39 @@
set -l path $DIRNAME/.t-$TESTNAME-(random)
function -S setup
mkdir -p $path $path/void
printf "%s\n" foo bar > $path/bundle
printf "%s\n" baz norf > $path/fishfile
function fisher_install
set -l count 0
while read -l plugin
# Fisherman CLI text message are usually written to /dev/stderr,
# so we must write to /dev/stderr too.
echo $plugin > /dev/stderr
set count (math $count + 1)
end
echo "$count plugin/s" > /dev/stderr
end
end
function -S teardown
rm -rf $path
functions -e fisher_install
end
test "$TESTNAME - List dependencies to be installed"
(__fisher_deps_install $path > /dev/null ^| sed -E 's/.*>> (.*)/\1/') = "(foo bar baz norf)"
end
test "$TESTNAME - Install dependencies from one or more bundle/fishfile files"
(__fisher_deps_install $path ^ /dev/null) = 04
end
test "$TESTNAME - Fail to indicate no dependencies were installed"
(__fisher_deps_install $path/void) = 0
end

@ -0,0 +1,7 @@
set -l manifest $DIRNAME/fixtures/manifest
while read -l plugin
test "$TESTNAME - Check if plugin <$plugin> exists in fishfile"
(__fisher_file_contains "$plugin" < $manifest/fishfile) = "$plugin"
end
end < $manifest/fishfile-no-comments

@ -0,0 +1,17 @@
set -l path $DIRNAME/.t-$TESTNAME-(random)
set -l manifest $DIRNAME/fixtures/manifest
function -S setup
mkdir -p $path
cp $manifest/fishfile $path
end
function -S teardown
rm -rf $path
end
while read -l plugin
test "$TESTNAME - Remove plugin <$plugin> from fishfile"
(__fisher_file_remove "$plugin" $path/fishfile) = "$plugin"
end
end < $manifest/fishfile-no-comments

@ -0,0 +1,15 @@
set -l path $DIRNAME/.t-$TESTNAME-(random)
set -l manifest $DIRNAME/fixtures/manifest
# __fisher_file parses a fishfile/bundle and writes declared plugins to standard out.
# URLs and paths are returned *as is*. To retrieve the plugin names use fisher --list
# See also `list-fishfile.fish`.
test "$TESTNAME - Parse a fishfile/bundle #1"
(__fisher_file < $manifest/fishfile) = (cat $manifest/fishfile-parsed)
end
test "$TESTNAME - Parse a fishfile/bundle #2"
(__fisher_file < $manifest/fishfile-parsed) = (cat $manifest/fishfile-parsed)
end

@ -1,10 +1,9 @@
set -l cmd awk
set -l fishfile $DIRNAME/fixtures/fishfile
set -l mock_command awk
function -S setup
set -g fisher_alias "$cmd=A,B"
set -g fisher_alias "$mock_command=A,B"
function fisher_$cmd
function fisher_$mock_command
if not set -q argv[1]
echo usage:...
return 1
@ -14,44 +13,33 @@ function -S setup
end
function -S teardown
functions -e fisher_$cmd
functions -e fisher_$mock_command
end
test "read a fishfile using --file"
(fisher --file=$fishfile) = foo bar baz github/foo/bar
test "$TESTNAME - Evaluate `fisher_' (sub) commands"
(fisher $mock_command) = usage:...
end
test "fisher --list retrieves plugin names in the cache"
(fisher --list) = (
for file in $fisher_cache/*
basename $file
end)
test "$TESTNAME - Commands can read standard input"
(echo "foo bar baz" | fisher $mock_command '{ print $2 }' | xargs) = "bar"
end
test "evaluate commands"
(fisher $cmd) = usage:...
end
test "evaluate commands w/ standard input"
(echo "foo bar baz" | fisher $cmd '{ print $2 }' | xargs) = "bar"
end
test "display version information"
test "$TESTNAME - Display version information"
(fisher --version | cut -d " " -f3) = (sed 1q $fisher_home/VERSION)
end
test "evaluate \$fisher_alias=<command=alias[,...]> as aliases"
(fisher A; fisher B) = (fisher $cmd; fisher $cmd)
test "$TESTNAME - Handle \$fisher_alias aliases"
(fisher A; fisher B) = (fisher $mock_command; fisher $mock_command)
end
test "display usage"
(fisher | sed 1q) = "usage: fisher <command> [<options>] [--version] [--help]"
test "$TESTNAME - Display usage help"
(fisher | sed 1q) = "usage: fisher <command> [<args>] [--list] [--version] [--help]"
end
test "display help information about 'help' at the bottom"
test "$TESTNAME - Display basic information about using the `help' command by default"
(fisher | tail -n2 | xargs) = "Use fisher help -g to list guides and other documentation. See fisher help <command or concept> to access a man page."
end
test "display basic help information about available commands"
(fisher | sed -E 's/ +//' | grep "^$cmd\$")
test "$TESTNAME - Display basic information about available commands"
(fisher | sed -E 's/ +//' | grep "^$mock_command\$")
end

@ -1,8 +0,0 @@
# fishfile example
###################
foo
bar
package baz # omf
# comment
# comment
github/foo/bar

@ -0,0 +1,27 @@
usage: fisher update [<plugins>] [--quiet] [--help]
-q --quiet Enable quiet mode
-h --help Show usage help
usage: fisher uninstall [<plugins>] [--force] [--quiet] [--help]
-f --force Delete copy from cache
-q --quiet Enable quiet mode
-h --help Show usage help
usage: fisher search [<plugins>] [--and|--or] [--quiet] [--help]
*--<field> 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
usage: fisher install [<plugins>] [--force] [--quiet] [--help]
-f --force Reinstall given plugin/s
-q --quiet Enable quiet mode
-h --help Show usage help
usage: fisher help [<keyword>] [--all] [--guides] [--help]
-a --all List available documentation
-g --guides List available guides
-u --usage[=<cmd>] Display command usage
-h --help Show usage help

@ -0,0 +1,4 @@
function fish_user_key_bindings
# Comment
# User Custom Code
end

@ -0,0 +1,2 @@
bind -e foo
bind -e bar

@ -0,0 +1,6 @@
##foo##
echo bind foo
##foo##
##bar##
echo bind bar
##bar##

@ -0,0 +1,5 @@
function fish_user_key_bindings
# 1
__fisher_key_bindings
# 2
end

@ -0,0 +1,2 @@
function fish_user_key_bindings
end

@ -0,0 +1,5 @@
function fish_user_key_bindings
foo
bar
baz
end

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save