MATLAB Spoken Here

May 16th, 2011

MATLAB Editor API Examples

Last week, I showed off the MATLAB Editor API. This week I thought I would give some examples on how to use it by showing you some helper functions I've built with it.

Using the Active File's Path
Last release, we introduced the ability to open a file's directory from the Editor tab's context menu. From this menu, you can also add that file's directory to the path. Before this menu, there was no easy way to manage MATLAB's path in relation to the file currently being edited. And if the file you were currently editing wasn't in the current working folder, there was no good way to see the files in that folder or perform operations on that folder, such as using source control tools or opening a file in another program. Now you have your choice of either using the context menu or a simple one-line command:

winopen(fileparts(matlab.desktop.editor.getActiveFilename))% open the directory in Windows Explorer
addpath(fileparts(matlab.desktop.editor.getActiveFilename)) % add the file's directory to the path

This example makes use of matlab.desktop.editor.getActiveFilename. The getActiveFilename package function returns the path to the "active" Editor Document. The active Document is the last Editor tab or window that had focus. In most cases, you can just think of it as "the file I'm currently working with". In the case where you're editing a file that has never been saved, the filename is going to be some form of "Untitled", and using it in this example would cause an error.

Also a big help here is the FILEPARTS command. When there is only one output requested, FILEPARTS just returns the path part of a filename string.

Global Find and Replace
I find myself often having to cut and paste MATLAB Code into HTML documents. If you've ever done this, you know that > and < brackets are not HTML-friendly. Using the Text property, I can do a find and replace on the file's text. This example is not particularly efficient, but I think it illustrates the point.

activeEditor = matlab.desktop.editor.getActive;
activeEditor.Text = strrep(strrep(strrep(activeEditor.Text,'&','&amp;'),'<','&lt;'),'>','&gt;');

Cut, Copy and Paste
Using the the Selection and SelectedText property along with the CLIPBOARD function, we can perform programmatic cut, copy, and paste operations in the Editor. The trick here is understanding what the Selection means. This property is a 1 x 4 array in the format [ "start line" "position in the start line" "end line" "position in the end line"]. When there is no selection, the start and end are equal to the insertion point. Otherwise, the array represents the start and end of a selection, which can span multiple lines. The Text property is a 1-D array of all the text, and therefore you can't use lines and positions to directly index into it. That's where the matlab.desktop.editor.positionInLineToIndex function comes in. Its parameters are the Editor object, the line, and the position in that line, and it outputs that position as a linear index into the Text array.

% copy
activeEditor = matlab.desktop.editor.getActive;
clipboard('copy',activeEditor.SelectedText);
% cut
selectionPosition = activeEditor.Selection;
%convert the selection from Lines/Columns to index
startPos = matlab.desktop.editor.positionInLineToIndex(activeEditor, selectionPosition(1), selectionPosition(2));
endPos = matlab.desktop.editor.positionInLineToIndex(activeEditor, selectionPosition(3), selectionPosition(4));
% copy the text
clipboard('copy',activeEditor.SelectedText);
% remove the text
newText = activeEditor.Text;
newText(startPos:endPos) = [];
activeEditor.Text = newText;
% paste
%paste starts off like cut, but we splice in the clipboard text
selectionPosition = activeEditor.Selection;
%convert the selection from Lines/Columns to index
startPos = matlab.desktop.editor.positionInLineToIndex(activeEditor, selectionPosition(1), selectionPosition(2));
endPos = matlab.desktop.editor.positionInLineToIndex(activeEditor, selectionPosition(3), selectionPosition(4));
% remove the text (NOTE: this not checking array bounds, although it should to be robust)
newText = activeEditor.Text;
newText = [newText(1:startPos-1) clipboard('paste') newText(endPos+1:end)];
activeEditor.Text = newText;

Using matlab.desktop.editor.positionInLineToIndex, STRREP, and the replace technique illustrated in the paste example, you can implement a local search and replace limited to the Selection area. The Selection is also settable, which means you can programmatically highlight a section:

%highlight the second line
activeEditor.Selection = [2 1 2 inf]

Smart Templates
The old way of creating a template file was to come up with the template text, write it to a file, and then use EDIT to load it into the Editor. With the newDocument function you can skip the "write to disk" step in that process. This allows the file's name and location to be decided later when it is saved.

newFunctionName = 'newfunction';
text = sprintf('function %s\n%%%s H1 line\n\n%% Copyright %s The MathWorks, Inc.\n\n\% CODE HERE', newFunctionName, newFunctionName, datestr(now,'YYYY'));
newDoc = matlab.desktop.editor.newDocument(text);

Switching Context
My final example this week is one that came up in the comments of last week's post: saving and restoring the Editor's state. Upon startup MATLAB will reopen any files that were open when it shut down, but sometimes you may want to save and restore some intermediate state. This is most useful when working on two separate projects, and you want to maintain a clean environment by just working with one set at a time. The following example saves and then restores the open Documents.

%save state
openDocuments = matlab.desktop.editor.getAll
filenames = {openDocuments.Filename}
%remove Untitled files
filenames(strncmp(filenames,'Untitled',8)) = [];
save filenames filenames

%close them all (will prompt user to save unsaved files)
openDocuments.close

%And then to load them back again
load filenames
matlab.desktop.editor.openDocument(filenames)

Final Thoughts
If you find yourself using the getActive or getActiveFilename function, you might consider making that code reusable by saving the code snippet as a Shortcut in the toolbar. This way it's like you have a custom action button that applies to where you are currently editing.

Let us know how you use this new API.

11 Responses to “MATLAB Editor API Examples”

  1. Richard Tantaris replied on :

    Hi Mike,

    I ran your example above under switching context. It runs but I still get warnings (over 40 of them) like:

    Warning: com.mathworks.mde.editor.MatlabEditor@69b5a7 is not serializable
    > In file_close_test2 at 8
    Warning: com.mathworks.mde.editor.MatlabEditor@14ffc5 is not serializable

    Any idea what this is? Based on your explaination to my previous post, I saved the filenames in a char array and did not get these warnings.

    Thanks,

    Richard

  2. Wes replied on :

    Hi Mike

    I guess you didn’t see this question on the previous post, so here it is again:

    Say I develop a nifty tool with this API, what’s the best way to actually invoke that tool when I’m coding? Can I add my tool to the editor’s toolbar, or assign it a keyboard shortcut, or anything else?

  3. Mike replied on :

    @Richard,
    You are absolutely right. I fixed my example. The Document object should not be saved, because the in-memory representation of a Document changes each time a document is re-opened, and thus saving it would not do much good as when it is restored, it will be an invalid handle. Just the filenames variable should be saved and not the openDocuments.

    @Wes,
    Sorry for not responding to the earlier post. How you invoke the code is entirely context dependent. For example, in the string replace example, I’ve put this in a Shortcut on the toolbar, so I can apply it to any current file with the click of a button. In the saving filenames example, I have startup scripts that I run when loading a project.

    The MATLAB Desktop does not support creating toolbar buttons, menus, or assigning keyboard shortcuts to run arbitrary scripts or functions. But you can create toolbar and menu items for your own GUIs.

  4. Andy replied on :

    Wes you could use Yair Altman’s EditorMacro utility from the FEX: http://www.mathworks.com/matlabcentral/fileexchange/24615-editormacro-assign-a-macro-to-a-keyboard-key-stroke-in-the-matlab-editor-and-command-window

    Mike, is there any ability to control M-Lint via the Editor API?

  5. Mike replied on :

    @Andy,

    There is not, as this API is meant to be more or less for programmatic access only, and the M-Lint tool is pretty visual. However, You can use the MLINT function like so:

    mlint(matlab.desktop.editor.getActiveFilename)
    
  6. Andy replied on :

    @Mike,

    I am talking about things I would want to do programmatically. Imagine, for example, making a few shortcut buttons that toggle on and off individual M-Lint warnings (or using Yair’s EditorMacro to do so with keyboard shortcuts). Or imagine the ability to create your own custom M-Lint warnings by parsing your file looking for some regular expression, and, whenever you find it, add an M-Lint warning of the color of your choice. (I’ve already put in an enhancement request. I was just wondering if it already happened while I was stuck in R2009a.)

  7. Mike replied on :

    @Andy,
    Ah, I see what you mean. I, of course, can’t comment on the state of that project (but it’s not delivered yet), but I do think it’s a good idea, so I’ll nudge those developers :)

  8. bendai replied on :

    Row operation should be supported by matlab editor.

  9. Tony replied on :

    For the Switching Context example, I think this feature is great. Is there any way to preserve the order that files are listed in the editor window? Right now it seems that editor.getAll returns the files in the order opened, rather than the order currently listed.

  10. Aimbot MW3 replied on :

    I think the admin of this website is genuinely
    working hard in support of his web page, because here every stuff is quality based material.

  11. http://www.bomdia.lu replied on :

    Today, while I was at work, my cousin stole my iPad and tested to see if it
    can survive a 25 foot drop, just so she can be a youtube sensation.

    My apple ipad is now destroyed and she has 83 views. I know this is completely off topic but I had to share it with
    someone!

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


MathWorks
News from the intersection of MATLAB, Community, and the web.

These postings are the author's and don't necessarily represent the opinions of MathWorks.