scintilla: Update scintilla with changeset 3662:1d1c06df8a2f using gtk+3
[anjuta-extras.git] / plugins / scintilla / aneditor-indent.cxx
blob9983ac32eba5ab1da2ca23e74cd88abef9dcb422
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 aneditor-indent.cxx
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)
27 SendEditor (SCI_TAB);
28 return;
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);
41 return;
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) {
51 if (indent < 0)
52 return;
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) {
59 // Move selection on
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;
71 else
72 crange.cpMin = posAfter;
74 if (crange.cpMax >= posAfter) {
75 if (crange.cpMax >= posBefore)
76 crange.cpMax += posDifference;
77 else
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);
94 #if 0
95 for (int i = start;i < end;i++) {
96 if ((acc[i] != ' ') && (acc[i] != '\t'))
97 return false;
99 #endif
100 return true;
103 #if 0
105 unsigned int AnEditor::GetLinePartsInStyle(int line, int style1, int style2,
106 SString sv[], int len) {
107 for (int i = 0; i < len; i++)
108 sv[i] = "";
109 WindowAccessor acc(wEditor.GetID(), *props);
110 SString s;
111 int part = 0;
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)) {
116 char c[2];
117 c[0] = acc[pos];
118 c[1] = '\0';
119 s += c;
120 } else if (s.length() > 0) {
121 if (part < len) {
122 sv[part++] = s;
124 s = "";
127 if ((s.length() > 0) && (part < len)) {
128 sv[part++] = s;
130 return part;
133 static bool includes(const StyleAndWords &symbols, const SString value) {
134 if (symbols.words.length() == 0) {
135 return false;
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();
140 while (symbol) {
141 const char *symbolEnd = strchr(symbol, ' ');
142 size_t lenSymbol = strlen(symbol);
143 if (symbolEnd)
144 lenSymbol = symbolEnd - symbol;
145 if (lenSymbol == lenVal) {
146 if (strncmp(symbol, value.c_str(), lenSymbol) == 0) {
147 return true;
150 symbol = symbolEnd;
151 if (symbol)
152 symbol++;
154 } else {
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;
159 return false;
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;
184 return indentState;
187 int AnEditor::IndentOfBlockProper(int line) {
189 if (line < 0)
190 return 0;
192 int indentSize = SendEditor(SCI_GETINDENT);
193 int indentBlock = GetLineIndentation(line);
194 int minIndent = indentBlock;
195 int backLine = line;
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;
202 if (lineLimit < 0)
203 lineLimit = 0;
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) {
211 if (!indentOpening)
212 indentBlock += indentSize;
214 if (indentState == isBlockEnd) {
215 if (indentClosing)
216 indentBlock -= indentSize;
217 if (indentBlock < 0)
218 indentBlock = 0;
220 if ((indentState == isKeyWordStart) && (backLine == line))
221 indentBlock += indentSize;
222 } else if (noIndentFound) {
223 int currentIndent = GetLineIndentation(backLine);
224 minIndent = MIN(minIndent, currentIndent);
226 backLine--;
228 if (noIndentFound && minIndent > 0)
229 indentBlock = minIndent;
230 return indentBlock;
233 int AnEditor::IndentOfBlock(int line) {
235 int backLine = 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;
248 int pos;
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)) {
254 char c[2];
255 c[0] = acc[pos];
256 c[1] = '\0';
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;
264 break;
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);
269 return indentBlock;
271 if (c[0] == ')' || c[0] == ']') {
272 int braceOpp;
273 int lineOpp;
274 braceOpp = SendEditor(SCI_BRACEMATCH, pos, 0);
275 // printf ("Brace opp. at %d\n", braceOpp);
276 if (braceOpp >= 0) {
277 currentPos = braceOpp - 1;
278 lineOpp = SendEditor (SCI_LINEFROMPOSITION,
279 braceOpp);
280 if (backLine != lineOpp) {
281 backLine = lineOpp;
282 // printf ("Jumping to line %d (%d)\n", backLine, currentPos);
283 break;
284 } else {
285 pos = currentPos;
287 } else {
288 foundTerminator = true;
289 break;
292 } else if ((acc.StyleAt(pos) == statementIndent.styleNumber) &&
293 (acc.StyleAt(pos+1) != statementIndent.styleNumber)) {
294 char buffer[128];
295 if (GetWordAtPosition (buffer, 128, pos)) {
296 if (includes (statementIndent, buffer)) {
297 printf ("Found keyword terminator before unmatched (\n");
298 foundTerminator = true;
299 break;
304 if (foundTerminator)
305 break;
306 if (pos < thisLineStart) {
307 backLine--;
308 currentPos = pos;
312 return IndentOfBlockProper(backLine);
314 #endif
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)
326 lastLine--;
328 if (lastLine >= 0) {
329 indentAmount = GetLineIndentation(lastLine);
331 if (indentAmount > 0) {
332 SetLineIndentation(curLine, indentAmount);
337 #if 0
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]) {
346 // Dedent maybe
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 == ' ')) {
354 // Dedent maybe
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)
382 - indentSize);
383 // Recalculate as may have changed previous line
384 indentBlock = IndentOfBlock(curLine - 1);
388 SetLineIndentation(curLine, indentBlock);
390 // Home cursor.
391 if (SendEditor (SCI_GETCOLUMN,
392 SendEditor(SCI_GETCURRENTPOS)) < indentBlock)
393 SendEditor (SCI_VCHOME);
395 } else if (lexLanguage == SCLEX_CPP) {
396 if ((ch == '\t')) {
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);
415 } else {
416 SetLineIndentation(curLine, indentBlock);
419 // Home cursor.
420 if (SendEditor (SCI_GETCOLUMN,
421 SendEditor(SCI_GETCURRENTPOS)) < indentBlock)
422 SendEditor (SCI_VCHOME);
426 #endif