From be9bb2304d51970f8eb48bfdfb2aaa4f9a99980a Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Thu, 29 Oct 2026 07:57:42 +0100 Subject: [PATCH 1/2] Group whatis lines under module name and wrap them to terminal width The whatis and search sub-commands print one output line per module-whatis entry, each prefixed by the module name right-aligned in a fixed-width column. A long description is sent as a single line that the terminal wraps at an arbitrary character, with the continuation flush left where it visually merges with the next entry. When a modulefile defines several module-whatis lines, the repeated name adds noise and hides where one module ends and the next begins. Report the module name once per matching modulefile, with its first whatis line beside it and the following ones aligned under the start of this text. Wrap text to the terminal width, cutting at whitespace so that words are kept whole and continuation lines stay attached to their module. SGR codes highlighting the search string are not counted in line length. A name longer than its column shifts the text start column for that module only. JSON output is unchanged. Fixes #720 Assisted-by: Claude:claude-fable-5-1 Signed-off-by: Xavier Delaruelle --- NEWS.rst | 4 ++ doc/source/changes.rst | 5 ++ doc/source/module.rst | 16 ++++++ tcl/report.tcl.in | 50 +++++++++++++++++++ tcl/subcmd.tcl.in | 24 +++++++-- testsuite/modules.20-locate/100-wspace.exp | 2 + .../modules.50-cmds/730-linked_envvars.exp | 4 +- testsuite/modules.70-maint/055-whatis.exp | 39 +++++++++++---- testsuite/modules.70-maint/060-apropos.exp | 19 ++++++- 9 files changed, 147 insertions(+), 16 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index ae6582beb..14e91e638 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -18,6 +18,10 @@ Modules 5.8.0 (not yet released) * Add :mfcmd:`module-info modulename` and :mfcmd:`module-info moduleversion` modulefile commands to get the name part and the version part of currently evaluating modulefile. (fix issue #713) +* Improve readability of :subcmd:`whatis` and :subcmd:`search` output: name of + each matching modulefile is reported once, followed by its + :mfcmd:`module-whatis` lines wrapped to the terminal width. (fix issue + #720) .. _5.7 release notes: diff --git a/doc/source/changes.rst b/doc/source/changes.rst index 21f1a90c7..cc6e7b5a1 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -1062,6 +1062,11 @@ The following module sub-commands appeared on Modules 5. of :subcmd:`reload` sub-command. No more support from ``MODULESBEGINENV``, initial environment handling now covers this use case. +:subcmd:`search`, :subcmd:`whatis` + + Starting Modules 5.8, name of each matching modulefile is reported once, + followed by its :mfcmd:`module-whatis` lines wrapped to the terminal width. + Environment """"""""""" diff --git a/doc/source/module.rst b/doc/source/module.rst index 9a957f7d0..b83999076 100644 --- a/doc/source/module.rst +++ b/doc/source/module.rst @@ -2677,6 +2677,10 @@ Module Sub-Commands *string* in a case insensitive manner will be displayed. *string* may contain wildcard characters. + Name of each matching *modulefile* is reported once, followed by its + *module-whatis* lines. This text is wrapped to the terminal width and its + continuation lines are aligned under the start of the first line text. + .. only:: html or latex .. versionadded:: 4.0 @@ -2689,6 +2693,10 @@ Module Sub-Commands .. versionchanged:: 4.6 Option :option:`--all`/:option:`-a` added + .. versionchanged:: 5.8 + Module name is reported once with its *module-whatis* lines grouped + below and wrapped to terminal width + .. subcmd:: sh-to-mod shell script [arg...] Evaluate with *shell* the designated *script* with defined *arguments* to @@ -3172,6 +3180,10 @@ Module Sub-Commands *modulefiles* matching *pattern*. *pattern* may contain wildcard characters. If no *pattern* is specified, all :mfcmd:`module-whatis` lines will be shown. + Name of each matching *modulefile* is reported once, followed by its + *module-whatis* lines. This text is wrapped to the terminal width and its + continuation lines are aligned under the start of the first line text. + The parameter *pattern* may also be a symbolic modulefile name or a modulefile alias. It may also leverage a specific syntax to finely select module version (see `Advanced module version specifiers`_ section below). @@ -3198,6 +3210,10 @@ Module Sub-Commands Results from a multi *pattern* search are consolidated under a single output + .. versionchanged:: 5.8 + Module name is reported once with its *module-whatis* lines grouped + below and wrapped to terminal width + Modulefiles ^^^^^^^^^^^ diff --git a/tcl/report.tcl.in b/tcl/report.tcl.in index d893b9bd4..75d124d65 100644 --- a/tcl/report.tcl.in +++ b/tcl/report.tcl.in @@ -1645,6 +1645,56 @@ proc showModulePath {} { } } +# split text into lines whose visible length does not exceed max_len, cutting +# at whitespace position (SGR codes consume no length). A word longer than +# max_len is kept whole on its own line +proc wrapTextToWidth {text max_len} { + # empty text produces one empty line + if {$text eq {}} { + return [list {}] + } + set wrapped_list {} + foreach line [split $text \n] { + while {1} { + # walk through line until max_len visible characters are passed + set idx 0 + set vis_len 0 + set line_len [string length $line] + while {$idx < $line_len} { + if {[string range $line $idx $idx+1] eq "\033\[" && [set midx\ + [string first m $line $idx]] != -1} { + set idx [expr {$midx + 1}] + } elseif {$vis_len == $max_len} { + break + } else { + incr idx + incr vis_len + } + } + # whole remaining line fits + if {$idx >= $line_len} { + lappend wrapped_list $line + break + } + # cut after word if no whitespace found before it + if {[set cut_idx [string last { } $line $idx]] < 1} { + set cut_idx [string first { } $line $idx] + } + if {$cut_idx == -1} { + lappend wrapped_list $line + break + } + lappend wrapped_list [string range $line 0 $cut_idx-1] + set line [string trimleft [string range $line $cut_idx+1 end]] + # nothing left to report if only whitespace remains after cut + if {$line eq {}} { + break + } + } + } + return $wrapped_list +} + proc displayTableHeader {sgrkey args} { foreach {title col_len} $args { set col "- [sgr $sgrkey $title] " diff --git a/tcl/subcmd.tcl.in b/tcl/subcmd.tcl.in index d53928dfe..41d089104 100644 --- a/tcl/subcmd.tcl.in +++ b/tcl/subcmd.tcl.in @@ -399,10 +399,26 @@ proc cmdModuleSearch {args} { whatis a $::g_whatis 1] } else { set eltsgr [string map $matchmodmap $elt] - foreach line $::g_whatis { - set linesgr [string map $matchsearchmap $line] - lappend display_list "[string repeat { } [expr {20 -\ - [string length $elt]}]]$eltsgr: $linesgr" + set eltpad [string repeat { } [expr {20 - [string length\ + $elt]}]] + # module name on first line only, whatis text of next lines + # aligned under first line text and wrapped to term width + set text_col [expr {[tcl::mathfunc::max 20 [string length\ + $elt]] + 2}] + set text_pad [string repeat { } $text_col] + set text_len [tcl::mathfunc::max [expr {[getState\ + term_columns] - $text_col}] 1] + set first 1 + foreach entry $::g_whatis { + foreach line [wrapTextToWidth [string map\ + $matchsearchmap $entry] $text_len] { + if {$first} { + set first 0 + lappend display_list "$eltpad$eltsgr: $line" + } else { + lappend display_list $text_pad$line + } + } } } } diff --git a/testsuite/modules.20-locate/100-wspace.exp b/testsuite/modules.20-locate/100-wspace.exp index 96fb3774d..5b11456f8 100644 --- a/testsuite/modules.20-locate/100-wspace.exp +++ b/testsuite/modules.20-locate/100-wspace.exp @@ -667,6 +667,8 @@ testouterr_cmd sh "unuse $modpath\\ wspac\\ " $ans {} # module whose name and target finish with space character testouterr_cmd sh {avail -t space\ y\ /1\ } OK "$mp:\n'space y /1 '(n )" testouterr_cmd_re sh {whatis space\ y\ /1\ } OK "$modlin $mpre $modlin\n\\s+space y /1 : space y /1 " +# whatis text cut at terminal width right before its trailing space +testouterr_cmd_re sh {-w 32 whatis space\ y\ /1\ } OK "$modlin $mpre $modlin\n\\s+space y /1 : space y /1" set ans [list] lappend ans [list set __MODULES_LMALTNAME "space y /1 &space y /n &al|space y /a "] lappend ans [list set _LMFILES_ "$mp/space y /1 "] diff --git a/testsuite/modules.50-cmds/730-linked_envvars.exp b/testsuite/modules.50-cmds/730-linked_envvars.exp index 579e548c9..8fd5418c9 100644 --- a/testsuite/modules.50-cmds/730-linked_envvars.exp +++ b/testsuite/modules.50-cmds/730-linked_envvars.exp @@ -573,8 +573,8 @@ testouterr_cmd_re bash {display link/1} OK $tserr setenv_var TESTSUITE_LINKED_ENVVARS append1 set tserr "$modlin $mpre $modlin \\s*link/1: link/1 -\\s*link/1: BAR: val2 -\\s*link/1: QUX: value" +\\s*BAR: val2 +\\s*QUX: value" testouterr_cmd_re bash {whatis link/1} OK $tserr setenv_var TESTSUITE_LINKED_ENVVARS prepend1 diff --git a/testsuite/modules.70-maint/055-whatis.exp b/testsuite/modules.70-maint/055-whatis.exp index fd3012596..68133d205 100644 --- a/testsuite/modules.70-maint/055-whatis.exp +++ b/testsuite/modules.70-maint/055-whatis.exp @@ -54,7 +54,10 @@ set ts_csh_2 "$header\n$whatis_2: Testsuite-Modulefile" # module-whatis call produce a single module-whatis line, not one line per passed argument set ts_csh_3 "$header\n$whatis_3: Testsuite Whatis Modulefile" set ts_csh_4 "$header\n$whatis_4: Testsuite Whatis Modulefile" -set ts_csh_5 "$header\n$whatis_5: Testsuite Whatis Modulefile\n$whatis_5: Second line of whatis tokens" +# module name is reported once, next whatis lines are aligned under text of +# first line +set text_pad [string repeat { } 22] +set ts_csh_5 "$header\n$whatis_5: Testsuite Whatis Modulefile\n${text_pad}Second line of whatis tokens" set ts_csh_6 "$err_path'$module_6'" set ts_csh_7 "$header\n$whatis_7: erroneous module test" @@ -62,21 +65,39 @@ set ts_csh_7 "$header\n$whatis_7: erroneous module test" # The tests # -testouterr_cmd_re "csh" "--terse whatis $module_1" "OK" "$ts_csh_1" -testouterr_cmd_re "csh" "--terse whatis $module_2" "OK" "$ts_csh_2" -testouterr_cmd_re "csh" "--terse whatis $module_3" "OK" "$ts_csh_3" +testouterr_cmd_re "csh" "whatis $module_1" "OK" "$ts_csh_1" +testouterr_cmd_re "csh" "whatis $module_2" "OK" "$ts_csh_2" +testouterr_cmd_re "csh" "whatis $module_3" "OK" "$ts_csh_3" skip_if_quick_mode -testouterr_cmd_re "csh" "--terse whatis $module_4" "OK" "$ts_csh_4" -testouterr_cmd_re "csh" "--terse whatis $module_5" "OK" "$ts_csh_5" +testouterr_cmd_re "csh" "whatis $module_4" "OK" "$ts_csh_4" +testouterr_cmd_re "csh" "whatis $module_5" "OK" "$ts_csh_5" +testouterr_cmd_re "csh" "whatis $module_5 $module_2" "OK" "$ts_csh_5\n$whatis_2: Testsuite-Modulefile" # command nickname tests -testouterr_cmd_re "csh" "--terse wh $module_5" "OK" "$ts_csh_5" +testouterr_cmd_re "csh" "wh $module_5" "OK" "$ts_csh_5" + +set module_8 "verssort/1.8-2015-12-01" +set text_pad_8 [string repeat { } 25] + +# whatis text is wrapped to terminal width, module name longer than its column +# shifts text start column +testouterr_cmd_re "csh" "-w 40 whatis $module_5" "OK" "$header\n$whatis_5: Testsuite Whatis\n${text_pad}Modulefile\n${text_pad}Second line of\n${text_pad}whatis tokens" +testouterr_cmd_re "csh" "whatis $module_8" "OK" "$header\n$module_8: module version sort test" +testouterr_cmd_re "csh" "-w 40 whatis $module_8" "OK" "$header\n$module_8: module version\n${text_pad_8}sort test" +# word longer than remaining width is kept whole on its own line +testouterr_cmd_re "csh" "-w 30 whatis $module_8" "OK" "$header\n$module_8: module\n${text_pad_8}version\n${text_pad_8}sort\n${text_pad_8}test" +testouterr_cmd_re "csh" "-w 10 whatis $module_8" "OK" "$header\n$module_8: module\n${text_pad_8}version\n${text_pad_8}sort\n${text_pad_8}test" +testouterr_cmd_re "csh" "-w 1 whatis $module_8" "OK" "$header\n$module_8: module\n${text_pad_8}version\n${text_pad_8}sort\n${text_pad_8}test" + +# json output +set ts_json_5 "{\"$modpathre\": {\n\"$module_5\": { \"name\": \"$module_5\", \"whatis\": \\\[ \"Testsuite Whatis Modulefile\", \"Second line of whatis tokens\" \\\]}\n}}" +testouterr_cmd_re "csh" "-j whatis $module_5" "OK" "$ts_json_5" # setup MODULEPATH with a trailing slash and an empty dir element setenv_path_var MODULEPATH {} "$modpath/" -testouterr_cmd_re "csh" "--terse whatis $module_1" "OK" "$ts_csh_1" +testouterr_cmd_re "csh" "whatis $module_1" "OK" "$ts_csh_1" # restore MODULEPATH setenv_path_var MODULEPATH $modpath @@ -115,7 +136,7 @@ setenv_loaded_module [list foo bar] "/path/to/foo" set ts_csh_8 "$err_loinconsist LOADEDMODULES=foo bar _LMFILES_=/path/to/foo" -testouterr_cmd_re "csh" "--terse whatis $module_5" ERR $ts_csh_8 +testouterr_cmd_re "csh" "whatis $module_5" ERR $ts_csh_8 # # Cleanup diff --git a/testsuite/modules.70-maint/060-apropos.exp b/testsuite/modules.70-maint/060-apropos.exp index 320529c25..3c3fa4b9a 100644 --- a/testsuite/modules.70-maint/060-apropos.exp +++ b/testsuite/modules.70-maint/060-apropos.exp @@ -35,7 +35,10 @@ set header "$modlin $modpathre $modlin" set warn_opt "$warn_msgs: Unsupported option " set ts_1 " whatis/lines: Testsuite Whatis Modulefile" -set ts_1a " whatis/lines: Second line of whatis tokens" +# module name is reported once, next whatis lines are aligned under text of +# first line +set text_pad [string repeat { } 22] +set ts_1a "${text_pad}Second line of whatis tokens" # different behavior than C-version: on Tcl-version multiple arguments provided on a single # module-whatis call produce a single module-whatis line, not one line per passed argument set ts_2 " whatis/multiple: Testsuite Whatis Modulefile" @@ -69,6 +72,20 @@ testouterr_cmd_re "csh" "apropos token" "ERR" "$header\n$ts_1\n$ts_1a" testouterr_cmd_re "csh" "keyword token" "ERR" "$header\n$ts_1\n$ts_1a" testouterr_cmd_re "csh" "search token" "ERR" "$header\n$ts_1\n$ts_1a" +# text is wrapped to terminal width +testouterr_cmd_re "csh" "-w 45 search Whatis" "ERR" "$header\n whatis/lines: Testsuite Whatis\n${text_pad}Modulefile\n${text_pad}Second line of whatis\n${text_pad}tokens\n whatis/multiple: Testsuite Whatis\n${text_pad}Modulefile\n whatis/string: Testsuite Whatis\n${text_pad}Modulefile" + +# highlighted search string does not count in wrapped line length +setenv_var MODULES_COLOR always +setenv_var MODULES_COLORS {hi=1:mp=1;94} +set hi [sgr 1] +set nohi [sgr 22] +set header_sgr "$modlin [sgr {1;94}]$modpathre[sgr 0] $modlin" +testouterr_cmd_re "csh" "-w 49 search token" "ERR" "$header_sgr\n whatis/lines: Testsuite Whatis Modulefile\n${text_pad}Second line of whatis\n${text_pad}${hi}token${nohi}s" +testouterr_cmd_re "csh" "-w 50 search token" "ERR" "$header_sgr\n whatis/lines: Testsuite Whatis Modulefile\n${text_pad}Second line of whatis ${hi}token${nohi}s" +setenv_var MODULES_COLOR never +unsetenv_var MODULES_COLORS + # # test with erroneous modulefile # should not produce error message From e868bb6384c98a6a56d1d6e22c846c26715c15f3 Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Thu, 29 Oct 2026 07:58:48 +0100 Subject: [PATCH 2/2] Support --terse option on whatis and search sub-commands Now that whatis and search group module-whatis lines under a single module name and wrap them to the terminal width, scripts parsing their results have no stable one line per entry format to rely on anymore. Accept the --terse option on both sub-commands, as avail and list already do, to report each module-whatis line on its own output line prefixed by the module name. No padding is added before the module name and no wrapping is applied, so each line holds a complete entry. The modulepath is reported as a header line, like avail does in terse mode. JSON output is unchanged. Fixes #720 Assisted-by: Claude:claude-fable-5-1 Signed-off-by: Xavier Delaruelle --- NEWS.rst | 4 ++ doc/source/changes.rst | 8 ++++ doc/source/module.rst | 30 +++++++++++---- init/Makefile | 4 +- init/zsh-functions/_module.in | 2 + tcl/report.tcl.in | 4 +- tcl/subcmd.tcl.in | 44 +++++++++++++--------- testsuite/modules.70-maint/055-whatis.exp | 13 ++++++- testsuite/modules.70-maint/060-apropos.exp | 9 +++++ testsuite/modules.70-maint/240-icase.exp | 4 +- 10 files changed, 90 insertions(+), 32 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 14e91e638..429bf56b8 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -22,6 +22,10 @@ Modules 5.8.0 (not yet released) each matching modulefile is reported once, followed by its :mfcmd:`module-whatis` lines wrapped to the terminal width. (fix issue #720) +* Add support for the :option:`--terse` option on :subcmd:`whatis` and + :subcmd:`search` sub-commands to get one output line per + :mfcmd:`module-whatis` entry prefixed by module name, without wrapping or + padding, and modulepath reported as a header line. (fix issue #720) .. _5.7 release notes: diff --git a/doc/source/changes.rst b/doc/source/changes.rst index cc6e7b5a1..d344c4b7b 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -914,6 +914,11 @@ The following command line switches appeared on Modules 5. Starting Modules 5.6, :subcmd:`spider` sub-command is supported. +:option:`--terse` + + Starting Modules 5.8, :subcmd:`search` and :subcmd:`whatis` sub-commands are + supported. + :option:`--default`, :option:`--latest`, :option:`--indepth`, :option:`--no-indepth` @@ -1066,6 +1071,9 @@ The following module sub-commands appeared on Modules 5. Starting Modules 5.8, name of each matching modulefile is reported once, followed by its :mfcmd:`module-whatis` lines wrapped to the terminal width. + The :option:`--terse` option reports each :mfcmd:`module-whatis` line on its + own output line prefixed by the module name, without wrapping or padding, + and the modulepath as a header line. Environment """"""""""" diff --git a/doc/source/module.rst b/doc/source/module.rst index b83999076..7f133a1ab 100644 --- a/doc/source/module.rst +++ b/doc/source/module.rst @@ -645,8 +645,9 @@ switches are accepted: .. option:: --terse, -t - Display :subcmd:`avail`, :subcmd:`list`, :subcmd:`savelist`, :subcmd:`spider` - and :subcmd:`stashlist` output in short format. + Display :subcmd:`avail`, :subcmd:`list`, :subcmd:`savelist`, + :subcmd:`search`, :subcmd:`spider`, :subcmd:`stashlist` and :subcmd:`whatis` + output in short format. .. only:: html or latex @@ -659,6 +660,9 @@ switches are accepted: .. versionchanged:: 5.6 Support for :subcmd:`spider` sub-command added + .. versionchanged:: 5.8 + Support for :subcmd:`search` and :subcmd:`whatis` sub-commands added + .. option:: --timer Prints at the end of the output an evaluation of the total execution time of @@ -2670,7 +2674,7 @@ Module Sub-Commands ``__init__`` or when no collection name is specified and no *default* collection exists -.. subcmd:: search [-a] [-j] string +.. subcmd:: search [-a] [-t|-j] string Seeks through the :mfcmd:`module-whatis` information of all *modulefiles* for the specified *string*. All *module-whatis* information matching the @@ -2679,7 +2683,10 @@ Module Sub-Commands Name of each matching *modulefile* is reported once, followed by its *module-whatis* lines. This text is wrapped to the terminal width and its - continuation lines are aligned under the start of the first line text. + continuation lines are aligned under the start of the first line text. With + the :option:`--terse` option, each *module-whatis* line is reported on its + own output line prefixed by the module name, without wrapping or padding, + and the modulepath is reported as a header line. .. only:: html or latex @@ -2695,7 +2702,9 @@ Module Sub-Commands .. versionchanged:: 5.8 Module name is reported once with its *module-whatis* lines grouped - below and wrapped to terminal width + below and wrapped to terminal width; option + :option:`--terse`/:option:`-t` added to get one output line per + *module-whatis* line .. subcmd:: sh-to-mod shell script [arg...] @@ -3174,7 +3183,7 @@ Module Sub-Commands :subcmd:`module use` is called from the command-line or within an initialization modulefile script -.. subcmd:: whatis [-a] [-j] [pattern...] +.. subcmd:: whatis [-a] [-t|-j] [pattern...] Display the information set up by the :mfcmd:`module-whatis` commands inside *modulefiles* matching *pattern*. *pattern* may contain wildcard characters. @@ -3182,7 +3191,10 @@ Module Sub-Commands Name of each matching *modulefile* is reported once, followed by its *module-whatis* lines. This text is wrapped to the terminal width and its - continuation lines are aligned under the start of the first line text. + continuation lines are aligned under the start of the first line text. With + the :option:`--terse` option, each *module-whatis* line is reported on its + own output line prefixed by the module name, without wrapping or padding, + and the modulepath is reported as a header line. The parameter *pattern* may also be a symbolic modulefile name or a modulefile alias. It may also leverage a specific syntax to finely select @@ -3212,7 +3224,9 @@ Module Sub-Commands .. versionchanged:: 5.8 Module name is reported once with its *module-whatis* lines grouped - below and wrapped to terminal width + below and wrapped to terminal width; option + :option:`--terse`/:option:`-t` added to get one output line per + *module-whatis* line Modulefiles diff --git a/init/Makefile b/init/Makefile index 244a25fe5..65c41c5a0 100644 --- a/init/Makefile +++ b/init/Makefile @@ -137,8 +137,8 @@ comp_stashlist_opts := -j -l -t --json --long --terse comp_clear_opts := --force -f comp_avail_opts := -a -C -d -i -j -L -l -o -S -t --all --contains --default --icase --json --latest --long --output --output= --starts-with --terse --indepth --no-indepth comp_mfile_opts := -i --icase -comp_whatis_opts := -a -i -j --all --icase --json -comp_search_opts := -a -j --all --json +comp_whatis_opts := -a -i -j -t --all --icase --json --terse +comp_search_opts := -a -j -t --all --json --terse comp_aliases_opts := -a --all comp_use_opts := -a --append -p --prepend comp_isavail_opts := -i --icase diff --git a/init/zsh-functions/_module.in b/init/zsh-functions/_module.in index 661c6a94a..7ddbe4c09 100644 --- a/init/zsh-functions/_module.in +++ b/init/zsh-functions/_module.in @@ -381,12 +381,14 @@ _module() { (whatis) _arguments \ '(-i --icase)'{-i,--icase}'[Case insensitive match]' \ + '(-t --terse)'{-t,--terse}'[Display output in terse format]' \ '(-j --json)'{-j,--json}'[Display output in JSON format]' \ '(-a --all)'{-a,--all}'[Include hidden modules in search]' \ "*::modulefile:{_module_avail_mods $cur}" && ret=0 ;; (apropos|keyword|search) _arguments \ + '(-t --terse)'{-t,--terse}'[Display output in terse format]' \ '(-j --json)'{-j,--json}'[Display output in JSON format]' \ '(-a --all)'{-a,--all}'[Include hidden modules in search]' \ && ret=0 diff --git a/tcl/report.tcl.in b/tcl/report.tcl.in index 75d124d65..a2091ba45 100644 --- a/tcl/report.tcl.in +++ b/tcl/report.tcl.in @@ -2101,9 +2101,9 @@ Listing / Searching commands: [-i] [--indepth|--no-indepth] [mod ...] List all or matching available modules aliases [-a] List all module aliases - whatis [-a] [-i] [-j] [modulefile ...] + whatis [-a] [-i] [-j|-t] [modulefile ...] Print whatis information of modulefile(s) - apropos | keyword | search [-a] [-j] str + apropos | keyword | search [-a] [-j|-t] str Search all name and whatis containing str spider [-a] [-t|-l|-j] [-S|-C] [-d|-L] [-o LIST] [-i] [--indepth|--no-indepth] [mod ...] diff --git a/tcl/subcmd.tcl.in b/tcl/subcmd.tcl.in index 41d089104..14139d5b3 100644 --- a/tcl/subcmd.tcl.in +++ b/tcl/subcmd.tcl.in @@ -217,6 +217,7 @@ proc cmdModuleSearch {args} { set mod_pattern_list [lassign $args search] set json [isStateEqual report_format json] + set terse [isStateEqual report_format terse] set icase [isIcase] lappend searchmod rc_defs_included @@ -399,24 +400,32 @@ proc cmdModuleSearch {args} { whatis a $::g_whatis 1] } else { set eltsgr [string map $matchmodmap $elt] - set eltpad [string repeat { } [expr {20 - [string length\ - $elt]}]] + # one line per whatis entry, each prefixed by module name + if {$terse} { + foreach line $::g_whatis { + set linesgr [string map $matchsearchmap $line] + lappend display_list "$eltsgr: $linesgr" + } # module name on first line only, whatis text of next lines # aligned under first line text and wrapped to term width - set text_col [expr {[tcl::mathfunc::max 20 [string length\ - $elt]] + 2}] - set text_pad [string repeat { } $text_col] - set text_len [tcl::mathfunc::max [expr {[getState\ - term_columns] - $text_col}] 1] - set first 1 - foreach entry $::g_whatis { - foreach line [wrapTextToWidth [string map\ - $matchsearchmap $entry] $text_len] { - if {$first} { - set first 0 - lappend display_list "$eltpad$eltsgr: $line" - } else { - lappend display_list $text_pad$line + } else { + set eltpad [string repeat { } [expr {20 - [string length\ + $elt]}]] + set text_col [expr {[tcl::mathfunc::max 20 [string\ + length $elt]] + 2}] + set text_pad [string repeat { } $text_col] + set text_len [tcl::mathfunc::max [expr {[getState\ + term_columns] - $text_col}] 1] + set first 1 + foreach entry $::g_whatis { + foreach line [wrapTextToWidth [string map\ + $matchsearchmap $entry] $text_len] { + if {$first} { + set first 0 + lappend display_list "$eltpad$eltsgr: $line" + } else { + lappend display_list $text_pad$line + } } } } @@ -424,7 +433,8 @@ proc cmdModuleSearch {args} { } } - displayElementList $dir mp sepline 1 0 0 $display_list + displayElementList $dir mp [expr {$terse ? {terse} : {sepline}}] 1\ + 0 0 $display_list } } lpopState mode diff --git a/testsuite/modules.70-maint/055-whatis.exp b/testsuite/modules.70-maint/055-whatis.exp index 68133d205..f8a07c9e5 100644 --- a/testsuite/modules.70-maint/055-whatis.exp +++ b/testsuite/modules.70-maint/055-whatis.exp @@ -91,9 +91,20 @@ testouterr_cmd_re "csh" "-w 30 whatis $module_8" "OK" "$header\n$module_8: modul testouterr_cmd_re "csh" "-w 10 whatis $module_8" "OK" "$header\n$module_8: module\n${text_pad_8}version\n${text_pad_8}sort\n${text_pad_8}test" testouterr_cmd_re "csh" "-w 1 whatis $module_8" "OK" "$header\n$module_8: module\n${text_pad_8}version\n${text_pad_8}sort\n${text_pad_8}test" -# json output +# terse output mode: one line per whatis entry, each prefixed by module name +# without padding nor wrapping, modulepath reported as header line +set header_t "$modpathre:" +set ts_csh_5t "$header_t\n$module_5: Testsuite Whatis Modulefile\n$module_5: Second line of whatis tokens" +testouterr_cmd_re "csh" "--terse whatis $module_5" "OK" "$ts_csh_5t" +testouterr_cmd_re "csh" "-t whatis $module_5 $module_2" "OK" "$ts_csh_5t\n$module_2: Testsuite-Modulefile" +testouterr_cmd_re "csh" "whatis -t $module_8" "OK" "$header_t\n$module_8: module version sort test" +testouterr_cmd_re "csh" "-w 30 -t whatis $module_8" "OK" "$header_t\n$module_8: module version sort test" +testouterr_cmd_re "csh" "-t whatis $module_1" "OK" "$ts_csh_1" + +# json output is not affected by terse mode set ts_json_5 "{\"$modpathre\": {\n\"$module_5\": { \"name\": \"$module_5\", \"whatis\": \\\[ \"Testsuite Whatis Modulefile\", \"Second line of whatis tokens\" \\\]}\n}}" testouterr_cmd_re "csh" "-j whatis $module_5" "OK" "$ts_json_5" +testouterr_cmd_re "csh" "-t -j whatis $module_5" "OK" "$ts_json_5" # setup MODULEPATH with a trailing slash and an empty dir element setenv_path_var MODULEPATH {} "$modpath/" diff --git a/testsuite/modules.70-maint/060-apropos.exp b/testsuite/modules.70-maint/060-apropos.exp index 3c3fa4b9a..ecf33a27f 100644 --- a/testsuite/modules.70-maint/060-apropos.exp +++ b/testsuite/modules.70-maint/060-apropos.exp @@ -72,6 +72,14 @@ testouterr_cmd_re "csh" "apropos token" "ERR" "$header\n$ts_1\n$ts_1a" testouterr_cmd_re "csh" "keyword token" "ERR" "$header\n$ts_1\n$ts_1a" testouterr_cmd_re "csh" "search token" "ERR" "$header\n$ts_1\n$ts_1a" +# terse output mode: one line per whatis entry, each prefixed by module name +# without padding nor wrapping, modulepath reported as header line +set header_t "$modpathre:" +set ts_1t "whatis/lines: Testsuite Whatis Modulefile\nwhatis/lines: Second line of whatis tokens" +testouterr_cmd_re "csh" "-t search token" "ERR" "$header_t\n$ts_1t" +testouterr_cmd_re "csh" "search -t token" "ERR" "$header_t\n$ts_1t" +testouterr_cmd_re "csh" "-w 45 -t search Whatis" "ERR" "$header_t\n$ts_1t\nwhatis/multiple: Testsuite Whatis Modulefile\nwhatis/string: Testsuite Whatis Modulefile" + # text is wrapped to terminal width testouterr_cmd_re "csh" "-w 45 search Whatis" "ERR" "$header\n whatis/lines: Testsuite Whatis\n${text_pad}Modulefile\n${text_pad}Second line of whatis\n${text_pad}tokens\n whatis/multiple: Testsuite Whatis\n${text_pad}Modulefile\n whatis/string: Testsuite Whatis\n${text_pad}Modulefile" @@ -83,6 +91,7 @@ set nohi [sgr 22] set header_sgr "$modlin [sgr {1;94}]$modpathre[sgr 0] $modlin" testouterr_cmd_re "csh" "-w 49 search token" "ERR" "$header_sgr\n whatis/lines: Testsuite Whatis Modulefile\n${text_pad}Second line of whatis\n${text_pad}${hi}token${nohi}s" testouterr_cmd_re "csh" "-w 50 search token" "ERR" "$header_sgr\n whatis/lines: Testsuite Whatis Modulefile\n${text_pad}Second line of whatis ${hi}token${nohi}s" +testouterr_cmd_re "csh" "-w 49 -t search token" "ERR" "[sgr {1;94}]$modpathre[sgr 0]:\nwhatis/lines: Testsuite Whatis Modulefile\nwhatis/lines: Second line of whatis ${hi}token${nohi}s" setenv_var MODULES_COLOR never unsetenv_var MODULES_COLORS diff --git a/testsuite/modules.70-maint/240-icase.exp b/testsuite/modules.70-maint/240-icase.exp index 5b8b5fa27..203c63166 100644 --- a/testsuite/modules.70-maint/240-icase.exp +++ b/testsuite/modules.70-maint/240-icase.exp @@ -161,7 +161,7 @@ testouterr_cmd sh {avail -i -t nOcAsE/vi} OK "$mp:\nnocase/virt" testouterr_cmd sh {avail -i -t NOCASE/Dee} OK "$mp:\nnocase/deep/(dirsym)\nnocase/deep/2\nnocase/deep/3" testouterr_cmd sh {avail -i -t NOcaSe2} OK "$mp:\nnocase2" testouterr_cmd sh {avail -i -t NOcase3} OK "$mp:\nnocase3(@)" -testouterr_cmd_re sh {whatis -i -t noCASE/aL*} OK "$modlin $mpre $modlin\n\\s+nocase/1: nocase/1" +testouterr_cmd_re sh {whatis -i -t noCASE/aL*} OK "$mpre:\nnocase/1: nocase/1" testouterr_cmd sh {paths -i noCASE/VE*} [list [list text $mp/nocase/1]] {} testouterr_cmd sh {whatis -i -t noCASE/aL} ERR $err_path'noCASE/aL' testouterr_cmd sh {paths -i noCASE/VE} OK {} @@ -174,7 +174,7 @@ testouterr_cmd_re sh {whatis -i noCASE/.hiDden} OK "$modlin $mpre $modlin\n\\s+n # add a bit of wildcard characters in specification testouterr_cmd sh {avail -i -t nOcAsE/vi?} OK "$mp:\nnocase/virt" -testouterr_cmd_re sh {whatis -i -t noCASE/a*L*} OK "$modlin $mpre $modlin\n\\s+nocase/1: nocase/1" +testouterr_cmd_re sh {whatis -i -t noCASE/a*L*} OK "$mpre:\nnocase/1: nocase/1" testouterr_cmd sh {whatis -i -t noCASE/a*L} ERR $err_path'noCASE/a*L' testouterr_cmd sh {paths -i noCASE/V*E?} OK {} testouterr_cmd sh {paths -i noCASE/V*E*} [list [list text $mp/nocase/1]] {}