Code covered by the BSD License  

Highlights from
BetterHelp

image thumbnail

BetterHelp

by

 

03 May 2013 (Updated )

Improves Matlab's help functionality for functions that do not have their own help files.

help2html(topic,pagetitle,helpCommandOption)
function [outStr, found] = help2html(topic,pagetitle,helpCommandOption)
%HELP2HTML Convert M-help to an HTML form.
% 
%   This file is a helper function used by the HelpPopup Java component.  
%   It is unsupported and may change at any time without notice.
%
%   This is a modified version of help2html. For m-files that contain the
%   normal <a href="matlab:web(['jar:file:', matlabroot,
%   '/help/techdoc/help.jar!/matlab_prog/brubzjb-1.html#br_jrv5'],
%   '-helpbrowser')">Help Within a Program File</a>, nothing is changed.
%   However, if the help contains %CUSTOM_HELP% at the end, it will be
%   parsed with some additional features. For instance,
%
%   A blank line, phrase, colon, newline, indent:
%     like this will be treated as a section, and the phrase will be
%     highlighted. Note that all indentation and line wrapping is
%     conserved.
%
%
%  But not indenting will back out of the section. We can also create
%  definition style lists by doing the following inside a section:
%
%  List Section:
%     list_element 1 - definition of list_element 1
%     list element 2 - definition of list element 2
%
%  Finally, you can modify word styles using *bold*, and |code|,
%  as long as you're inside a section:
%
%  Section:
%   *bold text*, |code|. You can use \\ to escape them \-> \\*bold\\*
%
%  Of course, See Also, Note, Overloaded methods:, and "Published output in
%  the Help browser" work as before:
%
%
%
%  See Also:
%     help, doc
%
%  Note:
%     Noting! (No.te that n.o.t.e cannot be in the n.o.t.e text!) Also,
%     these four sequences must be in this order to parsed correctly,
%     whether or not you are using custom help.
%
%  Overloaded methods:
%     <a href="matlab:edit(fullfile(matlabroot, 'toolbox', 'matlab',
%     'helptools', 'help2html'))">help2html</a>
%
%  Published output in the Help browser:
%     <a href="matlab:showdemo airfoil">showdemo airfoil</a>
%
%  %CUSTOM_HELP%

%   Copyright 2007-2008 The MathWorks, Inc.
%   Modified by: ryanmt1
%   $Revision: 2.0 $ $Date: 2011/08/13 17:29:40 $
if nargin == 0
    topic = '';
end
if nargin < 2
    pagetitle = '';
end
if nargin < 3
    helpCommandOption = '-helpwin';
end
dom = com.mathworks.xml.XMLUtils.createDocument('help-info');
dom.getDomConfig.setParameter('cdata-sections',true);

[helpNode, helpstr, fcnName] = help2xml(dom, topic, pagetitle, helpCommandOption);
found = ~isempty(helpstr);

afterHelp = '';
custom_help = false;
if found
    % Handle characters that are special to HTML 
    helpstr = fixsymbols(helpstr);

    % Extract the see also and overloaded links from the help text.
    % Since these are already formatted as links, we'll keep them 
    % intact rather than parsing them into XML and transforming
    % them back to HTML.
    
    
    
    if ~isempty(regexp(helpstr,'^\s*%CUSTOM_HELP%\s*$','once','lineanchors'))
        helpstr = regexprep(helpstr,'^\s*%CUSTOM_HELP%\s*','','lineanchors');
        custom_help = true;
        head='[^:\n]+';
        examples = regexpi(helpstr, ...
            ['\n[ \t]*\n',...
            '(?<indent>[ \t]*)',...
            '(?<header>',head,'):[ \t]*\n',...
            '(?<body>(\k<indent>[ \t]+.*\n?)*)$'],...
            'names', 'lineanchors', 'dotexceptnewline');
        if ~isempty(examples)
            other_fields = {examples(1,:).header};
            for i1=1:numel(other_fields)
                temp = regexpi(other_fields{i1},...
                    ['See also','|',...
                    'note','|',...
                    'Overloaded methods:','|',...
                    'Published output in the Help browser']);
                if ~isempty(temp)
                    other_fields{i1}='';
                end
            end
        else
            other_fields = cell(0);
        end
        if ~isempty(regexp(helpstr,...
                '.*\n(?<indent>[ \t]*).*(\k<indent>.*)*',...
                'dotexceptnewline','once'))
            helpstr = regexprep(helpstr,'(.*\n)','$1<br><br>',...
                'dotexceptnewline','once');
        end
    else
        other_fields = cell(0);
    end
    
    helpParts = myHelpUtils.helpParts(helpstr,other_fields);
    afterHelp = moveToAfterHelp(afterHelp, helpParts, {'seeAlso', 'note', 'overloaded', 'demo'});
    if custom_help
        processHelpParts(helpParts,other_fields);
    end
    helpstr = deblank(helpParts.getFullHelpText);
    shortName = regexp(fcnName, '(?<=\W)\w*$', 'match', 'once');
    helpstr = helpUtils.highlightHelp(helpstr, fcnName, shortName, '<span class="helptopic">', '</span>');
    
elseif strcmp(helpCommandOption, '-doc')
    outStr = '';
    return;
end

helpdir = fileparts(mfilename('fullpath'));
helpdir = ['file:///' strrep(helpdir,'\','/')];
addTextNode(dom,dom.getDocumentElement,'helptools-dir',helpdir);

if found
    addAttribute(dom,helpNode,'helpfound','true');
else
    addAttribute(dom,helpNode,'helpfound','false');
    % It's easier to escape the quotes in M than in XSL, so do it here.
    addTextNode(dom,helpNode,'escaped-topic',strrep(fcnName,'''',''''''));
end

% Prepend warning about empty docroot, if we've been called by doc.m
if strcmp(helpCommandOption, '-doc') && ~helpUtils.isDocInstalled
    addAttribute(dom,dom.getDocumentElement,'doc-installed','false');
    warningGif = sprintf('file:///%s',strrep(fullfile(matlabroot,'toolbox','matlab','icons','warning.gif'),'\','/'));
    addTextNode(dom,dom.getDocumentElement,'warning-image',warningGif);
    helperrPage = sprintf('file:///%s',strrep(fullfile(matlabroot,'toolbox','local','helperr.html'),'\','/'));
    addTextNode(dom,dom.getDocumentElement,'error-page',helperrPage);
end

addTextNode(dom,dom.getDocumentElement,'default-topics-text',getString(message('MATLAB:helpwin:sprintf_DefaultTopics')));
xslfile = fullfile(fileparts(mfilename('fullpath')),'private','helpwin.xsl');
outStr = xslt(dom,xslfile,'-tostring');

if custom_help
    outStr = regexprep(outStr,{'<pre>','</pre>'},'');
end

% Use HTML entities for non-ASCII characters
helpstr = regexprep(helpstr,'[^\x0-\x7f]','&#x${dec2hex($0)};');
afterHelp = regexprep(afterHelp,'[^\x0-\x7f]','&#x${dec2hex($0)};');
outStr = regexprep(outStr,'\s*(<!--\s*helptext\s*-->)', sprintf('$1%s',regexptranslate('escape',helpstr)));
outStr = regexprep(outStr,'\s*(<!--\s*after help\s*-->)', sprintf('$1%s',regexptranslate('escape',afterHelp)));

if custom_help
    outStr = regexprep(outStr,['(Contents of .* is both',...
        ' a directory and a function\.\n*)'],'<pre>$1</pre>',...
        'dotall','lineanchors','once');
end

%==========================================================================
function afterHelp = moveToAfterHelp(afterHelp, helpParts, parts)
for i = 1:length(parts)
    part = helpParts.getPart(parts{i});
    if ~isempty(part)
        title = part.getTitle;
        if title(end) == ':'
            title = title(1:end-1);
        end
        afterHelp = sprintf('%s<!--%s-->', afterHelp, parts{i});
        afterHelp = sprintf('%s\n<div class="footerlinktitle">%s\n</div>', afterHelp, title);
        afterHelp = sprintf('%s\n<div class="footerlink">%s\n</div>', afterHelp, part.getText);
        part.clearPart;
    end
end

%==========================================================================
function processHelpParts(helpParts, parts)
    for ii = 1:length(parts)
        part = helpParts.getPart(parts{ii});
        if ~isempty(part)
            title = part.getTitle;
            if title(end) == ':'
                title = title(1:end-1);
            end
            text = part.getText;
            text = processText(text);
            part.setTitle(sprintf('\n<div class="sectiontitle">\n%s\n</div>\n',title));
            part.replaceText(sprintf('\n<div class="section">\n%s\n</div>\n',text));
        end
    end

%==========================================================================
function text=processText(text)
    
    % You can add additional formatting symbols here, but note that other
    % people will not see them with the formatting, they'll only see
    % _italics_, which may or may not be acceptable. Also be careful, as
    % previously unescaped code might now be display incorrectly. That is
    % why _ is currently unavailabe, as they conflict with valid variable
    % names.
    formatting = { % 'symbol', 'tag';
        '\|','code';
        '\*','b';
        %'_','i'
        };
    
    for ii=1:size(formatting,1)
        text = regexprep(text,['(?<!\\) ',formatting{ii,1},...
            ' ( (  (\\',formatting{ii,1},')? [^',...
            formatting{ii,1},'] )* ) ',formatting{ii,1},' '],...
            ['<',formatting{ii,2},'>$1</',formatting{ii,2},'>'],...
            'freespacing');
    end
    
    listregex = ['^(?<indent>[ \t]*)',...
        '(?<name>[^-\n]+)','[ \t]*(?<!\\)-[ \t]*',...
        '(?<value>.*(\n\k<indent>[ \t]+.*)*)$'];
    
    [list,listparts,rest] = regexp(text,listregex,...
        'lineanchors','dotexceptnewline','match','names','split');
    
    
    
    for jj=1:numel(list)
        text = strrep(text,list{jj},...
            ['<ul><li>',listparts(jj).name,...
            '</li><ul><li>',listparts(jj).value,...
            '</li></ul></ul>']);
    end
    rest = regexp([rest{:}],'\r?\n','split');
    mod_rest = cell(size(rest));
    for jj=1:numel(rest)
        if ~isempty(regexp(rest{jj},'\S','once'))
            rest{jj} = regexptranslate('escape',rest{jj});
            mod_rest{jj} = rest{jj};
            mod_rest{jj} = regexprep(mod_rest{jj},...
                '(\ {2,})','${repmat(''&nbsp'',1,length($1))} ');
        else
            rest{jj} = '';
        end
    end
    text = regexprep(regexprep(text,rest,mod_rest),'(\r?\n)','<br>$1');
    text = regexprep(text,'(<br>)*\s*</','</');
    text = regexprep(text,'\\-','-');
    text = regexprep(text,'\\\\','\\');

%==========================================================================
function addTextNode(dom,parent,name,text)
child = dom.createElement(name);
child.appendChild(dom.createTextNode(text));
parent.appendChild(child);

%==========================================================================
function addAttribute(dom,elt,name,text)
att = dom.createAttribute(name);
att.appendChild(dom.createTextNode(text));
elt.getAttributes.setNamedItem(att);

Contact us