amtoine / nu-git-manager

A collection of Nushell tools to manage Git repositories.
GNU General Public License v3.0
26 stars 2 forks source link

completion support coverage #23

Open amtoine opened 1 year ago

amtoine commented 1 year ago

in the long run, i'd like to have more external and custom completions inside both gm and sugar :+1:

in gm

in sugar

external completions

custom completions

amtoine commented 1 year ago

i've started with the git external completions with the following WIP script :open_mouth:

def extract-subcommand-options [] {
    let command = $in

    let output = (
        do -i { nu -c $"git ($command) -h" }
        | complete
        | reject exit_code  # merge stdout and stderr, e.g. `am` to stderr and `checkout` to stdout
        | transpose key value
        | get value
        | str join
        | lines --skip-empty
        | str trim
        | str replace '^-' "%%-"  # merge the multiline options
        | str join "  "
        | split row "%%"
    )

    {
        usage: ($output | find --invert --regex '^-' | str replace '^usage: ' '' | split row "or:" | str trim)
        options: (
            $output
            | find --regex '^-'  # pick the options only
            | str replace "  " " %% "  # separate the flag and its description
            | split column "%%" option description
            | str trim
        )
    }
}

export def git-commands [] {
    git help -a
    | lines
    | split list ""
    | skip 1
    | each {|section| {
        section: ($section | get 0)
        commands: ($section | skip 1)
    }}
    | where section not-in ["Command aliases" "External commands"]
    | update commands { str trim | parse "{command} {description}" | str trim }
    | flatten --all
    | upsert data {|it|
        print -n $"(ansi erase_line)extracting `git ($it.command)` from (char dq)($it.section)(char dq)\r"
        $it.command | extract-subcommand-options
    }
    | flatten --all
}
def to-nu [--indent: int = 4] {
    str replace '-(.), --([\w-]*)' '--${2} (-${1})' option  # fix the short/long flag format
    | to md --pretty  # convert to md table to have a nice alignment
    | lines
    | skip 2
    | str replace '^\| ' $'(" " * $indent)'  # remove the md table formatting
    | str replace '\s+\|$' ''
    | str replace ' \| ' '  # '
    | to text
}

export def dump [file?: path] {
    let output = (each {|it|
        if ($it.usage | str join | str contains "is not a git command") {
            print $"skipping ($it.command): not a git command"
        } else {
            let options = ($it.options | to-nu --indent 4 | str trim)

            if ($options | is-empty) {
                print $"skipping ($it.command): no option"
            } else {[
                $"# ($it.section)"
                $"#"
                $"# ($it.usage | str join $"\n(char hash)(char space)")"
                $"export extern (char dq)git ($it.command)(char dq) ["
                $"    ($options)"
                $"]"
            ] | str join "\n"}
        }
    } | str join "\n\n")

    if $file != null {
        $output | save --force $file
    } else {
        $output
    }
}

which can be used with

let commands = (git-commands)
$commands | dump commands.nu

and has to be completed with

export extern git [
    --version                     # Prints the Git suite version that the git program came from.
    --help                        # Prints the synopsis and a list of the most commonly used commands.
    -C <path>                     # Run as if git was started in <path> instead of the current working directory.
    -c <name>=<value>             # Pass a configuration parameter to the command. The value given will override values from configuration files.
    --config-env <name>=<envvar>  # Like -c <name>=<value>, give configuration variable <name> a value, where <envvar> is the name of an environment variable from which to retrieve the value.
    --exec-path[=<path>]          # Path to wherever your core Git programs are installed.
    --html-path                   # Print the path, without trailing slash, where Git’s HTML documentation is installed and exit.
    --man-path                    # Print the manpath (see man(1)) for the man pages for this version of Git and exit.
    --info-path                   # Print the path where the Info files documenting this version of Git are installed and exit.
    --paginate (-p)               # Pipe all output into less (or if set, $PAGER) if standard output is a terminal.
    --no-pager (-P)               # Do not pipe Git output into a pager.
    --git-dir=<path>              # Set the path to the repository (".git" directory).
    --work-tree=<path>            # Set the path to the working tree. It can be an absolute path or a path relative to the current working directory.
    --namespace=<path>            # Set the Git namespace. See gitnamespaces(7) for more details.
    --super-prefix=<path>         # Currently for internal use only.
    --bare                        # Treat the repository as a bare repository.
    --no-replace-objects          # Do not use replacement refs to replace Git objects. See git-replace(1) for more information.
    --literal-pathspecs           # Treat pathspecs literally (i.e. no globbing, no pathspec magic).
    --glob-pathspecs              # Add "glob" magic to all pathspec.
    --noglob-pathspecs            # Add "literal" magic to all pathspec.
    --icase-pathspecs             # Add "icase" magic to all pathspec.
    --no-optional-locks           # Do not perform optional operations that require locks.
    --list-cmds=group[,group...]  # List commands by group. This is an internal/experimental option and may change or be removed in the future.
]