From 7fc43fa7c4058476ba50cf5d5432dc4274bcb8ae Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 19 Feb 2023 21:04:06 +0000 Subject: texdoc (19feb23) git-svn-id: svn://tug.org/texlive/trunk@65938 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/man/man1/texdoc.1 | 12 +- Master/texmf-dist/doc/man/man1/texdoc.man1.pdf | Bin 27010 -> 25452 bytes Master/texmf-dist/doc/support/texdoc/NEWS | 16 ++ Master/texmf-dist/doc/support/texdoc/README.md | 38 +-- .../texmf-dist/doc/support/texdoc/texdoc-doc.cls | 12 +- Master/texmf-dist/doc/support/texdoc/texdoc.pdf | Bin 84314 -> 90076 bytes Master/texmf-dist/doc/support/texdoc/texdoc.tex | 94 ++++++- .../texmf-dist/scripts/texdoc/texdoclib-alias.tlu | 2 +- Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu | 93 ++++--- .../texmf-dist/scripts/texdoc/texdoclib-config.tlu | 87 +++++-- .../texmf-dist/scripts/texdoc/texdoclib-const.tlu | 276 +++++++++++++++++++-- .../texmf-dist/scripts/texdoc/texdoclib-score.tlu | 5 +- .../texmf-dist/scripts/texdoc/texdoclib-util.tlu | 114 ++++++++- .../texmf-dist/scripts/texdoc/texdoclib-view.tlu | 131 ++++++++-- Master/texmf-dist/scripts/texdoc/texdoclib.tlu | 2 +- Master/texmf-dist/texdoc/texdoc.cnf | 40 +-- 16 files changed, 747 insertions(+), 175 deletions(-) diff --git a/Master/texmf-dist/doc/man/man1/texdoc.1 b/Master/texmf-dist/doc/man/man1/texdoc.1 index e614721b832..c0a2250cc62 100644 --- a/Master/texmf-dist/doc/man/man1/texdoc.1 +++ b/Master/texmf-dist/doc/man/man1/texdoc.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "TEXDOC" "1" "March 2022" "Texdoc 3.4.1" "Texdoc manual" +.TH "TEXDOC" "1" "February 2023" "Texdoc 4.0" "Texdoc manual" . .SH "NAME" \fBtexdoc\fR \- find & view documentation in TeX Live @@ -86,6 +86,10 @@ Print the list of configuration files used\. \fB\-\-just\-view\fR FILE Display FILE, given with full path (no searching)\. . +.TP +\fB\-\-print\-completion\fR SHELL +Print SHELL completion\. +. .SH "ENVIRONMENT" The following environment variables can be split by colon and used to set viewers: . @@ -117,8 +121,8 @@ Set the command to be used for PS documents\. The following environment variables are also used: . .TP -\fBLANG\fR, \fBLC_ALL\fR and so on -Set the locale (which will influence on the search results)\. +\fBLANG\fR, \fBLC_ALL\fR, \fBLANGUAGE\fR, \fBLANGUAGE_texdoc\fR +Set the locale, which will influence on the search results\. . .TP \fBTEXDOCS\fR @@ -156,7 +160,7 @@ Texdoc home page: \fIhttp://tug\.org/texdoc/\fR Source: \fIhttps://github\.com/TeX\-Live/texdoc\fR . .SH "COPYRIGHT" -Copyright 2008\-2022 Manuel Pe\'gourie\'\-Gonnard, Takuto Asakura, the TeX Live Team\. +Copyright 2008\-2023 Manuel Pe\'gourie\'\-Gonnard, Takuto Asakura, the TeX Live Team\. . .br License: GNU GPL version 3 or later \fIhttp://gnu\.org/licenses/gpl\.html\fR\. diff --git a/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf b/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf index dfe06fb9730..8034eb038bc 100644 Binary files a/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf and b/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf differ diff --git a/Master/texmf-dist/doc/support/texdoc/NEWS b/Master/texmf-dist/doc/support/texdoc/NEWS index 64cb2199a94..cfb10ca9322 100644 --- a/Master/texmf-dist/doc/support/texdoc/NEWS +++ b/Master/texmf-dist/doc/support/texdoc/NEWS @@ -2,6 +2,22 @@ NEWS for texdoc =============== (This file public domain.) +Version 4.0 (TeX Live 2023) +=========================== +Released on 2023-02-20 + +Major changes +- Online search feature is added: + users using TL without documentation will be sent to texdoc.org +- Add new action --print-completion: + for the moment, only zsh is supported. Contributions welcome. + +Minor fixes and tweaks +- Reflect environment variables (e.g., LANGUAGE, LC_ALL, and LANG) before checking system locale +- Line continuation with tailing backslashes in config files +- Scoring adjustments +- Documentation tweaks + Version 3.4.1 ------------- - Bug fix: give locale bonus only if "lang" is set diff --git a/Master/texmf-dist/doc/support/texdoc/README.md b/Master/texmf-dist/doc/support/texdoc/README.md index 02150ce4703..57fa31a485e 100644 --- a/Master/texmf-dist/doc/support/texdoc/README.md +++ b/Master/texmf-dist/doc/support/texdoc/README.md @@ -21,15 +21,15 @@ If you want to try/test the develop version, please see below. The easiest way to install the develop version of Texdoc is using [Bundler](https://bundler.io/) and [Rake](https://github.com/ruby/rake): -``` -$ bundle install -$ rake install +```shell +bundle install +rake install ``` If you want to uninstall the develop version (to use the TeX Live version), just try: -``` -$ rake uninstall +```shell +rake uninstall ``` ### Installing manually @@ -50,50 +50,50 @@ You can make sure that the right files are used by running `texdoc --files`: the ## Building and Testing -Many building tasks are defined as [Rake](https://github.com/ruby/rake) tasks: +Many building tasks are defined as [Rake](https://github.com/ruby/rake) tasks. ### Generating all documentation The following will generate both the PDF and the manpage in `doc/` directory. -``` -$ rake doc +```shell +rake doc ``` ### Generating a pre-hashed cache file The following will generate a pre-hashed cache file `script/Data.tlpdb.lua`. This task have to be done under a TeX Live setup with tlpdb. -``` -$ rake gen_datafile +```shell +rake gen_datafile ``` ### Running tests The following will run all tests in `spec/` directory. -``` -$ rake test +```shell +rake test ``` Alternatively, you can give spec names with the `--list` (`-l`) option for this task. E.g., following will run only `spec/action/help_spec.rb` and `spec/mode/list_spec.rb`: -``` -$ rake test -- -l action/help,mode/list +```shell +rake test -- -l action/help,mode/list ``` ### Showing all available tasks Following will show all available tasks with a short description. -``` -$ rake -T +```shell +rake -T ``` In addition to that, for options available tasks, e.g., `rake test` and `rake run_texdoc`, you can get options information with `-h` option for each task: -``` -$ rake test -- -h +```shell +rake test -- -h ``` ## Further Information @@ -104,7 +104,7 @@ More specific information, such as the TODO list of this project and some inform ## Copyright and License -Copyright 2008-2021 Manuel Pégourié-Gonnard, Takuto Asakura, the TeX Live Team. +Copyright 2008-2023 Manuel Pégourié-Gonnard, Takuto Asakura, the TeX Live Team. This package is distributed under the terms of the GNU General Public License as published by the Free Software Foundation, either [version 3](./COPYING) of the License, or (at your option) any later version. diff --git a/Master/texmf-dist/doc/support/texdoc/texdoc-doc.cls b/Master/texmf-dist/doc/support/texdoc/texdoc-doc.cls index a9d229b6a71..5e960588ba3 100644 --- a/Master/texmf-dist/doc/support/texdoc/texdoc-doc.cls +++ b/Master/texmf-dist/doc/support/texdoc/texdoc-doc.cls @@ -1,9 +1,9 @@ % Document style for Texdoc user manual -% Copyright 2008-2020 Manuel Pégourié-Gonnard and Takuto Asakura +% Copyright 2008-2023 Manuel Pégourié-Gonnard and Takuto Asakura % distributed under the terms of GPL v3 or later \NeedsTeXFormat{LaTeX2e} \ProvidesClass{texdoc-doc} - [2020/02/02 Document class for Texdoc user manual] + [2023-02-17 Document class for Texdoc user manual] % class options \DeclareOption{draft}{\setlength\overfullrule{5pt}} @@ -163,7 +163,7 @@ \@for\@item:=#1\do{\@delim\@item}% \egroup} \newcommand*{\code}[1]{\bgroup - \chardef\_=`\_\code@font #1\egroup} + \chardef\_=`\_\chardef\~=`\~\code@font #1\egroup} \newcommand*{\sopt}[1]{\hyperlink{cl:#1}{\code{\hyph#1}}} \newcommand*{\lopt}[1]{\hyperlink{cl:#1}{\code{\hyph{}\hyph#1}}} \newcommand*{\ci}[1]{\bgroup @@ -219,6 +219,12 @@ \hypertarget{\@tmp@hyname}{\code{#1 = #2}}% \IfNoValueF{#3}{\hfill (#3)}% \begin{manual@entry}% + \bgroup% + \def\meta##1{##1}% + \def\_{\string_}% + \edef\conf@title{#1}% + \belowpdfbookmark{\conf@title}{\conf@title}% + \egroup% } {\ifvmode\else\unskip\fi\end{manual@entry}} diff --git a/Master/texmf-dist/doc/support/texdoc/texdoc.pdf b/Master/texmf-dist/doc/support/texdoc/texdoc.pdf index 5619830b780..f648933a2e1 100644 Binary files a/Master/texmf-dist/doc/support/texdoc/texdoc.pdf and b/Master/texmf-dist/doc/support/texdoc/texdoc.pdf differ diff --git a/Master/texmf-dist/doc/support/texdoc/texdoc.tex b/Master/texmf-dist/doc/support/texdoc/texdoc.tex index 689e6968775..0e1a0db3e80 100644 --- a/Master/texmf-dist/doc/support/texdoc/texdoc.tex +++ b/Master/texmf-dist/doc/support/texdoc/texdoc.tex @@ -1,6 +1,6 @@ -%#!xelatex +%#!texfot xelatex % Texdoc user manual -% Copyright 2008-2022 Manuel Pégourié-Gonnard and Takuto Asakura +% Copyright 2008-2023 Manuel Pégourié-Gonnard and Takuto Asakura % distributed under the terms of GPL v3 or later \documentclass{texdoc-doc} @@ -8,7 +8,7 @@ \subtitle{Find \& view documentation in \TL} \pkgurl{https://tug.org/texdoc/} \author{Manuel Pégourié-Gonnard\and Takuto Asakura} -\date{v3.4.1\quad \today} +\date{v4.0\quad \today} \begin{document} @@ -151,6 +151,12 @@ but rather intended to be used from another program, like a GUI front-end to Texdoc. \end{clopt} +\begin{clopt}{\code{\lopt{print-completion} \meta{shell}}} +Print |«shell»| completion. For the time being, it only supports +zsh\footnote{Your contributions are welcome!}. See +Section~\ref{sec:completion} for the details. +\end{clopt} + Some normal options such as \sopt{v} are effective for some actions but note that you have to specify such options \emph{before} the action option. Options after an action option will be ignored. @@ -257,8 +263,8 @@ Variable & Use for & Configuration item \\ \hline \end{tabular} \end{center} -Third, on Unix systems, locale-related variables such as |LANG| and |LC_ALL| -are used for the default value of \ci{lang}. +Third, locale-related variables |LANGUAGE_texdoc|, |LANGUAGE|, |LC_ALL|, and +|LANG| are used to set \ci{lang}. \subsection{Precedence of configuration sources} \label{sec:prec} @@ -504,6 +510,25 @@ allowance by using the configuration item \ci{fuzzy\_level}. Results of fuzzy search could be different among executions if multiple package names have the same Levenshtein distance to the input. +\subsection{Online Search} +\label{sec:online} + +If Texdoc cannot find any good matches for a document, it may sometimes prompt +you to search online. + +If you use the |view| option, there are no ``good'' matches (|score|${}\ge{}$0), +but you have some local documentation installed, Texdoc will show you the three +best locally-installed documents while also prompting you to search online. + +If you use the |view| option when you have no local documentation installed, +Texdoc will skip showing any fuzzy matches, and will instead prompt you to +search online immediately. + +Texdoc checks to see if the |kpathsea| documentation as a heuristic for if +\emph{any} documentation is installed. If the documentation for Texdoc is +installed, but no other documentation is installed, the online search prompt +may produce unexpected results. + \section{Configuration items} \label{sec:conf} @@ -511,7 +536,7 @@ Configuration files are line-oriented text files. Comments begin with a |#| and run to the end of line. Lines containing only space are ignored. Space at the beginning or end of a line, as well as around an |=| sign, is ignored. Apart from comments and empty lines, each line must be of one of the following -forms. +forms: % \begin{htcode} «configuration item» = «value» @@ -521,6 +546,9 @@ stopalias «original keyword» adjscore «pattern» = «score adjustment» adjscore(«keyword») «pattern» = «score adjustment» \end{htcode} +% +You can put a backslash (\code{\char`\\}) at the end of a line to indicate that +the line is continued on the following line. We will concentrate on the |«configuration item»| part here, since other directives have already been presented (Section~\ref{sec:alias} and @@ -727,11 +755,63 @@ Texdoc within a {\TL}-based {\TeX} distribution which does not ship |texlive.tlpdb|. \end{confitem} +\begin{confitem}{online\_url}{\meta{url}} + [default: \code{https://texdoc.org/serve/PKGNAME/0}] +Sets the \meta{url} to use for online documentation. Texdoc will replace +|PKGNAME| with the name of the package to search for. +\end{confitem} + +\section{Shell Completion} +\label{sec:completion} + +\subsection{Zsh} + +To enable completion for zsh, you need to put +% +\begin{htcode} +autoload -Uz compinit && compinit +\end{htcode} +% +in your zsh configuration file (such as \code{\~/.zshrc}). You can install our +completion function with either of the following two ways: +% +\begin{itemize} +\item adding \code{eval \$(texdoc \lopt{print-completion} zsh)} to your + zsh configuration file. + +\item adding the following file (also provided by + \href{https://github.com/zsh-users/zsh-completions}{zsh-completions}) to \\ + \code{/usr/share/zsh/site-functions/\_texdoc}: +% +\begin{htcode} +#compdef texdoc +(( $+functions[__texdoc] )) || eval "$(texdoc \textbackslash + --print-completion zsh)" && __texdoc +\end{htcode} +\end{itemize} + +You can confirm your installation by checking whether \code{\~/.zcompdump} +contains the following: +% +\begin{htcode} +'texdoc' '_texdoc' +\end{htcode} + +Note: The path \code{/usr/share} is for GNU/Linux. For other platforms, the +path can be: +% +\begin{description} +\item[macOS (homebrew, x86)] \verb|/usr/local/share| +\item[macOS (homebrew, arm)] \verb|/opt/homebrew/share| +\item[Android (Termux)] \verb|/data/data/com.termux/files/usr/share| +\item[Windows (Msys2 Mingw64)] \verb|/mingw64/share| +\end{description} + \section{Licence} \label{sec:licence} The current version of Texdoc program and its documentation are copyright -2008--2022 Manuel Pégourié-Gonnard, Takuto Asakura, the {\TL} Team. +2008--2023 Manuel Pégourié-Gonnard, Takuto Asakura, the {\TL} Team. They are free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-alias.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-alias.tlu index d430623a41c..09e6dacd0ab 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-alias.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-alias.tlu @@ -90,7 +90,7 @@ function M.get_patterns(name, no_alias) end -- interpret a confline as an alias setting or return false -function M.confline_to_alias(line, file, pos) +function M.confline_to_alias(line) -- alias directive without score local key, val = string.match(line, '^alias%s+([%w%p]+)%s*=%s*(.+)') if key and val then diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu index 5818af7f184..5eddc8f7f59 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu @@ -81,14 +81,17 @@ end local function parse_options() local curr_arg + local option local cl_config = {} - local function insert_cl_config(key, val, opt_name) - table.insert(cl_config, {key, val, opt_name}) - end - -- actual parsing - opts = getopt(arg, 'cd') + local optstring = '' + for _, o in pairs(C.options) do + if o['type'] == 'string' and o['short'] then + optstring = optstring .. o['short'] + end + end + local opts = getopt(arg, optstring) for _, tp in ipairs(opts) do local k, v = tp[1], tp[2] @@ -98,52 +101,28 @@ local function parse_options() curr_arg = '--' .. k end - -- action - if (curr_arg == '-h') or (curr_arg == '--help') then - return true, 'help', cl_config - elseif (curr_arg == '-V') or (curr_arg == '--version') then - return true, 'version', cl_config - elseif (curr_arg == '-f') or (curr_arg == '--files') then - return true, 'files', cl_config - elseif curr_arg == '--just-view' then - return true, 'view', cl_config - - -- mode - elseif (curr_arg == '-w') or (curr_arg == '--view') then - insert_cl_config('mode', 'view', curr_arg) - elseif (curr_arg == '-m') or (curr_arg == '--mixed') then - insert_cl_config('mode', 'mixed', curr_arg) - elseif (curr_arg == '-l') or (curr_arg == '--list') then - insert_cl_config('mode', 'list', curr_arg) - elseif (curr_arg == '-s') or (curr_arg == '--showall') then - insert_cl_config('mode', 'showall', curr_arg) - - -- interaction - elseif (curr_arg == '-I') or (curr_arg == '--nointeract') then - insert_cl_config('interact_switch', 'false', curr_arg) - elseif (curr_arg == '-i') or (curr_arg == '--interact') then - insert_cl_config('interact_switch', 'true', curr_arg) - - -- output format - elseif (curr_arg == '-M') or (curr_arg == '--machine') then - insert_cl_config('machine_switch', 'true', curr_arg) - - -- config - elseif curr_arg == '-c' then - insert_cl_config(v, nil, curr_arg) - - -- debug - elseif (curr_arg == '-d') or (curr_arg == '--debug') then - if v == true then v = 'all' end - insert_cl_config('debug_list', v, curr_arg) - elseif curr_arg == '-D' then - insert_cl_config('debug_list', 'all', curr_arg) - - -- verbosity - elseif (curr_arg == '-q') or (curr_arg == '--quiet') then - insert_cl_config('verbosity_level', C.min_verbosity, curr_arg) - elseif (curr_arg == '-v') or (curr_arg == '--verbose') then - insert_cl_config('verbosity_level', C.max_verbosity, curr_arg) + for i, o in ipairs(C.options) do + if k == o["short"] or k == o["long"] then + k = i + break + end + end + + option = C.options[k] + if option['group'] == 'action' then + if option['long'] == 'just-view' then + return true, 'view', cl_config + elseif option['long'] == 'print-completion' then + return true, 'complete', cl_config + else + return true, option['long'], cl_config + end + elseif option['group'] then + if option['type'] == 'boolean' then + option['action'](cl_config, curr_arg) + elseif option['type'] == 'string' then + option['action'](cl_config, curr_arg, v) + end -- having trouble else @@ -180,6 +159,18 @@ local function do_action(action) end texdoc.view.view_file(arg[1]) os.exit(C.exit_ok) + elseif action == 'complete' then + if not arg[1] then + err_print('error', 'Missing shell operand to --print-completion.') + err_print('error', C.error_msg) + os.exit(C.exit_usage) + elseif arg[1] == 'zsh' then + texdoc.util.print_zsh_completion() + os.exit(C.exit_ok) + else + err_print('error', arg[1] .. ' is not supported currently!') + os.exit(C.exit_error) + end end end diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu index 3f2dddb34a9..cf756b7b6a1 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu @@ -169,6 +169,19 @@ local function set_config_list(conf, context) end end +-- treat locale strings +local function parse_locale(lc_str) + local lang + + if lc_str:match('^[a-z][a-z]$') then -- the simplest + lang = lc_str + elseif lc_str:match('^[a-z][a-z]_') then -- such as 'en_US' + lang = lc_str:sub(1, 2) + end + + return lang +end + ------------------------ config from command-line ------------------------ -- set config from the command-line @@ -196,26 +209,45 @@ end -- set config from environment if available local function setup_config_from_env() - local function set_config_elt_from_vars(key, vars) + -- lang + local lc_env_vars = {'LANGUAGE_texdoc', 'LANGUAGE', 'LC_ALL', 'LANG'} + + for _, var in ipairs(lc_env_vars) do + local value = os.getenv(var) + + if type(value) == 'string' then + local lang = parse_locale(value) + if lang then + set_config_element('lang', lang, {src='env', name=var}) + end + end + end + + -- viewers + local function set_config_viewer_from_vars(key, vars) for _, var in ipairs(vars) do local value = os.getenv(var) + + -- support colon-separated list value = value and string.gmatch(value, '([^:]+)')() + if value then set_config_element(key, value, {src='env', name=var}) end end end - set_config_elt_from_vars('viewer_pdf', + + set_config_viewer_from_vars('viewer_pdf', {'PDFVIEWER_texdoc', 'PDFVIEWER', 'TEXDOCVIEW_pdf', 'TEXDOC_VIEWER_PDF'}) - set_config_elt_from_vars('viewer_ps', + set_config_viewer_from_vars('viewer_ps', {'PSVIEWER_texdoc', 'PSVIEWER', 'TEXDOCVIEW_ps', 'TEXDOC_VIEWER_PS'}) - set_config_elt_from_vars('viewer_dvi', + set_config_viewer_from_vars('viewer_dvi', {'DVIVIEWER_texdoc', 'DVIVIEWER', 'TEXDOCVIEW_dvi', 'TEXDOC_VIEWER_DVI'}) - set_config_elt_from_vars('viewer_html', + set_config_viewer_from_vars('viewer_html', {'BROWSER_texdoc', 'BROWSER', 'TEXDOCVIEW_html', 'TEXDOC_VIEWER_HTML'}) - set_config_elt_from_vars('viewer_md', + set_config_viewer_from_vars('viewer_md', {'MDVIEWER_texdoc', 'MDVIEWER', 'TEXDOCVIEW_md', 'TEXDOC_VIEWER_MD'}) - set_config_elt_from_vars('viewer_txt', + set_config_viewer_from_vars('viewer_txt', {'PAGER_texdoc', 'PAGER', 'TEXDOCVIEW_txt', 'TEXDOC_VIEWER_TXT'}) end @@ -239,8 +271,9 @@ local function read_config_file(configfile) local cnf = assert(io.open(configfile, 'r')) local lineno = 0 + local line_cont, line_buffer = false, '' while true do - local line=cnf:read('*line') + local line = cnf:read('*line') lineno = lineno + 1 if line == nil then break end -- EOF @@ -248,10 +281,22 @@ local function read_config_file(configfile) line = string.gsub(line, '%s*$', '') -- remove trailing spaces line = string.gsub(line, '^%s*', '') -- remove leading spaces + -- tailing \ indicates line continuation + if string.match(line, '\\$') then + line_cont = true + line = string.gsub(line, '\\$', '') + line_buffer = line_buffer .. line + goto continue + elseif line_cont then + line_cont = false + line = line_buffer .. line + line_buffer = '' + end + -- try to interpret the line local ok = string.match(line, '^%s*$') - or confline_to_alias(line, configfile, lineno) - or confline_to_score(line, configfile, lineno) + or confline_to_alias(line) + or confline_to_score(line) or confline_to_config(line, configfile, lineno) -- complain if it failed @@ -259,6 +304,8 @@ local function read_config_file(configfile) err_print('warning', 'syntax error in %s at line %d.', configfile, lineno) end + + ::continue:: end cnf:close() end @@ -357,21 +404,21 @@ end -- end scope of config_files ---------------------- config from locale settings ------------------------- -- set up the locale from the system setting --- Note that luatex set the locale to a neutral value for a reason, so we need --- to set the locale (for the category 'all') to nil to ignore it. +-- Note: luatex set the locale to a neutral value for a reason, so we need +-- to set the locale (for the category 'all') to nil to ignore it. local function setup_config_from_locale() local current, native, lang + current = os.setlocale(nil, 'all') -- save the default value os.setlocale('', 'all') -- set it to nil temporary native = os.setlocale(nil, 'all') -- get the actual system locale os.setlocale(current, 'all') -- put back the default value - if native == 'C' then -- the default C locale is en - lang = 'en' - else - lang = string.match(native, '^[a-z][a-z]') - end - if lang then - set_config_element('lang', lang, {src='loc'}) + + if type(native) == 'string' then + lang = parse_locale(native) + if lang then + set_config_element('lang', lang, {src='loc'}) + end end end @@ -545,6 +592,7 @@ local function setup_config_from_defaults() debug_list = '', max_lines = '20', fuzzy_level = '3', + online_url = 'https://texdoc.org/serve/PKGNAME/0', } -- zip-related options set_config_ls { @@ -558,7 +606,6 @@ end -- populate the config and alias arrays function M.setup_config_and_alias(cl_config) - -- setup config from all sources setup_config_from_cl(cl_config) setup_config_from_env() diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-const.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-const.tlu index 50d7ba4ca81..16acce71aae 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-const.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-const.tlu @@ -22,8 +22,8 @@ end -- progname and version fullname = kpse.find_file('texdoc/texdoclib', 'lua') progname = 'Texdoc' -version = '3.4.1' -release_date = '2022-03-19' +version = '4.0' +release_date = '2023-02-20' -- make sure to update setup_config_from_cl() accordingly -- and set a default value in setup_config_from_defaults() if relevant @@ -35,27 +35,14 @@ Try to find appropriate TeX documentation for the specified NAME(s). Alternatively, perform the given ACTION and exit. Options: - -w, --view Use view mode: start a viewer. (default) - -m, --mixed Use mixed mode (view or list). - -l, --list Use list mode: show a list of results. - -s, --showall Use showall mode: show also "bad" results. - - -i, --interact Use interactive menus. (default) - -I, --nointeract Use plain lists, no interaction required. - -M, --machine Machine-readable output for lists (implies -I). - - -q, --quiet Suppress warnings and most error messages. - -v, --verbose Print additional information (e.g., viewer command). - -D, --debug Activate all debug output (equal to "--debug=all"). - -d LIST, --debug=LIST - Activate debug output restricted to LIST. - -c NAME=VALUE Set configuration item NAME to VALUE. +{{mode}} + +{{interaction}} + +{{debug}} Actions: - -h, --help Print this help message. - -V, --version Print the version number. - -f, --files Print the list of configuration files used. - --just-view FILE Display FILE, given with full path (no searching). +{{action}} Full manual available via `texdoc texdoc'. @@ -63,8 +50,217 @@ Website: Repository: Please email bugs to .]] +zsh_completion = [[ +compdef __texdoc texdoc + +__texdoc() { + local options=( + {{action}} + + mode + {{mode}} + + interaction + {{interaction}} + + debug + {{debug}} + ) + _arguments -C -A $options \ + '*: :->arguments' && return + case $state in + arguments) + local tlpdb="$(kpsewhich -var-value TEXMFROOT)/tlpkg/texlive.tlpdb" + _values package $(awk '/^name[^.]*$/ {print $2}' $tlpdb) + ;; + esac +} +]] + +--[[ structure of the options table + +options = { + { + desc = description, + long = long option name, + short = short option name, + type = argument type (boolean|string), + group = group of the option, -- also used for shell completion + action = to be called + }, + ... +} +--]] + +options = { + -- action + { + desc = 'Print this help message.', + long = 'help', + short = 'h', + type = 'boolean', + group = 'action' + }, + { + desc = 'Print the version number.', + long = 'version', + short = 'V', + type = 'boolean', + group = 'action' + }, + { + desc = 'Print the list of configuration files used.', + long = 'files', + short = 'f', + type = 'boolean', + group = 'action' + }, + { + desc = 'Display FILE, given with full path (no searching).', + long = 'just-view', + type = 'string', + metavar = 'FILE', + complete = 'files', + group = 'action' + }, + { + desc = 'Print SHELL completion.', + long = 'print-completion', + type = 'string', + metavar = 'SHELL', + complete = {'zsh'}, + group = 'action', + }, + -- mode + { + desc = 'Use view mode: start a viewer. (default)', + long = 'view', + short = 'w', + type = 'boolean', + group = 'mode', + action = function(cl_config, opt_name) + table.insert(cl_config, {'mode', 'view', opt_name}) + end + }, + { + desc = 'Use mixed mode (view or list).', + long = 'mixed', + short = 'm', + type = 'boolean', + group = 'mode', + action = function(cl_config, opt_name) + table.insert(cl_config, {'mode', 'mixed', opt_name}) + end + }, + { + desc = 'Use list mode: show a list of results.', + long = 'list', + short = 'l', + type = 'boolean', + group = 'mode', + action = function(cl_config, opt_name) + table.insert(cl_config, {'mode', 'list', opt_name}) + end + }, + { + desc = 'Use showall mode: show also "bad" results.', + long = 'showall', + short = 's', + type = 'boolean', + group = 'mode', + action = function(cl_config, opt_name) + table.insert(cl_config, {'mode', 'showall', opt_name}) + end + }, + -- interaction + { + desc = 'Use interactive menus. (default)', + long = 'interact', + short = 'i', + type = 'boolean', + group = 'interaction', + action = function(cl_config, opt_name) + table.insert(cl_config, {'interact_switch', 'true', opt_name}) + end + }, + { + desc = 'Use plain lists, no interaction required.', + long = 'nointeract', + short = 'I', + type = 'boolean', + group = 'interaction', + action = function(cl_config, opt_name) + table.insert(cl_config, {'interact_switch', 'false', opt_name}) + end + }, + -- output format + { + desc = 'Machine-readable output for lists (implies -I).', + long = 'machine', + short = 'M', + type = 'boolean', + group = 'interaction', + action = function(cl_config, opt_name) + table.insert(cl_config, {'machine_switch', 'true', opt_name}) + end + }, + -- verbosity + { + desc = 'Suppress warnings and most error messages.', + long = 'quiet', + short = 'q', + type = 'boolean', + group = 'debug', + action = function(cl_config, opt_name) + table.insert(cl_config, {'verbosity_level', '0', opt_name}) + end + }, + { + desc = 'Print additional information (e.g., viewer command).', + long = 'verbose', + short = 'v', + type = 'boolean', + group = 'debug', + action = function(cl_config, opt_name) + table.insert(cl_config, {'verbosity_level', '3', opt_name}) + end + }, + -- debug + { + desc = 'Activate all debug output (equal to "--debug=all").', + short = 'D', + type = 'boolean', + group = 'debug', + action = function(cl_config, opt_name) + table.insert(cl_config, {'debug_list', 'all', opt_name}) + end + }, + { + desc = 'Activate debug output restricted to LIST.', + long = 'debug', + short = 'd', + metavar = 'LIST', + type = 'string', + complete = 'debugs', + group = 'debug', + action = function(cl_config, opt_name, val) + if val == true then val = 'all' end + table.insert(cl_config, {'debug_list', val, opt_name}) + end + }, + -- config + { + desc = 'Set configuration item NAME to VALUE.', + short = 'c', + metavar = 'NAME=VALUE', + type = 'string', + complete = 'options', + group = 'debug', + action = function(cl_config, opt_name, val) + table.insert(cl_config, {val, nil, opt_name}) + end + }, +} + copyright_msg = [[ -Copyright 2008-2022 Manuel Pégourié-Gonnard, Takuto Asakura, the TeX Live Team. +Copyright 2008-2023 Manuel Pégourié-Gonnard, Takuto Asakura, the TeX Live Team. License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it.]] @@ -91,17 +287,51 @@ known_options = { 'lang', 'fuzzy_level', 'texlive_tlpdb', + 'online_url', } error_msg = [[ Try `texdoc --help' for short help, `texdoc texdoc' for full manual.]] notfound_msg = [[ -Sorry, no documentation found for "PKGNAME". +Sorry, no local documentation found for "PKGNAME". +You can try the online version of Texdoc at . If you are unsure about the name, try full-text searching on CTAN. Search form: ]] notfound_msg_ph = 'PKGNAME' +badmatch_msg = [[ +Unfortunately, there are no good matches for "PKGNAME". + +Here are the top three matches: +]] +badmatch_msg_ph = 'PKGNAME' +badmatch_prompt = [[ +Enter number of file to view, Y to search online, or any other key to exit: ]] + +nomatch_msg = [[ +Unfortunately, there are no good matches for "PKGNAME". + +]] +nomatch_msg_ph = 'PKGNAME' + +nolocaldocs_msg = [[ +You don't appear to have any local documentation installed. + +]] +nolocaldocs_prompt = [[ +Would you like to search online? (y/N) ]] + +online_msg = [[ +There may be online documentation available for "PKGNAME" at + URL +This documentation may be for a different version than you have installed. + +]] +online_msg_url = 'URL' +online_msg_ph = 'PKGNAME' +online_baseurl_ph = 'PKGNAME' + -- exit codes exit_ok = 0 exit_error = 1 -- apparently hard-coded in Lua diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-score.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-score.tlu index d609224cea2..7124a834e4f 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-score.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-score.tlu @@ -30,7 +30,7 @@ local function set_score_table(tab, key, val) end -- interpret a confline as a score directive or return false -function M.confline_to_score(line, file, pos) +function M.confline_to_score(line) local keyw, pat, val -- try global adjscore pat, val = string.match(line, '^adjscore%s+([%w%p]+)%s*=%s*([%d+-.]+)') @@ -223,6 +223,9 @@ local function set_score(df, original_kw) if config_lang == file_lang then score = score + 1 dbg_score('Locale match bonus: +1.0') + elseif file_lang ~= nil then + score = score - 0.1 + dbg_score('Locale unmatch: -0.1') end end diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu index db043b150ee..445bfaf6bc7 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu @@ -143,7 +143,119 @@ end -- print a usage message function M.print_usage() - print(C.usage_msg) + local groups = { + action = {}, + mode = {}, + interaction = {}, + debug = {}, + } + for _, opt in ipairs(C.options) do + local line = '' + local shortopt = '' + local longopt = '' + if opt['short'] then + if opt['short'] == 'D' then + opt['long'] = 'debug' + end + if opt['metavar'] then + shortopt = '-' .. opt['short'] .. ' ' .. opt['metavar'] + else + shortopt = '-' .. opt['short'] + end + end + if opt['long'] then + if opt['metavar'] then + local sep = '=' + if opt['group'] == 'action' then + sep = ' ' + end + longopt = '--' .. opt['long'] .. sep .. opt['metavar'] + else + longopt = '--' .. opt['long'] + end + end + if #shortopt > 0 and #longopt > 0 then + line = ' ' .. shortopt .. ', ' .. longopt + elseif #shortopt > 0 then + line = ' ' .. shortopt + elseif #longopt > 0 then + line = ' ' .. longopt + end + if #line > 20 then + line = line .. "\n" + end + for _ = 1, 20 - #string.gsub(line, ".*\n", '') do + line = line .. ' ' + end + line = line .. opt['desc'] + table.insert(groups[opt['group']], line) + end + local usage_msg = C.usage_msg + for k, v in pairs(groups) do + usage_msg = string.gsub(usage_msg, '{{' .. k .. '}}', table.concat(v, "\n")) + end + print(usage_msg) +end + +function M.print_zsh_completion() + local groups = { + action = {}, + mode = {}, + interaction = {}, + debug = {}, + } + local option = '' + local complete = '' + local choices = {} + local prefix = '' + for _, opt in ipairs(C.options) do + local stop_completions = {opt['group']} + if opt['group'] == 'action' then + stop_completions = {'-', ':', '*'} + end + prefix = '"(' .. table.concat(stop_completions, ' ') .. ')"' + if opt['short'] and opt['long'] then + if opt['long'] == 'debug' then + option = '{-' .. opt['short'] .. ',--' .. opt['long'] .. '=-}' + else + option = '{-' .. opt['short'] .. ',--' .. opt['long'] .. '}' + end + elseif opt['short'] then + option = '-' .. opt['short'] + elseif opt['long'] then + option = '--' .. opt['long'] + end + option = prefix .. option .. '"[' .. opt['desc'] .. ']' + if opt['type'] == 'string' then + if opt['complete'] == 'options' then + choices = {} + for _, v in pairs(C.known_options) do + v = string.gsub(v, '%.%*', '') + table.insert(choices, v) + end + elseif opt['complete'] == 'debugs' then + choices = {} + for i, _ in pairs(C.known_debugs) do + table.insert(choices, i) + end + elseif type(opt['complete']) == 'table' then + choices = opt['complete'] + end + complete = '(' .. table.concat(choices, ' ') .. ')' + if opt['complete'] == 'files' then + opt['metavar'] = ' ' + complete = '_files' + end + option = option .. ':' .. string.lower(opt['metavar']) .. ':' .. complete + end + option = option .. '"' + table.insert(groups[opt['group']], option) + end + local completion = C.zsh_completion + for k, v in pairs(groups) do + completion = string.gsub(completion, '{{' .. k .. '}}', table.concat(v, "\n ")) + end + print(completion) end return M diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu index 49148ea976b..3bf6860a35f 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu @@ -7,6 +7,7 @@ local texdoc = { const = require('texdoclib-const'), util = require('texdoclib-util'), config = require('texdoclib-config'), + search = require('texdoclib-search'), } -- shortcuts @@ -116,6 +117,10 @@ function M.view_file(filename) -- files without extension are assumed to be text local viewext = (filename:match('.*%.([^/]*)$') or 'txt'):lower() + if filename:match('^http') then + viewext = 'html' + end + -- special case : sty files use txt viewer -- FIXME: hardcoding such cases this way is not very clean if viewext == 'sty' then viewext = 'txt' end @@ -164,8 +169,8 @@ local function print_menu(name, doclist, showall) -- there may be too many lines, count them local n = 0 for _, doc in pairs(doclist) do - if doc.quality == 'good' or - (showall and doc.quality ~= 'killed') then + if doc:get_quality() == 'good' or + (showall and doc:get_quality() ~= 'killed') then n = n + 1 end end @@ -180,24 +185,41 @@ local function print_menu(name, doclist, showall) end end end - local i, doc, last_i - for i, doc in ipairs(doclist) do - if doc.quality == 'killed' then break end - if doc.quality ~= 'good' and not showall then break end - if texdoc.config.get_value('machine_switch') == true then - print(name, doc.score, texdoc.util.w32_path(doc.realpath), - doc.lang or '', doc.details or '') - else + local last_i + while true do + for i, doc in ipairs(doclist) do + if doc:get_quality() == 'killed' then break end + if doc:get_quality() ~= 'good' and not showall then break end + last_i = i -- save for test below - print(string.format('%2d %s', i, texdoc.util.w32_path(doc.realpath))) - if doc.details or doc.lang then - local line = ' = ' - if doc.lang then line = line .. '[' .. doc.lang .. '] ' end - if doc.details then line = line .. doc.details end - print(line) + if texdoc.config.get_value('machine_switch') == true then + print(name, doc.score, texdoc.util.w32_path(doc.realpath), + doc.lang or '', doc.details or '') + else + print(string.format('%2d %s', i, texdoc.util.w32_path(doc.realpath))) + if doc.details or doc.lang then + local line = ' = ' + if doc.lang then line = line .. '[' .. doc.lang .. '] ' end + if doc.details then line = line .. doc.details end + print(line) + end end end + + if last_i or showall then + break + else + err_print('warning', 'No good result found, showing all results.') + showall = true + end + end + + if not last_i then + local msg = string.gsub(C.notfound_msg, C.notfound_msg_ph, name) + io.stderr:write(msg .. '\n') -- get rid of gsub's 2nd value + os.exit(C.exit_notfound) end + if texdoc.config.get_value('interact_switch') then io.write('Enter number of file to view, RET to view 1, anything else to skip: ') local num_str = io.read('*line') @@ -211,31 +233,86 @@ local function print_menu(name, doclist, showall) end end +local function search_online(name, doclist) + if not texdoc.config.get_value('interact_switch') or + texdoc.config.get_value('machine_switch') + then + view_doc(doclist[1]) + return + end + + local function write(msg) + io.stderr:write(msg .. '') -- cast to string + end + -- Fuzzy heuristic to see if the user has _any_ local documentation + local kpathsea_docs = texdoc.search.get_doclist("kpathsea") + local docs_installed = kpathsea_docs[1] and + kpathsea_docs[1].basename == "kpathsea.pdf" and + not os.getenv("TEXDOC_NO_LOCAL_DOCS") + + if docs_installed and doclist[1] then + write(C.badmatch_msg:gsub(C.badmatch_msg_ph, name)) + + for i=1,3 do + local doc = (doclist[i] and doclist[i].normname) or '' + write(' ' .. i .. ' ' .. doc .. '\n') + end + write('\n') + elseif docs_installed then + write(C.nomatch_msg:gsub(C.nomatch_msg_ph, name)) + else + write(C.nolocaldocs_msg) + end + + local url = texdoc.config.get_value('online_url') + :gsub(C.online_baseurl_ph, name) + + write(C.online_msg:gsub(C.online_msg_url, url) + :gsub(C.online_msg_ph, name)) + + if docs_installed and doclist[1] then + write(C.badmatch_prompt) + else + write(C.nolocaldocs_prompt) + end + + local ans = io.read('*line') + + if ans:match('^\r?[yY]') then + M.view_file(url) + elseif tonumber(ans) then + view_doc(doclist[tonumber(ans)]) + end +end + ----------------------- deliver results based on mode --------------------- function M.deliver_results(name, doclist, many) -- ensure that results were found or apologize - if not doclist[1] or doclist[1].quality == 'killed' then + if (not doclist[1] or doclist[1]:get_quality() == 'killed') and + not texdoc.config.get_value('interact_switch') + then local msg = string.gsub(C.notfound_msg, C.notfound_msg_ph, name) io.stderr:write(msg .. '\n') -- get rid of gsub's 2nd value os.exit(C.exit_notfound) end -- shall we show all of them or only the "good" ones? - local showall = (texdoc.config.get_value('mode') == 'showall') - if not showall and doclist[1].quality ~= 'good' then - showall = true - err_print('info', 'No good result found, showing all results.') - end + local mode = texdoc.config.get_value('mode') + -- view result or show menu based on mode and number of results - if (texdoc.config.get_value('mode') == 'view') - or texdoc.config.get_value('mode') == 'mixed' and (not doclist[2] - or (doclist[2].quality ~= 'good' and not showall)) then + if (mode == 'view' and doclist[1] and doclist[1]:get_quality() == 'good') or + (mode == 'mixed' and + (not doclist[2] or doclist[2]:get_quality() ~= 'good') + ) + then view_doc(doclist[1]) - else + elseif mode ~= 'view' then if many and not texdoc.config.get_value('machine_switch') then print('*** Results for: ' .. name .. ' ***') end - print_menu(name, doclist, showall) + print_menu(name, doclist, mode == 'showall') + else + search_online(name, doclist) end end diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib.tlu index 3c0f66c1d28..83c300833e8 100644 --- a/Master/texmf-dist/scripts/texdoc/texdoclib.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib.tlu @@ -1,7 +1,7 @@ -- texdoclib.tlu: the texdoc library --[[ -Copyright 2008-2022 Manuel Pégourié-Gonnard, Takuto Asakura, the TeX Live Team. +Copyright 2008-2023 Manuel Pégourié-Gonnard, Takuto Asakura, the TeX Live Team. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/Master/texmf-dist/texdoc/texdoc.cnf b/Master/texmf-dist/texdoc/texdoc.cnf index d5e7d7afd1f..7ba7d538def 100644 --- a/Master/texmf-dist/texdoc/texdoc.cnf +++ b/Master/texmf-dist/texdoc/texdoc.cnf @@ -85,7 +85,9 @@ # badbasename_list = readme, 00readme # Known suffixes for documentation -suffix_list = doc, -doc, _doc, .doc, /doc, manual, /manual, -manual, userguide, /user_guide, -guide, -user, man, -man, notes, -info, ref +suffix_list = doc, -doc, _doc, .doc, /doc, manual, /manual, -manual, \ + userguide, /user_guide, -guide, -user, man, -man, \ + -documentation, notes, -info, ref ## Fuzzy search @@ -93,6 +95,13 @@ suffix_list = doc, -doc, _doc, .doc, /doc, manual, /manual, -manual, userguide, # # fuzzy_level = 3 +## Online URL + +# Here you can configure the URL to prompt the user to open when Texdoc +# is unable to find any local matches. + +# online_url = https://texdoc.org/serve/PKGNAME/0 + # Score adjustments # ================= @@ -290,7 +299,7 @@ alias xelatex = xetex-reference alias e-tex = etex_man alias etex = etex_man alias pdftex = pdftex-a -#alias xetex = xetex-reference # OK +alias xetex = xetex-reference # needed by packages with "xetex" in their names alias xelatex = xetex-reference alias e-tex-man = etex.man1 @@ -369,18 +378,18 @@ alias amsproc-dev = amsclass alias amsmath-dev = amsmath # koma-script -alias koma = scrguien -alias koma-script = scrguien -alias scrartcl = scrguien -alias scrbook = scrguien -alias scrreprt = scrguien -alias typearea = scrguien -alias koma-de = scrguide -alias koma-script-de = scrguide -alias scrartcl-de = scrguide -alias scrbook-de = scrguide -alias scrreprt-de = scrguide -alias typearea-de = scrguide +alias koma = scrguide-en +alias koma-script = scrguide-en +alias scrartcl = scrguide-en +alias scrbook = scrguide-en +alias scrreprt = scrguide-en +alias typearea = scrguide-en +alias koma-de = scrguide-de +alias koma-script-de = scrguide-de +alias scrartcl-de = scrguide-de +alias scrbook-de = scrguide-de +alias scrreprt-de = scrguide-de +alias typearea-de = scrguide-de # tugboat package and classes alias tugboat = ltubguid @@ -459,9 +468,6 @@ alias llmk = light-latex-make/llmk alias(2) llmk = light-latex-make/README alias mls = montex alias musixtex = musixdoc -alias newcm = newcomputermodern/README -alias(5) newcm = newcomputermodern/newcomputermodern-sample.pdf -alias(5) newcm = newcomputermodern/newcm-unimath-symbols.pdf alias newtxtext = newtxdoc alias newtxmath = newtxdoc alias nonfloat = nonfloat-en -- cgit v1.2.3