This site has lately focused on quite detailed Java-related topics. Next week I will present the promised EDT article, which will dive into even deeper Java territory. So I thought to take a short break and present an entirely pure-Matlab non-Java undocumented feature, which is simple and yet quite useful.
A few months ago, a CSSM reader asked whether it is possible to customize Matlab tab-completion for user-defined functions (see related). A similar question on StackOverflow provided the necessary solution lead:
Apparently, Matlab has a file called TC.xml in its [matlabroot ‘/toolbox/local/’] folder that contains the definitions of the tab-completable functions and their arguments. In order for a user-defined function’s arguments to support tab-completion, a new entry needs to be added to this XML file.
TC.xml & TC.xsd
The full syntax of the TC.xml file can be found in the TC.xsd file, which is located in the same folder as TC.xml. Here are some sample definitions from my TC.xml file (which might vary across Matlab releases):
<binding name="addpath" ctype="DIR"/> <binding name="help" ctype="FUN SUBFUN"/> <binding name="clear" ctype="FUN VAR"/> <binding name="whos" ctype="VAR"> <arg previous="-file" ctype= "MATFILE"/> </binding> <binding name="open"> <arg argn="1" ctype="VAR MATFILE FIGFILE MFILE MDLFILE FILE"/> </binding> <binding name="openfig"> <arg argn="1" ctype="FIGFILE"/> <arg argn="2" ctype="VAR" value="new visible invisible reuse"/> </binding> <binding name="mlint" ctype="FUN"> <arg argn="2:10" ctype="VAR" value="-struct -string -id"/> </binding>
The first example defines that an unlimited number of addpath arguments are all of type DIR. Therefore, when completing any argument of this function in the Command-Window, Matlab will present only relevant DIR (=folder) elements in the pop-up window (lexically sorted):
Similarly, help defines all its arguments to be a function or sub-function type, so the popup-up will only be populated with the function names currently visible in the desktop:
Similarly, clear defines all its arguments as function names or variables. Note that the list of available functions and variables may change depending on the current execution stack position. The full list of supported types is defined in the TC.xsd file. It is: VAR, FUN, SUBFUN, DIR, FILE, MFILE, MATFILE, FIGFILE and MDLFILE. Addendum: Matlab release 7.10 (R2010a) added the MCOSPCG and MCOSCLASS types; release 7.13 (R2011b) added the MESSAGEID type.
The whos function defines all its arguments as VAR, except the single MATFILE argument that follows a ‘-file’ argument (look at whos‘s help page to understand why).
The open function defines tab completion only for its first argument (with plenty of possible types…). Likewise, openfig defines its first argument as a FIGFILE, and its second as VAR with a few extra special-purpose strings that are added to the popup-up menu.
Finally, the mlint example shows that multiple arguments can be defined using a single XML definition element. In this case, args #2-10 are defined as VAR (with three extra special-purpose strings), while args #1 and #11+ are defined as FUN.
The careful user can edit the TC.xml file using any text editor (I strongly suggest saving a backup first):
User-defined functions can easily be added to TC.xml, and we can even add/modify the built-in Matlab functions that are already defined. Note that changes to TC.xml only take effect after a Matlab restart. From then on, all future Matlab sessions will use the modification, so a really simple one-time edit can improve our workflow for a long time – at least until we upgrade Matlab, when we’ll need to redo our edits…
In order to facilitate TC.xml editing, I have created a utility called TabComplete, which is now available on the Matlab File Exchange. The use of this utility is very simple. For example:
tabcomplete test file 'DIR +data -data no_data' VAR
defines a user-defined function test that accepts a FILE argument, followed by a DIR argument with three special-purpose strings, followed by any number of VAR arguments. If I wished to define specific argument types without any default type, I would use:
tabcomplete test file 'DIR +data -data no_data' ''
Addendum: Matlab releases 7.10 (R2010a) through 7.13 (R2011b) have a bug that causes Matlab to enter an endless loop (full CPU load) whenever tab-completion is requested for an argument that has possible values that are not simple terms. In the case above, “+data” and “-data” both cause this abnormal behavior. In such cases, the only remedy is to kill the Matlab process via the OS’s task manager. In Matlab R2010a-R2011b, I therefore suggest to use only simple values. This bug is apparently fixed in R2012a, making non-simple terms safe to use again. I take at least partial credit for this, having reported this bug to Mathworks in August 2011 (1-FCGDEI).
TabComplete can also be used to retrieve the current list of tab-completion definitions:
>> definitions = tabcomplete; >> definitions(1) ans = functionName: 'addpath' defaultType: 'DIR' extraValues: '' platform: '' functionArgs:  >> definitions(54) ans = functionName: 'openfig' defaultType: '' extraValues: '' platform: '' functionArgs: [1x2 struct] >> definitions(54).functionArgs(1) ans = previousArg: '' argType: 'FIGFILE' extraValues: '' >> definitions(54).functionArgs(2) ans = previousArg: '' argType: 'VAR' extraValues: 'new visible invisible reuse'
TabComplete has a few limitations: it does not support the -previous option described above (you can do this by manually editing TC.xml). There are also some inherent limitations in Matlab’s TC functionality: changes take effect only after a Matlab restart (there might be a way to reload the definitions in the current Matlab session, but I do not know of any); the list of standard types cannot be modified; and the default type does not support extra special-purpose strings as do the numbered arguments.
There is another very annoying limitation: by default, TC.xml only supports lowercase function names. This is stupid, since Matlab has many function names with UPPERCASE characters, and certainly user-defined function names also do. Luckily, this last limitation can easily be overcome by editing the TC.xsd file (note that this is the TC.XSD file, not the TC.XML file). Instead of:
<xsd:simpletype name="tcBindingNameType"> <xsd:restriction base="xsd:token"> <xsd:pattern value='[A-Za-z_0-9]+(/[a-z_0-9]+)?'/> </xsd:restriction> </xsd:simpletype>
Change the xsd:pattern definition element to:
<!-- Yair 21/2/2010: added A-Z --> <xsd:pattern value='[A-Za-z_0-9]+(/[A-Za-z_0-9]+)?'/>
(note the way comments can be added to the XSD/XML files)
Addendum: Matlab release 7.11 (R2011a) has fixed this XSD definition; perhaps due to this article 🙂
P.S. an entirely different customization, for user-defined class members, was presented by Michal Kutil.