- update to r291 of google-code-prettify (issue 32: matlab mode courtesy amroamroamro)
- update PrettifyTest to cope with non-standard (keyword length >= 3) decoration keywords for matlab test
- modify the test case source file of issue 84 to cope with the new PrettifyTest change
diff --git a/src/prettify/lang/LangMatlab.java b/src/prettify/lang/LangMatlab.java
new file mode 100644
index 0000000..0c4e80a
--- /dev/null
+++ b/src/prettify/lang/LangMatlab.java
@@ -0,0 +1,172 @@
+// Copyright (c) 2013 by Amro <amroamroamro@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+package prettify.lang;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+import prettify.parser.Prettify;
+
+/**
+ * This is similar to the lang-ml.js in JavaScript Prettify.
+ *
+ * All comments are adapted from the JavaScript Prettify.
+ *
+ * <p> 0 Registers a language handler for MATLAB.
+ *
+ * To use, include prettify.js and this file in your HTML page. Then put your
+ * code inside an HTML tag like <pre class="prettyprint lang-matlab">
+ * </pre>
+ *
+ * @see https://github.com/amroamroamro/prettify-matlab
+ */
+public class LangMatlab extends Lang {
+
+    public static final String PR_IDENTIFIER = "ident";
+    public static final String PR_CONSTANT = "const";
+    public static final String PR_FUNCTION = "fun";
+    public static final String PR_FUNCTION_TOOLBOX = "fun_tbx";
+    public static final String PR_SYSCMD = "syscmd";
+    public static final String PR_CODE_OUTPUT = "codeoutput";
+    public static final String PR_ERROR = "err";
+    public static final String PR_WARNING = "wrn";
+    public static final String PR_TRANSPOSE = "transpose";
+    public static final String PR_LINE_CONTINUATION = "linecont";
+
+    public LangMatlab() {
+        List<List<Object>> _shortcutStylePatterns = new ArrayList<List<Object>>();
+        List<List<Object>> _fallthroughStylePatterns = new ArrayList<List<Object>>();
+
+        // identifiers: variable/function name, or a chain of variable names joined by dots (obj.method, struct.field1.field2, etc..)
+        // valid variable names (start with letter, and contains letters, digits, and underscores).
+        // we match "xx.yy" as a whole so that if "xx" is plain and "yy" is not, we dont get a false positive for "yy"
+        //var reIdent = '(?:[a-zA-Z][a-zA-Z0-9_]*)';
+        //var reIdentChain = '(?:' + reIdent + '(?:\.' + reIdent + ')*' + ')';
+
+        // patterns that always start with a known character. Must have a shortcut string.
+        // whitespaces: space, tab, carriage return, line feed, line tab, form-feed, non-break space
+        _shortcutStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_PLAIN, Pattern.compile("^[ \\t\\r\\n\\v\\f\\xA0]+"), null, " \t\n\r" + Character.toString((char) 0x0B) + Character.toString((char) 0x0C) + Character.toString((char) 0xA0)}));
+        // block comments
+        //TODO: chokes on nested block comments
+        //TODO: false positives when the lines with %{ and %} contain non-spaces
+        //[PR.PR_COMMENT, /^%(?:[^\{].*|\{(?:%|%*[^\}%])*(?:\}+%?)?)/, null],
+        _shortcutStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_COMMENT, Pattern.compile("^%\\{[^%]*%+(?:[^\\}%][^%]*%+)*\\}"), null}));
+        // single-line comments
+        _shortcutStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_COMMENT, Pattern.compile("^%[^\\r\\n]*"), null, "%"}));
+        // system commands
+        _shortcutStylePatterns.add(Arrays.asList(new Object[]{PR_SYSCMD, Pattern.compile("^![^\\r\\n]*"), null, "!"}));
+
+        // patterns that will be tried in order if the shortcut ones fail. May have shortcuts.
+        // line continuation
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_LINE_CONTINUATION, Pattern.compile("^\\.\\.\\.\\s*[\\r\\n]"), null}));
+        // error message
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_ERROR, Pattern.compile("^\\?\\?\\? [^\\r\\n]*"), null}));
+        // warning message
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_WARNING, Pattern.compile("^Warning: [^\\r\\n]*"), null}));
+        // command prompt/output
+        //[PR_CODE_OUTPUT, /^>>\s+[^\r\n]*[\r\n]{1,2}[^=]*=[^\r\n]*[\r\n]{1,2}[^\r\n]*/, null],    // full command output (both loose/compact format): `>> EXP\nVAR =\n VAL`
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_CODE_OUTPUT, Pattern.compile("^>>\\s+"), null}));       // only the command prompt `>> `
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_CODE_OUTPUT, Pattern.compile("^octave:\\d+>\\s+"), null}));       // Octave command prompt `octave:1> `
+        // identifier (chain) or closing-parenthesis/brace/bracket, and IS followed by transpose operator
+        // this way we dont misdetect the transpose operator ' as the start of a string
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{"lang-matlab-operators", Pattern.compile("^((?:[a-zA-Z][a-zA-Z0-9_]*(?:\\.[a-zA-Z][a-zA-Z0-9_]*)*|\\)|\\]|\\}|\\.)')"), null}));
+        // identifier (chain), and NOT followed by transpose operator
+        // this must come AFTER the "is followed by transpose" step (otherwise it chops the last char of identifier)
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{"lang-matlab-identifiers", Pattern.compile("^([a-zA-Z][a-zA-Z0-9_]*(?:\\.[a-zA-Z][a-zA-Z0-9_]*)*)(?!')"), null}));
+        // single-quoted strings: allow for escaping with '', no multilines
+        //[PR.PR_STRING, /(?:(?<=(?:\(|\[|\{|\s|=|;|,|:))|^)'(?:[^']|'')*'(?=(?:\)|\]|\}|\s|=|;|,|:|~|<|>|&|-|\+|\*|\.|\^|\|))/, null],  // string vs. transpose (check before/after context using negative/positive lookbehind/lookahead)
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_STRING, Pattern.compile("^'(?:[^']|'')*'"), null}));  // "'"
+        // floating point numbers: 1, 1.0, 1i, -1.1E-1
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_LITERAL, Pattern.compile("^[+\\-]?\\.?\\d+(?:\\.\\d*)?(?:[Ee][+\\-]?\\d+)?[ij]?"), null}));
+        // parentheses, braces, brackets
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_TAG, Pattern.compile("^(?:\\{|\\}|\\(|\\)|\\[|\\])"), null}));     // "{}()[]"
+        // other operators
+        _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_PUNCTUATION, Pattern.compile("^(?:<|>|=|~|@|&|;|,|:|!|\\-|\\+|\\*|\\^|\\.|\\||\\\\|\\/)"), null}));
+
+        setShortcutStylePatterns(_shortcutStylePatterns);
+        setFallthroughStylePatterns(_fallthroughStylePatterns);
+
+        setExtendedLangs(Arrays.asList(new Lang[]{new LangMatlab.LangMatlabIdentifier(), new LangMatlab.LangMatlabOperator()}));
+    }
+
+    public static List<String> getFileExtensions() {
+        return Arrays.asList(new String[]{"matlab"});
+    }
+
+    protected static class LangMatlabIdentifier extends Lang {
+
+        public LangMatlabIdentifier() {
+            List<List<Object>> _shortcutStylePatterns = new ArrayList<List<Object>>();
+            List<List<Object>> _fallthroughStylePatterns = new ArrayList<List<Object>>();
+
+            // Refer to: http://www.mathworks.com/help/matlab/functionlist-alpha.html
+            String coreFunctions = "abs|accumarray|acos(?:d|h)?|acot(?:d|h)?|acsc(?:d|h)?|actxcontrol(?:list|select)?|actxGetRunningServer|actxserver|addlistener|addpath|addpref|addtodate|airy|align|alim|all|allchild|alpha|alphamap|amd|ancestor|and|angle|annotation|any|area|arrayfun|asec(?:d|h)?|asin(?:d|h)?|assert|assignin|atan(?:2|d|h)?|audiodevinfo|audioplayer|audiorecorder|aufinfo|auread|autumn|auwrite|avifile|aviinfo|aviread|axes|axis|balance|bar(?:3|3h|h)?|base2dec|beep|BeginInvoke|bench|bessel(?:h|i|j|k|y)|beta|betainc|betaincinv|betaln|bicg|bicgstab|bicgstabl|bin2dec|bitand|bitcmp|bitget|bitmax|bitnot|bitor|bitset|bitshift|bitxor|blanks|blkdiag|bone|box|brighten|brush|bsxfun|builddocsearchdb|builtin|bvp4c|bvp5c|bvpget|bvpinit|bvpset|bvpxtend|calendar|calllib|callSoapService|camdolly|cameratoolbar|camlight|camlookat|camorbit|campan|campos|camproj|camroll|camtarget|camup|camva|camzoom|cart2pol|cart2sph|cast|cat|caxis|cd|cdf2rdf|cdfepoch|cdfinfo|cdflib(?:\\.(?:close|closeVar|computeEpoch|computeEpoch16|create|createAttr|createVar|delete|deleteAttr|deleteAttrEntry|deleteAttrgEntry|deleteVar|deleteVarRecords|epoch16Breakdown|epochBreakdown|getAttrEntry|getAttrgEntry|getAttrMaxEntry|getAttrMaxgEntry|getAttrName|getAttrNum|getAttrScope|getCacheSize|getChecksum|getCompression|getCompressionCacheSize|getConstantNames|getConstantValue|getCopyright|getFileBackward|getFormat|getLibraryCopyright|getLibraryVersion|getMajority|getName|getNumAttrEntries|getNumAttrgEntries|getNumAttributes|getNumgAttributes|getReadOnlyMode|getStageCacheSize|getValidate|getVarAllocRecords|getVarBlockingFactor|getVarCacheSize|getVarCompression|getVarData|getVarMaxAllocRecNum|getVarMaxWrittenRecNum|getVarName|getVarNum|getVarNumRecsWritten|getVarPadValue|getVarRecordData|getVarReservePercent|getVarsMaxWrittenRecNum|getVarSparseRecords|getVersion|hyperGetVarData|hyperPutVarData|inquire|inquireAttr|inquireAttrEntry|inquireAttrgEntry|inquireVar|open|putAttrEntry|putAttrgEntry|putVarData|putVarRecordData|renameAttr|renameVar|setCacheSize|setChecksum|setCompression|setCompressionCacheSize|setFileBackward|setFormat|setMajority|setReadOnlyMode|setStageCacheSize|setValidate|setVarAllocBlockRecords|setVarBlockingFactor|setVarCacheSize|setVarCompression|setVarInitialRecs|setVarPadValue|SetVarReservePercent|setVarsCacheSize|setVarSparseRecords))?|cdfread|cdfwrite|ceil|cell2mat|cell2struct|celldisp|cellfun|cellplot|cellstr|cgs|checkcode|checkin|checkout|chol|cholinc|cholupdate|circshift|cla|clabel|class|clc|clear|clearvars|clf|clipboard|clock|close|closereq|cmopts|cmpermute|cmunique|colamd|colon|colorbar|colordef|colormap|colormapeditor|colperm|Combine|comet|comet3|commandhistory|commandwindow|compan|compass|complex|computer|cond|condeig|condest|coneplot|conj|containers\\.Map|contour(?:3|c|f|slice)?|contrast|conv|conv2|convhull|convhulln|convn|cool|copper|copyfile|copyobj|corrcoef|cos(?:d|h)?|cot(?:d|h)?|cov|cplxpair|cputime|createClassFromWsdl|createSoapMessage|cross|csc(?:d|h)?|csvread|csvwrite|ctranspose|cumprod|cumsum|cumtrapz|curl|customverctrl|cylinder|daqread|daspect|datacursormode|datatipinfo|date|datenum|datestr|datetick|datevec|dbclear|dbcont|dbdown|dblquad|dbmex|dbquit|dbstack|dbstatus|dbstep|dbstop|dbtype|dbup|dde23|ddeget|ddesd|ddeset|deal|deblank|dec2base|dec2bin|dec2hex|decic|deconv|del2|delaunay|delaunay3|delaunayn|DelaunayTri|delete|demo|depdir|depfun|det|detrend|deval|diag|dialog|diary|diff|diffuse|dir|disp|display|dither|divergence|dlmread|dlmwrite|dmperm|doc|docsearch|dos|dot|dragrect|drawnow|dsearch|dsearchn|dynamicprops|echo|echodemo|edit|eig|eigs|ellipj|ellipke|ellipsoid|empty|enableNETfromNetworkDrive|enableservice|EndInvoke|enumeration|eomday|eq|erf|erfc|erfcinv|erfcx|erfinv|error|errorbar|errordlg|etime|etree|etreeplot|eval|evalc|evalin|event\\.(?:EventData|listener|PropertyEvent|proplistener)|exifread|exist|exit|exp|expint|expm|expm1|export2wsdlg|eye|ezcontour|ezcontourf|ezmesh|ezmeshc|ezplot|ezplot3|ezpolar|ezsurf|ezsurfc|factor|factorial|fclose|feather|feature|feof|ferror|feval|fft|fft2|fftn|fftshift|fftw|fgetl|fgets|fieldnames|figure|figurepalette|fileattrib|filebrowser|filemarker|fileparts|fileread|filesep|fill|fill3|filter|filter2|find|findall|findfigs|findobj|findstr|finish|fitsdisp|fitsinfo|fitsread|fitswrite|fix|flag|flipdim|fliplr|flipud|floor|flow|fminbnd|fminsearch|fopen|format|fplot|fprintf|frame2im|fread|freqspace|frewind|fscanf|fseek|ftell|FTP|full|fullfile|func2str|functions|funm|fwrite|fzero|gallery|gamma|gammainc|gammaincinv|gammaln|gca|gcbf|gcbo|gcd|gcf|gco|ge|genpath|genvarname|get|getappdata|getenv|getfield|getframe|getpixelposition|getpref|ginput|gmres|gplot|grabcode|gradient|gray|graymon|grid|griddata(?:3|n)?|griddedInterpolant|gsvd|gt|gtext|guidata|guide|guihandles|gunzip|gzip|h5create|h5disp|h5info|h5read|h5readatt|h5write|h5writeatt|hadamard|handle|hankel|hdf|hdf5|hdf5info|hdf5read|hdf5write|hdfinfo|hdfread|hdftool|help|helpbrowser|helpdesk|helpdlg|helpwin|hess|hex2dec|hex2num|hgexport|hggroup|hgload|hgsave|hgsetget|hgtransform|hidden|hilb|hist|histc|hold|home|horzcat|hostid|hot|hsv|hsv2rgb|hypot|ichol|idivide|ifft|ifft2|ifftn|ifftshift|ilu|im2frame|im2java|imag|image|imagesc|imapprox|imfinfo|imformats|import|importdata|imread|imwrite|ind2rgb|ind2sub|inferiorto|info|inline|inmem|inpolygon|input|inputdlg|inputname|inputParser|inspect|instrcallback|instrfind|instrfindall|int2str|integral(?:2|3)?|interp(?:1|1q|2|3|ft|n)|interpstreamspeed|intersect|intmax|intmin|inv|invhilb|ipermute|isa|isappdata|iscell|iscellstr|ischar|iscolumn|isdir|isempty|isequal|isequaln|isequalwithequalnans|isfield|isfinite|isfloat|isglobal|ishandle|ishghandle|ishold|isinf|isinteger|isjava|iskeyword|isletter|islogical|ismac|ismatrix|ismember|ismethod|isnan|isnumeric|isobject|isocaps|isocolors|isonormals|isosurface|ispc|ispref|isprime|isprop|isreal|isrow|isscalar|issorted|isspace|issparse|isstr|isstrprop|isstruct|isstudent|isunix|isvarname|isvector|javaaddpath|javaArray|javachk|javaclasspath|javacomponent|javaMethod|javaMethodEDT|javaObject|javaObjectEDT|javarmpath|jet|keyboard|kron|lasterr|lasterror|lastwarn|lcm|ldivide|ldl|le|legend|legendre|length|libfunctions|libfunctionsview|libisloaded|libpointer|libstruct|license|light|lightangle|lighting|lin2mu|line|lines|linkaxes|linkdata|linkprop|linsolve|linspace|listdlg|listfonts|load|loadlibrary|loadobj|log|log10|log1p|log2|loglog|logm|logspace|lookfor|lower|ls|lscov|lsqnonneg|lsqr|lt|lu|luinc|magic|makehgtform|mat2cell|mat2str|material|matfile|matlab\\.io\\.MatFile|matlab\\.mixin\\.(?:Copyable|Heterogeneous(?:\\.getDefaultScalarElement)?)|matlabrc|matlabroot|max|maxNumCompThreads|mean|median|membrane|memmapfile|memory|menu|mesh|meshc|meshgrid|meshz|meta\\.(?:class(?:\\.fromName)?|DynamicProperty|EnumeratedValue|event|MetaData|method|package(?:\\.(?:fromName|getAllPackages))?|property)|metaclass|methods|methodsview|mex(?:\\.getCompilerConfigurations)?|MException|mexext|mfilename|min|minres|minus|mislocked|mkdir|mkpp|mldivide|mlint|mlintrpt|mlock|mmfileinfo|mmreader|mod|mode|more|move|movefile|movegui|movie|movie2avi|mpower|mrdivide|msgbox|mtimes|mu2lin|multibandread|multibandwrite|munlock|namelengthmax|nargchk|narginchk|nargoutchk|native2unicode|nccreate|ncdisp|nchoosek|ncinfo|ncread|ncreadatt|ncwrite|ncwriteatt|ncwriteschema|ndgrid|ndims|ne|NET(?:\\.(?:addAssembly|Assembly|convertArray|createArray|createGeneric|disableAutoRelease|enableAutoRelease|GenericClass|invokeGenericMethod|NetException|setStaticProperty))?|netcdf\\.(?:abort|close|copyAtt|create|defDim|defGrp|defVar|defVarChunking|defVarDeflate|defVarFill|defVarFletcher32|delAtt|endDef|getAtt|getChunkCache|getConstant|getConstantNames|getVar|inq|inqAtt|inqAttID|inqAttName|inqDim|inqDimID|inqDimIDs|inqFormat|inqGrpName|inqGrpNameFull|inqGrpParent|inqGrps|inqLibVers|inqNcid|inqUnlimDims|inqVar|inqVarChunking|inqVarDeflate|inqVarFill|inqVarFletcher32|inqVarID|inqVarIDs|open|putAtt|putVar|reDef|renameAtt|renameDim|renameVar|setChunkCache|setDefaultFormat|setFill|sync)|newplot|nextpow2|nnz|noanimate|nonzeros|norm|normest|not|notebook|now|nthroot|null|num2cell|num2hex|num2str|numel|nzmax|ode(?:113|15i|15s|23|23s|23t|23tb|45)|odeget|odeset|odextend|onCleanup|ones|open|openfig|opengl|openvar|optimget|optimset|or|ordeig|orderfields|ordqz|ordschur|orient|orth|pack|padecoef|pagesetupdlg|pan|pareto|parseSoapResponse|pascal|patch|path|path2rc|pathsep|pathtool|pause|pbaspect|pcg|pchip|pcode|pcolor|pdepe|pdeval|peaks|perl|perms|permute|pie|pink|pinv|planerot|playshow|plot|plot3|plotbrowser|plotedit|plotmatrix|plottools|plotyy|plus|pol2cart|polar|poly|polyarea|polyder|polyeig|polyfit|polyint|polyval|polyvalm|pow2|power|ppval|prefdir|preferences|primes|print|printdlg|printopt|printpreview|prod|profile|profsave|propedit|propertyeditor|psi|publish|PutCharArray|PutFullMatrix|PutWorkspaceData|pwd|qhull|qmr|qr|qrdelete|qrinsert|qrupdate|quad|quad2d|quadgk|quadl|quadv|questdlg|quit|quiver|quiver3|qz|rand|randi|randn|randperm|RandStream(?:\\.(?:create|getDefaultStream|getGlobalStream|list|setDefaultStream|setGlobalStream))?|rank|rat|rats|rbbox|rcond|rdivide|readasync|real|reallog|realmax|realmin|realpow|realsqrt|record|rectangle|rectint|recycle|reducepatch|reducevolume|refresh|refreshdata|regexp|regexpi|regexprep|regexptranslate|rehash|rem|Remove|RemoveAll|repmat|reset|reshape|residue|restoredefaultpath|rethrow|rgb2hsv|rgb2ind|rgbplot|ribbon|rmappdata|rmdir|rmfield|rmpath|rmpref|rng|roots|rose|rosser|rot90|rotate|rotate3d|round|rref|rsf2csf|run|save|saveas|saveobj|savepath|scatter|scatter3|schur|sec|secd|sech|selectmoveresize|semilogx|semilogy|sendmail|serial|set|setappdata|setdiff|setenv|setfield|setpixelposition|setpref|setstr|setxor|shading|shg|shiftdim|showplottool|shrinkfaces|sign|sin(?:d|h)?|size|slice|smooth3|snapnow|sort|sortrows|sound|soundsc|spalloc|spaugment|spconvert|spdiags|specular|speye|spfun|sph2cart|sphere|spinmap|spline|spones|spparms|sprand|sprandn|sprandsym|sprank|spring|sprintf|spy|sqrt|sqrtm|squeeze|ss2tf|sscanf|stairs|startup|std|stem|stem3|stopasync|str2double|str2func|str2mat|str2num|strcat|strcmp|strcmpi|stream2|stream3|streamline|streamparticles|streamribbon|streamslice|streamtube|strfind|strjust|strmatch|strncmp|strncmpi|strread|strrep|strtok|strtrim|struct2cell|structfun|strvcat|sub2ind|subplot|subsasgn|subsindex|subspace|subsref|substruct|subvolume|sum|summer|superclasses|superiorto|support|surf|surf2patch|surface|surfc|surfl|surfnorm|svd|svds|swapbytes|symamd|symbfact|symmlq|symrcm|symvar|system|tan(?:d|h)?|tar|tempdir|tempname|tetramesh|texlabel|text|textread|textscan|textwrap|tfqmr|throw|tic|Tiff(?:\\.(?:getTagNames|getVersion))?|timer|timerfind|timerfindall|times|timeseries|title|toc|todatenum|toeplitz|toolboxdir|trace|transpose|trapz|treelayout|treeplot|tril|trimesh|triplequad|triplot|TriRep|TriScatteredInterp|trisurf|triu|tscollection|tsearch|tsearchn|tstool|type|typecast|uibuttongroup|uicontextmenu|uicontrol|uigetdir|uigetfile|uigetpref|uiimport|uimenu|uiopen|uipanel|uipushtool|uiputfile|uiresume|uisave|uisetcolor|uisetfont|uisetpref|uistack|uitable|uitoggletool|uitoolbar|uiwait|uminus|undocheckout|unicode2native|union|unique|unix|unloadlibrary|unmesh|unmkpp|untar|unwrap|unzip|uplus|upper|urlread|urlwrite|usejava|userpath|validateattributes|validatestring|vander|var|vectorize|ver|verctrl|verLessThan|version|vertcat|VideoReader(?:\\.isPlatformSupported)?|VideoWriter(?:\\.getProfiles)?|view|viewmtx|visdiff|volumebounds|voronoi|voronoin|wait|waitbar|waitfor|waitforbuttonpress|warndlg|warning|waterfall|wavfinfo|wavplay|wavread|wavrecord|wavwrite|web|weekday|what|whatsnew|which|whitebg|who|whos|wilkinson|winopen|winqueryreg|winter|wk1finfo|wk1read|wk1write|workspace|xlabel|xlim|xlsfinfo|xlsread|xlswrite|xmlread|xmlwrite|xor|xslt|ylabel|ylim|zeros|zip|zlabel|zlim|zoom";
+            String statsFunctions = "addedvarplot|andrewsplot|anova(?:1|2|n)|ansaribradley|aoctool|barttest|bbdesign|beta(?:cdf|fit|inv|like|pdf|rnd|stat)|bino(?:cdf|fit|inv|pdf|rnd|stat)|biplot|bootci|bootstrp|boxplot|candexch|candgen|canoncorr|capability|capaplot|caseread|casewrite|categorical|ccdesign|cdfplot|chi2(?:cdf|gof|inv|pdf|rnd|stat)|cholcov|Classification(?:BaggedEnsemble|Discriminant(?:\\.(?:fit|make|template))?|Ensemble|KNN(?:\\.(?:fit|template))?|PartitionedEnsemble|PartitionedModel|Tree(?:\\.(?:fit|template))?)|classify|classregtree|cluster|clusterdata|cmdscale|combnk|Compact(?:Classification(?:Discriminant|Ensemble|Tree)|Regression(?:Ensemble|Tree)|TreeBagger)|confusionmat|controlchart|controlrules|cophenet|copula(?:cdf|fit|param|pdf|rnd|stat)|cordexch|corr|corrcov|coxphfit|createns|crosstab|crossval|cvpartition|datasample|dataset|daugment|dcovary|dendrogram|dfittool|disttool|dummyvar|dwtest|ecdf|ecdfhist|ev(?:cdf|fit|inv|like|pdf|rnd|stat)|ExhaustiveSearcher|exp(?:cdf|fit|inv|like|pdf|rnd|stat)|factoran|fcdf|ff2n|finv|fitdist|fitensemble|fpdf|fracfact|fracfactgen|friedman|frnd|fstat|fsurfht|fullfact|gagerr|gam(?:cdf|fit|inv|like|pdf|rnd|stat)|GeneralizedLinearModel(?:\\.fit)?|geo(?:cdf|inv|mean|pdf|rnd|stat)|gev(?:cdf|fit|inv|like|pdf|rnd|stat)|gline|glmfit|glmval|glyphplot|gmdistribution(?:\\.fit)?|gname|gp(?:cdf|fit|inv|like|pdf|rnd|stat)|gplotmatrix|grp2idx|grpstats|gscatter|haltonset|harmmean|hist3|histfit|hmm(?:decode|estimate|generate|train|viterbi)|hougen|hyge(?:cdf|inv|pdf|rnd|stat)|icdf|inconsistent|interactionplot|invpred|iqr|iwishrnd|jackknife|jbtest|johnsrnd|KDTreeSearcher|kmeans|knnsearch|kruskalwallis|ksdensity|kstest|kstest2|kurtosis|lasso|lassoglm|lassoPlot|leverage|lhsdesign|lhsnorm|lillietest|LinearModel(?:\\.fit)?|linhyptest|linkage|logn(?:cdf|fit|inv|like|pdf|rnd|stat)|lsline|mad|mahal|maineffectsplot|manova1|manovacluster|mdscale|mhsample|mle|mlecov|mnpdf|mnrfit|mnrnd|mnrval|moment|multcompare|multivarichart|mvn(?:cdf|pdf|rnd)|mvregress|mvregresslike|mvt(?:cdf|pdf|rnd)|NaiveBayes(?:\\.fit)?|nan(?:cov|max|mean|median|min|std|sum|var)|nbin(?:cdf|fit|inv|pdf|rnd|stat)|ncf(?:cdf|inv|pdf|rnd|stat)|nct(?:cdf|inv|pdf|rnd|stat)|ncx2(?:cdf|inv|pdf|rnd|stat)|NeighborSearcher|nlinfit|nlintool|nlmefit|nlmefitsa|nlparci|nlpredci|nnmf|nominal|NonLinearModel(?:\\.fit)?|norm(?:cdf|fit|inv|like|pdf|rnd|stat)|normplot|normspec|ordinal|outlierMeasure|parallelcoords|paretotails|partialcorr|pcacov|pcares|pdf|pdist|pdist2|pearsrnd|perfcurve|perms|piecewisedistribution|plsregress|poiss(?:cdf|fit|inv|pdf|rnd|tat)|polyconf|polytool|prctile|princomp|ProbDist(?:Kernel|Parametric|UnivKernel|UnivParam)?|probplot|procrustes|qqplot|qrandset|qrandstream|quantile|randg|random|randsample|randtool|range|rangesearch|ranksum|rayl(?:cdf|fit|inv|pdf|rnd|stat)|rcoplot|refcurve|refline|regress|Regression(?:BaggedEnsemble|Ensemble|PartitionedEnsemble|PartitionedModel|Tree(?:\\.(?:fit|template))?)|regstats|relieff|ridge|robustdemo|robustfit|rotatefactors|rowexch|rsmdemo|rstool|runstest|sampsizepwr|scatterhist|sequentialfs|signrank|signtest|silhouette|skewness|slicesample|sobolset|squareform|statget|statset|stepwise|stepwisefit|surfht|tabulate|tblread|tblwrite|tcdf|tdfread|tiedrank|tinv|tpdf|TreeBagger|treedisp|treefit|treeprune|treetest|treeval|trimmean|trnd|tstat|ttest|ttest2|unid(?:cdf|inv|pdf|rnd|stat)|unif(?:cdf|inv|it|pdf|rnd|stat)|vartest(?:2|n)?|wbl(?:cdf|fit|inv|like|pdf|rnd|stat)|wblplot|wishrnd|x2fx|xptread|zscore|ztest";
+            String imageFunctions = "adapthisteq|analyze75info|analyze75read|applycform|applylut|axes2pix|bestblk|blockproc|bwarea|bwareaopen|bwboundaries|bwconncomp|bwconvhull|bwdist|bwdistgeodesic|bweuler|bwhitmiss|bwlabel|bwlabeln|bwmorph|bwpack|bwperim|bwselect|bwtraceboundary|bwulterode|bwunpack|checkerboard|col2im|colfilt|conndef|convmtx2|corner|cornermetric|corr2|cp2tform|cpcorr|cpselect|cpstruct2pairs|dct2|dctmtx|deconvblind|deconvlucy|deconvreg|deconvwnr|decorrstretch|demosaic|dicom(?:anon|dict|info|lookup|read|uid|write)|edge|edgetaper|entropy|entropyfilt|fan2para|fanbeam|findbounds|fliptform|freqz2|fsamp2|fspecial|ftrans2|fwind1|fwind2|getheight|getimage|getimagemodel|getline|getneighbors|getnhood|getpts|getrangefromclass|getrect|getsequence|gray2ind|graycomatrix|graycoprops|graydist|grayslice|graythresh|hdrread|hdrwrite|histeq|hough|houghlines|houghpeaks|iccfind|iccread|iccroot|iccwrite|idct2|ifanbeam|im2bw|im2col|im2double|im2int16|im2java2d|im2single|im2uint16|im2uint8|imabsdiff|imadd|imadjust|ImageAdapter|imageinfo|imagemodel|imapplymatrix|imattributes|imbothat|imclearborder|imclose|imcolormaptool|imcomplement|imcontour|imcontrast|imcrop|imdilate|imdisplayrange|imdistline|imdivide|imellipse|imerode|imextendedmax|imextendedmin|imfill|imfilter|imfindcircles|imfreehand|imfuse|imgca|imgcf|imgetfile|imhandles|imhist|imhmax|imhmin|imimposemin|imlincomb|imline|immagbox|immovie|immultiply|imnoise|imopen|imoverview|imoverviewpanel|impixel|impixelinfo|impixelinfoval|impixelregion|impixelregionpanel|implay|impoint|impoly|impositionrect|improfile|imputfile|impyramid|imreconstruct|imrect|imregconfig|imregionalmax|imregionalmin|imregister|imresize|imroi|imrotate|imsave|imscrollpanel|imshow|imshowpair|imsubtract|imtool|imtophat|imtransform|imview|ind2gray|ind2rgb|interfileinfo|interfileread|intlut|ippl|iptaddcallback|iptcheckconn|iptcheckhandle|iptcheckinput|iptcheckmap|iptchecknargin|iptcheckstrs|iptdemos|iptgetapi|iptGetPointerBehavior|iptgetpref|ipticondir|iptnum2ordinal|iptPointerManager|iptprefs|iptremovecallback|iptSetPointerBehavior|iptsetpref|iptwindowalign|iradon|isbw|isflat|isgray|isicc|isind|isnitf|isrgb|isrset|lab2double|lab2uint16|lab2uint8|label2rgb|labelmatrix|makecform|makeConstrainToRectFcn|makehdr|makelut|makeresampler|maketform|mat2gray|mean2|medfilt2|montage|nitfinfo|nitfread|nlfilter|normxcorr2|ntsc2rgb|openrset|ordfilt2|otf2psf|padarray|para2fan|phantom|poly2mask|psf2otf|qtdecomp|qtgetblk|qtsetblk|radon|rangefilt|reflect|regionprops|registration\\.metric\\.(?:MattesMutualInformation|MeanSquares)|registration\\.optimizer\\.(?:OnePlusOneEvolutionary|RegularStepGradientDescent)|rgb2gray|rgb2ntsc|rgb2ycbcr|roicolor|roifill|roifilt2|roipoly|rsetwrite|std2|stdfilt|strel|stretchlim|subimage|tformarray|tformfwd|tforminv|tonemap|translate|truesize|uintlut|viscircles|warp|watershed|whitepoint|wiener2|xyz2double|xyz2uint16|ycbcr2rgb";
+            String optimFunctions = "bintprog|color|fgoalattain|fminbnd|fmincon|fminimax|fminsearch|fminunc|fseminf|fsolve|fzero|fzmult|gangstr|ktrlink|linprog|lsqcurvefit|lsqlin|lsqnonlin|lsqnonneg|optimget|optimset|optimtool|quadprog";
+
+            // list of keywords (`iskeyword`)
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_KEYWORD, Pattern.compile("^\\b(?:break|case|catch|classdef|continue|else|elseif|end|for|function|global|if|otherwise|parfor|persistent|return|spmd|switch|try|while)\\b"), null}));
+            // some specials variables/constants
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_CONSTANT, Pattern.compile("^\\b(?:true|false|inf|Inf|nan|NaN|eps|pi|ans|nargin|nargout|varargin|varargout)\\b"), null}));
+            // some data types
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_TYPE, Pattern.compile("^\\b(?:cell|struct|char|double|single|logical|u?int(?:8|16|32|64)|sparse)\\b"), null}));
+            // commonly used builtin functions from core MATLAB and a few popular toolboxes
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_FUNCTION, Pattern.compile("^\\b(?:" + coreFunctions + ")\\b"), null}));
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_FUNCTION_TOOLBOX, Pattern.compile("^\\b(?:" + statsFunctions + ")\\b"), null}));
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_FUNCTION_TOOLBOX, Pattern.compile("^\\b(?:" + imageFunctions + ")\\b"), null}));
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_FUNCTION_TOOLBOX, Pattern.compile("^\\b(?:" + optimFunctions + ")\\b"), null}));
+            // plain identifier (user-defined variable/function name)
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_IDENTIFIER, Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]*(?:\\.[a-zA-Z][a-zA-Z0-9_]*)*"), null}));
+
+            setShortcutStylePatterns(_shortcutStylePatterns);
+            setFallthroughStylePatterns(_fallthroughStylePatterns);
+        }
+
+        public static List<String> getFileExtensions() {
+            return Arrays.asList(new String[]{"matlab-identifiers"});
+        }
+    }
+
+    protected static class LangMatlabOperator extends Lang {
+
+        public LangMatlabOperator() {
+            List<List<Object>> _shortcutStylePatterns = new ArrayList<List<Object>>();
+            List<List<Object>> _fallthroughStylePatterns = new ArrayList<List<Object>>();
+
+            // forward to identifiers to match
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{"lang-matlab-identifiers", Pattern.compile("^([a-zA-Z][a-zA-Z0-9_]*(?:\\.[a-zA-Z][a-zA-Z0-9_]*)*)"), null}));
+            // parentheses, braces, brackets
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_TAG, Pattern.compile("^(?:\\{|\\}|\\(|\\)|\\[|\\])"), null}));       // "{}()[]"
+            // other operators
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{Prettify.PR_PUNCTUATION, Pattern.compile("^(?:<|>|=|~|@|&|;|,|:|!|\\-|\\+|\\*|\\^|\\.|\\||\\\\|\\/)"), null}));
+            // transpose operators
+            _fallthroughStylePatterns.add(Arrays.asList(new Object[]{PR_TRANSPOSE, Pattern.compile("^'"), null}));
+
+            setShortcutStylePatterns(_shortcutStylePatterns);
+            setFallthroughStylePatterns(_fallthroughStylePatterns);
+        }
+
+        public static List<String> getFileExtensions() {
+            return Arrays.asList(new String[]{"matlab-operators"});
+        }
+    }
+}
diff --git a/src/prettify/parser/Prettify.java b/src/prettify/parser/Prettify.java
index df70e79..e079db5 100644
--- a/src/prettify/parser/Prettify.java
+++ b/src/prettify/parser/Prettify.java
@@ -34,6 +34,7 @@
 import prettify.lang.LangLisp;
 import prettify.lang.LangLlvm;
 import prettify.lang.LangLua;
+import prettify.lang.LangMatlab;
 import prettify.lang.LangMl;
 import prettify.lang.LangMumps;
 import prettify.lang.LangN;
@@ -375,6 +376,7 @@
       register(LangLisp.class);
       register(LangLlvm.class);
       register(LangLua.class);
+      register(LangMatlab.class);
       register(LangMl.class);
       register(LangMumps.class);
       register(LangN.class);
diff --git a/test/prettify/PrettifyTest.java b/test/prettify/PrettifyTest.java
index 907de3b..6ada004 100644
--- a/test/prettify/PrettifyTest.java
+++ b/test/prettify/PrettifyTest.java
@@ -87,13 +87,13 @@
    * @throws IOException error occurred when reading source or result file
    */
   public void test(String extension, String code, boolean removeJSLineNumbering) throws IOException {
-    String source = new String(readFile(new File(packagePath + "source/" + code + ".txt")), "UTF-8");
+    String source = unescapeHtmlSpecialChars(new String(readFile(new File(packagePath + "source/" + code + ".txt")), "UTF-8"));
     Job job = new Job(0, source);
     prettify.langHandlerForExtension(extension, source).decorate(job);
     List<Object> decorations = removeJSLineNumbering ? removeNewLines(job.getDecorations(), source) : job.getDecorations();
     final byte[] bytes = readFile(new File(packagePath + "result/" + code + ".txt"));
     final StringBuilder plainResult = new StringBuilder();
-    List<Object> compare = readResult(new String(bytes, "UTF-8").replace("&lt;", "<").replace("&gt;", ">").replace("&nbsp;", " ").replace("&amp;", "&"), removeJSLineNumbering, plainResult);
+    List<Object> compare = readResult(unescapeHtmlSpecialChars(new String(bytes, "UTF-8")), removeJSLineNumbering, plainResult);
 
     if (!removeJSLineNumbering) {
       assertEquals(source, plainResult.toString());
@@ -174,6 +174,7 @@
     test("pascal", "pascal_lang", false);
     test("basic", "basic_lang", false);
     test("js", "issue217", false);
+    test("matlab", "matlab", false);
   }
 
   /**
@@ -284,6 +285,7 @@
     if (removeJSLineNumbering) {
       _resultText = _resultText.replaceAll("[\r\n]", "");
 
+      // combine 'adjacent with identical decoration keyword' segments
       StringBuffer sb = new StringBuffer();
       Pattern pattern = Pattern.compile("(`[A-Z]{3})([^`]+?)`END\\1([^`]+?)`END", Pattern.MULTILINE | Pattern.DOTALL);
       Matcher matcher = pattern.matcher(_resultText);
@@ -296,24 +298,42 @@
       _resultText = sb.toString();
     }
 
+    // digest result(string) into segments by identifing standard 'decoration keyword' start & end
     int count = 0;
-    Pattern pattern = Pattern.compile("`([A-Z]{3})(.+?)`END", Pattern.MULTILINE | Pattern.DOTALL);
-    Matcher matcher = pattern.matcher(_resultText);
+    Pattern decorationPattern = Pattern.compile("`([A-Z]{3})(.+?)`END|<span class=\"([a-z]+)\">(.+?)`END", Pattern.MULTILINE | Pattern.DOTALL);
+    Matcher matcher = decorationPattern.matcher(_resultText);
     while (matcher.find()) {
       returnList.add(count);
-      returnList.add(matcher.group(1).toLowerCase());
-      count += matcher.group(2).length();
-      plainResult.append(matcher.group(2));
+
+      String decorationKeyword = null;
+      String decoratedContent = null;
+
+      if (matcher.group(1) != null) {
+        decorationKeyword = matcher.group(1);
+        decoratedContent = matcher.group(2);
+      } else {
+        decorationKeyword = matcher.group(3);
+        decoratedContent = matcher.group(4);
+      }
+
+      returnList.add(decorationKeyword.toLowerCase());
+      count += decoratedContent.length();
+      plainResult.append(decoratedContent);
     }
 
     returnList = Util.removeDuplicates(returnList, _resultText);
 
     // for debug
 //        StringBuffer sb = new StringBuffer();
-//        matcher = pattern.matcher(resultText);
+//        matcher = decorationPattern.matcher(resultText);
 //        while (matcher.find()) {
-//            matcher.appendReplacement(sb, "");
-//            sb.append(matcher.group(2));
+//            if (matcher.group(1) != null) {
+//                matcher.appendReplacement(sb, "");
+//                sb.append(matcher.group(2));
+//            } else {
+//                matcher.appendReplacement(sb, "");
+//                sb.append(matcher.group(4));
+//            }
 //        }
 //        matcher.appendTail(sb);
 //        String plainCode = sb.toString();
@@ -328,6 +348,10 @@
     return returnList;
   }
 
+  protected static String unescapeHtmlSpecialChars(String inputString) {
+      return inputString.replace("&lt;", "<").replace("&gt;", ">").replace("&nbsp;", " ").replace("&amp;", "&");
+  }
+
 	private static String prettify(String source, List<Object> decorations) {
 		if (decorations.size() % 2 != 0) {
 			throw new IllegalArgumentException();
diff --git a/test/prettify/PrettifyTest/result/matlab.txt b/test/prettify/PrettifyTest/result/matlab.txt
new file mode 100644
index 0000000..c83b641
--- /dev/null
+++ b/test/prettify/PrettifyTest/result/matlab.txt
@@ -0,0 +1,221 @@
+`COM%%%%%%%%%%%%%%%%%% DATA TYPES %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END<span class="ident">v`END`PLN `END`PUN=`END`PLN `END`TAG[`END`LIT1`END`PUN,`END`LIT2`END`PUN,`END`LIT3`END`PUN;`END`LIT4`END`PUN,`END`LIT5`END`PUN,`END`LIT6`END`TAG]`END`PUN;`END`PLN

+`END<span class="ident">v`END`TAG(`END<span class="ident">v`END`PUN&gt;`END`LIT4`END`TAG)`END`PLN `END`PUN=`END`PLN `END`LIT0`END`PUN;`END`PLN

+

+`END<span class="ident">s`END`PLN `END`PUN=`END`PLN `END`TYPstruct`END`TAG(`END`STR'key'`END`PUN,`END`LIT1`END`PUN,`END`PLN `END`STR'key2'`END`PUN,`END`STR'string'`END`TAG)`END`PUN;`END`PLN

+`END<span class="ident">s.key`END`PLN `END`PUN=`END`PLN `END`LIT2`END`PUN;`END`PLN

+

+`END<span class="ident">C`END`PLN `END`PUN=`END`PLN `END`TYPcell`END`TAG(`END`LIT1`END`PUN,`END`LIT2`END`TAG)`END`PUN;`END`PLN

+`END<span class="ident">C`END`TAG{`END`LIT1`END`PUN,`END`LIT1`END`TAG}`END`PLN `END`PUN=`END`PLN `END`LIT0`END`PUN:`END`LIT9`END`PUN;`END`PLN

+

+`END`TYPdouble`END`TAG(`END`LIT1`END`TAG)`END`PLN

+`END`TYPsingle`END`TAG(`END`LIT1`END`TAG)`END`PLN

+`END`TYPuint8`END`TAG(`END`LIT1`END`TAG)`END`PLN

+`END`TYPint8`END`TAG(`END`LIT1`END`TAG)`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% STRINGS &amp; TRANSPOSE %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END`FUNplot`END`TAG(`END<span class="ident">data`END<span class="transpose">'`END`TAG)`END`PUN;`END`PLN

+`END`FUNlegend`END`TAG(`END<span class="ident">labels`END`TAG)`END`PLN

+

+`END<span class="ident">str`END`PLN `END`PUN=`END`PLN `END`STR'asdasd'`END`PUN;`END`PLN     `END`COM% this is a string`END`PLN

+`END<span class="ident">str`END`PLN `END`PUN=`END`PLN `END`STR'asdas'`END`PUN;`END`PLN

+`END<span class="ident">str`END`PLN `END`PUN=`END`PLN `END`STR'sdasd''sdasd'`END`PUN;`END`PLN

+

+`END<span class="ident">str`END`PLN `END`PUN=`END`PLN `END`TAG[`END`STR'one'`END`PLN `END`STR'two'`END`PLN `END`STR'three'`END`TAG]`END`PUN;`END`PLN

+`END<span class="ident">str`END`PLN `END`PUN=`END`PLN `END`FUNstrcat`END`TAG(`END`STR'one'`END`PUN,`END`PLN `END`STR'two'`END`PUN,`END`PLN `END`STR'three'`END`TAG)`END`PUN;`END`PLN

+

+`END`COM% matrix transpose`END`PLN

+`END<span class="ident">M`END`PLN `END`PUN=`END`PLN `END`FUNrand`END`TAG(`END`LIT3`END`PUN,`END`LIT3`END`TAG)`END<span class="transpose">'`END`PUN;`END`PLN

+`END<span class="ident">x`END`PLN `END`PUN=`END`PLN `END<span class="ident">M`END`PUN.`END<span class="transpose">'`END`PUN;`END`PLN

+`END<span class="ident">x`END`PLN `END`PUN=`END`PLN `END`TAG[`END`LIT10`END`PLN `END`LIT20`END`PUN;`END`PLN `END`LIT30`END`PUN,`END`PLN `END`LIT40`END`TAG]`END<span class="transpose">'`END`PUN;`END`PLN

+`END`FUNdisp`END`TAG(`END<span class="ident">x`END<span class="transpose">'`END`TAG)`END`PLN

+`END`FUNfprintf`END`TAG(`END`STR'%d\n'`END`PUN,`END`PLN `END<span class="ident">x`END`TAG(`END`PUN:`END`TAG)`END<span class="transpose">'`END`TAG)`END`PLN      `END`COM% with comment`END`PLN

+`END`TAG{`END`LIT1`END`PUN,`END`LIT2`END`TAG}`END<span class="transpose">'`END`PLN                      `END`COM% another comment`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% LINE CONTINUATION %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END`TAG[`END`LIT1`END`PLN `END`LIT20`END`PUN;`END`PLN `END<span class="linecont">...

+`END`LIT30`END`PLN `END`LIT4`END`TAG]`END`PLN

+

+`END`TAG[`END`STR'gdgsd'`END<span class="linecont">...

+`END`STR'sdfs'`END`TAG]`END`PLN

+

+`END`TAG{`END<span class="linecont">...

+`END`STR'sdasd'`END`PLN `END`PUN;`END`PLN

+`END`STR'asdsad'`END`TAG}`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% SYSTEM COMMANDS %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END<span class="syscmd">!touch file.txt`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% COMMAND OUTPUT %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END<span class="codeoutput">&gt;&gt; `END`LIT1+1`END`PLN

+`END<span class="const">ans`END`PLN `END`PUN=`END`PLN

+     `END`LIT2`END`PLN

+

+`END<span class="codeoutput">&gt;&gt; `END`LIT1+1`END`PLN

+

+`END<span class="const">ans`END`PLN `END`PUN=`END`PLN

+

+     `END`LIT2`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% KEYWORDS %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END`KWDfunction`END`PLN `END<span class="ident">ret`END`PLN `END`PUN=`END`PLN `END<span class="ident">fcn`END`TAG(`END<span class="ident">in`END`TAG)`END`PLN

+        `END<span class="ident">ret`END`PLN `END`PUN=`END`PLN `END`FUNsum`END`TAG(`END<span class="ident">in`END`PUN.^`END`LIT2`END`TAG)`END`PUN;`END`PLN

+`END`KWDend`END`PLN

+

+`END`KWDclassdef`END`PLN `END<span class="ident">CC`END`PLN `END`PUN&lt;`END`PLN `END`FUNhandle`END`PLN

+        `END<span class="ident">properties`END`PLN `END`TAG(`END<span class="ident">SetAccess`END`PLN `END`PUN=`END`PLN `END<span class="ident">public`END`TAG)`END`PLN

+                `END<span class="ident">x`END`PLN `END`PUN=`END`PLN `END`LIT0`END`PUN;`END`PLN

+        `END`KWDend`END`PLN

+        `END`FUNmethods`END`PLN

+                `END`KWDfunction`END`PLN `END<span class="ident">this`END`PLN `END`PUN=`END`PLN `END<span class="ident">CC`END`TAG(`END<span class="const">varargin`END`TAG)`END`PLN

+                        `END<span class="ident">this.x`END`PLN `END`PUN=`END`PLN `END`LIT9`END`PUN;`END`PLN

+                `END`KWDend`END`PLN

+        `END`KWDend`END`PLN

+`END`KWDend`END`PLN

+

+`END<span class="ident">x`END`PLN `END`PUN=`END`PLN `END`TAG[]`END`PUN;`END`PLN

+`END`KWDparfor`END`PLN `END<span class="ident">i`END`PUN=`END`LIT1`END`PUN:`END`LIT10`END`PLN

+        `END<span class="ident">x`END`TAG[`END<span class="ident">i`END`TAG]`END`PLN `END`PUN=`END`PLN `END<span class="ident">i`END`PUN;`END`PLN

+`END`KWDend`END`PLN

+

+`END<span class="const">true`END`PLN `END`PUN~=`END`PLN `END<span class="const">false`END`PLN

+

+`END`KWDif`END`PLN `END<span class="ident">x`END`PUN==`END`LIT1`END`PLN

+        `END<span class="const">true`END`PLN

+`END`KWDelseif`END`PLN

+        `END<span class="const">false`END`PLN

+`END`KWDelse`END`PLN

+        `END`KWDreturn`END`PLN

+`END`KWDend`END`PLN

+

+`END`KWDwhile`END`PLN `END<span class="const">true`END`PLN

+        `END`KWDcontinue`END`PLN

+        `END`KWDbreak`END`PLN

+`END`KWDend`END`PLN

+

+`END`KWDtry`END`PLN

+        `END`FUNerror`END`TAG(`END`STR'aa:aa'`END`PUN,`END`PLN `END`STR'asdasd'`END`TAG)`END`PLN

+`END`KWDcatch`END`PLN `END<span class="ident">ME`END`PLN

+        `END`FUNwarning`END`TAG(`END<span class="ident">ME`END`TAG)`END`PLN

+`END`KWDend`END`PLN

+

+`END`KWDswitch`END`PLN `END<span class="ident">x`END`PLN

+        `END`KWDcase`END`PLN `END`LIT1`END`PLN

+                `END`FUNdisp`END`TAG(`END`LIT1`END`TAG)`END`PLN

+        `END`KWDotherwise`END`PLN

+                `END`LIT0`END`PLN

+`END`KWDend`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% NUM LITERALS %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END`LIT1`END`PLN

+`END`LIT1.`END`PLN

+`END`LIT.1`END`PLN

+`END`LIT1.0`END`PLN

+`END`LIT-1`END`PLN

+`END`LIT-1.`END`PLN

+`END`LIT-.1`END`PLN

+`END`LIT-1.0`END`PLN

+`END`LIT+10`END`PLN

+`END`LIT+01.`END`PLN

+`END`LIT+.1`END`PLN

+`END`LIT+1.0`END`PLN

+`END`LIT1e1`END`PLN

+`END`LIT1e-1`END`PLN

+`END`LIT1.e1`END`PLN

+`END`LIT1.e-1`END`PLN

+`END`LIT1.0e1`END`PLN

+`END`LIT1.0e-1`END`PLN

+`END`LIT.1e1`END`PLN

+`END`LIT.1e-1`END`PLN

+`END`LIT-.1e+1`END`PLN

+`END`LIT+1.e-1`END`PLN

+

+`END`LIT1i`END`PLN

+`END`LIT.10j`END`PLN

+`END`LIT-1.001i`END`PLN

+`END`LIT+1e-100j`END`PLN

+`END`LIT-.10e-01i`END`PLN

+

+`END`COM% unary vs binary operators`END`PLN

+`END`LIT1+1`END`PLN

+`END`LIT1`END`PUN+`END`PLN `END`LIT1`END`PLN

+`END`LIT1`END`PLN `END`LIT+1`END`PLN

+`END`LIT1`END`PLN `END`PUN+`END`PLN `END`LIT1`END`PLN

+`END`LIT+1+1`END`PLN

+`END`LIT+1`END`PUN+`END`PLN `END`LIT1`END`PLN

+`END`LIT+1`END`PLN `END`LIT+1`END`PLN

+`END`LIT+1`END`PLN `END`PUN+`END`PLN `END`LIT1`END`PLN

+

+`END`COM%%%%%%%%%%%%%%%%%% COMMENTS %%%%%%%%%%%%%%%%%%`END`PLN

+

+`END`COM% % comment % %`END`PLN

+   `END`COM% comment`END`PLN

+`END`COM% comment`END`PLN

+`END`COM%# comment`END`PLN

+`END`COM%% comment`END`PLN

+`END`COM%#x = sum(x);`END`PLN

+

+`END`COM%{

+block comment

+%}`END`PLN

+

+`END`COM%{

+%}`END`PLN

+

+`END`COM%{

+

+%}`END`PLN

+

+`END`COM%{

+1

+2

+%}`END`PLN

+

+`END`COM%{

+% sdf {}

+sdf

+%asda{}

+sfds

+%}`END`PLN

+

+    `END`COM%{

+dsf

+        %}`END`PLN

+

+`END`COM%{%}`END`PLN

+

+`END`COM%{ zzz=10; %}`END`PLN

+

+`END`COM%{%x=10;%}`END`PLN

+

+`END`COM%{  x

+a=10;

+%}`END`PLN

+

+`END`COM%{

+%a=10;

+%}`END`PLN   `END<span class="ident">x`END`PLN

+

+`END`COM% nested block comments fail`END`PLN

+`END`COM%{

+dfsdf

+%{

+xxx

+%}`END`PLN

+`END<span class="ident">dfsdf`END`PLN

+`END`COM%}`END`PLN

+

+`END`COM% fails here!`END`PLN

+`END`COM%{

+x=10;

+%%{

+%%}`END`PLN

+`END<span class="ident">y`END`PUN=`END`LIT20`END`PUN;`END`PLN

+`END`COM%}`END
\ No newline at end of file
diff --git a/test/prettify/PrettifyTest/source/issue84.txt b/test/prettify/PrettifyTest/source/issue84.txt
index 4994711..6daf3b0 100644
--- a/test/prettify/PrettifyTest/source/issue84.txt
+++ b/test/prettify/PrettifyTest/source/issue84.txt
@@ -1 +1 @@
-super("&nbsp;");
\ No newline at end of file
+super("&amp;nbsp;");
\ No newline at end of file
diff --git a/test/prettify/PrettifyTest/source/matlab.txt b/test/prettify/PrettifyTest/source/matlab.txt
new file mode 100644
index 0000000..deef81e
--- /dev/null
+++ b/test/prettify/PrettifyTest/source/matlab.txt
@@ -0,0 +1,221 @@
+%%%%%%%%%%%%%%%%%% DATA TYPES %%%%%%%%%%%%%%%%%%

+

+v = [1,2,3;4,5,6];

+v(v&gt;4) = 0;

+

+s = struct('key',1, 'key2','string');

+s.key = 2;

+

+C = cell(1,2);

+C{1,1} = 0:9;

+

+double(1)

+single(1)

+uint8(1)

+int8(1)

+

+%%%%%%%%%%%%%%%%%% STRINGS &amp; TRANSPOSE %%%%%%%%%%%%%%%%%%

+

+plot(data');

+legend(labels)

+

+str = 'asdasd';     % this is a string

+str = 'asdas';

+str = 'sdasd''sdasd';

+

+str = ['one' 'two' 'three'];

+str = strcat('one', 'two', 'three');

+

+% matrix transpose

+M = rand(3,3)';

+x = M.';

+x = [10 20; 30, 40]';

+disp(x')

+fprintf('%d\n', x(:)')      % with comment

+{1,2}'                      % another comment

+

+%%%%%%%%%%%%%%%%%% LINE CONTINUATION %%%%%%%%%%%%%%%%%%

+

+[1 20; ...

+30 4]

+

+['gdgsd'...

+'sdfs']

+

+{...

+'sdasd' ;

+'asdsad'}

+

+%%%%%%%%%%%%%%%%%% SYSTEM COMMANDS %%%%%%%%%%%%%%%%%%

+

+!touch file.txt

+

+%%%%%%%%%%%%%%%%%% COMMAND OUTPUT %%%%%%%%%%%%%%%%%%

+

+&gt;&gt; 1+1

+ans =

+     2

+

+&gt;&gt; 1+1

+

+ans =

+

+     2

+

+%%%%%%%%%%%%%%%%%% KEYWORDS %%%%%%%%%%%%%%%%%%

+

+function ret = fcn(in)

+        ret = sum(in.^2);

+end

+

+classdef CC &lt; handle

+        properties (SetAccess = public)

+                x = 0;

+        end

+        methods

+                function this = CC(varargin)

+                        this.x = 9;

+                end

+        end

+end

+

+x = [];

+parfor i=1:10

+        x[i] = i;

+end

+

+true ~= false

+

+if x==1

+        true

+elseif

+        false

+else

+        return

+end

+

+while true

+        continue

+        break

+end

+

+try

+        error('aa:aa', 'asdasd')

+catch ME

+        warning(ME)

+end

+

+switch x

+        case 1

+                disp(1)

+        otherwise

+                0

+end

+

+%%%%%%%%%%%%%%%%%% NUM LITERALS %%%%%%%%%%%%%%%%%%

+

+1

+1.

+.1

+1.0

+-1

+-1.

+-.1

+-1.0

++10

++01.

++.1

++1.0

+1e1

+1e-1

+1.e1

+1.e-1

+1.0e1

+1.0e-1

+.1e1

+.1e-1

+-.1e+1

++1.e-1

+

+1i

+.10j

+-1.001i

++1e-100j

+-.10e-01i

+

+% unary vs binary operators

+1+1

+1+ 1

+1 +1

+1 + 1

++1+1

++1+ 1

++1 +1

++1 + 1

+

+%%%%%%%%%%%%%%%%%% COMMENTS %%%%%%%%%%%%%%%%%%

+

+% % comment % %

+   % comment

+% comment

+%# comment

+%% comment

+%#x = sum(x);

+

+%{

+block comment

+%}

+

+%{

+%}

+

+%{

+

+%}

+

+%{

+1

+2

+%}

+

+%{

+% sdf {}

+sdf

+%asda{}

+sfds

+%}

+

+    %{

+dsf

+        %}

+

+%{%}

+

+%{ zzz=10; %}

+

+%{%x=10;%}

+

+%{  x

+a=10;

+%}

+

+%{

+%a=10;

+%}   x

+

+% nested block comments fail

+%{

+dfsdf

+%{

+xxx

+%}

+dfsdf

+%}

+

+% fails here!

+%{

+x=10;

+%%{

+%%}

+y=20;

+%}
\ No newline at end of file