[tex-live] texdoc in luatex
Frank Küster
frank at kuesterei.ch
Thu Jun 28 19:40:28 CEST 2007
Frank Küster <frank at kuesterei.ch> wrote:
> Frank Küster <frank at kuesterei.ch> wrote:
>
>> Thanks, I've started working on "texdoclua".
>
> So here is the next iteration.
Now I'm at version 0.3:
--[[ Changelog
0.3 2007-06-28
- added changelog
- better OS detection for default viewer settings
- removed some debugging code
- -s now works in dirs without ls-R, too
And I guess that should be it for a while (I'm going on vacation the
next two weeks).
Regards, Frank
--
Frank Küster
Single Molecule Spectroscopy, Protein Folding @ Inst. f. Biochemie, Univ. Zürich
Debian Developer (teTeX/TeXLive)
-------------- next part --------------
#!/usr/bin/env texlua
--[[ Written in lua by Frank Küster (2007) based on the shell script by
Thomas Esser, David Aspinall, and Simon Wilkinson.
Public domain.]]
--[[ Changelog
0.3 2007-06-28
- added changelog
- better OS detection for default viewer settings
- removed some debugging code
- -s now works in dirs without ls-R, too
0.2 2007-06-28
- implemented reading of configuration from texmf.cnf
- fixed "-s" option
0.1
- initial public release
]]
progname = 'texdoc';
version = '0.2';
usage = ' Usage: ' .. progname ..' [-h|--help] name\
-h|--help\t\t Show this help\
-V|--version\t\t Print the version of the program\
-v|--verbose\t\t Show the command being used to display the documentation\
-l|--list\t\t List matching files, do not start a viewer.\
-s|--search\t\t search for name as a pattern';
if not arg[1] then
print (usage);
return
end
mode = 'view';
verbose = false;
while table.maxn(arg) > 0 and string.match(arg[1],'^%-') do
curr_arg = table.remove(arg,1)
if string.match (curr_arg,'-h') or string.match (curr_arg,'--help') then
print (usage);
os.exit(0);
elseif string.match (curr_arg,'-V') or string.match (curr_arg,'--version') then
print (progname .. ' version: ' .. version );
os.exit(0);
elseif string.match (curr_arg,'-v') or string.match (curr_arg,'--verbose') then
verbose = true;
elseif string.match (curr_arg,'-l') or string.match (curr_arg,'--list' ) then
mode = 'list';
elseif string.match (curr_arg,'-s') or string.match (curr_arg,'--search' ) then
mode = 'search';
end
end
--[[ function definitions ]]
function list_iter (t)
local i = 0
local n = table.getn(t)
return function ()
i = i + 1
if i <= n then return t[i] end
end
end
-- [[ functions for the search option ]]
no_lsr_doctrees = {};
function get_lsr_files ()
local lsr_files = {};
local pathlist = kpse.expand_braces('$TEXDOCS');
for path in string.gmatch(pathlist, "[^:;]+") do
path = string.gsub(path,'//$','')
local tree_root
tree_root = string.gsub(path,'doc$','')
tree_root = string.gsub(tree_root,'^!!','')
if lfs.isfile(tree_root .. "ls-R") then
table.insert(lsr_files,tree_root .. "ls-R")
else
if not string.match(path,'^%.$') and lfs.isdir(path) then
table.insert(no_lsr_doctrees,path)
end
end -- does lsRfile exist?
end -- for path
local i = 0
local n = table.getn(lsr_files)
-- TODO: We completely ignore trees without ls-R files. Since I
-- don't know how to get the output of "find" without resorting to
-- temporary files, anyway, I don't care.
return function ()
i = i +1
if i <= n then return lsr_files[i] end
end
end -- get_lsr_files()
function deluaficate(oldpat)
local newpat
-- better use long strings here, no escaping of \ needed there.
newpat = string.gsub(oldpat,'([^\\])%-','%1%%%-')
newpat = string.gsub(newpat,'\\','')
return newpat
end --deluaficate
docdirs = {}
docfiles = {}
function pattern_search (pattern)
pattern = deluaficate(pattern)
-- populate docdirs and doclines list
for database in get_lsr_files() do
local texmf_tree = string.gsub(database,'ls%-R$','')
is_docline = false
local this_dir -- changed to each individual docdir
for line in io.lines(database) do
if string.match(line,'^./') then
-- a directory
this_dir = string.gsub(line,'^./',texmf_tree)
this_dir = string.gsub(this_dir,':$','/')
if string.match(line,'^./doc') then
-- the next file lines are in docdir "this_dir"
is_docline = true
-- save it in the docdirs table
table.insert(docdirs,this_dir)
else
is_docline = false
end -- docdir
elseif string.match(line,'^%s*$') then
-- empty line, do nothing
-- now we have only file lines left, are they a docline?
elseif is_docline then
local fullpath = this_dir .. line
-- print(fullpath)
table.insert(docfiles,fullpath)
end -- line starting with ./
end -- for line
end -- for database
for no_lsr_dir in list_iter(no_lsr_doctrees) do
recurse_tree(no_lsr_dir)
end
print("Directories that match:")
for dir in list_iter(docdirs) do
if string.match(dir,pattern) then
print (dir)
end
end -- for dir
print()
print("Files that match:")
for file in list_iter(docfiles) do
if string.match(file,pattern) then
print (file)
end
end -- for file
end -- function pattern_search()
function recurse_tree (path)
for file in lfs.dir(path) do
if file ~= "." and file ~= ".." then
local f = path..'/'..file
local attr = lfs.attributes (f)
if attr then -- else stale symlink
if attr.mode == "directory" then
table.insert(docdirs,f)
recurse_tree (f)
else
table.insert(docfiles,f)
end
end
end
end
end --function recurse_tree
--[[ functions for parsing texmf.cnf ]]
function set_var_from_texmf(oldvalue,texmfvar)
local newvalue
newvalue = kpse.var_value(texmfvar)
if newvalue then
return newvalue
else
return oldvalue
end
end
function set_listvar_from_texmf(oldvalue,texmfvar)
local list_as_string
local templist = {}
list_as_string = set_var_from_texmf('',texmfvar)
for element in string.gmatch(list_as_string,'[^,;:]+') do
table.insert(templist,element)
end
if table.maxn(templist) > 0 then
return templist
else
return oldvalue
end
end -- set_listvar_from_texmf
function set_listvar_from_expand_braces(oldvalue,texmfvar)
local list_as_string
local templist = {}
list_as_string = kpse.expand_braces(texmfvar)
for element in string.gmatch(list_as_string,'[^,;:]*:') do
element = string.gsub(element,':','')
table.insert(templist,element)
end
if table.maxn(templist) > 0 then
return templist
else
return oldvalue
end
end -- set_listvar_from_expand_braces
--[[ initialize kpathsea ]]
kpse.set_program_name("texdoc")
-- [[ initialize some variables ]]
texdoc_formats = {'dvi','pdf','ps','txt','html'}
if string.find(os.getenv("PATH"),";") then
-- probably Windows (or OS/2)
-- which commands should we use for unzipping?
texdoc_unzip = {
gz = "gzip -d -c ",
bz2 = "bzip2 -d -c "
};
texdoc_viewer = {
dvi = '(start %s ) &',
html = '(start %s) &',
pdf = '(start %s) &',
ps = '(start %s) &',
txt = '(start %s) &',
tex = '(start %s) &'
};
rmfile_command = 'del /F ';
rmdir_command = 'rmdir ';
else
-- probably UNIX-like
texdoc_unzip = {
gz = "gzip -d -c ",
bz2 = "bzip2 -d -c "
};
texdoc_viewer = {
dvi = '(xdvi %s ) &',
html = '(see %s) &',
pdf = '(xpdf %s) &',
ps = '(gv %s) &',
txt = '(less %s )',
tex = '(less %s )'
};
rmfile_command = 'rm -f ';
rmdir_command = 'rmdir ';
end
texdoc_zipformats = {'','gz','bz2'};
texdoc_formats = {'','dvi','html','pdf','ps','txt','tex'};
extlist = {'','.dvi', '.dvi.gz', '.dvi.bz2', '.pdf', '.pdf.gz', '.pdf.bz2', '.ps', '.ps.gz', '.ps.bz2', '.txt', '.txt.gz', '.txt.bz2', '.html'};
-- [[ override hardcoded variables with values from texmf.cnf ]]
rmfile_command = set_var_from_texmf(rmfile_command,'TEXDOC_RMFILE')
rmdir_command = set_var_from_texmf(rmdir_command,'TEXDOC_RMDIR')
texdoc_formats = set_listvar_from_texmf(texdoc_formats,'TEXDOC_FORMATS')
for format in list_iter(texdoc_formats) do
viewer_var = 'TEXDOC_VIEWER_' .. string.upper(format)
texdoc_viewer[format] = set_var_from_texmf(texdoc_viewer[format],viewer_var)
end
texdoc_zipformats = set_listvar_from_texmf(texdoc_zipformats,'TEXDOC_ZIPFORMATS')
for zipext in list_iter(texdoc_zipformats) do
viewer_var = 'TEXDOC_UNZIP_' .. string.upper(zipext)
texdoc_unzip[zipext] = set_var_from_texmf(texdoc_unzip[zipext],viewer_var)
end
extlist = set_listvar_from_expand_braces(extlist,'$TEXDOCEXT');
-- we want an empty string for ext at the beginning, so that it works
-- to specify the complete filename. Doesn't matter when there's one
-- more empty string, but we can easily avoid two in a row
if not extlist[1] == '' then
insert(extlist,1,'')
end
for docname in list_iter (arg) do
if string.match(mode,'search') then
pattern_search(docname);
elseif string.match(mode,'view') or string.match(mode,'list') then
for ext in list_iter(extlist) do
filename = kpse.find_file(docname .. ext , "TeX system documentation")
if filename then
if string.match (mode, 'list') then
print(filename);
else
-- mode is view, is unzipping needed?
zipext = string.match(ext,'%..*%.(.*)');
if zipext then
unzip_command = texdoc_unzip[zipext];
viewext = string.match(ext,'%.(.*)%..*$');
basebame_pattern = '.*/(.*%.' .. viewext .. ')';
basename = string.match(filename,basebame_pattern);
-- uncompress only once per file, in case it is given more
-- than once (dvi besides ps or so)
-- TODO: to be done
tmpdir = os.tmpname();
is_ok_tmpdir,error_string = lfs.mkdir(tmpdir)
if is_ok_tmpdir then
-- needs_cleanup = true;
else
print(error_string);
os.exit(1);
end
unzip_commandline = unzip_command .. filename .. " > " .. tmpdir .. "/" .. basename;
if os.execute(unzip_commandline) then
filename = tmpdir .. "/" .. basename;
else
print("Error executing \n" .. unzip_commandline);
end
viewer_replacement = filename .. ';' .. rmfile_command .. filename .. ';' .. rmdir_command .. tmpdir;
else
if ext == '' then
-- fallback if complete filename has been specified
ext = string.match(filename,'.*(%..*)$')
end
viewer_replacement = filename;
viewext = string.match(ext,'%.(.*)$');
if not texdoc_viewer[viewext] then
-- complete filename specified, unknown extension, use "txt"
viewext = 'txt'
end
end -- zipped or not
view_command = string.gsub(texdoc_viewer[viewext],'%%s',viewer_replacement)
if verbose then
print(view_command);
end
view_result = os.execute(view_command);
if view_result then
do break end;
else
print("Error executing \n" .. view_command);
end
end -- list or view
end -- found a filename with that extension or not?
end -- for ext
end -- if construct "case mode in"
end -- for docname
-- cleanup_tmpdir();
-------------- next part --------------
.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sh \" Subsection heading
.br
.if t .Sp
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
'br\}
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. nr % 0
. rr F
.\}
.\"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.hy 0
.if n .na
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "TEXDOC 1"
.TH TEXDOC 1 "2007-06-05" "perl v5.8.8" "User Contributed Perl Documentation"
.SH "NAME"
texdoc \- Search for NAME in the TeX documentation and start a viewer.
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
\&\fBtexdoc\fR
[\fB\-h|\-\-help\fR]
[\fB\-v|\-\-verbose\fR]
[\fB\-V|\-\-version\fR]
[\fB\-l|\-\-list\fR]
[\fB\-S|\-\-search\fR]
[\fIname|pattern\fR]
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\fBtexdoc\fR is a script which attempts to find and display
documentation for tex files. Without any options, the file
\fBname\fR\fI.ext\fR is displayed, where \fI.ext\fR is one of the
extensions defined in the variable \s-1TEXDOCEXT\s0 in
\&\fBtexmf.cnf\fR. The viewer used for displaying the file can be
customized.
\fBtexdoc\fR accepts compressed files, too. You can also specify the
complete filename, e.g. to decide which of two files with equal
basename you want., In this case, however, access to compressed files
is not possible.
.SH "OPTIONS"
.IP "\fB\-h\fR, \fB\-\-help\fR" 4
Display a usage message
.IP "\fB\-V\fR, \fB\-\-version\fR" 4
Display version information and exit
.IP "\fB\-v\fR, \fB\-\-verbose\fR" 4
verbose mode: show viewer command
.IP "\fB\-l\fR, \fB\-\-list\fR" 4
Just list all files that match \fIname\fR, do not start a viewer.
.IP "\fB\-S\fR, \fB\-\-search\fR \fIpattern\fR" 4
\&\fIpattern\fR is treated as a lua pattern (similar to basic regular
expressions, with `%' as escape character instead of `\\'). The output first lists all
directory names which match \fIpattern\fR and then all files.
Currently, directories without an ls-R file are ignored.
.SH "VARIABLES"
.RS 4
.IP "TEXDOCS = .;$TEXMF/doc//"
Specifies the directories where TeX documentation is stored
.IP "\s-1TEXDOCEXT\s0 = {:.pdf:.ps:.dvi:.txt:.tex}{:.gz:.bz2}:.html" 4
Recognized formats for documentation, the first match wins. The
default uses standard kpathsea brace notation. `html' should be last
in order to prevent the catalogue entry from being shown when other
documentation exists.
.IP "\s-1TEXDOC_VIEWER_\fBFORMAT\fR\s0 = (command %s) &" 4
Defines the viewer to be used for \fBFORMAT\fR,
e.g. \fITEXDOC_VIEWER_DVI\fR. The filename (and tempfile cleanup
commands, if needed after decompression) is substituted for `%s'. If
the viewer does not put itself in the background, the command must be
enclosed in parentheses and the `&' sign appended, as shown in the
example for \fIcommand\fR.
.IP "\s-1TEXDOC_UNZIP_\fBFORMAT\fR\s0 = command -a -c " 4
This variable specifies the command which is used to uncompress a file
compressed as \fBFORMAT\fR. It result must go to \fIstdout\fR.
.IP "\s-1TEXDOC_FORMATS\s0 = pdf,dvi,ps,txt,tex" 4
The formats for which a viewer is defined in \fItexmf.cnf\fR (order
does not matter).
.IP "\s-1TEXDOC_ZIPFORMATS\s0 = gz,bz2" 4
The compression formats for which a decompression command is defined
in \fItexmf.cnf\fR.
.IP "\s-1TEXDOC_RMFILE\s0 = rm -f" 4
The command used to remove a file on the target system. This is used
for temporary files which are needed for viewing compressed documents.
.IP "\s-1TEXDOC_RMDIR\s0 = rmdir" 4
The command used to remove a directory on the target system. This is
used for temporary directories which are needed for viewing compressed
documents.
.SH "BUGS"
Currently no bugs are known, but there are some limitations:
.IP "Specifying the filename, complete with extension"
This doesn't work for compressed files.
.IP manpage
The manpage has been written on a template created by pod2man, and its
source contains a lot of (probably) useless cruft at the beginning.
.SH "HISTORY"
Original version by David Aspinall <da at dcs.ed.ac.uk>
.Sp
Rewritten for use with bash 2 and teTeX under Linux by Simon Wilkinson
<sxw at dcs.ed.ac.uk>
.Sp
Changes for web2c\-7.2 resp. teTeX\-0.9 and portability fixes by
Thomas Esser <te at dbs.uni\-hannover.de>, Jun 14 1998
.Sp
Support for compressed documentation implemented by adopting changes
made by debian. Thomas Esser, Dec. 2004.
.Sp
Rewritten using texlua by Frank Küster <frank at kuesterei.ch>. Changed
the \-s option to use ls-R instead of \fIfind\fR, May/June 2007.
More information about the tex-live
mailing list