line source
+ − function count = cprintf(style,format,varargin)
+ − % 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'
+ − %
+ − % Note: styles beginning with '-' will be underlined. For example:
+ − % '-Blue' is underlined blue, like 'Hyperlinks';
+ − % '-Comments' is underlined green etc.
+ − %
+ − % STYLE also accepts a regular Matlab RGB vector, that can be negated
+ − % for underlining. For example: -[0,1,1] means underlined cyan.
+ − %
+ − % STYLE is case-insensitive and accepts unique partial strings just
+ − % like handle property names.
+ − %
+ − % Examples:
+ − % cprintf('text', 'regular black text');
+ − % cprintf('hyper', 'followed %s','by');
+ − % cprintf('k', '%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');
+ − %
+ − % 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. For unfortunate implementation reasons, a single space character
+ − % is inserted at the beginning of each CPRINTF text segment.
+ − % I hope to solve this in a future version of CPRINTF.
+ − %
+ − % 2. 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 cevron ('>>') 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. Multi-line styles only affect the first line on old Matlab versions
+ − % (e.g., Matlab 7.1 R14). Single-line styles work as expected.
+ − % R14 also appends a single space after underlined segments.
+ − %
+ − % Change log:
+ − % 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
+ −
+ − % License to use and modify this code is granted freely to all interested, as long as the original author is
+ − % referenced and attributed as such. The original author maintains the right to be solely associated with this work.
+ −
+ − % Programmed and Copyright by Yair M. Altman: altmany(at)gmail.com
+ − % $Revision: 1.2 $ $Date: 2009/08/27 19:31:59 $
+ −
+ − % The following is for debug use only:
+ − %global docElement txt el
+ − if ~exist('el','var') || isempty(el), el=handle([]); end %#ok mlint short-circuit error ("used before defined")
+ − if isempty(style), return; end
+ − if ishandle(style), dumpElement(style); return; end
+ −
+ − % Process the text string
+ − error(nargchk(2, inf, nargin, 'struct'));
+ − str = sprintf(format,varargin{:});
+ −
+ − % Get the normalized style name and underlining flag
+ − [underlineFlag, style] = processStyleInfo(style);
+ −
+ − % Set hyperlinking, is so requested
+ − if underlineFlag
+ − str = ['<a href=" ">' str '</a>'];
+ − v = version;
+ −
+ − % Matlab 7.1 R14 (possibly a few newer versions as well?)
+ − % have a bug in rendering consecutive hyperlinks
+ − % This is fixed by appending a single non-linked space
+ − if str2double(v(1:3)) <= 7.1
+ − str(end+1) = ' ';
+ − end
+ − end
+ −
+ − % Get the current CW position
+ − cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
+ − lastPos = cmdWinDoc.getLength;
+ −
+ − % If not beginning of line
+ − bolFlag = 0; %#ok
+ − %if docElement.getEndOffset - docElement.getStartOffset > 1
+ − % Display a hyperlink element in order to force element separation
+ − % (otherwise adjacent elements on the same line will me merged)
+ − if ~underlineFlag
+ − fprintf('<a href=""> </a>');
+ − else
+ − fprintf(' ');
+ − end
+ − % drawnow;
+ − bolFlag = 1;
+ − %end
+ −
+ − % Get a handle to the Command Window component
+ − mde = com.mathworks.mde.desk.MLDesktop.getInstance;
+ − cw = mde.getClient('Command Window');
+ − xCmdWndView = cw.getComponent(0).getViewport.getComponent(0);
+ −
+ − % Store the CW background color as a special color pref
+ − % This way, if the CW bg color changes (via File/Preferences),
+ − % it will also affect existing rendered strs
+ − com.mathworks.services.Prefs.setColorPref('CW_BG_Color',xCmdWndView.getBackground);
+ −
+ − % Display the text in the Command Window
+ − count = fprintf(2,str);
+ − %awtinvoke(cmdWinDoc,'remove',lastPos,1); % TODO: find out how to remove the extra '_'
+ − drawnow;
+ − docElement = cmdWinDoc.getParagraphElement(lastPos+1);
+ − if bolFlag && ~underlineFlag
+ − % Set the leading hyperlink space character ('_') to the bg color, effectively hiding it
+ − % Note: old Matlab versions have a bug in hyperlinks that need to be accounted for...
+ − %disp(' '); dumpElement(docElement)
+ − setElementStyle(docElement,'CW_BG_Color',1+underlineFlag); %+getUrlsFix(docElement));
+ − %disp(' '); dumpElement(docElement)
+ − el(end+1) = handle(docElement);
+ − end
+ −
+ − % Fix a problem with some hidden hyperlinks becoming unhidden...
+ − fixHyperlink(docElement);
+ −
+ − % Get the Document Element(s) corresponding to the latest fprintf operation
+ − while docElement.getStartOffset < cmdWinDoc.getLength
+ − % Set the element style according to the current style
+ − setElementStyle(docElement,style,underlineFlag);
+ − docElement2 = cmdWinDoc.getParagraphElement(docElement.getEndOffset+1);
+ − if isequal(docElement,docElement2), break; end
+ − docElement = docElement2;
+ − end
+ −
+ − % Force a Command-Window repaint
+ − % Note: this is important in case the rendered str was not '\n'-terminated
+ − xCmdWndView.repaint;
+ −
+ − % The following is for debug use only:
+ − el(end+1) = handle(docElement); %#ok used in debug only
+ − %elementStart = docElement.getStartOffset;
+ − %elementLength = docElement.getEndOffset - elementStart;
+ − %txt = cmdWinDoc.getText(elementStart,elementLength);
+ −
+ − return; % debug breakpoint
+ −
+ − % Process the requested style information
+ − function [underlineFlag,style] = processStyleInfo(style)
+ − underlineFlag = 0;
+ −
+ − % Style = valid matlab RGB vector
+ − if isnumeric(style) && length(style)==3 && all(style<=1) && all(abs(style)>=0)
+ − if any(style<0)
+ − underlineFlag = 1;
+ − style = abs(style);
+ − end
+ − style = getColorStyle(style);
+ −
+ − elseif ~ischar(style)
+ − error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values')
+ −
+ − % Style name
+ − else
+ − % Styles starting with '-' should be underlined (using a no-target hyperlink hack)
+ − if style(1)=='-'
+ − underlineFlag = 1;
+ − style = style(2:end);
+ − end
+ −
+ − % Try case-insensitive partial/full match with the accepted style names
+ − validStyles = {'Text','Keywords','Comments','Strings','UnterminatedStrings','SystemCommands','Errors', ...
+ − 'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White', ...
+ − 'Hyperlinks'};
+ − matches = find(strncmpi(style,validStyles,length(style)));
+ −
+ − % No match - error
+ − if isempty(matches)
+ − error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values')
+ −
+ − % Too many matches (ambiguous) - error
+ − elseif length(matches) > 1
+ − error('YMA:cprintf:AmbigStyle','Ambiguous style name - supply extra characters for uniqueness')
+ −
+ − % Regular text
+ − elseif matches == 1
+ − style = '';
+ −
+ − % Highlight preference style name
+ − elseif matches < 8
+ − style = ['Colors_M_' validStyles{matches}];
+ −
+ − % Color name
+ − elseif matches < length(validStyles)
+ − 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];
+ − requestedColor = colors(matches-7,:);
+ − style = getColorStyle(requestedColor);
+ −
+ − % Hyperlink
+ − else
+ − style = 'Colors_HTML_HTMLLinks'; % CWLink
+ − underlineFlag = 1;
+ − end
+ − end
+ −
+ − % Convert a Matlab RGB vector into a known style name (e.g., '[255,37,0]')
+ − function styleName = getColorStyle(rgb)
+ − intColor = int32(floor(rgb*255));
+ − javaColor = java.awt.Color(intColor(1), intColor(2), intColor(3));
+ − styleName = sprintf('[%d,%d,%d]',intColor);
+ − com.mathworks.services.Prefs.setColorPref(styleName,javaColor);
+ −
+ − % Fix a bug in some Matlab versions, where the number of URL segments
+ − % is larger than the number of style segments in a doc element
+ − function delta = getUrlsFix(docElement) %#ok currently unused
+ − tokens = docElement.getAttribute('SyntaxTokens');
+ − links = docElement.getAttribute('LinkStartTokens');
+ − if length(links) > length(tokens(1))
+ − delta = length(links) > length(tokens(1));
+ − else
+ − delta = 0;
+ − end
+ −
+ − % fprintf(2,str) causes all previous '_'s in the line to become red - fix this
+ − function fixHyperlink(docElement)
+ − try
+ − tokens = docElement.getAttribute('SyntaxTokens');
+ − urls = docElement.getAttribute('HtmlLink');
+ − urls = urls(2);
+ − links = docElement.getAttribute('LinkStartTokens');
+ − offsets = tokens(1);
+ − styles = tokens(2);
+ − doc = docElement.getDocument;
+ −
+ − % Loop over all segments in this docElement
+ − for idx = 1 : length(offsets)-1
+ − % If this is a hyperlink with no URL target and starts with ' ' and is collored as an error (red)...
+ − if strcmp(styles(idx).char,'Colors_M_Errors')
+ − character = char(doc.getText(offsets(idx)+docElement.getStartOffset,1));
+ − if strcmp(character,' ')
+ − if isempty(urls(idx)) && links(idx)==0
+ − % Revert the style color to the CW background color (i.e., hide it!)
+ − styles(idx) = java.lang.String('CW_BG_Color');
+ − end
+ − end
+ − end
+ − end
+ − catch
+ − % never mind...
+ − end
+ −
+ − % Set an element to a particular style (color)
+ − function setElementStyle(docElement,style,hyperlinkFlag)
+ − %global tokens links urls urlTargets % for debug only
+ − if nargin<3, hyperlinkFlag=0; end
+ − % Set the last Element token to the requested style:
+ − % Colors:
+ − tokens = docElement.getAttribute('SyntaxTokens');
+ − try
+ − styles = tokens(2);
+ − %hyperlinkFlag = ~isempty(strmatch('CWLink',tokens(2)));
+ − %hyperlinkFlag = 0 + any(cellfun(@(c)(~isempty(c)&&strcmp(c,'CWLink')),tokens(2).cell));
+ − styles(end) = java.lang.String('');
+ − styles(end-hyperlinkFlag) = java.lang.String(style); %#ok apparently unused but in reality used by Java
+ − catch
+ − % never mind for now
+ − end
+ −
+ − % Underlines (hyperlinks):
+ − links = docElement.getAttribute('LinkStartTokens');
+ − if isempty(links)
+ − %docElement.addAttribute('LinkStartTokens',repmat(int32(-1),length(tokens(2)),1));
+ − else
+ − %TODO: remove hyperlink by setting the value to -1
+ − end
+ −
+ − % Correct empty URLs to be un-hyperlinkable (only underlined)
+ − urls = docElement.getAttribute('HtmlLink');
+ − if isempty(urls), return; end
+ − urlTargets = urls(2);
+ − for urlIdx = 1 : length(urlTargets)
+ − try
+ − if urlTargets(urlIdx).length < 1
+ − urlTargets(urlIdx) = []; % '' => []
+ − end
+ − catch
+ − % never mind...
+ − a=1; %#ok used for debug breakpoint...
+ − end
+ − end
+ −
+ − % Display information about element(s)
+ − function dumpElement(docElements)
+ − %return;
+ − numElements = length(docElements);
+ − for elementIdx = 1 : numElements
+ − if numElements > 1, fprintf('Element #%d:\n',elementIdx); end
+ − docElement = docElements(elementIdx);
+ − if ~isjava(docElement), docElement = docElement.java; end
+ − %docElement.dump(java.lang.System.out,1)
+ − tokens = docElement.getAttribute('SyntaxTokens');
+ − if isempty(tokens), continue; end
+ − links = docElement.getAttribute('LinkStartTokens');
+ − urls = docElement.getAttribute('HtmlLink');
+ − try
+ − data = [tokens(2).cell m2c(tokens(1)) m2c(links) m2c(urls(1)) cell(urls(2))];
+ − catch
+ − try
+ − data = [tokens(2).cell m2c(tokens(1)) m2c(links)];
+ − catch
+ − disp([tokens(2).cell m2c(tokens(1))]);
+ − try
+ − data = [m2c(links) m2c(urls(1)) cell(urls(2))];
+ − catch
+ − % Mtlab 7.1 only has urls(1)...
+ − data = [m2c(links) urls.cell];
+ − end
+ − end
+ − end
+ − disp(' ');
+ − disp(docElement)
+ − disp(data)
+ − end
+ −
+ − % Utility function to convert matrix => cell
+ − function cells = m2c(data)
+ − datasize = size(data);
+ − cells = mat2cell(data,ones(1,datasize(1)),ones(1,datasize(2)));
+ −
+ −
+ − %%%%%%%%%%%%%%%%%%%%%%%%%% TODO %%%%%%%%%%%%%%%%%%%%%%%%%
+ − % - Fix: Remove leading space char (hidden underline '_')
+ − % - Fix: Find workaround for multi-line quirks/limitations
+ − % - Fix: Non-\n-terminated segments are displayed as black
+ − % - Fix: Check whether the hyperlink fix for 7.1 is also needed on 7.2 etc.