Code covered by the BSD License  

Highlights from
Enhanced help--improve your workflow

image thumbnail

Enhanced help--improve your workflow

by

 

31 Aug 2006 (Updated )

Simple enhancement to help listings: adds hyperlinks to open files for editing.

makehelphyper(actionName, pathname, fcnName, helpStr)
function hyperHelp = makehelphyper(actionName, pathname, fcnName, helpStr)
%MAKEHELPHYPER Reformat help output so that the content has hyperlinks
%
% ******************************************************************************
% Modifications to add hyperlinks allowing you to open files for editing
%   directly from help and directory Contents listings.
%
%   John Iversen (john_iversen@post.harvard.edu)
%
%   9/23/05 JRI initial version.
%   9/1/06  JRI new installation instructions; fix bug when 
%               encountering a directory containing a file of the 
%               same name. (Thanks to John D'Errico). Change help.m to allow
%               linking to class methods.
%
%       1) Added an 'Edit this file' link at the end of every help listing 
%           for individual functions. Clicking opens the file in the editor.
%       2) Contents pages have an edit hyperlink by each file name.
%       3) Links are provided to edit Contents pages themselves--handy for
%           keeping them up to date.
%       4) In case you have a directory containing an m-file of the same name
%           add links to both the m-file and directory's Contents file.
%       5) It handles overloaded class methods properly, but only after fixing a
%           help.m, which does not provide the class name properly.
%
%
%   INSTALLATION
%
%   The easy way: place this file, and the accompanying help.m file anywhere in
%   your working directory tree that is in front of default matlab directories
%   on your search path. These new versions will then be found before the stock
%   ones. (I've created a directory called 'overrides' for this purpose).
%
%   >> which help   %verify it's now picking up your overloaded copies
%       .../mymatlabcode/overrides/help.m
%
%   >> which makehelphyper
%       .../mymatlabcode/overrides/makehelphyper.m
%
%   %verify it's working
%   >> help help
%
%   %you should see the following text at the end of the help listing, with
%       'edit help' being a clickable hyperlink that will open help.m
%
%        Edit this file
%           edit help
%
% ******************************************************************************
%   This is a modified version of the file supplied with matlab (R14SP1) that
%   adds hyperlinks for editing files to help listings.
%       The original is found in MATLAB701/toolbox/matlab/helptools/private
%
%      [my modifications are clearly indicated in the code, search for 'JRI']
%
% ******************************************************************************
%

%   Copyright 1984-2004 The MathWorks, Inc.
%   $Revision: 1.1.6.7 $  $Date: 2004/08/25 19:09:13 $

itemLoc = which(fcnName);
if (strcmp(itemLoc,'built-in'))
    itemLoc = which([fcnName '.m']);
end

% ******************************************************************************
% *** JRI 9/1/06, add variable to preserve full pathname for edit hyperlink
JRI_fullFcnName = fcnName;
% ******************************************************************************

% Isolate the function name in case a full pathname was passed in
[unused fcnName unused unused] = fileparts(fcnName);
% Is this topic a function?
itemIsFunction = length(itemLoc);

% Make "see also" references act as hot links
CR = sprintf('\n');
seeAlso = sprintf('See also');
lengthSeeAlso = length(seeAlso);
xrefStart = findstr(helpStr, sprintf('See also'));
for seeAlsoIndex = 1:length(xrefStart)
    nameChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_/.';  % Note : '.' is now valid (for MATLAB class syntax)
    delimChars = [ ', ' CR ];
    % Determine start and end of "see also" portion of the help output
    pieceStr = helpStr(xrefStart(seeAlsoIndex)+lengthSeeAlso : length(helpStr));
    periodPos = findstr(pieceStr, '.');
    notePos = min([findstr(pieceStr, sprintf('Overloaded')) findstr(lower(pieceStr), sprintf('note:'))]);
    crPos = findstr(pieceStr,[CR CR]);  % blank line
    if isempty(notePos) && isempty(crPos)
        xrefEnd = length(helpStr);
        trailerStr = '';
    elseif ~isempty(notePos)
        xrefEnd = xrefStart(seeAlsoIndex)+lengthSeeAlso + notePos(1) - 1;
        trailerStr = pieceStr(notePos(1):length(pieceStr));
    else
        xrefEnd = xrefStart(seeAlsoIndex)+lengthSeeAlso + crPos(1) - 1;
        trailerStr = pieceStr(crPos(1):length(pieceStr));
    end

    % Parse the "See Also" portion of help output to isolate function names.
    seealsoStr = '';
    word = '';
    for chx = xrefStart(seeAlsoIndex)+lengthSeeAlso : xrefEnd
        if length(findstr(nameChars, helpStr(chx))) == 1
            word = [ word helpStr(chx)];
        elseif (length(findstr(delimChars, helpStr(chx))) == 1)
            if length(word) > 0
                % This word appears to be a function name.
                % Make link in corresponding "see also" string.
                fname = lower(word);
                suffix = '';
                if fname(length(fname)) == '.'
                    % Don't hyperlink the last period of the word.
                    fname = fname(1:length(fname)-1);
                    suffix = '.';
                end
                seealsoStr = [seealsoStr '<a href="matlab:' actionName ' ' fname '">' fname '</a>' suffix];
            end
            seealsoStr = [seealsoStr helpStr(chx)];
            word = '';
        else
            seealsoStr = [seealsoStr word helpStr(chx)];
            word = '';
        end
    end
    % Replace "See Also" section with modified string (with links)
    helpStr = [helpStr(1:xrefStart(seeAlsoIndex)+lengthSeeAlso -1) seealsoStr trailerStr];
end

% If there is a list of overloaded methods, make these act as links.
overloadPos =  findstr(helpStr, 'Overloaded');
if strcmp(actionName,'doc') == 1
    textToFind = ' doc ';
    len = 5;
else
    textToFind = ' help ';
    len = 6;
end

if length(overloadPos) > 0
    pieceStr = helpStr(overloadPos(1) : length(helpStr));
    % Parse the "Overload methods" section to isolate strings of the form "help DIRNAME/METHOD"
    overloadStr = '';
    linebrkPos = find(pieceStr == CR);
    lineStrt = 1;
    for lx = 1 : length(linebrkPos)
        lineEnd = linebrkPos(lx);
        curLine = pieceStr(lineStrt : lineEnd);
        methodStartPos = findstr(curLine, textToFind);
        methodEndPos = [length(curLine) - 2];
        if (length(methodStartPos) > 0 ) && (length(methodEndPos) > 0 )
            linkTag = ['<a href="matlab:' actionName ' ' curLine(methodStartPos(1)+len:methodEndPos(1)+1) '">'];
            overloadStr = [overloadStr curLine(1:methodStartPos(1)) linkTag curLine(methodStartPos(1)+1:methodEndPos(1)+1) '</a>' curLine(methodEndPos(1)+2:length(curLine))];
        else
            overloadStr = [overloadStr curLine];
        end
        lineStrt = lineEnd + 1;
    end
    % Replace "Overloaded methods" section with modified string (with links)
    helpStr = [helpStr(1:overloadPos(1)-1) overloadStr];
end


% If this topic is not a function description, then it is likely a Contents.m file.
% Scan it for function lists, and modify function names to act as active links.

%*******************************************************************************
% *** JRI 9/1/06 Logic of original function does not work with my modifications
%       to add links to edit files.
%   (1) Original doesn't correctly handle the case when topic is BOTH a function and a 
%       directory with Contents.m file
%*******************************************************************************
if (itemIsFunction == 0) || (strcmpi(fcnName, 'Contents')) || (length(findstr(helpStr,'is both a directory and a function'))) || (strcmp(fcnName,'simulink')) || (strcmp(fcnName,'debug'))
    fcnPath = '';
    %***************************************************************************
    % *** JRI 9/1/06 *** (1) don't change fcnName to Contents it it's also a function!
    %%% if ~strcmpi(fcnName,'Contents') && ~isempty(fcnName) % ORIGINAL
    if ~strcmpi(fcnName,'Contents') && ~isempty(fcnName) && (itemIsFunction == 0),
    %***************************************************************************
        % We need the pathname to be the name of the dictory, and the
        % fcnName to be 'Contents'.
        if isempty(pathname)
            pathname = fcnName;
        else
            pathname = [pathname '/' fcnName];
        end
        fcnName = 'Contents';
    end 
    if strcmpi(fcnName, 'Contents') && ~isempty(pathname)
        [fcnPath unused unused] = fileparts(which([pathname filesep fcnName]));
        if strncmp(matlabroot, fcnPath, length(matlabroot)) == 1
            % if under matlabroot, find the toplevel product directory to
            % use for comparison later.
            tbxPath = fullfile(matlabroot, 'toolbox');
            
            % get the portion of the path after "toolbox"
            postTbxPath = fcnPath(length(tbxPath)+2:end);
            
            % final path for comparison is mlroot/toolbox/<dirname>...
            fcnPath = fcnPath(1:length(tbxPath)+findstr(postTbxPath, filesep));
        end
    end
    TAB = sprintf('\t');
    helpStr = strrep(helpStr, TAB, ' ');
    modHelpStr = '';
    linebrkPos = find(helpStr == CR);
    lineStrt = 1;
    for lx = 1 : length(linebrkPos)
        lineEnd = linebrkPos(lx);
        curLine = helpStr(lineStrt : lineEnd);
        hyphPos = findstr(curLine, ' - ');
        if any(hyphPos)
            nonblankPos = find(curLine ~= ' ');
            if curLine(nonblankPos(1)) == '-'
                modHelpStr = [modHelpStr curLine];
            else
                for i = nonblankPos(1):hyphPos(1)
                    if (curLine(i) == ' ') || (curLine(i) == ','), break, end;
                end
                fname = curLine(nonblankPos(1):i-1);
                remainder = curLine(i:end);
                try
                    % If there is any help for this name, insert a link for it.
                    % However, avoid the expensive call to "help" by using "exist"
                    % to first test for mfiles, builtins, and directories.
                    fnameType = exist(fname);
                    if (fnameType == 2) || (fnameType == 7) || (fnameType == 5) || (fnameType == 8) || (any(builtin('helpfunc',fname)))
                        if ~isempty(fcnPath) && strncmp(fcnPath, which(fname), length(fcnPath)) == 0
                            % this is likely a shadowed function
                            modHelpStr = [modHelpStr curLine];                            
                        elseif strcmp(fname,'Readme')
                            modHelpStr = [modHelpStr curLine(1:nonblankPos(1)-1) '<a href="' 'matlab:' actionName ' ' topic '/Readme">' fname '</a>' remainder];
                        elseif remainder(1) == ','
                            % Sometimes there are two names separated by a comma.
                            [fname2, remainder2] = strtok(remainder(3:end));
                            modHelpStr = [modHelpStr curLine(1:nonblankPos(1)-1) '<a href="' 'matlab:' actionName ' ' fname '">' fname '</a>, ' '<a href="' 'matlab:help ' fname2 '">' fname2 '</a>' remainder2];
                        else
                            %%%modHelpStr = [modHelpStr curLine(1:nonblankPos(1)-1) '<a href="' 'matlab:' actionName ' ' fname '">' fname '</a>' remainder]; % ORIGINAL
                            % *********************************************************************
                            % *** JRI 9/23/05 --add hyperlink in Contents listing to edit the file
                            %         special case: no edit links for 'help' (root level help)
                            if ~isempty(pathname),
                                modHelpStr = [modHelpStr curLine(1:nonblankPos(1)-1) '<a href="' 'matlab:' actionName ' ' fname '">' fname '</a>'  ' <a href="matlab:edit ' fname '">[edit]</a>' remainder];
                            else %root level 'help'
                                modHelpStr = [modHelpStr curLine(1:nonblankPos(1)-1) '<a href="' 'matlab:' actionName ' ' fname '">' fname '</a>' remainder];
                            end
                            % *********************************************************************
                        end
                    else
                        modHelpStr = [modHelpStr curLine];
                    end
                catch
                    % Just in case an error occurred during the helpfunc call, don't try to
                    % hyperlink anything.
                    modHelpStr = [modHelpStr curLine];
                end
            end
        else
            modHelpStr = [modHelpStr curLine];
        end
        lineStrt = lineEnd + 1;
    end
    helpStr = modHelpStr;
end

%*******************************************************************************
% *** JRI 9/23/05 --for single-function help, add hyperlink to edit the file
%       in case of Contents.m, prepend directory name to it
%       for root level help ('help'), or help on directories without Contents,
%         don't print a link as there's nothing to edit
%

if (itemIsFunction) && ~isempty(pathname),
    if (strcmpi(fcnName, 'Contents')),
        JRI_linkFcnName = [pathname filesep fcnName];
        JRI_fileStr = 'directory''s Contents file';
    else
        JRI_linkFcnName = JRI_fullFcnName;
        JRI_fileStr = 'file';
    end
    editLinkLine = [CR CR '    Edit this ' JRI_fileStr  CR '       <a href="matlab:edit ''' JRI_linkFcnName '''">edit ' JRI_linkFcnName '</a>'];
    helpStr = [helpStr editLinkLine];
    
    % if we have function and directory of the same name, also add a link to the
    %   directory's Contents file (if it has one)
    if (length(findstr(helpStr,'is both a directory and a function'))),
        JRI_linkFcnName = [pathname filesep 'Contents.m'];
        if exist(JRI_linkFcnName,'file'),
            editLinkLine = [CR CR '    Edit this directory''s Contents file' CR '       <a href="matlab:edit ''' JRI_linkFcnName '''">edit ' JRI_linkFcnName '</a>'];
            helpStr = [helpStr editLinkLine];
        end
    end

end
%*******************************************************************************

hyperHelp = helpStr;



Contact us