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 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
17 // The License.txt file describes the conditions under which this software may be distributed.
27 #include "Scintilla.h"
31 #include "LexAccessor.h"
33 #include "StyleContext.h"
34 #include "CharacterSet.h"
35 #include "LexerModule.h"
38 using namespace Scintilla
;
41 static bool IsMatlabCommentChar(int c
) {
45 static bool IsOctaveCommentChar(int c
) {
46 return (c
== '%' || c
== '#') ;
49 static bool IsMatlabComment(Accessor
&styler
, int pos
, int len
) {
50 return len
> 0 && IsMatlabCommentChar(styler
[pos
]) ;
53 static bool IsOctaveComment(Accessor
&styler
, int pos
, int len
) {
54 return len
> 0 && IsOctaveCommentChar(styler
[pos
]) ;
57 static void ColouriseMatlabOctaveDoc(
58 unsigned int startPos
, int length
, int initStyle
,
59 WordList
*keywordlists
[], Accessor
&styler
,
60 bool (*IsCommentChar
)(int),
63 WordList
&keywords
= *keywordlists
[0];
65 styler
.StartAt(startPos
);
67 // boolean for when the ' is allowed to be transpose vs the start/end
69 bool transpose
= false;
71 // approximate position of first non space character in a line
72 int nonSpaceColumn
= -1;
73 // approximate column position of the current character in a line
76 // use the line state of each line to store the block comment depth
77 int curLine
= styler
.GetLine(startPos
);
78 int commentDepth
= curLine
> 0 ? styler
.GetLineState(curLine
-1) : 0;
81 StyleContext
sc(startPos
, length
, initStyle
, styler
);
83 for (; sc
.More(); sc
.Forward(), column
++) {
86 // set the line state to the current commentDepth
87 curLine
= styler
.GetLine(sc
.currentPos
);
88 styler
.SetLineState(curLine
, commentDepth
);
90 // reset the column to 0, nonSpace to -1 (not set)
95 // save the column position of first non space character in a line
96 if((nonSpaceColumn
== -1) && (! IsASpace(sc
.ch
)))
98 nonSpaceColumn
= column
;
101 // check for end of states
102 if (sc
.state
== SCE_MATLAB_OPERATOR
) {
103 if (sc
.chPrev
== '.') {
104 if (sc
.ch
== '*' || sc
.ch
== '/' || sc
.ch
== '\\' || sc
.ch
== '^') {
105 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
107 } else if (sc
.ch
== '\'') {
108 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
110 } else if(sc
.ch
== '.' && sc
.chNext
== '.') {
111 // we werent an operator, but a '...'
112 sc
.ChangeState(SCE_MATLAB_COMMENT
);
115 sc
.SetState(SCE_MATLAB_DEFAULT
);
118 sc
.SetState(SCE_MATLAB_DEFAULT
);
120 } else if (sc
.state
== SCE_MATLAB_KEYWORD
) {
121 if (!isalnum(sc
.ch
) && sc
.ch
!= '_') {
123 sc
.GetCurrentLowered(s
, sizeof(s
));
124 if (keywords
.InList(s
)) {
125 sc
.SetState(SCE_MATLAB_DEFAULT
);
128 sc
.ChangeState(SCE_MATLAB_IDENTIFIER
);
129 sc
.SetState(SCE_MATLAB_DEFAULT
);
133 } else if (sc
.state
== SCE_MATLAB_NUMBER
) {
134 if (!isdigit(sc
.ch
) && sc
.ch
!= '.'
135 && !(sc
.ch
== 'e' || sc
.ch
== 'E')
136 && !((sc
.ch
== '+' || sc
.ch
== '-') && (sc
.chPrev
== 'e' || sc
.chPrev
== 'E'))) {
137 sc
.SetState(SCE_MATLAB_DEFAULT
);
140 } else if (sc
.state
== SCE_MATLAB_STRING
) {
142 if (sc
.chNext
== '\'') {
145 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
148 } else if (sc
.state
== SCE_MATLAB_DOUBLEQUOTESTRING
) {
150 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
153 } else if (sc
.ch
== '\"') {
154 sc
.ForwardSetState(SCE_MATLAB_DEFAULT
);
156 } else if (sc
.state
== SCE_MATLAB_COMMAND
) {
158 sc
.SetState(SCE_MATLAB_DEFAULT
);
161 } else if (sc
.state
== SCE_MATLAB_COMMENT
) {
162 // end or start of a nested a block comment?
163 if( IsCommentChar(sc
.ch
) && sc
.chNext
== '}' && nonSpaceColumn
== column
) {
164 if(commentDepth
> 0) commentDepth
--;
166 curLine
= styler
.GetLine(sc
.currentPos
);
167 styler
.SetLineState(curLine
, commentDepth
);
170 if (commentDepth
== 0) {
171 sc
.ForwardSetState(SCE_D_DEFAULT
);
175 else if( IsCommentChar(sc
.ch
) && sc
.chNext
== '{' && nonSpaceColumn
== column
)
179 curLine
= styler
.GetLine(sc
.currentPos
);
180 styler
.SetLineState(curLine
, commentDepth
);
184 } else if(commentDepth
== 0) {
185 // single line comment
186 if (sc
.atLineEnd
|| sc
.ch
== '\r' || sc
.ch
== '\n') {
187 sc
.SetState(SCE_MATLAB_DEFAULT
);
193 // check start of a new state
194 if (sc
.state
== SCE_MATLAB_DEFAULT
) {
195 if (IsCommentChar(sc
.ch
)) {
196 // ncrement depth if we are a block comment
197 if(sc
.chNext
== '{' && nonSpaceColumn
== column
)
199 curLine
= styler
.GetLine(sc
.currentPos
);
200 styler
.SetLineState(curLine
, commentDepth
);
201 sc
.SetState(SCE_MATLAB_COMMENT
);
202 } else if (sc
.ch
== '!' && sc
.chNext
!= '=' ) {
204 sc
.SetState(SCE_MATLAB_COMMAND
);
206 sc
.SetState(SCE_MATLAB_OPERATOR
);
208 } else if (sc
.ch
== '\'') {
210 sc
.SetState(SCE_MATLAB_OPERATOR
);
212 sc
.SetState(SCE_MATLAB_STRING
);
214 } else if (sc
.ch
== '"') {
215 sc
.SetState(SCE_MATLAB_DOUBLEQUOTESTRING
);
216 } else if (isdigit(sc
.ch
) || (sc
.ch
== '.' && isdigit(sc
.chNext
))) {
217 sc
.SetState(SCE_MATLAB_NUMBER
);
218 } else if (isalpha(sc
.ch
)) {
219 sc
.SetState(SCE_MATLAB_KEYWORD
);
220 } else if (isoperator(static_cast<char>(sc
.ch
)) || sc
.ch
== '@' || sc
.ch
== '\\') {
221 if (sc
.ch
== ')' || sc
.ch
== ']') {
226 sc
.SetState(SCE_MATLAB_OPERATOR
);
235 static void ColouriseMatlabDoc(unsigned int startPos
, int length
, int initStyle
,
236 WordList
*keywordlists
[], Accessor
&styler
) {
237 ColouriseMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsMatlabCommentChar
, true);
240 static void ColouriseOctaveDoc(unsigned int startPos
, int length
, int initStyle
,
241 WordList
*keywordlists
[], Accessor
&styler
) {
242 ColouriseMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsOctaveCommentChar
, false);
245 static void FoldMatlabOctaveDoc(unsigned int startPos
, int length
, int,
246 WordList
*[], Accessor
&styler
,
247 bool (*IsComment
)(Accessor
&, int, int)) {
249 int endPos
= startPos
+ length
;
251 // Backtrack to previous line in case need to fix its fold status
252 int lineCurrent
= styler
.GetLine(startPos
);
254 if (lineCurrent
> 0) {
256 startPos
= styler
.LineStart(lineCurrent
);
260 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsComment
);
261 char chNext
= styler
[startPos
];
262 for (int i
= startPos
; i
< endPos
; i
++) {
264 chNext
= styler
.SafeGetCharAt(i
+ 1);
266 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n') || (i
== endPos
)) {
267 int lev
= indentCurrent
;
268 int indentNext
= styler
.IndentAmount(lineCurrent
+ 1, &spaceFlags
, IsComment
);
269 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
)) {
270 // Only non whitespace lines can be headers
271 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext
& SC_FOLDLEVELNUMBERMASK
)) {
272 lev
|= SC_FOLDLEVELHEADERFLAG
;
273 } else if (indentNext
& SC_FOLDLEVELWHITEFLAG
) {
274 // Line after is blank so check the next - maybe should continue further?
276 int indentNext2
= styler
.IndentAmount(lineCurrent
+ 2, &spaceFlags2
, IsComment
);
277 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext2
& SC_FOLDLEVELNUMBERMASK
)) {
278 lev
|= SC_FOLDLEVELHEADERFLAG
;
282 indentCurrent
= indentNext
;
283 styler
.SetLevel(lineCurrent
, lev
);
289 static void FoldMatlabDoc(unsigned int startPos
, int length
, int initStyle
,
290 WordList
*keywordlists
[], Accessor
&styler
) {
291 FoldMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsMatlabComment
);
294 static void FoldOctaveDoc(unsigned int startPos
, int length
, int initStyle
,
295 WordList
*keywordlists
[], Accessor
&styler
) {
296 FoldMatlabOctaveDoc(startPos
, length
, initStyle
, keywordlists
, styler
, IsOctaveComment
);
299 static const char * const matlabWordListDesc
[] = {
304 static const char * const octaveWordListDesc
[] = {
309 LexerModule
lmMatlab(SCLEX_MATLAB
, ColouriseMatlabDoc
, "matlab", FoldMatlabDoc
, matlabWordListDesc
);
311 LexerModule
lmOctave(SCLEX_OCTAVE
, ColouriseOctaveDoc
, "octave", FoldOctaveDoc
, octaveWordListDesc
);