Help for ISIS/S-Lang

From Remeis-Wiki
Jump to navigation Jump to search

The help/description of S-Lang or ISIS functions -- which can be obtained, e.g., with isis> help function_name -- is defined in plain text files. (In order to take effect, these must be introduced to S-Lang's help system via add_doc_file -- which is usually performed by S-Lang or ISIS itself, or by an external module. get_doc_files can be used to query at runtime which files are available.)

Although these help files could, in principle, be edited directly, most programs from the S-Lang ecosystem generate them from text macro files, which are rendered by the script (using jed).

Advantages of defining logically structured tm-files (using macros like \usage, \description, ...) -- rather than physically formatted help files -- are:

  • The structural elements (like USAGE, DESCRIPTION, ...) will always be rendered consistently.
  • The same text macro file can be rendered in different formats -- for example also produce PDF documentation (see, e.g., the S-Lang and ISIS manuals) besides S-Lang help files.

(tmexpand can simply use different macro definitions. Note the similarity to LaTeX!)

For convenience (and more correct documentation... ;-)), text macros can be directly defined within the source code. tmexpand comes with a tm-strip script that extracts text macros from comments enclosed by %!%+ and %!%- (in S-Lang files).

A help definition within the ISISscripts, which automatically run the tm-strip -- tmexpand pipeline, might look like that:

%!%+
%\function{function_name}
%\synopsis{short description}
%\usage{type return_value = function_name( arguments );}
%\altusage{alternative usage, if applicable}
%\qualifiers{
%\qualifier{qualifier1}{: description}
%\qualifier...
%}
%\description
%   Describe the function and tell what it does.
%\example
%   Give an example of the usage here.
%\seealso{function_name2, function_name3}
%!%-

For example, the help of the CCF_1D function:

%%%%%%%%%%%%%
define CCF_1d()
%%%%%%%%%%%%%
%!%+
%\function{CCF_1d}
%\synopsis{calculates the cross correlation function of two (1d) arrays}
%\usage{Double_Type CCF = CCF_1d(a1, a2, Integer_Type dx);
%\altusage{Array_Type CCF[] = CCF_1d(a1, a2);}
%}
%\qualifiers{
%\qualifier{notperiodic}{: no periodic boundary conditions at the edges.}
%}
%\description
%    The arrays \code{a1} and \code{a2} from which the CCF is to be computed can
%    either be passed directly or by a reference to the arrays (see example).
%    This function computes the correlation of a1[x] and a2[x-dx],
%    where the index x takes all values such that x and x-dx are contained:
%       \code{CCF = sum_x { (a1[x]-<a1>)/|a1| * (a2[x]-dx)-<a2>)/|a2| }}
%    The norm \code{|a| = sqrt{ sum_x a[x]^2 }} ensures that \code{CCF_1d(a, +-a, 0) = +-1}.
%    for any array \code{a}.\n
%    \n
%    If just a1 and a2 are give, the function returns an array which
%    contains all possible correlations between them. Its first entry
%    responds to dx=0, the second to dx=1, ... .\n
%    \n
%    By default, periodic boundary conditions are taken at the edges
%    of the array.
%    
%\example
%    variable a1 = Double_Type[N];  % some data
%    variable a2 = Double_Type[N];  % some other data
%    variable DX = [-N/2;N/2];
%    variable CCF = array_map(Double_Type, &CCF_1d, &a1, &a2, DX);
%    % If used with array_map, explicit references to a1 and a2 are required,
%    % as each function call to CCF_1d has to get the full array.
%    variable dx_opt = DX[where( abs(CCF) == max(abs(CCF)) )];\n
%    \n
%    or\n
%    \n
%    variable a1 = Double_Type[N]; 
%    variable a2 = Double_Type[N]; 
%    variable CCF[] = CFF_1d(a1,a2);
%\seealso{CCF_2d}
%!%-

gives the following output when called by help CFF_1d:

 SYNOPSIS                                                                                       
    calculates the cross correlation function of two (1d) arrays                                
                                                                                                
 USAGE                                                                                          
    Double_Type CCF = CCF_1d(a1, a2, Integer_Type dx);                                          
    % or                                                                                        
    Array_Type CCF[] = CCF_1d(a1, a2);                                                          

 QUALIFIERS
    ; notperiodic: no periodic boundary conditions at the edges.

 DESCRIPTION
    The arrays a1 and a2 from which the CCF is to be computed can
    either be passed directly or by a reference to the arrays (see example).
    This function computes the correlation of a1[x] and a2[x-dx],
    where the index x takes all values such that x and x-dx are contained:
       CCF = sum_x { (a1[x]-<a1>)/|a1| * (a2[x]-dx)-<a2>)/|a2| }
    The norm |a| = sqrt{ sum_x a[x]^2 } ensures that CCF_1d(a, +-a, 0) = +-1.
    for any array a.

    If just a1 and a2 are give, the function returns an array which
    contains all possible correlations between them. Its first entry
    responds to dx=0, the second to dx=1, ... .

    By default, periodic boundary conditions are taken at the edges
    of the array.

 EXAMPLE
    variable a1 = Double_Type[N];  % some data
    variable a2 = Double_Type[N];  % some other data
    variable DX = [-N/2;N/2];
    variable CCF = array_map(Double_Type, &CCF_1d, &a1, &a2, DX);
    % If used with array_map, explicit references to a1 and a2 are required,
    % as each function call to CCF_1d has to get the full array.
    variable dx_opt = DX[where( abs(CCF) == max(abs(CCF)) )];

    or

    variable a1 = Double_Type[N];
    variable a2 = Double_Type[N];
    variable CCF[] = CFF_1d(a1,a2);

 SEE ALSO
    CCF_2d

The macros \n and \code are not relevant for plain text help files, but may become important to structure Isis:ccf 1d.pdf.

Create your own help files

Here is what you can do to use tm-strip and tmexpand to generate help files for your private function collections:

  • install the tmexpand package
  • copy the *.tm files from isisscripts/doc/share/ to where you can easily access them locally on you machine
  • write the help to your own functions as explained above
  • run tm-strip and tmexpand as
tm-strip yourfuns.sl >> yourfuns.tm
tmexpand -Ipath/to/isisscripts/doc/share -Mslhlp_isisscripts yourfuns.tm yourfuns.txt
  • discard yourfuns.tm
  • add_doc_file("yourfuns.txt"); for ISIS to find your new help file. If you'd like to have the help files available at all times without loading them by hand, you can add this command to your .isssrc. As an alternative, you can add the help directly through yourfuns.sl in the manner of the isisscripts:
$1 = __FILE__[[:-4]]+".txt";
ifnot(path_is_absolute($1)) $1 = path_concat(getcwd(), $1);
if(stat_file($1)!=NULL) set_doc_files([$1, get_doc_files()]);

However, this particular set of command only works if your help files are in the same folder as your scripts and you are not accessing your script through a softlink. It works correctly, if you required your function collection through a location that is added to your ISIS load path.