From 7a8b3c6f337259f7d0f69bc4af39f47a7e12b71a Mon Sep 17 00:00:00 2001 From: Manuel Pégourié-Gonnard Date: Mon, 28 Jul 2008 01:29:16 +0000 Subject: Introducing new implementation of search functions, and changing a few things in modes and the print_menu function to accomodate. Viewing currently broken. git-svn-id: svn://tug.org/texlive/trunk@9831 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf/scripts/texlive/texdoc.tlu | 279 +++++++++++++++++--------------- 1 file changed, 145 insertions(+), 134 deletions(-) diff --git a/Master/texmf/scripts/texlive/texdoc.tlu b/Master/texmf/scripts/texlive/texdoc.tlu index 5236e3a9edc..a3f53b2840b 100755 --- a/Master/texmf/scripts/texlive/texdoc.tlu +++ b/Master/texmf/scripts/texlive/texdoc.tlu @@ -81,134 +81,134 @@ end -- functions for the search options ----------------------------------- --- full tree exploration with or without ls-R file - --- check which texmf roots have a ls-R file (returns an iterator for those) --- and which don't (put them in the global no_lsr_trees) (bad) -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) - return function () - i = i +1 - if i <= n then return lsr_files[i] end +-- BEGIN kpse-like + +-- temporary, will be an option soon +no_regex = true + +-- get global texdocs, do_recurse and must_have_lsr lists from kpse's $TEXDOCS +function get_texdocs () + local sep = (os.type == 'window') and ';' or ':' + -- avoid duplicates like {/english,} or {/man,} in $TEXDOCS + texdocs = string.gsub (kpse.expand_var ("$TEXDOCS"), "{[^{}]+,}", "") + -- expand the path and turn it into a lua list + texdocs = string.explode (kpse.expand_braces (texdocs), sep) + do_recurse, must_have_lsr = {}, {} -- global + for i, dir in ipairs (texdocs) do + local n + dir, n = string.gsub (dir, '//$', '') + do_recurse[i] = (n == 1) + texdocs[i], n = string.gsub (dir, '^!!', '') + must_have_lsr[i] = (n == 1) end end --- protect - in patterns instead of trusting the user to do that -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 - --- return files in the TEXDOCS tree whose full path matches against pattern -function pattern_search (pattern) - docfiles = {} -- should not be local (used in recurse_tree) - pattern = deluaficate(pattern) - -- populate docfiles 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 - 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 - if string.match(fullpath, pattern) then - if lfs.isfile(fullpath) then -- cannot know from ls-R - table.insert(docfiles,fullpath) - end - end - end -- line starting with ./ - end -- for line - end -- for database - for no_lsr_dir in list(no_lsr_doctrees) do - recurse_tree(no_lsr_dir, pattern) +-- says if ext is 'good' according to ext_list +function is_good_ext (ext) + for e in list (config.ext_list) do + if e == '*' then + return true + elseif (e == '') and (not ext) then + return true + elseif ext == e then + return true + end + end + return false +end + +-- include a file in the lists if it should be +function process_file (file, pathfile, code, pattern, sure_isfile) + local base, ext = string.match(file, '^(.*)%.(.*)$') + if string.find(pathfile, pattern, 1, no_regex) and is_good_ext (ext) + and (sure_isfile or lfs.isfile (pathfile)) then + if base == pattern then + table.insert(exact_docfiles, code..':'..pathfile) + else + table.insert(rel_docfiles, code..':'..pathfile) + end end - return docfiles end --- recursively explore a tree and put the file matching pattern in docfiles -function recurse_tree (path, pattern) +-- scan a tree +function scan_tree (code, path, pattern, recurse) 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 - recurse_tree (f, pattern) - else - if string.match (f, pattern) then - table.insert(docfiles,f) - end - end + if file ~= '.' and file ~= '..' then + local f = (path == '.') and file or path..'/'..file + if lfs.isdir(f) then + if recurse then scan_tree(code, f, pattern, recurse) end + else + process_file(file, f, code, pattern, true) end end end end +-- finds a root with ls-R above path 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 + end +end --- filename and mixed search modes - --- add a dot to ext except if it's empty -function dotted(ext) - if (ext == '') then - return ext - else - return '.'..ext +-- scan a ls-R file +function scan_lsr (code, shift, pattern) + local isdoc = false + local current_dir + local lsr = assert(io.open('ls-R', 'r')) + while true do + local line = lsr:read('*line') + if line == nil then break end -- EOF + local dir_line = string.match (line, '^%./(.*):$') + if dir_line then + if string.find (dir_line, '^'..shift) then + isdoc = true + current_dir = dir_line + elseif isdoc then + break -- we're exiting the ./doc (or shift) dir, so it's over + end + elseif isdoc then + process_file (line, current_dir..'/'..line, code, pattern, false) + end end + lsr:close() end --- simple search on filename using kpse -function filename_search (filename) - files = {} - for ext in list(config.ext_list) do - found = kpse.find_file(filename .. dotted(ext), - "TeX system documentation") - if found then table.insert(files, found) end +-- find dirfiles according to pattern +function populate_docfiles (pattern) + if not texdocs then get_texdocs() end + rel_docfiles, exact_docfiles = {}, {} -- global + local curr_dir = lfs.currentdir() + for code, docdir in ipairs (texdocs) do + root, shift = lsr_root (docdir) + if root and shift and do_recurse[code] then + assert(lfs.chdir(root)) + scan_lsr(code, shift, pattern) + elseif (not must_have_lsr[code]) and lfs.isdir(docdir) then + assert(lfs.chdir(docdir)) + scan_tree(code, '.', pattern, do_recurse[code]) + end end - return files + assert(lfs.chdir(curr_dir)) end --- do a filename search and try a full search if unsuccessfull -function mixed_search (filename, alternative) - results = filename_search (filename) - if not results[1] then - print ("texdoc info: No result with simple search, ".. - "trying full search mode.") - results = pattern_search (alternative) +-- END kpse-like + +function mixed_populate_docfiles (pattern) + populate_docfiles (pattern) + if not exact_docfiles[1] then + print ("texdoc info: No exact match, trying full search mode.") + exact_docfiles = rel_docfiles end - return results end @@ -575,22 +575,33 @@ function ext_pos (ext) return ext_pos (ext) end --- print a list of files as a menu -function print_menu (files) - local n = #files +-- display a table, sorted, numbered with given offset (0 by default) +function display_table (t, offset) + offset = offset or 0 + table.sort(t, file_order) + for i, val in ipairs (t) do + print (i+offset, val) + end +end + +-- print a list of files as a menu (with an coptional complementary list) +function print_menu (files, comp) + comp = comp or {} + local f = #files + local n = f + #comp if n > 20 then - io.write (n, " files found. Display the complete list? (y/N) ") + io.write (n, "results. Display them all? (y/N) ") local ans = io.read(1) - if not ((ans == 'y') or (ans == 'Y')) then return end - end - -- table.sort(results, file_order) - for i, file in ipairs (files) do - print (i, file) + if not ((ans == 'y') or (ans == 'Y')) then return end end + display_table (files) + display_table (comp, f) io.write ("Please enter the number of the file to view, or 0 to exit: ") local num = io.read('*number') - if num and files[num] then + if num and (num <= #files) and files[num] then print ("Viewing file '"..files[num].."'.") + elseif num and comp[num-f] then + print ("Viewing file '"..comp[num-f].."'.") elseif num ~= 0 then print ("Incorrect input, skipping.") end @@ -667,41 +678,41 @@ end exit_code = 0 for docname in list (arg) do original_docname = docname - if enable_alias and alias[docname]then + if enable_alias and alias[docname] then print ("texdoc info: "..docname.." aliased to "..alias[docname]) docname = alias[docname] end local docfound = false if (config.mode == 'search') then - results = pattern_search (docname) - if results[1] then - print_menu (results) + populate_docfiles(docname) + if exact_docfiles[1] or rel_docfiles[1] then + print_menu (exact_docfiles, rel_docfiles) else apologize ('notfound', docname) end elseif (config.mode == 'list') then - results = mixed_search (docname, original_docname) - if results[1] then - print_menu (results) + mixed_populate_docfiles (docname) + if exact_docfiles[1] then + print_menu (exact_docfiles) else apologize ('notfound', docname) end elseif (config.mode == 'view') then - results = mixed_search (docname, original_docname) - if results[1] then - try_viewing (how_to_view(results[1])) + mixed_populate_docfiles (docname) + if exact_docfiles[1] then + try_viewing (how_to_view(exact_docfiles[1])) else apologize ('notfound', docname) end elseif (config.mode == 'mixed') then - results = mixed_search (docname, original_docname) - if (not results[1]) then -- no results + mixed_populate_docfiles (docname) + if (not exact_docfiles[1]) then -- no results apologize ('notfound', docname) - elseif (not results[2]) then -- 1 result (faster than table.maxn) - local ok = try_viewing (how_to_view(results[1])) + elseif (not exact_docfiles[2]) then -- 1 result + local ok = try_viewing (how_to_view(exact_docfiles[1])) if not ok then apologize ('oops') end - else -- 2 or more results - print_menu (results) + else -- 2 or more results + print_menu (exact_docfiles) end end -- if construct "case config.mode in" end -- for docname in arg -- cgit v1.2.3