- Undocumented Matlab - https://undocumentedmatlab.com -
EditorMacro v2 – setting Command Window key-bindings
Posted By Yair Altman On August 20, 2009 | 4 Comments
Some weeks ago, I introduced my EditorMacro utility [1] as a means of assigning user-defined text strings and runnable macros (callbacks) to keyboard shortcuts in the Matlab Editor. I later showed how EditorMacro can be used to set non-textual editor macros [2].
Since then, I was contacted by several users with questions, enhancement requests and improvement suggestions. Of these, the most notable was from Perttu Ranta-aho who suggested (and provided sample code for) using the editor’s built-in actions. The next logical step was to extend this to support the editor menus, and then extend again to support Command Window key-bindings. We bounced several increasingly-powerful versions of the utility between us, until arriving at the version I uploaded yesterday, which has the following significant improvements over the first version:
It turns out that the Editor and Command-Window both have some ~200 built-in (native) available actions, about half of them common. Actions are identified by name, which is a lowercase dash-separated description like ‘selection-up’ (this format is familiar to Emacs users). Altogether, there are over 300 unique built-in actions which can be used, but only ~100 of them are assigned a default key-bindings. A few dozen actions have multiple assigned key-bindings. For example, the ‘selection-up’ action is assigned to both ‘shift pressed UP’ (=<shift>-<up>) and ‘shift pressed KP_UP’ (=<shift>-<Keypad-up>):
>> [bindings, actions] = EditorMacro
actions =
...[snip]
'selection-page-down' 'shift pressed PAGE_DOWN' 'editor native action'
'selection-page-up' 'shift pressed PAGE_UP' 'editor native action'
'selection-previous-word' {2x1 cell} 'editor native action'
'selection-up' {2x1 cell} 'editor native action'
'set-read-only' [] 'editor native action'
'set-writable' [] 'editor native action'
'shift-insert-break' 'shift pressed ENTER' 'editor native action'
'shift-line-left' 'ctrl pressed OPEN_BRACKET' 'editor native action'
'shift-line-right' 'ctrl pressed CLOSE_BRACKET' 'editor native action'
'shift-tab-pressed' 'shift pressed TAB' 'editor native action'
...[snip]...
'toggle-typing-mode' 'pressed INSERT' 'editor native action'
'uncomment' 'ctrl pressed T' 'editor native action'
'undo' 'ctrl pressed Z' 'editor native action'
'unselect' 'pressed ESCAPE' 'editor native action'
'adjust-window-bottom' [] 'cmdwin native action'
'adjust-window-top' [] 'cmdwin native action'
'beep' 'ctrl pressed G' 'cmdwin native action'
'break-interrupt' 'ctrl pressed CANCEL' 'cmdwin native action'
...[snip]...
'toggle-typing-mode' 'pressed INSERT' 'cmdwin native action'
'unselect' 'ctrl pressed BACK_SLASH' 'cmdwin native action'
'new-mfile' 'ctrl pressed N' 'editor menu action'
'Figure' [] 'editor menu action'
...[snip]...
Even more interesting, apparently some 200 actions do not have any pre-assigned default key-bindings, such as ‘set-read-only’ and ‘set-writable’ in the snippet above. Let’s take the ‘match-brace’ action for example. This sounded promising so I assigned it an unused key-binding and indeed found that it can be very useful: if your cursor is placed on a beginning or end of some code, clicking the assigned key-binding will jump the cursor to the other end, and then back again. This works nicely for (..), [..], for..end, try..end, if..end, etc.
>> % Ensure that -M is unassigned
>> bindings = EditorMacro('alt m')
bindings =
Empty cell array: 0-by-4
>> % Assign the key-binding and verify
>> EditorMacro('alt m','match-brace','run');
>> bindings = EditorMacro('alt m')
b =
'alt pressed M' 'match-brace' 'run' 'editor native action'
Interested readers of this post are encouraged to look within EditorMacro’s source code [3] and see how the native actions and keybindings were retrieved and modified for the editor, Command-Window and menus. In a nutshell, the native action names and key-bindings are stored in a Java Map object. Here’s a code snippet:
%% Get all available actions even those without any key-binding
function actionNames = getNativeActions(hEditorPane)
try
actionNames = {};
actionKeys = hEditorPane.getActionMap.allKeys;
actionNames = cellfun(@char,cell(actionKeys),'Uniform',0);
actionNames = sort(actionNames);
catch
% never mind...
end
%% Get all active native shortcuts (key-bindings)
function accelerators = getAccelerators(hEditorPane)
try
accelerators = cell(0,2);
inputMap = hEditorPane.getInputMap;
inputKeys = inputMap.allKeys;
accelerators = cell(numel(inputKeys),2);
for ii = 1 : numel(inputKeys)
thisKey = inputKeys(ii);
thisAction = inputMap.get(thisKey);
accelerators(ii,:) = {char(thisKey), char(thisAction)};
end
accelerators = sortrows(accelerators,1);
catch
% never mind...
end
The menu retrieval was more difficult: while it is possible to directly access the menubar reference (jMainPane.getRootPane.getMenuBar), the menu items themselves are not visible until their main menu item is clicked (displayed). The only way I know to access menu actions/keybindings is to read them from the individual menu items (if anyone knows a better way please tell me – perhaps some central key-listener repository?). Therefore, a simulation of the menu-click events is done and the menu hierarchy is traveled recuresively to collect all its actions and key-bindings.
A final note relates to the use of EDT. EDT really deserves a separate post, but in a nutshell it means that any action that affects the GUI needs to be invoked asynchronously (via the EDT) rather than synchronously (on the main Matlab thread). This is no real problem in the editor, but it is indeed an issue in the Command Window: If we do not use EDT there, we get ugly red stack-trace exceptions thrown on the Command Window whenever we run our EditorMacro-assigned macro. Here’s the code snippet that solves this:
try
% Matlab 7
%jEditorPane.insert(caretPosition, macro); % better to use replaceSelection() than insert()
try
% Try to dispatch on EDT
awtinvoke(jEditorPane.java, 'replaceSelection', macro);
catch
% no good - try direct invocation
jEditorPane.replaceSelection(macro);
end
catch
% Matlab 6
%jEditorPane.insert(macro, caretPosition); % note the reverse order of input args vs. Matlab 7...
try
% Try to dispatch on EDT
awtinvoke(jEditorPane.java, 'replaceRange', macro, jEditorPane.getSelStart, jEditorPane.getSelEnd);
catch
% no good - try direct invocation
jEditorPane.replaceRange(macro, jEditorPane.getSelStart, jEditorPane.getSelEnd);
end
end
Some limitations remain in EditorMacro – here are the major ones:
The first couple of limitations have a non-perfect workaround that Perttu came up with. He implemented this in his KeyBindings utility [4] on the Matlab File Exchange. Perhaps one day Perttu or me will find the time to merge these utilities into one.
Have you designed some crafty user-defined macro? or found some important unassigned built-in action? Please share your experience using EditorMacro in the comments section below.
Categories: Desktop, High risk of breaking in future versions, Java, Listeners
Article printed from Undocumented Matlab: https://undocumentedmatlab.com
URL to article: https://undocumentedmatlab.com/articles/editormacro-v2-setting-command-window-key-bindings
URLs in this post:
[1] EditorMacro utility: http://undocumentedmatlab.com/blog/editormacro-assign-a-keyboard-macro-in-the-matlab-editor/
[2] set non-textual editor macros: http://undocumentedmatlab.com/blog/non-textual-editor-actions/
[3] EditorMacro’s source code: http://www.mathworks.com/matlabcentral/fileexchange/24615
[4] KeyBindings utility: http://www.mathworks.com/matlabcentral/fileexchange/25089
[5] EditorMacro – assign a keyboard macro in the Matlab editor : https://undocumentedmatlab.com/articles/editormacro-assign-a-keyboard-macro-in-the-matlab-editor
[6] R2009b keyboard bindings : https://undocumentedmatlab.com/articles/r2009b-keyboard-bindings
[7] Changing Matlab's Command Window colors : https://undocumentedmatlab.com/articles/changing-matlab-command-window-colors
[8] Bold color text in the Command Window : https://undocumentedmatlab.com/articles/bold-color-text-in-the-command-window
[9] Another Command Window text color hack : https://undocumentedmatlab.com/articles/another-command-window-text-color-hack
[10] cprintf – display formatted color text in the Command Window : https://undocumentedmatlab.com/articles/cprintf-display-formatted-color-text-in-command-window
[11] : http://blogs.mathworks.com/desktop/2011/05/09/r2011a-matlab-editor-api/
Click here to print.
Copyright © Yair Altman - Undocumented Matlab. All rights reserved.
4 Comments To "EditorMacro v2 – setting Command Window key-bindings"
#1 Comment By jo On August 21, 2009 @ 13:43
Thanks!
EditorMacro has been added to the startup.m file! 🙂
So far I’ve created few macros that remarkably speed up my work.
One of them is a macro that executes code between tags embedded in a comment of an m-file – excellent alternative for Edit Run Configuration… + F5 combination during debugging an m-file, but… I cannot solve one problem: automatic saving file before run (eg. to activate fresh breakpoints).
Your post about internal commands gave me new hope. I’ve made some trials to save m-file programmatically but without effect.
Do you know if such an action is possible from inside the macro?
#2 Comment By Yair Altman On August 22, 2009 @ 12:47
@Jo – Here’s a snippet of a sample macro (callback) function:
Also look at Perttu’s KeyBindings utility for other usage examples of MLEditorServices.
Yair
#3 Comment By mb On January 13, 2012 @ 05:38
Hi,
In Matlab 2011 com.mathworks.mlservices.MLEditorServices has no such method as saveDocument.
Instead of it one can use matlab editor api to save the document:
More about it can be found here [11] .
I hope it will save someone’s time.
Regards,
mb
#4 Comment By Yair Altman On January 13, 2012 @ 05:59
This is indeed a very good example of the risks in using internal Matlab components – their API can change dramatically from one release to another, without prior notice.
Here is the alternative in the latest Matlab release (12a):
Other useful methods of the
jEditorApp.getActiveEditor
reference are: