Mercurial > hg > ltpda
comparison m-toolbox/m/etc/cprintf.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0afece42f48 |
---|---|
1 function count = cprintf(style,format,varargin) | |
2 % CPRINTF displays styled formatted text in the Command Window | |
3 % | |
4 % Syntax: | |
5 % count = cprintf(style,format,...) | |
6 % | |
7 % Description: | |
8 % CPRINTF processes the specified text using the exact same FORMAT | |
9 % arguments accepted by the built-in SPRINTF and FPRINTF functions. | |
10 % | |
11 % CPRINTF then displays the text in the Command Window using the | |
12 % specified STYLE argument. The accepted styles are those used for | |
13 % Matlab's syntax highlighting (see: File / Preferences / Colors / | |
14 % M-file Syntax Highlighting Colors), and also user-defined colors. | |
15 % | |
16 % The possible pre-defined STYLE names are: | |
17 % | |
18 % 'Text' - default: black | |
19 % 'Keywords' - default: blue | |
20 % 'Comments' - default: green | |
21 % 'Strings' - default: purple | |
22 % 'UnterminatedStrings' - default: dark red | |
23 % 'SystemCommands' - default: orange | |
24 % 'Errors' - default: light red | |
25 % 'Hyperlinks' - default: underlined blue | |
26 % | |
27 % 'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White' | |
28 % | |
29 % Note: styles beginning with '-' will be underlined. For example: | |
30 % '-Blue' is underlined blue, like 'Hyperlinks'; | |
31 % '-Comments' is underlined green etc. | |
32 % | |
33 % STYLE also accepts a regular Matlab RGB vector, that can be negated | |
34 % for underlining. For example: -[0,1,1] means underlined cyan. | |
35 % | |
36 % STYLE is case-insensitive and accepts unique partial strings just | |
37 % like handle property names. | |
38 % | |
39 % Examples: | |
40 % cprintf('text', 'regular black text'); | |
41 % cprintf('hyper', 'followed %s','by'); | |
42 % cprintf('k', '%d colored', 4); | |
43 % cprintf('-comment','& underlined'); | |
44 % cprintf('err', 'elements\n'); | |
45 % cprintf('cyan', 'cyan'); | |
46 % cprintf('-green', 'underlined green'); | |
47 % cprintf(-[1,0,1], 'underlined magenta'); | |
48 % cprintf([1,0.5,0],'and multi-\nline orange\n'); | |
49 % | |
50 % Bugs and suggestions: | |
51 % Please send to Yair Altman (altmany at gmail dot com) | |
52 % | |
53 % Warning: | |
54 % This code heavily relies on undocumented and unsupported Matlab | |
55 % functionality. It works on Matlab 7+, but use at your own risk! | |
56 % | |
57 % A technical description of the implementation can be found at: | |
58 % <a href="http://undocumentedmatlab.com/blog/cprintf/">http://UndocumentedMatlab.com/blog/cprintf/</a> | |
59 % | |
60 % Limitations: | |
61 % 1. For unfortunate implementation reasons, a single space character | |
62 % is inserted at the beginning of each CPRINTF text segment. | |
63 % I hope to solve this in a future version of CPRINTF. | |
64 % | |
65 % 2. consecutive differently-colored multi-line CPRINTFs sometimes | |
66 % display incorrectly on the bottom line. | |
67 % As far as I could tell this is due to a Matlab bug. Examples: | |
68 % >> cprintf('-str','under\nline'); cprintf('err','red\n'); % hidden 'red', unhidden '_' | |
69 % >> cprintf('str','regu\nlar'); cprintf('err','red\n'); % underline red (not purple) 'lar' | |
70 % | |
71 % 3. Sometimes, non newline ('\n')-terminated segments display unstyled | |
72 % (black) when the command prompt cevron ('>>') regains focus on the | |
73 % continuation of that line (I can't pinpoint when this happens). | |
74 % To fix this, simply newline-terminate all command-prompt messages. | |
75 % | |
76 % 4. Multi-line styles only affect the first line on old Matlab versions | |
77 % (e.g., Matlab 7.1 R14). Single-line styles work as expected. | |
78 % R14 also appends a single space after underlined segments. | |
79 % | |
80 % Change log: | |
81 % 2009-05-13: First version posted on <a href="http://www.mathworks.com/matlabcentral/fileexchange/authors/27420">MathWorks File Exchange</a> | |
82 % | |
83 % See also: | |
84 % sprintf, fprintf | |
85 | |
86 % License to use and modify this code is granted freely to all interested, as long as the original author is | |
87 % referenced and attributed as such. The original author maintains the right to be solely associated with this work. | |
88 | |
89 % Programmed and Copyright by Yair M. Altman: altmany(at)gmail.com | |
90 % $Revision: 1.2 $ $Date: 2009/08/27 19:31:59 $ | |
91 | |
92 % The following is for debug use only: | |
93 %global docElement txt el | |
94 if ~exist('el','var') || isempty(el), el=handle([]); end %#ok mlint short-circuit error ("used before defined") | |
95 if isempty(style), return; end | |
96 if ishandle(style), dumpElement(style); return; end | |
97 | |
98 % Process the text string | |
99 error(nargchk(2, inf, nargin, 'struct')); | |
100 str = sprintf(format,varargin{:}); | |
101 | |
102 % Get the normalized style name and underlining flag | |
103 [underlineFlag, style] = processStyleInfo(style); | |
104 | |
105 % Set hyperlinking, is so requested | |
106 if underlineFlag | |
107 str = ['<a href=" ">' str '</a>']; | |
108 v = version; | |
109 | |
110 % Matlab 7.1 R14 (possibly a few newer versions as well?) | |
111 % have a bug in rendering consecutive hyperlinks | |
112 % This is fixed by appending a single non-linked space | |
113 if str2double(v(1:3)) <= 7.1 | |
114 str(end+1) = ' '; | |
115 end | |
116 end | |
117 | |
118 % Get the current CW position | |
119 cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance; | |
120 lastPos = cmdWinDoc.getLength; | |
121 | |
122 % If not beginning of line | |
123 bolFlag = 0; %#ok | |
124 %if docElement.getEndOffset - docElement.getStartOffset > 1 | |
125 % Display a hyperlink element in order to force element separation | |
126 % (otherwise adjacent elements on the same line will me merged) | |
127 if ~underlineFlag | |
128 fprintf('<a href=""> </a>'); | |
129 else | |
130 fprintf(' '); | |
131 end | |
132 % drawnow; | |
133 bolFlag = 1; | |
134 %end | |
135 | |
136 % Get a handle to the Command Window component | |
137 mde = com.mathworks.mde.desk.MLDesktop.getInstance; | |
138 cw = mde.getClient('Command Window'); | |
139 xCmdWndView = cw.getComponent(0).getViewport.getComponent(0); | |
140 | |
141 % Store the CW background color as a special color pref | |
142 % This way, if the CW bg color changes (via File/Preferences), | |
143 % it will also affect existing rendered strs | |
144 com.mathworks.services.Prefs.setColorPref('CW_BG_Color',xCmdWndView.getBackground); | |
145 | |
146 % Display the text in the Command Window | |
147 count = fprintf(2,str); | |
148 %awtinvoke(cmdWinDoc,'remove',lastPos,1); % TODO: find out how to remove the extra '_' | |
149 drawnow; | |
150 docElement = cmdWinDoc.getParagraphElement(lastPos+1); | |
151 if bolFlag && ~underlineFlag | |
152 % Set the leading hyperlink space character ('_') to the bg color, effectively hiding it | |
153 % Note: old Matlab versions have a bug in hyperlinks that need to be accounted for... | |
154 %disp(' '); dumpElement(docElement) | |
155 setElementStyle(docElement,'CW_BG_Color',1+underlineFlag); %+getUrlsFix(docElement)); | |
156 %disp(' '); dumpElement(docElement) | |
157 el(end+1) = handle(docElement); | |
158 end | |
159 | |
160 % Fix a problem with some hidden hyperlinks becoming unhidden... | |
161 fixHyperlink(docElement); | |
162 | |
163 % Get the Document Element(s) corresponding to the latest fprintf operation | |
164 while docElement.getStartOffset < cmdWinDoc.getLength | |
165 % Set the element style according to the current style | |
166 setElementStyle(docElement,style,underlineFlag); | |
167 docElement2 = cmdWinDoc.getParagraphElement(docElement.getEndOffset+1); | |
168 if isequal(docElement,docElement2), break; end | |
169 docElement = docElement2; | |
170 end | |
171 | |
172 % Force a Command-Window repaint | |
173 % Note: this is important in case the rendered str was not '\n'-terminated | |
174 xCmdWndView.repaint; | |
175 | |
176 % The following is for debug use only: | |
177 el(end+1) = handle(docElement); %#ok used in debug only | |
178 %elementStart = docElement.getStartOffset; | |
179 %elementLength = docElement.getEndOffset - elementStart; | |
180 %txt = cmdWinDoc.getText(elementStart,elementLength); | |
181 | |
182 return; % debug breakpoint | |
183 | |
184 % Process the requested style information | |
185 function [underlineFlag,style] = processStyleInfo(style) | |
186 underlineFlag = 0; | |
187 | |
188 % Style = valid matlab RGB vector | |
189 if isnumeric(style) && length(style)==3 && all(style<=1) && all(abs(style)>=0) | |
190 if any(style<0) | |
191 underlineFlag = 1; | |
192 style = abs(style); | |
193 end | |
194 style = getColorStyle(style); | |
195 | |
196 elseif ~ischar(style) | |
197 error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values') | |
198 | |
199 % Style name | |
200 else | |
201 % Styles starting with '-' should be underlined (using a no-target hyperlink hack) | |
202 if style(1)=='-' | |
203 underlineFlag = 1; | |
204 style = style(2:end); | |
205 end | |
206 | |
207 % Try case-insensitive partial/full match with the accepted style names | |
208 validStyles = {'Text','Keywords','Comments','Strings','UnterminatedStrings','SystemCommands','Errors', ... | |
209 'Black','Cyan','Magenta','Blue','Green','Red','Yellow','White', ... | |
210 'Hyperlinks'}; | |
211 matches = find(strncmpi(style,validStyles,length(style))); | |
212 | |
213 % No match - error | |
214 if isempty(matches) | |
215 error('YMA:cprintf:InvalidStyle','Invalid style - see help section for a list of valid style values') | |
216 | |
217 % Too many matches (ambiguous) - error | |
218 elseif length(matches) > 1 | |
219 error('YMA:cprintf:AmbigStyle','Ambiguous style name - supply extra characters for uniqueness') | |
220 | |
221 % Regular text | |
222 elseif matches == 1 | |
223 style = ''; | |
224 | |
225 % Highlight preference style name | |
226 elseif matches < 8 | |
227 style = ['Colors_M_' validStyles{matches}]; | |
228 | |
229 % Color name | |
230 elseif matches < length(validStyles) | |
231 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]; | |
232 requestedColor = colors(matches-7,:); | |
233 style = getColorStyle(requestedColor); | |
234 | |
235 % Hyperlink | |
236 else | |
237 style = 'Colors_HTML_HTMLLinks'; % CWLink | |
238 underlineFlag = 1; | |
239 end | |
240 end | |
241 | |
242 % Convert a Matlab RGB vector into a known style name (e.g., '[255,37,0]') | |
243 function styleName = getColorStyle(rgb) | |
244 intColor = int32(floor(rgb*255)); | |
245 javaColor = java.awt.Color(intColor(1), intColor(2), intColor(3)); | |
246 styleName = sprintf('[%d,%d,%d]',intColor); | |
247 com.mathworks.services.Prefs.setColorPref(styleName,javaColor); | |
248 | |
249 % Fix a bug in some Matlab versions, where the number of URL segments | |
250 % is larger than the number of style segments in a doc element | |
251 function delta = getUrlsFix(docElement) %#ok currently unused | |
252 tokens = docElement.getAttribute('SyntaxTokens'); | |
253 links = docElement.getAttribute('LinkStartTokens'); | |
254 if length(links) > length(tokens(1)) | |
255 delta = length(links) > length(tokens(1)); | |
256 else | |
257 delta = 0; | |
258 end | |
259 | |
260 % fprintf(2,str) causes all previous '_'s in the line to become red - fix this | |
261 function fixHyperlink(docElement) | |
262 try | |
263 tokens = docElement.getAttribute('SyntaxTokens'); | |
264 urls = docElement.getAttribute('HtmlLink'); | |
265 urls = urls(2); | |
266 links = docElement.getAttribute('LinkStartTokens'); | |
267 offsets = tokens(1); | |
268 styles = tokens(2); | |
269 doc = docElement.getDocument; | |
270 | |
271 % Loop over all segments in this docElement | |
272 for idx = 1 : length(offsets)-1 | |
273 % If this is a hyperlink with no URL target and starts with ' ' and is collored as an error (red)... | |
274 if strcmp(styles(idx).char,'Colors_M_Errors') | |
275 character = char(doc.getText(offsets(idx)+docElement.getStartOffset,1)); | |
276 if strcmp(character,' ') | |
277 if isempty(urls(idx)) && links(idx)==0 | |
278 % Revert the style color to the CW background color (i.e., hide it!) | |
279 styles(idx) = java.lang.String('CW_BG_Color'); | |
280 end | |
281 end | |
282 end | |
283 end | |
284 catch | |
285 % never mind... | |
286 end | |
287 | |
288 % Set an element to a particular style (color) | |
289 function setElementStyle(docElement,style,hyperlinkFlag) | |
290 %global tokens links urls urlTargets % for debug only | |
291 if nargin<3, hyperlinkFlag=0; end | |
292 % Set the last Element token to the requested style: | |
293 % Colors: | |
294 tokens = docElement.getAttribute('SyntaxTokens'); | |
295 try | |
296 styles = tokens(2); | |
297 %hyperlinkFlag = ~isempty(strmatch('CWLink',tokens(2))); | |
298 %hyperlinkFlag = 0 + any(cellfun(@(c)(~isempty(c)&&strcmp(c,'CWLink')),tokens(2).cell)); | |
299 styles(end) = java.lang.String(''); | |
300 styles(end-hyperlinkFlag) = java.lang.String(style); %#ok apparently unused but in reality used by Java | |
301 catch | |
302 % never mind for now | |
303 end | |
304 | |
305 % Underlines (hyperlinks): | |
306 links = docElement.getAttribute('LinkStartTokens'); | |
307 if isempty(links) | |
308 %docElement.addAttribute('LinkStartTokens',repmat(int32(-1),length(tokens(2)),1)); | |
309 else | |
310 %TODO: remove hyperlink by setting the value to -1 | |
311 end | |
312 | |
313 % Correct empty URLs to be un-hyperlinkable (only underlined) | |
314 urls = docElement.getAttribute('HtmlLink'); | |
315 if isempty(urls), return; end | |
316 urlTargets = urls(2); | |
317 for urlIdx = 1 : length(urlTargets) | |
318 try | |
319 if urlTargets(urlIdx).length < 1 | |
320 urlTargets(urlIdx) = []; % '' => [] | |
321 end | |
322 catch | |
323 % never mind... | |
324 a=1; %#ok used for debug breakpoint... | |
325 end | |
326 end | |
327 | |
328 % Display information about element(s) | |
329 function dumpElement(docElements) | |
330 %return; | |
331 numElements = length(docElements); | |
332 for elementIdx = 1 : numElements | |
333 if numElements > 1, fprintf('Element #%d:\n',elementIdx); end | |
334 docElement = docElements(elementIdx); | |
335 if ~isjava(docElement), docElement = docElement.java; end | |
336 %docElement.dump(java.lang.System.out,1) | |
337 tokens = docElement.getAttribute('SyntaxTokens'); | |
338 if isempty(tokens), continue; end | |
339 links = docElement.getAttribute('LinkStartTokens'); | |
340 urls = docElement.getAttribute('HtmlLink'); | |
341 try | |
342 data = [tokens(2).cell m2c(tokens(1)) m2c(links) m2c(urls(1)) cell(urls(2))]; | |
343 catch | |
344 try | |
345 data = [tokens(2).cell m2c(tokens(1)) m2c(links)]; | |
346 catch | |
347 disp([tokens(2).cell m2c(tokens(1))]); | |
348 try | |
349 data = [m2c(links) m2c(urls(1)) cell(urls(2))]; | |
350 catch | |
351 % Mtlab 7.1 only has urls(1)... | |
352 data = [m2c(links) urls.cell]; | |
353 end | |
354 end | |
355 end | |
356 disp(' '); | |
357 disp(docElement) | |
358 disp(data) | |
359 end | |
360 | |
361 % Utility function to convert matrix => cell | |
362 function cells = m2c(data) | |
363 datasize = size(data); | |
364 cells = mat2cell(data,ones(1,datasize(1)),ones(1,datasize(2))); | |
365 | |
366 | |
367 %%%%%%%%%%%%%%%%%%%%%%%%%% TODO %%%%%%%%%%%%%%%%%%%%%%%%% | |
368 % - Fix: Remove leading space char (hidden underline '_') | |
369 % - Fix: Find workaround for multi-line quirks/limitations | |
370 % - Fix: Non-\n-terminated segments are displayed as black | |
371 % - Fix: Check whether the hyperlink fix for 7.1 is also needed on 7.2 etc. |