No BSD License  

Highlights from
HyperSubFunHelp

image thumbnail
from HyperSubFunHelp by Mathias Ortner
Display expandable help of nested and subfunctions in an Mfile with recursive behavior

hyperSubFunHelp(mFile,mode,nSubFun)
function hyperSubFunHelp(mFile,mode,nSubFun)
% HYPERSUBFUNHELP displays help of a file with expandable recursive subfunctions help
%  HYPERSUBFUNHELP(MFILE) displays the help of MFILE with expandable help
%  for each nested/sub functions that are preceeded by a line of comment
%  containing the key expression  '% Display Help'
% 
%  A set of links is generated containing the name of a sub functions and a
%  the h1 line of every subfunction. 
% 
%  The expension of one link results in the following displays: 
%   - a link for retracting the subfunction help,
%   - the subfunction help,
%   - links for expanding subfunctions of the current subfunction are
%   displayed (recursive  behavior) provided that the subfunctions are
%   preceeded by a '% Display Help' Tag. 
% 
%  HYPERSUBFUNHELP(MFILE,'short') does not display the main help. 
%  It is usefull for including a link in an Mfile help that adds links to
%  subfunction help beneath the main help, without repeating it.
% 
%  Note 1: The depth parsing of subfunctions is based on the indentation
%  (spaces).  If the mfile is not properly indented, the function might not
%  work. 
%  
%  Example :
%    see the result of 'hyperSubFunHelp hyperSubFunHelp'
%    Click <a href="matlab:hyperSubFunHelp('hyperSubFunHelp','short')">here</a>

% Hidden Help :
%  HYPERSUBFUNHELP(MFILE,'toogle',NUMBER) will expand/retract the help for
%  the subfunction identified by an integer NUMBER

% Author :  Mathias Ortner

% version log 
% 0.5 first
% 0.6 corrected a bug  by adding a drawnow command
% 0.7 added recursive behavior - removed the 'home command'.
% 0.8 corrected a bug with subfunctions 

% -- PARAMETERS -- 

% This is the pattern that is matched for displaying help
stringToMatch ='% Display Help'; 

% Which column the h1 line are displayed: 
h1LineColumnNumber = 45;

% indentation for link display
linkIndentation  = 2;

% indentation for help display
helpIndentation  = 4;

% identation for sub depth
stepIndentation  = 6;


% Persistent variables (stay between calls to the function)
persistent names lines comments previous charCount isOpened ...
    nFunctions h1Line depth fathers doDisplay %#ok<PUSE>


% names : cell array of string with names of subfunctions
% lines : int array of line numbers (not used yet)
% comments   : cell array of string with help
% previous   : previous lines
% charCount  : number of characters displayed by last called (used for
%             erasing using backspaces).
% isOpened   : array of 1 and 0 standing for expanded subfunctions
% nFunctions : number of functions
% h1Line     : first line
% depth      : depth of each function
% fathers    : parent function of ech function
% doDisplay  : booleean for selecting which display to use.

dispMain=0;

% if no mode where provided, default display.
if(~exist('mode','var') ||isempty(mode))
    mode = 'start';
    dispMain = 1;
end


% if the short mode has been selected, do not display the main function
% help 
switch(mode)
    case 'short'
         dispMain = 0;
         mode = 'start';
end


% Main variables

offsetDisp = 0;  % number of additionnal space characters for indenting display


% this is used for flushing display at once
outputString    =   cell(900,1); % Line to be displayed
iLine           =   0; % current line counter

switch(mode)
    case 'start'
        % This mode is used once, for initiating the display

        
        % this parses the mfile for finding sub/nested functions
        [names lines comments h1Line previous depth fathers]=getSubFunctions(mFile);
        
        
        nFunctions = size(names,1);
        charCount  = zeros(900,1);

        % Let's find the good functions (+ the Main one)
        matchTag    = cellfun(@(x) strcmpi(x,stringToMatch),previous(2:end))';
        doDisplay   = [dispMain matchTag];  
        goodInd     = [0 1 find(doDisplay)];
        
        % Check for coherency 
        isUncoherent = ~ismember(fathers(2:end),goodInd);
        if any(isUncoherent)
            ind = find(isUncoherent,1,'first')+1;
            error('You asked to display [%s], subfunction  of [%s] that is not displayed',names{ind},names{fathers(ind)});
        end
                
        % by default retract all helps
        isOpened      = zeros(nFunctions,1);
        isOpened(1)   = 1;
        
        % Display help
        displayAll();

    case 'toggle'
        % this mode changes the status of one help
        
        % toogle the required displayed help
        isOpened(nSubFun) = 1-isOpened(nSubFun);

        % erase previous display
        erasePreviousDisplay();

        % displays help
        displayAll();
end

% Display Help
    function erasePreviousDisplay
        %ERASEPREVIOUSDISPLAY erase previous disp using backspaces
        %

        nChars = sum(charCount);
        fprintf(1,repmat(sprintf('\b'),1,nChars));
        charCount = zeros(900,1);
    end

% Display Help
    function displayAll
        %DISPLAYALL  displays the help using the current state
        % DISPLAYALL displays the main help plus required subfunction help
        % as well as hyperlinks for expanding/retracting subfuntions help

        % Indenting set to 0
        offsetDisp=0;
        iLine = 0;

        % countDisp(sprintf('\n'));
        drawnow;

        % Displays main help
        if(doDisplay(1))
            displayHelpText(comments{1});
        end
        
        % loop on subfunctions
        for i = 2: nFunctions
            if doDisplay(i) && (fathers(i)==0 || isOpened(fathers(i))) 
                if(isOpened(i))
                    % If expanded
                    
                    html        = helpLink(mFile,names{i},'',i);

                    % Display link
                    % Specific disp that counts the number of chars
                    offsetDisp  = stepIndentation*(depth(i)-1)+linkIndentation;
                    countDisp(html);

                    offsetDisp = stepIndentation*(depth(i)-1)+helpIndentation;

                    % Display help
                    displayHelpText(comments{i})
                else
                    % if not expanded
                    offsetDisp = stepIndentation*(depth(i)-1)+linkIndentation;
                    html = helpLink(mFile,names{i},h1Line{i},i);

                    % display link
                    countDisp(html);
                end
            end
        end


        flushOutput();
    end

% Display Help
    function flushOutput
        %FLUSHOUTPUT displays everything in the disp buffer
        % FLUSHOUTPUT hopefully speeds things up

        cellfun(@(x) fprintf(1,'%s\n',x),outputString(1:iLine));
        charCount(1:iLine)=1+charCount(1:iLine);
        drawnow;

        % Display Help
        function doNothing  %#ok<DEFNU>
            %DONOTHING1 this function does nothing
            % the purpose is showing the recursive behavior.
        end
        
         % Display Help
        function doNothing2  %#ok<DEFNU>
            %DONOTHING2 this function does nothing
            % the purpose is showing the recursive behavior.
        end
    end


% Display Help
    function html = helpLink(mFile,name,h1line,number)
        %HELPLINK generates hyperlink for expanding/retracting help
        %   HTML = HELPLINK(MFILE,LINENUM,NAME) returns HTML code to generate hyperlink.

        %calling syntax
        cmd = sprintf('matlab:hyperSubFunHelp(''%s'',''toggle'',%d)',mFile,number);

        %hyperlink HTML script
        html = sprintf('<a href="%s">%s</a> %s',cmd,...
            name,[repmat(' ',1,max(h1LineColumnNumber-offsetDisp-length(name),1)) h1line]);

    end



% Display Help
    function displayHelpText(helpStr)
        %DISPLAYHELPTEXT for outputing an help String
        %  DISPLAYHELPTEXT(HELPSTR) is originally a subroutine of
        %  help and converts a string witch CR into lines

        a = regexp(helpStr, '\n');

        if ~isempty(a)
            substart = 1;
            for n=1:length(a)
                subend = a(n)-1;
                if subend<substart
                    % This is a blank line
                    countDisp(' ');
                else
                    b = helpStr(substart:subend);
                    countDisp(b);
                end
                substart=subend+2;
            end
            % display the last line (if after the last carriage return)
            b = helpStr(subend+2:length(helpStr));
            if (~isempty(b))
                countDisp(b);
            end
        else
            countDisp(helpStr);
        end

    end

% Display Help
    function countDisp(str)
        %COUNTDISP for displaying with char count
        % COUNTDISP(STR) adds a number of spaces
        % and counts the chars (removes links)

        if(~isempty(str))

            len=length(str);

            % let's deal with potential hyperlinks
            f=regexp(str,'<[^>]*>','match');

            if(~isempty(f))
                len=len-sum(cellfun(@length,f));
            end


            offSpace=repmat(' ',1,offsetDisp);

            iLine = iLine+1;

            outputString(iLine) = {sprintf('%s%s',offSpace,str)};
            charCount(iLine)    = len+offsetDisp;

        end


    end

end

Contact us at files@mathworks.com