A few days ago, a reader emailed me with a challenge to modify the standard matlab Command-Window prompt from “>> ” to some other string, preferably a dynamic prompt with the current timestamp. At first thought this cannot be done: The Command-Window prompts are hard-coded and to the best of my knowledge cannot be modified via properties or system preferences.
So the prompt can (probably) not be modified in advance, but what if it could be modified after being displayed? It is true that my cprintf utility modifies the Command-Window contents in order to display formatted text in a variety of font colors. But this case is different since cprintf runs once synchronously (user-invoked), whereas the prompt appears asynchronously multiple times.
There are two methods of handling multiple asynchronous events in Matlab: setting a callback on the object, and setting a PostSet handle.listener (or schema.listener) on the relevant object property. The first of these methods is a well-known Matlab practice, although we shall see that it uses an undocumented callback and functionality; the PostSet method is entirely undocumented and not well-known and shall be described in some later article. I decided to use the callback method to set the prompt – interested readers can try the PostSet method.
Setting the Command Window’s callback
The solution involved finding the Command-Window reference handle, and setting one of its many callbacks, in our case CaretUpdateCallback. This callback is fired whenever the desktop text is modified, which is an event we trap to replace the displayed prompt:
% Get the reference handle to the Command Window text area jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance; try cmdWin = jDesktop.getClient('Command Window'); jTextArea = cmdWin.getComponent(0).getViewport.getComponent(0); catch commandwindow; jTextArea = jDesktop.getMainFrame.getFocusOwner; end % Instrument the text area's callback if nargin && ~isempty(newPrompt) && ~strcmp(newPrompt,'>> ') set(jTextArea,'CaretUpdateCallback',{@setPromptFcn,newPrompt}); else set(jTextArea,'CaretUpdateCallback',[]); end
Now that we have the Command-Window object callback set, we need to set the logic of prompt replacement – this is done in the internal Matlab function setPromptFcn. Here is its core code:
% Does the displayed text end with the default prompt? % Note: catch a possible trailing newline try jTextArea = jTextArea.java; catch, end %#ok cwText = get(jTextArea,'Text'); pos = strfind(cwText(max(1,end-3):end),'>> '); if ~isempty(pos) % Short prompts need to be space-padded newLen = jTextArea.getCaretPosition; if length(newPrompt)<3 newPrompt(end+1:3) = ' '; elseif length(newPrompt)>3 fprintfStr = newPrompt(1:end-3); fprintf(fprintfStr); newLen = newLen + length(fprintfStr); end % The Command-Window text should be modified on the EDT awtinvoke(jTextArea,'replaceRange(Ljava.lang.String;II)',... newPrompt(end-2:end), newLen-3, newLen); awtinvoke(jTextArea,'repaint()'); end
In this code snippet, note that we space-pad prompt string that are shorter than 3 characters: this is done to prevent an internal-Matlab mixup when displaying additional text – Matlab “knows” the Command-Window’s text position and it gets mixed up if it turns out to be shorter than expected.
Also note that I use the semi-documented awtinvoke function to replace the default prompt (and an automatically-appended space) on the Event-Dispatch Thread (more on this in a future article). Since Matlab R2008a, I could use the more convenient javaMethodEDT function, but I wanted my code to work on all prior Matlab 7 versions, where javaMethodEDT was not yet available.
Preventing callback re-entry
The callback snippet above would enter an endless loop if not changed: whenever the prompt is modified the callback would have been re-fired, the prompt re-modified and so on endlessly. There are many methods of preventing callback re-entry – here’s the one I chose:
function setPromptFcn(jTextArea,eventData,newPrompt) % Prevent overlapping reentry due to prompt replacement persistent inProgress if isempty(inProgress) inProgress = 1; %#ok unused else return; end try % *** Prompt modification code goes here *** % force prompt-change callback to fizzle-out... pause(0.02); catch % Never mind - ignore errors... end % Enable new callbacks now that the prompt has been modified inProgress = []; end % setPromptFcn
Handling multiple prompt types
I now wanted my function to handle both static prompt strings (like: ‘[Yair] ‘) and dynamic prompts (like: ‘[25-Jan-2010 01:00:51] ‘). This is done by accepting string-evaluable strings/functions:
% Try to evaluate the new prompt as a function try origNewPrompt = newPrompt; newPrompt = feval(newPrompt); catch try newPrompt = eval(newPrompt); catch % Never mind - probably a string... end end if ~ischar(newPrompt) && ischar(origNewPrompt) newPrompt = origNewPrompt; end
File Exchange submission
I then added some edge-case error handling and wrapped everything in a single utility called setPrompt that is now available on the File Exchange.
In the future, if I find time, energy and interest, maybe I’ll combine cprintf’s font-styling capabilities, to enable setting colored prompts.
Setting a continuously-updated timestamp prompt
Using the code above, we can now display a dynamic timestamp prompt, as follows:

setPrompt usage examples
However, the displayed timestamp is somewhat problematic in the sense that it indicates the time of prompt creation rather than the time that the associated Command-Window command was executed. In the screenshot above, [25-Jan-2010 01:29:42] is the time that the 234 command was executed, not the time that the setPrompt command was executed. This is somewhat misleading. It would be better if the last (current) timestamp was continuously updated and would therefore always display the latest command’s execution time. This can be done using a Matlab timer as follows:
% This is entered in the main function before setting the prompt: stopPromptTimers; if nargin && strcmpi(newPrompt,'timestamp') % Update initial prompt & prepare a timer to continuously update it newPrompt = @()(['[',datestr(now),'] ']); start(timer('Tag','setPromptTimer', 'Name','setPromptTimer', ... 'ExecutionMode','fixedDelay', 'ObjectVisibility','off', ... 'Period',0.99, 'StartDelay',0.5, ... 'TimerFcn',{@setPromptTimerFcn,jTextArea})); end % Stop & delete any existing prompt timer(s) function stopPromptTimers try timers = timerfindall('tag','setPromptTimer'); if ~isempty(timers) stop(timers); delete(timers); end catch % Never mind... end end % stopPromptTimers % Internal timer callback function function setPromptTimerFcn(timerObj,eventData,jTextArea) try try jTextArea = jTextArea.java; catch, end %#ok pos = getappdata(jTextArea,'setPromptPos'); newPrompt = datestr(now); awtinvoke(jTextArea,'replaceRange(Ljava.lang.String;II)',... newPrompt, pos, pos+length(newPrompt)); awtinvoke(jTextArea,'repaint()'); catch % Never mind... end end % setPromptTimerFcn
Can you come up with some innovative prompts? If so, please share them in a comment below.
Update 2010-Jan-26: The code in this article was updated since it was first published yesterday.












