From d055a01ce90510a6f8ff44bb7fceace9b2dbcf97 Mon Sep 17 00:00:00 2001 From: tiymat <138939221+tiymat@users.noreply.github.com> Date: Fri, 21 Mar 2025 20:45:57 -0230 Subject: [PATCH] scripts: update completion.pl to parse options from docs Reported-by: kpcyrd on github Fixes #16072 Closes #16789 --- docs/cmdline-opts/proxy-tls13-ciphers.md | 2 +- docs/cmdline-opts/tls13-ciphers.md | 2 +- scripts/Makefile.am | 4 +- scripts/completion.pl | 65 ++++++++++++++---------- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/docs/cmdline-opts/proxy-tls13-ciphers.md b/docs/cmdline-opts/proxy-tls13-ciphers.md index 72bae4e75d..6fcf6d79dc 100644 --- a/docs/cmdline-opts/proxy-tls13-ciphers.md +++ b/docs/cmdline-opts/proxy-tls13-ciphers.md @@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: proxy-tls13-ciphers Arg: -help: TLS 1.3 proxy cipher suites +Help: TLS 1.3 proxy cipher suites Protocols: TLS Category: proxy tls Added: 7.61.0 diff --git a/docs/cmdline-opts/tls13-ciphers.md b/docs/cmdline-opts/tls13-ciphers.md index 94ea6c775d..ccd08f7c81 100644 --- a/docs/cmdline-opts/tls13-ciphers.md +++ b/docs/cmdline-opts/tls13-ciphers.md @@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: tls13-ciphers Arg: -help: TLS 1.3 cipher suites to use +Help: TLS 1.3 cipher suites to use Protocols: TLS Category: tls Added: 7.61.0 diff --git a/scripts/Makefile.am b/scripts/Makefile.am index b29c99d892..021843bf4b 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -47,7 +47,7 @@ if CROSSCOMPILING @echo "NOTICE: we can't generate zsh completion when cross-compiling!" else # if not cross-compiling: if test -z "$(PERL)"; then echo "No perl: can't install completion script"; else \ - $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell zsh > $@ ; fi + $(PERL) $(srcdir)/completion.pl --opts-dir $(top_srcdir)/docs/cmdline-opts --shell zsh > $@ ; fi endif endif @@ -57,7 +57,7 @@ if CROSSCOMPILING @echo "NOTICE: we can't generate fish completion when cross-compiling!" else # if not cross-compiling: if test -z "$(PERL)"; then echo "No perl: can't install completion script"; else \ - $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell fish > $@ ; fi + $(PERL) $(srcdir)/completion.pl --opts-dir $(top_srcdir)/docs/cmdline-opts --shell fish > $@ ; fi endif endif diff --git a/scripts/completion.pl b/scripts/completion.pl index dd0c81d35b..150a56db81 100755 --- a/scripts/completion.pl +++ b/scripts/completion.pl @@ -28,18 +28,17 @@ use warnings; use Getopt::Long(); use Pod::Usage(); -my $curl = 'curl'; +my $opts_dir = '../docs/cmdline-opts'; my $shell = 'zsh'; my $help = 0; Getopt::Long::GetOptions( - 'curl=s' => \$curl, + 'opts-dir=s' => \$opts_dir, 'shell=s' => \$shell, 'help' => \$help, ) or Pod::Usage::pod2usage(); Pod::Usage::pod2usage() if $help; -my $regex = '\s+(?:(-[^\s]+),\s)?(--[^\s]+)\s*(\<.+?\>)?\s+(.*)'; -my @opts = parse_main_opts('--help all', $regex); +my @opts = parse_main_opts($opts_dir); if ($shell eq 'fish') { print "# curl fish completion\n\n"; @@ -76,23 +75,43 @@ EOS } sub parse_main_opts { - my ($cmd, $regex) = @_; + my ($opts_dir) = @_; - my @list; - my @lines = call_curl($cmd); + my (@files, @list); + my ($dir_handle, $file_content); - foreach my $line (@lines) { - my ($short, $long, $arg, $desc) = ($line =~ /^$regex/) or next; + opendir($dir_handle, $opts_dir) || die "Unable to open dir: $opts_dir due to error: $!"; + @files = readdir($dir_handle); + closedir($dir_handle) || die "Unable to close handle on dir: $opts_dir due to error: $!"; - my $option = ''; + # We want regular files that end with .md and don't start with an underscore + # Edge case: MANPAGE.md doesn't start with an underscore but also isn't documentation for an option + @files = grep { $_ =~ /\.md$/i && !/^_/ && -f "$opts_dir/$_" && $_ ne "MANPAGE.md" } @files; - $arg =~ s/\:/\\\:/g if defined $arg; + for my $file (@files) { + open(my $doc_handle, '<', "$opts_dir/$file") || die "Unable to open file: $file due to error: $!"; + $file_content = join('', <$doc_handle>); + close($doc_handle) || die "Unable to close file: $file due to error: $!"; + + # Extract the curldown header section demarcated by --- + $file_content =~ /^---\s*\n(.*?)\n---\s*\n/s || die "Unable to parse file $file"; + $file_content = $1; + my ($short, $long, $arg, $desc); + + if ($file_content =~ /^Short:\s+(.*)\s*$/im) {$short = "-$1";} + if ($file_content =~ /^Long:\s+(.*)\s*$/im) {$long = "--$1";} + if ($file_content =~ /^Arg:\s+(.*)\s*$/im) {$arg = $1;} + if ($file_content =~ /^Help:\s+(.*)\s*$/im) {$desc = $1;} + + $arg =~ s/\:/\\\:/g if defined $arg; $desc =~ s/'/'\\''/g if defined $desc; $desc =~ s/\[/\\\[/g if defined $desc; $desc =~ s/\]/\\\]/g if defined $desc; $desc =~ s/\:/\\\:/g if defined $desc; + my $option = ''; + if ($shell eq 'fish') { $option .= "complete --command curl"; $option .= " --short-option '" . strip_dash(trim($short)) . "'" @@ -123,16 +142,17 @@ sub parse_main_opts { } } - push @list, $option; + push(@list, $option); } # Sort longest first, because zsh won't complete an option listed - # after one that's a prefix of it. + # after one that's a prefix of it. When length is equal, fall back + # to stringwise cmp. @list = sort { $a =~ /([^=]*)/; my $ma = $1; $b =~ /([^=]*)/; my $mb = $1; - length($mb) <=> length($ma) + length($mb) <=> length($ma) || $ma cmp $mb } @list if $shell eq 'zsh'; return @list; @@ -141,17 +161,6 @@ sub parse_main_opts { sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s }; sub strip_dash { my $s = shift; $s =~ s/^-+//g; return $s }; -sub call_curl { - my ($cmd) = @_; - my $output = `"$curl" $cmd`; - if ($? == -1) { - die "Could not run curl: $!"; - } elsif ((my $exit_code = $? >> 8) != 0) { - die "curl returned $exit_code with output:\n$output"; - } - return split /\n/, $output; -} - __END__ =head1 NAME @@ -162,8 +171,8 @@ completion.pl - Generates tab-completion files for various shells completion.pl [options...] - --curl path to curl executable - --shell zsh/fish - --help prints this help + --opts_dir path to cmdline-opts directory + --shell zsh/fish + --help prints this help =cut -- 2.47.3