diff options
author | Karl Berry <karl@freefriends.org> | 2019-03-28 20:58:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-03-28 20:58:51 +0000 |
commit | 58f64f141bad7d97ff02df9375bc53453444ba46 (patch) | |
tree | 5d6444f973219154f144330bd86f113510bd6910 /Master/texmf-dist | |
parent | f8c6d58ac3a950c7c156180064a167d575d38576 (diff) |
texdoc (28mar19)
git-svn-id: svn://tug.org/texlive/trunk@50627 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
21 files changed, 2282 insertions, 2008 deletions
diff --git a/Master/texmf-dist/doc/man/man1/texdoc.1 b/Master/texmf-dist/doc/man/man1/texdoc.1 index 943cf71478c..cf072bd5fce 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" "June 2018" "Texdoc 3.0" "Texdoc manual" +.TH "TEXDOC" "1" "March 2019" "Texdoc 3.1" "Texdoc manual" . .SH "NAME" \fBtexdoc\fR \- find & view documentation in TeX Live @@ -10,29 +10,11 @@ \fBtexdoc\fR [OPTION\.\.\.] NAME\.\.\. . .br -\fBtexdoc\fR ACTION +\fBtexdoc\fR [OPTION\.\.\.] ACTION . .SH "DESCRIPTION" Try to find appropriate TeX documentation for the specified NAME(s)\. Alternatively, perform the given ACTION and exit\. . -.SH "ACTIONS" -. -.TP -\fB\-h\fR, \fB\-\-help\fR -Print this help message\. -. -.TP -\fB\-V\fR, \fB\-\-version\fR -Print the version number\. -. -.TP -\fB\-f\fR, \fB\-\-files\fR -Print the list of configuration files used\. -. -.TP -\fB\-\-just\-view FILE\fR -Display file, given with full path (no searching)\. -. .SH "OPTIONS" . .TP @@ -69,22 +51,97 @@ Suppress warnings and most error messages\. . .TP \fB\-v\fR, \fB\-\-verbose\fR -Print additional information (eg, viewer command)\. +Print additional information (e\.g\., viewer command)\. . .TP \fB\-D\fR, \fB\-\-debug\fR Activate all debug output (equal to "\-\-debug=all")\. . .TP -\fB\-d\fRLIST, \fB\-\-debug\fR=LIST -Activate debug output restricted to LIST\. +\fB\-d\fR LIST, \fB\-\-debug\fR=LIST +Activate debug output restricted to the items specified in LIST\. +. +.br +Available items: \fBconfig\fR, \fBfiles\fR, \fBsearch\fR, \fBscore\fR, \fBtexdocs\fR, \fBtlpdb\fR, \fBversion\fR, \fBview\fR, and \fBall\fR to activate all of these\. +. +.TP +\fB\-c\fR NAME=VALUE +Set configuration item NAME to VALUE\. +. +.SH "ACTIONS" +. +.TP +\fB\-h\fR, \fB\-\-help\fR +Print this help message\. +. +.TP +\fB\-V\fR, \fB\-\-version\fR +Print the version number\. +. +.TP +\fB\-f\fR, \fB\-\-files\fR +Print the list of configuration files used\. +. +.TP +\fB\-\-just\-view\fR FILE +Display FILE, given with full path (no searching)\. . .SH "ENVIRONMENT" -PAGER, BROWSER, PDFVIEWER, PSVIEWER, DVIVIEWER, and *_texdoc of each\. +. +.TP +\fBBROWSER\fR, \fBBROWSER_texdoc\fR +Set the command to be used for HTML documents\. +. +.TP +\fBDVIVIEWER\fR, \fBDVIVIEWER_texdoc\fR +Set the command to be used for DVI documents\. +. +.TP +\fBMDVIEWER\fR, \fBMDVIEWER_texdoc\fR +Set the command to be used for Markdown documents\. +. +.TP +\fBPAGER\fR, \fBPAGER_texdoc\fR +Set the command to be used for text documents\. +. +.TP +\fBPDFVIEWER\fR, \fBPDFVIEWER_texdoc\fR +Set the command to be used for PDF documents\. +. +.TP +\fBPSVIEWER\fR, \fBPSVIEWER_texdoc\fR +Set the command to be used for PS documents\. +. +.TP +\fBLANG\fR, \fBLC_ALL\fR and so on +Set the locale (which will influence on the search results)\. +. +.TP +\fBTEXDOCS\fR +In addition to the documents included in the TeX Live database, Texdoc also searches documentation under TEXMF trees specified by the kpathsea variable \fBTEXDOCS\fR\. . .SH "FILES" \fB<texmf>/texdoc/texdoc\.cnf\fR, see output of the \fB\-\-files\fR option\. . +.SH "EXIT STATUS" +The \fBtexdoc\fR command exists with one of the following values: +. +.TP +0 +Success\. +. +.TP +1 +Internal error\. +. +.TP +2 +Usage error\. +. +.TP +3 +No documentation found\. +. .SH "REPORTING BUGS" Report bugs to \fItexdoc@tug\.org\fR\. . diff --git a/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf b/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf Binary files differindex a1c601652fb..b3af528aebe 100644 --- a/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf +++ b/Master/texmf-dist/doc/man/man1/texdoc.man1.pdf diff --git a/Master/texmf-dist/doc/support/texdoc/NEWS b/Master/texmf-dist/doc/support/texdoc/NEWS index 27c1853677d..430c925d24f 100644 --- a/Master/texmf-dist/doc/support/texdoc/NEWS +++ b/Master/texmf-dist/doc/support/texdoc/NEWS @@ -2,6 +2,14 @@ NEWS for texdoc =============== (This file public domain.) +Version 3.1 (TeX Live 2019) +=========================== +- New option -c: changing configure temporally +- New config item `texlive_tlpdb` to specify a path for texlive.tlpdb +- Fixed an issue that texdoc fails to open gzipped file in GNOME/XFCE +- Added prefixes to script files not to contaminate kpse search space +- Many other small improvements and bug fixes + Version 3.0 (TeX Live 2018) =========================== This version has two big features: diff --git a/Master/texmf-dist/doc/support/texdoc/README.md b/Master/texmf-dist/doc/support/texdoc/README.md index 19b0208825a..f0da3fc2341 100644 --- a/Master/texmf-dist/doc/support/texdoc/README.md +++ b/Master/texmf-dist/doc/support/texdoc/README.md @@ -1,6 +1,7 @@ -# Texdoc (v3.0) +# Texdoc v3.1 (2019-03-28) [![Build Status](https://travis-ci.org/TeX-Live/texdoc.svg?branch=master)](https://travis-ci.org/TeX-Live/texdoc) +[![Build status](https://ci.appveyor.com/api/projects/status/uq28ms7eba7ns6d3/branch/master?svg=true)](https://ci.appveyor.com/project/wtsnjp/texdoc/branch/master) Texdoc is a command line program to find and view documentation in TeX Live. @@ -55,7 +56,7 @@ Many building tasks are defined as [Rake](https://github.com/ruby/rake) tasks: ### Generating all documentation -This will generate both the PDF and the manpage in `doc/` directory. +Following will generate both the PDF and the manpage in `doc/` directory. ``` $ rake doc @@ -63,37 +64,49 @@ $ rake doc ### Generating a pre-hashed cache file -This will generate a pre-hashed cache file `script/Data.tlpdb.lua`. This task have to be done under a TeX Live setup with tlpdb. +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 ``` -### Running all tests +### Running tests -This will run all tests in `spec/` directory. +Following will run all tests in `spec/` directory. ``` $ 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 +``` + ### Showing all available tasks -This will show all available tasks with a short discription. +Following will show all available tasks with a short description. ``` $ 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 +``` + ## Further Information -More specific information (e.g. TODO) can be found in the Wiki of our GitHub repository. Please visit: +More specific information (e.g., TODO) can be found in the Wiki of our GitHub repository. Please visit: * <https://github.com/TeX-Live/texdoc/wiki> ## Copyright and License -Copyright 2008-2018 Manuel Pégourié-Gonnard, Takuto Asakura, Karl Berry, and Norbert Preining. All rights reserved. +Copyright 2008 Manuel Pégourié-Gonnard, Takuto Asakura, and 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.pdf b/Master/texmf-dist/doc/support/texdoc/texdoc.pdf Binary files differindex 1606e91d33b..d897017714d 100644 --- a/Master/texmf-dist/doc/support/texdoc/texdoc.pdf +++ b/Master/texmf-dist/doc/support/texdoc/texdoc.pdf diff --git a/Master/texmf-dist/doc/support/texdoc/texdoc.tex b/Master/texmf-dist/doc/support/texdoc/texdoc.tex index a300236ae67..37b44602591 100644 --- a/Master/texmf-dist/doc/support/texdoc/texdoc.tex +++ b/Master/texmf-dist/doc/support/texdoc/texdoc.tex @@ -1,13 +1,11 @@ +%#!xelatex % Texdoc user manual -% Copyright 2018 Manuel Pégourié-Gonnard and Takuto Asakura +% Copyright 2008 Manuel Pégourié-Gonnard and Takuto Asakura % distributed under the terms of GPL v3 or later -%!TEX encoding=utf-8 -%!TEX program=xelatex - \setlength\overfullrule{5pt} -\documentclass[a4paper, oneside]{scrartcl} +\documentclass[a4paper,oneside]{scrartcl} \usepackage{fontspec} \usepackage{xunicode} @@ -19,13 +17,13 @@ \newcommand\mylangle{$\langle$} \newcommand\myrangle{$\rangle$} -\usepackage{xargs, xspace, fancyvrb, xcolor, pifont, calc, ifmtarg, mathstyle} +\usepackage{xargs,xspace,fancyvrb,xcolor,pifont,calc,ifmtarg,mathstyle} -\usepackage[sf, bf]{titlesec} +\usepackage[sf,bf]{titlesec} \titlelabel{\makebox[0pt][r]{\thetitle\kern1pc}} -\titleformat{\subsubsection}[runin]{\itshape}{% - \makebox[0pt][r]{\thetitle\kern1pc}}{% - 0pt}{}[\maybedot\space --- \kern0pt] +\titleformat{\subsubsection}[runin]{\itshape} + {\makebox[0pt][r]{\thetitle\kern1pc}} + {0pt}{}[\maybedot\space --- \kern0pt] \titlespacing{\subsubsection}{0pt}{0.5\baselineskip}{0pt} \usepackage{enumitem} @@ -40,7 +38,8 @@ pdftitle={Texdoc: find and view documentation in TeX Live}, pdfauthor={Manuel Pégourié-Gonnard, Takuto Asakura}, pdfsubject={Texdoc's user manual}, - pdfkeywords={Texdoc, TeX Live, manual, documentation}} + pdfkeywords={Texdoc, TeX Live, manual, documentation}, +} \usepackage[yyyymmdd]{datetime} \renewcommand{\dateseparator}{-} @@ -68,15 +67,13 @@ formatcom=\cofont, defineactive=\makeallfancy, codes=\fancyactives, - } -\newcommand\fancyactives{% - \catcode`\«\active} -\newcommand\makeallfancy{% - \makefancyog} -{\catcode`\«\active -\global\def\makefancyog{% - \def«##1»{\meta{##1}}} } +\newcommand\fancyactives{\catcode`\«\active} +\newcommand\makeallfancy{\makefancyog} +\bgroup + \catcode`\«\active + \global\def\makefancyog{\def«##1»{\meta{##1}}} +\egroup \newif\ifframed \newlength\dec @@ -88,7 +85,7 @@ \def\bmtext{#2}% \def\thelabel{#3}% \SaveVerbatim[samepage, gobble=2]{verbmat}% - }{% +}{% \endSaveVerbatim \xdef\sectioncmd{\noexpand\nodotthistime \thecmd[\bmtext]{% @@ -100,32 +97,31 @@ \BUseVerbatim{verbmat}}% \fi \noexpand\label{\thelabel}}}% - \aftergroup\sectioncmd} + \aftergroup\sectioncmd +} \makeatother \newcommand\maybedot{.} -\newcommand\nodotthistime{% - \renewcommand\maybedot{% - \global\def\maybedot{.}}} +\newcommand\nodotthistime{\renewcommand\maybedot{\global\def\maybedot{.}}} -\newenvironment{cmdsubsec}[2]{% - \framedtrue \commandes\subsection{#1}{#2}% - }{% - \endcommandes} +\newenvironment{cmdsubsec}[2] + {\framedtrue \commandes\subsection{#1}{#2}} + {\endcommandes} -\newenvironment{cmdsubsub}[2]{% - \framedfalse \commandes\subsubsection{#1}{#2}% - }{% - \endcommandes} +\newenvironment{cmdsubsub}[2] + {\framedfalse \commandes\subsubsection{#1}{#2}} + {\endcommandes} \makeatletter -\newenvironment{htcode}{% % code en hors-texte - \SaveVerbatim[samepage, gobble=2]{verbmat}% - }{% - \endSaveVerbatim - \par\medskip\noindent\hspace*{\parindent}% - \BUseVerbatim{verbmat}% - \par\medskip\@endpetrue} +% code in hors-text +\newenvironment{htcode} + {\SaveVerbatim[samepage, gobble=2]{verbmat}} + { + \endSaveVerbatim + \par\medskip\noindent\hspace*{\parindent}% + \BUseVerbatim{verbmat}% + \par\medskip\@endpetrue + } \makeatother \DefineShortVerb{\|} @@ -139,7 +135,7 @@ \subtitle{Find \& view documentation in \texlive\\ \href{https://tug.org/texdoc/}{https://tug.org/texdoc/}} \author{Manuel Pégourié-Gonnard\and Takuto Asakura} -\date{v3.0 \today} +\date{v3.1\quad \today} \begin{document} \VerbatimFootnotes @@ -150,7 +146,7 @@ \subsection{Basics} -Texdoc is a command line tool which search and view documentations in \texlive. +Texdoc is a command line tool which find and view documentation in \texlive. If you type % \begin{quote} @@ -158,21 +154,21 @@ If you type \end{quote} % in your command line, the documentation of the |«name»| package will pop up. Of -course, replace |«name»| with the actual name of the package. To look up the -documentation of more than one package at once, just use multiple |«name»|s as -arguments. +course, you have to replace |«name»| with the actual name of the package. To +look up the documentation of more than one package at once, just use multiple +|«name»|s as arguments. \subsection{Modes}\label{ss-modes} Texdoc has different modes that determine how results will be handled. In the -default, ``view'' mode, it opens the first (supposedly the best) result in a -viewer. It is rather handy when you know what you want to read, and want to -access it quickly. On the other hand, there may be other relevant documents -for the given |«name»|, which are ignored in view mode. +default, ``view'' mode, it opens the first (supposedly the best) result with a +suitable viewer. It is rather handy when you know what you want to read, and +want to access it quickly. On the other hand, there may be other relevant +documents for the given |«name»|, which are ignored in view mode. The so-called ``list mode'' makes Texdoc list all relevant documentation and -ask you which one you want to view. It is useful when there a other -interesting sources of information besides the package's main documentation. +ask you which one you want to view. It is useful when there another interesting +sources of information besides the package's main documentation. There is also a ``mixed'' mode, intended to combine the best of view mode and list mode: if there is only one relevant result, then Texdoc opens it in a @@ -194,14 +190,14 @@ configurations files. \subsection{Configuration files}\label{ss-quick-file} Use |texdoc --files| to know where to put your personal configuration file; -you'll need to create this file (an possibly some directories) the first time. +you'll need to create this file (a possibly some directories) the first time. (If you want to know the full list of possible configuration files, see~\ref{ss-prec}.) -In order to select you favorite mode, just insert a line |mode = «yourmode»| -in this file, where |«yourmode»| is one of |view|, |mixed|, |list| or -|showall|. To set your favorite language, use |lang = «2-letter code»|, though -it is usually detected automatically. +In order to select you favorite mode, just insert a line |mode = «mode»| in +this file, where |«mode»| is one of |view|, |mixed|, |list| or |showall|. To +set your favorite language, use |lang = «2-letter code»|, though it is usually +detected automatically. The configuration file can be used to tweak Texdoc in many ways, the most useful of which is probably the selection of the viewers for various types of @@ -210,7 +206,7 @@ documents, explained in the next section. \subsection{Viewers}\label{ss-viewer} Texdoc's mechanism for choosing a viewer varies according to your platform. -On Windows, macOS, or Unix with KDE, Gnome or XFCE, it uses your file +On Windows, macOS, or Unix with KDE, GNOME, or XFCE, it uses your file associations like when you double-click files in the Explorer, the Finder or your default file manager (except for the text viewer, which is always a pager). Otherwise, it tries to find a viewer in the path from a list of @@ -225,13 +221,13 @@ insert the line |viewer_pdf = xpdf %s &| in your configuration file. Here, \subsection{You can stop reading now} -The next part explains Texdoc mechanisms for finding the best results and how -to cutomize them. The default configuration file tries hard to set appropriate -values so that you normally don't need to fiddle with that, but you may be -curious or have special needs. +Following parts explain Texdoc's mechanisms for finding the best results and +how to customize them. We have been trying hard to optimize the default +configuration values so that you normally don't need to fiddle with that, but +you may be curious or have special needs. The final part is a full reference including a few points omitted in the -present and next part. +present and next parts. \clearpage @@ -247,7 +243,7 @@ sources: selects all files containing |«keyword»| in their name (including the directory name); \item In the \texlive Database, it looks for packages named - |«keyword»| or containing a file |«keyword».«ext»| where |«ext»| may me + |«keyword»| or containing a file |«keyword».«ext»| where |«ext»| may be |sty| or |cls|, and selects all the documentation files from this package. \end{enumerate} Files are filtered by extension: only files with known extensions may be @@ -255,7 +251,7 @@ selected. In case Texdoc cannot find any documentation here, fuzzy search will find the closest package name to the |«keyword»| and reselect the files (see \ref{ss-fuzzy}). -The selected files are then score according to some simple heuristics. For +The selected files are then score according to some simple heuristics. For example, a file named |«keyword».pdf|, is good, |«keyword»-«lang».pdf| will score higher if your favorite language |«lang»| is detected or configured, |«keyword»-doc| will be preferred over |«keyword»whatever|, files in a @@ -282,7 +278,7 @@ or, more likely, to recognize which of the files found is the most relevant. For example, assume you are looking for the documentation of the shortvrb {\LaTeX} package. Texdoc will find |shortvrb.sty| in the |latex| \texlive package, but since this package contains a lot of documentation files, none of -which contains the string |shortverb|, it will sort them basically at random. +which contains the string |shortvrb|, it will sort them basically at random. Here comes the notion of \emph{alias}: in the default configuration file, |shortvrb| is aliased to |base/doc|, so that when you type |texdoc shortvrb|, @@ -337,13 +333,13 @@ configured, see the |lang| option) are also used for |«keyword»| and get a |+1| score upgrade. You can have a look at the configuration file provided (the last shown by -|texdoc -f|) for examples. If you feel one of the aliases you defined locally +|texdoc -f|) for examples. If you feel one of the aliases you defined locally should be added to the default configuration, please share it on the \tdml. Aliases are additive: if you define your own aliases for a keyword in your configuration file, and there are also aliases for the same keyword in the default configuration, they will add up. To prevent the default aliases -from begin applied for a particular keyword, include |stopalias «keyword»| in +from being applied for a particular keyword, include |stopalias «keyword»| in your personal configuration file. It will preserve the aliases defined before this directive (if any) but prevent all further aliasing on this keyword. @@ -364,8 +360,8 @@ in the next subsections. It is possible to adjust the score of results containing some pattern as a subword, either globally (for the result of all searches) or only when searching with a particular keyword. This is done in a configuration file -(\ref{ss-quick-file} or \ref{ss-prec}) using the |adjustscore| directive. Here -are a few examples from the default configuration file. +(\ref{ss-quick-file} or \ref{ss-prec}) using the |adjscore| directive. Here are +a few examples from the default configuration file. \begin{htcode} adjscore /Makefile = -1000 @@ -385,17 +381,17 @@ The third directive gives a malus for results containing |texdoc| only if the search keyword is |tex|. Otherwise, such results would get a high score because the heuristic scoring would think |texdoc| is the name of \TeX's documentation. The value -10 is enough to ensure that those results will have -a negative score, so wil not be displayed unless ``showall'' mode is active. +a negative score, so will not be displayed unless ``showall'' mode is active. \textbf{Warning}: Values of scores (like the default score for aliases, the range of heuristic scoring, etc.) may change in a future version of Texdoc. So, don't be surprised if you need to adapt your scoring directives after a -future update of Texdoc. This warning will hopefully disappear at some point. +future update of Texdoc. This warning will hopefully disappear at some point. \subsection{File extensions and names}\label{ss-ext} The allowed file extensions are defined by the configuration item |ext_list| -(default: pdf, html, htm, txt, ps, dvi, no extension). You can configure it +(default: pdf, html, htm, txt, md, ps, dvi, no extension). You can configure it with a line |ext_list = «your, list»| in a configuration file. Be aware that it will completely override the default list, not add to it. An empty string in the list means files without extension (no dot in the name), while a @@ -418,24 +414,28 @@ either is known to be ``bad.'' \subsection{Variants}\label{ss-variants} The documentation for a given package is often found in a file named like -|«package»-doc|. To handle this properlr, Texdoc gives a special score files +|«package»-doc|. To handle this properly, Texdoc gives a special score files named |«package»«suffix»| where |«suffix»| is one element of the list given by the configuration setting |suffix_list|. To customise this list, add a line with |suffix_list = «your, list»| in a -configuration files. Be warned, it will replace the default list, no expand +configuration file. Be warned, it will replace the default list, no expand it. You'll find the default list in the shipped configuration file; feel free to suggest additions on the \tdml (with a real-life example). \subsection{Fuzzy search}\label{ss-fuzzy} -When the normal search can't find any document in \texlive, Texdoc will execute -fuzzy search without user-interactions. The results of fuzzy search are shown -by as an informational message. (you can see that with option |-v|) +When the normal search can't find any document in {\texlive}, Texdoc will +execute fuzzy search without user-interactions. The fuzzy search finds the +closest name of package in {\texlive}\footnote{Note that the feature searches +only package names at this point. Other objects such as aliases cannot be found +by the fuzzy search.} to the input |«keyword»|. The results of fuzzy search are +shown by as an informational message (you can see that with option |-v|). -The default allowance of Levenshtein distance is 5. You can change this -default value by specifying |fuzzy_level| in your |texdoc.cnf| (see -\ref{cf-fuzzy_level}). +The default allowance of Levenshtein distance is 5. You can change this default +value by specifying |fuzzy_level| in your |texdoc.cnf| (see +\ref{cf-fuzzy_level}). Results of fuzzy search could be irreproducible if +multiple strings have the same Levenshtein distance. \clearpage @@ -482,22 +482,23 @@ item. -h, --help \end{cmdsubsub} -Show a quick help message (namely a list of command-line options) and exit +Shows a quick help message (namely a list of command-line options) and exit successfully. \begin{cmdsubsub}{-V, --version}{cl-V} -V, --version \end{cmdsubsub} -Show the current version of the program and exit successfully. +Shows the current version of the program and exit successfully. \begin{cmdsubsub}{-f, --files}{cl-f} -f, --files \end{cmdsubsub} -Show the list of configuration files for the current installation and -platform, with their status (active, not found, or disabled -(see~\ref{cf-lastfile_switch})) and exit successfully. +Shows the list of configuration files for the current installation and +platform, with their status and exit successfully. Normally, only ``active'' +and ``disabled'' files are shown (see~\ref{cf-lastfile_switch}). To show ``not +found'' files as well, you can use |--verbose|. \begin{cmdsubsub}{--just-view}{cl-just-view} --just-view «file» @@ -518,7 +519,7 @@ Set |mode| to the given value, see~\ref{cf-mode}. -i, --interact, -I, --nointeract \end{cmdsubsub} -Set |interact_switch| to true (resp. false), see~\ref{cf-interact_switch}. +Set |interact_switch| to true (or false), see~\ref{cf-interact_switch}. \begin{cmdsubsub}{-M, --machine}{cl-M} -M, --machine @@ -543,25 +544,33 @@ Set |verbosity_level| to maximum, see~\ref{cf-verbosity_level}. \end{cmdsubsub} Set |debug_list|, see~\ref{cf-debug_list}. If you specify |-D| or |--debug| -without the list, activates all available debug items. +without specifying a list, activates all available debug items. + +\begin{cmdsubsub}{-c}{cl-c} + -c «name»=«value» +\end{cmdsubsub} + +Set configuration item |«name»| to |«value»|. This is a general way to access +any configuration items listed in \ref{ss-conf} from command line. \subsection{Environment variables}\label{ss-envvar} They all correspond to some |viewer_«ext»| setting, and the reader is referred to~\ref{cf-viewer_*} for details.\footnote{Old names of environment variables, -namely |TEXDOCVIEW_{txt,html,dvi,ps,pdf}| and -|TEXDOC_VIEWER_{TXT,HTML,DVI,PS,PDF}|, are deprecated but still work.} You can +namely |TEXDOCVIEW_{html,dvi,md,txt,pdf,ps}| and +|TEXDOC_VIEWER_{HTML,DVI,MD,TXT,PDF,PS}|, are deprecated but still work.} You can append |_texdoc| to every name in the first column: this wins over every other name. \begin{center} \begin{tabular}{ll} Environment variables & Configuration items \\ -|PAGER| & |viewer_txt| \\ |BROWSER| & |viewer_html| \\ |DVIVIEWER| & |viewer_dvi| \\ -|PSVIEWER| & |viewer_ps| \\ +|MDVIEWER| & |viewer_md| \\ +|PAGER| & |viewer_txt| \\ |PDFVIEWER| & |viewer_pdf| \\ +|PSVIEWER| & |viewer_ps| \\ \end{tabular} \end{center} @@ -610,14 +619,14 @@ In these cases, an improper |«value»| will raise a warning too. \begin{cmdsubsub}{mode}{cf-mode} mode = «view, list, mixed, showall» \end{cmdsubsub} -Set the mode to the given value. Default is |view|. The various modes +Set the mode to the given value. Default is |view|. The various modes have been presented in~\ref{ss-modes}. \begin{cmdsubsub}{interact}{cf-interact_switch} interact_switch = «true, false» \end{cmdsubsub} -Turn on or off interaction. Default is on. Turning interaction off prevents +Turn on or off interaction. Default is on. Turning interaction off prevents Texdoc from asking you to choose a file to view when there are multiple choices, so it just prints the list of files found. @@ -632,18 +641,20 @@ the empty list, but see the shipped configuration file for more. ext_list = «list» \end{cmdsubsub} -Set the list of recognised extensions to |«list»|. Default is +Set the list of recognised extensions to |«list»|. The default value is: +% \begin{htcode} - pdf, html, htm, txt, dvi, ps, + pdf, html, htm, txt, md, dvi, ps, \end{htcode} +% This list is used to filter and sort the results that have the same -score(with the default value: pdf first, etc). Two special values are +score (with the default value: pdf first, etc). Two special values are recognised: \begin{itemize} \item \emph{The empty element}. This means files without extensions, or more - precisely without a dot in their name. This is meant for files like - |README|, etc. The file is assumed to be plain text for viewing purpose. - \item |*| means any extension. Of course if it is present in the list, it + precisely without a dot in their name. This is meant for files like + |README|, etc. The file is assumed to be plain text for viewing purpose. + \item |*| means any extension. Of course if it is present in the list, it can be the only element! \end{itemize} @@ -655,11 +666,11 @@ necessary since every sty file would have a proper documentation in pdf, html or plain text, but\dots For each |«ext»| in |ext_list| there should be a corresponding |viewer_«ext»| -value set. Defaults are defined corresponding to the default |ext_list|, but -you can add values if you want. For example, if you want Texdoc to be able +value set. Defaults are defined corresponding to the default |ext_list|, but +you can add values if you want. For example, if you want Texdoc to be able to find man pages and display them with the |man| command, you can use \begin{htcode} - ext_list = pdf, html, htm, 1, 5, txt, dvi, ps, + ext_list = pdf, html, htm, 1, 5, txt, md, dvi, ps, viewer_1 = man viewer_5 = man \end{htcode} @@ -672,15 +683,15 @@ viewer is used and a warning is issued. badext_list = «list» \end{cmdsubsub} -Set the list of ``bad'' extensions to |«list»|. Default is ``|txt,|''. Files -with those extensions get a malus of |1| on their heurisitc score if it was +Set the list of ``bad'' extensions to |«list»|. Default is ``|txt,|''. Files +with those extensions get a malus of |1| on their heuristic score if it was previously positive. \begin{cmdsubsub}{basename_list}{cf-basename_list} basename_list = «list» \end{cmdsubsub} -Set the list of ``known'' base names to |«list»|. Default is ``|readme|''. +Set the list of ``known'' base names to |«list»|. Default is ``|readme|''. Files with those base names are selected regardless of their extension. If the extension is unknown, the text viewer will be used to view the file. @@ -688,8 +699,8 @@ extension is unknown, the text viewer will be used to view the file. badbasename_list = «list» \end{cmdsubsub} -Set the list of ``bad'' base names to |«list»|. Default is ``|readme|''. Files -with those names get a malus of |1| on their heurisitc score if it was +Set the list of ``bad'' base names to |«list»|. Default is ``|readme|''. Files +with those names get a malus of |1| on their heuristic score if it was previously positive. \begin{cmdsubsub}{viewer_*}{cf-viewer_*} @@ -699,7 +710,7 @@ previously positive. Set the viewer command for files with extension |«ext»| to |«cmd»|. For files without extension, |viewer_txt| is used, and there's no |viewer_| variable. In |«cmd»|, |%s| can be used as a placeholder for the file name, which is -otherwise inserted at the end of the command. The command can be a arbitrary +otherwise inserted at the end of the command. The command can be an arbitrary shell construct. \begin{cmdsubsub}{lang}{cf-lang} @@ -721,9 +732,10 @@ recommended). debug_list = «list» \end{cmdsubsub} -Set the list of activated debug items (default: none; if the command-line -option is used without arguments, the list defaults to all known debug items). -Implies |--verbose|. Debug information is printed on standard error. +Set the list of activated debug items (default: none). Available debug items +are |config|, |files|, |search|, |score|, |texdocs|, |tlpdb|, |version|, +|view|, and |all| to activate all of these. Implies |--verbose|. Debug +information are printed on standard error. \begin{cmdsubsub}{max_line}{cf-max_lines} max_lines = «number» @@ -737,38 +749,38 @@ is disabled. machine_switch = «true, false» \end{cmdsubsub} -Turn on or off machine-readable output (default: off). With this option +Turn on or off machine-readable output (default: off). With this option active, the value of |interact_switch| is forced to |false|, and each line of output is \begin{htcode} «argument»\t«score»\t«filename» \end{htcode} where |«argument»| is the name of the argument to which the results correspond -(mainly useful if there were many arguments), |\t| is the tab (ascii 9) +(mainly useful if there were many arguments), |\t| is the tab (ASCII \#9) character, and the other entries are pretty self-explanatory. Nothing else is -printed on stdout, except if a internal error occurs (in which case exit code +printed on stdout, except if an internal error occurs (in which case exit code will be 1). In the future, more tab-separated fields may be added at the end of the line, but the first 3 fields will remain unchanged. Currently, there are two additional fields: a two-letter language code, and an unstructured description, both taken from the CTAN catalogue (via the \texlive -database). These fields may be empty and they are not guaranteed to keep the +database). These fields may be empty, and they are not guaranteed to keep the same meaning in future versions of Texdoc. \begin{cmdsubsub}{zipext_list}{cf-zipext_list} zipext_list = «list» \end{cmdsubsub} -List of supported extensions for zipped files (default: empty). Allows +List of supported extensions for zipped files (default: empty). Allows compressed files with names like |foobar.«zip»|, with |«zip»| in the given |«list»|, to be found and unzipped before the viewer is started (the temporary file will be destroyed right after). \textbf{Warning.} Support for zipped documentation is not meant to work on -windows, a Unix shell is assumed! If you add anything to this list, please -make sure that you also set a corresponding |unzip=«ext»| value for each -|«ext»| in the list. Also make sure you are using blocking (i.e. not returning -immediately) viewers. +windows, a Unix shell is assumed! If you add anything to this list, please make +sure that you also set a corresponding |unzip=«ext»| value for each |«ext»| in +the list. At the same time, make sure you are using blocking (i.e., not +returning immediately) viewers. \textit{Remark.} \texlive doesn't ship compressed documentation files, so this option is mainly useful with re-packaged version of \texlive that do, @@ -794,11 +806,12 @@ Commands for removing files (resp. directories) on your system (defaults: lastfile_switch = «true, false» \end{cmdsubsub} -If set to true, prevents Texdoc from reading any other configuration file -after this one (they will be reported as ``disabled'' by |texdoc -f|). Mainly -useful for installing a newer version of Texdoc in your home and preventing -the default configuration file from older versions to be used (see the -\href{https://tug.org/texdoc/}{web site} for instructions on how to do so). +If set to true, prevents Texdoc from reading any other configuration file after +this one (they will be reported as ``disabled'' by |texdoc -f|). Mainly useful +for installing a newer version of Texdoc in your home and preventing the +default configuration file from older versions to be used (see the +\href{https://github.com/TeX-Live/texdoc}{README} for instructions on how to do +so). \begin{cmdsubsub}{fuzzy_level}{cf-fuzzy_level} fuzzy_level = «n» @@ -814,12 +827,13 @@ The current exit codes are: \item Success. \item Internal error. \item Usage error. + \item No documentation found. \end{enumerate} \section{Licence}\label{s-licence} -The current Texdoc program and its documentation are copyright 2008--2018 -Manuel Pégourié-Gonnard, Takuto Asakura, Karl Berry, and Norbert Preining. +The current version of Texdoc program and its documentation are copyright 2008 +Manuel Pégourié-Gonnard, Takuto Asakura, and the {\texlive} 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 @@ -828,11 +842,11 @@ version. This program is distributed in the hope that it will be useful, but \emph{without any warranty}; without even the implied warranty of -\emph{merchantability} or \emph{fitness for a particular purpose}. See the +\emph{merchantability} or \emph{fitness for a particular purpose}. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program. If not, see \url{http://www.gnu.org/licenses/}. +this program. If not, see \url{http://www.gnu.org/licenses/}. \bigskip @@ -845,7 +859,7 @@ Previous work (Texdoc program) in the public domain: \end{itemize} \bigskip -\begin{center}\Large\rmfamily\bfseries +\begin{center}\Large\bfseries Happy {\TeX}ing! \end{center} diff --git a/Master/texmf-dist/scripts/texdoc/config.tlu b/Master/texmf-dist/scripts/texdoc/config.tlu deleted file mode 100644 index cb72343c6ad..00000000000 --- a/Master/texmf-dist/scripts/texdoc/config.tlu +++ /dev/null @@ -1,583 +0,0 @@ --- config.tlu: configuration handling for texdoc --- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details - --------------------------- hide the config table -------------------------- - --- config is read-only (but not "deep" read-only) -function set_read_only(table, name) - assert(next(table) == nil, - 'Internal error: '..name..' should be empty at this point.') - local ro = 'Internal error: attempt to update read-only table ' - local real = {} - setmetatable(table, { - __index = real, - __newindex = function () error(ro..name..'.') end, - }) - return function(k, v) real[k] = v end -end - -real_set_config = set_read_only(config, 'config') - - -------------------------- general config functions ------------------------ - --- set a config parameter, but don't overwrite it if already set --- three special types: *_list (list), *_switch (boolean), *_level (number) -function set_config_element (key, value, context) - local is_known = false -- is key a valid option? - local option - for _, option in ipairs(C.known_options) do - if string.match(key, '^'..option..'$') then is_known = true break end - end - -- warn and exit if key is not a known option - if not is_known then config_warn(key, nil, context, true) return end - -- exit if key is already set (/!\ must test for nil, not false) - if not (config[key] == nil) then - if context.src ~= 'def' then - deb_print('config', "Ignoring '"..key.."="..value.."' " - ..context_to_string(context)..'.') - end - return nil - end - -- record the source of the setting - real_set_config(key..'_src', context.src) - -- detect the type of the key - if string.match(key, '_list$') then - -- coma-separated list - local values - if value == '' then - values = {} - else - values = string.explode(value, ',') - end - local inverse = {} - for i, j in ipairs(values) do -- sanitize values... - j = string.gsub(j, '%s*$', '') - j = string.gsub(j, '^%s*', '') - values[i] = j - inverse[j] = i -- ... and build inverse mapping on the way - end - real_set_config(key, values) - real_set_config(key..'_inv', inverse) - real_set_config(key..'_max', #values) - elseif string.find (key, '_switch$') then - -- boolean - if value == 'true' then - real_set_config(key, true) - elseif value == 'false' then - real_set_config(key, false) - else - config_warn (key, value, context) - end - elseif string.find (key, '_level$') then - -- integer - local val = tonumber (value) - if val then - real_set_config(key, val) - else - config_warn (key, value, context) - end - else -- string - real_set_config(key, value) - end - -- special case: if we just set debug_list, print version info now - if key == 'debug_list' then - deb_print('version', C.fullname..' version '..C.version) - end - -- now tell what we have just done, for debugging - deb_print('config', - "Setting '"..key.."="..value.."' "..context_to_string(context)..'.') -end - --- a helper function for warning messages in the above -function config_warn (key, value, context, unknown) - local begin = unknown - and 'Unknown option "'..key..'"' - or 'Illegal value "'..tostring(value)..'" for option "'..key..'"' - local ending = '. Skipping.' - err_print('warning', begin..' '..context_to_string(context)..ending) -end - --- interpreting 'context' for the previous functions -function context_to_string(context) - if not context then return '(no context)' end - if context.src == 'cl' then - return 'from command line option "'..context.name..'"' - elseif context.src == 'env' then - return 'from environment variable "'..context.name..'"' - elseif context.src == 'loc' then - return 'from operating system locale' - elseif context.src == 'file' then - return 'in file "'..context.file..'" on line '..context.line - elseif context.src == 'def' then - return 'from built-in defaults' - else - return 'from unkown source (should not happen, please report)' - end -end - --- set a whole list, also whithout overwriting -function set_config_list (conf, context) - for key, value in pairs(conf) do - set_config_element (key, value, context) - end -end - ------------------------- options from command line ------------------------ - --- set config from the command line --- Please make sure to update C.usage_msg accordingly --- and set a default value in setup_config_from_defaults() if relevant. -function setup_config_from_cl(arg) - local curr_arg - local action = true - local function set_config_elt(key, val) - set_config_element(key, val, {src='cl', name=curr_arg}) - end - - -- modified Alternative Get Opt - -- cf. http://lua-users.org/wiki/AlternativeGetOpt - local function getopt(arg, options) - local tmp - local tab = {} - local saved_arg = { table.unpack(arg) } - for k, v in ipairs(saved_arg) do - if string.sub(v, 1, 2) == "--" then - table.remove(arg, 1) - local x = string.find(v, "=", 1, true) - if x then tab[string.sub(v, 3, x-1)] = string.sub(v, x+1) - else tab[string.sub(v, 3)] = true - end - elseif string.sub(v, 1, 1) == "-" then - table.remove(arg, 1) - local y = 2 - local l = string.len(v) - local jopt - while (y <= l) do - jopt = string.sub(v, y, y) - if string.find(options, jopt, 1, true) then - if y < l then - tmp = string.sub(v, y+1) - y = l - else - table.remove(arg, 1) - tmp = saved_arg[k + 1] - end - if string.match(tmp, '^%-') then - tab[jopt] = false - else - tab[jopt] = tmp - end - else - tab[jopt] = true - end - y = y + 1 - end - end - end - return tab - end - - opts = getopt(arg, 'd') - for k, v in pairs(opts) do - if #k == 1 then - curr_arg = '-' .. k - else - curr_arg = '--' .. k - end - - -- action - if (curr_arg == '-h') or (curr_arg == '--help') then - action = 'help' - elseif (curr_arg == '-V') or (curr_arg == '--version') then - action = 'version' - elseif (curr_arg == '-f') or (curr_arg == '--files') then - action = 'files' - elseif curr_arg == '--just-view' then - action = 'view' - -- mode - elseif (curr_arg == '-w') or (curr_arg == '--view') then - set_config_elt('mode', 'view') - elseif (curr_arg == '-m') or (curr_arg == '--mixed') then - set_config_elt('mode', 'mixed') - elseif (curr_arg == '-l') or (curr_arg == '--list') then - set_config_elt('mode', 'list') - elseif (curr_arg == '-s') or (curr_arg == '--showall') then - set_config_elt ('mode', 'showall') - -- interaction - elseif (curr_arg == '-I') or (curr_arg == '--nointeract') then - set_config_elt('interact_switch', 'false') - elseif (curr_arg == '-i') or (curr_arg == '--interact') then - set_config_elt('interact_switch', 'true') - -- output format - elseif (curr_arg == '-M') or (curr_arg == '--machine') then - set_config_elt('machine_switch', 'true') - -- debug - elseif (curr_arg == '-d') or (curr_arg == '--debug') then - if v == true then v = 'all' end - set_config_elt('debug_list', v) - elseif curr_arg == '-D' then - set_config_elt('debug_list', 'all') - -- verbosity - elseif (curr_arg == '-q') or (curr_arg == '--quiet') then - set_config_elt('verbosity_level', C.min_verbosity) - elseif (curr_arg == '-v') or (curr_arg == '--verbose') then - set_config_elt('verbosity_level', C.max_verbosity) - -- problem - else - err_print('error', "unknown option: "..curr_arg) - err_print('error', C.error_msg) - return false - end - end - return action -end - -------------------------- config from environment -------------------------- - --- set config from environment if available -function setup_config_from_env () - local function set_config_elt_from_vars(key, vars) - for _, var in ipairs(vars) do - local value = os.getenv(var) - if value then - set_config_element(key, value, {src='env', name=var}) - end - end - end - set_config_elt_from_vars('viewer_pdf', - {"PDFVIEWER_texdoc", "PDFVIEWER", "TEXDOCVIEW_pdf", "TEXDOC_VIEWER_PDF"}) - set_config_elt_from_vars('viewer_ps', - {"PSVIEWER_texdoc", "PSVIEWER", "TEXDOCVIEW_ps", "TEXDOC_VIEWER_PS"}) - set_config_elt_from_vars('viewer_dvi', - {"DVIVIEWER_texdoc", "DVIVIEWER", "TEXDOCVIEW_dvi", "TEXDOC_VIEWER_DVI"}) - set_config_elt_from_vars('viewer_html', - {"BROWSER_texdoc", "BROWSER", "TEXDOCVIEW_html", "TEXDOC_VIEWER_HTML"}) - set_config_elt_from_vars('viewer_md', - {"MDVIEWER_texdoc", "PAGER", "TEXDOCVIEW_md", "TEXDOC_VIEWER_MD"}) - set_config_elt_from_vars('viewer_txt', - {"PAGER_texdoc", "PAGER", "TEXDOCVIEW_txt", "TEXDOC_VIEWER_TXT"}) -end - ----------------------- options and aliases from files ---------------------- - --- set config+aliases from a particular config file assumed to exist -function read_config_file(configfile) - local cnf = assert(io.open(configfile, 'r')) - local lineno = 0 - while true do - local line=cnf:read('*line') - lineno = lineno + 1 - if line == nil then break end -- EOF - line = string.gsub(line, '%s*#.*$', '') -- comments begin with # - line = string.gsub(line, '%s*$', '') -- remove trailing spaces - line = string.gsub(line, '^%s*', '') -- remove leading spaces - -- 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_config(line, configfile, lineno) - -- complain if it failed - if not ok then - err_print('warning', - 'syntax error in '..configfile..' at line '..lineno..'.') - end - end - cnf:close() -end - --- interpret a confline as a config setting or return false -function confline_to_config(line, file, pos) - local key, val = string.match(line, '^([%a%d_]+)%s*=%s*(.+)') - if key and val then - set_config_element(key, val, {src='file', file=file, line=pos}) - return true - end - return false -end - --- return the list of configuration files -function get_config_files() - -- get names - local platform = string.match (kpse.var_value ('SELFAUTOLOC'), '.*/(.*)$') - local names = { - 'texdoc-'..platform..'.cnf', - 'texdoc.cnf', - 'texdoc-dist.cnf', - } - -- get dirs - local sep = (os.type == 'windows') and ';' or ':' - local texmf_texdoc = kpse.expand_path('$TEXMF/texdoc') - local dirs = texmf_texdoc:explode(sep) - -- merge them - local ret = {} - for _, dir in ipairs(dirs) do - for _, name in ipairs(names) do - local pathname = dir .. '/' .. name - if lfs.isfile(pathname) then - table.insert(ret, pathname) - end - end - end - return ret -end - --- the config_files table is shared by the next two functions -do -local config_files = {} - --- set config/aliases from all config files -function setup_config_from_files () - local file_list = get_config_files() - for i, file in ipairs (file_list) do - local status = config.lastfile_switch and 'disabled' or 'active' - config_files[i] = { - path = file, - status = status, - } - if status == 'active' then - read_config_file (file) - end - end -end - --- now a special information function (see -f,--file option) -function show_config_files (print_fun, verbose) - local pref = verbose and ' ' or '' - print_fun("Configuration files are:") - for i, file in ipairs (config_files) do - print_fun(pref..file.status..'\t'..w32_path(file.path)) - end - if verbose then - print_fun('Recommended file(s) for personal settings:') - local sep = (os.type == 'windows') and ';' or ':' - local texmfhomes = string.explode(kpse.var_value('TEXMFHOME'), sep) - for _, home in ipairs(texmfhomes) do - print_fun(pref..home..'/texdoc/texdoc.cnf') - end - end -end - -end -- scope of config_files - ----------------------- config from locale settings ------------------------- - -function setup_config_from_locale() - local current = os.setlocale(nil, "all") - os.setlocale("", "all") - local native = os.setlocale(nil, "time") - os.setlocale(current, "all") - local lang = string.match(native, "^[a-z][a-z]") - if lang then - set_config_element("lang", lang, {src="loc"}) - end -end - ----------------------- options from built-in defaults ---------------------- - --- for default viewer on general Unix, we have a list; the following two --- functions are used to check in the path which program is available - --- check if "name" is the name of a file in the path --- Warning: to be used only on Unix! (separators, and PATH irrelevant on win32) --- the value of PATH is cached -do local path_list = string.explode(os.getenv("PATH"), ':') -function is_in_path(name) - for _, path in ipairs(path_list) do - if lfs.isfile(path..'/'..name) then return true end - end - return false -end -end - --- guess a viewer from a list: --- - xdg-open from freedesktop if available --- - try detecting desktop environments --- - or return the first element of "list" whose name is found in path --- - or nil --- caches results of desktop environment detection -do local de_viewer -function guess_viewer(cmds) - -- try the freedesktop method - if is_in_path('xdg-open') then - return '(xdg-open %s) &' - end - -- try desktop environment - if not de_viewer then de_viewer = desktop_environment_viewer() end - if de_viewer then return de_viewer end - -- or look along path - for _, cmd in ipairs(cmds) do - if is_in_path(cmd[1]) then return cmd[2] end - end -end -end - --- returns a viewer specific to a desktop environement if relevant --- doesn't work on windows (uses io.popen) --- logic stolen from xdg-open (http://www.freedesktop.org/) and adapted -function desktop_environment_viewer() - if os.getenv('KDE_SESSION_VERSION') and is_in_path('kde-open') then - return '(kde-open %s) &' -- kde 4 (or greater) - end - if os.getenv('KDE_FULL_SESSION') and is_in_path('kfmclient') then - return '(kfmclient exec %s) &' -- kde < 4 - end - if os.getenv('GNOME_DESKTOP_SESSION_ID') then -- gnome - if is_in_path('gvfs-open') then return '(gvfs-open %s) &' end - if is_in_path('gnome-open') then return '(gnome-open %s) &' end - end - if not is_in_path('xprop') then return end - local xprop_fh = io.popen('xprop -root _DT_SAVE_MODE 2>/dev/null') - local xprop_out = xprop_fh:read('*line') - xprop_fh:close() - if xprop_out and string.find(xprop_out, '= "xfce4"$') then -- xfce - return '(exo-open %s) &' - end -end - --- set viewers from defaults (done only if necessary) -function get_default_viewers() - local function set_config_ls(ls) set_config_list(ls, {src='def'}) end - if (os.type == "windows") then - set_config_ls { - -- Use 'start' to get file associations. - -- We need to quote the filenames, but the first quoted argument - -- is considered as the title by start, so we provide a dummy title. - -- Also, since the command line parser removes quotes if there - -- is no space inside, the dummy title must contain spaces. - viewer_dvi = 'start "texdoc dvi viewer"', - viewer_html = 'start "texdoc html viewer"', - viewer_pdf = 'start "texdoc pdf viewer"', - viewer_ps = 'start "texdoc ps viewer"', - -- 'more' is always available. - -- However, we can't assume texdoc is called from a cmd.exe window - -- (it can be run from the start->run menu), hence we make sure - -- to open a new window if needed. - viewer_txt = 'start cmd /k more', - viewer_md = viewer_txt, - } - elseif (os.name == 'macosx') then - set_config_ls { - viewer_dvi = 'open', - viewer_html = 'open', - viewer_pdf = 'open', - viewer_ps = 'open', - viewer_txt = 'less', - viewer_md = viewer_txt, - } - else -- generic Unix - set_config_ls { - viewer_dvi = guess_viewer { - {'xdvi', '(xdvi %s) &'}, - {'evince', '(evince %s) &'}, - {'okular', '(okular %s) &'}, - {'kdvi', '(kdvi %s) &'}, - {'xgdvi', '(xgdvi %s) &'}, - {'spawg', '(spawg %s) &'}, - {'spawx11', '(spawx11 %s) &'}, - {'tkdvi', '(tkdvi %s) &'}, - {'dvilx', '(dvilx %s) &'}, - {'advi', '(advi %s) &'}, - {'xdvik-ja', '(xdvik-ja %s) &'}, - {'see', '(see %s) &'} - }, - viewer_html = guess_viewer { - {'firefox', '(firefox %s) &'}, - {'seamonkey', '(seamonkey %s) &'}, - {'mozilla', '(mozilla %s) &'}, - {'konqueror', '(konqueror %s) &'}, - {'epiphany', '(epiphany %s) &'}, - {'opera', '(opera %s) &'}, - {'w3m', 'w3m'}, - {'links', 'links'}, - {'lynx', 'lynx'}, - {'see', 'see'} - }, - viewer_pdf = guess_viewer { - {'xpdf', '(xpdf %s) &'}, - {'evince', '(evince %s) &'}, - {'okular', '(okular %s) &'}, - {'kpdf', '(kpdf %s) &'}, - {'acroread', '(xpdf %s) &'}, - {'see', '(see %s) &'} - }, - viewer_ps = guess_viewer { - {'gv', '(gv %s) &'}, - {'evince', '(evince %s) &'}, - {'okular', '(okular %s) &'}, - {'kghostview', '(kghostview %s) &'}, - {'see', '(see %s) &'} - }, - viewer_txt = guess_viewer { - {'most', 'most'}, - {'less', 'less'}, - {'more', 'more'} - }, - viewer_md = viewer_txt, - } - end -end - --- set some fall-back default values if no previous value is set -function setup_config_from_defaults() - local function set_config_ls(ls) set_config_list(ls, {src='def'}) end - local function set_config_elt(key, val) - set_config_element(key, val, {src='def'}) - end - -- various, platform independent, stuff - set_config_ls { - mode = 'view', - interact_switch = 'true', - machine_switch = 'false', - ext_list = 'pdf, htm, html, txt, ps, dvi, ', - basename_list = 'readme, 00readme', - badext_list = 'txt, ', - badbasename_list = 'readme, 00readme', - suffix_list = '', - verbosity_level = C.def_verbosity, - debug_list = '', - max_lines = '20', - fuzzy_level = '5', - } - -- zip-related options - set_config_ls { - zipext_list = '', - rm_file = 'rm -f', - rm_dir = 'rmdir', - } -end - --------------------------- set all configuration --------------------------- - --- populate the config and alias arrays -function setup_config_and_alias(arg) - -- setup config from all sources - local ret = setup_config_from_cl(arg) - setup_config_from_env() - setup_config_from_files() - setup_config_from_locale() - setup_config_from_defaults() - -- machine mode implies no interaction - if config.machine_switch == true then - real_set_config('interact_switch', false) - end - -- debug implies verbose - if #config.debug_list > 0 then - real_set_config('verbosity_level', tonumber(C.max_verbosity)) - end - -- we were waiting for config.debug_list to be known to do this - show_config_files(function(s) deb_print('files', s) end) - -- propagated return value of _from_cl() - return ret -end - -return { - setup_config_and_alias = setup_config_and_alias, - get_default_viewers = get_default_viewers, - show_config_files = show_config_files, - read_config_file = read_config_file, -} - --- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/functions.tlu b/Master/texmf-dist/scripts/texdoc/functions.tlu deleted file mode 100644 index 88b66b2ca40..00000000000 --- a/Master/texmf-dist/scripts/texdoc/functions.tlu +++ /dev/null @@ -1,118 +0,0 @@ --- functions.tlu: general-use functions for texdoc --- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details - --- change '/' to '\' on windows --- Use: internal representation of files always use forward slashes. --- This function should be called only before displaying a file name. -if os.type == "windows" then - function w32_path (path) - return (string.gsub (path, '/', '\\')) - end -else - function w32_path (path) - return path - end -end - --- remove the last direcory component of a path -if os.type == 'windows' then - function path_parent(path) - return string.match(path, '^(.*)[\\/]') - end -else - function path_parent(path) - return string.match(path, '^(.*)/') - end -end - --- generic error display function (see the err_priority constant) -function err_print (lvl, msg) - -- be careful: maybe config.verbosity_level is not set yet - local verbosity_level = config.verbosity_level or tonumber(C.def_verbosity) - if C.err_priority[lvl] <= verbosity_level then - io.stderr:write ("texdoc "..lvl..": "..msg.."\n") - end -end - -do --scope of active_debugs -local active_debugs - --- generic debug function -function deb_print(cat, msg) - -- make sure active_debugs is set - if not active_debugs then set_active_debugs() end - -- print message it belongs to an active category - if active_debugs and active_debugs[cat] or cat == 'XXX' then - io.stderr:write ("texdoc debug-"..cat..": "..msg.."\n") - end -end - --- set active_debugs -function set_active_debugs() - if not config.debug_list then return end - active_debugs = {} - -- all debug options imply version info - if config.debug_list[1] then - active_debugs.version = true - else - return - end - -- if 'all' is the first keyword, just activate all categories - if config.debug_list[1] == 'all' then - for deb in pairs(C.known_debugs) do - active_debugs[deb] = true end - return - end - -- activate options from the list - for _, deb in ipairs(config.debug_list) do - local deps = C.known_debugs[deb] - if deps then - active_debugs[deb] = true - for _, d in ipairs(deps) do active_debugs[d] = true end - else - err_print('warning', "Unknown debug category '"..deb.."'.") - end - end -end - -end -- scope of active_debugs - --- if file is base..'.'..zip with zip in zipext_list, return: base, zip --- otherwise, return: file, nil -function parse_zip(file) - local zip - for _, zip in ipairs(config.zipext_list) do - local l = #zip + 1 - if string.sub(file, -l, -1) == '.'..zip then - return string.sub(file, 1, -l - 1), zip - end - end - return file, nil -end - --- print a usage message, with the proper 'active values' line -function print_usage(actions) - local usage_msg = C.usage_msg - -- include actions if any - if actions then - usage_msg = usage_msg:gsub(C.actions_ph, - C.actions_ph .. actions .. '\n\n') - else - usage_msg = usage_msg:gsub(C.actions_ph, '') - end - -- finally print it - print(usage_msg) -end - -return { - err_print = err_print, - deb_print = deb_print, - w32_path = w32_path, - parse_zip = parse_zip, - print_usage = print_usage, - path_parent = path_parent, -} - --- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/main.tlu b/Master/texmf-dist/scripts/texdoc/main.tlu deleted file mode 100644 index b5ada6e7dfb..00000000000 --- a/Master/texmf-dist/scripts/texdoc/main.tlu +++ /dev/null @@ -1,73 +0,0 @@ --- main.tlu: default command-line interface of texdoc --- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details - --- load texdoclib (kpse initialized by the wrapper) -local texdoc = require('texdoc.texdoclib') - --- exit codes -local exit_ok = 0 -local exit_error = 1 -- apparently hard-coded in Lua -local exit_usage = 2 - --- action command-line options -local action_help = [[ - -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).]] - --- get configuration and parse command line -local action = texdoc.setup_config_and_alias(arg) -if not action then - os.exit(exit_usage) -end - --- handle action options -if action == 'help' then - texdoc.print_usage(action_help) - os.exit(exit_ok) -elseif action == 'version' then - print(texdoc.const.progname .. ' ' .. texdoc.const.version) - print('\n' .. texdoc.const.copyright_msg) - os.exit(exit_ok) -elseif action == 'files' then - print(texdoc.const.fullname .. ' ' .. texdoc.const.version) - texdoc.show_config_files(print, true) - os.exit(exit_ok) -elseif action == 'view' then - if not arg[1] then - texdoc.err_print('error', "missing file operand to --just-view") - texdoc.err_print('error', texdoc.const.error_msg) - os.exit(exit_usage) - end - local ok = texdoc.view_file(arg[1]) - os.exit(ok and exit_ok or exit_error) -end - --- make sure we actually have argument(s) -if not arg[1] then - texdoc.err_print('error', "no action specified") - texdoc.err_print('error', texdoc.const.error_msg) - os.exit(exit_usage) -end - --- initialise databases -texdoc.init_databases() - --- main loop -local docname -for _, docname in ipairs(arg) do - -- do we have more then one argument? - local multiarg = not not arg[2] - -- get results - local doclist = texdoc.get_doclist(docname) - -- deliver results to the user - texdoc.deliver_results(docname, doclist, multiarg) -end - --- the end -os.exit(exit_ok) - --- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/texdoc.tlu b/Master/texmf-dist/scripts/texdoc/texdoc.tlu index 90b507e283a..b8598682364 100755 --- a/Master/texmf-dist/scripts/texdoc/texdoc.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoc.tlu @@ -1,11 +1,17 @@ #!/usr/bin/env texlua --- texdoc.tlu: small wrapper around main.tlu --- (makes it easier to install a new version of texdoc in TEXMFHOME) +-- texdoc.tlu: the main program of texdoc -- --- The TeX Live team, GPLv3, see texdoclib.tlu for details +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details +-- Note: we keep this file small as much as possible so that make it easier +-- to install a new version of texdoc in TEXMFHOME. + +-- setup the kpse library and load texdoclib kpse.set_program_name(arg[-1], 'texdoc') -require('texdoc.main') +local texdoc = require('texdoclib') + +-- execute +texdoc.cli.exec() -- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/alias.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-alias.tlu index 44c4fc38385..16c375b3bad 100644..100755 --- a/Master/texmf-dist/scripts/texdoc/alias.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-alias.tlu @@ -1,12 +1,11 @@ --- alias.tlu: configuration handling for texdoc +-- texdoclib-alias.tlu: alias handling for texdoc -- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details --[[ structure of the alias table alias = { - name1 = { <true or nill> stop, <aliasentry> aliasentry1, ... }, + name1 = {<true or nill> stop, <aliasentry> aliasentry1, ...}, ... } stop == true means further alias directives should be ignored @@ -17,16 +16,24 @@ aliasentry = { original = <true or nil> is this the original keyword?, locale = <true or nil> is this entry found via config.lang? } -score == nil means to use the default score (defined in score.tlu) +score == nil means to use the default score (defined in texdoclib-score.tlu) --]] +-- dependencies +local texdoc = { + config = require('texdoclib-config'), +} + +-- shortcuts +local M = {} + -- alias is local to this file local alias = {} -- turn a name into a suitable alias entry -- if score is 'false', this is the original name -function make_alias(pat, score) +local function make_alias(pat, score) local al = {} al.name = pat if score == false then @@ -38,48 +45,52 @@ function make_alias(pat, score) end -- add an alias value for a key -function add_alias(key, value, score) +local function add_alias(key, value, score) local k = string.lower(key) - alias[k] = alias[k] or { make_alias(key, false) } + alias[k] = alias[k] or {make_alias(key, false)} if alias[k].stop then return end table.insert(alias[k], make_alias(value, score)) end -- prevent a key from being further aliased -function stop_alias(key) +local function stop_alias(key) local k = string.lower(key) alias[k] = alias[k] or {} alias[k].stop = true end -- get patterns for a name -function get_patterns(name, no_alias) +function M.get_patterns(name, no_alias) local n = string.lower(name) + -- get normal aliases local res if alias[n] and not no_alias then res = alias[n] else - res = { make_alias(name, false) } + res = {make_alias(name, false)} end + -- check for language-specific aliases - local lang = config.lang and alias[n .. '-' .. config.lang] + local config_lang = texdoc.config.get_value('lang') + local lang = config_lang and alias[n .. '-' .. config_lang] if lang then for _, entry in ipairs(lang) do if not entry.original then table.insert(res, { - name = entry.name, - score = entry.score, - locale = true, + name = entry.name, + score = entry.score, + locale = true, }) end end end + return res end -- interpret a confline as an alias setting or return false -function confline_to_alias(line, file, pos) +function M.confline_to_alias(line, file, pos) -- alias directive without score local key, val = string.match(line, '^alias%s+([%w%p]+)%s*=%s*(.+)') if key and val then @@ -96,7 +107,7 @@ function confline_to_alias(line, file, pos) end -- stopalias directive local key = string.match(line, '^stopalias%s+(.+)') - if key then + if key then stop_alias(key) return true end @@ -104,16 +115,13 @@ function confline_to_alias(line, file, pos) end -- iterator over the list of keys in the alias table -function aliased_names() +-- Note: currently this function is not used (for debug) +function M.aliased_names() return function(_, cur) return (next(alias, cur)) end end -return { - confline_to_alias = confline_to_alias, - get_patterns = get_patterns, - aliased_names = aliased_names, -} +return M -- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu new file mode 100755 index 00000000000..3de786ef2c8 --- /dev/null +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-cli.tlu @@ -0,0 +1,219 @@ +-- texdoclib-cli.tlu: command line interfaces for texdoc +-- +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details + +-- dependencies +local texdoc = { + const = require('texdoclib-const'), + util = require('texdoclib-util'), + config = require('texdoclib-config'), + search = require('texdoclib-search'), + view = require('texdoclib-view'), +} + +-- shortcuts +local M = {} +local C = texdoc.const +local err_print = texdoc.util.err_print + +-------------------------- parsing options -------------------------- + +-- modified Alternative GetOpt +-- cf. http://lua-users.org/wiki/AlternativeGetOpt +local function getopt(arg, options) + local tmp + local tab = {} + local saved_arg = {table.unpack(arg)} + + for k, v in ipairs(saved_arg) do + if string.sub(v, 1, 2) == '--' then + table.remove(arg, 1) + local x = string.find(v, '=', 1, true) + if x then + table.insert(tab, {string.sub(v, 3, x-1), string.sub(v, x+1)}) + else + table.insert(tab, {string.sub(v, 3), true}) + end + elseif string.sub(v, 1, 1) == '-' then + table.remove(arg, 1) + local y = 2 + local l = string.len(v) + local jopt + while (y <= l) do + jopt = string.sub(v, y, y) + if string.find(options, jopt, 1, true) then + if y < l then + tmp = string.sub(v, y+1) + y = l + else + table.remove(arg, 1) + tmp = saved_arg[k + 1] + end + if string.match(tmp, '^%-') then + table.insert(tab, {jopt, false}) + else + table.insert(tab, {jopt, tmp}) + end + else + table.insert(tab, {jopt, true}) + end + y = y + 1 + end + end + end + + return tab +end + +local function parse_options() + local curr_arg + local action = true + 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') + + for _, tp in ipairs(opts) do + local k, v = tp[1], tp[2] + if #k == 1 then + curr_arg = '-' .. k + else + curr_arg = '--' .. k + end + + -- action + if (curr_arg == '-h') or (curr_arg == '--help') then + action = 'help' + elseif (curr_arg == '-V') or (curr_arg == '--version') then + action = 'version' + elseif (curr_arg == '-f') or (curr_arg == '--files') then + action = 'files' + elseif curr_arg == '--just-view' then + action = 'view' + + -- 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 + local item, value = string.match(v, '^([%a%d_]+)%s*=%s*(.+)') + insert_cl_config(item, value, 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) + + -- having trouble + else + err_print('error', 'unknown option: ' .. curr_arg) + err_print('error', C.error_msg) + return false + end + end + + return action, cl_config +end + +-------------------------- process execution -------------------------- + +-- handling actions +local function do_action(action) + if action == 'help' then + texdoc.util.print_usage() + os.exit(C.exit_ok) + elseif action == 'version' then + print(string.format( + '%s %s (%s)', C.progname, C.version, C.release_date) .. + '\n\n' .. C.copyright_msg) + os.exit(C.exit_ok) + elseif action == 'files' then + print(C.fullname .. ' ' .. C.version) + texdoc.config.show_config_files(true) + os.exit(C.exit_ok) + elseif action == 'view' then + if not arg[1] then + err_print('error', 'Missing file operand to --just-view.') + err_print('error', C.error_msg) + os.exit(C.exit_usage) + end + texdoc.view.view_file(arg[1]) + os.exit(C.exit_ok) + end +end + +-- the main loop +local function do_texdoc() + texdoc.search.init_databases() + + for _, docname in ipairs(arg) do + -- do we have more then one argument? + local multiarg = not not arg[2] + -- get results + local doclist = texdoc.search.get_doclist(docname) + -- deliver results to the user + texdoc.view.deliver_results(docname, doclist, multiarg) + end +end + +-------------------------- the main function -------------------------- + +function M.exec() + -- parsing command line options + local action, cl_config = parse_options() + + if not action then + os.exit(C.exit_usage) + end + + -- setup config and alias + texdoc.config.setup_config_and_alias(cl_config) + + -- special action + do_action(action) + + -- do we actually have arguments? + if not arg[1] then + err_print('error', 'No action specified.') + err_print('error', C.error_msg) + os.exit(C.exit_usage) + end + + -- the main feature + do_texdoc() + + os.exit(C.exit_ok) +end + +return M + +-- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu new file mode 100755 index 00000000000..471fef9fdcb --- /dev/null +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-config.tlu @@ -0,0 +1,559 @@ +-- texdoclib-config.tlu: handling config of texdoc +-- +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details + +-- shortcuts +local M = {} +local C = require('texdoclib-const') + +-- config is local to this file +local config = {} + +-------------------------- handling dependencies -------------------------- + +-- in this file, dependencies should be required ondemand to prevent infinite +-- recursion. + +local texdoc = {} + +-- import specified function from the submodule +local function import_function(mod, func) + texdoc[mod] = texdoc[mod] or require('texdoclib-' .. mod) + return texdoc[mod][func] +end + +-------------------------- hide the config table -------------------------- + +-- config is read-only (but not "deep" read-only) +local function set_read_only(table, name) + assert(next(table) == nil, + 'Internal error: ' .. name .. ' should be empty at this point.') + local ro = 'Internal error: attempt to update read-only table ' + local real = {} + setmetatable(table, { + __index = real, + __newindex = function() error(ro .. name .. '.') end, + }) + return function(k, v) real[k] = v end +end +local real_set_config = set_read_only(config, 'config') + +-- the accessor +function M.get_value(key) return config[key] end + +------------------------- general config functions ------------------------ + +-- interpreting 'context' in this section +local function context_to_string(context) + if not context then return '(no context)' end + if context.src == 'cl' then + return 'from command line option "' .. context.name .. '"' + elseif context.src == 'env' then + return 'from environment variable "' .. context.name .. '"' + elseif context.src == 'loc' then + return 'from operating system locale' + elseif context.src == 'file' then + return 'in file "' .. context.file .. '" on line ' .. context.line + elseif context.src == 'def' then + return 'from built-in defaults' + else + return 'from unkown source (should not happen, please report)' + end +end + +-- a helper function for warning messages in this section +local function config_warn(key, value, context, unknown) + local err_print = import_function('util', 'err_print') + local begin = unknown + and string.format('Unknown option "%s"', key) + or string.format('Illegal value "%s" for option "%s"', + key, tostring(value)) + texdoc.util.err_print('warning', + '%s %s. Skipping.', begin, context_to_string(context)) +end + +-- set a config parameter, but don't overwrite it if already set +-- three special types: *_list (list), *_switch (boolean), *_level (number) +function M.set_config_element(key, value, context) + local dbg_print = import_function('util', 'dbg_print') + local parse_error = false + + local is_known = false -- is key a valid option? + local option + for _, option in ipairs(C.known_options) do + if string.match(key, '^' .. option .. '$') then + is_known = true + break + end + end + + -- warn and exit if key is not a known option + if not is_known then config_warn(key, nil, context, true) return end + + -- exit if key is already set (/!\ must test for nil, not false) + if not (config[key] == nil) then + if context.src ~= 'def' then + dbg_print('config', 'Ignoring "%s=%s" %s.', + key, tostring(value), context_to_string(context)) + end + return nil + end + + -- record the source of the setting + real_set_config(key .. '_src', context.src) + + -- detect the type of the key + if string.match(key, '_list$') then + -- coma-separated list + local values + if value == '' then + values = {} + else + values = string.explode(value, ',') + end + + local inverse = {} + for i, j in ipairs(values) do -- sanitize values... + j = string.gsub(j, '%s*$', '') + j = string.gsub(j, '^%s*', '') + values[i] = j + inverse[j] = i -- ... and build inverse mapping on the way + end + + real_set_config(key, values) + real_set_config(key .. '_inv', inverse) + real_set_config(key .. '_max', #values) + elseif string.find(key, '_switch$') then + -- boolean + if value == 'true' then + real_set_config(key, true) + elseif value == 'false' then + real_set_config(key, false) + else + config_warn(key, value, context) + parse_error = true + end + elseif string.find(key, '_level$') then + -- integer + local val = tonumber(value) + if val then + real_set_config(key, val) + else + config_warn(key, value, context) + parse_error = true + end + else -- string + real_set_config(key, value) + end + + -- special case: if we just set debug_list, print version info now + if key == 'debug_list' then + dbg_print('version', '%s v%s', C.fullname, C.version) + end + + -- now tell what we have just done, for debugging + if not parse_error then + dbg_print('config', 'Setting "%s=%s" %s.', + key, tostring(value), context_to_string(context)) + end +end +local set_config_element = M.set_config_element + +-- set a whole list, also without overwriting +local function set_config_list(conf, context) + for key, value in pairs(conf) do + set_config_element(key, value, context) + end +end + +------------------------ config from command line ------------------------ + +-- set config from the command line +-- Note: Make sure to set a default value in setup_config_from_defaults() +-- if relevant. +local function setup_config_from_cl(cl_config) + for _, e in ipairs(cl_config) do + set_config_element(e[1], e[2], {src='cl', name=e[3]}) + end +end + +------------------------- config from environment -------------------------- + +-- set config from environment if available +local function setup_config_from_env() + local function set_config_elt_from_vars(key, vars) + for _, var in ipairs(vars) do + local value = os.getenv(var) + if value then + set_config_element(key, value, {src='env', name=var}) + end + end + end + set_config_elt_from_vars('viewer_pdf', + {'PDFVIEWER_texdoc', 'PDFVIEWER', 'TEXDOCVIEW_pdf', 'TEXDOC_VIEWER_PDF'}) + set_config_elt_from_vars('viewer_ps', + {'PSVIEWER_texdoc', 'PSVIEWER', 'TEXDOCVIEW_ps', 'TEXDOC_VIEWER_PS'}) + set_config_elt_from_vars('viewer_dvi', + {'DVIVIEWER_texdoc', 'DVIVIEWER', 'TEXDOCVIEW_dvi', 'TEXDOC_VIEWER_DVI'}) + set_config_elt_from_vars('viewer_html', + {'BROWSER_texdoc', 'BROWSER', 'TEXDOCVIEW_html', 'TEXDOC_VIEWER_HTML'}) + set_config_elt_from_vars('viewer_md', + {'MDVIEWER_texdoc', 'MDVIEWER', 'TEXDOCVIEW_md', 'TEXDOC_VIEWER_MD'}) + set_config_elt_from_vars('viewer_txt', + {'PAGER_texdoc', 'PAGER', 'TEXDOCVIEW_txt', 'TEXDOC_VIEWER_TXT'}) +end + +---------------------- options and aliases from files ---------------------- + +-- interpret a confline as a config setting or return false +local function confline_to_config(line, file, pos) + local key, val = string.match(line, '^([%a%d_]+)%s*=%s*(.+)') + if key and val then + set_config_element(key, val, {src='file', file=file, line=pos}) + return true + end + return false +end + +-- set config and aliases from a particular config file assumed to exist +local function read_config_file(configfile) + local err_print = import_function('util', 'err_print') + local confline_to_alias = import_function('alias', 'confline_to_alias') + local confline_to_score = import_function('score', 'confline_to_score') + + local cnf = assert(io.open(configfile, 'r')) + local lineno = 0 + while true do + local line=cnf:read('*line') + lineno = lineno + 1 + + if line == nil then break end -- EOF + line = string.gsub(line, '%s*#.*$', '') -- comments begin with # + line = string.gsub(line, '%s*$', '') -- remove trailing spaces + line = string.gsub(line, '^%s*', '') -- remove leading spaces + + -- 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_config(line, configfile, lineno) + + -- complain if it failed + if not ok then + err_print('warning', + 'syntax error in %s at line %d.', configfile, lineno) + end + end + cnf:close() +end + +-- return the list of configuration files +local function get_config_files() + -- get names + local platform = string.match(kpse.var_value('SELFAUTOLOC'), '.*/(.*)$') + local names = { + 'texdoc-' .. platform .. '.cnf', + 'texdoc.cnf', + 'texdoc-dist.cnf', + } + + -- get dirs + local sep = (os.type == 'windows') and ';' or ':' + local texmf_texdoc = kpse.expand_path('$TEXMF/texdoc') + local dirs = texmf_texdoc:explode(sep) + + -- merge them + local ret = {} + for _, dir in ipairs(dirs) do + for _, name in ipairs(names) do + local pathname = dir .. '/' .. name + table.insert(ret, pathname) + end + end + return ret +end + +-- the config_files table is shared by the following two functions +local setup_config_from_files + +do -- begin scope of config_files +local config_files = {} + +-- set config/aliases from all config files +setup_config_from_files = function() + local file_list = get_config_files() + + for i, file in ipairs(file_list) do + -- determine the status of the config file + local status + if lfs.isfile(file) then + status = config.lastfile_switch and 'disabled' or 'active' + else + status = 'not found' + end + + -- register it + config_files[i] = { + path = file, + status = status, + } + + -- read only if active + if status == 'active' then + read_config_file(file) + end + end +end + +-- now a special information function (see -f,--file option) +function M.show_config_files(is_action) + local w32_path = import_function('util', 'w32_path') + local dbg_print = import_function('util', 'dbg_print') + + -- controled print_func + local indent = is_action and ' ' or '' + local print_func = is_action and print + or function(s) dbg_print('files', s) end + + -- show the list of configuration files + print_func('Configuration files are:') + for i, file in ipairs(config_files) do + -- if not verbose, do not show "not found" files for -f + if file.status ~= "not found" + or (not is_action or config.verbosity_level == 3) then + print_func(indent .. file.status .. '\t' .. w32_path(file.path)) + end + end + + -- show the recommendation (only for the "files" action) + if is_action then + print_func('Recommended file(s) for personal settings:') + local sep = (os.type == 'windows') and ';' or ':' + local texmfhomes = string.explode(kpse.var_value('TEXMFHOME'), sep) + for _, home in ipairs(texmfhomes) do + print_func(indent .. w32_path(home .. '/texdoc/texdoc.cnf')) + end + end +end + +end -- end scope of config_files + +---------------------- config from locale settings ------------------------- + +local function setup_config_from_locale() + local current = os.setlocale(nil, 'all') + os.setlocale('', 'all') + local native = os.setlocale(nil, 'time') + os.setlocale(current, 'all') + local lang = string.match(native, '^[a-z][a-z]') + if lang then + set_config_element('lang', lang, {src='loc'}) + end +end + +---------------------- options from built-in defaults ---------------------- + +-- for default viewer on general Unix, we have a list; the following function is +-- used to check in the path which program is available + +-- check if "name" is the name of a file in the path +-- Warning: to be used only on Unix! (separators, and PATH irrelevant on win32) +-- the value of PATH is cached +local is_in_path +do local path_list = string.explode(os.getenv('PATH'), ':') +is_in_path = function(name) + for _, path in ipairs(path_list) do + if lfs.isfile(path .. '/' .. name) then return true end + end + return false +end +end + +-- returns a viewer specific to a desktop environment if relevant +-- doesn't work on windows (uses io.popen) +-- logic stolen from xdg-open (http://www.freedesktop.org/) and adapted +local function desktop_environment_viewer() + local xdg_current_desktop = os.getenv('XDG_CURRENT_DESKTOP') or '' + if (os.getenv('KDE_SESSION_VERSION') or os.getenv('KDE_FULL_SESSION')) + or string.match(xdg_current_desktop, '.*KDE.*') then + if is_in_path('kde-open') then return '(kde-open %s) &' end + if is_in_path('kfmclient') then return '(kfmclient exec %s) &' end + end + if os.getenv('GNOME_DESKTOP_SESSION_ID') + or string.match(xdg_current_desktop, '.*GNOME.*') then -- gnome + if is_in_path('gvfs-open') then return '(gvfs-open %s) &' end + if is_in_path('gnome-open') then return '(gnome-open %s) &' end + end + if not is_in_path('xprop') then return end + local xprop_fh = io.popen('xprop -root _DT_SAVE_MODE 2>/dev/null') + local xprop_out = xprop_fh:read('*line') + xprop_fh:close() + if xprop_out and string.find(xprop_out, '= "xfce4"$') then -- xfce + return '(exo-open %s) &' + end +end + +-- guess a viewer from a list: +-- - xdg-open from freedesktop if available +-- - try detecting desktop environments +-- - or return the first element of "list" whose name is found in path +-- - or nil +-- caches results of desktop environment detection +local guess_viewer +do local de_viewer +guess_viewer = function(cmds) + -- try the freedesktop method + if is_in_path('xdg-open') then + return '(xdg-open %s) &' + end + -- try desktop environment + if not de_viewer then de_viewer = desktop_environment_viewer() end + if de_viewer then return de_viewer end + -- or look along path + for _, cmd in ipairs(cmds) do + if is_in_path(cmd[1]) then return cmd[2] end + end +end +end + +-- set viewers from defaults (done only if necessary) +function M.get_default_viewers() + local function set_config_ls(ls) set_config_list(ls, {src='def'}) end + if (os.type == 'windows') then + set_config_ls { + -- Use 'start' to get file associations. + -- We need to quote the filenames, but the first quoted argument + -- is considered as the title by start, so we provide a dummy title. + -- Also, since the command line parser removes quotes if there + -- is no space inside, the dummy title must contain spaces. + viewer_dvi = 'start "texdoc dvi viewer"', + viewer_html = 'start "texdoc html viewer"', + viewer_pdf = 'start "texdoc pdf viewer"', + viewer_ps = 'start "texdoc ps viewer"', + -- 'more' is always available. + -- However, we can't assume texdoc is called from a cmd.exe window + -- (it can be run from the start->run menu), hence we make sure + -- to open a new window if needed. + viewer_txt = 'start cmd /k more', + viewer_md = viewer_txt, + } + elseif (os.name == 'macosx') then + set_config_ls { + viewer_dvi = 'open', + viewer_html = 'open', + viewer_pdf = 'open', + viewer_ps = 'open', + viewer_txt = 'less', + viewer_md = viewer_txt, + } + else -- generic Unix + set_config_ls { + viewer_dvi = guess_viewer { + {'xdvi', '(xdvi %s) &'}, + {'evince', '(evince %s) &'}, + {'okular', '(okular %s) &'}, + {'kdvi', '(kdvi %s) &'}, + {'xgdvi', '(xgdvi %s) &'}, + {'spawg', '(spawg %s) &'}, + {'spawx11', '(spawx11 %s) &'}, + {'tkdvi', '(tkdvi %s) &'}, + {'dvilx', '(dvilx %s) &'}, + {'advi', '(advi %s) &'}, + {'xdvik-ja', '(xdvik-ja %s) &'}, + {'see', '(see %s) &'} + }, + viewer_html = guess_viewer { + {'firefox', '(firefox %s) &'}, + {'seamonkey', '(seamonkey %s) &'}, + {'mozilla', '(mozilla %s) &'}, + {'konqueror', '(konqueror %s) &'}, + {'epiphany', '(epiphany %s) &'}, + {'opera', '(opera %s) &'}, + {'w3m', 'w3m'}, + {'links', 'links'}, + {'lynx', 'lynx'}, + {'see', 'see'} + }, + viewer_pdf = guess_viewer { + {'xpdf', '(xpdf %s) &'}, + {'evince', '(evince %s) &'}, + {'okular', '(okular %s) &'}, + {'kpdf', '(kpdf %s) &'}, + {'acroread', '(xpdf %s) &'}, + {'see', '(see %s) &'} + }, + viewer_ps = guess_viewer { + {'gv', '(gv %s) &'}, + {'evince', '(evince %s) &'}, + {'okular', '(okular %s) &'}, + {'kghostview', '(kghostview %s) &'}, + {'see', '(see %s) &'} + }, + viewer_txt = guess_viewer { + {'most', 'most'}, + {'less', 'less'}, + {'more', 'more'} + }, + viewer_md = viewer_txt, + } + end +end + +-- set some fall-back default values if no previous value is set +local function setup_config_from_defaults() + local function set_config_ls(ls) set_config_list(ls, {src='def'}) end + local function set_config_elt(key, val) + set_config_element(key, val, {src='def'}) + end + -- various, platform independent, stuff + set_config_ls { + mode = 'view', + interact_switch = 'true', + machine_switch = 'false', + ext_list = 'pdf, htm, html, txt, md, ps, dvi, ', + basename_list = 'readme, 00readme', + badext_list = 'txt, ', + badbasename_list = 'readme, 00readme', + suffix_list = '', + verbosity_level = C.def_verbosity, + debug_list = '', + max_lines = '20', + fuzzy_level = '5', + } + -- zip-related options + set_config_ls { + zipext_list = '', + rm_file = 'rm -f', + rm_dir = 'rmdir', + } +end + +-------------------------- set all configuration --------------------------- + +-- 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() + setup_config_from_files() + setup_config_from_locale() + setup_config_from_defaults() + + -- machine mode implies no interaction + if config.machine_switch == true then + real_set_config('interact_switch', false) + end + + -- debug implies verbose + if #config.debug_list > 0 then + real_set_config('verbosity_level', tonumber(C.max_verbosity)) + end + + -- we were waiting for config.debug_list to be known to do this + M.show_config_files() +end + +return M + +-- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/constants.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-const.tlu index 51d059196cd..5d34bed3f67 100644..100755 --- a/Master/texmf-dist/scripts/texdoc/constants.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-const.tlu @@ -1,14 +1,14 @@ --- constants.tlu: global "constants" for texdoc. +-- texdoclib-const.tlu: global constants for texdoc -- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details +-- The TeX Live team, GPLv3, see texdoclib.tlu for details -- use an empty environment that will become texdoc_env.C (see EOF) local constants = {} local kpse = kpse local setfenv = setfenv local texdoc_env -if setfenv then + +if setfenv then -- Lua <5.2 texdoc_env = getfenv() setfenv(1, constants) else @@ -19,39 +19,43 @@ end -- BEGIN constants -- progname and version -fullname = kpse.find_file('texdoc/texdoclib', 'lua') -progname = 'Texdoc' -version = '3.0' +fullname = kpse.find_file('texdoc/texdoclib', 'lua') +progname = 'Texdoc' +version = '3.1' +release_date = '2019-03-28' -- make sure to update setup_config_from_cl() accordingly -- and set a default value in setup_config_from_defaults() if relevant usage_msg = [[ Usage: texdoc [OPTION...] NAME... - or: texdoc ACTION + or: texdoc [OPTION...] ACTION Try to find appropriate TeX documentation for the specified NAME(s). Alternatively, perform the given ACTION and exit. -Actions: 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 (eg, viewer command). - -D, --debug Activate all debug output (equal to "--debug=all"). - -dLIST, --debug=LIST Activate debug output restricted to LIST. + -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. -Environment variables: PAGER, BROWSER, PDFVIEWER, PSVIEWER, DVIVIEWER, -and *_texdoc of each. +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). -Files: <TEXMF>/texdoc/texdoc.cnf; see output of the --files option. Full manual available via `texdoc texdoc'. Website: <https://tug.org/texdoc/> @@ -59,8 +63,8 @@ Repository: <https://github.com/TeX-Live/texdoc> Please email bugs to <texdoc@tug.org>.]] copyright_msg = [[ -Copyright 2018 Manuel Pégourié-Gonnard, Takuto Asakura, Karl Berry, and Norbert Preining. -License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. +Copyright 2008 Manuel Pégourié-Gonnard, Takuto Asakura, and the TeX Live Team. +License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it.]] actions_ph = 'Actions:\n' @@ -85,34 +89,42 @@ known_options = { 'max_lines', 'lang', 'fuzzy_level', + 'texlive_tlpdb', } error_msg = [[ Try `texdoc --help' for short help, `texdoc texdoc' for full manual.]] notfound_msg = [[ -Sorry, no documentation found for PKGNAME. -If you are unsure about the name, try searching CTAN's TeX catalogue at -http://ctan.org/search.html#byDescription.]] +Sorry, no documentation found for "PKGNAME". +If you are unsure about the name, try full-text searching on CTAN. +Search form: <https://www.ctan.org/search/>]] notfound_msg_ph = 'PKGNAME' +-- exit codes +exit_ok = 0 +exit_error = 1 -- apparently hard-coded in Lua +exit_usage = 2 +exit_notfound = 3 + err_priority = { - error = 1, + error = 1, warning = 2, - info = 3, + info = 3, } -min_verbosity='0' -- (nothing at all) -max_verbosity='3' -def_verbosity='2' +min_verbosity = '0' -- (nothing at all) +max_verbosity = '3' +def_verbosity = '2' known_debugs = { - version = {}, - files = {}, - config = {'files'}, - view = {}, + config = {'files'}, + files = {}, + search = {}, + score = {}, texdocs = {}, - score = {}, - tlpdb = {} + tlpdb = {}, + version = {}, + view = {}, } -- various cache or non-cache files @@ -130,16 +142,17 @@ else _ENV = texdoc_env end --- Make global C a read-only proxy to the local <constants>. +-- Make table C a read-only proxy to the local <constants>. -- Note this is not deep read-only: C.known_debugs is read-only, but -- C.known_debugs.version isn't, for instance. -assert(next(C) == nil, - 'Internal error: table of constants should be empty at this point') +local C = {} setmetatable(C, { __index = constants, - __newindew = function () + __newindew = function() error('Internal error: attempt to modify a constant.') end }) +return C + -- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/score.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-score.tlu index e3b7d0866af..81e1be2a333 100644..100755 --- a/Master/texmf-dist/scripts/texdoc/score.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-score.tlu @@ -1,25 +1,45 @@ --- score.tlu: scoring functions for texdoc +-- texdoclib-score.tlu: scoring functions for texdoc -- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details + +-- dependencies +local texdoc = { + util = require('texdoclib-util'), + config = require('texdoclib-config'), +} + +-- shortcuts +local M = {} +local dbg_print = texdoc.util.dbg_print -- shared variables local global_adjscore, spec_adjscore = {}, {} ------------------------- configuration directives ------------------------- +-- set key in score table to val, without overriding +local function set_score_table(tab, key, val) + local k = string.lower(key) + local v = tonumber(val) + if v then + if tab[k] == nil then tab[k] = v end + return true + end + return false +end + -- interpret a confline as a score directive or return false -function confline_to_score(line, file, pos) +function M.confline_to_score(line, file, pos) local keyw, pat, val -- try global adjscore pat, val = string.match(line, '^adjscore%s+([%w%p]+)%s*=%s*([%d+-.]+)') - if pat and val then + if pat and val then return set_score_table(global_adjscore, pat, val) end -- try keyword specific adjscore keyw, pat, val = string.match(line, - '^adjscore%(([%w%p]+)%)%s+([%w%p]+)%s*=%s*([%d+-.]+)') - if keyw and pat and val then + '^adjscore%(([%w%p]+)%)%s+([%w%p]+)%s*=%s*([%d+-.]+)') + if keyw and pat and val then keyw = string.lower(keyw) spec_adjscore[keyw] = spec_adjscore[keyw] or {} return set_score_table(spec_adjscore[keyw], pat, val) @@ -27,33 +47,88 @@ function confline_to_score(line, file, pos) return false end --- set key in score table to val, without overriding -function set_score_table(tab, key, val) - local k = string.lower(key) - local v = tonumber(val) - if v then - if tab[k] == nil then tab[k] = v end - return true +---------------------------- score computation ----------------------------- + +-- says if pat is a "subword" of str +local function is_subword(str, pat) + local function is_delim(str, i) + return not not string.find(string.sub(str, i, i), '%p') end - return false + + local i, j = string.find(str, pat, 1, true) + return not not (i and j + and (i == 1 or is_delim(str, i) or is_delim(str, i-1)) + and (j == #str or is_delim(str, j) or is_delim(str, j+1))) end ----------------------------- score computation ----------------------------- +-- says if a filename has a bad basename +local function has_bad_basename(file) + file = file:gsub('.*/', '') + for _, b in ipairs(texdoc.config.get_value('badbasename_list')) do + if file:find('^' .. b .. '$') or file:find('^' .. b .. '%.') then + return true + end + end + return false +end --- set the scores for a doclist -function set_list_scores(list, original_kw) - for _, df in ipairs(list) do - set_score(df, original_kw) +-- compute a heuristic score -10 <= s < 10 +local function heuristic_score(file, pat) + dbg_print('score', 'Start heuristic scoring with pattern: ' .. pat) + -- score management + local score = -10 + local function upscore(s, reason, force) + if s > score or force then + score = s + dbg_print('score', + 'New heuristic score: %.1f. Reason: %s', s, reason) + end + end + local slash = not not string.find(pat, '/', 1, true) + -- look for exact or subword match + if M.is_exact_locale(file, pat) then + upscore(5, 'exact match with correct locale') + elseif M.is_exact(file, pat) then + upscore(4, 'exact match') + elseif is_subword(file, pat) then + upscore(1, 'subword match') + end + -- try derivatives unless pat contains a slash + if not slash then + for _, suffix in ipairs(texdoc.config.get_value('suffix_list')) do + local deriv = pat..suffix + if M.is_exact(file, deriv) then + upscore(3, 'exact match for derived pattern: ' .. deriv) + elseif is_subword(file, deriv) then + upscore(2, 'subword match for derived pattern: ' .. deriv) + end + end + end + -- if extension is bad, score becomes an epsilon + local ext = texdoc.config.get_value('ext_list')[M.ext_pos(file)] + if ext and texdoc.config.get_value('badext_list_inv')[ext] and score > 0 then + upscore(0.1, 'bad extension', true) end + -- if basename is bad, score becomes an epsilon + if has_bad_basename(file) and score > 0 then + upscore(0.1, 'bad basename', true) + end + -- bonus for being in the right directory + if string.find('/' .. file, '/' .. pat .. '/', 1, true) and not slash then + upscore(score + 1.5, 'directory bonus') + end + -- done + dbg_print('score', 'Final heuristic score: %.1f', score) + return score end -- set the score of a docfile -function set_score(df, original_kw) - -- scoring is case-insenstitive (patterns are already lowercased) +local function set_score(df, original_kw) + -- scoring is case-insensitive (patterns are already lowercased) local name = string.lower(df.shortname) - deb_print('score', '----------') - deb_print('score', 'Start scoring '..df.realpath) - deb_print('score', 'Name used: '..name) + dbg_print('score', '----------') + dbg_print('score', 'Start scoring ' .. df.realpath) + dbg_print('score', 'Name used: ' .. name) -- get score from patterns local score = -10 for _, pat in ipairs(df.matches) do @@ -61,122 +136,79 @@ function set_score(df, original_kw) local p = string.lower(pat.name) if pat.original then s = df.tree > -1 and heuristic_score(name, p) or 1 - elseif is_exact(name, p) then - local bonus, msg = 0, '' + elseif M.is_exact(name, p) then + local bonus, note = 0, '' if pat.locale then - bonus, msg = 5, ', (language-based)' + bonus, note = 5, ', (language-based)' end s = (pat.score or 10) + bonus -- default alias score is 10 - deb_print('score', string.format( - "Matching alias '%s', score: %g%s", pat.name, s, msg)) + dbg_print('score', + 'Matching alias "%s", score: %.1f%s', pat.name, s, note) end if s > score then score = s end end - deb_print('score', 'Max pattern score: '..tostring(score)) + dbg_print('score', 'Max pattern score: %.1f', score) -- get score from tlp associations if score == -10 and df.tlptodoc then score = -1 - deb_print('score', 'New score: '..tostring(score) - ..' from package name association') + dbg_print('score', + 'New score: %.1f from package name association', score) end if score == -10 and df.runtodoc then score = -5 - deb_print('score', 'New score: '..tostring(score) - ..' from sty/cls association') + dbg_print('score', + 'New score: %.1f from sty/cls association', score) end -- bonus for metadata if df.details then if string.find(string.lower(df.details), 'readme') then score = score + 0.1 - deb_print('score', 'Catalogue "readme" bonus: +0.1') + dbg_print('score', 'Catalogue "readme" bonus: +0.1') else score = score + 1.5 - deb_print('score', 'Catalogue details bonus: +1.5') + dbg_print('score', 'Catalogue details bonus: +1.5') end end -- adjust from keyword-specific tables if df.tree > -1 and spec_adjscore[original_kw] then for pat, val in pairs(spec_adjscore[original_kw]) do - if val and is_subword('/'..name, pat) then + if val and is_subword('/' .. name, pat) then score = score + val - deb_print('score', string.format( - "Adjust by %g from specific pattern '%s'", val, pat)) + dbg_print('score', + 'Adjust by %.1f from specific pattern "%s"', val, pat) end end end -- adjust from global tables if df.tree > -1 then for pat, val in pairs(global_adjscore) do - if val and is_subword('/'..name, pat) then + if val and is_subword('/' .. name, pat) then if score > -10 or val < 0 then score = score + val end - deb_print('score', string.format( - "Adjust by %g from global pattern '%s'", val, pat)) + dbg_print('score', + 'Adjust by %.1f from global pattern "%s"', val, pat) end end end - deb_print('score', 'Final score: '..tostring(score)) + dbg_print('score', 'Final score: %.1f', score) df.score = score end --- compute a heuristic score -10 <= s < 10 -function heuristic_score(file, pat) - deb_print('score', 'Start heuristic scoring with pattern: '..pat) - -- score management - local score = -10 - local function upscore(s, reason, force) - if s > score or force then - score = s - deb_print('score', 'New heuristic score: '..tostring(s) - ..'. Reason: '..reason) - end - end - local slash = not not string.find(pat, '/', 1, true) - -- look for exact or subword match - if is_exact_locale(file, pat) then - upscore(5, 'exact match with correct locale') - elseif is_exact(file, pat) then - upscore(4, 'exact match') - elseif is_subword(file, pat) then - upscore(1, 'subword match') - end - -- try derivatives unless pat contains a slash - if not slash then - for _, suffix in ipairs(config.suffix_list) do - local deriv = pat..suffix - if is_exact(file, deriv) then - upscore(3, 'exact match for derived pattern: '..deriv) - elseif is_subword(file, deriv) then - upscore(2, 'subword match for derived pattern: '..deriv) - end - end - end - -- if extension is bad, score becomes an epsilon - local ext = config.ext_list[ext_pos(file)] - if ext and config.badext_list_inv[ext] and score > 0 then - upscore(0.1, 'bad extension', true) - end - -- if basename is bad, score becomes an epsilon - if has_bad_basename(file) and score > 0 then - upscore(0.1, 'bad basename', true) - end - -- bonus for being in the right directory - if string.find('/'..file, '/'..pat..'/', 1, true) and not slash then - upscore(score + 1.5, 'directory bonus') +-- set the scores for a doclist +local function set_list_scores(list, original_kw) + for _, df in ipairs(list) do + set_score(df, original_kw) end - -- done - deb_print('score', 'Final heuristic score: '..tostring(score)) - return score end -- says if file is an exact match for pat -function is_exact(file, pat) - file = parse_zip(file) +function M.is_exact(file, pat) + file = texdoc.util.parse_zip(file) local slashes = string.gsub(pat, '[^/]+', '[^/]+') - basename = string.match(file, slashes..'$') + basename = string.match(file, slashes .. '$') if not basename then return nil end if basename == pat then return true end - for _, ext in ipairs(config.ext_list) do - if ext ~= '' and ext ~= '*' and basename == pat..'.'..ext then + for _, ext in ipairs(texdoc.config.get_value('ext_list')) do + if ext ~= '' and ext ~= '*' and basename == pat .. '.' .. ext then return true end end @@ -184,56 +216,32 @@ function is_exact(file, pat) end -- says if file is an exact match for pat and the current locale -function is_exact_locale(file, pat) +function M.is_exact_locale(file, pat) if string.match(pat, '%-%l%l%l?$') then -- don't match if the pattern appears to include a language code return false end - local lang = config.lang + local lang = texdoc.config.get_value('lang') if lang then - return is_exact(file, pat .. '-' .. lang) - or is_exact(file, lang .. '-' .. pat) - end - return false -end - --- say if pat is a "subword" of str -function is_subword(str, pat) - local i, j = string.find(str, pat, 1, true) - return not not (i and j - and (i == 1 or is_delim(str, i) or is_delim(str, i-1)) - and (j == #str or is_delim(str, j) or is_delim(str, j+1))) -end - --- say if character i of str is a delimiter (ponctuation) -function is_delim(str, i) - return not not string.find(string.sub(str, i, i), '%p') -end - --- say if a filename has a bad basename -function has_bad_basename(file) - file = file:gsub('.*/', '') - for _, b in ipairs(config.badbasename_list) do - if file:find('^'..b..'$') or file:find('^'..b..'%.') then - return true - end + return M.is_exact(file, pat .. '-' .. lang) + or M.is_exact(file, lang .. '-' .. pat) end return false end --- compare two docfile's: (see search.tlu for structure) +-- compare two docfile's: (see texdoclib-search.tlu for structure) -- 1. by score -- 2. then by extensions (ordered as in ext_list), --- 3. then lexicographically by filename. +-- 3. then lexicographically by fullpath. -- 4. then by tree. -- return true if a is better than b -function docfile_order (a, b) - if a.score > b.score then return true - elseif a.score < b.score then return false - elseif a.ext_pos < b.ext_pos then return true - elseif a.ext_pos > b.ext_pos then return false - elseif a.basename < b.basename then return true - elseif a.basename > b.basename then return false +local function docfile_order(a, b) + if a.score > b.score then return true + elseif a.score < b.score then return false + elseif a.ext_pos < b.ext_pos then return true + elseif a.ext_pos > b.ext_pos then return false + elseif a.realpath < b.realpath then return true + elseif a.realpath > b.realpath then return false else return (a.tree > b.tree) end end @@ -242,28 +250,28 @@ end -- returns the index of the most specific extension of file in ext_list, -- or config.ext_list_max + 1 -function ext_pos(file) +function M.ext_pos(file) -- remove zipext if applicable - file = parse_zip(file) + file = texdoc.util.parse_zip(file) -- now find the extension local p, e, pos, ext - for p, e in ipairs(config.ext_list) do + for p, e in ipairs(texdoc.config.get_value('ext_list')) do if (e == '*') and (ext == nil) then pos, ext = p, e elseif (e == '') and not string.find(file, '.', 1, true) then pos, ext = p, e - elseif string.sub(file, -string.len(e)-1) == '.'..e then + elseif string.sub(file, -string.len(e)-1) == '.' .. e then if (ext == nil) or (ext == '*') or (string.len(e) > string.len(ext)) then pos, ext = p, e end end end - return pos or (config.ext_list_max + 1) + return pos or (texdoc.config.get_value('ext_list_max') + 1) end -- return the "quality" of docfile -function docfile_quality(df) +function M.docfile_quality(df) if df.score > 0 then return 'good' elseif df.score > -100 then @@ -274,18 +282,12 @@ function docfile_quality(df) end -- sort a doclist -function sort_doclist(dl, original_kw) +function M.sort_doclist(dl, original_kw) dl:stop() set_list_scores(dl, original_kw) table.sort(dl, docfile_order) end -return { - sort_doclist = sort_doclist, - docfile_quality = docfile_quality, - ext_pos = ext_pos, - is_exact = is_exact, - confline_to_score = confline_to_score, -} +return M -- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/search.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-search.tlu index 3978021f769..1a7270d0b73 100644..100755 --- a/Master/texmf-dist/scripts/texdoc/search.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-search.tlu @@ -1,21 +1,74 @@ --- search.tlu: file searching functions for texdoc. +-- texdoclib-search.tlu: file searching functions for texdoc -- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details --- Warning: every single function here assumes init_databases() has been called. +-- Warning: Some functions here assume that M.init_databases() has been called. + +-- dependencies +local texdoc = { + const = require('texdoclib-const'), + util = require('texdoclib-util'), + alias = require('texdoclib-alias'), + score = require('texdoclib-score'), + config = require('texdoclib-config'), +} + +-- shortcuts +local M = {} +local C = texdoc.const +local err_print = texdoc.util.err_print +local dbg_print = texdoc.util.dbg_print -- shared by all functions in this file -local s_doclist -- the Doclist objet to be populated by various functions +local s_doclist -- the Doclist object to be populated by various functions local s_meta -- {[normname] = meta, ...} (populated by init_tlp_database) local vanilla -- is this a vanilla TL or a re-package one without tlpdb? +---------------------------- utility functions ----------------------------- + +-- find the TeX Live root +local function get_tlroot() + local tlroot = kpse.var_value('TEXMFROOT') + get_tlroot = function() return tlroot end + return tlroot +end + +-- says if file has a known extension according to ext_list +-- (or known basename according to basename_list) +local function check_ext(file) + file = string.lower(file) + -- remove zipext if applicable + file = texdoc.util.parse_zip(file) + -- then do the normal thing + for _, e in ipairs(texdoc.config.get_value('ext_list')) do + if e == '*' then + return true + elseif (e == '') then + if not string.find(file, '.', 1, true) then + return true + end + else + local dot_e = '.'..e + if string.sub(file, -string.len(dot_e)) == dot_e then + return true + end + end + end + -- is the basename good? + for _, b in ipairs(texdoc.config.get_value('basename_list')) do + if file:find('^' .. b .. '$') or file:find('^' .. b .. '%.') then + return true + end + end + return false +end + ----------------------- docfile and doclist objects ------------------------ --[[ doclist = { [1] = docfile1, [2] = docfiles2, ..., - inv = { realpath1 = index1, ... } + inv = {realpath1 = index1, ...} } The inv subtable is such that for all i @@ -28,18 +81,30 @@ Doclist.__index = Doclist -- create a new list of docfiles function Doclist:new() - local dl = { inv = {} } + local dl = {inv = {}} setmetatable(dl, self) return dl end -- add a docfile to a list function Doclist:add(df) - if not df.realpath then return end -- useful if vanilla == false + -- if no realpath information, unable to add + -- (useful if vanilla == false) + if not df.realpath then return end + + -- check the existence of the file + if not lfs.isfile(df.realpath) then + dbg_print('search', 'File %s not found. Skipping.', df.realpath) + return + end + + -- add the docfile to the list local index = self.inv[df.realpath:lower()] if index then self[index]:mergein(df) else + dbg_print('search', 'File %s found.', df.realpath) + local newindex = #self + 1 self[newindex] = df self.inv[df.realpath:lower()] = newindex @@ -53,7 +118,7 @@ end --[[ docfile = { - -- name and tree are mendatory + -- name and tree are mandatory name = filename (used for scoring only) tree = code of the tree, see below -- at least one of the following fields should exist @@ -83,21 +148,21 @@ tree = - 1 if and only if file is a sty file. Here name is absolute. local Docfile = {} function Docfile:__index(key) if Docfile[key] then return Docfile[key] end - local getter = Docfile['get_'..key] + local getter = Docfile['get_' .. key] if getter then rawset(self, key, getter(self)) return rawget(self, key) end end --- create a new docfile objet using initilisation info +-- create a new docfile object using initialisation info -- required fields: name, tree function Docfile:new(info) local df = {} setmetatable(df, self) for k, v in pairs(info) do if k == 'pattern' then - df.matches = { info.pattern } + df.matches = {info.pattern} else df[k] = v end @@ -105,7 +170,7 @@ function Docfile:new(info) return df end --- merge a second docfile objet in, assuming it represents the same file +-- merge a second docfile object in, assuming it represents the same file function Docfile:mergein(df) for k, v in pairs(df) do if k == 'matches' then @@ -119,12 +184,13 @@ function Docfile:mergein(df) end -- return the full path to the file +local texdocs_tree_to_path -- definition later function Docfile:get_realpath() - if self.tree > 0 then + if self.tree > 0 then return texdocs_tree_to_path(self.tree, self.name) elseif self.tree == 0 then if vanilla then - return get_tlroot()..'/'..self.name + return get_tlroot() .. '/' .. self.name else return kpse.find_file(self.normname, 'TeX system documentation') end @@ -134,7 +200,7 @@ function Docfile:get_realpath() end -- normalise a name from the tlpdb (use for s_meta indexes) -function reloc_tlpdb_path(name) +local function reloc_tlpdb_path(name) return string.gsub(name, '^texmf[^/]*/doc/', '', 1) end @@ -172,97 +238,62 @@ function Docfile:get_matches() return {} end --- from score.tlu -Docfile.get_quality = docfile_quality +-- from texdoclib-score.tlu +Docfile.get_quality = texdoc.score.docfile_quality --- from score.tlu +-- from texdoclib-score.tlu function Docfile:get_ext_pos() - return ext_pos(self.basename) + return texdoc.score.ext_pos(self.basename) end ---------------------- manage TEXDOCS trees à la kpse ---------------------- - -do -- scope of doc_roots -local doc_roots - ---[[ -doc_roots[i] = { - path = initial path, - db = { [file1] = basename1, [file2] = basename2, ... }, -} ---]] +-------------------- select results from TEXDOCS trees --------------------- --- populate the doc_roots filename databases -function init_texdocs_database() - doc_roots = {} - local sep = (os.type == 'windows') and ';' or ':' - local kpse_texdocs = kpse.expand_var("$TEXDOCS") - -- expand the path and turn it into a lua list - local raw_doc_roots = string.explode(kpse.expand_braces(kpse_texdocs), sep) - local max = #raw_doc_roots + 1 - for j, dir in ipairs(raw_doc_roots) do - local i = max - j - local n - local path, db - -- get path, !! and // values - dir, n = string.gsub (dir, '//$', '') - local recursion_allowed = (n == 1) - local path, n = string.gsub (dir, '^!!', '') - local index_mandatory = (n == 1) - deb_print('texdocs', string.format( - 'texdocs[%d] = %s (index_mandatory=%s, recursion_allowed=%s)', - i, path, tostring(index_mandatory), tostring(recursion_allowed))) - -- decide if we should use a ls-R index, the filesystem, or do nothing - local root, shift = lsr_root(path) - if root and shift and recursion_allowed then - deb_print('texdocs', string.format( - 'texdocs[%d] using index: %s (shift=%s)', i, root, shift)) - db = init_lsr_db(root, shift) - elseif not index_mandatory and lfs.isdir(path) then - deb_print('texdocs', string.format( - 'texdocs[%d] using filesystem search', i)) - db = init_tree_db(path, recursion_allowed) - end - -- register this in docroots - doc_roots[i] = { path = path, db = db } +-- says if a file (with its path) matches a pattern +local function matches(pattern, file) + if pattern.original then + return string.find(file:lower(), pattern.name:lower(), 1, true) + else + return texdoc.score.is_exact(file, pattern.name) end end --- return the real path from a texdocs tree number + relative path -function texdocs_tree_to_path(tree, rel) - return doc_roots[tree].path..'/'..rel -end - --- find docfiles in texdocs directories -function get_doclist_texdocs(patlist) - for code, dr in ipairs(doc_roots) do - if dr.db then scan_db(patlist, code, dr.db) end +-- return a docfile object if file "matches", nil otherwise +local function process_file(patlist, file, pathfile, code) + local docfile + local pattern + for _, pattern in ipairs(patlist) do + if matches(pattern, pathfile) then + local info = { + name = pathfile, + tree = code, + pattern = pattern, + } + if docfile then + docfile:mergein(Docfile:new(info)) + else + docfile = Docfile:new(info) + end + end end + return docfile end -end -- scope of doc_roots - --- find a ls-R file in a parent directory and return it or nil -function lsr_root (path) - if not lfs.isdir (path) then return end - local root, shift = path, '' - if string.sub(root, -1) == '/' then root = string.sub(root, 1, -2) end - while string.find(root, '/', 1, true) do - if lfs.isfile(root..'/ls-R') then - return root, shift - end - local last_comp = string.match(root, '^.*/(.*)$') - -- /!\ cannot put last_comp in a regex: can contain special char - root = string.sub(root, 1, - (#last_comp + 2)) - shift = last_comp..'/'..shift +-- scan a database +local function scan_db(patlist, code, lsr_db) + for file, basename in pairs(lsr_db) do + local df = process_file(patlist, basename, file, code) + if df then s_doclist:add(df) end end end +--------------------- manage TEXDOCS trees à la kpse ---------------------- + -- build a db from a ls-R file -function init_lsr_db(root, shift) +local function init_lsr_db(root, shift) -- open the file - local lsr = assert(io.open(root..'/ls-R', 'r')) + local lsr = assert(io.open(root .. '/ls-R', 'r')) local _ = lsr:read('*line') -- throw away first line (comment) + -- scan it local db = {} local maybe_dir, isdoc = true, false @@ -275,7 +306,7 @@ function init_lsr_db(root, shift) local dir_line = maybe_dir and string.match(line, '^%./(.*):$') if dir_line then maybe_dir = false -- next line may not be a dir - if string.sub(dir_line..'/', 1, l) == shift then + if string.sub(dir_line .. '/', 1, l) == shift then isdoc = true current_dir = string.sub(dir_line, l+1) db[current_dir] = nil @@ -283,21 +314,23 @@ function init_lsr_db(root, shift) break -- we're exiting the ./doc (or shift) dir, so it's over end elseif isdoc then - local file = (current_dir == '') and line or current_dir..'/'..line + local file = (current_dir == '') and line or current_dir .. '/' .. line if check_ext(line) then db[file] = line end end end + lsr:close() + return db end -- build a db for a tree without ls-R index -function init_tree_db(base, recurse) +local function init_tree_db(base, recurse) local db = {} local function init_tree_db_rec(dir) - for file in lfs.dir(base..'/'..dir) do + for file in lfs.dir(base .. '/' .. dir) do if file ~= '.' and file ~= '..' then - local f = (dir == '') and file or dir..'/'..file + local f = (dir == '') and file or dir .. '/' .. file if lfs.isdir(base..'/'..f) then if recurse then init_tree_db_rec(f) end else @@ -310,86 +343,99 @@ function init_tree_db(base, recurse) return db end --------------------- select results from TEXDOCS trees --------------------- +local init_texdocs_database, get_doclist_texdocs --- scan a database -function scan_db(patlist, code, lsr_db) - for file, basename in pairs(lsr_db) do - local df = process_file(patlist, basename, file, code) - if df then s_doclist:add(df) end - end -end +do -- begin scope of doc_roots +local doc_roots --- says if file has a known extenstion according to ext_list --- (or known basename according to basename_list) -function check_ext(file) - file = string.lower(file) - -- remove zipext if applicable - file = parse_zip(file) - -- then do the normal thing - for _, e in ipairs(config.ext_list) do - if e == '*' then - return true - elseif (e == '') then - if not string.find(file, '.', 1, true) then - return true - end - else - local dot_e = '.'..e - if string.sub(file, -string.len(dot_e)) == dot_e then - return true +--[[ +doc_roots[i] = { + path = initial path, + db = {[file1] = basename1, [file2] = basename2, ...}, +} +--]] + +-- populate the doc_roots filename databases +init_texdocs_database = function() + -- find a ls-R file in a parent directory and return it or nil + local function lsr_root(path) + if not lfs.isdir (path) then return end + local root, shift = path, '' + if string.sub(root, -1) == '/' then root = string.sub(root, 1, -2) end + while string.find(root, '/', 1, true) do + if lfs.isfile(root .. '/ls-R') then + return root, shift end + local last_comp = string.match(root, '^.*/(.*)$') + -- /!\ cannot put last_comp in a regex: can contain special char + root = string.sub(root, 1, - (#last_comp + 2)) + shift = last_comp .. '/' .. shift end end - -- is the basename good? - for _, b in ipairs(config.basename_list) do - if file:find('^'..b..'$') or file:find('^'..b..'%.') then - return true + + doc_roots = {} + local sep = (os.type == 'windows') and ';' or ':' + local kpse_texdocs = kpse.expand_var("$TEXDOCS") + + -- expand the path and turn it into a lua list + local raw_doc_roots = string.explode(kpse.expand_braces(kpse_texdocs), sep) + local max = #raw_doc_roots + 1 + + for j, dir in ipairs(raw_doc_roots) do + local i = max - j + local n + local path, db + + -- get path, !! and // values + dir, n = string.gsub (dir, '//$', '') + local recursion_allowed = (n == 1) + local path, n = string.gsub (dir, '^!!', '') + local index_mandatory = (n == 1) + dbg_print('texdocs', + 'texdocs[%d] = %s (index_mandatory=%s, recursion_allowed=%s)', + i, path, tostring(index_mandatory), tostring(recursion_allowed)) + + -- decide if we should use a ls-R index, the filesystem, or do nothing + local root, shift = lsr_root(path) + if root and shift and recursion_allowed then + dbg_print('texdocs', + 'texdocs[%d] using index: %s (shift=%s)', i, root, shift) + db = init_lsr_db(root, shift) + elseif not index_mandatory and lfs.isdir(path) then + dbg_print('texdocs', + 'texdocs[%d] using filesystem search', i) + db = init_tree_db(path, recursion_allowed) end + + -- register this in docroots + doc_roots[i] = {path=path, db=db} end - return false end --- say if a file (with its path) matches a pattern -function matches(pattern, file) - if pattern.original then - return string.find(file:lower(), pattern.name:lower(), 1, true) - else - return is_exact(file, pattern.name) +-- find docfiles in texdocs directories +get_doclist_texdocs = function(patlist) + for code, dr in ipairs(doc_roots) do + if dr.db then scan_db(patlist, code, dr.db) end end end --- return a docfile object if file "matches", nil ortherwise -function process_file(patlist, file, pathfile, code) - local docfile - local pattern - for _, pattern in ipairs(patlist) do - if matches(pattern, pathfile) then - local info = { - name = pathfile, - tree = code, - pattern = pattern, - } - if docfile then - docfile:mergein(Docfile:new(info)) - else - docfile = Docfile:new(info) - end - end - end - return docfile +-- return the real path from a texdocs tree number + relative path +texdocs_tree_to_path = function (tree, rel) + return doc_roots[tree].path .. '/' .. rel end +end -- end scope of doc_roots + ---------------------------- look for sty files ---------------------------- -- add doclist entries for sty files in patlist -function get_doclist_sty(patlist) +local function get_doclist_sty(patlist) for _, pat in ipairs(patlist) do local file = kpse.find_file(pat.name) if file then local df = Docfile:new({ - name = file, - tree = -1, + name = file, + tree = -1, pattern = pat, }) s_doclist:add(df) @@ -401,15 +447,8 @@ end -- tlpdb mean TeX Live Package DataBase and tlp means TeX Live Package --- find the TeX Live root -function get_tlroot() - local tlroot = kpse.var_value('SELFAUTOPARENT') - get_tlroot = function() return tlroot end - return tlroot -end - -- return true if cache exists and is newer than original, false otherwise -function good_cache(cache, ori) +local function good_cache(cache, ori) local cache_date = lfs.attributes(cache, 'modification') if not cache_date then return false end local ori_date = assert(lfs.attributes(ori, 'modification')) @@ -417,9 +456,9 @@ function good_cache(cache, ori) end -- make sure a given directory exists, or return nil plus an error string -function mkdir_p(dir) +local function mkdir_p(dir) if lfs.isdir(dir) then return true end - local parent = path_parent(dir) + local parent = texdoc.util.path_parent(dir) if parent then local ok, msg = mkdir_p(parent) if not ok then return nil, msg end @@ -427,41 +466,29 @@ function mkdir_p(dir) return lfs.mkdir(dir) end --- get tlpinfo tables initialised by whatever mean -function init_tlp_database() - local TEXMFVAR = kpse.var_value('TEXMFVAR') - local cache_file = TEXMFVAR..'/'..C.cache_name - local texlive_tlpdb = get_tlroot()..'/tlpkg/texlive.tlpdb' - vanilla = lfs.isfile(texlive_tlpdb) - if vanilla then - if good_cache(cache_file, texlive_tlpdb) then - deb_print('tlpdb', 'Using cached data from '..cache_file) - get_tlpinfo_from_cache(cache_file) - else - deb_print('tlpdb', 'Getting data from tlpdb file '..texlive_tlpdb) - get_tlpinfo_from_tlpdb(texlive_tlpdb) - deb_print('tlpdb', 'Writing data in cache file '..cache_file) - local ok, msg = mkdir_p(path_parent(cache_file)) - if not ok then - err_print('warning', - 'Failed to create cache file in '..cache_file..':') - err_print('warning', msg) - else - print_out_tlpinfo(cache_file) +local print_out_tlpinfo, get_doclist_tlpdb +local get_tlpinfo_from_tlpdb, get_tlpinfo_from_cache, get_tlpinfo_from_dist + +do -- begin scope of tlpinfo tables +local tlp_from_runfile -- {[runfile_basename] = {tlp1 = true, ...}, ...} +local tlp_doclist -- {[tlp_name] = {relname1, relname2, ...}, ...} + +-- remove entries for tlp without any docfile +local function remove_useless_tlp() + for tlp, doclist in pairs(tlp_doclist) do + if #doclist == 0 then tlp_doclist[tlp] = nil end + end + for runfile, tlp_set in pairs(tlp_from_runfile) do + for tlp in pairs(tlp_set) do + if not tlp_doclist[tlp] then + tlp_from_runfile[runfile][tlp] = nil end end - else - deb_print('tlpdb', 'Using shipped tlpdb data.') - get_tlpinfo_from_dist() end end -do -- begin scope of tlpinfo tables -local tlp_from_runfile -- { [runfile_basename] = {tlp1 = true, ...}, ... } -local tlp_doclist -- { [tlp_name] = { relname1, relname2, ...}, ... } - -- populate tlpinfo tables using the given texlive.tlpdb -function get_tlpinfo_from_tlpdb(filename) +get_tlpinfo_from_tlpdb = function(filename) s_meta, tlp_from_runfile, tlp_doclist = {}, {}, {} local curr_tlp local state = 'none' @@ -513,24 +540,11 @@ function get_tlpinfo_from_tlpdb(filename) remove_useless_tlp() end --- remove entries for tlp without any docfile -function remove_useless_tlp() - for tlp, doclist in pairs(tlp_doclist) do - if #doclist == 0 then tlp_doclist[tlp] = nil end - end - for runfile, tlp_set in pairs(tlp_from_runfile) do - for tlp in pairs(tlp_set) do - if not tlp_doclist[tlp] then - tlp_from_runfile[runfile][tlp] = nil - end - end - end -end - -- print out data from tlpdb in dofile()-able form -function print_out_tlpinfo(filename) +print_out_tlpinfo = function(filename) local fh = assert(io.open(filename, 'w')) local function printf(s, ...) fh:write(string.format(s, ...)) end + -- s_meta printf('local s_meta = {\n') for k, v in pairs(s_meta) do @@ -539,6 +553,7 @@ function print_out_tlpinfo(filename) printf('},\n') end printf('}\n') + -- tlp_from_runfile printf('local tlp_from_runfile = {\n') for k, v in pairs(tlp_from_runfile) do @@ -547,6 +562,7 @@ function print_out_tlpinfo(filename) printf('},\n') end printf('}\n') + -- tlp_doclist printf('local tlp_doclist = {\n') for k, v in pairs(tlp_doclist) do @@ -556,30 +572,36 @@ function print_out_tlpinfo(filename) end printf('}\n') printf('return s_meta, tlp_from_runfile, tlp_doclist\n') + fh:close() end -- get pre-hashed tlpdb info from a cache file -function get_tlpinfo_from_cache(filename) +get_tlpinfo_from_cache = function(filename) s_meta, tlp_from_runfile, tlp_doclist = dofile(filename) end -- get pre-hashed tlpdb info from a pseudo-cache file -function get_tlpinfo_from_dist() - local f = assert(kpse.find_file(C.data_tlpdb_name, 'texmfscripts')) +get_tlpinfo_from_dist = function() + local f = kpse.find_file(C.data_tlpdb_name, 'texmfscripts') + if not f then + err_print('error', 'No texlive.tlpdb nor shipped tlpdb data found.') + os.exit(C.exit_usage) + end + dbg_print('tlpdb', 'Getting data from shipped tlpdb data file ' .. f) s_meta, tlp_from_runfile, tlp_doclist = dofile(f) end -- get docfiles for pattern using specific tlpdb information -function get_doclist_tlpdb(pattern) +get_doclist_tlpdb = function(pattern) -- runfile to tlp to docfile if tlp_from_runfile[pattern] then for tlp in pairs(tlp_from_runfile[pattern]) do for _, file in ipairs(tlp_doclist[tlp]) do s_doclist:add(Docfile:new{ - name = file, - tree = 0, - runtodoc = true, + name = file, + tree = 0, + runtodoc = true, }) end end @@ -588,109 +610,162 @@ function get_doclist_tlpdb(pattern) if tlp_doclist[pattern] then for _, file in ipairs(tlp_doclist[pattern]) do s_doclist:add(Docfile:new{ - name = file, - tree = 0, - tlptodoc = true, + name = file, + tree = 0, + tlptodoc = true, }) end end end --- fuzzy search by using levenshtein distance -function fuzzy_search(pattern) - local tmp_d - local min = 100 - local result - - for p in pairs(tlp_doclist) do - tmp_d = levenshtein(pattern, p) - if tmp_d < min then - min, result = tmp_d, p - end - end - - if min <= config.fuzzy_level then - return result - else - return '' - end -end - --- calculate levenshtein distance by dynamic programming +-- calculating Levenshtein distance by dynamic programming -- cf. http://lua-users.org/lists/lua-l/2008-01/msg00095.html -function levenshtein(s, t) +function M.levenshtein(s, t) local s, t = tostring(s), tostring(t) if type(s) == 'string' and type(t) == 'string' then local m, n, d = #s, #t, {} - for i = 0, m do d[i] = { [0] = i } end + for i = 0, m do d[i] = {[0] = i} end for j = 1, n do d[0][j] = j end for i = 1, m do for j = 1, n do local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1 - d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost) + d[i][j] = math.min( + d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + cost + ) end end return d[m][n] end end -end --scope of tlpinfo table +-- fuzzy search by using Levenshtein distance +function M.fuzzy_search(pattern) + local tmp_d + local min = math.huge + local result = '' + + for p in pairs(tlp_doclist) do + tmp_d = M.levenshtein(pattern, p) + if tmp_d < min then + min, result = tmp_d, p + end + end + + return result, min +end + +end -- end scope of tlpinfo table + +-- get tlpinfo tables initialised by whatever mean +local function init_tlp_database() + local TEXMFVAR = kpse.var_value('TEXMFVAR') + local cache_file = TEXMFVAR .. '/' .. C.cache_name + + -- set vanilla and detect texlive.tlpdb to use + local texlive_tlpdb = get_tlroot() .. '/tlpkg/texlive.tlpdb' + vanilla = lfs.isfile(texlive_tlpdb) + local tlpdb_found = vanilla + + local custom_texlive_tlpdb = texdoc.config.get_value('texlive_tlpdb') + if custom_texlive_tlpdb then + if lfs.isfile(custom_texlive_tlpdb) then + texlive_tlpdb = custom_texlive_tlpdb + tlpdb_found = true + else + err_print('warning', + 'Specified texlive.tlpdb does not exist: ' .. + texdoc.util.w32_path(custom_texlive_tlpdb)) + err_print('warning', + 'Fallback to use the texlive.tlpdb in the distribution.') + end + end + + -- get tlpinfo + if tlpdb_found then + if good_cache(cache_file, texlive_tlpdb) then + dbg_print('tlpdb', 'Using cached data from ' .. cache_file) + get_tlpinfo_from_cache(cache_file) + else + dbg_print('tlpdb', 'Getting data from tlpdb file ' .. texlive_tlpdb) + get_tlpinfo_from_tlpdb(texlive_tlpdb) + dbg_print('tlpdb', 'Writing data in cache file ' .. cache_file) + local ok, msg = mkdir_p(texdoc.util.path_parent(cache_file)) + if not ok then + err_print('warning', + 'Failed to create cache file in %s:', cache_file) + err_print('warning', msg) + else + print_out_tlpinfo(cache_file) + end + end + else + dbg_print('tlpdb', 'Using shipped tlpdb data.') + get_tlpinfo_from_dist() + end +end ------------------------------ main function ------------------------------- -- initialise the various databases (must be called first) -function init_databases() +function M.init_databases() init_texdocs_database() init_tlp_database() end -- find docfiles according to pattern -function get_doclist(pattern, no_alias) +function M.get_doclist(pattern, no_alias) + -- separate sty patterns from the rest + local function normal_vs_sty(list) + local normal, sty = {}, {} + for _, p in ipairs(list) do + if string.match(string.lower(p.name), '%.([^/.]*)$') == 'sty' then + table.insert(sty, p) + else + table.insert(normal, p) + end + end + return normal, sty + end + + local function doc_search(pattern, no_alias) + -- get patterns (inc. aliases) + local patterns = texdoc.alias.get_patterns(pattern, no_alias) + local normal, sty = normal_vs_sty(patterns) + + -- get results; _texdocs search comes after _tlpdb search so that + -- files found by both will have the priority of the _texdocs tree. + -- (https://puszcza.gnu.org.ua/bugs/?369) + get_doclist_sty(sty) + get_doclist_tlpdb(pattern) + get_doclist_texdocs(normal) + end + -- initialise result list s_doclist = Doclist:new() + -- 1. normal search with the input pattern doc_search(pattern, no_alias) + -- 2. if no result, execute fuzzy search - if not s_doclist[1] then - local f_res = fuzzy_search(pattern) - if f_res ~= '' then + local fuzzy_level = texdoc.config.get_value('fuzzy_level') + if not s_doclist[1] and fuzzy_level > 0 then + local f_res, f_lev = M.fuzzy_search(pattern) + if f_lev <= fuzzy_level then err_print('info', 'Fuzzy search result: ' .. f_res) + dbg_print('search', 'Levenshtein distance: ' .. f_lev) pattern = f_res doc_search(pattern, no_alias) + else + dbg_print('search', 'Fuzzy search result: ' .. f_res) + dbg_print('search', 'Levenshtein distance: ' .. f_lev) end end + -- finally, sort results - sort_doclist(s_doclist, pattern) + texdoc.score.sort_doclist(s_doclist, pattern) return s_doclist end -function doc_search(pattern, no_alias) - -- get patterns (inc. aliases) - local normal, sty = normal_vs_sty(get_patterns(pattern, no_alias)) - -- get results; _texdocs search comes after _tlpdb search so that - -- files found by both will have the priority of the _texdocs tree. - -- (https://puszcza.gnu.org.ua/bugs/?369) - get_doclist_sty(sty) - get_doclist_tlpdb(pattern) - get_doclist_texdocs(normal) -end - --- separate sty patterns from the rest -function normal_vs_sty(list) - local normal, sty = {}, {} - for _, p in ipairs(list) do - if string.match(string.lower(p.name), '%.([^/.]*)$') == 'sty' then - table.insert(sty, p) - else - table.insert(normal, p) - end - end - return normal, sty -end - -return { - init_databases = init_databases, - get_doclist = get_doclist, -} +return M -- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu new file mode 100755 index 00000000000..d14a212a123 --- /dev/null +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-util.tlu @@ -0,0 +1,127 @@ +-- texdoclib-util.tlu: utility functions for texdoc +-- +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details + +-- dependencies +local texdoc = { + const = require('texdoclib-const'), + config = require('texdoclib-config'), +} + +-- shortcuts +local M = {} +local C = texdoc.const + +-- change '/' to '\' on windows +-- Note: Internal representation of files always use forward slashes. +-- This function should be called only before displaying a path. +if os.type == 'windows' then + function M.w32_path(path) + return (string.gsub(path, '/', '\\')) + end +else + function M.w32_path(path) + return path + end +end + +-- remove the last directory component of a path +if os.type == 'windows' then + function M.path_parent(path) + return string.match(path, '^(.*)[\\/]') + end +else + function M.path_parent(path) + return string.match(path, '^(.*)/') + end +end + +-- generic log display function +local function log(label, msg, ...) + io.stderr:write('texdoc ' .. label .. ': ' .. msg:format(...) .. '\n') +end + +-- generic error display function (see the err_priority constant) +function M.err_print(lvl, msg, ...) + -- be careful: maybe config item "verbosity_level" has not set yet + local verbosity_level = texdoc.config.get_value('verbosity_level') + or tonumber(C.def_verbosity) + + -- print if the priority is higher than current verbosity level + if C.err_priority[lvl] <= verbosity_level then + log(lvl, msg, ...) + end +end +local err_print = M.err_print + +do -- begin scope of active_debugs +local active_debugs + +-- set active_debugs +local function set_active_debugs() + local debug_list = texdoc.config.get_value('debug_list') + + if not debug_list then return end + active_debugs = {} + + -- all debug options imply version info + if debug_list[1] then + active_debugs.version = true + else + return + end + + -- if 'all' is the first keyword, just activate all categories + if debug_list[1] == 'all' then + for dbg in pairs(C.known_debugs) do + active_debugs[dbg] = true end + return + end + + -- activate options from the list + for _, dbg in ipairs(debug_list) do + local deps = C.known_debugs[dbg] + if deps then + active_debugs[dbg] = true + for _, d in ipairs(deps) do active_debugs[d] = true end + else + err_print('warning', 'Unknown debug category "' .. dbg .. '".') + end + end +end + +-- generic debug function +function M.dbg_print(cat, msg, ...) + -- make sure active_debugs is set + if not active_debugs then set_active_debugs() end + + -- print message it belongs to an active category + if active_debugs and active_debugs[cat] or cat == 'XXX' then + log('debug-' .. cat, msg, ...) + end +end + +end -- end scope of active_debugs + +-- if file is base .. '.' .. zip with zip in zipext_list, return: base, zip +-- otherwise, return: file, nil +function M.parse_zip(file) + local zip + for _, zip in ipairs(texdoc.config.get_value('zipext_list')) do + local l = #zip + 1 + if string.sub(file, -l, -1) == '.' .. zip then + return string.sub(file, 1, -l - 1), zip + end + end + + return file, nil +end + +-- print a usage message +function M.print_usage() + print(C.usage_msg) +end + +return M + +-- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu new file mode 100755 index 00000000000..126ca576869 --- /dev/null +++ b/Master/texmf-dist/scripts/texdoc/texdoclib-view.tlu @@ -0,0 +1,246 @@ +-- texdoclib-view.tlu: view a document and/or display the list of results in texdoc +-- +-- The TeX Live Team, GPLv3, see texdoclib.tlu for details + +-- dependencies +local texdoc = { + const = require('texdoclib-const'), + util = require('texdoclib-util'), + config = require('texdoclib-config'), +} + +-- shortcuts +local M = {} +local C = texdoc.const +local err_print = texdoc.util.err_print +local dbg_print = texdoc.util.dbg_print + +----------------------------- view a document ----------------------------- + +-- view a document +-- see texdoclib-search.tlu for the structure of the argument +local function view_doc(docfile) + M.view_file(docfile.realpath) +end + +-- view a file, if possible +local function try_viewing(view_command, viewer_replacement) + if string.match (view_command, C.place_holder) then + view_command = string.gsub( + view_command, C.place_holder, viewer_replacement) + else + view_command = view_command .. ' ' .. viewer_replacement + end + + -- try to catch problems with missing DISPLAY on Unix + if os.type == 'unix' and not (os.name == 'macosx') + and os.getenv('DISPLAY') == nil then + err_print('warning', + 'DISPLAY is not set; your viewer will likely have problems.') + err_print('warning', + 'Try --list to list results instead of displaying them.') + end + err_print('info', 'View command: ' .. view_command) + + -- See long comment below this function for the LC_CTYPE story. + -- We only want to reset the environment if we have the value + -- to reset it to. In older versions of luatex, status.lc_* will be nil. + local env_lc_ctype = status.lc_ctype + local luatex_lc_ctype = os.setlocale(nil, 'ctype') + if (env_lc_ctype) then + err_print('info', 'Setting environment LC_CTYPE to: ' .. env_lc_ctype) + os.setenv('LC_CTYPE', env_lc_ctype) + end + + -- the big casino: run the external command. + if os.execute(view_command) > 0 then + err_print('error', 'Failed to execute: ' .. view_command) + os.exit(C.exit_error) + end + + -- reset back to "C" (should always be C and always happen, but in case...) + if (luatex_lc_ctype) then + os.setenv('LC_CTYPE', luatex_lc_ctype) + end +end + +-- get viewer and viewer_replacement before calling try_viewing +-- returns false of failure, true on success viewer_replacement is either: +-- +-- 1. the filename, quoted with "" +-- 2. the filename, quoted with "" and followed by some rm commands +-- +-- The second case happens when the doc is zipped. In the case, this function +-- unzips it in a tmpdir so that the viewer command can use the unzipped file. +function M.view_file(filename) + local viewer, viewer_replacement + + -- check if the file is zipped + local nozipname, zipext = texdoc.util.parse_zip(filename) + + -- determine viewer_replacement + if zipext then + local unzip_cmd = texdoc.config.get_value('unzip_' .. zipext) + + if not unzip_cmd then + err_print('error', 'No unzip command for ".%s" files.', zipext) + os.exit(C.exit_error) + end + + local tmpdir = os.tmpdir('/tmp/texdoc.XXXXXX') + if not tmpdir then + err_print('error', 'Failed to create tempdir to unzip.') + os.exit(C.exit_error) + end + + local basename = string.match(nozipname, '.*/(.*)$') or nozipname + local tmpfile = '"' .. tmpdir .. '/' .. basename .. '"' + local unzip = unzip_cmd .. ' "' .. filename .. '">' .. tmpfile + dbg_print('view', 'Unzip command: ' .. unzip) + + if not os.execute(unzip) then + err_print('error', 'Failed to unzip ' .. filename) + os.remove(tmpfile) + os.remove(tmpdir) + os.exit(C.exit_error) + end + + -- it is necessary to sleep a few secounds. Otherwise, the temporary + -- file could be removed before opening it. + viewer_replacement = tmpfile .. '; sleep 2; ' .. + texdoc.config.get_value('rm_file') .. ' ' ..tmpfile .. '; ' .. + texdoc.config.get_value('rm_dir') .. ' ' .. tmpdir + filename = nozipname + else + viewer_replacement = '"' .. texdoc.util.w32_path(filename) .. '"' + end + + -- files without extension are assumed to be text + local viewext = (filename:match('.*%.([^/]*)$') or 'txt'):lower() + + -- special case : sty files use txt viewer + -- FIXME: hardcoding such cases this way is not very clean + if viewext == 'sty' then viewext = 'txt' end + if viewext == 'texlive' then viewext = 'txt' end + if viewext == 'htm' then viewext = 'html' end + + -- get a viewer from built-in defaults if not already set + if not texdoc.config.get_value('viewer_' .. viewext) then + texdoc.config.get_default_viewers() + end + + -- still no viewers? use txt as a fallback + if not texdoc.config.get_value('viewer_' .. viewext) then + err_print('warning', + 'No viewer defined for ".%s" files, using "viewer_txt" instead.', + viewext) + viewext = 'txt' + end + + -- finally, check validity of the viewer + viewer = texdoc.config.get_value('viewer_' .. viewext) + assert(viewer, 'Internal error: no viewer found.') + dbg_print('view', 'Using "viewer_%s" to open the file.', viewext ) + + return try_viewing(viewer, viewer_replacement) +end + +-- Explanation of locale madness: +-- LuaTeX resets LC_CTYPE, LC_COLLATE, LC_NUMERIC to "C". That is good for +-- inside luatex, but when we run an external program, if the user's +-- environment is something else, we want to switch back to it. As of +-- TL 2017 LuaTeX, we can inspect the user's locale with status.lc_ctype, etc. +-- +-- For texdoc purposes, what matters is LC_CTYPE (so we don't bother with +-- the others). For example, with the less pager, when LC_CTYPE=C, +-- non-ASCII bytes are displayed as "<xx>", where xx is the two hex +-- digits for the byte. + +----------------------------- display results ----------------------------- + +-- print a list of docfile objects (see texdoclib-search.tlu) as a menu +-- if showall is false, stop as soon as a bad result is encountered +local function print_menu(name, doclist, showall) + local max_lines = tonumber(texdoc.config.get_value('max_lines')) + if texdoc.config.get_value('interact_switch') and doclist[max_lines + 1] then + -- 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 + n = n + 1 + end + end + + if n > max_lines then + io.write(n, ' results. Display them all? (y/N) ') + local ans = io.read('*line') + if not ((ans == 'y') or (ans == 'Y') + -- io.read had a bug wrt windows eol on some versions of texlua + or (ans == '\ry') or (ans == '\rY')) then + return + 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 + 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) + end + end + 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') + -- That returns the empty string on an empty line, nil on EOF. + -- We only want to default to viewing 1 on an empty line. + -- Use Lua's faked ternary operator for fun and brevity: + num = (num_str == '' and 1 or tonumber(num_str)) + if num and doclist[num] and num <= last_i then + view_doc(doclist[num]) + end + 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 + 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 + -- 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 + view_doc(doclist[1]) + else + if many and not texdoc.config.get_value('machine_switch') then + print('*** Results for: ' .. name .. ' ***') + end + print_menu(name, doclist, showall) + end +end + +return M + +-- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/texdoclib.tlu b/Master/texmf-dist/scripts/texdoc/texdoclib.tlu index 5de6996aa5f..fb85895d37e 100644 --- a/Master/texmf-dist/scripts/texdoc/texdoclib.tlu +++ b/Master/texmf-dist/scripts/texdoc/texdoclib.tlu @@ -1,8 +1,7 @@ -- texdoclib.tlu: the texdoc library --[[ -Copyright 2008-2018 Manuel Pégourié-Gonnard, Takuto Asakura, Karl Berry, and -Norbert Preining. +Copyright 2008 Manuel Pégourié-Gonnard, Takuto Asakura, and 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 @@ -11,10 +10,10 @@ version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. +PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. +this program. If not, see <https://www.gnu.org/licenses/>. Previous work in the public domain: - Contributions from Reinhard Kotucha (2008). @@ -22,87 +21,17 @@ Previous work in the public domain: - Original shell script by Thomas Esser, David Aspinall, and Simon Wilkinson. --]] ------------------------- functions for submodules ------------------------ - --- texdoc is divided in submodules (files). Each module is loaded in a private --- copy of a shared environment, and can export symbols to this environments --- by returning a table to be merge with this environment. - --- return a simple (not deep) copy of a table -local function simple_copy(t) - local c = {} - for sym, val in pairs(t) do - c[sym] = val - end - return c -end - --- initialise the shared environment with a copy of the global environment -local prv_env = simple_copy(_G) -if setfenv then - setfenv(1, prv_env) -else - _ENV = prv_env -end - --- import symbols from a table to the share environment -local function import_symbols(symbols, name) - for sym, val in pairs(symbols) do - assert(val ~= nil, - 'Internal error: '..name..' exporting undefined symbol '..sym..'.') - assert(prv_env[sym] == nil, - 'Internal error: '..name..' exporting existing symbol '..sym..'.') - prv_env[sym] = val - end -end - --- load a submodule of texdoc -local function texdoc_do(name) - local pathname = kpse.find_file('texdoc/'..name, 'lua') - assert(pathname, 'Internal error: missing submodule: '..name) - local submod - if setfenv then - submod = assert(loadfile (pathname)) - setfenv(submod, simple_copy(prv_env)) - else - local f = assert(io.open(pathname)) - local s = f:read('*a') - f:close() - submod = assert(load(s, pathname, 'bt', simple_copy(prv_env))) - -- submod = assert(loadfile(pathname, 'bt', simple_copy(prv_env))) - end - local symbols = submod() - if symbols then import_symbols(symbols, name) end -end - ------------------------- initilisation & main code ------------------------- - --- pre-declare variables in the shared environment -C = {} -- constants -config = {} -- configuration settings - --- actually load the submodules now -texdoc_do('constants') -texdoc_do('functions') -texdoc_do('alias') -texdoc_do('score') -texdoc_do('config') -texdoc_do('search') -texdoc_do('view') - -return { - setup_config_and_alias = setup_config_and_alias, - read_config_file = read_config_file, - init_databases = init_databases, - print_usage = print_usage, - get_doclist = get_doclist, - deliver_results = deliver_results, - aliased_names = aliased_names, - show_config_files = show_config_files, - config = config, - view_file = view_file, - err_print = err_print, - const = C, +local texdoc = { + const = require('texdoclib-const'), + util = require('texdoclib-util'), + alias = require('texdoclib-alias'), + score = require('texdoclib-score'), + config = require('texdoclib-config'), + search = require('texdoclib-search'), + view = require('texdoclib-view'), + cli = require('texdoclib-cli'), } +return texdoc + -- vim: ft=lua: diff --git a/Master/texmf-dist/scripts/texdoc/view.tlu b/Master/texmf-dist/scripts/texdoc/view.tlu deleted file mode 100644 index 15784ff7390..00000000000 --- a/Master/texmf-dist/scripts/texdoc/view.tlu +++ /dev/null @@ -1,226 +0,0 @@ --- view.tlu view a document and/or display the list of results in texdoc --- --- Manuel Pégourié-Gonnard and the TeX Live team, GPLv3, --- see texdoclib.tlu for details - ------------------------------ view a document ----------------------------- - --- view a document --- see search.tlu for the structure of the argument -function view_doc(docfile) - return view_file(docfile.realpath) -end - --- get viewer and viewer_replacement before calling try_viewing --- returns false of failure, true on success --- viewer_replacement is either: --- 1. the filename, quoted with " --- 2. the filename, quoted with " followed by some rm commands --- The second case happens when the doc was zipped. In the case, this function --- unzips it in a tempdir so that the viewer command can use the unzipped file. -function view_file (filename) - local viewer, viewer_replacement - -- check if the file is zipped - local nozipname, zipext = parse_zip(filename) - -- determine viewer_replacement - if zipext then - local unzip_cmd = config['unzip_'..zipext] - if not unzip_cmd then - err_print('error', - "No unzip command for ."..zipext..' files, skipping '..filename) - return false - end - local tmpdir = os.tmpdir("/tmp/texdoc.XXXXXX") - if not tmpdir then - err_print('error', 'Failed to create tempdir to unzip.') - return false - end - local basename = string.match(nozipname, '.*/(.*)$') or nozipname - local tmpfile = '"'..tmpdir..'/'..basename..'"' - local unzip = unzip_cmd..' "'..filename..'">'..tmpfile - deb_print('view', "Unzip command: "..unzip) - if not os.execute(unzip) then - err_print('error', "Failed to unzip '"..filename.."'") - os.remove(tmpfile) - os.remove(tmpdir) - return false - end - viewer_replacement = ''..tmpfile..'; ' - ..config.rm_file..' '..tmpfile..'; ' - ..config.rm_dir..' '..tmpdir - filename = nozipname - else - viewer_replacement = '"'..w32_path(filename)..'"' - end - -- files without extension are assumed to be text - local viewext = (filename:match('.*%.([^/]*)$') or 'txt'):lower() - -- special case : sty files use txt viewer - if viewext == 'sty' then viewext = 'txt' end - -- FIXME: hardcoding such cases this way is not very clean - if viewext == 'texlive' then viewext = 'txt' end - if viewext == 'htm' then viewext = 'html' end - -- get a viewer from built-in defaults if not already set - if not config['viewer_'..viewext] then - get_default_viewers() - end - -- still no viewers? use txt as a fallback - if not config['viewer_'..viewext] then - err_print('warning', - "No viewer_"..viewext.." defined, using viewer_txt.") - viewext = 'txt' - end - assert(config['viewer_'..viewext], 'Internal error: no viewer found.') - return try_viewing(config['viewer_'..viewext], viewer_replacement) -end - --- view a file, if possible -function try_viewing (view_command, viewer_replacement) - if string.match (view_command, C.place_holder) then - view_command = string.gsub( - view_command, C.place_holder, viewer_replacement) - else - view_command = view_command..' '..viewer_replacement - end - - -- try to catch problems with missing DISPLAY on Unix - if os.type == 'unix' and not (os.name == 'macosx') - and os.getenv('DISPLAY') == nil then - err_print('warning', - "DISPLAY is not set; your viewer will likely have problems.") - err_print('warning', - "Try --list to list results instead of displaying them.") - end - err_print('info', 'View command: '..view_command) - - -- See long comment below this function for the LC_CTYPE story. - -- We only want to reset the environment if we have the value - -- to reset it to. In older versions of luatex, status.lc_* will be nil. - local env_lc_ctype = status.lc_ctype - local luatex_lc_ctype = os.setlocale(nil, 'ctype') - if (env_lc_ctype) then - err_print('info', "Setting environment LC_CTYPE to: "..env_lc_ctype) - os.setenv("LC_CTYPE", env_lc_ctype) - end - - -- the big casino: run the external command. - if not os.execute(view_command) then - err_print('error', "Failed to execute: "..view_command) - return false - end - - -- reset back to "C" (should always be C and always happen, but in case...) - if (luatex_lc_ctype) then - os.setenv("LC_CTYPE", luatex_lc_ctype) - end - - return true -end - --- Explanation of locale madness: --- LuaTeX resets LC_CTYPE, LC_COLLATE, LC_NUMERIC to "C". That is good for --- inside luatex, but when we run an external program, if the user's --- environment is something else, we want to switch back to it. As of --- TL 2017 LuaTeX, we can inspect the user's locale with status.lc_ctype, etc. --- --- For texdoc purposes, what matters is LC_CTYPE (so we don't bother with --- the others). For example, with the less pager, when LC_CTYPE=C, --- non-ASCII bytes are displayed as "<xx>", where xx is the two hex --- digits for the byte. --- --- See <texdoc-dev-source>/tools/Makefile for a standalone test case. - ------------------------------ display results ----------------------------- - --- print a list of docfile objects (see search.tlu) as a menu --- if showall is false, stop as soon as a bad result is encountered -function print_menu(name, doclist, showall) - local max_lines = tonumber(config.max_lines) - if config.interact_switch and doclist[max_lines+1] then - -- there may be too many lines, count them - local n - if showall then - n = #doclist - else - n = 0 - while doclist[n+1] and doclist[n+1].quality == 'good' do - n = n + 1 - end - end - if n > max_lines then - io.write (n, " results. Display them all? (y/N) ") - local ans = io.read('*line') - if not ((ans == 'y') or (ans == 'Y') - -- io.read had a bug wrt windows eol on some versions of texlua - or (ans == '\ry') or (ans == '\rY')) then - return - 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 config.machine_switch == true then - print(name, doc.score, w32_path(doc.realpath), - doc.lang or '', doc.details or '') - else - last_i = i -- save for test below - print(string.format('%2d %s', i, 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 config.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') - -- That returns the empty string on an empty line, nil on EOF. - -- We only want to default to viewing 1 on an empty line. - -- Use Lua's faked ternary operator for fun and brevity: - num = (num_str == "" and 1 or tonumber(num_str)) - if num and doclist[num] and num <= last_i then - view_doc(doclist[num]) - end - end -end - ------------------------ deliver results based on mode --------------------- - -function deliver_results(name, doclist, many) - -- ensure that results were found or apologize - if not doclist[1] or doclist[1].quality == 'killed' then - if not config.machine_switch then - local msg = string.gsub(C.notfound_msg, C.notfound_msg_ph, name) - print(msg) -- get rid of gsub's 2nd value - end - return - end - -- shall we show all of them or only the "good" ones? - local showall = (config.mode == 'showall') - if not showall and doclist[1].quality ~= 'good' then - showall = true - err_print('info', 'No good result found, showing all results.') - end - -- view result or show menu based on mode and number of results - if (config.mode == 'view') - or config.mode == 'mixed' and (not doclist[2] - or (doclist[2].quality ~= 'good' and not showall)) then - view_doc(doclist[1]) - else - if many and not config.machine_switch then - print ("*** Results for: "..name.." ***") - end - print_menu(name, doclist, showall) - end -end - -return { - view_file = view_file, - deliver_results = deliver_results, -} - --- vim: ft=lua: diff --git a/Master/texmf-dist/texdoc/texdoc.cnf b/Master/texmf-dist/texdoc/texdoc.cnf index bdf2ad1394d..5fcb2a53448 100644 --- a/Master/texmf-dist/texdoc/texdoc.cnf +++ b/Master/texmf-dist/texdoc/texdoc.cnf @@ -2,10 +2,10 @@ # Public domain. # # DO NOT edit this file! -# For your personal settings, run 'texdoc -f' and use the file indicated by a -# star; you may need to create it. DO NOT copy the present file, please -# create a new one (you may want to copy/paste/edit portions of the present -# file however, or just read it for inspiration). +# For your personal settings, run 'texdoc -f' and use the recommended file; you +# may need to create it. DO NOT copy the present file, please create a new one +# (you may want to copy/paste/edit portions of the present file however, or +# just read it for inspiration). # # For system-wide configuration or other uses, you may want to use the other # files listed, see the manual (texdoc texdoc) for details. The files are read @@ -18,9 +18,8 @@ # Everything after a # on a line is ignored. # Spaces at the beginning/end of a line, as well as empty lines, are ignored. # -# For more details, see the texdoc manual (try `texdoc texdoc'). +# For more details, see the texdoc manual (try 'texdoc texdoc'). - # General settings # ================ @@ -49,52 +48,51 @@ ## Zipped documentation support # WARNING: support for zipped documents works only on Unix. Make sure that the -# values of the associated options are adapted to your system. Read the above +# values of the associated options are adapted to your system. Read the above # warning concerning viewers. # Built-in defaults (for reference): # -# zipext_list = # (empty list) -# rm_file = rm -f -# rm_dir = rmdir +# zipext_list = # the empty list +# rm_file = rm -f +# rm_dir = rmdir # # For each "ext" in zipext_list, you must define a "unzip_ext" unzipper. # The unzipped data must be printed on stdout. Example: # # zipext_list = gz -# unzip_gz = gzip -d -c +# unzip_gz = gzip -d -c ## User interaction # Built-in defaults (for reference): # -# mode = view +# mode = view # -# interact_switch = true -# machine_switch = false +# interact_switch = true +# machine_switch = false # -# verbosity_level = 2 # Print: 0: nothing, 1: errors, 2: warnings, 3: infos -# debug_list = # the empty list +# verbosity_level = 2 # Print: 0: nothing, 1: errors, 2: warnings, 3: infos +# debug_list = # the empty list ## Documentation searching # Built-in defaults (for reference): # -# ext_list = pdf, htm, html, txt, ps, dvi, # Note: empty string at end -# badext_list = txt, # Note: empty string at end -# basename_list = readme, 00readme +# ext_list = pdf, html, htm, txt, md, ps, dvi, # Note: empty string at end +# badext_list = txt, # Note: empty string at end +# basename_list = readme, 00readme # badbasename_list = readme, 00readme ## Fuzzy search # Built-in defaults (for reference): # -# fuzzy_level = 5 +# fuzzy_level = 5 # Known suffixes for documentation suffix_list = doc, -doc, _doc, .doc, /doc, manual, /manual, -manual, userguide, /user_guide, -guide, -user, -man, notes, -info, ref - # Score adjustments # ================= @@ -103,7 +101,7 @@ suffix_list = doc, -doc, _doc, .doc, /doc, manual, /manual, -manual, userguide, # Results with score <= -100 are never displayed. # # The score of results containing a given pattern can be adjusted using the -# 'adjscore' directive, either globally or only for specific queries. It is +# 'adjscore' directive, either globally or only for specific queries. It is # also possible to set the score directly in alias directives, see the next # section. # @@ -119,71 +117,66 @@ suffix_list = doc, -doc, _doc, .doc, /doc, manual, /manual, -manual, userguide, # Makefile are never documentation, just as documents in src or source subdir # -1000 should be enough to kill them adjscore /Makefile = -1000 -adjscore /src/ = -1000 -adjscore /source/ = -1000 +adjscore /src/ = -1000 +adjscore /source/ = -1000 # licence files aren't very likely to contain relevant documentation, but it # feels wrong to totally kill them adjscore copying = -10 adjscore license = -10 -adjscore gpl = -10 +adjscore gpl = -10 # tex-virtual-academy provides a lot of spurious matches adjscore /tex-virtual-academy-pl/ = -50 # test and example files are not likely the best documentation -adjscore example = -1 -adjscore examples = -1 -adjscore sample = -1 -adjscore samples = -1 -adjscore test = -3 -adjscore tests = -3 -adjscore /demo/ = -1 -adjscore /demos/ = -1 +adjscore example = -1 +adjscore examples = -1 +adjscore sample = -1 +adjscore samples = -1 +adjscore test = -3 +adjscore tests = -3 +adjscore /demo/ = -1 +adjscore /demos/ = -1 adjscore /figures/ = -3 -adjscore /images/ = -3 +adjscore /images/ = -3 -# readme's usually get a negative score because they have a bad extension, +# readme files usually get negative scores because they have bad extensions, # but they're still slightly better than other results with negative scores -adjscore readme = 0.1 - -# uncomment this to make the man pages have a greater priority -#adjscore .man1. = 5 -#adjscore .man5. = 5 +adjscore readme = +0.1 ## Specific adjustments -# 'texdoc' may look like "tex's documentation" but it isn't -# similar problem with 'tex-*' -adjscore(tex) texdoc = -10 +# 'texdoc' may look like "tex's documentation" but it isn't; 'tex-*' as well +adjscore(tex) texdoc = -10 adjscore(tex) tex-gyre = -10 -adjscore(tex) tex-ps = -10 +adjscore(tex) tex-ps = -10 # avoid too many results to be shown for 'latex' # package names -adjscore(latex) cjw-latex = -10 -adjscore(latex) cweb-latex = -10 -adjscore(latex) duerer-latex = -10 -adjscore(latex) guide-to-latex = -10 # only useful with the book -adjscore(latex) latex-web-companion = -10 -adjscore(latex) ocr-latex = -10 -adjscore(latex) tufte-latex = -10 +adjscore(latex) cjw-latex = -10 +adjscore(latex) cweb-latex = -10 +adjscore(latex) duerer-latex = -10 +adjscore(latex) guide-to-latex = -10 # only useful with the book +adjscore(latex) latex-web-companion = -10 +adjscore(latex) ocr-latex = -10 +adjscore(latex) tufte-latex = -10 # file names adjscore(latex) Content_LaTeX_Package_Demo = -10 -adjscore(latex) example_latex = -10 -adjscore(latex) test_latex = -10 +adjscore(latex) example_latex = -10 +adjscore(latex) test_latex = -10 # beamer adjscore(beamer) beamer-tut-pt/tutorialbeamer = +10 -adjscore(beamer) beamer-FUBerlin = -3 -adjscore(beamer) beamer-tut-pt = -10 -adjscore(beamer) presentations = -10 +adjscore(beamer) beamer-FUBerlin = -3 +adjscore(beamer) beamer-tut-pt = -10 +adjscore(beamer) presentations = -10 # misc -adjscore(context) circuitikz = -10 -adjscore(context) /gnuplot/ = -3 +adjscore(context) circuitikz = -10 +adjscore(context) /gnuplot/ = -3 adjscore(context) context.man1 = +2 -adjscore(symbols) /staves/ = -5 +adjscore(symbols) /staves/ = -5 # catalogue info missing in the tlcontrib version of the package :-( adjscore(pgf) pgfmanual.pdf = +5 @@ -192,7 +185,7 @@ adjscore(pgf) pgfmanual.pdf = +5 adjscore(hyph-utf8) hyphenation.pdf = +5 # let's not have context version found first -adjscore(fixme) /third/ = -6 +adjscore(fixme) /third/ = -6 # prioritize newer document adjscore(babel-german) ngermanb.pdf = +5 @@ -200,7 +193,9 @@ adjscore(babel-german) ngermanb.pdf = +5 # prioritize man page adjscore(findhyph) findhyph.man1 = +5 - +# prioritize official latex-tools +adjscore(layout) /tools/ = +1 + # Aliases # ======= @@ -213,43 +208,44 @@ adjscore(findhyph) findhyph.man1 = +5 ## Essential documentation -alias live = texlive-en -alias texlive = texlive-en +alias live = texlive-en +alias texlive = texlive-en alias tex-live = texlive-en ## various stuff # a few useful general documents alias faq-en = newfaq -alias faq = newfaq -alias latex = latex-doc-ptr +alias faq = newfaq +alias latex = latex-doc-ptr # various lshort translations adjscore(lshort) /lshort-english/ = +0.5 # original -alias lshort-de = l2kurz # german -alias lshort-pl = lshort-polish/lshort2e # polish -alias lshort-pt = pt-lshort # portuguese -alias lshort-sk = slshorte # slovak -alias lshort-es = lshort-spanish/lshort-a4 # spanish +alias lshort-de = l2kurz # german +alias lshort-ja = jlshort # japanese +alias lshort-pl = lshort-polish/lshort2e # polish +alias lshort-pt = pt-lshort # portuguese +alias lshort-sk = slshorte # slovak +alias lshort-es = lshort-spanish/lshort-a4 # spanish # *TeX engines reference manuals, man pages and related -alias e-tex-ref = etex_man -alias etex-ref = etex_man +alias e-tex-ref = etex_man +alias etex-ref = etex_man alias pdftex-ref = pdftex-a -#alias xetex-ref = xetex-reference # OK -alias xelatex = xetex-reference +#alias xetex-ref = xetex-reference # OK +alias xelatex = xetex-reference alias luatex-ref = luatexref-t # by default, <engine> = <engine>-ref (duplicated: no alias cascading) -alias e-tex = etex_man -alias etex = etex_man -alias pdftex = pdftex-a -#alias xetex = xetex-reference # OK -alias xelatex = xetex-reference -alias luatex = luatexref-t - -alias e-tex-man = etex.man1 -alias etex-man = etex.man1 +alias e-tex = etex_man +alias etex = etex_man +alias pdftex = pdftex-a +#alias xetex = xetex-reference # OK +alias xelatex = xetex-reference +alias luatex = luatexref-t + +alias e-tex-man = etex.man1 +alias etex-man = etex.man1 alias pdftex-man = pdftex.man1 #alias xetex-man = xetex.man1 # missing alias luatex-man = luatex.man1 @@ -257,169 +253,172 @@ alias luatex-man = luatex.man1 alias luatex-pkg = oberdiek/luatex.pdf # latex/basic classes -alias article = classes -alias book = classes -alias report = classes -#alias ltxguide = ? # missing -#alias minimal = ? # missing +alias article = classes +alias book = classes +alias report = classes +#alias ltxguide = ? # missing +#alias minimal = ? # missing adjscore(minimal) europecv = -1000 # false positive # latex/basic packages, sorted by dtx -alias doc = base/doc -alias shortvrb = base/doc -alias letter = base/letter -alias slides = base/slides -alias(20) fontenc = encguide +alias doc = base/doc +alias shortvrb = base/doc +alias letter = base/letter +alias slides = base/slides +alias(20) fontenc = encguide alias(20) textcomp = encguide -alias fix-cm = fixltx2e -alias bezier = latex209 -alias fleqn = latex209 -alias leqno = latex209 -alias openbib = latex209 -alias t1enc = latex209 -alias makeidx = makeindx -alias showidx = makeindx -alias flafter = source2e -alias fontenc = source2e -alias textcomp = source2e -alias tracefnt = source2e +alias fix-cm = fixltx2e +alias bezier = latex209 +alias fleqn = latex209 +alias leqno = latex209 +alias openbib = latex209 +alias t1enc = latex209 +alias makeidx = makeindx +alias showidx = makeindx +alias flafter = source2e +alias fontenc = source2e +alias textcomp = source2e +alias tracefnt = source2e # TODO: try to avoid the huge amount of false positives for `doc' itself. # latex's required graphics bundle -alias color-dev = color -alias epsfig-dev = epsfig +alias color-dev = color +alias epsfig-dev = epsfig alias graphics-dev = graphics alias graphicx-dev = graphicx -alias color = grfguide -alias epsfig = grfguide -alias graphics = grfguide -alias graphicx = grfguide +alias color = grfguide +alias epsfig = grfguide +alias graphics = grfguide +alias graphicx = grfguide # latex's required psnfss2e bundle -alias avant = psnfss2e -alias bookman = psnfss2e -alias chancery = psnfss2e -alias charter = psnfss2e -alias courier = psnfss2e -alias helvet = psnfss2e -alias mathpazo = psnfss2e -alias mathpple = psnfss2e -alias mathptm = psnfss2e -alias mathptmx = psnfss2e -alias newcent = psnfss2e -alias palatino = psnfss2e -alias times = psnfss2e -alias utopia = psnfss2e +alias avant = psnfss2e +alias bookman = psnfss2e +alias chancery = psnfss2e +alias charter = psnfss2e +alias courier = psnfss2e +alias helvet = psnfss2e +alias mathpazo = psnfss2e +alias mathpple = psnfss2e +alias mathptm = psnfss2e +alias mathptmx = psnfss2e +alias newcent = psnfss2e +alias palatino = psnfss2e +alias times = psnfss2e +alias utopia = psnfss2e # ams -alias amsfonts = amsfndoc -alias amslatex2 = technote -alias amsmath = amsldoc -alias amsrefs = amsrdoc -alias amsthm = amsthdoc -alias amsart = instr-l -alias amsbook = instr-l -alias amscls = instr-l -alias amsproc = instr-l -alias amsart-dev = amsclass +alias amsfonts = amsfndoc +alias amslatex2 = technote +alias amsmath = amsldoc +alias amsrefs = amsrdoc +alias amsthm = amsthdoc +alias amsart = instr-l +alias amsbook = instr-l +alias amscls = instr-l +alias amsproc = instr-l +alias amsart-dev = amsclass alias amsbook-dev = amsclass -alias amscls-dev = amsclass +alias amscls-dev = amsclass 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 = 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 scrartcl-de = scrguide +alias scrbook-de = scrguide +alias scrreprt-de = scrguide +alias typearea-de = scrguide # tugboat package and classes alias tugboat = ltubguid # caption -alias caption = caption-eng +alias caption = caption-eng alias caption-dev = caption.pdf # metapost by various names -alias metapost = mpman +alias metapost = mpman alias(5) metapost = mpgraph alias(5) metapost = mpintro -alias mpost = mpman -alias(5) mpost = mpgraph -alias(5) mpost = mpintro -alias mp = mpman -alias(5) mp = mpgraph -alias(5) mp = mpintro +alias mpost = mpman +alias(5) mpost = mpgraph +alias(5) mpost = mpintro +alias mp = mpman +alias(5) mp = mpgraph +alias(5) mp = mpintro # latex3 and friends -alias latex3 = ltx3info -alias l3bootstrap = interface3 -alias l3names = interface3 -alias l3basics = interface3 -alias l3expan = interface3 -alias l3prg = interface3 -alias l3quark = interface3 -alias l3token = interface3 -alias l3int = interface3 -alias l3skip = interface3 -alias l3tl = interface3 -alias l3seq = interface3 -alias l3clist = interface3 -alias l3prop = interface3 -alias l3box = interface3 -alias l3coffins = interface3 -alias l3color = interface3 -alias l3msg = interface3 -alias l3keys = interface3 -alias l3file = interface3 -alias l3fp = interface3 -alias l3luatex = interface3 +alias latex3 = ltx3info +alias(3) expl3 = interface3 +alias(3) expl3 = source3 +alias l3bootstrap = interface3 +alias l3names = interface3 +alias l3basics = interface3 +alias l3expan = interface3 +alias l3prg = interface3 +alias l3quark = interface3 +alias l3token = interface3 +alias l3int = interface3 +alias l3skip = interface3 +alias l3tl = interface3 +alias l3seq = interface3 +alias l3clist = interface3 +alias l3prop = interface3 +alias l3box = interface3 +alias l3coffins = interface3 +alias l3color = interface3 +alias l3msg = interface3 +alias l3keys = interface3 +alias l3file = interface3 +alias l3fp = interface3 +alias l3luatex = interface3 # misc -alias autofe = ucs -alias afoot = arabtex-doc -alias arabicfont = bezos -alias bibtex = btxdoc -alias changes = changes.english.pdf -alias(5) cmsuper = cm-super/FAQ -alias cm-super = cm-super/README -alias cmsuper = cm-super/README -alias cyrillic = cyrillic/00readme.txt -alias elsarticle = elsdoc -alias(0.1) fontinst = fontinstallationguide -alias hyperref = hyperref/manual.pdf -alias hyperref-dev = hyperref.pdf -alias iso = isoman -alias lettrine = lettrine # to hide context/third/lettrine-doc.pdf -alias nonfloat-de = nonfloat -alias nonfloat = nonfloat-en -alias xstring-fr = xstring_doc_fr -alias arabic = arabi/user_guide -alias 3parttable = threeparttable -alias croatian = babel -alias mls = montex -alias vrbexin = verbasef -alias dtk = dtk/doc/beispiel.pdf -alias musixtex = musixdoc -alias mychemistry = mychemistry_en -alias mychemistry-de = mychemistry_de -alias cjk = CJK.txt # FIXME: should be case insensitive -alias ieee = IEEEtran_HOWTO -alias layouts = layman -alias plnfss = plnfss.txt # XXX -alias teubner = teubner-doc -alias xypic = xyguide -alias kvoptions-patch = kvoptions # XXX? -alias cweb = cwebman # XXX: is in 'cweb' dir, should win -alias einfuehrung = einfuehrung/README # tl should get "readme" tag +alias autofe = ucs +alias afoot = arabtex-doc +alias arabicfont = bezos +alias bibtex = btxdoc +alias changes = changes.english.pdf +alias cm = cm/README +alias(5) cmsuper = cm-super/FAQ +alias cm-super = cm-super/README +alias cmsuper = cm-super/README +alias cyrillic = cyrillic/00readme.txt +alias elsarticle = elsdoc +alias(0.1) fontinst = fontinstallationguide +alias hyperref = hyperref/manual.pdf +alias hyperref-dev = hyperref.pdf +alias iso = isoman +alias lettrine = lettrine # to hide context/third/lettrine-doc.pdf +alias nonfloat-de = nonfloat +alias nonfloat = nonfloat-en +alias xstring-fr = xstring_doc_fr +alias arabic = arabi/user_guide +alias 3parttable = threeparttable +alias croatian = babel +alias mls = montex +alias vrbexin = verbasef +alias dtk = dtk/doc/beispiel.pdf +alias musixtex = musixdoc +alias mychemistry = mychemistry_en +alias mychemistry-de = mychemistry_de +alias cjk = CJK.txt # FIXME: should be case insensitive +alias ieee = IEEEtran_HOWTO +alias layouts = layman +alias plnfss = plnfss.txt # XXX +alias teubner = teubner-doc +alias xypic = xyguide +alias kvoptions-patch = kvoptions # XXX? +alias cweb = cwebman # XXX: is in 'cweb' dir, should win +alias einfuehrung = einfuehrung/README # tl should get "readme" tag ## a few easy patterns @@ -430,47 +429,46 @@ alias tree-dvips = tree-manual alias cweb-latex = cweb-user # egrep 'doc\.pdf\>' -alias barcode = eandoc.pdf -alias enctex-cz = encdoc -alias ngerman = gerdoc -alias jurabib-de = jbgerdoc -alias ofs-cz = ofsdoc -alias ofs = ofsdoc-e -alias pst-geo = pst-map3d-doc +alias barcode = eandoc.pdf +alias enctex-cz = encdoc +alias ngerman = gerdoc +alias jurabib-de = jbgerdoc +alias ofs-cz = ofsdoc +alias ofs = ofsdoc-e +alias pst-geo = pst-map3d-doc ## aliases basically borrowed from texdoctk.dat with some adaptations - -alias akletter = akletter/lettereng -alias arydshln = arydshln-man -alias cv = curve/curve +alias akletter = akletter/lettereng +alias arydshln = arydshln-man +alias cv = curve/curve alias datenumber-de = datenumber/docgerman -alias labels(1) = envlab/elguide -alias expressg = expeg -alias flcards = flashcards -alias lehman = fontinstallationguide -alias gnlogic = gn-logic14 -alias kluwer = kluwer/usrman -alias lmfonts = lm-info -alias mathenv = mdwtab -alias montex = mlsquick -alias mltex = mltex/mltex.txt -alias natbib2 = natnotes -alias uktugfaq = newfaq -alias onrannual = onrannual/README -alias otibet = otibet/unidoc -alias pbdiagram = pb-manual -alias tikz = pgfmanual -alias apmgraph = pmgraph -alias preprint = preprint/00readme.txt -alias dutch = rapdoc -alias startex = startex/base/guide -alias tangles = t-angles/t-manual -alias tex4ht = tex4ht/mn.html -alias(60) akademia = tex-virtual-academy-pl/index.html -alias treetex = tree_doc -alias lineno = ulineno -alias texguide = usrguide -alias(5) xypic = xyrefer +alias labels(1) = envlab/elguide +alias expressg = expeg +alias flcards = flashcards +alias lehman = fontinstallationguide +alias gnlogic = gn-logic14 +alias kluwer = kluwer/usrman +alias lmfonts = lm-info +alias mathenv = mdwtab +alias montex = mlsquick +alias mltex = mltex/mltex.txt +alias natbib2 = natnotes +alias uktugfaq = newfaq +alias onrannual = onrannual/README +alias otibet = otibet/unidoc +alias pbdiagram = pb-manual +alias tikz = pgfmanual +alias apmgraph = pmgraph +alias preprint = preprint/00readme.txt +alias dutch = rapdoc +alias startex = startex/base/guide +alias tangles = t-angles/t-manual +alias tex4ht = tex4ht/mn.html +alias(60) akademia = tex-virtual-academy-pl/index.html +alias treetex = tree_doc +alias lineno = ulineno +alias texguide = usrguide +alias(5) xypic = xyrefer ## packages from ctan/macros/latex/contrib/misc or with doc in .sty only @@ -482,28 +480,28 @@ alias(5) xypic = xyrefer # produce suitable documentation for all these packages (thanks to Philipp # Stephani and Robin Fairbairns mostly). -alias(4.1) 3parttable = 3parttable.sty -alias(4.1) bibcheck = bibcheck.sty -alias(4.1) concrete = concrete.sty -alias(4.1) linsys = linsys.sty -alias(4.1) mitpress = mitpress.sty -alias(4.1) nextpage = nextpage.sty -alias(4.1) setspace = setspace.sty -alias(4.1) statex = statex.sty -alias(4.1) statex2 = statex2.sty +alias(4.1) 3parttable = 3parttable.sty +alias(4.1) bibcheck = bibcheck.sty +alias(4.1) concrete = concrete.sty +alias(4.1) linsys = linsys.sty +alias(4.1) mitpress = mitpress.sty +alias(4.1) nextpage = nextpage.sty +alias(4.1) setspace = setspace.sty +alias(4.1) statex = statex.sty +alias(4.1) statex2 = statex2.sty alias(4.1) texilikecover = texilikecover.sty -alias(4.1) thrmappendix = thrmappendix.sty -alias(4.1) topcapt = topcapt.sty -alias(4.1) vrbexin = vrbexin.sty +alias(4.1) thrmappendix = thrmappendix.sty +alias(4.1) topcapt = topcapt.sty +alias(4.1) vrbexin = vrbexin.sty - # Final hack +# ================ # # The next line has no effect when this file is installed as the last # configuration file (default) but is useful when you install it as the "tricky" # configuration file (usually TEXMFHOME/texdoc/texdoc-dist.cnf) whose mere -# existence is a hack to make it easier to run the the development version, see -# <http://tug.org/texdoc/dev/>. +# existence is a hack to make it easier to run the development version, see +# <https://github.com/TeX-Live/texdoc>. # # It is strongly recommended NOT to use it in any other circumstance. lastfile_switch = true |