113498266Sopenharmony_ci#!/usr/bin/env perl
213498266Sopenharmony_ci#***************************************************************************
313498266Sopenharmony_ci#                                  _   _ ____  _
413498266Sopenharmony_ci#  Project                     ___| | | |  _ \| |
513498266Sopenharmony_ci#                             / __| | | | |_) | |
613498266Sopenharmony_ci#                            | (__| |_| |  _ <| |___
713498266Sopenharmony_ci#                             \___|\___/|_| \_\_____|
813498266Sopenharmony_ci#
913498266Sopenharmony_ci# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
1013498266Sopenharmony_ci#
1113498266Sopenharmony_ci# This software is licensed as described in the file COPYING, which
1213498266Sopenharmony_ci# you should have received as part of this distribution. The terms
1313498266Sopenharmony_ci# are also available at https://curl.se/docs/copyright.html.
1413498266Sopenharmony_ci#
1513498266Sopenharmony_ci# You may opt to use, copy, modify, merge, publish, distribute and/or sell
1613498266Sopenharmony_ci# copies of the Software, and permit persons to whom the Software is
1713498266Sopenharmony_ci# furnished to do so, under the terms of the COPYING file.
1813498266Sopenharmony_ci#
1913498266Sopenharmony_ci# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
2013498266Sopenharmony_ci# KIND, either express or implied.
2113498266Sopenharmony_ci#
2213498266Sopenharmony_ci# SPDX-License-Identifier: curl
2313498266Sopenharmony_ci#
2413498266Sopenharmony_ci###########################################################################
2513498266Sopenharmony_ci
2613498266Sopenharmony_ciuse strict;
2713498266Sopenharmony_ciuse warnings;
2813498266Sopenharmony_ciuse Getopt::Long();
2913498266Sopenharmony_ciuse Pod::Usage();
3013498266Sopenharmony_ci
3113498266Sopenharmony_cimy $curl = 'curl';
3213498266Sopenharmony_cimy $shell = 'zsh';
3313498266Sopenharmony_cimy $help = 0;
3413498266Sopenharmony_ciGetopt::Long::GetOptions(
3513498266Sopenharmony_ci    'curl=s' => \$curl,
3613498266Sopenharmony_ci    'shell=s' => \$shell,
3713498266Sopenharmony_ci    'help' => \$help,
3813498266Sopenharmony_ci) or Pod::Usage::pod2usage();
3913498266Sopenharmony_ciPod::Usage::pod2usage() if $help;
4013498266Sopenharmony_ci
4113498266Sopenharmony_cimy $regex = '\s+(?:(-[^\s]+),\s)?(--[^\s]+)\s*(\<.+?\>)?\s+(.*)';
4213498266Sopenharmony_cimy @opts = parse_main_opts('--help all', $regex);
4313498266Sopenharmony_ci
4413498266Sopenharmony_ciif ($shell eq 'fish') {
4513498266Sopenharmony_ci    print "# curl fish completion\n\n";
4613498266Sopenharmony_ci    print qq{$_ \n} foreach (@opts);
4713498266Sopenharmony_ci} elsif ($shell eq 'zsh') {
4813498266Sopenharmony_ci    my $opts_str;
4913498266Sopenharmony_ci
5013498266Sopenharmony_ci    $opts_str .= qq{  $_ \\\n} foreach (@opts);
5113498266Sopenharmony_ci    chomp $opts_str;
5213498266Sopenharmony_ci
5313498266Sopenharmony_cimy $tmpl = <<"EOS";
5413498266Sopenharmony_ci#compdef curl
5513498266Sopenharmony_ci
5613498266Sopenharmony_ci# curl zsh completion
5713498266Sopenharmony_ci
5813498266Sopenharmony_cilocal curcontext="\$curcontext" state state_descr line
5913498266Sopenharmony_citypeset -A opt_args
6013498266Sopenharmony_ci
6113498266Sopenharmony_cilocal rc=1
6213498266Sopenharmony_ci
6313498266Sopenharmony_ci_arguments -C -S \\
6413498266Sopenharmony_ci$opts_str
6513498266Sopenharmony_ci  '*:URL:_urls' && rc=0
6613498266Sopenharmony_ci
6713498266Sopenharmony_cireturn rc
6813498266Sopenharmony_ciEOS
6913498266Sopenharmony_ci
7013498266Sopenharmony_ci    print $tmpl;
7113498266Sopenharmony_ci} else {
7213498266Sopenharmony_ci    die("Unsupported shell: $shell");
7313498266Sopenharmony_ci}
7413498266Sopenharmony_ci
7513498266Sopenharmony_cisub parse_main_opts {
7613498266Sopenharmony_ci    my ($cmd, $regex) = @_;
7713498266Sopenharmony_ci
7813498266Sopenharmony_ci    my @list;
7913498266Sopenharmony_ci    my @lines = call_curl($cmd);
8013498266Sopenharmony_ci
8113498266Sopenharmony_ci    foreach my $line (@lines) {
8213498266Sopenharmony_ci        my ($short, $long, $arg, $desc) = ($line =~ /^$regex/) or next;
8313498266Sopenharmony_ci
8413498266Sopenharmony_ci        my $option = '';
8513498266Sopenharmony_ci
8613498266Sopenharmony_ci        $arg =~ s/\:/\\\:/g if defined $arg;
8713498266Sopenharmony_ci
8813498266Sopenharmony_ci        $desc =~ s/'/'\\''/g if defined $desc;
8913498266Sopenharmony_ci        $desc =~ s/\[/\\\[/g if defined $desc;
9013498266Sopenharmony_ci        $desc =~ s/\]/\\\]/g if defined $desc;
9113498266Sopenharmony_ci        $desc =~ s/\:/\\\:/g if defined $desc;
9213498266Sopenharmony_ci
9313498266Sopenharmony_ci        if ($shell eq 'fish') {
9413498266Sopenharmony_ci            $option .= "complete --command curl";
9513498266Sopenharmony_ci            $option .= " --short-option '" . strip_dash(trim($short)) . "'"
9613498266Sopenharmony_ci                if defined $short;
9713498266Sopenharmony_ci            $option .= " --long-option '" . strip_dash(trim($long)) . "'"
9813498266Sopenharmony_ci                if defined $long;
9913498266Sopenharmony_ci            $option .= " --description '" . strip_dash(trim($desc)) . "'"
10013498266Sopenharmony_ci                if defined $desc;
10113498266Sopenharmony_ci        } elsif ($shell eq 'zsh') {
10213498266Sopenharmony_ci            $option .= '{' . trim($short) . ',' if defined $short;
10313498266Sopenharmony_ci            $option .= trim($long)  if defined $long;
10413498266Sopenharmony_ci            $option .= '}' if defined $short;
10513498266Sopenharmony_ci            $option .= '\'[' . trim($desc) . ']\'' if defined $desc;
10613498266Sopenharmony_ci
10713498266Sopenharmony_ci            if (defined $arg) {
10813498266Sopenharmony_ci                $option .= ":'$arg'";
10913498266Sopenharmony_ci                if ($arg =~ /<file ?(name)?>|<path>/) {
11013498266Sopenharmony_ci                    $option .= ':_files';
11113498266Sopenharmony_ci                } elsif ($arg =~ /<dir>/) {
11213498266Sopenharmony_ci                    $option .= ":'_path_files -/'";
11313498266Sopenharmony_ci                } elsif ($arg =~ /<url>/i) {
11413498266Sopenharmony_ci                    $option .= ':_urls';
11513498266Sopenharmony_ci                } elsif ($long =~ /ftp/ && $arg =~ /<method>/) {
11613498266Sopenharmony_ci                    $option .= ":'(multicwd nocwd singlecwd)'";
11713498266Sopenharmony_ci                } elsif ($arg =~ /<method>/) {
11813498266Sopenharmony_ci                    $option .= ":'(DELETE GET HEAD POST PUT)'";
11913498266Sopenharmony_ci                }
12013498266Sopenharmony_ci            }
12113498266Sopenharmony_ci        }
12213498266Sopenharmony_ci
12313498266Sopenharmony_ci        push @list, $option;
12413498266Sopenharmony_ci    }
12513498266Sopenharmony_ci
12613498266Sopenharmony_ci    # Sort longest first, because zsh won't complete an option listed
12713498266Sopenharmony_ci    # after one that's a prefix of it.
12813498266Sopenharmony_ci    @list = sort {
12913498266Sopenharmony_ci        $a =~ /([^=]*)/; my $ma = $1;
13013498266Sopenharmony_ci        $b =~ /([^=]*)/; my $mb = $1;
13113498266Sopenharmony_ci
13213498266Sopenharmony_ci        length($mb) <=> length($ma)
13313498266Sopenharmony_ci    } @list if $shell eq 'zsh';
13413498266Sopenharmony_ci
13513498266Sopenharmony_ci    return @list;
13613498266Sopenharmony_ci}
13713498266Sopenharmony_ci
13813498266Sopenharmony_cisub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
13913498266Sopenharmony_cisub strip_dash { my $s = shift; $s =~ s/^-+//g; return $s };
14013498266Sopenharmony_ci
14113498266Sopenharmony_cisub call_curl {
14213498266Sopenharmony_ci    my ($cmd) = @_;
14313498266Sopenharmony_ci    my $output = `"$curl" $cmd`;
14413498266Sopenharmony_ci    if ($? == -1) {
14513498266Sopenharmony_ci        die "Could not run curl: $!";
14613498266Sopenharmony_ci    } elsif ((my $exit_code = $? >> 8) != 0) {
14713498266Sopenharmony_ci        die "curl returned $exit_code with output:\n$output";
14813498266Sopenharmony_ci    }
14913498266Sopenharmony_ci    return split /\n/, $output;
15013498266Sopenharmony_ci}
15113498266Sopenharmony_ci
15213498266Sopenharmony_ci__END__
15313498266Sopenharmony_ci
15413498266Sopenharmony_ci=head1 NAME
15513498266Sopenharmony_ci
15613498266Sopenharmony_cicompletion.pl - Generates tab-completion files for various shells
15713498266Sopenharmony_ci
15813498266Sopenharmony_ci=head1 SYNOPSIS
15913498266Sopenharmony_ci
16013498266Sopenharmony_cicompletion.pl [options...]
16113498266Sopenharmony_ci
16213498266Sopenharmony_ci    --curl   path to curl executable
16313498266Sopenharmony_ci    --shell  zsh/fish
16413498266Sopenharmony_ci    --help   prints this help
16513498266Sopenharmony_ci
16613498266Sopenharmony_ci=cut
167