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