cprintf

PURPOSE ^

CPRINTF displays styled formatted text in the Command Window

SYNOPSIS ^

function count = cprintf(style,format,varargin)

DESCRIPTION ^

 CPRINTF displays styled formatted text in the Command Window

 Syntax:
    count = cprintf(style,format,...)

 Description:
    CPRINTF processes the specified text using the exact same FORMAT
    arguments accepted by the built-in SPRINTF and FPRINTF functions.

    CPRINTF then displays the text in the Command Window using the
    specified STYLE argument. The accepted styles are those used for
    Matlab's syntax highlighting (see: File / Preferences / Colors / 
    M-file Syntax Highlighting Colors), and also user-defined colors.

    The possible pre-defined STYLE names are:

       'Text'                 - default: black
       'Keywords'             - default: blue
       'Comments'             - default: green
       'Strings'              - default: purple
       'UnterminatedStrings'  - default: dark red
       'SystemCommands'       - default: orange
       'Errors'               - default: light red
       'Hyperlinks'           - default: underlined blue

       'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White'

    STYLE beginning with '-' or '_' will be underlined. For example:
          '-Blue' is underlined blue, like 'Hyperlinks';
          '_Comments' is underlined green etc.

    STYLE beginning with '*' will be bold (R2011b+ only). For example:
          '*Blue' is bold blue;
          '*Comments' is bold green etc.
    Note: Matlab does not currently support both bold and underline,
          only one of them can be used in a single cprintf command. But of
          course bold and underline can be mixed by using separate commands.

    STYLE also accepts a regular Matlab RGB vector, that can be underlined
    and bolded: -[0,1,1] means underlined cyan, '*[1,0,0]' is bold red.

    STYLE is case-insensitive and accepts unique partial strings just
    like handle property names.

    CPRINTF by itself, without any input parameters, displays a demo

 Example:
    cprintf;   % displays the demo
    cprintf('text',   'regular black text');
    cprintf('hyper',  'followed %s','by');
    cprintf('key',    '%d colored', 4);
    cprintf('-comment','& underlined');
    cprintf('err',    'elements\n');
    cprintf('cyan',   'cyan');
    cprintf('_green', 'underlined green');
    cprintf(-[1,0,1], 'underlined magenta');
    cprintf([1,0.5,0],'and multi-\nline orange\n');
    cprintf('*blue',  'and *bold* (R2011b+ only)\n');
    cprintf('string');  % same as fprintf('string') and cprintf('text','string')

 Bugs and suggestions:
    Please send to Yair Altman (altmany at gmail dot com)

 Warning:
    This code heavily relies on undocumented and unsupported Matlab
    functionality. It works on Matlab 7+, but use at your own risk!

    A technical description of the implementation can be found at:
    <a href="http://undocumentedmatlab.com/blog/cprintf/">http://UndocumentedMatlab.com/blog/cprintf/</a>

 Limitations:
    1. In R2011a and earlier, a single space char is inserted at the
       beginning of each CPRINTF text segment (this is ok in R2011b+).

    2. In R2011a and earlier, consecutive differently-colored multi-line
       CPRINTFs sometimes display incorrectly on the bottom line.
       As far as I could tell this is due to a Matlab bug. Examples:
         >> cprintf('-str','under\nline'); cprintf('err','red\n'); % hidden 'red', unhidden '_'
         >> cprintf('str','regu\nlar'); cprintf('err','red\n'); % underline red (not purple) 'lar'

    3. Sometimes, non newline ('\n')-terminated segments display unstyled
       (black) when the command prompt chevron ('>>') regains focus on the
       continuation of that line (I can't pinpoint when this happens). 
       To fix this, simply newline-terminate all command-prompt messages.

    4. In R2011b and later, the above errors appear to be fixed. However,
       the last character of an underlined segment is not underlined for
       some unknown reason (add an extra space character to make it look better)

    5. In old Matlab versions (e.g., Matlab 7.1 R14), multi-line styles
       only affect the first line. Single-line styles work as expected.
       R14 also appends a single space after underlined segments.

    6. Bold style is only supported on R2011b+, and cannot also be underlined.

 Change log:
    2012-08-09: Graceful degradation support for deployed (compiled) and non-desktop applications; minor bug fixes
    2012-08-06: Fixes for R2012b; added bold style; accept RGB string (non-numeric) style
    2011-11-27: Fixes for R2011b
    2011-08-29: Fix by Danilo (FEX comment) for non-default text colors
    2011-03-04: Performance improvement
    2010-06-27: Fix for R2010a/b; fixed edge case reported by Sharron; CPRINTF with no args runs the demo
    2009-09-28: Fixed edge-case problem reported by Swagat K
    2009-05-28: corrected nargout behavior sugegsted by Andreas G�
    2009-05-13: First version posted on <a href="http://www.mathworks.com/matlabcentral/fileexchange/authors/27420">MathWorks File Exchange</a>

 See also:
    sprintf, fprintf

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function count = cprintf(style,format,varargin)
0002 % CPRINTF displays styled formatted text in the Command Window
0003 %
0004 % Syntax:
0005 %    count = cprintf(style,format,...)
0006 %
0007 % Description:
0008 %    CPRINTF processes the specified text using the exact same FORMAT
0009 %    arguments accepted by the built-in SPRINTF and FPRINTF functions.
0010 %
0011 %    CPRINTF then displays the text in the Command Window using the
0012 %    specified STYLE argument. The accepted styles are those used for
0013 %    Matlab's syntax highlighting (see: File / Preferences / Colors /
0014 %    M-file Syntax Highlighting Colors), and also user-defined colors.
0015 %
0016 %    The possible pre-defined STYLE names are:
0017 %
0018 %       'Text'                 - default: black
0019 %       'Keywords'             - default: blue
0020 %       'Comments'             - default: green
0021 %       'Strings'              - default: purple
0022 %       'UnterminatedStrings'  - default: dark red
0023 %       'SystemCommands'       - default: orange
0024 %       'Errors'               - default: light red
0025 %       'Hyperlinks'           - default: underlined blue
0026 %
0027 %       'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White'
0028 %
0029 %    STYLE beginning with '-' or '_' will be underlined. For example:
0030 %          '-Blue' is underlined blue, like 'Hyperlinks';
0031 %          '_Comments' is underlined green etc.
0032 %
0033 %    STYLE beginning with '*' will be bold (R2011b+ only). For example:
0034 %          '*Blue' is bold blue;
0035 %          '*Comments' is bold green etc.
0036 %    Note: Matlab does not currently support both bold and underline,
0037 %          only one of them can be used in a single cprintf command. But of
0038 %          course bold and underline can be mixed by using separate commands.
0039 %
0040 %    STYLE also accepts a regular Matlab RGB vector, that can be underlined
0041 %    and bolded: -[0,1,1] means underlined cyan, '*[1,0,0]' is bold red.
0042 %
0043 %    STYLE is case-insensitive and accepts unique partial strings just
0044 %    like handle property names.
0045 %
0046 %    CPRINTF by itself, without any input parameters, displays a demo
0047 %
0048 % Example:
0049 %    cprintf;   % displays the demo
0050 %    cprintf('text',   'regular black text');
0051 %    cprintf('hyper',  'followed %s','by');
0052 %    cprintf('key',    '%d colored', 4);
0053 %    cprintf('-comment','& underlined');
0054 %    cprintf('err',    'elements\n');
0055 %    cprintf('cyan',   'cyan');
0056 %    cprintf('_green', 'underlined green');
0057 %    cprintf(-[1,0,1], 'underlined magenta');
0058 %    cprintf([1,0.5,0],'and multi-\nline orange\n');
0059 %    cprintf('*blue',  'and *bold* (R2011b+ only)\n');
0060 %    cprintf('string');  % same as fprintf('string') and cprintf('text','string')
0061 %
0062 % Bugs and suggestions:
0063 %    Please send to Yair Altman (altmany at gmail dot com)
0064 %
0065 % Warning:
0066 %    This code heavily relies on undocumented and unsupported Matlab
0067 %    functionality. It works on Matlab 7+, but use at your own risk!
0068 %
0069 %    A technical description of the implementation can be found at:
0070 %    <a href="http://undocumentedmatlab.com/blog/cprintf/">http://UndocumentedMatlab.com/blog/cprintf/</a>
0071 %
0072 % Limitations:
0073 %    1. In R2011a and earlier, a single space char is inserted at the
0074 %       beginning of each CPRINTF text segment (this is ok in R2011b+).
0075 %
0076 %    2. In R2011a and earlier, consecutive differently-colored multi-line
0077 %       CPRINTFs sometimes display incorrectly on the bottom line.
0078 %       As far as I could tell this is due to a Matlab bug. Examples:
0079 %         >> cprintf('-str','under\nline'); cprintf('err','red\n'); % hidden 'red', unhidden '_'
0080 %         >> cprintf('str','regu\nlar'); cprintf('err','red\n'); % underline red (not purple) 'lar'
0081 %
0082 %    3. Sometimes, non newline ('\n')-terminated segments display unstyled
0083 %       (black) when the command prompt chevron ('>>') regains focus on the
0084 %       continuation of that line (I can't pinpoint when this happens).
0085 %       To fix this, simply newline-terminate all command-prompt messages.
0086 %
0087 %    4. In R2011b and later, the above errors appear to be fixed. However,
0088 %       the last character of an underlined segment is not underlined for
0089 %       some unknown reason (add an extra space character to make it look better)
0090 %
0091 %    5. In old Matlab versions (e.g., Matlab 7.1 R14), multi-line styles
0092 %       only affect the first line. Single-line styles work as expected.
0093 %       R14 also appends a single space after underlined segments.
0094 %
0095 %    6. Bold style is only supported on R2011b+, and cannot also be underlined.
0096 %
0097 % Change log:
0098 %    2012-08-09: Graceful degradation support for deployed (compiled) and non-desktop applications; minor bug fixes
0099 %    2012-08-06: Fixes for R2012b; added bold style; accept RGB string (non-numeric) style
0100 %    2011-11-27: Fixes for R2011b
0101 %    2011-08-29: Fix by Danilo (FEX comment) for non-default text colors
0102 %    2011-03-04: Performance improvement
0103 %    2010-06-27: Fix for R2010a/b; fixed edge case reported by Sharron; CPRINTF with no args runs the demo
0104 %    2009-09-28: Fixed edge-case problem reported by Swagat K
0105 %    2009-05-28: corrected nargout behavior sugegsted by Andreas G�
0106 %    2009-05-13: First version posted on <a href="http://www.mathworks.com/matlabcentral/fileexchange/authors/27420">MathWorks File Exchange</a>
0107 %
0108 % See also:
0109 %    sprintf, fprintf
0110 
0111 % License to use and modify this code is granted freely to all interested, as long as the original author is
0112 % referenced and attributed as such. The original author maintains the right to be solely associated with this work.
0113 
0114 % Programmed and Copyright by Yair M. Altman: altmany(at)gmail.com
0115 % $Revision$  $Date$
0116 
0117   persistent majorVersion minorVersion
0118   if isempty(majorVersion)
0119       %v = version; if str2double(v(1:3)) <= 7.1
0120       %majorVersion = str2double(regexprep(version,'^(\d+).*','$1'));
0121       %minorVersion = str2double(regexprep(version,'^\d+\.(\d+).*','$1'));
0122       %[a,b,c,d,versionIdStrs]=regexp(version,'^(\d+)\.(\d+).*');  %#ok unused
0123       v = sscanf(version, '%d.', 2);
0124       majorVersion = v(1); %str2double(versionIdStrs{1}{1});
0125       minorVersion = v(2); %str2double(versionIdStrs{1}{2});
0126   end
0127 
0128   % The following is for debug use only:
0129   %global docElement txt el
0130   if ~exist('el','var') || isempty(el),  el=handle([]);  end  %#ok mlint short-circuit error ("used before defined")
0131   if nargin<1, showDemo(majorVersion,minorVersion); return;  end
0132   if isempty(style),  return;  end
0133   if all(ishandle(style)) && length(style)~=3
0134       dumpElement(style);
0135       return;
0136   end
0137 
0138   % Process the text string
0139   if nargin<2, format = style; style='text';  end
0140   %error(nargchk(2, inf, nargin, 'struct'));
0141   %str = sprintf(format,varargin{:});
0142 
0143   % In compiled mode
0144   try useDesktop = usejava('desktop'); catch, useDesktop = false; end
0145   if isdeployed | ~useDesktop %#ok<OR2> - for Matlab 6 compatibility
0146       % do not display any formatting - use simple fprintf()
0147       % See: http://undocumentedmatlab.com/blog/bold-color-text-in-the-command-window/#comment-103035
0148       % Also see: https://mail.google.com/mail/u/0/?ui=2&shva=1#all/1390a26e7ef4aa4d
0149       % Also see: https://mail.google.com/mail/u/0/?ui=2&shva=1#all/13a6ed3223333b21
0150       count1 = fprintf(format,varargin{:});
0151   else
0152       % Else (Matlab desktop mode)
0153       % Get the normalized style name and underlining flag
0154       [underlineFlag, boldFlag, style] = processStyleInfo(style);
0155 
0156       % Set hyperlinking, if so requested
0157       if underlineFlag
0158           format = ['<a href="">' format '</a>'];
0159 
0160           % Matlab 7.1 R14 (possibly a few newer versions as well?)
0161           % have a bug in rendering consecutive hyperlinks
0162           % This is fixed by appending a single non-linked space
0163           if majorVersion < 7 || (majorVersion==7 && minorVersion <= 1)
0164               format(end+1) = ' ';
0165           end
0166       end
0167 
0168       % Set bold, if requested and supported (R2011b+)
0169       if boldFlag
0170           if (majorVersion > 7 || minorVersion >= 13)
0171               format = ['<strong>' format '</strong>'];
0172           else
0173               boldFlag = 0;
0174           end
0175       end
0176 
0177       % Get the current CW position
0178       cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
0179       lastPos = cmdWinDoc.getLength;
0180 
0181       % If not beginning of line
0182       bolFlag = 0;  %#ok
0183       %if docElement.getEndOffset - docElement.getStartOffset > 1
0184           % Display a hyperlink element in order to force element separation
0185           % (otherwise adjacent elements on the same line will be merged)
0186           if majorVersion<7 || (majorVersion==7 && minorVersion<13)
0187               if ~underlineFlag
0188                   fprintf('<a href=""> </a>');  %fprintf('<a href=""> </a>\b');
0189               elseif format(end)~=10  % if no newline at end
0190                   fprintf(' ');  %fprintf(' \b');
0191               end
0192           end
0193           %drawnow;
0194           bolFlag = 1;
0195       %end
0196 
0197       % Get a handle to the Command Window component
0198       mde = com.mathworks.mde.desk.MLDesktop.getInstance;
0199       cw = mde.getClient('Command Window');
0200       xCmdWndView = cw.getComponent(0).getViewport.getComponent(0);
0201 
0202       % Store the CW background color as a special color pref
0203       % This way, if the CW bg color changes (via File/Preferences),
0204       % it will also affect existing rendered strs
0205       com.mathworks.services.Prefs.setColorPref('CW_BG_Color',xCmdWndView.getBackground);
0206 
0207       % Display the text in the Command Window
0208       count1 = fprintf(2,format,varargin{:});
0209 
0210       %awtinvoke(cmdWinDoc,'remove',lastPos,1);   % TODO: find out how to remove the extra '_'
0211       drawnow;  % this is necessary for the following to work properly (refer to Evgeny Pr in FEX comment 16/1/2011)
0212       docElement = cmdWinDoc.getParagraphElement(lastPos+1);
0213       if majorVersion<7 || (majorVersion==7 && minorVersion<13)
0214           if bolFlag && ~underlineFlag
0215               % Set the leading hyperlink space character ('_') to the bg color, effectively hiding it
0216               % Note: old Matlab versions have a bug in hyperlinks that need to be accounted for...
0217               %disp(' '); dumpElement(docElement)
0218               setElementStyle(docElement,'CW_BG_Color',1+underlineFlag,majorVersion,minorVersion); %+getUrlsFix(docElement));
0219               %disp(' '); dumpElement(docElement)
0220               el(end+1) = handle(docElement);  %#ok used in debug only
0221           end
0222 
0223           % Fix a problem with some hidden hyperlinks becoming unhidden...
0224           fixHyperlink(docElement);
0225           %dumpElement(docElement);
0226       end
0227 
0228       % Get the Document Element(s) corresponding to the latest fprintf operation
0229       while docElement.getStartOffset < cmdWinDoc.getLength
0230           % Set the element style according to the current style
0231           %disp(' '); dumpElement(docElement)
0232           specialFlag = underlineFlag | boldFlag;
0233           setElementStyle(docElement,style,specialFlag,majorVersion,minorVersion);
0234           %disp(' '); dumpElement(docElement)
0235           docElement2 = cmdWinDoc.getParagraphElement(docElement.getEndOffset+1);
0236           if isequal(docElement,docElement2),  break;  end
0237           docElement = docElement2;
0238           %disp(' '); dumpElement(docElement)
0239       end
0240 
0241       % Force a Command-Window repaint
0242       % Note: this is important in case the rendered str was not '\n'-terminated
0243       xCmdWndView.repaint;
0244 
0245       % The following is for debug use only:
0246       el(end+1) = handle(docElement);  %#ok used in debug only
0247       %elementStart  = docElement.getStartOffset;
0248       %elementLength = docElement.getEndOffset - elementStart;
0249       %txt = cmdWinDoc.getText(elementStart,elementLength);
0250   end
0251 
0252   if nargout
0253       count = count1;
0254   end
0255   return;  % debug breakpoint
0256 
0257 % Process the requested style information
0258 function [underlineFlag,boldFlag,style] = processStyleInfo(style)
0259   underlineFlag = 0;
0260   boldFlag = 0;
0261 
0262   % First, strip out the underline/bold markers
0263   if ischar(style)
0264       % Styles containing '-' or '_' should be underlined (using a no-target hyperlink hack)
0265       %if style(1)=='-'
0266       underlineIdx = (style=='-') | (style=='_');
0267       if any(underlineIdx)
0268           underlineFlag = 1;
0269           %style = style(2:end);
0270           style = style(~underlineIdx);
0271       end
0272 
0273       % Check for bold style (only if not underlined)
0274       boldIdx = (style=='*');
0275       if any(boldIdx)
0276           boldFlag = 1;
0277           style = style(~boldIdx);
0278       end
0279       if underlineFlag && boldFlag
0280           warning('YMA:cprintf:BoldUnderline','Matlab does not support both bold & underline')
0281       end
0282 
0283       % Check if the remaining style sting is a numeric vector
0284       %styleNum = str2num(style); %#ok<ST2NM>  % not good because style='text' is evaled!
0285       %if ~isempty(styleNum)
0286       if any(style==' ' | style==',' | style==';')
0287           style = str2num(style); %#ok<ST2NM>
0288       end
0289   end
0290 
0291   % Style = valid matlab RGB vector
0292   if isnumeric(style) && length(style)==3 && all(style<=1) && all(abs(style)>=0)
0293       if any(style<0)
0294           underlineFlag = 1;
0295           style = abs(style);
0296       end
0297       style = getColorStyle(style);
0298 
0299   elseif ~ischar(style)
0300       error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values')
0301 
0302   % Style name
0303   else
0304       % Try case-insensitive partial/full match with the accepted style names
0305       validStyles = {'Text','Keywords','Comments','Strings','UnterminatedStrings','SystemCommands','Errors', ...
0306                      'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White', ...
0307                      'Hyperlinks'};
0308       matches = find(strncmpi(style,validStyles,length(style)));
0309 
0310       % No match - error
0311       if isempty(matches)
0312           error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values')
0313 
0314       % Too many matches (ambiguous) - error
0315       elseif length(matches) > 1
0316           error('YMA:cprintf:AmbigStyle','Ambiguous style name - supply extra characters for uniqueness')
0317 
0318       % Regular text
0319       elseif matches == 1
0320           style = 'ColorsText';  % fixed by Danilo, 29/8/2011
0321 
0322       % Highlight preference style name
0323       elseif matches < 8
0324           style = ['Colors_M_' validStyles{matches}];
0325 
0326       % Color name
0327       elseif matches < length(validStyles)
0328           colors = [0,0,0; 0,1,1; 1,0,1; 0,0,1; 0,1,0; 1,0,0; 1,1,0; 1,1,1];
0329           requestedColor = colors(matches-7,:);
0330           style = getColorStyle(requestedColor);
0331 
0332       % Hyperlink
0333       else
0334           style = 'Colors_HTML_HTMLLinks';  % CWLink
0335           underlineFlag = 1;
0336       end
0337   end
0338 
0339 % Convert a Matlab RGB vector into a known style name (e.g., '[255,37,0]')
0340 function styleName = getColorStyle(rgb)
0341   intColor = int32(rgb*255);
0342   javaColor = java.awt.Color(intColor(1), intColor(2), intColor(3));
0343   styleName = sprintf('[%d,%d,%d]',intColor);
0344   com.mathworks.services.Prefs.setColorPref(styleName,javaColor);
0345 
0346 % Fix a bug in some Matlab versions, where the number of URL segments
0347 % is larger than the number of style segments in a doc element
0348 function delta = getUrlsFix(docElement)  %#ok currently unused
0349   tokens = docElement.getAttribute('SyntaxTokens');
0350   links  = docElement.getAttribute('LinkStartTokens');
0351   if length(links) > length(tokens(1))
0352       delta = length(links) > length(tokens(1));
0353   else
0354       delta = 0;
0355   end
0356 
0357 % fprintf(2,str) causes all previous '_'s in the line to become red - fix this
0358 function fixHyperlink(docElement)
0359   try
0360       tokens = docElement.getAttribute('SyntaxTokens');
0361       urls   = docElement.getAttribute('HtmlLink');
0362       urls   = urls(2);
0363       links  = docElement.getAttribute('LinkStartTokens');
0364       offsets = tokens(1);
0365       styles  = tokens(2);
0366       doc = docElement.getDocument;
0367 
0368       % Loop over all segments in this docElement
0369       for idx = 1 : length(offsets)-1
0370           % If this is a hyperlink with no URL target and starts with ' ' and is collored as an error (red)...
0371           if strcmp(styles(idx).char,'Colors_M_Errors')
0372               character = char(doc.getText(offsets(idx)+docElement.getStartOffset,1));
0373               if strcmp(character,' ')
0374                   if isempty(urls(idx)) && links(idx)==0
0375                       % Revert the style color to the CW background color (i.e., hide it!)
0376                       styles(idx) = java.lang.String('CW_BG_Color');
0377                   end
0378               end
0379           end
0380       end
0381   catch
0382       % never mind...
0383   end
0384 
0385 % Set an element to a particular style (color)
0386 function setElementStyle(docElement,style,specialFlag, majorVersion,minorVersion)
0387   %global tokens links urls urlTargets  % for debug only
0388   global oldStyles
0389   if nargin<3,  specialFlag=0;  end
0390   % Set the last Element token to the requested style:
0391   % Colors:
0392   tokens = docElement.getAttribute('SyntaxTokens');
0393   try
0394       styles = tokens(2);
0395       oldStyles{end+1} = styles.cell;
0396 
0397       % Correct edge case problem
0398       extraInd = double(majorVersion>7 || (majorVersion==7 && minorVersion>=13));  % =0 for R2011a-, =1 for R2011b+
0399       %{
0400       if ~strcmp('CWLink',char(styles(end-hyperlinkFlag))) && ...
0401           strcmp('CWLink',char(styles(end-hyperlinkFlag-1)))
0402          extraInd = 0;%1;
0403       end
0404       hyperlinkFlag = ~isempty(strmatch('CWLink',tokens(2)));
0405       hyperlinkFlag = 0 + any(cellfun(@(c)(~isempty(c)&&strcmp(c,'CWLink')),tokens(2).cell));
0406       %}
0407 
0408       styles(end-extraInd) = java.lang.String('');
0409       styles(end-extraInd-specialFlag) = java.lang.String(style);  %#ok apparently unused but in reality used by Java
0410       if extraInd
0411           styles(end-specialFlag) = java.lang.String(style);
0412       end
0413 
0414       oldStyles{end} = [oldStyles{end} styles.cell];
0415   catch
0416       % never mind for now
0417   end
0418   
0419   % Underlines (hyperlinks):
0420   %{
0421   links = docElement.getAttribute('LinkStartTokens');
0422   if isempty(links)
0423       %docElement.addAttribute('LinkStartTokens',repmat(int32(-1),length(tokens(2)),1));
0424   else
0425       %TODO: remove hyperlink by setting the value to -1
0426   end
0427   %}
0428 
0429   % Correct empty URLs to be un-hyperlinkable (only underlined)
0430   urls = docElement.getAttribute('HtmlLink');
0431   if ~isempty(urls)
0432       urlTargets = urls(2);
0433       for urlIdx = 1 : length(urlTargets)
0434           try
0435               if urlTargets(urlIdx).length < 1
0436                   urlTargets(urlIdx) = [];  % '' => []
0437               end
0438           catch
0439               % never mind...
0440               a=1;  %#ok used for debug breakpoint...
0441           end
0442       end
0443   end
0444   
0445   % Bold: (currently unused because we cannot modify this immutable int32 numeric array)
0446   %{
0447   try
0448       %hasBold = docElement.isDefined('BoldStartTokens');
0449       bolds = docElement.getAttribute('BoldStartTokens');
0450       if ~isempty(bolds)
0451           %docElement.addAttribute('BoldStartTokens',repmat(int32(1),length(bolds),1));
0452       end
0453   catch
0454       % never mind - ignore...
0455       a=1;  %#ok used for debug breakpoint...
0456   end
0457   %}
0458   
0459   return;  % debug breakpoint
0460 
0461 % Display information about element(s)
0462 function dumpElement(docElements)
0463   %return;
0464   numElements = length(docElements);
0465   cmdWinDoc = docElements(1).getDocument;
0466   for elementIdx = 1 : numElements
0467       if numElements > 1,  fprintf('Element #%d:\n',elementIdx);  end
0468       docElement = docElements(elementIdx);
0469       if ~isjava(docElement),  docElement = docElement.java;  end
0470       %docElement.dump(java.lang.System.out,1)
0471       disp(' ');
0472       disp(docElement)
0473       tokens = docElement.getAttribute('SyntaxTokens');
0474       if isempty(tokens),  continue;  end
0475       links = docElement.getAttribute('LinkStartTokens');
0476       urls  = docElement.getAttribute('HtmlLink');
0477       try bolds = docElement.getAttribute('BoldStartTokens'); catch, bolds = []; end
0478       txt = {};
0479       tokenLengths = tokens(1);
0480       for tokenIdx = 1 : length(tokenLengths)-1
0481           tokenLength = diff(tokenLengths(tokenIdx+[0,1]));
0482           if (tokenLength < 0)
0483               tokenLength = docElement.getEndOffset - docElement.getStartOffset - tokenLengths(tokenIdx);
0484           end
0485           txt{tokenIdx} = cmdWinDoc.getText(docElement.getStartOffset+tokenLengths(tokenIdx),tokenLength).char;  %#ok
0486       end
0487       lastTokenStartOffset = docElement.getStartOffset + tokenLengths(end);
0488       txt{end+1} = cmdWinDoc.getText(lastTokenStartOffset, docElement.getEndOffset-lastTokenStartOffset).char;  %#ok
0489       %cmdWinDoc.uiinspect
0490       %docElement.uiinspect
0491       txt = strrep(txt',sprintf('\n'),'\n');
0492       try
0493           data = [tokens(2).cell m2c(tokens(1)) m2c(links) m2c(urls(1)) cell(urls(2)) m2c(bolds) txt];
0494           if elementIdx==1
0495               disp('    SyntaxTokens(2,1) - LinkStartTokens - HtmlLink(1,2) - BoldStartTokens - txt');
0496               disp('    ==============================================================================');
0497           end
0498       catch
0499           try
0500               data = [tokens(2).cell m2c(tokens(1)) m2c(links) txt];
0501           catch
0502               disp([tokens(2).cell m2c(tokens(1)) txt]);
0503               try
0504                   data = [m2c(links) m2c(urls(1)) cell(urls(2))];
0505               catch
0506                   % Mtlab 7.1 only has urls(1)...
0507                   data = [m2c(links) urls.cell];
0508               end
0509           end
0510       end
0511       disp(data)
0512   end
0513 
0514 % Utility function to convert matrix => cell
0515 function cells = m2c(data)
0516   %datasize = size(data);  cells = mat2cell(data,ones(1,datasize(1)),ones(1,datasize(2)));
0517   cells = num2cell(data);
0518 
0519 % Display the help and demo
0520 function showDemo(majorVersion,minorVersion)
0521   fprintf('cprintf displays formatted text in the Command Window.\n\n');
0522   fprintf('Syntax: count = cprintf(style,format,...);  click <a href="matlab:help cprintf">here</a> for details.\n\n');
0523   url = 'http://UndocumentedMatlab.com/blog/cprintf/';
0524   fprintf(['Technical description: <a href="' url '">' url '</a>\n\n']);
0525   fprintf('Demo:\n\n');
0526   boldFlag = majorVersion>7 || (majorVersion==7 && minorVersion>=13);
0527   s = ['cprintf(''text'',    ''regular black text'');' 10 ...
0528        'cprintf(''hyper'',   ''followed %s'',''by'');' 10 ...
0529        'cprintf(''key'',     ''%d colored'',' num2str(4+boldFlag) ');' 10 ...
0530        'cprintf(''-comment'',''& underlined'');' 10 ...
0531        'cprintf(''err'',     ''elements:\n'');' 10 ...
0532        'cprintf(''cyan'',    ''cyan'');' 10 ...
0533        'cprintf(''_green'',  ''underlined green'');' 10 ...
0534        'cprintf(-[1,0,1],  ''underlined magenta'');' 10 ...
0535        'cprintf([1,0.5,0], ''and multi-\nline orange\n'');' 10];
0536    if boldFlag
0537        % In R2011b+ the internal bug that causes the need for an extra space
0538        % is apparently fixed, so we must insert the sparator spaces manually...
0539        % On the other hand, 2011b enables *bold* format
0540        s = [s 'cprintf(''*blue'',   ''and *bold* (R2011b+ only)\n'');' 10];
0541        s = strrep(s, ''')',' '')');
0542        s = strrep(s, ''',5)',' '',5)');
0543        s = strrep(s, '\n ','\n');
0544    end
0545    disp(s);
0546    eval(s);
0547 
0548 
0549 %%%%%%%%%%%%%%%%%%%%%%%%%% TODO %%%%%%%%%%%%%%%%%%%%%%%%%
0550 % - Fix: Remove leading space char (hidden underline '_')
0551 % - Fix: Find workaround for multi-line quirks/limitations
0552 % - Fix: Non-\n-terminated segments are displayed as black
0553 % - Fix: Check whether the hyperlink fix for 7.1 is also needed on 7.2 etc.
0554 % - Enh: Add font support

Community support and wiki are available on Redmine. Last update: 18-Apr-2019.