scintilla: Fix default foreground and background text color
[anjuta-extras.git] / plugins / scintilla / aneditor.cxx
blob76a0dfb817f38565f99e9cf89b764992b02db6ac
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 aneditor.cxx
4 Copyright (C) 2003 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 * Most of the code stolen from SciTE and heavily modified.
22 * If code sections are later imported from SciTE, utmost care
23 * should be taken to ensure that it does not conflict with the present code.
26 #include "aneditor-priv.h"
28 #include <libanjuta/anjuta-debug.h>
30 static void lowerCaseString(char *s);
31 static AnEditor * aneditor_get(AnEditorID id);
33 gint on_aneditor_focus_in(GtkWidget* widget, gpointer * unused, AnEditor* ed);
34 gint on_aneditor_focus_out(GtkWidget* widget, gpointer * unused, AnEditor* ed);
36 static const char *extList[] = {
37 "", "x", "x.cpp", "x.cpp", "x.html", "x.xml", "x.js", "x.vbs", "x.mak", "x.java",
38 "x.lua", "x.py", "x.pl", "x.sql", "x.spec", "x.php3", "x.tex", "x.diff", "x.pas",
39 "x.cs", "x.properties", "x.conf", "x.bc", "x.adb", "x.lisp", "x.rb", ".m"
42 const AnEditorID ANE_ID_INVALID = G_MAXUINT;
43 AnEditorID AnEditor::focusedID = ANE_ID_INVALID;
45 AnEditor::AnEditor(PropSetFile* p) {
47 characterSet = 0;
48 language = "java";
49 lexLanguage = SCLEX_CPP;
51 indentSize = 8;
52 indentOpening = true;
53 indentClosing = true;
54 statementLookback = 10;
56 indentMaintain = true;
57 indentAutomatic = true;
59 wrapLine = true;
60 isReadOnly = false;
61 fnEditor = 0;
62 ptrEditor = 0;
63 fnOutput = 0;
64 ptrOutput = 0;
65 tbVisible = false;
66 sbVisible = false;
67 tabVisible = false;
68 tabMultiLine = false;
69 visHeightTools = 0;
70 visHeightStatus = 0;
71 visHeightEditor = 1;
72 heightBar = 7;
74 heightOutput = 0;
76 allowMenuActions = true;
77 isDirty = false;
79 ptStartDrag.x = 0;
80 ptStartDrag.y = 0;
81 capturedMouse = false;
82 firstPropertiesRead = true;
83 splitVertical = false;
84 bufferedDraw = true;
85 bracesCheck = true;
86 bracesSloppy = false;
87 bracesStyle = 0;
88 braceCount = 0;
90 indentationWSVisible = true;
92 autoCompleteIgnoreCase = false;
93 callTipIgnoreCase = false;
94 autoCCausedByOnlyOne = false;
95 // startCalltipWord = 0;
97 // init calltips
98 SetCallTipDefaults( );
99 call_tip_node_queue = g_queue_new();
100 lastPos = 0;
102 autocompletion = NULL;
104 margin = false;
105 marginWidth = marginWidthDefault;
106 foldMargin = true;
107 foldMarginWidth = foldMarginWidthDefault;
108 lineNumbers = false;
109 lineNumbersWidth = lineNumbersWidthDefault;
110 usePalette = false;
112 accelGroup = NULL;
113 calltipShown = false;
114 // debugTipOn = false;
116 fileName[0] = '\0';
117 props = p;
119 wEditor = scintilla_new();
120 g_object_ref (G_OBJECT (wEditor.GetID()));
121 g_object_ref_sink (G_OBJECT (wEditor.GetID()));
122 scintilla_set_id(SCINTILLA(wEditor.GetID()), 0);
124 fnEditor = reinterpret_cast<SciFnDirect>(Platform::SendScintilla(
125 wEditor.GetID(), SCI_GETDIRECTFUNCTION, 0, 0));
127 ptrEditor = Platform::SendScintilla(wEditor.GetID(),
128 SCI_GETDIRECTPOINTER, 0, 0);
130 g_signal_connect (wEditor.GetID(), "sci-notify", G_CALLBACK(NotifySignal), this);
132 /* We will handle all accels ourself */
133 /* SendEditor(SCI_CLEARALLCMDKEYS); */
135 /*We have got our own popup menu */
136 SendEditor(SCI_USEPOPUP, false);
137 /* Set default editor mode */
138 SendEditor(SCI_SETEOLMODE, SC_EOL_LF);
139 /* Allow multiple typing */
140 SendEditor(SCI_SETADDITIONALSELECTIONTYPING, true);
142 #if 0
143 // Trap 'TAB' key for automatic indentation.
144 // SendEditor (SCI_ASSIGNCMDKEY, SCK_TAB, SCI_NULL);
145 g_signal_connect (wEditor.GetID(), "key-press-event",
146 G_CALLBACK (KeyPressEvent), this);
148 /* Register images to be used for autocomplete */
149 typedef struct {
150 SVNodeType type;
151 char **xpm_data;
152 } PixAndType;
153 PixAndType pix_list[] = {
154 { sv_none_t , sv_unknown_xpm }
155 , { sv_class_t, sv_class_xpm }
156 , { sv_struct_t, sv_struct_xpm }
157 , { sv_union_t, sv_struct_xpm }
158 , { sv_function_t, sv_function_xpm }
159 , { sv_macro_t, sv_macro_xpm }
160 , { sv_variable_t, sv_variable_xpm }
161 , { sv_private_func_t, sv_private_fun_xpm }
162 , { sv_private_var_t, sv_private_var_xpm }
163 , { sv_protected_func_t, sv_protected_fun_xpm }
164 , { sv_protected_var_t, sv_protected_var_xpm }
165 , { sv_public_func_t, sv_public_fun_xpm }
166 , { sv_public_var_t, sv_public_var_xpm }
168 for (guint i = 0; i < (sizeof(pix_list)/sizeof(pix_list[0])); ++i)
170 SendEditor(SCI_REGISTERIMAGE, (long) pix_list[i].type
171 , reinterpret_cast<long>(pix_list[i].xpm_data));
173 #endif
176 void AnEditor::SetParent(AnEditor *parent)
178 long pdoc = parent->SendEditor(SCI_GETDOCPOINTER, 0, 0);
179 SendEditor(SCI_SETDOCPOINTER, 0, pdoc);
182 #if 0
183 static SVNodeType
184 sv_get_node_type (TMTag *tag)
186 char access;
188 if (!tag || (tm_tag_file_t == tag->type))
189 return sv_none_t;
191 access = tag->atts.entry.access;
192 switch (tag->type)
194 case tm_tag_class_t:
195 return sv_class_t;
196 case tm_tag_struct_t:
197 return sv_struct_t;
198 case tm_tag_union_t:
199 return sv_union_t;
200 case tm_tag_function_t:
201 case tm_tag_prototype_t:
202 switch (access)
204 case TAG_ACCESS_PRIVATE:
205 return sv_private_func_t;
207 case TAG_ACCESS_PROTECTED:
208 return sv_protected_func_t;
210 case TAG_ACCESS_PUBLIC:
211 return sv_public_func_t;
213 default:
214 return sv_function_t;
216 case tm_tag_member_t:
217 switch (access)
219 case TAG_ACCESS_PRIVATE:
220 return sv_private_var_t;
222 case TAG_ACCESS_PROTECTED:
223 return sv_protected_var_t;
225 case TAG_ACCESS_PUBLIC:
226 return sv_public_var_t;
228 default:
229 return sv_variable_t;
232 case tm_tag_externvar_t:
233 case tm_tag_variable_t:
234 return sv_variable_t;
236 case tm_tag_macro_t:
237 case tm_tag_macro_with_arg_t:
238 return sv_macro_t;
240 default:
241 return sv_none_t;
246 #endif
248 void
249 AnEditor::SetAccelGroup(GtkAccelGroup* acl) {
250 accelGroup = acl;
253 AnEditor::~AnEditor() {
254 g_object_unref (G_OBJECT (wEditor.GetID()));
257 long AnEditor::SendEditor(unsigned int msg, unsigned long wParam, long lParam) {
258 return fnEditor(ptrEditor, msg, wParam, lParam);
261 long AnEditor::SendEditorString(unsigned int msg, unsigned long wParam, const char *s) {
262 return SendEditor(msg, wParam, reinterpret_cast<long>(s));
265 void AnEditor::ViewWhitespace(bool view) {
266 if (view && indentationWSVisible)
267 SendEditor(SCI_SETVIEWWS, SCWS_VISIBLEALWAYS);
268 else if (view)
269 SendEditor(SCI_SETVIEWWS, SCWS_VISIBLEAFTERINDENT);
270 else
271 SendEditor(SCI_SETVIEWWS, SCWS_INVISIBLE);
274 StyleAndWords AnEditor::GetStyleAndWords(const char *base) {
275 StyleAndWords sw;
276 SString fileNameForExtension = ExtensionFileName();
277 SString sAndW = props->GetNewExpand(base, fileNameForExtension.c_str());
278 sw.styleNumber = sAndW.value();
279 const char *space = strchr(sAndW.c_str(), ' ');
280 if (space)
281 sw.words = space + 1;
282 return sw;
285 void AnEditor::AssignKey(int key, int mods, int cmd) {
286 SendEditor(SCI_ASSIGNCMDKEY,
287 Platform::LongFromTwoShorts(static_cast<short>(key),
288 static_cast<short>(mods)), cmd);
291 void AnEditor::SetOverrideLanguage(int ID) {
292 overrideExtension = extList[ID - TE_LEXER_BASE];
295 int AnEditor::LengthDocument() {
296 return SendEditor(SCI_GETLENGTH);
299 int AnEditor::GetCaretInLine() {
300 int caret = SendEditor(SCI_GETCURRENTPOS);
301 int line = SendEditor(SCI_LINEFROMPOSITION, caret);
302 int lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
303 return caret - lineStart;
306 void AnEditor::GetLine(SString & text, int line) {
307 if (line < 0)
308 line = GetCurrentLineNumber();
309 int lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
310 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
311 int len = lineEnd - lineStart + 1;
312 char *text_buffer = SString::StringAllocate (len);
313 GetRange(wEditor, lineStart, lineEnd, text_buffer);
314 text_buffer[len] = '\0';
315 text.attach(text_buffer, len);
318 int AnEditor::GetFullLine(SString & text, int line) {
319 int caret, lineStart, lineEnd;
320 if (line < 0)
322 line = GetCurrentLineNumber();
323 caret = GetCaretInLine();
324 lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
325 lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
327 else
329 lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
330 lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
331 caret = lineEnd - lineStart - 1;
333 int count = 25, current;
334 int len = lineEnd - lineStart + 1;
335 text.clear();
336 while(count)
339 char *text_buffer = SString::StringAllocate (len + text.length());
340 GetRange(wEditor, lineStart, lineEnd, text_buffer);
341 memcpy(text_buffer + len - 1, text.c_str(), text.length());
342 text_buffer[len + text.length()] = '\0';
343 text.attach(text_buffer, len + text.length());
345 current = caret;
346 while(current > 0)
348 if(text[current - 1] == ';' ||
349 text[current - 1] == '{' || text[current - 1] == '}')
351 return caret;
353 current--;
355 line--;
356 if(line < 0) break;
357 lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
358 lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
359 len = lineEnd - lineStart;
360 caret += len;
361 len++;
362 count--;
364 text.clear();
365 return -1;
369 void AnEditor::GetRange(Window &win, int start, int end, char *text) {
370 TextRange tr;
371 tr.chrg.cpMin = start;
372 tr.chrg.cpMax = end;
373 tr.lpstrText = text;
374 Platform::SendScintilla(win.GetID(), SCI_GETTEXTRANGE, 0, reinterpret_cast<long>(&tr));
377 void AnEditor::GetRange(guint start, guint end, gchar *text, gboolean styled) {
378 TextRange tr;
379 tr.chrg.cpMin = start;
380 tr.chrg.cpMax = end;
381 tr.lpstrText = text;
382 if (styled)
383 SendEditor (SCI_GETSTYLEDTEXT, 0, reinterpret_cast<long>(&tr));
384 else
385 SendEditor (SCI_GETTEXTRANGE, 0, reinterpret_cast<long>(&tr));
388 #if 0
391 * Check if the given line is a preprocessor condition line.
392 * @return The kind of preprocessor condition (enum values).
394 int AnEditor::IsLinePreprocessorCondition(const char *line) {
395 const char *currChar = line;
396 char word[32];
397 int i = 0;
399 if (!currChar) {
400 return false;
402 while (isspacechar(*currChar) && *currChar) {
403 currChar++;
405 if (preprocessorSymbol && (*currChar == preprocessorSymbol)) {
406 currChar++;
407 while (isspacechar(*currChar) && *currChar) {
408 currChar++;
410 while (!isspacechar(*currChar) && *currChar) {
411 word[i++] = *currChar++;
413 word[i] = '\0';
414 if (preprocCondStart.InList(word)) {
415 return ppcStart;
417 if (preprocCondMiddle.InList(word)) {
418 return ppcMiddle;
420 if (preprocCondEnd.InList(word)) {
421 return ppcEnd;
424 return noPPC;
428 * Search a matching preprocessor condition line.
429 * @return @c true if the end condition are meet.
430 * Also set curLine to the line where one of these conditions is mmet.
432 bool AnEditor::FindMatchingPreprocessorCondition(
433 int &curLine, ///< Number of the line where to start the search
434 int direction, ///< Direction of search: 1 = forward, -1 = backward
435 int condEnd1, ///< First status of line for which the search is OK
436 int condEnd2) { ///< Second one
438 bool isInside = false;
439 SString line;
440 int status, level = 0;
441 int maxLines = SendEditor(SCI_GETLINECOUNT);
443 while (curLine < maxLines && curLine > 0 && !isInside) {
444 curLine += direction; // Increment or decrement
445 GetLine(line, curLine);
446 status = IsLinePreprocessorCondition(line.c_str());
448 if ((direction == 1 && status == ppcStart) || (direction == -1 && status == ppcEnd)) {
449 level++;
450 } else if (level > 0 && ((direction == 1 && status == ppcEnd) || (direction == -1 && status == ppcStart))) {
451 level--;
452 } else if (level == 0 && (status == condEnd1 || status == condEnd2)) {
453 isInside = true;
457 return isInside;
461 * Find if there is a preprocessor condition after or before the caret position,
462 * @return @c true if inside a preprocessor condition.
464 #ifdef __BORLANDC__
465 // Borland warns that isInside is assigned a value that is never used in this method.
466 // This is OK so turn off the warning just for this method.
467 #pragma warn -aus
468 #endif
469 bool AnEditor::FindMatchingPreprocCondPosition(
470 bool isForward, ///< @c true if search forward
471 int &mppcAtCaret, ///< Matching preproc. cond.: current position of caret
472 int &mppcMatch) { ///< Matching preproc. cond.: matching position
474 bool isInside = false;
475 int curLine;
476 SString line;
477 int status;
479 // Get current line
480 curLine = SendEditor(SCI_LINEFROMPOSITION, mppcAtCaret);
481 GetLine(line, curLine);
482 status = IsLinePreprocessorCondition(line.c_str());
484 switch (status) {
485 case ppcStart:
486 if (isForward) {
487 isInside = FindMatchingPreprocessorCondition(curLine, 1, ppcMiddle, ppcEnd);
488 } else {
489 mppcMatch = mppcAtCaret;
490 return true;
492 break;
493 case ppcMiddle:
494 if (isForward) {
495 isInside = FindMatchingPreprocessorCondition(curLine, 1, ppcMiddle, ppcEnd);
496 } else {
497 isInside = FindMatchingPreprocessorCondition(curLine, -1, ppcStart, ppcMiddle);
499 break;
500 case ppcEnd:
501 if (isForward) {
502 mppcMatch = mppcAtCaret;
503 return true;
504 } else {
505 isInside = FindMatchingPreprocessorCondition(curLine, -1, ppcStart, ppcMiddle);
507 break;
508 default: // Should be noPPC
510 if (isForward) {
511 isInside = FindMatchingPreprocessorCondition(curLine, 1, ppcMiddle, ppcEnd);
512 } else {
513 isInside = FindMatchingPreprocessorCondition(curLine, -1, ppcStart, ppcMiddle);
515 break;
518 if (isInside) {
519 mppcMatch = SendEditor(SCI_POSITIONFROMLINE, curLine);
521 return isInside;
523 #endif
525 #ifdef __BORLANDC__
526 #pragma warn .aus
527 #endif
530 * Find if there is a brace next to the caret, checking before caret first, then
531 * after caret. If brace found also find its matching brace.
532 * @return @c true if inside a bracket pair.
534 bool AnEditor::FindMatchingBracePosition(bool editor, int &braceAtCaret, int &braceOpposite, bool sloppy) {
535 bool isInside = false;
536 // Window &win = editor ? wEditor : wOutput;
537 Window &win = wEditor;
538 int bracesStyleCheck = editor ? bracesStyle : 0;
539 int caretPos = Platform::SendScintilla(win.GetID(), SCI_GETCURRENTPOS, 0, 0);
540 braceAtCaret = -1;
541 braceOpposite = -1;
542 char charBefore = '\0';
543 char styleBefore = '\0';
544 char buffer[6];
546 if (caretPos > 0) {
547 GetRange (caretPos - 1, caretPos + 1, buffer, true);
548 charBefore = buffer[0];
549 styleBefore = buffer[1];
551 else
553 GetRange (caretPos, caretPos + 1, buffer + 2, true);
556 // Priority goes to character before caret
557 if (charBefore && strchr("[](){}", charBefore) &&
558 ((styleBefore == bracesStyleCheck) || (!bracesStyle))) {
559 braceAtCaret = caretPos - 1;
561 bool colonMode = false;
562 if (lexLanguage == SCLEX_PYTHON && ':' == charBefore) {
563 braceAtCaret = caretPos - 1;
564 colonMode = true;
566 bool isAfter = true;
567 if (sloppy && (braceAtCaret < 0)) {
568 // No brace found so check other side
569 char charAfter = buffer[2];
570 char styleAfter = buffer[3] & 31;
571 if (charAfter && strchr("[](){}", charAfter) && (styleAfter == bracesStyleCheck)) {
572 braceAtCaret = caretPos;
573 isAfter = false;
575 if (lexLanguage == SCLEX_PYTHON && ':' == charAfter) {
576 braceAtCaret = caretPos;
577 colonMode = true;
580 if (braceAtCaret >= 0) {
581 if (colonMode) {
582 int lineStart = Platform::SendScintilla(win.GetID(), SCI_LINEFROMPOSITION, braceAtCaret);
583 int lineMaxSubord = Platform::SendScintilla(win.GetID(), SCI_GETLASTCHILD, lineStart, -1);
584 braceOpposite = Platform::SendScintilla(win.GetID(), SCI_GETLINEENDPOSITION, lineMaxSubord);
585 } else {
586 braceOpposite = Platform::SendScintilla(win.GetID(), SCI_BRACEMATCH, braceAtCaret, 0);
588 if (braceOpposite > braceAtCaret) {
589 isInside = isAfter;
590 } else {
591 isInside = !isAfter;
595 return isInside;
598 void AnEditor::BraceMatch(bool editor) {
599 if (!bracesCheck)
600 return;
601 int braceAtCaret = -1;
602 int braceOpposite = -1;
603 FindMatchingBracePosition(editor, braceAtCaret, braceOpposite, bracesSloppy);
604 // Window &win = editor ? wEditor : wOutput;
605 Window &win = wEditor;
606 if ((braceAtCaret != -1) && (braceOpposite == -1)) {
607 Platform::SendScintilla(win.GetID(), SCI_BRACEBADLIGHT, braceAtCaret, 0);
608 SendEditor(SCI_SETHIGHLIGHTGUIDE, 0);
609 } else {
610 char chBrace = static_cast<char>(Platform::SendScintilla(
611 win.GetID(), SCI_GETCHARAT, braceAtCaret, 0));
612 Platform::SendScintilla(win.GetID(), SCI_BRACEHIGHLIGHT, braceAtCaret, braceOpposite);
613 int columnAtCaret = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, braceAtCaret, 0);
614 int columnOpposite = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, braceOpposite, 0);
615 if (chBrace == ':') {
616 int lineStart = Platform::SendScintilla(win.GetID(), SCI_LINEFROMPOSITION, braceAtCaret);
617 int indentPos = Platform::SendScintilla(win.GetID(), SCI_GETLINEINDENTPOSITION, lineStart, 0);
618 int indentPosNext = Platform::SendScintilla(win.GetID(), SCI_GETLINEINDENTPOSITION, lineStart + 1, 0);
619 columnAtCaret = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, indentPos, 0);
620 int columnAtCaretNext = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, indentPosNext, 0);
621 int indentationSize = Platform::SendScintilla(win.GetID(), SCI_GETINDENT);
622 if (columnAtCaretNext - indentationSize > 1)
623 columnAtCaret = columnAtCaretNext - indentationSize;
624 //Platform::DebugPrintf(": %d %d %d\n", lineStart, indentPos, columnAtCaret);
625 if (columnOpposite == 0) // If the final line of the structure is empty
626 columnOpposite = columnAtCaret;
629 if (props->GetInt("highlight.indentation.guides"))
630 Platform::SendScintilla(win.GetID(), SCI_SETHIGHLIGHTGUIDE, Platform::Minimum(columnAtCaret, columnOpposite), 0);
634 CharacterRange AnEditor::GetSelection() {
635 CharacterRange crange;
636 crange.cpMin = SendEditor(SCI_GETSELECTIONSTART);
637 crange.cpMax = SendEditor(SCI_GETSELECTIONEND);
638 return crange;
641 void AnEditor::SetSelection(int anchor, int currentPos) {
642 SendEditor(SCI_SETSEL, anchor, currentPos);
645 bool AnEditor::iswordcharforsel(char ch) {
646 return !strchr("\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", ch);
649 void AnEditor::WordSelect() {
650 int lengthDoc = LengthDocument();
651 int selStart;
652 int selEnd;
653 int line;
654 int lineStart;
655 int lineEnd;
656 char *buffer;
658 selStart = selEnd = SendEditor(SCI_GETCURRENTPOS);
659 line = SendEditor(SCI_LINEFROMPOSITION, selStart);
660 lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
661 lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
663 buffer = new char [lineEnd - lineStart + 1];
664 GetRange(wEditor, lineStart, lineEnd, buffer);
666 if (iswordcharforsel(buffer[selStart - lineStart])) {
667 while ((selStart > lineStart) && (iswordcharforsel(buffer[selStart - 1 - lineStart])))
668 selStart--;
669 while ((selEnd < lineEnd - 1) && (iswordcharforsel(buffer[selEnd + 1 + lineStart])))
670 selEnd++;
671 if (selStart < selEnd)
672 selEnd++; // Because normal selections end one past
674 delete []buffer;
675 SetSelection(selStart, selEnd);
678 void AnEditor::LineSelect() {
679 int pos = SendEditor(SCI_GETCURRENTPOS);
680 int line = SendEditor(SCI_LINEFROMPOSITION, pos);
681 int lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
682 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
684 SetSelection(lineStart, lineEnd);
687 long AnEditor::Find (long flags, char* findWhat) {
688 if (!findWhat) return -1;
689 TextToFind ft = {{0, 0}, 0, {0, 0}};
690 CharacterRange crange = GetSelection();
691 if (flags & ANEFIND_REVERSE_FLAG) {
692 ft.chrg.cpMin = crange.cpMin - 1;
693 ft.chrg.cpMax = 1;
694 } else {
695 ft.chrg.cpMin = crange.cpMax;
696 ft.chrg.cpMax = LengthDocument();
698 ft.lpstrText = findWhat;
699 ft.chrgText.cpMin = 0;
700 ft.chrgText.cpMax = 0;
701 int posFind = SendEditor(SCI_FINDTEXT, flags, reinterpret_cast<long>(&ft));
702 if (posFind >= 0) {
703 EnsureRangeVisible(ft.chrgText.cpMin, ft.chrgText.cpMax);
704 SetSelection(ft.chrgText.cpMin, ft.chrgText.cpMax);
706 return posFind;
709 void AnEditor::BookmarkToggle( int lineno ) {
710 if (lineno == -1)
716 lineno = GetCurrentLineNumber();
717 int state = SendEditor(SCI_MARKERGET, lineno);
718 if ( state & (1 << ANE_MARKER_BOOKMARK))
719 SendEditor(SCI_MARKERDELETE, lineno, ANE_MARKER_BOOKMARK);
720 else {
721 SendEditor(SCI_MARKERADD, lineno, ANE_MARKER_BOOKMARK);
725 void AnEditor::BookmarkFirst() {
726 int lineno = GetCurrentLineNumber();
727 int nextLine = SendEditor(SCI_MARKERNEXT, 0, 1 << ANE_MARKER_BOOKMARK);
728 if (nextLine < 0 || nextLine == lineno)
729 gdk_beep(); // how do I beep? -- like this ;-)
730 else {
731 SendEditor(SCI_ENSUREVISIBLE, nextLine);
732 SendEditor(SCI_GOTOLINE, nextLine);
736 void AnEditor::BookmarkPrev() {
737 int lineno = GetCurrentLineNumber();
738 int nextLine = SendEditor(SCI_MARKERPREVIOUS, lineno - 1, 1 << ANE_MARKER_BOOKMARK);
739 if (nextLine < 0 || nextLine == lineno) {
740 if(props->GetInt("editor.wrapbookmarks")) {
741 int nrOfLines = SendEditor(SCI_GETLINECOUNT, 0, 1 << ANE_MARKER_BOOKMARK);
742 int nextLine1 = SendEditor(SCI_MARKERPREVIOUS, nrOfLines, 1 << ANE_MARKER_BOOKMARK);
743 if (nextLine1 < 0 || nextLine1 == lineno) {
744 gdk_beep(); // how do I beep? -- like this ;-)
745 } else {
746 SendEditor(SCI_ENSUREVISIBLE, nextLine1);
747 SendEditor(SCI_GOTOLINE, nextLine1);
750 } else {
751 SendEditor(SCI_ENSUREVISIBLE, nextLine);
752 SendEditor(SCI_GOTOLINE, nextLine);
756 void AnEditor::BookmarkNext() {
757 int lineno = GetCurrentLineNumber();
758 int nextLine = SendEditor(SCI_MARKERNEXT, lineno + 1, 1 << ANE_MARKER_BOOKMARK);
759 if (nextLine < 0 || nextLine == lineno) {
760 if(props->GetInt("editor.wrapbookmarks")) {
761 int nextLine1 = SendEditor(SCI_MARKERNEXT, 0, 1 << ANE_MARKER_BOOKMARK);
762 if (nextLine1 < 0 || nextLine1 == lineno) {
763 gdk_beep(); // how do I beep? -- like this ;-)
764 } else {
765 SendEditor(SCI_ENSUREVISIBLE, nextLine1);
766 SendEditor(SCI_GOTOLINE, nextLine1);
769 } else {
770 SendEditor(SCI_ENSUREVISIBLE, nextLine);
771 SendEditor(SCI_GOTOLINE, nextLine);
775 void AnEditor::BookmarkLast() {
776 int lineno = GetCurrentLineNumber();
777 int nextLine = SendEditor(SCI_MARKERPREVIOUS,
778 SendEditor(SCI_GETLINECOUNT), 1 << ANE_MARKER_BOOKMARK);
779 if (nextLine < 0 || nextLine == lineno)
780 gdk_beep(); // how do I beep? -- like this ;-)
781 else {
782 SendEditor(SCI_ENSUREVISIBLE, nextLine);
783 SendEditor(SCI_GOTOLINE, nextLine);
787 void AnEditor::BookmarkClear() {
788 SendEditor(SCI_MARKERDELETEALL, ANE_MARKER_BOOKMARK);
791 bool AnEditor::GetCurrentWord(char* buffer, int length) {
792 SString linebuf;
793 GetLine(linebuf);
794 int current = GetCaretInLine();
795 return FindWordInRegion(buffer, length, linebuf, current);
798 bool AnEditor::StartBlockComment() {
799 SString fileNameForExtension = ExtensionFileName();
800 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
801 SString base("comment.block.");
802 SString comment_at_line_start("comment.block.at.line.start.");
803 base += language;
804 comment_at_line_start += language;
805 SString comment = props->Get(base.c_str());
806 if (comment == "") { // user friendly error message box
807 //SString error("Block comment variable \"");
808 //error += base;
809 //error += "\" is not defined in SciTE *.properties!";
810 //WindowMessageBox(wEditor, error, MB_OK | MB_ICONWARNING);
811 return true;
813 comment += " ";
814 SString long_comment = comment;
815 char linebuf[1000];
816 size_t comment_length = comment.length();
817 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
818 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
819 size_t caretPosition = SendEditor(SCI_GETCURRENTPOS);
820 // checking if caret is located in _beginning_ of selected block
821 bool move_caret = caretPosition < selectionEnd;
822 int selStartLine = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
823 int selEndLine = SendEditor(SCI_LINEFROMPOSITION, selectionEnd);
824 int lines = selEndLine - selStartLine;
825 size_t firstSelLineStart = SendEditor(SCI_POSITIONFROMLINE, selStartLine);
826 // "caret return" is part of the last selected line
827 if ((lines > 0) &&
828 (selectionEnd == static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE, selEndLine))))
829 selEndLine--;
830 SendEditor(SCI_BEGINUNDOACTION);
831 for (int i = selStartLine; i <= selEndLine; i++) {
832 int lineStart = SendEditor(SCI_POSITIONFROMLINE, i);
833 int lineIndent = lineStart;
834 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, i);
835 if (props->GetInt(comment_at_line_start.c_str())) {
836 GetRange(wEditor, lineIndent, lineEnd, linebuf);
837 } else {
838 lineIndent = GetLineIndentPosition(i);
839 GetRange(wEditor, lineIndent, lineEnd, linebuf);
841 // empty lines are not commented
842 if (strlen(linebuf) < 1)
843 continue;
844 if (memcmp(linebuf, comment.c_str(), comment_length - 1) == 0) {
845 if (memcmp(linebuf, long_comment.c_str(), comment_length) == 0) {
846 // removing comment with space after it
847 SendEditor(SCI_SETSEL, lineIndent, lineIndent + comment_length);
848 SendEditorString(SCI_REPLACESEL, 0, "");
849 if (i == selStartLine) // is this the first selected line?
850 selectionStart -= comment_length;
851 selectionEnd -= comment_length; // every iteration
852 continue;
853 } else {
854 // removing comment _without_ space
855 SendEditor(SCI_SETSEL, lineIndent, lineIndent + comment_length - 1);
856 SendEditorString(SCI_REPLACESEL, 0, "");
857 if (i == selStartLine) // is this the first selected line?
858 selectionStart -= (comment_length - 1);
859 selectionEnd -= (comment_length - 1); // every iteration
860 continue;
863 if (i == selStartLine) // is this the first selected line?
864 selectionStart += comment_length;
865 selectionEnd += comment_length; // every iteration
866 SendEditorString(SCI_INSERTTEXT, lineIndent, long_comment.c_str());
868 // after uncommenting selection may promote itself to the lines
869 // before the first initially selected line;
870 // another problem - if only comment symbol was selected;
871 if (selectionStart < firstSelLineStart) {
872 if (selectionStart >= selectionEnd - (comment_length - 1))
873 selectionEnd = firstSelLineStart;
874 selectionStart = firstSelLineStart;
876 if (move_caret) {
877 // moving caret to the beginning of selected block
878 SendEditor(SCI_GOTOPOS, selectionEnd);
879 SendEditor(SCI_SETCURRENTPOS, selectionStart);
880 } else {
881 SendEditor(SCI_SETSEL, selectionStart, selectionEnd);
883 SendEditor(SCI_ENDUNDOACTION);
884 return true;
887 // Return true if the selected zone can be commented
888 // Return false if it cannot be commented or has been uncommented
889 // BOX_COMMENT : box_stream = true STREAM_COMMENT : box_stream = false
890 // Uncomment if the selected zone or the cursor is inside the comment
892 bool AnEditor::CanBeCommented(bool box_stream) {
893 SString fileNameForExtension = ExtensionFileName();
894 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
895 SString start_base("comment.box.start.");
896 SString middle_base("comment.box.middle.");
897 SString end_base("comment.box.end.");
898 SString white_space(" ");
899 start_base += language;
900 middle_base += language;
901 end_base += language;
902 SString start_comment = props->Get(start_base.c_str());
903 SString middle_cmt = props->Get(middle_base.c_str());
904 SString end_comment = props->Get(end_base.c_str());
905 start_comment += white_space;
906 middle_cmt += white_space;
907 white_space += end_comment;
908 end_comment = white_space;
909 size_t start_comment_length = start_comment.length();
910 size_t end_comment_length = end_comment.length();
911 size_t middle_cmt_length = middle_cmt.length();
912 SString start_base_stream ("comment.stream.start.");
913 start_base_stream += language;
914 SString end_base_stream ("comment.stream.end.");
915 end_base_stream += language;
916 SString end_comment_stream = props->Get(end_base_stream.c_str());
917 SString white_space_stream(" ");
918 //SString end_white_space_stream(" ");
919 SString start_comment_stream = props->Get(start_base_stream.c_str());
920 start_comment_stream += white_space_stream;
921 size_t start_comment_stream_length = start_comment_stream.length();
922 white_space_stream +=end_comment_stream;
923 end_comment_stream = white_space_stream ;
924 size_t end_comment_stream_length = end_comment_stream.length();
926 char linebuf[1000];
927 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
928 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
929 if (selectionStart == selectionEnd)
930 return FALSE;
931 int line = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
932 if (line < 0)
933 return FALSE;
934 bool start1 = false, start2 = false;
935 bool end1 = false, end2 = false;
936 int lineEnd1;
937 if (box_stream)
938 lineEnd1 = selectionStart + start_comment_length;
939 else
940 lineEnd1 = selectionStart + start_comment_stream_length +1;
941 if (lineEnd1 > LengthDocument())
942 lineEnd1 = LengthDocument();
944 int lineStart1 = 0;
945 size_t start_cmt = 0, end_cmt = 0;
946 int index = 0;
947 // Find Backward StartComment
948 while (line >= 0 && start1 == false && end1 == false)
950 lineStart1 = SendEditor(SCI_POSITIONFROMLINE, line);
951 GetRange(wEditor, lineStart1, lineEnd1, linebuf);
953 for (index = lineEnd1-lineStart1; index >= 0; index--)
955 if (end1= ((end_comment_length > 1 && !memcmp(linebuf+index,
956 end_comment.c_str(), end_comment_length ))
957 || (end_comment_stream_length > 0 && !memcmp(linebuf+index,
958 end_comment_stream.c_str(), end_comment_stream_length))))
959 break;
960 if (start1=((start_comment_length > 1 && !memcmp(linebuf+index,
961 start_comment.c_str(), start_comment_length))
962 || (start_comment_stream_length > 0 && !memcmp(linebuf+index,
963 start_comment_stream.c_str(), start_comment_stream_length))))
964 break;
966 line --;
967 lineEnd1= SendEditor(SCI_GETLINEENDPOSITION, line);
969 start_cmt = index + lineStart1;
970 line = SendEditor(SCI_LINEFROMPOSITION, selectionEnd);
971 if (box_stream)
972 lineStart1 = selectionEnd - start_comment_length;
973 else
974 lineStart1 = selectionEnd - start_comment_stream_length;
975 int last_line = SendEditor(SCI_GETLINECOUNT);
976 // Find Forward EndComment
977 while (line <= last_line && start2 == false && end2 == false)
979 lineEnd1= SendEditor(SCI_GETLINEENDPOSITION, line);
980 GetRange(wEditor, lineStart1, lineEnd1, linebuf);
981 for (index = 0; index <= (lineEnd1-lineStart1); index++)
983 if (start2= ((start_comment_length > 1 && !memcmp(linebuf+index,
984 start_comment.c_str(), start_comment_length))
985 || (start_comment_stream_length > 0 && !memcmp(linebuf+index,
986 start_comment_stream.c_str(), start_comment_stream_length))))
987 break;
988 if (end2= ((end_comment_length > 1 && !memcmp(linebuf+index,
989 end_comment.c_str(), end_comment_length ))
990 || (end_comment_stream_length > 0 && !memcmp(linebuf+index,
991 end_comment_stream.c_str(), end_comment_stream_length))))
992 break;
994 line ++;
995 end_cmt = lineStart1 + index;
996 lineStart1 = SendEditor(SCI_POSITIONFROMLINE, line);
998 // Uncomment
999 if(start1 || end2)
1001 if (start1 && end2)
1003 SendEditor(SCI_BEGINUNDOACTION);
1004 if (box_stream) // Box
1006 SendEditor(SCI_SETSEL, start_cmt, start_cmt +
1007 start_comment_length);
1008 end_cmt -= start_comment_length;
1010 else // Stream
1012 SendEditor(SCI_SETSEL, start_cmt, start_cmt +
1013 start_comment_stream_length);
1014 end_cmt -= start_comment_stream_length;
1016 SendEditorString(SCI_REPLACESEL, 0, "");
1017 line = SendEditor(SCI_LINEFROMPOSITION, start_cmt) + 1;
1018 last_line = SendEditor(SCI_LINEFROMPOSITION, end_cmt) ;
1019 for (int i = line; i < last_line; i++)
1021 int s = SendEditor(SCI_POSITIONFROMLINE, i);
1022 int e = SendEditor(SCI_GETLINEENDPOSITION, i);
1023 GetRange(wEditor, s, e, linebuf);
1024 if (!memcmp(linebuf, middle_cmt.c_str(), middle_cmt_length))
1026 SendEditor(SCI_SETSEL, s, s + middle_cmt_length);
1027 SendEditorString(SCI_REPLACESEL, 0, "");
1028 end_cmt -= middle_cmt_length;
1031 if (box_stream) // Box
1032 SendEditor(SCI_SETSEL, end_cmt, end_cmt + end_comment_length);
1033 else // Stream
1034 SendEditor(SCI_SETSEL, end_cmt, end_cmt + end_comment_stream_length);
1035 SendEditorString(SCI_REPLACESEL, 0, "");
1036 SendEditor(SCI_ENDUNDOACTION);
1038 return false;
1040 return true;
1044 bool AnEditor::StartBoxComment() {
1045 SString fileNameForExtension = ExtensionFileName();
1046 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
1047 SString start_base("comment.box.start.");
1048 SString middle_base("comment.box.middle.");
1049 SString end_base("comment.box.end.");
1050 SString white_space(" ");
1051 start_base += language;
1052 middle_base += language;
1053 end_base += language;
1054 SString start_comment = props->Get(start_base.c_str());
1055 SString middle_comment = props->Get(middle_base.c_str());
1056 SString end_comment = props->Get(end_base.c_str());
1057 if (start_comment == "" || middle_comment == "" || end_comment == "") {
1058 //SString error("Box comment variables \"");
1059 //error += start_base;
1060 //error += "\", \"";
1061 //error += middle_base;
1062 //error += "\"\nand \"";
1063 //error += end_base;
1064 //error += "\" are not ";
1065 //error += "defined in SciTE *.properties!";
1066 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1067 return true;
1069 start_comment += white_space;
1070 middle_comment += white_space;
1071 white_space += end_comment;
1072 end_comment = white_space;
1073 size_t start_comment_length = start_comment.length();
1074 size_t middle_comment_length = middle_comment.length();
1075 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
1076 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
1077 size_t caretPosition = SendEditor(SCI_GETCURRENTPOS);
1078 // checking if caret is located in _beginning_ of selected block
1079 bool move_caret = caretPosition < selectionEnd;
1080 size_t selStartLine = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
1081 size_t selEndLine = SendEditor(SCI_LINEFROMPOSITION, selectionEnd);
1082 size_t lines = selEndLine - selStartLine;
1083 // "caret return" is part of the last selected line
1084 if ((lines > 0) && (
1085 selectionEnd == static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE, selEndLine)))) {
1086 selEndLine--;
1087 lines--;
1088 // get rid of CRLF problems
1089 selectionEnd = SendEditor(SCI_GETLINEENDPOSITION, selEndLine);
1091 // Comment , Uncomment or Do Nothing
1092 if (CanBeCommented(true))
1094 SendEditor(SCI_BEGINUNDOACTION);
1095 // first commented line (start_comment)
1096 int lineStart = SendEditor(SCI_POSITIONFROMLINE, selStartLine);
1097 SendEditorString(SCI_INSERTTEXT, lineStart, start_comment.c_str());
1098 selectionStart += start_comment_length;
1099 // lines between first and last commented lines (middle_comment)
1100 for (size_t i = selStartLine + 1; i <= selEndLine; i++) {
1101 lineStart = SendEditor(SCI_POSITIONFROMLINE, i);
1102 SendEditorString(SCI_INSERTTEXT, lineStart, middle_comment.c_str());
1103 selectionEnd += middle_comment_length;
1105 // last commented line (end_comment)
1106 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, selEndLine);
1107 if (lines > 0) {
1108 SendEditorString(SCI_INSERTTEXT, lineEnd, "\n");
1109 SendEditorString(SCI_INSERTTEXT, lineEnd + 1, (end_comment.c_str() + 1));
1110 } else {
1111 SendEditorString(SCI_INSERTTEXT, lineEnd, end_comment.c_str());
1113 selectionEnd += (start_comment_length);
1114 if (move_caret) {
1115 // moving caret to the beginning of selected block
1116 SendEditor(SCI_GOTOPOS, selectionEnd);
1117 SendEditor(SCI_SETCURRENTPOS, selectionStart);
1118 } else {
1119 SendEditor(SCI_SETSEL, selectionStart, selectionEnd);
1121 SendEditor(SCI_ENDUNDOACTION);
1123 return true;
1126 bool AnEditor::StartStreamComment() {
1127 SString fileNameForExtension = ExtensionFileName();
1128 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
1129 SString start_base("comment.stream.start.");
1130 SString end_base("comment.stream.end.");
1131 SString white_space(" ");
1132 //SString end_white_space(" ");
1133 start_base += language;
1134 end_base += language;
1135 SString start_comment = props->Get(start_base.c_str());
1136 SString end_comment = props->Get(end_base.c_str());
1137 if (start_comment == "" || end_comment == "") {
1138 //SString error("Stream comment variables \"");
1139 //error += start_base;
1140 //error += "\" and \n\"";
1141 //error += end_base;
1142 //error += "\" are not ";
1143 //error += "defined in SciTE *.properties!";
1144 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1145 return true;
1147 start_comment += white_space;
1148 white_space += end_comment;
1149 end_comment = white_space;
1150 size_t start_comment_length = start_comment.length();
1151 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
1152 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
1153 size_t caretPosition = SendEditor(SCI_GETCURRENTPOS);
1154 // checking if caret is located in _beginning_ of selected block
1155 bool move_caret = caretPosition < selectionEnd;
1156 // if there is no selection?
1157 if (selectionEnd - selectionStart <= 0) {
1158 int selLine = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
1159 int lineIndent = GetLineIndentPosition(selLine);
1160 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, selLine);
1161 if (RangeIsAllWhitespace(lineIndent, lineEnd))
1162 return true; // we are not dealing with empty lines
1163 SString linebuf;
1164 GetLine(linebuf);
1165 int current = GetCaretInLine();
1166 // checking if we are not inside a word
1167 if (!wordCharacters.contains(linebuf[current]))
1168 return true; // caret is located _between_ words
1169 int startword = current;
1170 int endword = current;
1171 int start_counter = 0;
1172 int end_counter = 0;
1173 while (startword > 0 && wordCharacters.contains(linebuf[startword - 1])) {
1174 start_counter++;
1175 startword--;
1177 // checking _beginning_ of the word
1178 if (startword == current)
1179 return true; // caret is located _before_ a word
1180 while (linebuf[endword + 1] != '\0' && wordCharacters.contains(linebuf[endword + 1])) {
1181 end_counter++;
1182 endword++;
1184 selectionStart -= start_counter;
1185 selectionEnd += (end_counter + 1);
1187 // Comment , Uncomment or Do Nothing
1188 if (CanBeCommented(false))
1190 SendEditor(SCI_BEGINUNDOACTION);
1191 SendEditorString(SCI_INSERTTEXT, selectionStart, start_comment.c_str());
1192 selectionEnd += start_comment_length;
1193 selectionStart += start_comment_length;
1194 SendEditorString(SCI_INSERTTEXT, selectionEnd, end_comment.c_str());
1195 if (move_caret) {
1196 // moving caret to the beginning of selected block
1197 SendEditor(SCI_GOTOPOS, selectionEnd);
1198 SendEditor(SCI_SETCURRENTPOS, selectionStart);
1199 } else {
1200 SendEditor(SCI_SETSEL, selectionStart, selectionEnd);
1202 SendEditor(SCI_ENDUNDOACTION);
1204 return true;
1207 #if 0
1208 SString AnEditor::GetMode(SString language) {
1209 SString mode;
1210 if (strcmp(language.c_str(), "cpp") == 0)
1212 mode += " Mode: C;";
1213 if (props->GetInt("use.tabs"))
1214 mode += " indent-tabs-mode: t;";
1215 mode += " c-basic-offset: ";
1216 mode += g_strdup_printf("%d", props->GetInt("indent.size"));
1217 mode += "; tab-width: ";
1218 mode += g_strdup_printf("%d ", props->GetInt("tabsize"));
1220 //~ Other languages
1221 //~ .....
1222 return mode;
1225 /* Insert or Modify a Comment line
1226 giving File indent */
1227 bool AnEditor::InsertCustomIndent() {
1228 #define MAXBUF 1000
1230 SString fileNameForExtension = ExtensionFileName();
1231 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
1232 SString start_box_base("comment.box.start.");
1233 start_box_base += language;
1234 SString start_stream_base("comment.stream.start.");
1235 start_stream_base += language;
1236 SString end_box_base("comment.box.end.");
1237 end_box_base += language;
1238 SString end_stream_base("comment.stream.end.");
1239 end_stream_base += language;
1240 SString start_box = props->Get(start_box_base.c_str());
1241 SString start_stream = props->Get(start_stream_base.c_str());
1242 SString end_box = props->Get(end_box_base.c_str());
1243 SString end_stream = props->Get(end_stream_base.c_str());
1244 SString mark("-*-");
1245 int text_length = SendEditor(SCI_GETTEXTLENGTH);
1246 char buf[MAXBUF];
1247 int bufmax = text_length < MAXBUF ? text_length : MAXBUF;
1249 GetRange(wEditor, 0, bufmax - 1, buf);
1251 bool start_comment = false;
1252 bool indent_comment = false;
1253 int end_indent_comment = 0;
1255 for (int index = 0; index < bufmax; index++)
1257 if (!start_comment)
1259 if (memcmp(buf+index, start_box.c_str(), start_box.length()) == 0)
1261 index += (start_box.length() - 1);
1262 start_comment = true;
1263 continue;
1265 if (memcmp(buf+index, start_stream.c_str(), start_stream.length()) == 0)
1267 index += (start_stream.length() - 1);
1268 start_comment = true;
1269 continue;
1271 if (buf[index] != ' ' && buf[index] != '\t' && buf[index] != '\n')
1272 break;
1274 else
1276 if (!indent_comment)
1278 if (buf[index] == ' ' || buf[index] == '\t' || buf[index] == '\n')
1279 continue;
1280 if (memcmp(buf+index, mark.c_str(), 3) == 0)
1282 index += 3;
1283 indent_comment = true;
1285 else
1286 break;
1288 else
1290 if (memcmp(buf+index, end_box.c_str(), end_box.length()) == 0)
1292 end_indent_comment = index + end_box.length() - 1;
1293 break;
1295 if (memcmp(buf+index, end_stream.c_str(), end_stream.length()) == 0)
1297 end_indent_comment = index + end_stream.length() - 1;
1298 break;
1303 SString mode = GetMode(language);
1304 if (mode.c_str() != "")
1306 SString comment ;
1307 comment += start_stream.c_str() ;
1308 comment += " ";
1309 comment += mark.c_str();
1310 comment += mode.c_str();
1311 comment += mark.c_str();
1312 comment += " ";
1313 comment += end_stream.c_str() ;
1315 if (indent_comment)
1317 SendEditor(SCI_SETSEL, 0, end_indent_comment + 1);
1318 SendEditorString(SCI_REPLACESEL, 0, comment.c_str());
1320 else
1322 comment += "\n\n";
1323 SendEditorString(SCI_INSERTTEXT, 0, comment.c_str());
1326 return TRUE;
1329 #endif
1332 * Return the length of the given line, not counting the EOL.
1334 int AnEditor::GetLineLength(int line) {
1335 return SendEditor(SCI_GETLINEENDPOSITION, line) - SendEditor(SCI_POSITIONFROMLINE, line);
1338 int AnEditor::GetCurrentLineNumber() {
1339 CharacterRange crange = GetSelection();
1340 int selStart = crange.cpMin;
1341 return SendEditor(SCI_LINEFROMPOSITION, selStart);
1344 int AnEditor::GetCurrentScrollPosition() {
1345 int lineDisplayTop = SendEditor(SCI_GETFIRSTVISIBLELINE);
1346 return SendEditor(SCI_DOCLINEFROMVISIBLE, lineDisplayTop);
1349 // Upon a character being added, AnEditor may decide to perform some action
1350 // such as displaying a completion list.
1351 void AnEditor::CharAdded(char ch) {
1352 CharacterRange crange = GetSelection();
1353 int selStart = crange.cpMin;
1354 int selEnd = crange.cpMax;
1355 if ((selEnd == selStart) && (selStart > 0)) {
1356 int style = SendEditor(SCI_GETSTYLEAT, selStart - 1, 0);
1357 if (style != 1) {
1358 if (SendEditor(SCI_CALLTIPACTIVE)) { // calltip is active
1359 } else if (SendEditor(SCI_AUTOCACTIVE)) { // word autocompletion
1360 } else if (HandleXml(ch)) {
1361 // Handled in the routine
1362 } else { // we don't have autocompetion nor calltip active
1363 if (indentMaintain && indentAutomatic)
1364 MaintainIndentation(ch);
1371 * This routine will auto complete XML or HTML tags that are still open by closing them
1372 * @parm ch The characer we are dealing with, currently only works with the '/' character
1373 * @return True if handled, false otherwise
1375 bool AnEditor::HandleXml(char ch) {
1376 // We're looking for this char
1377 // Quit quickly if not found
1378 if (ch != '>') {
1379 return false;
1382 // This may make sense only in certain languages
1383 if (lexLanguage != SCLEX_HTML && lexLanguage != SCLEX_XML) {
1384 return false;
1387 // If the user has turned us off, quit now.
1388 // Default is off
1389 SString value = props->GetExpanded("xml.auto.close.tags");
1390 if ((value.length() == 0) || (value == "0")) {
1391 return false;
1394 // Grab the last 512 characters or so
1395 int nCaret = SendEditor(SCI_GETCURRENTPOS);
1396 char sel[512];
1397 int nMin = nCaret - (sizeof(sel) - 1);
1398 if (nMin < 0) {
1399 nMin = 0;
1402 if (nCaret - nMin < 3) {
1403 return false; // Smallest tag is 3 characters ex. <p>
1405 GetRange(wEditor, nMin, nCaret, sel);
1406 sel[sizeof(sel) - 1] = '\0';
1408 if (sel[nCaret - nMin - 2] == '/') {
1409 // User typed something like "<br/>"
1410 return false;
1413 SString strFound = FindOpenXmlTag(sel, nCaret - nMin);
1415 if (strFound.length() > 0) {
1416 SendEditor(SCI_BEGINUNDOACTION);
1417 SString toInsert = "</";
1418 toInsert += strFound;
1419 toInsert += ">";
1420 SendEditorString(SCI_REPLACESEL, 0, toInsert.c_str());
1421 SetSelection(nCaret, nCaret);
1422 SendEditor(SCI_ENDUNDOACTION);
1423 return true;
1426 return false;
1429 /** Search backward through nSize bytes looking for a '<', then return the tag if any
1430 * @return The tag name
1432 SString AnEditor::FindOpenXmlTag(const char sel[], int nSize) {
1433 SString strRet = "";
1435 if (nSize < 3) {
1436 // Smallest tag is "<p>" which is 3 characters
1437 return strRet;
1439 const char* pBegin = &sel[0];
1440 const char* pCur = &sel[nSize - 1];
1442 pCur--; // Skip past the >
1443 while (pCur > pBegin) {
1444 if (*pCur == '<') {
1445 break;
1446 } else if (*pCur == '>') {
1447 break;
1449 --pCur;
1452 if (*pCur == '<') {
1453 pCur++;
1454 while (strchr(":_-.", *pCur) || isalnum(*pCur)) {
1455 strRet += *pCur;
1456 pCur++;
1460 // Return the tag name or ""
1461 return strRet;
1464 void AnEditor::GoMatchingBrace(bool select) {
1465 int braceAtCaret = -1;
1466 int braceOpposite = -1;
1467 bool isInside = FindMatchingBracePosition(true, braceAtCaret, braceOpposite, true);
1468 // Convert the character positions into caret positions based on whether
1469 // the caret position was inside or outside the braces.
1470 if (isInside) {
1471 if (braceOpposite > braceAtCaret) {
1472 braceAtCaret++;
1473 } else {
1474 braceOpposite++;
1476 } else { // Outside
1477 if (braceOpposite > braceAtCaret) {
1478 braceOpposite++;
1479 } else {
1480 braceAtCaret++;
1483 if (braceOpposite >= 0) {
1484 EnsureRangeVisible(braceOpposite, braceOpposite);
1485 if (select) {
1486 SetSelection(braceAtCaret, braceOpposite);
1487 } else {
1488 SetSelection(braceOpposite, braceOpposite);
1493 int ControlIDOfCommand(unsigned long wParam) {
1494 return wParam & 0xffff;
1497 long AnEditor::Command(int cmdID, long wParam, long lParam) {
1498 switch (cmdID) {
1500 case ANE_INSERTTEXT:
1501 SendEditor(SCI_INSERTTEXT,wParam,lParam);
1502 break;
1504 case ANE_GETBOOKMARK_POS:
1505 return GetBookmarkLine( wParam );
1506 break; /* pleonastico */
1508 case ANE_BOOKMARK_TOGGLE_LINE:
1509 BookmarkToggle( wParam );
1510 break;
1512 case ANE_UNDO:
1513 SendEditor(SCI_UNDO);
1514 break;
1516 case ANE_REDO:
1517 SendEditor(SCI_REDO);
1518 break;
1520 case ANE_CUT:
1521 SendEditor(SCI_CUT);
1522 break;
1524 case ANE_COPY:
1525 SendEditor(SCI_COPY);
1526 break;
1528 case ANE_PASTE:
1529 SendEditor(SCI_PASTE);
1530 break;
1532 case ANE_CLEAR:
1533 SendEditor(SCI_CLEAR);
1534 break;
1536 case ANE_SELECTALL:
1537 SendEditor(SCI_SELECTALL);
1538 break;
1540 case ANE_FIND:
1541 return Find (wParam, (char*) lParam);
1543 case ANE_GOTOLINE:
1544 SendEditor(SCI_GOTOLINE, wParam);
1545 break;
1547 case ANE_SETZOOM:
1548 SendEditor(SCI_SETZOOM, wParam);
1549 break;
1551 case ANE_MATCHBRACE:
1552 GoMatchingBrace(false);
1553 break;
1555 case ANE_SELECTBLOCK:
1556 SelectBlock();
1557 break;
1559 case ANE_SELECTTOBRACE:
1560 GoMatchingBrace(true);
1561 break;
1563 case ANE_GETBLOCKSTARTLINE:
1564 return GetBlockStartLine();
1566 case ANE_GETBLOCKENDLINE:
1567 return GetBlockEndLine();
1569 case ANE_GETCURRENTWORD:
1570 return GetCurrentWord((char*)wParam, (int)lParam);
1572 case ANE_GETWORDBEFORECARAT:
1573 return GetWordBeforeCarat((char*)wParam, (int)lParam);
1575 case ANE_SHOWCALLTIP:
1576 StartCallTip_new();
1577 break;
1579 case ANE_COMPLETECALLTIP:
1580 CompleteCallTip();
1581 break;
1583 case ANE_COMPLETE:
1584 StartAutoComplete();
1585 break;
1587 case ANE_COMPLETEWORD:
1588 StartAutoCompleteWord(false);
1589 break;
1591 case ANE_TOGGLE_FOLD:
1592 FoldToggle();
1593 break;
1595 case ANE_OPEN_FOLDALL:
1596 FoldOpenAll();
1597 break;
1599 case ANE_CLOSE_FOLDALL:
1600 FoldCloseAll();
1601 break;
1603 case ANE_UPRCASE:
1604 SendEditor(SCI_UPPERCASE);
1605 break;
1607 case ANE_LWRCASE:
1608 SendEditor(SCI_LOWERCASE);
1609 break;
1611 case ANE_EXPAND:
1612 SendEditor(SCI_TOGGLEFOLD, GetCurrentLineNumber());
1613 break;
1615 case ANE_LINENUMBERMARGIN:
1616 lineNumbers = wParam;
1617 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ? lineNumbersWidth : 0);
1618 break;
1620 case ANE_SELMARGIN:
1621 margin = wParam;
1622 SendEditor(SCI_SETMARGINWIDTHN, 1, margin ? marginWidth : 0);
1623 break;
1625 case ANE_FOLDMARGIN:
1626 foldMargin = wParam;
1627 SendEditor(SCI_SETMARGINWIDTHN, 2, foldMargin ? foldMarginWidth : 0);
1628 break;
1630 case ANE_VIEWEOL:
1631 SendEditor(SCI_SETVIEWEOL, wParam);
1632 break;
1634 case ANE_EOL_CRLF:
1635 SendEditor(SCI_SETEOLMODE, SC_EOL_CRLF);
1636 break;
1638 case ANE_EOL_CR:
1639 SendEditor(SCI_SETEOLMODE, SC_EOL_CR);
1640 break;
1642 case ANE_EOL_LF:
1643 SendEditor(SCI_SETEOLMODE, SC_EOL_LF);
1644 break;
1646 case ANE_EOL_CONVERT:
1647 switch (wParam) {
1648 case ANE_EOL_CRLF:
1649 SendEditor(SCI_SETEOLMODE, SC_EOL_CRLF);
1650 SendEditor(SCI_CONVERTEOLS, SC_EOL_CRLF);
1651 break;
1652 case ANE_EOL_LF:
1653 SendEditor(SCI_SETEOLMODE, SC_EOL_LF);
1654 SendEditor(SCI_CONVERTEOLS, SC_EOL_LF);
1655 break;
1656 case ANE_EOL_CR:
1657 SendEditor(SCI_SETEOLMODE, SC_EOL_CR);
1658 SendEditor(SCI_CONVERTEOLS, SC_EOL_CR);
1659 break;
1660 default:
1661 SendEditor(SCI_CONVERTEOLS, SendEditor(SCI_GETEOLMODE));
1662 break;
1664 break;
1666 case ANE_WORDPARTLEFT:
1667 SendEditor(SCI_WORDPARTLEFT);
1668 break;
1670 case ANE_WORDPARTLEFTEXTEND:
1671 SendEditor(SCI_WORDPARTLEFTEXTEND);
1672 break;
1674 case ANE_WORDPARTRIGHT:
1675 SendEditor(SCI_WORDPARTRIGHT);
1676 break;
1678 case ANE_WORDPARTRIGHTEXTEND:
1679 SendEditor(SCI_WORDPARTRIGHTEXTEND);
1680 break;
1682 case ANE_VIEWSPACE:
1683 ViewWhitespace(wParam);
1684 break;
1686 case ANE_VIEWGUIDES:
1687 SendEditor(SCI_SETINDENTATIONGUIDES, wParam);
1688 break;
1690 case ANE_BOOKMARK_TOGGLE:
1691 BookmarkToggle();
1692 break;
1693 case ANE_BOOKMARK_FIRST:
1694 BookmarkFirst();
1695 break;
1696 case ANE_BOOKMARK_PREV:
1697 BookmarkPrev();
1698 break;
1699 case ANE_BOOKMARK_NEXT:
1700 BookmarkNext();
1701 break;
1702 case ANE_BOOKMARK_LAST:
1703 BookmarkLast();
1704 break;
1705 case ANE_BOOKMARK_CLEAR:
1706 BookmarkClear();
1707 break;
1709 case ANE_SETTABSIZE:
1710 SendEditor(SCI_SETTABWIDTH, wParam);
1711 break;
1713 case ANE_SETLANGUAGE:
1714 SetOverrideLanguage(wParam);
1715 break;
1717 case ANE_SETHILITE:
1718 ReadProperties((char*)wParam, (char **)lParam);
1719 SendEditor(SCI_COLOURISE, 0, -1);
1720 break;
1722 case ANE_SETACCELGROUP:
1723 SetAccelGroup((GtkAccelGroup*)wParam);
1724 break;
1726 case ANE_GETTEXTRANGE: {
1727 guint start, end;
1728 if(wParam == lParam) return 0;
1729 start = (guint) MINIMUM(wParam, lParam);
1730 end = (guint) MAXIMUM(wParam, lParam);
1731 gchar *buff = (gchar*) g_malloc(end-start+10);
1732 if(!buff) return 0;
1733 GetRange(start, end, buff, false);
1734 return (long) buff;
1736 break;
1738 case ANE_INDENT_INCREASE:
1739 IndentationIncrease();
1740 break;
1742 case ANE_INDENT_DECREASE:
1743 IndentationDecrease();
1744 break;
1746 case ANE_GETLENGTH:
1747 return SendEditor(SCI_GETLENGTH);
1749 case ANE_GET_LINENO:
1750 return GetCurrentLineNumber();
1752 case ANE_LINEWRAP:
1753 SetLineWrap((bool)wParam);
1754 break;
1756 case ANE_READONLY:
1757 SetReadOnly((bool)wParam);
1758 break;
1760 case ANE_GETSTYLEDTEXT: {
1761 guint start, end;
1762 if(wParam == lParam) return 0;
1763 start = (guint) MINIMUM(wParam, lParam);
1764 end = (guint) MAXIMUM(wParam, lParam);
1765 /* Allocate a bit more space to allow reading multi
1766 * byte characters more easily */
1767 gchar *buff = (gchar*) g_malloc((end-start+10)*2);
1768 if(!buff) return 0;
1769 GetRange(start, end, buff, true);
1770 memset (buff + (end-start) * 2, 0, 20);
1771 return (long) buff;
1773 break;
1774 case ANE_TEXTWIDTH:
1775 return SendEditor(SCI_TEXTWIDTH, wParam, lParam);
1776 case ANE_GETLANGUAGE:
1777 return (long) language.c_str();
1779 case ANE_BLOCKCOMMENT:
1780 return StartBlockComment();
1782 case ANE_BOXCOMMENT:
1783 return StartBoxComment();
1785 case ANE_STREAMCOMMENT:
1786 return StartStreamComment();
1788 case ANE_CUSTOMINDENT:
1789 return InsertCustomIndent();
1791 case ANE_WORDSELECT:
1792 WordSelect();
1793 break;
1795 case ANE_LINESELECT:
1796 LineSelect();
1797 break;
1799 case ANE_GETCURRENTPOS:
1800 return SendEditor(SCI_GETCURRENTPOS);
1802 case ANE_GOTOPOS:
1803 return SendEditor(SCI_GOTOPOS, wParam);
1805 case ANE_SETWRAPBOOKMARKS:
1806 // Nothing to do.
1807 break;
1809 case ANE_SETAUTOINDENTATION:
1810 indentAutomatic = wParam;
1811 break;
1813 case ANE_SETUSETABFORINDENT:
1814 SendEditor(SCI_SETUSETABS, wParam);
1815 break;
1817 case ANE_SETINDENTSIZE:
1818 indentSize = wParam;
1819 SendEditor(SCI_SETINDENT, wParam);
1820 break;
1822 case ANE_SETINDENTBRACESCHECK:
1823 bracesCheck = wParam;
1824 break;
1826 case ANE_SETINDENTOPENING:
1827 indentOpening = wParam;
1828 break;
1830 case ANE_SETINDENTCLOSING:
1831 indentClosing = wParam;
1832 break;
1834 case ANE_SETINDENTMAINTAIN:
1835 props->Set ("indent.maintain.*", wParam ? "1" : "0");
1836 indentMaintain = wParam;
1837 break;
1839 case ANE_SETTABINDENTS:
1840 SendEditor(SCI_SETTABINDENTS, wParam);
1841 break;
1843 case ANE_SETBACKSPACEUNINDENTS:
1844 SendEditor(SCI_SETBACKSPACEUNINDENTS, wParam);
1845 break;
1847 case ANE_SETFOLDSYMBOLS:
1848 SetFoldSymbols(reinterpret_cast<char *> (wParam));
1849 break;
1851 case ANE_SETFOLDUNDERLINE:
1852 if (wParam)
1853 SendEditor(SCI_SETFOLDFLAGS, props->GetInt("fold.flags"));
1854 else
1855 SendEditor(SCI_SETFOLDFLAGS, 0);
1856 break;
1857 case ANE_SETLINENUMWIDTH:
1858 lineNumbersWidth = wParam;
1859 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ? lineNumbersWidth : 0);
1860 break;
1861 case ANE_SETEDGECOLUMN:
1862 SendEditor(SCI_SETEDGECOLUMN, wParam);
1863 break;
1864 default:
1865 break;
1867 return 0;
1870 void AnEditor::FoldChanged(int line, int levelNow, int levelPrev) {
1871 if (levelNow & SC_FOLDLEVELHEADERFLAG) {
1872 SendEditor(SCI_SETFOLDEXPANDED, line, 1);
1873 } else if (levelPrev & SC_FOLDLEVELHEADERFLAG) {
1874 if (!SendEditor(SCI_GETFOLDEXPANDED, line)) {
1875 // Removing the fold from one that has been contracted so should expand
1876 // otherwise lines are left invisible with no way to make them visible
1877 Expand(line, true, false, 0, levelPrev);
1882 void AnEditor::Expand(int &line, bool doExpand, bool force, int visLevels, int level) {
1883 int lineMaxSubord = SendEditor(SCI_GETLASTCHILD, line, level);
1884 line++;
1885 while (line <= lineMaxSubord) {
1886 if (force) {
1887 if (visLevels > 0)
1888 SendEditor(SCI_SHOWLINES, line, line);
1889 else
1890 SendEditor(SCI_HIDELINES, line, line);
1891 } else {
1892 if (doExpand)
1893 SendEditor(SCI_SHOWLINES, line, line);
1895 int levelLine = level;
1896 if (levelLine ==-1)
1897 levelLine = SendEditor(SCI_GETFOLDLEVEL, line);
1898 if (levelLine & SC_FOLDLEVELHEADERFLAG) {
1899 if (force) {
1900 if (visLevels > 1)
1901 SendEditor(SCI_SETFOLDEXPANDED, line, 1);
1902 else
1903 SendEditor(SCI_SETFOLDEXPANDED, line, 0);
1904 Expand(line, doExpand, force, visLevels - 1);
1905 } else {
1906 if (doExpand && SendEditor(SCI_GETFOLDEXPANDED, line)) {
1907 Expand(line, true, force, visLevels - 1);
1908 } else {
1909 Expand(line, false, force, visLevels - 1);
1912 } else {
1913 line++;
1918 void AnEditor::FoldCode(bool expanding) {
1919 int maxLine = SendEditor (SCI_GETTEXTLENGTH);
1920 SendEditor(SCI_COLOURISE, 0, -1);
1921 for (int line = 0; line < maxLine; line++) {
1922 int level = SendEditor(SCI_GETFOLDLEVEL, line);
1923 if ((level & SC_FOLDLEVELHEADERFLAG) &&
1924 (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK))) {
1925 if (expanding) {
1926 SendEditor(SCI_SETFOLDEXPANDED, line, 1);
1927 Expand(line, true);
1928 line--;
1929 } else {
1930 int lineMaxSubord = SendEditor(SCI_GETLASTCHILD, line, -1);
1931 SendEditor(SCI_SETFOLDEXPANDED, line, 0);
1932 if (lineMaxSubord > line)
1933 SendEditor(SCI_HIDELINES, line + 1, lineMaxSubord);
1939 void AnEditor::FoldOpenAll() {
1940 FoldCode (true);
1943 void AnEditor::FoldCloseAll() {
1944 FoldCode (false);
1947 void AnEditor::FoldToggle() {
1948 int curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
1949 int level = SendEditor(SCI_GETFOLDLEVEL, curLine);
1950 if (level & SC_FOLDLEVELHEADERFLAG) {
1951 SendEditor(SCI_TOGGLEFOLD, curLine);
1952 return;
1954 int parent = SendEditor (SCI_GETFOLDPARENT, curLine);
1955 int lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
1956 if (curLine > parent && curLine <= lastChild)
1958 SendEditor(SCI_TOGGLEFOLD, parent);
1959 SendEditor(SCI_SETCURRENTPOS, SendEditor (SCI_POSITIONFROMLINE, parent));
1960 SendEditor(SCI_GOTOLINE, parent);
1962 else
1963 gdk_beep ();
1966 void AnEditor::SelectBlock () {
1967 int curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
1968 int parent = SendEditor (SCI_GETFOLDPARENT, curLine);
1969 int lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
1970 if (curLine > parent && curLine <= lastChild)
1972 gint start, end;
1973 start = SendEditor(SCI_POSITIONFROMLINE, parent);
1974 end = SendEditor(SCI_POSITIONFROMLINE, lastChild+1);
1975 SetSelection(start, end);
1977 else
1978 gdk_beep ();
1981 int AnEditor::GetBlockStartLine (int curLine) {
1982 if(curLine < 0)
1984 curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
1986 int level = SendEditor(SCI_GETFOLDLEVEL, curLine);
1987 if (level & SC_FOLDLEVELHEADERFLAG) {
1988 return curLine;
1990 int parent = -1;
1991 int lastChild = curLine;
1992 while(parent == -1)
1994 parent = SendEditor (SCI_GETFOLDPARENT, lastChild);
1995 if (parent == -1)
1997 return -1;
1999 lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
2000 if (curLine > parent && curLine <= lastChild)
2002 return parent;
2004 lastChild = parent - 1;
2005 parent = -1;
2007 return -1;
2010 int AnEditor::GetBlockEndLine (int curLine) {
2011 if(curLine < 0)
2013 curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
2015 int level = SendEditor(SCI_GETFOLDLEVEL, curLine);
2016 if (level & SC_FOLDLEVELHEADERFLAG) {
2017 /* this may be a problem when we use this function on "start" block line */
2018 return curLine;
2020 int parent = -1;
2021 int lastChild = curLine;
2022 while(parent == -1)
2024 parent = SendEditor (SCI_GETFOLDPARENT, lastChild);
2025 if (parent == -1)
2027 return -1;
2029 lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
2030 if (curLine > parent && curLine <= lastChild)
2032 return lastChild;
2034 lastChild = parent - 1;
2035 parent = -1;
2037 return -1;
2040 void AnEditor::EnsureRangeVisible(int posStart, int posEnd) {
2041 int lineStart = SendEditor(SCI_LINEFROMPOSITION, Platform::Minimum(posStart, posEnd));
2042 int lineEnd = SendEditor(SCI_LINEFROMPOSITION, Platform::Maximum(posStart, posEnd));
2043 for (int line = lineStart; line <= lineEnd; line++) {
2044 SendEditor(SCI_ENSUREVISIBLE, line);
2048 void AnEditor::SetLineWrap(bool wrap) {
2049 wrapLine = wrap;
2050 SendEditor(SCI_SETWRAPMODE, wrapLine ? SC_WRAP_WORD : SC_WRAP_NONE);
2051 SendEditor(SCI_SETHSCROLLBAR, !wrapLine);
2054 void AnEditor::SetReadOnly(bool readonly) {
2055 isReadOnly = readonly;
2056 SendEditor(SCI_SETREADONLY, isReadOnly);
2059 bool AnEditor::MarginClick(int position, int modifiers) {
2060 int lineClick = SendEditor(SCI_LINEFROMPOSITION, position);
2061 // SendEditor(SCI_GETFOLDLEVEL, lineClick) & SC_FOLDLEVELHEADERFLAG);
2062 if (modifiers & SCMOD_SHIFT) {
2063 FoldCloseAll();
2064 } else if (modifiers & SCMOD_CTRL) {
2065 FoldOpenAll();
2066 } else if (SendEditor(SCI_GETFOLDLEVEL, lineClick) & SC_FOLDLEVELHEADERFLAG) {
2067 if (modifiers & SCMOD_SHIFT) {
2068 // Ensure all children visible
2069 SendEditor(SCI_SETFOLDEXPANDED, lineClick, 1);
2070 Expand(lineClick, true, true, 100);
2071 } else if (modifiers & SCMOD_CTRL) {
2072 if (SendEditor(SCI_GETFOLDEXPANDED, lineClick)) {
2073 // Contract this line and all children
2074 SendEditor(SCI_SETFOLDEXPANDED, lineClick, 0);
2075 Expand(lineClick, false, true, 0);
2076 } else {
2077 // Expand this line and all children
2078 SendEditor(SCI_SETFOLDEXPANDED, lineClick, 1);
2079 Expand(lineClick, true, true, 100);
2081 } else {
2082 // Toggle this line
2083 SendEditor(SCI_TOGGLEFOLD, lineClick);
2086 return true;
2089 #if 0
2090 gint AnEditor::KeyPressEvent(GtkWidget *, GdkEventKey *event, AnEditor *anedit) {
2091 return anedit->KeyPress(event->state, event->keyval);
2093 #endif
2095 void AnEditor::NotifySignal(GtkWidget *, gint /*wParam*/, gpointer lParam, AnEditor *anedit) {
2096 anedit->Notify(reinterpret_cast<SCNotification *>(lParam));
2099 // FIXME:
2100 #if 0
2101 void
2102 eval_output_arrived_for_aneditor(GList* lines, gpointer data)
2104 // We expect lines->data to be a string of the form VARIABLE = VALUE,
2105 // and 'data' to be a pointer to an object of type
2106 // 'ExpressionEvaluationTipInfo'.
2108 if (data == NULL)
2109 return;
2111 auto_ptr<ExpressionEvaluationTipInfo> info(
2112 (ExpressionEvaluationTipInfo *) data);
2114 if (info->editor == NULL)
2115 return;
2117 if (info->editor != aneditor_get(AnEditor::focusedID))
2118 return;
2120 info->editor->EvalOutputArrived(lines, info->textPos, info->expression);
2123 void AnEditor::EvalOutputArrived(GList* lines, int textPos,
2124 const string &expression) {
2126 if (textPos <= 0)
2127 return;
2129 // Return if debug Tip has been canceled
2130 if (!debugTipOn)
2131 return;
2133 if (g_list_length(lines) == 0 || lines->data == NULL)
2134 return;
2136 string result = (char *) lines->data;
2137 string::size_type posEquals = result.find(" = ");
2138 if (posEquals != string::npos)
2139 result.replace(0, posEquals, expression);
2141 SendEditorString(SCI_CALLTIPSHOW, textPos, result.c_str());
2142 SendEditor(SCI_CALLTIPSETHLT, 0, result.length());
2145 void AnEditor::EndDebugEval() {
2146 if (debugTipOn)
2148 SendEditor(SCI_CALLTIPCANCEL);
2149 debugTipOn = false;
2153 void AnEditor::HandleDwellStart(int mousePos) {
2154 if (mousePos == -1)
2155 return;
2157 char expr[256];
2158 if (!debugger_is_active() || !debugger_is_ready())
2160 // Do not show expression tip if it can't be shown.
2161 // string s = string(expr) + ": " + _("debugger not active");
2162 // SendEditorString(SCI_CALLTIPSHOW, mousePos, s.c_str());
2163 return;
2165 // If debug tip is already running, return.
2166 if (debugTipOn)
2167 return;
2169 CharacterRange crange = GetSelection();
2170 if (crange.cpMin == crange.cpMax
2171 || mousePos < crange.cpMin
2172 || mousePos >= crange.cpMax)
2174 // There is no selection, or the mouse pointer is
2175 // out of the selection, so we search for a word
2176 // around the mouse pointer:
2177 if (!GetWordAtPosition(expr, sizeof(expr), mousePos))
2178 return;
2180 else
2182 long lensel = crange.cpMax - crange.cpMin;
2183 long max = sizeof(expr) - 1;
2184 guint end = (lensel < max ? crange.cpMax : crange.cpMin + max);
2185 GetRange(crange.cpMin, end, expr, false);
2187 // If there is any control character except TAB
2188 // in the expression, disregard it.
2189 size_t i;
2190 for (i = 0; i < end - crange.cpMin; i++)
2191 if ((unsigned char) expr[i] < ' ' && expr[i] != '\t')
2192 return;
2193 if (i < end - crange.cpMin)
2194 return;
2197 // Imitation of on_eval_ok_clicked():
2198 // The function eval_output_arrived_for_aneditor() will
2199 // be called eventually by the debugger with the result
2200 // of the print command for 'expr', and with the 'info'
2201 // pointer. That function must call delete on 'info'.
2203 // We don't turn GDB "pretty printing" on because we want
2204 // the entire value on a single line, in the case of a
2205 // struct or class.
2206 // We don't want static members of classes to clutter up
2207 // the displayed tip, however.
2209 ExpressionEvaluationTipInfo *info =
2210 new ExpressionEvaluationTipInfo(this, mousePos, expr);
2211 debugger_query_evaluate_expr_tip (expr, eval_output_arrived_for_aneditor, info);
2212 debugger_query_execute ();
2213 debugTipOn = true;
2215 #endif
2217 #if 0
2218 int AnEditor::KeyPress(unsigned int state, unsigned int keyval){
2220 unsigned int mask = GDK_SHIFT_MASK | GDK_LOCK_MASK |
2221 GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_MOD3_MASK |
2222 GDK_MOD4_MASK | GDK_MOD5_MASK;
2223 if (state & mask)
2224 return false;
2226 // Trap 'TAB' key for automatic indentation.
2227 // printf ("Key is '%c'\n", notification->ch);
2228 if ((keyval == GDK_Tab) &&
2229 (lexLanguage == SCLEX_CPP) &&
2230 (!indentMaintain) &&
2231 (props->GetInt("indent.automatic")) &&
2232 (!SendEditor(SCI_CALLTIPACTIVE)) &&
2233 (!SendEditor(SCI_AUTOCACTIVE))) {
2235 CharacterRange crange = GetSelection();
2236 int selStart = crange.cpMin;
2237 int selEnd = crange.cpMax;
2239 if (selStart == selEnd) {
2240 AutomaticIndentation('\t');
2241 return true;
2244 return false;
2246 #endif
2248 void AnEditor::Notify(SCNotification *notification) {
2249 switch (notification->nmhdr.code) {
2250 case SCN_CALLTIPCLICK:
2251 if (notification->position == 1) {
2252 call_tip_node.def_index--;
2253 if (call_tip_node.def_index < 0)
2254 call_tip_node.def_index = 0;
2256 if (notification->position == 2) {
2257 call_tip_node.def_index++;
2258 if (call_tip_node.def_index >= call_tip_node.max_def)
2259 call_tip_node.def_index = call_tip_node.max_def - 1;
2261 ResumeCallTip (false);
2262 break;
2263 case SCN_KEY: {
2264 if(!accelGroup) break;
2265 int mods = 0;
2266 if (notification->modifiers & SCMOD_SHIFT)
2267 mods |= GDK_SHIFT_MASK;
2268 if (notification->modifiers & SCMOD_CTRL)
2269 mods |= GDK_CONTROL_MASK;
2270 if (notification->modifiers & SCMOD_ALT)
2271 mods |= GDK_MOD1_MASK;
2272 gtk_accel_groups_activate(G_OBJECT (accelGroup), notification->ch,
2273 static_cast<GdkModifierType>(mods));
2276 case SCN_CHARADDED:
2277 CharAdded(static_cast<char>(notification->ch));
2278 break;
2280 case SCN_SAVEPOINTREACHED:
2281 isDirty = false;
2282 break;
2284 case SCN_SAVEPOINTLEFT:
2285 isDirty = true;
2286 break;
2288 case SCN_UPDATEUI:
2290 int pos = SendEditor(SCI_GETCURRENTPOS);
2291 BraceMatch(true);
2292 if (SendEditor(SCI_CALLTIPACTIVE) ) {
2293 // if we have a caret movement on left or right
2294 if (abs(pos - lastPos) == 1 ) {
2295 ContinueCallTip_new();
2298 lastPos = pos;
2300 break;
2302 case SCN_MODIFIED:
2303 if (notification->modificationType == SC_MOD_CHANGEFOLD) {
2304 FoldChanged(notification->line,
2305 notification->foldLevelNow, notification->foldLevelPrev);
2307 break;
2309 case SCN_MARGINCLICK:
2310 if (notification->margin == 2)
2311 MarginClick(notification->position, notification->modifiers);
2312 break;
2314 case SCN_NEEDSHOWN: {
2315 EnsureRangeVisible(notification->position, notification->position + notification->length);
2317 break;
2319 case SCN_DWELLSTART:
2320 HandleDwellStart(notification->position);
2321 break;
2323 case SCN_DWELLEND:
2324 EndDebugEval();
2325 // SendEditor(SCI_CALLTIPCANCEL);
2326 break;
2331 static int IntFromHexDigit(const char ch) {
2332 if (isdigit(ch))
2333 return ch - '0';
2334 else if (ch >= 'A' && ch <= 'F')
2335 return ch - 'A' + 10;
2336 else if (ch >= 'a' && ch <= 'f')
2337 return ch - 'a' + 10;
2338 else
2339 return 0;
2342 static Colour ColourFromString(const char *val) {
2343 int r = IntFromHexDigit(val[1]) * 16 + IntFromHexDigit(val[2]);
2344 int g = IntFromHexDigit(val[3]) * 16 + IntFromHexDigit(val[4]);
2345 int b = IntFromHexDigit(val[5]) * 16 + IntFromHexDigit(val[6]);
2346 return Colour(r, g, b);
2349 static long ColourOfProperty(PropSetFile *props, const char *key, ColourDesired colourDefault) {
2350 SString colour = props->Get(key);
2351 if (colour.length()) {
2352 return ColourFromString(colour.c_str()).AsLong();
2354 return colourDefault.AsLong();
2357 void AnEditor::SetGtkStyle(Window &win, int style) {
2358 GtkWidgetPath *path;
2359 GtkStyleContext *context;
2360 GdkRGBA fore;
2361 GdkRGBA back;
2363 /* Get theme style information for view widget */
2364 context = gtk_style_context_new ();
2365 gtk_style_context_set_parent (context, gtk_widget_get_style_context (GTK_WIDGET (win.GetID())));
2366 path = gtk_widget_path_copy (gtk_widget_get_path (GTK_WIDGET (win.GetID())));
2367 gtk_widget_path_append_type (path, GTK_TYPE_TEXT_VIEW);
2368 gtk_style_context_set_path (context, path);
2369 gtk_widget_path_free (path);
2370 gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2371 gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fore);
2372 gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &back);
2373 g_object_unref (context);
2375 Platform::SendScintilla(win.GetID(), SCI_STYLESETFORE, style, (gint)(fore.red * 255) | ((gint)(fore.green * 255) << 8) | ((gint)(fore.blue *255) << 16));
2376 Platform::SendScintilla(win.GetID(), SCI_STYLESETBACK, style, (gint)(back.red * 255) | ((gint)(back.green * 255) << 8) | ((gint)(back.blue *255) << 16));
2379 void AnEditor::SetOneStyle(Window &win, int style, const char *s) {
2380 char *val = StringDup(s);
2381 char *opt = val;
2382 while (opt) {
2383 char *cpComma = strchr(opt, ',');
2384 if (cpComma)
2385 *cpComma = '\0';
2386 char *colon = strchr(opt, ':');
2387 if (colon)
2388 *colon++ = '\0';
2389 if (0 == strcmp(opt, "italics"))
2390 Platform::SendScintilla(win.GetID(), SCI_STYLESETITALIC, style, 1);
2391 if (0 == strcmp(opt, "notitalics"))
2392 Platform::SendScintilla(win.GetID(), SCI_STYLESETITALIC, style, 0);
2393 if (0 == strcmp(opt, "bold"))
2394 Platform::SendScintilla(win.GetID(), SCI_STYLESETBOLD, style, 1);
2395 if (0 == strcmp(opt, "notbold"))
2396 Platform::SendScintilla(win.GetID(), SCI_STYLESETBOLD, style, 0);
2397 if (0 == strcmp(opt, "font"))
2398 Platform::SendScintilla(win.GetID(), SCI_STYLESETFONT, style, reinterpret_cast<long>(colon));
2399 if (0 == strcmp(opt, "fore"))
2400 Platform::SendScintilla(win.GetID(), SCI_STYLESETFORE, style, ColourFromString(colon).AsLong());
2401 if (0 == strcmp(opt, "back"))
2402 Platform::SendScintilla(win.GetID(), SCI_STYLESETBACK, style, ColourFromString(colon).AsLong());
2403 if (0 == strcmp(opt, "size"))
2404 Platform::SendScintilla(win.GetID(), SCI_STYLESETSIZE, style, atoi(colon));
2405 if (0 == strcmp(opt, "eolfilled"))
2406 Platform::SendScintilla(win.GetID(), SCI_STYLESETEOLFILLED, style, 1);
2407 if (0 == strcmp(opt, "noteolfilled"))
2408 Platform::SendScintilla(win.GetID(), SCI_STYLESETEOLFILLED, style, 0);
2409 if (0 == strcmp(opt, "underlined"))
2410 Platform::SendScintilla(win.GetID(), SCI_STYLESETUNDERLINE, style, 1);
2411 if (0 == strcmp(opt, "notunderlined"))
2412 Platform::SendScintilla(win.GetID(), SCI_STYLESETUNDERLINE, style, 0);
2413 if (0 == strcmp(opt, "case")) {
2414 if (*colon == 'u') {
2415 Platform::SendScintilla(win.GetID(), SCI_STYLESETCASE, style, SC_CASE_UPPER);
2416 } else if (*colon == 'l') {
2417 Platform::SendScintilla(win.GetID(), SCI_STYLESETCASE, style, SC_CASE_LOWER);
2418 } else {
2419 Platform::SendScintilla(win.GetID(), SCI_STYLESETCASE, style, SC_CASE_MIXED);
2422 if (0 == strcmp(opt, "visible"))
2423 Platform::SendScintilla(win.GetID(), SCI_STYLESETVISIBLE, style, 1);
2424 if (0 == strcmp(opt, "notvisible"))
2425 Platform::SendScintilla(win.GetID(), SCI_STYLESETVISIBLE, style, 0);
2426 if (0 == strcmp(opt, "changeable"))
2427 Platform::SendScintilla(win.GetID(), SCI_STYLESETCHANGEABLE, style, 1);
2428 if (0 == strcmp(opt, "notchangeable"))
2429 Platform::SendScintilla(win.GetID(), SCI_STYLESETCHANGEABLE, style, 0);
2430 if (cpComma)
2431 opt = cpComma + 1;
2432 else
2433 opt = 0;
2435 if (val)
2436 delete []val;
2437 Platform::SendScintilla(win.GetID(), SCI_STYLESETCHARACTERSET, style, characterSet);
2440 void AnEditor::SetStyleFor(Window &win, const char *lang) {
2441 for (int style = 0; style <= STYLE_MAX; style++) {
2442 if (style != STYLE_DEFAULT) {
2443 char key[200];
2444 sprintf(key, "style.%s.%0d", lang, style);
2445 SString sval = props->GetExpanded(key);
2446 // g_print ("Style for %s:%0d == %s\n", lang, style, sval.c_str());
2447 SetOneStyle(win, style, sval.c_str());
2452 void AnEditor::UpdateStyle(void) {
2454 char key[200];
2455 SString sval;
2457 SendEditor(SCI_STYLERESETDEFAULT, 0, 0);
2459 SetGtkStyle(wEditor, STYLE_DEFAULT);
2461 sprintf(key, "style.%s.%0d", "*", STYLE_DEFAULT);
2462 sval = props->GetNewExpand(key, "");
2463 SetOneStyle(wEditor, STYLE_DEFAULT, sval.c_str());
2465 sprintf(key, "style.%s.%0d", language.c_str(), STYLE_DEFAULT);
2466 sval = props->GetNewExpand(key, "");
2467 SetOneStyle(wEditor, STYLE_DEFAULT, sval.c_str());
2469 SendEditor(SCI_STYLECLEARALL, 0, 0);
2471 SetStyleFor(wEditor, "*");
2472 SetStyleFor(wEditor, language.c_str());
2475 void lowerCaseString(char *s) {
2476 while (*s) {
2477 *s = static_cast<char>(tolower(*s));
2478 s++;
2482 SString AnEditor::ExtensionFileName() {
2483 if (overrideExtension.length())
2484 return overrideExtension;
2485 else if (fileName[0]) {
2486 // Force extension to lower case
2487 char fileNameWithLowerCaseExtension[MAX_PATH];
2488 strcpy(fileNameWithLowerCaseExtension, fileName);
2489 char *extension = strrchr(fileNameWithLowerCaseExtension, '.');
2490 if (extension) {
2491 lowerCaseString(extension);
2493 return SString(fileNameWithLowerCaseExtension);
2494 } else
2495 return props->Get("default.file.ext");
2498 void AnEditor::ForwardPropertyToEditor(const char *key) {
2499 SString value = props->Get(key);
2500 SendEditorString(SCI_SETPROPERTY,
2501 reinterpret_cast<uptr_t>(key), value.c_str());
2504 SString AnEditor::FindLanguageProperty(const char *pattern, const char *defaultValue) {
2505 SString key = pattern;
2506 key.substitute("*", language.c_str());
2507 SString ret = props->GetExpanded(key.c_str());
2508 if (ret == "")
2509 ret = props->GetExpanded(pattern);
2510 if (ret == "")
2511 ret = defaultValue;
2512 return ret;
2515 void AnEditor::ReadProperties(const char *fileForExt, char **typedef_hl) {
2516 //DWORD dwStart = timeGetTime();
2517 int blink_time = 500;
2519 if (fileForExt)
2520 strcpy (fileName, fileForExt);
2521 else
2522 fileName[0] = '\0';
2524 SString fileNameForExtension;
2525 if(overrideExtension.length())
2526 fileNameForExtension = overrideExtension;
2527 else {
2528 fileNameForExtension = fileForExt;
2531 language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
2532 SendEditorString(SCI_SETLEXERLANGUAGE, 0, language.c_str());
2533 lexLanguage = SendEditor(SCI_GETLEXER);
2535 if ((lexLanguage == SCLEX_HTML) || (lexLanguage == SCLEX_XML))
2536 SendEditor(SCI_SETSTYLEBITS, 7);
2537 else
2538 SendEditor(SCI_SETSTYLEBITS, 5);
2540 SendEditor(SCI_SETLEXER, lexLanguage);
2542 SString kw0 = props->GetNewExpand("keywords.", fileNameForExtension.c_str());
2543 SendEditorString(SCI_SETKEYWORDS, 0, kw0.c_str());
2544 SString kw2 = props->GetNewExpand("keywords3.", fileNameForExtension.c_str());
2545 SendEditorString(SCI_SETKEYWORDS, 2, kw2.c_str());
2546 /* For C/C++ projects, get list of typedefs for colorizing */
2547 if (SCLEX_CPP == lexLanguage)
2549 SString kw1 = props->GetNewExpand("keywords2.", fileNameForExtension.c_str());
2550 SString kw3 = props->GetNewExpand("keywords4.", fileNameForExtension.c_str());
2551 if (typedef_hl != NULL)
2553 if (typedef_hl[0] != NULL)
2555 kw3 += ' ';
2556 kw3 += typedef_hl[0];
2558 if (typedef_hl[1] != NULL)
2560 kw1 += ' ';
2561 kw1 += typedef_hl[1];
2564 SendEditorString(SCI_SETKEYWORDS, 3, kw3.c_str());
2565 SendEditorString(SCI_SETKEYWORDS, 1, kw1.c_str());
2567 else
2569 SString kw1 = props->GetNewExpand("keywords2.", fileNameForExtension.c_str());
2570 SendEditorString(SCI_SETKEYWORDS, 1, kw1.c_str());
2571 SString kw3 = props->GetNewExpand("keywords4.", fileNameForExtension.c_str());
2572 SendEditorString(SCI_SETKEYWORDS, 3, kw3.c_str());
2573 SString kw4 = props->GetNewExpand("keywords5.", fileNameForExtension.c_str());
2574 SendEditorString(SCI_SETKEYWORDS, 4, kw4.c_str());
2575 SString kw5 = props->GetNewExpand("keywords6.", fileNameForExtension.c_str());
2576 SendEditorString(SCI_SETKEYWORDS, 5, kw5.c_str());
2579 ForwardPropertyToEditor("fold");
2580 ForwardPropertyToEditor("fold.use.plus");
2581 ForwardPropertyToEditor("fold.comment");
2582 ForwardPropertyToEditor("fold.comment.python");
2583 ForwardPropertyToEditor("fold.compact");
2584 ForwardPropertyToEditor("fold.html");
2585 ForwardPropertyToEditor("fold.preprocessor");
2586 ForwardPropertyToEditor("fold.quotes.python");
2587 ForwardPropertyToEditor("styling.within.preprocessor");
2588 ForwardPropertyToEditor("tab.timmy.whinge.level");
2589 ForwardPropertyToEditor("asp.default.language");
2591 // codePage = props->GetInt("code.page");
2592 //if (unicodeMode != uni8Bit) {
2593 // Override properties file to ensure Unicode displayed.
2594 // codePage = SC_CP_UTF8;
2595 // }
2596 // SendEditor(SCI_SETCODEPAGE, codePage);
2598 // Use unicode everytime.
2599 SendEditor(SCI_SETCODEPAGE, SC_CP_UTF8);
2601 characterSet = props->GetInt("character.set");
2602 setlocale(LC_CTYPE, props->Get("LC_CTYPE").c_str());
2604 SendEditor(SCI_SETCARETFORE,
2605 ColourOfProperty(props, "caret.fore", ColourDesired(0, 0, 0)));
2606 SendEditor(SCI_SETCARETWIDTH, props->GetInt("caret.width", 1));
2607 SendEditor(SCI_SETMOUSEDWELLTIME, props->GetInt("dwell.period", 750), 0);
2609 SString caretLineBack = props->Get("caret.line.back");
2610 if (caretLineBack.length()) {
2611 SendEditor(SCI_SETCARETLINEVISIBLE, 1);
2612 SendEditor(SCI_SETCARETLINEBACK,
2613 ColourFromString(caretLineBack.c_str()).AsLong());
2614 } else {
2615 SendEditor(SCI_SETCARETLINEVISIBLE, 0);
2618 SString controlCharSymbol = props->Get("control.char.symbol");
2619 if (controlCharSymbol.length()) {
2620 SendEditor(SCI_SETCONTROLCHARSYMBOL, static_cast<unsigned char>(controlCharSymbol[0]));
2621 } else {
2622 SendEditor(SCI_SETCONTROLCHARSYMBOL, 0);
2625 SendEditor(SCI_CALLTIPSETBACK,
2626 ColourOfProperty(props, "calltip.back", ColourDesired(0xff, 0xff, 0xff)));
2628 SString caretPeriod = props->Get("caret.period");
2629 if (caretPeriod.length()) {
2630 blink_time = caretPeriod.value();
2632 else {
2633 GtkSettings *settings = gtk_settings_get_default();
2634 gboolean blink;
2636 g_object_get(G_OBJECT (settings),
2637 "gtk-cursor-blink", &blink,
2638 "gtk-cursor-blink-time", &blink_time,
2639 NULL);
2640 blink_time /= 2;
2641 if (!blink) blink_time = 0;
2643 SendEditor(SCI_SETCARETPERIOD, blink_time);
2645 int caretSlop = props->GetInt("caret.policy.xslop", 1) ? CARET_SLOP : 0;
2646 int caretZone = props->GetInt("caret.policy.width", 50);
2647 int caretStrict = props->GetInt("caret.policy.xstrict") ? CARET_STRICT : 0;
2648 int caretEven = props->GetInt("caret.policy.xeven", 1) ? CARET_EVEN : 0;
2649 int caretJumps = props->GetInt("caret.policy.xjumps") ? CARET_JUMPS : 0;
2650 SendEditor(SCI_SETXCARETPOLICY, caretStrict | caretSlop | caretEven | caretJumps, caretZone);
2652 caretSlop = props->GetInt("caret.policy.yslop", 1) ? CARET_SLOP : 0;
2653 caretZone = props->GetInt("caret.policy.lines");
2654 caretStrict = props->GetInt("caret.policy.ystrict") ? CARET_STRICT : 0;
2655 caretEven = props->GetInt("caret.policy.yeven", 1) ? CARET_EVEN : 0;
2656 caretJumps = props->GetInt("caret.policy.yjumps") ? CARET_JUMPS : 0;
2657 SendEditor(SCI_SETYCARETPOLICY, caretStrict | caretSlop | caretEven | caretJumps, caretZone);
2659 int visibleStrict = props->GetInt("visible.policy.strict") ? VISIBLE_STRICT : 0;
2660 int visibleSlop = props->GetInt("visible.policy.slop", 1) ? VISIBLE_SLOP : 0;
2661 int visibleLines = props->GetInt("visible.policy.lines");
2662 SendEditor(SCI_SETVISIBLEPOLICY, visibleStrict | visibleSlop, visibleLines);
2664 SendEditor(SCI_SETEDGECOLUMN, props->GetInt("edge.column", 0));
2665 SendEditor(SCI_SETEDGEMODE, props->GetInt("edge.mode", EDGE_NONE));
2666 SendEditor(SCI_SETEDGECOLOUR,
2667 ColourOfProperty(props, "edge.colour", ColourDesired(0xff, 0xda, 0xda)));
2669 SString selfore = props->Get("selection.fore");
2670 if (selfore.length()) {
2671 SendEditor(SCI_SETSELFORE, 1, ColourFromString(selfore.c_str()).AsLong());
2672 } else {
2673 SendEditor(SCI_SETSELFORE, 0, 0);
2675 SString selBack = props->Get("selection.back");
2676 if (selBack.length()) {
2677 SendEditor(SCI_SETSELBACK, 1, ColourFromString(selBack.c_str()).AsLong());
2678 } else {
2679 if (selfore.length())
2680 SendEditor(SCI_SETSELBACK, 0, 0);
2681 else // Have to show selection somehow
2682 SendEditor(SCI_SETSELBACK, 1, ColourDesired(0xC0, 0xC0, 0xC0).AsLong());
2685 SString whitespaceFore = props->Get("whitespace.fore");
2686 if (whitespaceFore.length()) {
2687 SendEditor(SCI_SETWHITESPACEFORE, 1, ColourFromString(whitespaceFore.c_str()).AsLong());
2688 } else {
2689 SendEditor(SCI_SETWHITESPACEFORE, 0, 0);
2691 SString whitespaceBack = props->Get("whitespace.back");
2692 if (whitespaceBack.length()) {
2693 SendEditor(SCI_SETWHITESPACEBACK, 1, ColourFromString(whitespaceBack.c_str()).AsLong());
2694 } else {
2695 SendEditor(SCI_SETWHITESPACEBACK, 0, 0);
2698 for (int i = 0; i < 3; i++) {
2700 SString value_str;
2701 long default_indic_type[] = {INDIC_TT, INDIC_DIAGONAL, INDIC_SQUIGGLE};
2702 const char *default_indic_color[] = {"0000FF", "#00FF00", "#FF0000"};
2703 char key[200];
2704 sprintf(key, "indicator.%d.style", i);
2706 value_str = props->Get(key);
2707 if (value_str.length() > 0) {
2708 if (strcasecmp (value_str.c_str(), "underline-plain") == 0) {
2709 SendEditor(SCI_INDICSETSTYLE, i, INDIC_PLAIN);
2710 } else if (strcasecmp (value_str.c_str(), "underline-tt") == 0) {
2711 SendEditor(SCI_INDICSETSTYLE, i, INDIC_TT);
2712 } else if (strcasecmp (value_str.c_str(), "underline-squiggle") == 0) {
2713 SendEditor(SCI_INDICSETSTYLE, i, INDIC_SQUIGGLE);
2714 } else if (strcasecmp (value_str.c_str(), "strike-out") == 0) {
2715 SendEditor(SCI_INDICSETSTYLE, i, INDIC_STRIKE);
2716 } else if (strcasecmp (value_str.c_str(), "diagonal") == 0) {
2717 SendEditor(SCI_INDICSETSTYLE, i, INDIC_DIAGONAL);
2718 } else if (strcasecmp (value_str.c_str(), "hidden") == 0) {
2719 SendEditor(SCI_INDICSETSTYLE, i, INDIC_HIDDEN);
2720 } else if (strcasecmp (value_str.c_str(), "box") == 0) {
2721 SendEditor(SCI_INDICSETSTYLE, i, INDIC_BOX);
2722 } else if (strcasecmp (value_str.c_str(), "roundbox") == 0) {
2723 SendEditor(SCI_INDICSETSTYLE, i, INDIC_ROUNDBOX);
2724 } else if (strcasecmp (value_str.c_str(), "straightbox") == 0) {
2725 SendEditor(SCI_INDICSETSTYLE, i, INDIC_STRAIGHTBOX);
2726 } else if (strcasecmp (value_str.c_str(), "underline-dash") == 0) {
2727 SendEditor(SCI_INDICSETSTYLE, i, INDIC_DASH);
2728 } else if (strcasecmp (value_str.c_str(), "underline-dots") == 0) {
2729 SendEditor(SCI_INDICSETSTYLE, i, INDIC_DOTS);
2730 } else if (strcasecmp (value_str.c_str(), "underline-low-squiggle") == 0) {
2731 SendEditor(SCI_INDICSETSTYLE, i, INDIC_SQUIGGLELOW);
2732 } else if (strcasecmp (value_str.c_str(), "dotbox") == 0) {
2733 SendEditor(SCI_INDICSETSTYLE, i, INDIC_DOTBOX);
2734 } else {
2735 SendEditor(SCI_INDICSETSTYLE, i, default_indic_type[i]);
2737 } else {
2738 SendEditor(SCI_INDICSETSTYLE, i, default_indic_type[i]);
2740 sprintf(key, "indicator.%d.color", i);
2741 value_str = props->GetExpanded(key);
2742 if (value_str.length()) {
2743 SendEditor(SCI_INDICSETFORE, i, ColourFromString(value_str.c_str()).AsLong());
2744 } else {
2745 SendEditor(SCI_INDICSETFORE, i, ColourFromString(default_indic_color[i]).AsLong());
2748 sprintf(key, "indicator.%d.under", i);
2749 value_str = props->GetExpanded(key);
2750 if (value_str.length()) {
2751 SendEditor(SCI_INDICSETUNDER, i, props->GetInt(key));
2754 sprintf(key, "indicator.%d.alpha", i);
2755 value_str = props->GetExpanded(key);
2756 if (value_str.length()) {
2757 SendEditor(SCI_INDICSETALPHA, i, props->GetInt(key));
2761 char bracesStyleKey[200];
2762 sprintf(bracesStyleKey, "braces.%s.style", language.c_str());
2763 bracesStyle = props->GetInt(bracesStyleKey, 0);
2765 char key[200];
2766 SString sval;
2768 sval = FindLanguageProperty("calltip.*.ignorecase");
2769 callTipIgnoreCase = sval == "1";
2771 calltipWordCharacters = FindLanguageProperty("calltip.*.word.characters",
2772 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
2774 calltipEndDefinition = FindLanguageProperty("calltip.*.end.definition");
2776 sprintf(key, "autocomplete.%s.start.characters", language.c_str());
2777 autoCompleteStartCharacters = props->GetExpanded(key);
2778 if (autoCompleteStartCharacters == "")
2779 autoCompleteStartCharacters = props->GetExpanded("autocomplete.*.start.characters");
2780 // "" is a quite reasonable value for this setting
2782 sprintf(key, "autocomplete.%s.fillups", language.c_str());
2783 autoCompleteFillUpCharacters = props->GetExpanded(key);
2784 if (autoCompleteFillUpCharacters == "")
2785 autoCompleteFillUpCharacters =
2786 props->GetExpanded("autocomplete.*.fillups");
2787 SendEditorString(SCI_AUTOCSETFILLUPS, 0,
2788 autoCompleteFillUpCharacters.c_str());
2790 sprintf(key, "autocomplete.%s.ignorecase", "*");
2791 sval = props->GetNewExpand(key, "");
2792 autoCompleteIgnoreCase = sval == "1";
2793 sprintf(key, "autocomplete.%s.ignorecase", language.c_str());
2794 sval = props->GetNewExpand(key, "");
2795 if (sval != "")
2796 autoCompleteIgnoreCase = sval == "1";
2797 SendEditor(SCI_AUTOCSETIGNORECASE, autoCompleteIgnoreCase ? 1 : 0);
2799 int autoCChooseSingle = props->GetInt("autocomplete.choose.single");
2800 SendEditor(SCI_AUTOCSETCHOOSESINGLE, autoCChooseSingle),
2802 SendEditor(SCI_AUTOCSETCANCELATSTART, 0),
2803 SendEditor(SCI_AUTOCSETDROPRESTOFWORD, 0),
2805 // Set styles
2806 // For each window set the global default style,
2807 // then the language default style,
2808 // then the other global styles,
2809 // then the other language styles
2811 UpdateStyle();
2813 if (firstPropertiesRead) {
2814 ReadPropertiesInitial();
2817 /* Gtk handles it correctly */
2818 SendEditor(SCI_SETPRINTMAGNIFICATION, props->GetInt("print.magnification"));
2819 SendEditor(SCI_SETPRINTCOLOURMODE, props->GetInt("print.colour.mode"));
2821 int blankMarginLeft = props->GetInt("blank.margin.left", 1);
2822 int blankMarginRight = props->GetInt("blank.margin.right", 1);
2823 SendEditor(SCI_SETMARGINLEFT, 0, blankMarginLeft);
2824 SendEditor(SCI_SETMARGINRIGHT, 0, blankMarginRight);
2826 SendEditor(SCI_SETMARGINWIDTHN, 1, margin ? marginWidth : 0);
2827 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ?lineNumbersWidth : 0);
2829 bufferedDraw = props->GetInt("buffered.draw", 1);
2830 SendEditor(SCI_SETBUFFEREDDRAW, bufferedDraw);
2832 SendEditor(SCI_SETLAYOUTCACHE, props->GetInt("cache.layout"));
2834 bracesCheck = props->GetInt("braces.check");
2835 bracesSloppy = props->GetInt("braces.sloppy");
2837 wordCharacters = props->GetNewExpand("word.characters.", fileNameForExtension.c_str());
2838 if (wordCharacters.length()) {
2839 SendEditorString(SCI_SETWORDCHARS, 0, wordCharacters.c_str());
2840 } else {
2841 SendEditor(SCI_SETWORDCHARS, 0, 0);
2842 wordCharacters = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2844 // Why call this??
2845 // SendEditor(SCI_MARKERDELETEALL, static_cast<unsigned long>( -1));
2847 SendEditor(SCI_SETTABINDENTS, props->GetInt("tab.indents", 1));
2848 SendEditor(SCI_SETBACKSPACEUNINDENTS, props->GetInt("backspace.unindents", 1));
2850 SendEditor(SCI_SETUSETABS, props->GetInt("use.tabs", 1));
2851 int tabSize = props->GetInt("tabsize");
2852 if (tabSize) {
2853 SendEditor(SCI_SETTABWIDTH, tabSize);
2855 indentSize = props->GetInt("indent.size");
2856 SendEditor(SCI_SETINDENT, indentSize);
2858 indentOpening = props->GetInt("indent.opening");
2859 indentClosing = props->GetInt("indent.closing");
2861 indentMaintain = props->GetNewExpand("indent.maintain.", fileNameForExtension.c_str()).value();
2863 SString lookback = props->GetNewExpand("statement.lookback.", fileNameForExtension.c_str());
2864 statementLookback = lookback.value();
2865 statementIndent = GetStyleAndWords("statement.indent.");
2866 statementEnd =GetStyleAndWords("statement.end.");
2867 blockStart = GetStyleAndWords("block.start.");
2868 blockEnd = GetStyleAndWords("block.end.");
2872 SString list;
2873 list = props->GetNewExpand("preprocessor.symbol.", fileNameForExtension.c_str());
2874 preprocessorSymbol = list[0];
2875 list = props->GetNewExpand("preprocessor.start.", fileNameForExtension.c_str());
2876 preprocCondStart.Clear();
2877 preprocCondStart.Set(list.c_str());
2878 list = props->GetNewExpand("preprocessor.middle.", fileNameForExtension.c_str());
2879 preprocCondMiddle.Clear();
2880 preprocCondMiddle.Set(list.c_str());
2881 list = props->GetNewExpand("preprocessor.end.", fileNameForExtension.c_str());
2882 preprocCondEnd.Clear();
2883 preprocCondEnd.Set(list.c_str());
2886 if (props->GetInt("vc.home.key", 1)) {
2887 AssignKey(SCK_HOME, 0, SCI_VCHOME);
2888 AssignKey(SCK_HOME, SCMOD_SHIFT, SCI_VCHOMEEXTEND);
2889 } else {
2890 AssignKey(SCK_HOME, 0, SCI_HOME);
2891 AssignKey(SCK_HOME, SCMOD_SHIFT, SCI_HOMEEXTEND);
2893 if (props->GetInt("fold.underline"))
2894 SendEditor(SCI_SETFOLDFLAGS, props->GetInt("fold.flags"));
2895 else
2896 SendEditor(SCI_SETFOLDFLAGS, 0);
2898 // To put the folder markers in the line number region
2899 //SendEditor(SCI_SETMARGINMASKN, 0, SC_MASK_FOLDERS);
2901 SendEditor(SCI_SETMODEVENTMASK, SC_MOD_CHANGEFOLD);
2903 if (0==props->GetInt("undo.redo.lazy")) {
2904 // Trap for insert/delete notifications (also fired by undo
2905 // and redo) so that the buttons can be enabled if needed.
2906 SendEditor(SCI_SETMODEVENTMASK, SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT
2907 | SC_LASTSTEPINUNDOREDO | SendEditor(SCI_GETMODEVENTMASK, 0));
2909 //SC_LASTSTEPINUNDOREDO is probably not needed in the mask; it
2910 //doesn't seem to fire as an event of its own; just modifies the
2911 //insert and delete events.
2914 // Create a margin column for the folding symbols
2915 SendEditor(SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL);
2917 SendEditor(SCI_SETMARGINWIDTHN, 2, foldMargin ? foldMarginWidth : 0);
2919 SendEditor(SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS);
2920 SendEditor(SCI_SETMARGINSENSITIVEN, 1, 1); // Breakpoints-Bookmarks
2921 SendEditor(SCI_SETMARGINSENSITIVEN, 2, 1);
2923 SString fold_symbols = props->Get("fold.symbols");
2924 SetFoldSymbols (fold_symbols);
2926 // Well, unlike scite, we want it everytime.
2927 firstPropertiesRead = true;
2930 void AnEditor::SetFoldSymbols(SString fold_symbols)
2932 if (fold_symbols.length() <= 0)
2933 fold_symbols = "plus/minus";
2934 if (strcasecmp(fold_symbols.c_str(), "arrows") == 0)
2936 // Arrow pointing right for contracted folders, arrow pointing down for expanded
2937 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_ARROWDOWN, Colour(0, 0, 0), Colour(0, 0, 0));
2938 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_ARROW, Colour(0, 0, 0), Colour(0, 0, 0));
2939 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY, Colour(0, 0, 0), Colour(0, 0, 0));
2940 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY, Colour(0, 0, 0), Colour(0, 0, 0));
2941 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2942 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2943 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2944 } else if (strcasecmp(fold_symbols.c_str(), "circular") == 0) {
2945 // Like a flattened tree control using circular headers and curved joins
2946 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2947 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2948 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2949 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2950 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2951 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2952 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2953 } else if (strcasecmp(fold_symbols.c_str(), "squares") == 0) {
2954 // Like a flattened tree control using square headers
2955 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2956 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2957 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2958 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2959 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2960 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2961 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2962 } else { // Default
2963 // Plus for contracted folders, minus for expanded
2964 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2965 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_PLUS, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2966 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2967 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2968 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2969 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2970 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2974 // Anjuta: In our case, we read it everytime
2975 void AnEditor::ReadPropertiesInitial() {
2976 indentationWSVisible = props->GetInt("view.indentation.whitespace", 1);
2978 ViewWhitespace(props->GetInt(VIEW_WHITE_SPACES));
2979 SendEditor(SCI_SETINDENTATIONGUIDES, props->GetInt(VIEW_INDENTATION_GUIDES));
2980 SendEditor(SCI_SETVIEWEOL, props->GetInt(VIEW_EOL));
2982 SetReadOnly(props->GetInt("file.readonly", 0));
2983 SetLineWrap(props->GetInt(VIEW_LINE_WRAP, 1));
2985 //lineNumbersWidth = 0;
2986 /* FIXME: This is nowhere configureable
2987 SString linenums = props->Get("margin.linenumber.width");
2988 if (linenums.length())
2989 lineNumbersWidth = linenums.value(); */
2990 //lineNumbers = lineNumbersWidth;
2991 /* We do this dynamicly in text_editor_load_file now */
2992 /* if (lineNumbersWidth == 0)
2993 lineNumbersWidth = lineNumbersWidthDefault;*/
2995 marginWidth = 0;
2996 SString margwidth = props->Get("margin.marker.width");
2997 if (margwidth.length())
2998 marginWidth = margwidth.value();
2999 margin = marginWidth;
3000 if (marginWidth == 0)
3001 marginWidth = marginWidthDefault;
3003 foldMarginWidth = props->GetInt("margin.fold.width", foldMarginWidthDefault);
3004 foldMargin = foldMarginWidth;
3005 if (foldMarginWidth == 0)
3006 foldMarginWidth = foldMarginWidthDefault;
3008 lineNumbers = props->GetInt(VIEW_LINENUMBERS_MARGIN, 0);
3009 margin = props->GetInt(VIEW_MARKER_MARGIN, 0);
3010 foldMargin = props->GetInt(VIEW_FOLD_MARGIN, 1);
3013 void AnEditor::DefineMarker(int marker, int markerType, Colour fore, Colour back)
3015 SendEditor(SCI_MARKERDEFINE, marker, markerType);
3016 SendEditor(SCI_MARKERSETFORE, marker, fore.AsLong());
3017 SendEditor(SCI_MARKERSETBACK, marker, back.AsLong());
3020 int AnEditor::GetBookmarkLine( const int nLineStart )
3022 int nNextLine = SendEditor(SCI_MARKERNEXT, nLineStart+1, 1 << ANE_MARKER_BOOKMARK);
3023 //printf( "...look %d --> %d\n", nLineStart, nNextLine );
3024 if ( (nNextLine < 0) || (nNextLine == nLineStart) )
3025 return -1 ;
3026 else
3027 return nNextLine;
3030 void AnEditor::FocusInEvent(GtkWidget* widget)
3032 if (calltipShown)
3034 StartCallTip_new();
3038 void AnEditor::FocusOutEvent(GtkWidget* widget)
3040 if (SendEditor(SCI_CALLTIPACTIVE))
3042 SendEditor(SCI_CALLTIPCANCEL);
3043 calltipShown = true;
3045 else
3047 calltipShown = false;
3051 static GList* editors;
3053 static AnEditor*
3054 aneditor_get(AnEditorID id)
3056 AnEditor* ed;
3057 if(id >= g_list_length(editors))
3059 DEBUG_PRINT("%s", "Invalid AnEditorID supplied");
3060 return NULL;
3062 ed = (AnEditor*)g_list_nth_data(editors, (guint)id);
3063 if(!ed)
3065 DEBUG_PRINT("%s", "Trying to use already destroyed AnEditor Object");
3066 return NULL;
3068 return ed;
3071 AnEditorID
3072 aneditor_new(gpointer propset)
3074 AnEditor* ed = new AnEditor((PropSetFile*)propset);
3075 if (!ed)
3077 DEBUG_PRINT("%s", "Memory allocation error.");
3078 return ANE_ID_INVALID;
3080 g_signal_connect(ed->GetID(), "focus_in_event",
3081 G_CALLBACK(on_aneditor_focus_in), ed);
3082 g_signal_connect(ed->GetID(), "focus_out_event",
3083 G_CALLBACK(on_aneditor_focus_out), ed);
3084 editors = g_list_append(editors, ed);
3085 return (AnEditorID)(g_list_length(editors) - 1);
3088 void
3089 aneditor_destroy(AnEditorID id)
3091 AnEditor* ed;
3093 ed = aneditor_get(id);
3094 if(!ed) return;
3096 /* We will not remove the editor from the list */
3097 /* so that already assigned handles work properly */
3098 /* We'll simply make it NULL to indicate that the */
3099 /* editor is destroyed */
3100 g_list_nth(editors, id)->data = NULL;
3102 /* Disconnect the focus in/out signals */
3103 g_signal_handlers_disconnect_by_func (ed->GetID(),
3104 (void*)G_CALLBACK(on_aneditor_focus_in), ed);
3105 g_signal_handlers_disconnect_by_func (ed->GetID(),
3106 (void*)G_CALLBACK(on_aneditor_focus_out), ed);
3108 delete ed;
3111 GtkWidget*
3112 aneditor_get_widget(AnEditorID handle)
3114 AnEditor *ed;
3115 ed = aneditor_get(handle);
3116 if(!ed) return NULL;
3118 // Forced conversion is safe here, so do it.
3119 return (GtkWidget*)ed->GetID();
3122 glong
3123 aneditor_command(AnEditorID handle, gint command, glong wparam, glong lparam)
3125 AnEditor *ed;
3126 ed = aneditor_get(handle);
3127 if(!ed) return 0;
3128 return ed->Command(command, wparam, lparam);
3131 void
3132 aneditor_set_focused_ed_ID(AnEditorID id)
3134 AnEditor::focusedID = id;
3137 void
3138 aneditor_set_parent(AnEditorID id, AnEditorID parent_id)
3140 AnEditor *editor;
3141 AnEditor *parent;
3143 editor = aneditor_get (id);
3144 parent = aneditor_get (parent_id);
3145 editor->SetParent(parent);
3148 gint
3149 on_aneditor_focus_in (GtkWidget* widget, gpointer* unused, AnEditor* ed)
3151 ed->FocusInEvent(widget);
3152 return FALSE;
3155 gint
3156 on_aneditor_focus_out (GtkWidget* widget, gpointer * unused, AnEditor* ed)
3158 /* ed->EndDebugEval(); */
3159 ed->FocusOutEvent(widget);
3160 return FALSE;