60cb9204cc7b32250840b015e938f8ecaf2ae03f
[scilab.git] / scilab / modules / helptools / macros / help_from_sci.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2008-2009 - T. Pettersen
3 // Copyright (C) 2010 - DIGITEO - Allan CORNET
4 // Copyright (C) 2011 - DIGITEO - Michael Baudin
5 // Copyright (C) 2017 - Samuel GOUGEON
6 //
7 // Copyright (C) 2012 - 2016 - Scilab Enterprises
8 //
9 // This file is hereby licensed under the terms of the GNU GPL v2.0,
10 // pursuant to article 5.3.4 of the CeCILL v.2.1.
11 // This file was originally licensed under the terms of the CeCILL v2.1,
12 // and continues to be available under such terms.
13 // For more information, see the COPYING file which you should have received
14 // along with this program.
15 //==============================================================================
16
17 function [helptxt,demotxt]=help_from_sci(funname,helpdir,demodir)
18     // Generate help files and demo files from the head comments section of a .sci source file.
19     //
20     // Syntax
21     //  help_from_sci() // generate an empty function template
22     //  helptxt = help_from_sci() // generate an empty function template
23     //  help_from_sci(funname,helpdir) // generate helpdir/funname.xml from funname.sci.
24     //  help_from_sci(dirname,helpdir) // process dirname/*.sci and create helpdir/*.xml help files.
25     //  help_from_sci(dirname,helpdir,demodir) // as above but also creating demodir/*.dem.sce demo files.
26     //  [helptxt,demotxt]=help_from_sci(funname) // return funname.xml and funname.dem.sce code as two text matrices.
27     // Parameters
28     //  funname: the name of a single .sci source file to be processed.
29     //  dirname: directory name where all .sci files will be processed.
30     //  helpdir: optional path where the .xml help file will be created.
31     //  demodir: optional path where .dem.sce demo files will be created based on code from the Examples section.
32     //  helptxt: returns the XML help code if helpdir is empty, or the path to the .xml file.
33     //  demotxt: returns the demo code if demodir is empty, or the path to the .dem.sce file.
34     //
35     // Description
36     //  The help_from_sci function generates .xml help files based on the head comments section
37     //  of .sci source files. Optionally .dem.sce demo files can be generated based on
38     //  code from the Examples section in the head comments section of .sci files.
39     //
40     //  In order for help_from_sci to format the .xml file properly the
41     //  head comments section should comply with some simple formatting rules.
42     //
43     //  The first comment line following the function definition should contain a short description
44     //  of the function.
45     //
46     //  The remaining comments are formatted according to the following (optional) headlines:
47     //  "Syntax", "Parameters", "Description", "Examples", "See also", "Used functions",
48     //  "Authors" and "Bibliography".
49     //
50     //  The following guidelines should be used when writing the source code comments:
51     //  <itemizedlist>
52     //    <listitem><para><literal>Syntax</literal> - one example pr. line.</para></listitem>
53     //    <listitem><para><literal>Parameters</literal> - separate parameter name and
54     //    description by a ":". Keep the description of each parameter on the same line.</para></listitem>
55     //    <listitem><para><literal>Description</literal> - formatting of the text can be done
56     //    using XML commands. Compare the output of head_comments("help_from_sci") with help("help_from_sci")
57     //    to get some hints.
58     //    Adding an empty comment line in the Description section is interpreted as the
59     //    start of a new paragraph.</para></listitem>
60     //    <listitem><para><literal>See also</literal> - list one function name pr line.</para></listitem>
61     //    <listitem><para><literal>Authors</literal> - write one author on each line following
62     //    the Authors headline. Use ";" to separate the authors name
63     //    from any add additional information.</para></listitem>
64     //    <listitem><para><literal>Bibliography</literal> - write one reference pr line
65     //    following the References headline.</para></listitem>
66     //  </itemizedlist>
67     //
68     // Examples
69     //  help_from_sci()   // Open an empty source code template in the scinotes editor.
70     //  // Save this template as test_fun.sci in the current directory before running
71     //  // the next example commands.
72     //
73     //  help_from_sci("test_fun")        // return the xml skeleton as a text string
74     //
75     //  help_from_sci("test_fun",".")    // create the xml help file in the current directory.
76     //
77     //  // create both a xml help file and a demo file in the current directory.
78     //  help_from_sci("test_fun",".",".")
79     //
80     //  // From a toolbox root directory a typical syntax would be:
81     //  // help_from_sci("macros","help\en_US","demos")
82     //  // This command would process all .sci files in the macros directory
83     //  // and use the head comments section to update all .xml help files in the
84     //  // help\en_US directory an rebuild the .dem.sce files in the demos\ directory.
85     //
86     // See also
87     //  help
88     //  help_skeleton
89     //  head_comments
90     //
91     // Authors
92     // Copyright (C) 2008-2009 - T. Pettersen
93     // Copyright (C) 2010 - DIGITEO - Allan CORNET
94     // Copyright (C) 2011 - DIGITEO - Michael Baudin
95
96     if argn(2) == 0 then
97         helptxt = [..
98         "function [z] = function_template(x,y)"
99         "// Short description on the first line following the function header."
100         "//"
101         "// Syntax"
102         "//   [z] = template_function(x,y) // calling examples, one pr. line"
103         "//"
104         "// Parameters"
105         "// x: the x parameter   // single line description of each parameter."
106         "// y: the y parameter   // parameter name and description must be "
107         "// z: the z parameter   // separated by "":""."
108         "//"
109         "// Description"
110         "// Here is a description of the function."
111         "// Add an empty comment line to format the text into separate paragraphs."
112         "//"
113         "// XML format commands may also be used directly in the text, "
114         "// as in the following examples."
115         "//"
116         "// This is an example of a itemized list:"
117         "// <itemizedlist>"
118         "// <listitem><para>An itemized list is shown here</para></listitem>"
119         "// </itemizedlist>"
120         "// The help text for help_from_sci was generated from the head comments section of help_from_sci.sci"
121         "// Compare the output from head_comments(""help_from_sci"") and help(""help_from_sci"")"
122         "// to see more examples on how to write the head comments section."
123         "//"
124         "// This is an example of the programlisting tag:"
125         "//   <programlisting>z = test_fun(x, y)</programlisting>"
126         "//"
127         "// This is an example of a latex equation:"
128         "//   <latex>"
129         "//   \begin{eqnarray}"
130         "//   m = |M| \beta^{1-p},"
131         "//   \end{eqnarray}"
132         "//   </latex>"
133         "//"
134         "// Examples"
135         "// [z] = test_fun(1, 2) // examples of use"
136         "//"
137         "// // An empty comment line in the Examples section will add a halt() statement"
138         "// // in the demo file test_fun.dem.sce generated by help_from_sci."
139         "//"
140         "// See also"
141         "//  help_from_sci"
142         "//  help_skeleton"
143         "//"
144         "// Authors"
145         "//  Author name ; should be listed one pr line. Use "";"" to separate names from additional information "
146         "//"
147         "// Bibliography"
148         "//   Literature references one pr. line"
149         ""
150         "// start of coding after on empty line to mark the end of the head_comments section"
151         "z = sin(x).*cos(x + y);"
152         "endfunction"
153         ];
154
155         mputl(helptxt, TMPDIR + filesep() + "function_template.sci");
156         if (isdef("editor") | (funptr("editor") <> 0)) then
157             editor(TMPDIR + filesep() + "function_template.sci");
158         end
159         [helptxt, demotxt] = help_from_sci("TMPDIR/function_template");
160         return;
161     end
162
163     if argn(2) < 3 then demodir = []; end
164     if argn(2) < 2 then helpdir = []; end
165
166     if ~isempty(demodir) & ~isdir(demodir) then
167         error(sprintf(gettext("%s: Wrong value for input argument #%d: A valid existing directory is expected.\n"), "help_from_sci", 3));
168     end
169
170     if isdir(funname) then
171         printf(gettext("%s: Reading from directory %s\n"), "help_from_sci", funname);
172         files = findfiles(funname, "*.sci");   // read *.sci files.
173         for i = 1:size(files, "r")
174             [tmp, out] = fileparts(files(i));
175             if isempty(helpdir) then
176                 help_from_sci(funname + filesep() + files(i), ".", demodir);
177                 printf(gettext("%s: Processing of file: %s to %s\n"), "help_from_sci", funname + "/" + out, out);
178             else
179                 help_from_sci(funname + filesep() + files(i), helpdir, demodir);
180                 printf(gettext("%s: Processing of file: %s to %s\n"), "help_from_sci", funname + "/" + out, helpdir + "/" + out);
181             end
182             if ~isempty(demodir) then
183                 printf(gettext("%s: Processing of file: %s\n"), "help_from_sci" , demodir + "/" + out + ".dem.sce");
184             else
185                 printf("\n");
186             end
187         end
188         printf(gettext("%s: processed %i files.\n"), "help_from_sci", i);
189         helptxt = "";
190         return;
191     end
192
193     out = tokens(pathconvert(funname), filesep());
194     out = out($);
195     out = tokens(out,".");
196     out = out(1);      // remove .sci (...wont work for fil.name.sci)
197     outxml = strsubst(out, "/^%/","percent", "r");
198
199     demotxt = ["mode(1)"
200     "//"
201     "// Demo of "+out+".sci"
202     "//"
203     ""];
204
205     verno = ver();
206     verno = verno(1,2);
207     helptxt = [
208     "<?xml version=""1.0"" encoding=""UTF-8""?>"
209     ""
210     "<!--"
211     " *"
212     " * This help file was generated from "+out+".sci using help_from_sci()."
213     " *"
214     " -->"
215     ""
216     "<refentry version=""5.0-subset Scilab"" xml:id="""+outxml+""" xml:lang=""en"""
217     "          xmlns=""http://docbook.org/ns/docbook"""
218     "          xmlns:xlink=""http://www.w3.org/1999/xlink"""
219     "          xmlns:svg=""http://www.w3.org/2000/svg"""
220     "          xmlns:ns3=""http://www.w3.org/1999/xhtml"""
221     "          xmlns:mml=""http://www.w3.org/1998/Math/MathML"""
222     "          xmlns:scilab=""http://www.scilab.org"""
223     "          xmlns:db=""http://docbook.org/ns/docbook"">"
224     ""
225     ];
226
227     if isempty(strindex(funname, ".sci")) then funname = funname + ".sci"; end;
228     if isempty(fileinfo(funname)) then
229         error(sprintf(gettext("%s: The file %s does not exist.\n"),"help_from_sci",funname));
230     end;
231     f = mopen(funname, "rt");
232     if isempty(f) then
233         error(sprintf(gettext("%s: Cannot open file %s.\n"), "help_from_sci", funname + ".sci"));
234     end
235     line = " ";
236     doc = [];
237
238     while isempty(strindex(line, "function ")) & ~meof(f), line = mgetl(f, 1); end
239
240     line = mgetl(f,1);
241     line = replaceTabBySpace(line);
242     short_descr = stripblanks(strsubst(line, "//", ""), %T);
243     helptxt = [helptxt;
244     "  <refnamediv>"
245     "    <refname>"+out+"</refname>"
246     "    <refpurpose>"+short_descr+"</refpurpose>"
247     "  </refnamediv>"
248     ];
249
250     cmds = ["SYNTAX", "PARAMETERS", "DESCRIPTION", "EXAMPLES", "SEE ALSO", ..
251     "AUTHORS", "BIBLIOGRAPHY", "USED FUNCTIONS"];
252
253     doing = "search";
254     i = strindex(line, "//");
255     line = mgetl(f, 1);
256     line = replaceTabBySpace(line);
257     // Continue until empty line or end of file or a scilab command line (Bug#5487)
258     while (~isempty(stripblanks(line)) & ~meof(f)) & ~isempty(regexp(stripblanks(line),"/^\/\/*/"))
259         if stripblanks(line) == "//" then
260             if doing == "Description" then
261                 in = "new_descr_param";
262             else
263                 in = "";
264             end
265         else
266
267             in = strsplit(line, i(1) + 1);
268             in = stripblanks(in(2));
269             code = in;  // store original line for the demos.
270             if (doing ~= "Examples") then // Replacing characters like <, > or & should not be done in the Examples
271                 in = strsubst(in, "&", "&amp;"); // remove elements that make xml crash.
272                 in = strsubst(in, "< ", "&lt; ");
273                 if strindex(in ,"<") then
274                     if ~helpfromsci_isxmlstr(in) then
275                         in = strsubst(in, "<", "&lt;");
276                     end;
277                 end
278                 in = strsubst(in, " >", " &gt;");
279                 if strindex(in, ">") then
280                     if ~helpfromsci_isxmlstr(in) then
281                         in = strsubst(in, ">", "&gt;");
282                     end;
283                 end
284             end
285         end
286
287         IN = convstr(in, "u");
288         if find(cmds == IN) then
289             [add_txt, doing] = change_activity(doing, in);
290             helptxt = [helptxt; add_txt];
291         else
292             if doing == "Syntax" then
293                 helptxt = [helptxt;"   " + in];
294             elseif doing == "Parameters" then
295                 i = strindex(in, ":");
296                 if ~isempty(i) then
297                     if length(in) > i(1) then
298                         in = strsplit(in,i(1));
299                         par_name = in(1);
300                         par_descr = in(2);
301                     else
302                         par_name = in;
303                         par_descr = " ";
304                     end
305                     helptxt = [helptxt; "   <varlistentry><term>" + par_name + "</term>"];
306                     helptxt = [helptxt;"      <listitem><para>" + par_descr + "</para></listitem></varlistentry>"];
307                 end
308             elseif doing == "Description" & in == "new_descr_param" then
309                 helptxt = [helptxt;"   </para>";"   <para>"];
310             elseif doing == "Description" then
311                 helptxt = [helptxt; in];
312             elseif doing == "Examples" & convstr(in, "u") ~= "EXAMPLES" then
313                 if isempty(stripblanks(in)) then
314                     demotxt = [demotxt; "halt()   // Press return to continue"; " "];
315                 else
316                     demotxt = [demotxt; code];
317                 end
318                 helptxt = [helptxt; in];
319             elseif doing == "See also" & convstr(in, "u") ~= "SEE ALSO" & ~isempty(stripblanks(in)) then
320                 str = stripblanks(in);
321                 i = strindex(str, " ");
322                 if i <> [] then
323                     str = stripblanks(strsplit(str, i(1)));
324                 else
325                     str = [str str];
326                 end
327                 helptxt = [helptxt; "   <member><link linkend=""" + str(1) + """>" + str(2) + "</link></member>"];
328             elseif doing == "Authors" & convstr(in, "u") ~= "AUTHORS" & ~isempty(stripblanks(in)) then
329                 [name, ref] = chop(in, ";");
330                 if isempty(ref) then
331                     helptxt = [helptxt; "   <member>" + name + "</member>"];
332                 else
333                     helptxt = [helptxt; "   <member>" + name + "</member><listitem><para>" + ref + "</para></listitem>"];
334                 end
335             elseif doing == "Bibliography" & convstr(in, "u") ~= "BIBLIOGRAPHY" & ~isempty(stripblanks(in)) then
336                 helptxt = [helptxt;"   <para>" + in + "</para>"];
337             elseif doing == "Used functions" & convstr(in, "u") ~= "USED FUNCTIONS" & ~isempty(stripblanks(in)) then
338                 helptxt = [helptxt;"   <para>" + in + "</para>"];
339             end
340         end
341         line = mgetl(f,1);
342         line = replaceTabBySpace(line);
343         i = strindex(line, "//");
344     end
345
346     helptxt = [helptxt; change_activity(doing, "FINISHED")];
347     mclose(f);
348
349     if ~isempty(helpdir) then
350         fnme = pathconvert(helpdir, %t, %f) + outxml + ".xml";
351         answ = 1;
352         if isfile(fnme) then  // file exists...
353             answ = messagebox(fnme + " exists!", "Warning - help_from_sci", "warning", ["Create anyway" "Skip file"], "modal");
354         end
355         if answ == 1 then
356             mputl(helptxt, fnme);
357             helptxt = fnme;
358         else
359             printf(gettext("%s: File skipped %s."), "help_from_sci", outxml + ".xml");
360             helptxt = "";
361         end
362     end
363
364     demotxt = [demotxt; "//========= E N D === O F === D E M O =========//"];
365     if ~isempty(demodir) then
366         fnme = demodir + filesep() + out + ".dem.sce";
367         answ = 1;
368         if isfile(fnme) then
369             answ = messagebox(fnme + " exists!", "Warning - help_from_sci", "warning", ["Create anyway" "Skip file"], "modal");
370         end
371         if answ == 1 then
372             mputl(demotxt, fnme);
373             demotxt = fnme;
374         else
375             printf(gettext("%s: File skipped %s."), "help_from_sci", out + ".demo.sce");
376             demotxt = "";
377         end
378     end
379 endfunction
380 //==============================================================================
381 function tf = helpfromsci_isxmlstr(str)
382     // Returns %t if the current string is a xml line
383     if ( ~isempty(regexp(str, "/\<*[a-z]\>/")) ) then
384         tf=%t
385     elseif ( ~isempty(regexp(str, "/\<(.*)\/\>/")) ) then
386         tf=%t
387     else
388         tf=%f
389     end
390 endfunction
391 //==============================================================================
392 function [head, tail] = chop(str, tok)
393     i = regexp(str, "/" + tok + "/", "o");
394     if isempty(i) then
395         head = str;
396         tail = [];
397     else
398         head = part(str, 1:i - 1);
399         tail = part(str, i + 1:length(str));
400     end
401 endfunction
402 //==============================================================================
403 function strOut = replaceTabBySpace(strIn)
404     strOut = strsubst(strIn, ascii(9), part(" ",1:4));
405 endfunction
406 //==============================================================================
407 function [txt, doing] = change_activity(currently_doing, start_doing)
408     doing = start_doing;
409     select convstr(currently_doing,"u")
410     case "SYNTAX" then
411         txt = ["   </synopsis>"; "</refsynopsisdiv>"];
412     case "PARAMETERS" then
413         txt = ["   </variablelist>"; "</refsection>"];
414     case "DESCRIPTION" then
415         txt = ["</para>"; "</refsection>"];
416     case "EXAMPLES" then
417         txt = ["   ]]></programlisting>"; "</refsection>"];
418     case "SEE ALSO" then
419         txt = ["   </simplelist>"; "</refsection>"];
420     case "AUTHORS" then
421         txt = ["   </simplelist>"; "</refsection>"];
422     case "BIBLIOGRAPHY" then
423         txt = ["</refsection>"];
424     case "USED FUNCTIONS" then
425         txt = ["</refsection>"];
426     else
427         txt = "";
428     end
429
430     select convstr(start_doing, "u"),
431     case "SYNTAX"
432         txt = [txt; ""; "<refsynopsisdiv>"; "   <title>Syntax</title>"; "   <synopsis>"];
433     case "PARAMETERS"
434         txt = [txt; ""; "<refsection>"; "   <title>Parameters</title>"; "   <variablelist>"];
435     case "DESCRIPTION"
436         txt = [txt; ""; "<refsection>"; "   <title>Description</title>"; "   <para>"];
437     case "EXAMPLES"
438         txt = [txt; ""; "<refsection>"; "   <title>Examples</title>"; "   <programlisting role=""example""><![CDATA["];
439     case "SEE ALSO"
440         txt = [txt; ""; "<refsection>"; "   <title>See also</title>"; "   <simplelist type=""inline"">"];
441     case "AUTHORS"
442         txt = [txt; ""; "<refsection>"; "   <title>Authors</title>"; "   <simplelist type=""vert"">"];
443     case "BIBLIOGRAPHY"
444         txt = [txt; ""; "<refsection>"; "   <title>Bibliography</title>"];
445     case "USED FUNCTIONS"
446         txt = [txt; ""; "<refsection>"; "   <title>Used functions</title>"];
447     case "FINISHED"
448         txt = [txt; "</refentry>"];
449     end
450 endfunction
451 //==============================================================================