1 // Scintilla source code edit control
2 /** @file LexMatlab.cxx
4 ** Written by José Fonseca
6 ** Changes by Christoph Dalitz 2003/12/04:
7 ** - added support for Octave
8 ** - Strings can now be included both in single or double quotes
10 ** Changes by John Donoghue 2012/04/02
11 ** - added block comment (and nested block comments)
12 ** - added ... displayed as a comment
13 ** - removed unused IsAWord functions
14 ** - added some comments
16 ** Changes by John Donoghue 2014/08/01
17 ** - fix allowed transpose ' after {} operator
19 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
20 // The License.txt file describes the conditions under which this software may be distributed.
30 #include "Scintilla.h"
34 #include "LexAccessor.h"
36 #include "StyleContext.h"
37 #include "CharacterSet.h"
38 #include "LexerModule.h"
41 using namespace Scintilla
;
44 static bool IsMatlabCommentChar(int c
) {
48 static bool IsOctaveCommentChar(int c
) {
49 return (c
== '%' || c
== '#') ;
52 static bool IsMatlabComment(Accessor
&styler
, int pos
, int len
) {
53 return len
> 0 && IsMatlabCommentChar(styler
[pos
]) ;
56 static bool IsOctaveComment(Accessor
&styler
, int pos
, int len
) {
57 return len
> 0 && IsOctaveCommentChar(styler
[pos
]) ;
60 static void ColouriseMatlabOctaveDoc(
61 unsigned int startPos
, int length
, int initStyle
,
62 WordList
*keywordlists
[], Accessor
&styler
,
63 bool (*IsCommentChar
)(int),
66 WordList
&keywords
= *keywordlists
[0];
68 styler
.StartAt(startPos
);
70 // boolean for when the ' is allowed to be transpose vs the start/end
72 bool transpose
= false;
74 // approximate position of first non space character in a line
75 int nonSpaceColumn
= -1;
76 // approximate column position of the current character in a line
79 // use the line state of each line to store the block comment depth
80 int curLine
= styler
.GetLine(startPos
);
81 int commentDepth
= curLine
> 0 ? styler
.GetLineState(curLine
-1) : 0;
84 StyleContext
sc(startPos
, length
, initStyle
, styler
);
86 for (; sc
.More(); sc
.Forward(), column
++) {
89 // set the line state to the current commentDepth
90 curLine
= styler
.GetLine(sc
.currentPos
);
91 styler
.SetLineState(curLine
, commentDepth
);
93 // reset the column to 0, nonSpace to -1 (not set)
98 // save the column position of first non space character in a line
99 if((nonSpaceColumn
== -1) && (! IsASpace(sc
.ch
)))
101 nonSpaceColumn
= column
;
104 // check for end of states
105 if (sc
.state
== SCE_MATLAB_OPERATOR
) {
106 if (sc
.chPrev
== '.') {
107 if (sc
.ch
== '*' || sc
.ch
== '/' || sc
.ch
== '\\' || sc
.ch
== '^') {
108 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
110 } else if (sc
.ch
== '\'') {
111 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
113 } else if(sc
.ch
== '.' && sc
.chNext
== '.') {
114 // we werent an operator, but a '...'
115 sc
.ChangeState(SCE_MATLAB_COMMENT
);
118 sc
.SetState(SCE_MATLAB_DEFAULT
);
121 sc
.SetState(SCE_MATLAB_DEFAULT
);
123 } else if (sc
.state
== SCE_MATLAB_KEYWORD
) {
124 if (!isalnum(sc
.ch
) && sc
.ch
!= '_') {
126 sc
.GetCurrentLowered(s
, sizeof(s
));
127 if (keywords
.InList(s
)) {
128 sc
.SetState(SCE_MATLAB_DEFAULT
);
131 sc
.ChangeState(SCE_MATLAB_IDENTIFIER
);
132 sc
.SetState(SCE_MATLAB_DEFAULT
);
136 } else if (sc
.state
== SCE_MATLAB_NUMBER
) {
137 if (!isdigit(sc
.ch
) && sc
.ch
!= '.'
138 && !(sc
.ch
== 'e' || sc
.ch
== 'E')
139 && !((sc
.ch
== '+' || sc
.ch
== '-') && (sc
.chPrev
== 'e' || sc
.chPrev
== 'E'))) {
140 sc
.SetState(SCE_MATLAB_DEFAULT
);
143 } else if (sc
.state
== SCE_MATLAB_STRING
) {
145 if (sc
.chNext
== '\'') {
148 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
151 } else if (sc
.state
== SCE_MATLAB_DOUBLEQUOTESTRING
) {
153 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
156 } else if (sc
.ch
== '\"') {
157 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
159 } else if (sc
.state
== SCE_MATLAB_COMMAND
) {
161 sc
.SetState(SCE_MATLAB_DEFAULT
);
164 } else if (sc
.state
== SCE_MATLAB_COMMENT
) {
165 // end or start of a nested a block comment?
166 if( IsCommentChar(sc
.ch
) && sc
.chNext
== '}' && nonSpaceColumn
== column
) {
167 if(commentDepth
> 0) commentDepth
--;
169 curLine
= styler
.GetLine(sc
.currentPos
);
170 styler
.SetLineState(curLine
, commentDepth
);
173 if (commentDepth
== 0) {
174 sc
.ForwardSetState(SCE_D_DEFAULT
);
178 else if( IsCommentChar(sc
.ch
) && sc
.chNext
== '{' && nonSpaceColumn
== column
)
182 curLine
= styler
.GetLine(sc
.currentPos
);
183 styler
.SetLineState(curLine
, commentDepth
);
187 } else if(commentDepth
== 0) {
188 // single line comment
189 if (sc
.atLineEnd
|| sc
.ch
== '\r' || sc
.ch
== '\n') {
190 sc
.SetState(SCE_MATLAB_DEFAULT
);
196 // check start of a new state
197 if (sc
.state
== SCE_MATLAB_DEFAULT
) {
198 if (IsCommentChar(sc
.ch
)) {
199 // ncrement depth if we are a block comment
200 if(sc
.chNext
== '{' && nonSpaceColumn
== column
)
202 curLine
= styler
.GetLine(sc
.currentPos
);
203 styler
.SetLineState(curLine
, commentDepth
);
204 sc
.SetState(SCE_MATLAB_COMMENT
);
205 } else if (sc
.ch
== '!' && sc
.chNext
!= '=' ) {
207 sc
.SetState(SCE_MATLAB_COMMAND
);
209 sc
.SetState(SCE_MATLAB_OPERATOR
);
211 } else if (sc
.ch
== '\'') {
213 sc
.SetState(SCE_MATLAB_OPERATOR
);
215 sc
.SetState(SCE_MATLAB_STRING
);
217 } else if (sc
.ch
== '"') {
218 sc
.SetState(SCE_MATLAB_DOUBLEQUOTESTRING
);
219 } else if (isdigit(sc
.ch
) || (sc
.ch
== '.' && isdigit(sc
.chNext
))) {
220 sc
.SetState(SCE_MATLAB_NUMBER
);
221 } else if (isalpha(sc
.ch
)) {
222 sc
.SetState(SCE_MATLAB_KEYWORD
);
223 } else if (isoperator(static_cast<char>(sc
.ch
)) || sc
.ch
== '@' || sc
.ch
== '\\') {
224 if (sc
.ch
== ')' || sc
.ch
== ']' || sc
.ch
== '}') {
229 sc
.SetState(SCE_MATLAB_OPERATOR
);
238 static void ColouriseMatlabDoc(unsigned int startPos
, int length
, int initStyle
,
239 WordList
*keywordlists
[], Accessor
&styler
) {
240 ColouriseMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsMatlabCommentChar
, true);
243 static void ColouriseOctaveDoc(unsigned int startPos
, int length
, int initStyle
,
244 WordList
*keywordlists
[], Accessor
&styler
) {
245 ColouriseMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsOctaveCommentChar
, false);
248 static void FoldMatlabOctaveDoc(unsigned int startPos
, int length
, int,
249 WordList
*[], Accessor
&styler
,
250 bool (*IsComment
)(Accessor
&, int, int)) {
252 int endPos
= startPos
+ length
;
254 // Backtrack to previous line in case need to fix its fold status
255 int lineCurrent
= styler
.GetLine(startPos
);
257 if (lineCurrent
> 0) {
259 startPos
= styler
.LineStart(lineCurrent
);
263 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsComment
);
264 char chNext
= styler
[startPos
];
265 for (int i
= startPos
; i
< endPos
; i
++) {
267 chNext
= styler
.SafeGetCharAt(i
+ 1);
269 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n') || (i
== endPos
)) {
270 int lev
= indentCurrent
;
271 int indentNext
= styler
.IndentAmount(lineCurrent
+ 1, &spaceFlags
, IsComment
);
272 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
)) {
273 // Only non whitespace lines can be headers
274 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext
& SC_FOLDLEVELNUMBERMASK
)) {
275 lev
|= SC_FOLDLEVELHEADERFLAG
;
276 } else if (indentNext
& SC_FOLDLEVELWHITEFLAG
) {
277 // Line after is blank so check the next - maybe should continue further?
279 int indentNext2
= styler
.IndentAmount(lineCurrent
+ 2, &spaceFlags2
, IsComment
);
280 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext2
& SC_FOLDLEVELNUMBERMASK
)) {
281 lev
|= SC_FOLDLEVELHEADERFLAG
;
285 indentCurrent
= indentNext
;
286 styler
.SetLevel(lineCurrent
, lev
);
292 static void FoldMatlabDoc(unsigned int startPos
, int length
, int initStyle
,
293 WordList
*keywordlists
[], Accessor
&styler
) {
294 FoldMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsMatlabComment
);
297 static void FoldOctaveDoc(unsigned int startPos
, int length
, int initStyle
,
298 WordList
*keywordlists
[], Accessor
&styler
) {
299 FoldMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsOctaveComment
);
302 static const char * const matlabWordListDesc
[] = {
307 static const char * const octaveWordListDesc
[] = {
312 LexerModule
lmMatlab(SCLEX_MATLAB
, ColouriseMatlabDoc
, "matlab", FoldMatlabDoc
, matlabWordListDesc
);
314 LexerModule
lmOctave(SCLEX_OCTAVE
, ColouriseOctaveDoc
, "octave", FoldOctaveDoc
, octaveWordListDesc
);