Rewrite Fish completion plugin docs & code comments

This commit is contained in:
Justin Mayer 2020-03-02 13:52:35 +01:00
parent d2d2b646c1
commit 82c3867fc0
2 changed files with 74 additions and 63 deletions

View file

@ -1,5 +1,6 @@
# This file is part of beets.
# Copyright 2015, winters jean-marie.
# Copyright 2020, Justin Mayer <https://justinmayer.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@ -12,12 +13,13 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""If you use the fish-shell http://fishshell.com/ ... this will do
autocomplete for you. It does the main commands and options for beet
and the plugins.
It gives you all the album and itemfields (like genre, album) but not all the
values for these. It suggest genre: or album: but not genre: Pop..Jazz...Rock
You can get that by specifying ex. --extravalues genre.
"""This plugin generates tab completions for Beets commands for the Fish shell
<https://fishshell.com/>, including completions for Beets commands, plugin
commands, and option flags. Also generated are completions for all the album
and track fields, suggesting for example `genre:` or `album:` when querying the
Beets database. Completions for the *values* of those fields are not generated by
default but can be included via the `-e` or `--extravalues` flag. For example:
`beet fish -e genre -e albumartist`
"""
from __future__ import (division, absolute_import, print_function,
@ -68,11 +70,11 @@ end
class FishPlugin(BeetsPlugin):
def commands(self):
cmd = ui.Subcommand('fish', help='make fish autocomplete beet')
cmd = ui.Subcommand('fish', help='generate Fish shell tab completions')
cmd.func = self.run
cmd.parser.add_option('-f', '--noFields', action='store_true',
default=False,
help='no item/album fields for autocomplete')
help='omit album/track field completions')
cmd.parser.add_option(
'-e',
'--extravalues',
@ -80,15 +82,15 @@ class FishPlugin(BeetsPlugin):
type='choice',
choices=library.Item.all_keys() +
library.Album.all_keys(),
help='pick field, get field-values for autocomplete')
help='include specified field *values* in completions')
return [cmd]
def run(self, lib, opts, args):
# we gather the commands from beet and from the plugins.
# we take the album and item fields.
# it wanted, we take the values from these fields.
# we make a giant string of tehm formatted in a way that
# allows fish to do autocompletion for beet.
# Gather the commands from Beets core and its plugins.
# Collect the album and track fields.
# If specified, also collect the values for these fields.
# Make a giant string of all the above, formatted in a way that
# allows Fish to do tab completion for the `beet` command.
homeDir = os.path.expanduser("~")
completePath = os.path.join(homeDir, '.config/fish/completions')
try:
@ -97,22 +99,22 @@ class FishPlugin(BeetsPlugin):
if not os.path.isdir(completePath):
raise
pathAndFile = os.path.join(completePath, 'beet.fish')
nobasicfields = opts.noFields # do not complete for item/album fields
extravalues = opts.extravalues # ex complete all artist values
nobasicfields = opts.noFields # Do not complete for album/track fields
extravalues = opts.extravalues # e.g., Also complete artists names
beetcmds = sorted(
(commands.default_commands +
commands.plugins.commands()),
key=attrgetter('name'))
fields = sorted(set(
library.Album.all_keys() + library.Item.all_keys()))
# collect cmds and their aliases and their help message
# Collect commands, their aliases, and their help text
cmd_names_help = []
for cmd in beetcmds:
names = ["\?" if alias == "?" else alias for alias in cmd.aliases]
names.append(cmd.name)
for name in names:
cmd_names_help.append((name, cmd.help))
# here we go assembling the string
# Concatenate the string
totstring = HEAD + "\n"
totstring += get_cmds_list([name[0] for name in cmd_names_help])
totstring += '' if nobasicfields else get_standard_fields(fields)
@ -124,7 +126,7 @@ class FishPlugin(BeetsPlugin):
"setup field completion for subcommands") + "\n"
totstring += get_subcommands(
cmd_names_help, nobasicfields, extravalues)
# setup completion for all the command-options
# Set up completion for all the command options
totstring += get_all_commands(beetcmds)
with open(pathAndFile, 'w') as fish_file:
@ -132,7 +134,7 @@ class FishPlugin(BeetsPlugin):
def get_cmds_list(cmds_names):
# make list of all commands in beet&plugins
# Make a list of all Beets core & plugin commands
substr = ''
substr += (
"set CMDS " + " ".join(cmds_names) + ("\n" * 2)
@ -141,7 +143,7 @@ def get_cmds_list(cmds_names):
def get_standard_fields(fields):
# make list of item/album fields & append with ':'
# Make a list of album/track fields and append with ':'
fields = (field + ":" for field in fields)
substr = ''
substr += (
@ -151,8 +153,8 @@ def get_standard_fields(fields):
def get_extravalues(lib, extravalues):
# make list of all values from a item/album field
# so type artist: and get completion for stones, beatles ..
# Make a list of all values from an album/track field.
# 'beet ls albumartist: <TAB>' yields completions for ABBA, Beatles, etc.
word = ''
setOfValues = get_set_of_values_for_field(lib, extravalues)
for fld in extravalues:
@ -165,7 +167,7 @@ def get_extravalues(lib, extravalues):
def get_set_of_values_for_field(lib, fields):
# get the unique values from a item/album field
# Get unique values from a specified album/track field
dictOfFields = {}
for each in fields:
dictOfFields[each] = set()
@ -196,7 +198,7 @@ def get_basic_beet_options():
def get_subcommands(cmd_name_and_help, nobasicfields, extravalues):
# formatting for fish to complete our fields/values
# Formatting for Fish to complete our fields/values
word = ""
for cmdname, cmdhelp in cmd_name_and_help:
word += "\n" + "# ------ {} -------".format(
@ -224,7 +226,7 @@ def get_subcommands(cmd_name_and_help, nobasicfields, extravalues):
def get_all_commands(beetcmds):
# formatting for fish to complete command-options
# Formatting for Fish to complete command options
word = ""
for cmd in beetcmds:
names = ["\?" if alias == "?" else alias for alias in cmd.aliases]
@ -259,12 +261,12 @@ def get_all_commands(beetcmds):
def clean_whitespace(word):
# remove to much whitespace,tabs in string
# Remove excess whitespace and tabs in a string
return " ".join(word.split())
def wrap(word):
# need " or ' around strings but watch out if they're in the string
# Need " or ' around strings but watch out if they're in the string
sptoken = '\"'
if ('"') in word and ("'") in word:
word.replace('"', sptoken)

View file

@ -1,43 +1,52 @@
Fish plugins
============
The ``fish`` plugin adds a ``beet fish`` command that will create a fish
autocompletion file ``beet.fish`` in ``~/.config/fish/completions``
This makes `fish`_ - a different shell - autocomplete commands for beet.
.. _fish: http://fishshell.com/
Configuring
Fish Plugin
===========
This will only make sense if you have the `fish`_ shell installed.
Enable the ``fish`` plugin (see :ref:`using-plugins`).
If you install or disable plugins, run ``beet fish`` again. It takes the values
from the plugins you have enabled.
The ``fish`` plugin adds a ``beet fish`` command that creates a `Fish shell`_
tab-completion file named ``beet.fish`` in ``~/.config/fish/completions``.
This enables tab-completion of ``beet`` commands for the `Fish shell`_.
Using
=====
.. _Fish shell: https://fishshell.com/
Type ``beet fish``. Hit ``enter`` and will see the file ``beet.fish`` appear
in ``.config/fish/completions`` in your home folder.
Configuration
-------------
For a not-fish user: After you type ``beet`` in your fish-prompt and ``TAB``
you will get the autosuggestions for all your plugins/commands and
typing ``-`` will get you all the options available to you.
If you type ``beet ls`` and you ``TAB`` you will get a list of all the album/item
fields that beet offers. Start typing ``genr`` ``TAB`` and fish completes
``genre:`` ... ready to type on...
Enable the ``fish`` plugin (see :ref:`using-plugins`) on a system running the
`Fish shell`_.
Usage
-----
Type ``beet fish`` to generate the ``beet.fish`` completions file at:
``~/.config/fish/completions/``. If you later install or disable plugins, run
``beet fish`` again to update the completions based on the enabled plugins.
For users not accustomed to tab completion… After you type ``beet`` followed by
a space in your shell prompt and then the ``TAB`` key, you should see a list of
the beets commands (and their abbreviated versions) that can be invoked in your
current environment. Similarly, typing ``beet -<TAB>`` will show you all the
option flags available to you, which also applies to subcommands such as
``beet import -<TAB>``. If you type ``beet ls`` followed by a space and then the
and the ``TAB`` key, you will see a list of all the album/track fields that can
be used in beets queries. For example, typing ``beet ls ge<TAB>`` will complete
to ``genre:`` and leave you ready to type the rest of your query.
Options
=======
-------
The default is that you get autocompletion for all the album/item fields.
You can disable that with ``beet fish -f`` In that case you only get all
the plugins/commands/options. Everything else you type in yourself.
If you want completion for a specific album/item field, you can get that like
this ``beet fish -e genre`` or ``beet fish -e genre -e albumartist`` .
Then when you type at your fish-prompt ``beet list genre:`` and you ``TAB``
you will get a list of all your genres to choose from.
REMEMBER : we get all the values of these fields and put them in the completion
file. It is not meant to be a replacement of your database. In other words :
speed and size matters.
In addition to beets commands, plugin commands, and option flags, the generated
completions also include by default all the album/track fields. If you only want
the former and do not want the album/track fields included in the generated
completions, use ``beet fish -f`` to only generate completions for beets/plugin
commands and option flags.
If you want generated completions to also contain album/track field *values* for
the items in your library, you can use the ``-e`` or ``--extravalues`` option.
For example: ``beet fish -e genre`` or ``beet fish -e genre -e albumartist``
In the latter case, subsequently typing ``beet list genre: <TAB>`` will display
a list of all the genres in your library and ``beet list albumartist: <TAB>``
will show a list of the album artists in your library. Keep in mind that all of
these values will be put into the generated completions file, so use this option
with care when specified fields contain a large number of values. Libraries with,
for example, very large numbers of genres/artists may result in higher memory
utilization, completion latency, et cetera. This option is not meant to replace
database queries altogether.