Mercurial > octave-antonio
comparison scripts/help/lookfor.m @ 20135:4c6d70a35192
lookfor.m: Overhaul function and fix bug #44924.
* lookfor.m: Rewrite docstring. Match variable names in function prototype to
docstring. Use more meaningful variable names throughout function. Don't
continue to process a function if get_first_help_sentence returns an error
(bug #44924). Iterate directly over cell list rather than using a for loop
with a range to index into cell list.
author | Rik <rik@octave.org> |
---|---|
date | Sun, 26 Apr 2015 21:14:53 -0700 |
parents | 4197fc428c7d |
children | 7503499a252b |
comparison
equal
deleted
inserted
replaced
20134:57b6e06ed811 | 20135:4c6d70a35192 |
---|---|
17 ## <http://www.gnu.org/licenses/>. | 17 ## <http://www.gnu.org/licenses/>. |
18 | 18 |
19 ## -*- texinfo -*- | 19 ## -*- texinfo -*- |
20 ## @deftypefn {Command} {} lookfor @var{str} | 20 ## @deftypefn {Command} {} lookfor @var{str} |
21 ## @deftypefnx {Command} {} lookfor -all @var{str} | 21 ## @deftypefnx {Command} {} lookfor -all @var{str} |
22 ## @deftypefnx {Function File} {[@var{func}, @var{helpstring}] =} lookfor (@var{str}) | 22 ## @deftypefnx {Function File} {[@var{fcn}, @var{help1str}] =} lookfor (@var{str}) |
23 ## @deftypefnx {Function File} {[@var{func}, @var{helpstring}] =} lookfor ("-all", @var{str}) | 23 ## @deftypefnx {Function File} {[@var{fcn}, @var{help1str}] =} lookfor ("-all", @var{str}) |
24 ## Search for the string @var{str} in all functions found in the current | 24 ## Search for the string @var{str} in all functions using the current function |
25 ## function search path. By default, @code{lookfor} searches for @var{str} | 25 ## search path. |
26 ## in the first sentence of the help string of each function found. The entire | |
27 ## help text of each function can be searched if the @qcode{"-all"} argument is | |
28 ## supplied. All searches are case insensitive. | |
29 ## | 26 ## |
30 ## Called with no output arguments, @code{lookfor} prints the list of | 27 ## By default, @code{lookfor} looks for @var{str} in the first sentence of the |
31 ## matching functions to the terminal. Otherwise, the output arguments | 28 ## help string for each function found. The entire help text of each function |
32 ## @var{func} and @var{helpstring} define the matching functions and the | 29 ## can be searched by using the @qcode{"-all"} argument. All searches are case |
33 ## first sentence of each of their help strings. | 30 ## insensitive. |
34 ## | 31 ## |
35 ## The ability of @code{lookfor} to correctly identify the first | 32 ## When called with no output arguments, @code{lookfor} prints the list of |
36 ## sentence of the help text is dependent on the format of the | 33 ## matching functions to the terminal. Otherwise, the output argument |
37 ## function's help. All Octave core functions are correctly | 34 ## @var{fcns} contains the function names and @var{help1str} contains the first |
38 ## formatted, but the same can not be guaranteed for external packages and | 35 ## sentence from the help string of each function. |
39 ## user-supplied functions. Therefore, the use of the @qcode{"-all"} | 36 ## |
40 ## argument may be necessary to find related functions that are not a part of | 37 ## Programming Note: The ability of @code{lookfor} to correctly identify the |
41 ## Octave. | 38 ## first sentence of the help text is dependent on the format of the function's |
39 ## help. All Octave core functions are correctly formatted, but the same can | |
40 ## not be guaranteed for external packages and user-supplied functions. | |
41 ## Therefore, the use of the @qcode{"-all"} argument may be necessary to find | |
42 ## related functions that are not a part of Octave. | |
42 ## @seealso{help, doc, which} | 43 ## @seealso{help, doc, which} |
43 ## @end deftypefn | 44 ## @end deftypefn |
44 | 45 |
45 function [out_fun, out_help_text] = lookfor (str, arg2) | 46 function [fcn, help1str] = lookfor (str, arg2) |
46 | 47 |
47 if (strcmpi (str, "-all")) | 48 if (strcmpi (str, "-all")) |
48 ## The difference between using '-all' and not, is which part of the caches | 49 ## The difference between using '-all' and not is which part of the caches |
49 ## we search. The cache is organized such that the first column contains | 50 ## we search. The cache is organized such that row |
50 ## the function name, the second column contains the full help text, and | 51 ## 1) contains the function name |
51 ## the third column contains the first sentence of the help text. | 52 ## 2) contains the full help text |
53 ## 3) contains the first sentence of the help text. | |
52 str = arg2; | 54 str = arg2; |
53 search_type = 2; # when using caches, search the second column | 55 search_type = 2; # search the second row (full help text) |
54 else | 56 else |
55 search_type = 3; # when using caches, search the third column | 57 search_type = 3; # search the third column (first help sentence) |
56 endif | 58 endif |
57 str = lower (str); # Compare is case insensitive | 59 str = lower (str); # Compare is case insensitive |
58 | 60 |
59 ## Search functions, operators, and keywords that come with Octave | 61 ## Search functions, operators, and keywords that come with Octave |
60 cache_file = doc_cache_file (); | 62 cache_file = doc_cache_file (); |
61 if (exist (cache_file, "file")) | 63 if (exist (cache_file, "file")) |
62 [fun, help_text] = search_cache (str, cache_file, search_type); | 64 [fcnlist, help_text] = search_cache (str, cache_file, search_type); |
63 had_core_cache = true; | 65 had_core_cache = true; |
64 else | 66 else |
65 fun = help_text = {}; | 67 fcnlist = help_text = {}; |
66 had_core_cache = false; | 68 had_core_cache = false; |
67 endif | 69 endif |
68 | 70 |
69 ## Search functions in new path dirs. | 71 ## Search functions in new path dirs. |
70 orig_path = ostrsplit (__pathorig__ (), pathsep ()); | 72 orig_path = ostrsplit (__pathorig__ (), pathsep ()); |
71 | 73 |
72 ## ditto for path. | 74 ## ditto for path. |
73 new_path = ostrsplit (path (), pathsep ()); | 75 new_path = ostrsplit (path (), pathsep ()); |
74 | 76 |
75 ## scratch out directories already covered by orig_path. | 77 ## remove directories already covered by orig_path. |
76 if (had_core_cache) | 78 if (had_core_cache) |
77 new_path = setdiff (new_path, orig_path); | 79 new_path = setdiff (new_path, orig_path); |
78 endif | 80 endif |
79 | 81 |
80 for n = 1:numel (new_path) | 82 for n = 1:numel (new_path) |
81 elt = new_path{n}; | 83 fcndir = new_path{n}; |
82 cache_file = fullfile (elt, "doc-cache"); | 84 cache_file = fullfile (fcndir, "doc-cache"); |
83 if (exist (cache_file, "file")) | 85 if (exist (cache_file, "file")) |
84 ## We have a cache in the directory, then read it and search it! | 86 ## We have a cache in the directory, then read it and search it! |
85 [funs, hts] = search_cache (str, cache_file, search_type); | 87 [fcns, htext] = search_cache (str, cache_file, search_type); |
86 fun(end+1:end+length (funs)) = funs; | 88 fcnlist(end+1:end+length (fcns)) = fcns; |
87 help_text(end+1:end+length (hts)) = hts; | 89 help_text(end+1:end+length (htext)) = htext; |
90 | |
88 else | 91 else |
89 ## We don't have a cache. Search files | 92 ## We don't have a cache. Search files. |
90 funs_in_f = __list_functions__ (elt); | 93 for fcn_in_fcndir = (__list_functions__ (fcndir)).' |
91 for m = 1:length (funs_in_f) | 94 fn = fcn_in_fcndir{1}; |
92 fn = funs_in_f{m}; | |
93 | 95 |
94 ## Skip files that start with __ | 96 ## Skip files that start with "__" |
95 if (length (fn) > 2 && strcmp (fn(1:2), "__")) | 97 if (strncmp (fn, "__", 2)) |
96 continue; | 98 continue; |
97 endif | 99 endif |
100 | |
101 status = 0; | |
98 | 102 |
99 ## Extract first sentence | 103 ## Extract first sentence |
100 try | 104 try |
101 warn_state = warning (); | 105 warn_state = warning (); |
102 unwind_protect | 106 unwind_protect |
103 warning ("off"); | 107 warning ("off"); |
104 first_sentence = get_first_help_sentence (fn, 1024); | 108 first_sentence = get_first_help_sentence (fn, 1024); |
105 status = 0; | |
106 unwind_protect_cleanup | 109 unwind_protect_cleanup |
107 warning (warn_state); | 110 warning (warn_state); |
108 end_unwind_protect | 111 end_unwind_protect |
109 catch | 112 catch |
110 status = 1; | 113 status = 1; |
111 end_try_catch | 114 end_try_catch |
112 | 115 |
113 if (search_type == 2) # search entire help text | 116 if (status) |
117 ## Error getting first help sentence | |
118 elseif (search_type == 3) | |
119 ## only search the first sentence of the help text | |
120 text = first_sentence; | |
121 elseif (search_type == 2) | |
122 ## search entire help text | |
114 try | 123 try |
115 warn_state = warning (); | 124 warn_state = warning (); |
116 unwind_protect | 125 unwind_protect |
117 warning ("off"); | 126 warning ("off"); |
118 [text, fmt] = get_help_text (fn); | 127 [text, fmt] = get_help_text (fn); |
119 status = 0; | 128 switch (lower (fmt)) |
129 case "plain text" | |
130 status = 0; | |
131 case "texinfo" | |
132 [text, status] = __makeinfo__ (text, "plain text"); | |
133 case "html" | |
134 [text, status] = strip_html_tags (text); | |
135 otherwise | |
136 status = 1; | |
137 endswitch | |
120 unwind_protect_cleanup | 138 unwind_protect_cleanup |
121 warning (warn_state); | 139 warning (warn_state); |
122 end_unwind_protect | 140 end_unwind_protect |
123 catch | 141 catch |
124 status = 1; | 142 status = 1; |
125 end_try_catch | 143 end_try_catch |
126 | |
127 ## Take action depending on help text fmt | |
128 switch (lower (fmt)) | |
129 case "plain text" | |
130 status = 0; | |
131 case "texinfo" | |
132 [text, status] = __makeinfo__ (text, "plain text"); | |
133 case "html" | |
134 [text, status] = strip_html_tags (text); | |
135 otherwise | |
136 status = 1; | |
137 endswitch | |
138 | |
139 elseif (status == 0) # only search the first sentence of the help text | |
140 text = first_sentence; | |
141 endif | 144 endif |
142 | 145 |
143 ## Search the help text, if we can | 146 ## Search the help text |
144 if (status == 0 && ! isempty (strfind (lower (text), str))) | 147 if (status == 0 && strfind (lower (text), str)) |
145 fun(end+1) = fn; | 148 fcnlist(end+1) = fn; |
146 help_text(end+1) = first_sentence; | 149 help_text(end+1) = first_sentence; |
147 endif | 150 endif |
148 endfor | 151 endfor |
149 endif | 152 endif |
150 endfor | 153 endfor |
153 ## Print the results (FIXME: it would be nice to break at word boundaries) | 156 ## Print the results (FIXME: it would be nice to break at word boundaries) |
154 indent = 20; | 157 indent = 20; |
155 term_width = (terminal_size ())(2); | 158 term_width = (terminal_size ())(2); |
156 desc_width = term_width - indent - 2; | 159 desc_width = term_width - indent - 2; |
157 indent_space = blanks (indent); | 160 indent_space = blanks (indent); |
158 for k = 1:length (fun) | 161 for k = 1:length (fcnlist) |
159 f = fun{k}; | 162 f = fcnlist{k}; |
160 f(end+1:indent-1) = " "; | 163 f(end+1:indent-1) = " "; |
161 puts ([f " "]); | 164 puts ([f " "]); |
162 lf = length (f); | 165 lf = length (f); |
163 desc = strtrim (strrep (help_text{k}, "\n", " ")); | 166 desc = strtrim (strrep (help_text{k}, "\n", " ")); |
164 ldesc = length (desc); | 167 ldesc = length (desc); |
166 for start = (desc_width - (lf - indent) + 1):desc_width:ldesc | 169 for start = (desc_width - (lf - indent) + 1):desc_width:ldesc |
167 stop = min (start + desc_width, ldesc); | 170 stop = min (start + desc_width, ldesc); |
168 printf ("%s%s\n", indent_space, strtrim (desc (start:stop))); | 171 printf ("%s%s\n", indent_space, strtrim (desc (start:stop))); |
169 endfor | 172 endfor |
170 endfor | 173 endfor |
171 | |
172 else | 174 else |
173 ## Return the results instead of displaying them | 175 ## Return the results instead of displaying them |
174 out_fun = fun; | 176 fcn = fcnlist; |
175 out_help_text = help_text; | 177 help1str = help_text; |
176 endif | 178 endif |
177 | 179 |
178 endfunction | 180 endfunction |
179 | 181 |
180 function [funs, help_texts] = search_cache (str, cache_file, search_type) | 182 function [fcns, help_texts] = search_cache (str, cache_file, search_type) |
181 load (cache_file); | 183 load (cache_file); |
182 if (! isempty (cache)) | 184 if (! isempty (cache)) |
183 t1 = strfind (lower (cache (1, :)), str); | 185 t1 = strfind (lower (cache (1, :)), str); |
184 t2 = strfind (lower (cache (search_type, :)), str); | 186 t2 = strfind (lower (cache (search_type, :)), str); |
185 cache_idx = find (! (cellfun ("isempty", t1) & cellfun ("isempty", t2))); | 187 cache_idx = find (! (cellfun ("isempty", t1) & cellfun ("isempty", t2))); |
186 funs = cache(1, cache_idx); | 188 fcns = cache(1, cache_idx); |
187 help_texts = cache(3, cache_idx); | 189 help_texts = cache(3, cache_idx); |
188 else | 190 else |
189 funs = help_texts = {}; | 191 fcns = help_texts = {}; |
190 endif | 192 endif |
191 endfunction | 193 endfunction |
192 | 194 |