mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-03 15:01:16 -03:00
create_manpage_completions: handle groff \X'...' device control escapes
help2man 1.50 added \X'tty: link URL' hyperlink escapes to generated man pages. coreutils 9.10 is the first widely-deployed package to ship these, and it broke completion generation for most of its commands (only 17/106 man pages parsed successfully). The escape wraps option text like this: \X'tty: link https://example.com/a'\fB\-a, \-\-all\fP\X'tty: link' Two places needed fixing: - remove_groff_formatting() didn't strip \X'...', so Type1-4 parsers extracted garbage option names like "--all\X'tty" - Deroffer.esc_char_backslash() didn't recognize \X, falling through to the generic single-char escape which stripped only the \, leaving "X'tty: link ...'" as literal text. Option lines then started with X instead of -, so TypeDeroffManParser's is_option() check failed. Also handle \Z'...' (zero-width string) which has identical syntax. Closes #12578
This commit is contained in:
committed by
Johannes Altmanninger
parent
14ce56d2a5
commit
7bd37dfe55
@@ -1,6 +1,10 @@
|
||||
fish ?.?.? (released ???)
|
||||
=========================
|
||||
|
||||
Other improvements
|
||||
------------------
|
||||
- ``fish_update_completions`` now handles groff ``\X'...'`` device control escapes, fixing completion generation for man pages produced by help2man 1.50 and later (such as coreutils 9.10).
|
||||
|
||||
fish 4.6.0 (released March 28, 2026)
|
||||
====================================
|
||||
|
||||
|
||||
@@ -501,6 +501,19 @@ class Deroffer:
|
||||
return True
|
||||
return False
|
||||
|
||||
def device_control(self):
|
||||
# groff \X'...' device control escape (and \Z'...' zero-width).
|
||||
# help2man 1.50+ uses \X'tty: link URL' for hyperlinks.
|
||||
# We just skip the entire escape.
|
||||
if self.str_at(1) in "XZ" and self.str_at(2) == "'":
|
||||
self.skip_char(3)
|
||||
while self.str_at(0) and self.str_at(0) != "'":
|
||||
self.skip_char()
|
||||
if self.str_at(0) == "'":
|
||||
self.skip_char()
|
||||
return True
|
||||
return False
|
||||
|
||||
def var(self):
|
||||
reg = ""
|
||||
s0s1 = self.s[0:2]
|
||||
@@ -650,6 +663,8 @@ class Deroffer:
|
||||
return self.size()
|
||||
elif c in "hvwud":
|
||||
return self.numreq()
|
||||
elif c in "XZ":
|
||||
return self.device_control()
|
||||
elif c in "n*":
|
||||
return self.var()
|
||||
elif c == "(":
|
||||
@@ -1314,6 +1329,9 @@ def built_command(options, description):
|
||||
|
||||
|
||||
def remove_groff_formatting(data):
|
||||
# Strip groff \X'...' device control escapes (help2man 1.50+ hyperlinks)
|
||||
# and \Z'...' zero-width escapes.
|
||||
data = re.sub(r"\\[XZ]'[^']*'", "", data)
|
||||
data = data.replace("\\fI", "")
|
||||
data = data.replace("\\fP", "")
|
||||
data = data.replace("\\f1", "")
|
||||
|
||||
38
tests/checks/manpage-completions-groff-x.fish
Normal file
38
tests/checks/manpage-completions-groff-x.fish
Normal file
@@ -0,0 +1,38 @@
|
||||
#RUN: %fish %s
|
||||
#REQUIRES: command -v python3
|
||||
|
||||
# Regression test for groff \X'...' device control escapes in man pages.
|
||||
# help2man 1.50+ emits \X'tty: link URL' hyperlinks which broke the parser.
|
||||
# See: coreutils 9.10 man pages.
|
||||
|
||||
set -l script (status dirname)/../../share/tools/create_manpage_completions.py
|
||||
set -l tmpdir (mktemp -d)
|
||||
|
||||
# Minimal man page with \X'tty: link' escapes as produced by help2man 1.50
|
||||
printf '%s\n' \
|
||||
'.TH TESTCMD "1" "March 2026" "test 1.0" "User Commands"' \
|
||||
'.SH NAME' \
|
||||
'testcmd \\- test command' \
|
||||
'.SH DESCRIPTION' \
|
||||
'A test command.' \
|
||||
'.TP' \
|
||||
'\\X'"'"'tty: link https://example.com/a'"'"'\\fB\\-a, \\-\\-all\\fP\\X'"'"'tty: link'"'"'' \
|
||||
'show all entries' \
|
||||
'.TP' \
|
||||
'\\X'"'"'tty: link https://example.com/v'"'"'\\fB\\-v, \\-\\-verbose\\fP\\X'"'"'tty: link'"'"'' \
|
||||
'be verbose' \
|
||||
'.TP' \
|
||||
'\\X'"'"'tty: link https://example.com/h'"'"'\\fB\\-\\-help\\fP\\X'"'"'tty: link'"'"'' \
|
||||
'display help' \
|
||||
'.PP' \
|
||||
'Some trailing paragraph text.' \
|
||||
'.SH AUTHOR' \
|
||||
'Nobody.' \
|
||||
> $tmpdir/testcmd.1
|
||||
|
||||
python3 $script --stdout $tmpdir/testcmd.1 | string match -r '^complete.*'
|
||||
#CHECK: complete -c testcmd -s a -l all -d 'show all entries'
|
||||
#CHECK: complete -c testcmd -s v -l verbose -d 'be verbose'
|
||||
#CHECK: complete -c testcmd -l help -d 'display help'
|
||||
|
||||
rm -rf $tmpdir
|
||||
Reference in New Issue
Block a user