summaryrefslogtreecommitdiffstats
path: root/ms/reqCA.ss
blob: 1f7138cadcca6ae95e5adaf99b3012006d743d75 (plain)
1
2
3
4
5
6
7
8
-----BEGIN CERTIFICATE REQUEST-----
MIHzMIGeAgEAMDkxCzAJBgNVBAYTAkFVMRcwFQYDVQQKEw5Eb2RneSBCcm90aGVy
czERMA8GA1UEAxMIRG9kZ3kgQ0EwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA0DQL
enM/ncK6CwSEJhOO1WfZUPUEi4pvos9fHW459jh3rRDADgi3fiCYxoRVSQhvB47k
DZ3ViNg5yrDhy7F9ywIDAQABoAAwDQYJKoZIhvcNAQEFBQADQQA5DZSZgDXs8flG
GZf4SGr8QpqkxSu9bZOYp/ySuz1khj7aupBrvZBmqZcZx4ZjAUN7UQpMWu2gyfKa
mAiiLPFN
-----END CERTIFICATE REQUEST-----
f='#n178'>178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
# -*- coding: utf-8 -*-
# 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
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""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 added via the `-e` / `--extravalues` flag. For example:
`beet fish -e genre -e albumartist`
"""

from __future__ import division, absolute_import, print_function

from beets.plugins import BeetsPlugin
from beets import library, ui
from beets.ui import commands
from operator import attrgetter
import os
BL_NEED2 = """complete -c beet -n '__fish_beet_needs_command' {} {}\n"""
BL_USE3 = """complete -c beet -n '__fish_beet_using_command {}' {} {}\n"""
BL_SUBS = """complete -c beet -n '__fish_at_level {} ""' {}  {}\n"""
BL_EXTRA3 = """complete -c beet -n '__fish_beet_use_extra {}' {} {}\n"""

HEAD = '''
function __fish_beet_needs_command
    set cmd (commandline -opc)
    if test (count $cmd) -eq 1
        return 0
    end
    return 1
end

function __fish_beet_using_command
    set cmd (commandline -opc)
    set needle (count $cmd)
    if test $needle -gt 1
        if begin test $argv[1] = $cmd[2];
            and not contains -- $cmd[$needle] $FIELDS; end
                return 0
        end
    end
    return 1
end

function __fish_beet_use_extra
    set cmd (commandline -opc)
    set needle (count $cmd)
    if test $argv[2]  = $cmd[$needle]
        return 0
    end
    return 1
end
'''


class FishPlugin(BeetsPlugin):

    def commands(self):
        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='omit album/track field completions')
        cmd.parser.add_option(
            '-e',
            '--extravalues',
            action='append',
            type='choice',
            choices=library.Item.all_keys() +
            library.Album.all_keys(),
            help='include specified field *values* in completions')
        return [cmd]

    def run(self, lib, opts, args):
        # 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.
        home_dir = os.path.expanduser("~")
        completion_dir = os.path.join(home_dir, '.config/fish/completions')
        try:
            os.makedirs(completion_dir)
        except OSError:
            if not os.path.isdir(completion_dir):
                raise
        completion_file_path = os.path.join(completion_dir, 'beet.fish')
        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 commands, their aliases, and their help text
        cmd_names_help = []
        for cmd in beetcmds:
            names = [alias for alias in cmd.aliases]
            names.append(cmd.name)
            for name in names:
                cmd_names_help.append((name, cmd.help))
        # 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)
        totstring += get_extravalues(lib, extravalues) if extravalues else ''
        totstring += "\n" + "# ====== {} =====".format(
            "setup basic beet completion") + "\n" * 2
        totstring += get_basic_beet_options()
        totstring += "\n" + "# ====== {} =====".format(
            "setup field completion for subcommands") + "\n"
        totstring += get_subcommands(
            cmd_names_help, nobasicfields, extravalues)
        # Set up completion for all the command options
        totstring += get_all_commands(beetcmds)

        with open(completion_file_path, 'w') as fish_file:
            fish_file.write(totstring)


def _escape(name):
    # Escape ? in fish
    if name == "?":
        name = "\\" + name
    return name


def get_cmds_list(cmds_names):
    # Make a list of all Beets core & plugin commands
    substr = ''
    substr += (
        "set CMDS " + " ".join(cmds_names) + ("\n" * 2)
    )
    return substr


def get_standard_fields(fields):
    # Make a list of album/track fields and append with ':'
    fields = (field + ":" for field in fields)
    substr = ''
    substr += (
        "set FIELDS " + " ".join(fields) + ("\n" * 2)
    )
    return substr


def get_extravalues(lib, extravalues):
    # Make a list of all values from an album/track field.
    # 'beet ls albumartist: <TAB>' yields completions for ABBA, Beatles, etc.
    word = ''
    values_set = get_set_of_values_for_field(lib, extravalues)
    for fld in extravalues:
        extraname = fld.upper() + 'S'
        word += (
            "set  " + extraname + " " + " ".join(sorted(values_set[fld]))
            + ("\n" * 2)
        )
    return word


def get_set_of_values_for_field(lib, fields):
    # Get unique values from a specified album/track field
    fields_dict = {}
    for each in fields:
        fields_dict[each] = set()
    for item in lib.items():
        for field in fields:
            fields_dict[field].add(wrap(item[field]))
    return fields_dict


def get_basic_beet_options():
    word = (
        BL_NEED2.format("-l format-item",
                        "-f -d 'print with custom format'") +
        BL_NEED2.format("-l format-album",
                        "-f -d 'print with custom format'") +
        BL_NEED2.format("-s  l  -l library",
                        "-f -r -d 'library database file to use'") +
        BL_NEED2.format("-s  d  -l directory",
                        "-f -r -d 'destination music directory'") +
        BL_NEED2.format("-s  v  -l verbose",
                        "-f -d 'print debugging information'") +

        BL_NEED2.format("-s  c  -l config",
                        "-f -r -d 'path to configuration file'") +
        BL_NEED2.format("-s  h  -l help",
                        "-f -d 'print this help message and exit'"))
    return word


def get_subcommands(cmd_name_and_help, nobasicfields, extravalues):
    # Formatting for Fish to complete our fields/values
    word = ""
    for cmdname, cmdhelp in cmd_name_and_help:
        cmdname = _escape(cmdname)

        word += "\n" + "# ------ {} -------".format(
            "fieldsetups for  " + cmdname) + "\n"
        word += (
            BL_NEED2.format(
                ("-a " + cmdname),
                ("-f " + "-d " + wrap(clean_whitespace(cmdhelp)))))

        if nobasicfields is False:
            word += (
                BL_USE3.format(
                    cmdname,
                    ("-a " + wrap("$FIELDS")),
                    ("-f " + "-d " + wrap("fieldname"))))

        if extravalues:
            for f in extravalues:
                setvar = wrap("$" + f.upper() + "S")
                word += " ".join(BL_EXTRA3.format(
                    (cmdname + " " + f + ":"),
                    ('-f ' + '-A ' + '-a ' + setvar),
                    ('-d ' + wrap(f))).split()) + "\n"
    return word


def get_all_commands(beetcmds):
    # Formatting for Fish to complete command options
    word = ""
    for cmd in beetcmds:
        names = [alias for alias in cmd.aliases]
        names.append(cmd.name)
        for name in names:
            name = _escape(name)

            word += "\n"
            word += ("\n" * 2) + "# ====== {} =====".format(
                "completions for  " + name) + "\n"

            for option in cmd.parser._get_all_options()[1:]:
                cmd_l = (" -l " + option._long_opts[0].replace('--', '')
                         )if option._long_opts else ''
                cmd_s = (" -s " + option._short_opts[0].replace('-', '')
                         ) if option._short_opts else ''
                cmd_need_arg = ' -r ' if option.nargs in [1] else ''
                cmd_helpstr = (" -d " + wrap(' '.join(option.help.split()))
                               ) if option.help else ''
                cmd_arglist = (' -a ' + wrap(" ".join(option.choices))
                               ) if option.choices else ''

                word += " ".join(BL_USE3.format(
                    name,
                    (cmd_need_arg + cmd_s + cmd_l + " -f " + cmd_arglist),
                    cmd_helpstr).split()) + "\n"

            word = (word + " ".join(BL_USE3.format(
                name,
                ("-s " + "h " + "-l " + "help" + " -f "),
                ('-d ' + wrap("print help") + "\n")
            ).split()))
    return word


def clean_whitespace(word):
    # 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
    sptoken = '\"'
    if ('"') in word and ("'") in word:
        word.replace('"', sptoken)
        return '"' + word + '"'

    tok = '"' if "'" in word else "'"
    return tok + word + tok