1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 Copyright (C) 2004 Naba Kumar
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "aneditor-priv.h"
23 void AnEditor::IndentationIncrease(){
24 CharacterRange crange
= GetSelection();
25 if (crange
.cpMin
!= crange
.cpMax
)
30 int line
=SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
31 int indent
=GetLineIndentation(line
);
32 indent
+=SendEditor(SCI_GETINDENT
);
33 SetLineIndentation(line
, indent
);
36 void AnEditor::IndentationDecrease(){
37 CharacterRange crange
= GetSelection();
38 if (crange
.cpMin
!= crange
.cpMax
)
40 SendEditor (SCI_BACKTAB
);
43 int line
=SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
44 int indent
= GetLineIndentation(line
);
45 indent
-=SendEditor(SCI_GETINDENT
);
46 if (indent
< 0) indent
= 0;
47 SetLineIndentation(line
, indent
);
50 void AnEditor::SetLineIndentation(int line
, int indent
) {
53 CharacterRange crange
= GetSelection();
54 int posBefore
= GetLineIndentPosition(line
);
55 SendEditor(SCI_SETLINEINDENTATION
, line
, indent
);
56 int posAfter
= GetLineIndentPosition(line
);
57 int posDifference
= posAfter
- posBefore
;
58 if (posAfter
> posBefore
) {
60 if (crange
.cpMin
>= posBefore
) {
61 crange
.cpMin
+= posDifference
;
63 if (crange
.cpMax
>= posBefore
) {
64 crange
.cpMax
+= posDifference
;
66 } else if (posAfter
< posBefore
) {
67 // Move selection back
68 if (crange
.cpMin
>= posAfter
) {
69 if (crange
.cpMin
>= posBefore
)
70 crange
.cpMin
+= posDifference
;
72 crange
.cpMin
= posAfter
;
74 if (crange
.cpMax
>= posAfter
) {
75 if (crange
.cpMax
>= posBefore
)
76 crange
.cpMax
+= posDifference
;
78 crange
.cpMax
= posAfter
;
81 SetSelection(crange
.cpMin
, crange
.cpMax
);
84 int AnEditor::GetLineIndentation(int line
) {
85 return SendEditor(SCI_GETLINEINDENTATION
, line
);
88 int AnEditor::GetLineIndentPosition(int line
) {
89 return SendEditor(SCI_GETLINEINDENTPOSITION
, line
);
92 bool AnEditor::RangeIsAllWhitespace(int start
, int end
) {
93 //FIXME WindowAccessor acc(wEditor.GetID(), *props);
95 for (int i
= start
;i
< end
;i
++) {
96 if ((acc
[i
] != ' ') && (acc
[i
] != '\t'))
105 unsigned int AnEditor::GetLinePartsInStyle(int line
, int style1
, int style2
,
106 SString sv
[], int len
) {
107 for (int i
= 0; i
< len
; i
++)
109 WindowAccessor
acc(wEditor
.GetID(), *props
);
112 int thisLineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
113 int nextLineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
+ 1);
114 for (int pos
= thisLineStart
; pos
< nextLineStart
; pos
++) {
115 if ((acc
.StyleAt(pos
) == style1
) || (acc
.StyleAt(pos
) == style2
)) {
120 } else if (s
.length() > 0) {
127 if ((s
.length() > 0) && (part
< len
)) {
133 static bool includes(const StyleAndWords
&symbols
, const SString value
) {
134 if (symbols
.words
.length() == 0) {
136 } else if (IsAlphabetic(symbols
.words
[0])) {
137 // Set of symbols separated by spaces
138 size_t lenVal
= value
.length();
139 const char *symbol
= symbols
.words
.c_str();
141 const char *symbolEnd
= strchr(symbol
, ' ');
142 size_t lenSymbol
= strlen(symbol
);
144 lenSymbol
= symbolEnd
- symbol
;
145 if (lenSymbol
== lenVal
) {
146 if (strncmp(symbol
, value
.c_str(), lenSymbol
) == 0) {
155 // Set of individual characters. Only one character allowed for now
156 char ch
= symbols
.words
[0];
157 return strchr(value
.c_str(), ch
) != 0;
162 #define ELEMENTS(a) (sizeof(a) / sizeof(a[0]))
164 IndentationStatus
AnEditor::GetIndentState(int line
) {
165 // C like language indentation defined by braces and keywords
166 IndentationStatus indentState
= isNone
;
167 SString controlWords
[20];
168 unsigned int parts
= GetLinePartsInStyle(line
, statementIndent
.styleNumber
,
169 -1, controlWords
, ELEMENTS(controlWords
));
170 for (unsigned int i
= 0; i
< parts
; i
++) {
171 if (includes(statementIndent
, controlWords
[i
]))
172 indentState
= isKeyWordStart
;
174 // Braces override keywords
175 SString controlStrings
[20];
176 parts
= GetLinePartsInStyle(line
, blockEnd
.styleNumber
,
177 -1, controlStrings
, ELEMENTS(controlStrings
));
178 for (unsigned int j
= 0; j
< parts
; j
++) {
179 if (includes(blockEnd
, controlStrings
[j
]))
180 indentState
= isBlockEnd
;
181 if (includes(blockStart
, controlStrings
[j
]))
182 indentState
= isBlockStart
;
187 int AnEditor::IndentOfBlockProper(int line
) {
192 int indentSize
= SendEditor(SCI_GETINDENT
);
193 int indentBlock
= GetLineIndentation(line
);
194 int minIndent
= indentBlock
;
197 IndentationStatus indentState
= isNone
;
198 if (statementIndent
.IsEmpty() && blockStart
.IsEmpty() && blockEnd
.IsEmpty())
199 indentState
= isBlockStart
; // Don't bother searching backwards
201 int lineLimit
= line
- statementLookback
;
204 bool noIndentFound
= true;
205 while ((backLine
>= lineLimit
) && (indentState
== 0)) {
206 indentState
= GetIndentState(backLine
);
207 if (indentState
!= 0) {
208 noIndentFound
= false;
209 indentBlock
= GetLineIndentation(backLine
);
210 if (indentState
== isBlockStart
) {
212 indentBlock
+= indentSize
;
214 if (indentState
== isBlockEnd
) {
216 indentBlock
-= indentSize
;
220 if ((indentState
== isKeyWordStart
) && (backLine
== line
))
221 indentBlock
+= indentSize
;
222 } else if (noIndentFound
) {
223 int currentIndent
= GetLineIndentation(backLine
);
224 minIndent
= MIN(minIndent
, currentIndent
);
228 if (noIndentFound
&& minIndent
> 0)
229 indentBlock
= minIndent
;
233 int AnEditor::IndentOfBlock(int line
) {
237 /* Find mismatched parenthesis */
238 if (lexLanguage
== SCLEX_CPP
) {
239 WindowAccessor
acc(wEditor
.GetID(), *props
);
240 int currentPos
= SendEditor(SCI_POSITIONFROMLINE
, backLine
+ 1);
242 while (backLine
>= 0) {
243 int thisLineStart
= SendEditor(SCI_POSITIONFROMLINE
, backLine
);
244 int nextLineStart
= currentPos
;
245 // printf("Scanning at line: %d (%d)\n", backLine, currentPos);
247 int foundTerminator
= false;
249 for (pos
= nextLineStart
- 1; pos
>= thisLineStart
; pos
--) {
251 // printf ("Style at %d = %d\n", pos, acc.StyleAt(pos));
253 if ((acc
.StyleAt(pos
) == 10)) {
257 // printf ("Looking at: \"%s\"\n", c);
258 if (includes(blockEnd
, c
) ||
259 includes(blockStart
, c
) ||
260 includes(statementEnd
, c
))
262 // printf ("Found block start/block end/statement end. Breaking\n");
263 foundTerminator
= true;
266 if (c
[0] == '(' || c
[0] == '[') {
267 int indentBlock
= SendEditor(SCI_GETCOLUMN
, pos
) + 1;// - thisLineStart;
268 // printf ("Found Unmatched '(' at col: %d. Returning\n", indentBlock);
271 if (c
[0] == ')' || c
[0] == ']') {
274 braceOpp
= SendEditor(SCI_BRACEMATCH
, pos
, 0);
275 // printf ("Brace opp. at %d\n", braceOpp);
277 currentPos
= braceOpp
- 1;
278 lineOpp
= SendEditor (SCI_LINEFROMPOSITION
,
280 if (backLine
!= lineOpp
) {
282 // printf ("Jumping to line %d (%d)\n", backLine, currentPos);
288 foundTerminator
= true;
292 } else if ((acc
.StyleAt(pos
) == statementIndent
.styleNumber
) &&
293 (acc
.StyleAt(pos
+1) != statementIndent
.styleNumber
)) {
295 if (GetWordAtPosition (buffer
, 128, pos
)) {
296 if (includes (statementIndent
, buffer
)) {
297 printf ("Found keyword terminator before unmatched (\n");
298 foundTerminator
= true;
306 if (pos
< thisLineStart
) {
312 return IndentOfBlockProper(backLine
);
316 void AnEditor::MaintainIndentation(char ch
) {
317 int eolMode
= SendEditor(SCI_GETEOLMODE
);
318 int curLine
= GetCurrentLineNumber();
319 int lastLine
= curLine
- 1;
320 int indentAmount
= 0;
322 if (((eolMode
== SC_EOL_CRLF
|| eolMode
== SC_EOL_LF
) && ch
== '\n') ||
323 (eolMode
== SC_EOL_CR
&& ch
== '\r')) {
324 if (props
->GetInt("indent.automatic")) {
325 while (lastLine
>= 0 && GetLineLength(lastLine
) == 0)
329 indentAmount
= GetLineIndentation(lastLine
);
331 if (indentAmount
> 0) {
332 SetLineIndentation(curLine
, indentAmount
);
338 void AnEditor::AutomaticIndentation(char ch
) {
339 CharacterRange crange
= GetSelection();
340 int selStart
= crange
.cpMin
;
341 int curLine
= GetCurrentLineNumber();
342 int thisLineStart
= SendEditor(SCI_POSITIONFROMLINE
, curLine
);
343 int indentSize
= SendEditor(SCI_GETINDENT
);
345 if (blockEnd
.IsSingleChar() && ch
== blockEnd
.words
[0]) {
347 if (!indentClosing
) {
348 if (RangeIsAllWhitespace(thisLineStart
, selStart
- 1)) {
349 int indentBlock
= IndentOfBlockProper(curLine
- 1);
350 SetLineIndentation(curLine
, indentBlock
- indentSize
);
353 } else if (!blockEnd
.IsSingleChar() && (ch
== ' ')) {
355 if (!indentClosing
&& (GetIndentState(curLine
) == isBlockEnd
)) {}
356 } else if (ch
== blockStart
.words
[0]) {
357 // Dedent maybe if first on line and previous line was starting keyword
358 if (!indentOpening
&&
359 (GetIndentState(curLine
- 1) == isKeyWordStart
)) {
360 if (RangeIsAllWhitespace(thisLineStart
, selStart
- 1)) {
361 int indentBlock
= IndentOfBlockProper(curLine
- 1);
362 SetLineIndentation(curLine
, indentBlock
- indentSize
);
365 } else if ((ch
== '\r' || ch
== '\n') && (selStart
== thisLineStart
)) {
366 // printf("New line block\n");
367 int indentBlock
= IndentOfBlock(curLine
- 1);
368 if (!indentClosing
&& !blockEnd
.IsSingleChar()) {
369 // Dedent previous line maybe
371 SString controlWords
[1];
372 // printf ("First if\n");
374 if (GetLinePartsInStyle(curLine
-1, blockEnd
.styleNumber
,
375 -1, controlWords
, ELEMENTS(controlWords
))) {
376 // printf ("Second if\n");
377 if (includes(blockEnd
, controlWords
[0])) {
378 // printf ("Third if\n");
379 // Check if first keyword on line is an ender
380 SetLineIndentation(curLine
-1,
381 IndentOfBlockProper(curLine
-2)
383 // Recalculate as may have changed previous line
384 indentBlock
= IndentOfBlock(curLine
- 1);
388 SetLineIndentation(curLine
, indentBlock
);
391 if (SendEditor (SCI_GETCOLUMN
,
392 SendEditor(SCI_GETCURRENTPOS
)) < indentBlock
)
393 SendEditor (SCI_VCHOME
);
395 } else if (lexLanguage
== SCLEX_CPP
) {
398 int indentBlock
= IndentOfBlock(curLine
- 1);
399 int indentState
= GetIndentState (curLine
);
401 if (blockStart
.IsSingleChar() && indentState
== isBlockStart
) {
402 if (!indentOpening
) {
403 if (RangeIsAllWhitespace(thisLineStart
, selStart
- 1)) {
404 // int indentBlock = IndentOfBlockProper(curLine - 1);
405 SetLineIndentation(curLine
, indentBlock
- indentSize
);
408 } else if (blockEnd
.IsSingleChar() && indentState
== isBlockEnd
) {
409 if (!indentClosing
) {
410 if (RangeIsAllWhitespace(thisLineStart
, selStart
- 1)) {
411 // int indentBlock = IndentOfBlockProper(curLine - 1);
412 SetLineIndentation(curLine
, indentBlock
- indentSize
);
416 SetLineIndentation(curLine
, indentBlock
);
420 if (SendEditor (SCI_GETCOLUMN
,
421 SendEditor(SCI_GETCURRENTPOS
)) < indentBlock
)
422 SendEditor (SCI_VCHOME
);