scintilla: Update scintilla with changeset 3662:1d1c06df8a2f using gtk+3
[anjuta-extras.git] / plugins / scintilla / aneditor.cxx
blob724605993e561b5e67bae414a9b2ccb3495af512
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 //FIXME WindowAccessor acc(win.GetID(), *props);
545 #if 0
546 if (caretPos > 0) {
547 charBefore = acc[caretPos - 1];
548 styleBefore = static_cast<char>(acc.StyleAt(caretPos - 1) & 31);
550 // Priority goes to character before caret
551 if (charBefore && strchr("[](){}", charBefore) &&
552 ((styleBefore == bracesStyleCheck) || (!bracesStyle))) {
553 braceAtCaret = caretPos - 1;
555 bool colonMode = false;
556 if (lexLanguage == SCLEX_PYTHON && ':' == charBefore) {
557 braceAtCaret = caretPos - 1;
558 colonMode = true;
560 bool isAfter = true;
561 if (sloppy && (braceAtCaret < 0)) {
562 // No brace found so check other side
563 char charAfter = acc[caretPos];
564 char styleAfter = static_cast<char>(acc.StyleAt(caretPos) & 31);
565 if (charAfter && strchr("[](){}", charAfter) && (styleAfter == bracesStyleCheck)) {
566 braceAtCaret = caretPos;
567 isAfter = false;
569 if (lexLanguage == SCLEX_PYTHON && ':' == charAfter) {
570 braceAtCaret = caretPos;
571 colonMode = true;
574 if (braceAtCaret >= 0) {
575 if (colonMode) {
576 int lineStart = Platform::SendScintilla(win.GetID(), SCI_LINEFROMPOSITION, braceAtCaret);
577 int lineMaxSubord = Platform::SendScintilla(win.GetID(), SCI_GETLASTCHILD, lineStart, -1);
578 braceOpposite = Platform::SendScintilla(win.GetID(), SCI_GETLINEENDPOSITION, lineMaxSubord);
579 } else {
580 braceOpposite = Platform::SendScintilla(win.GetID(), SCI_BRACEMATCH, braceAtCaret, 0);
582 if (braceOpposite > braceAtCaret) {
583 isInside = isAfter;
584 } else {
585 isInside = !isAfter;
588 #endif
589 return isInside;
592 void AnEditor::BraceMatch(bool editor) {
593 if (!bracesCheck)
594 return;
595 int braceAtCaret = -1;
596 int braceOpposite = -1;
597 FindMatchingBracePosition(editor, braceAtCaret, braceOpposite, bracesSloppy);
598 // Window &win = editor ? wEditor : wOutput;
599 Window &win = wEditor;
600 if ((braceAtCaret != -1) && (braceOpposite == -1)) {
601 Platform::SendScintilla(win.GetID(), SCI_BRACEBADLIGHT, braceAtCaret, 0);
602 SendEditor(SCI_SETHIGHLIGHTGUIDE, 0);
603 } else {
604 char chBrace = static_cast<char>(Platform::SendScintilla(
605 win.GetID(), SCI_GETCHARAT, braceAtCaret, 0));
606 Platform::SendScintilla(win.GetID(), SCI_BRACEHIGHLIGHT, braceAtCaret, braceOpposite);
607 int columnAtCaret = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, braceAtCaret, 0);
608 int columnOpposite = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, braceOpposite, 0);
609 if (chBrace == ':') {
610 int lineStart = Platform::SendScintilla(win.GetID(), SCI_LINEFROMPOSITION, braceAtCaret);
611 int indentPos = Platform::SendScintilla(win.GetID(), SCI_GETLINEINDENTPOSITION, lineStart, 0);
612 int indentPosNext = Platform::SendScintilla(win.GetID(), SCI_GETLINEINDENTPOSITION, lineStart + 1, 0);
613 columnAtCaret = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, indentPos, 0);
614 int columnAtCaretNext = Platform::SendScintilla(win.GetID(), SCI_GETCOLUMN, indentPosNext, 0);
615 int indentationSize = Platform::SendScintilla(win.GetID(), SCI_GETINDENT);
616 if (columnAtCaretNext - indentationSize > 1)
617 columnAtCaret = columnAtCaretNext - indentationSize;
618 //Platform::DebugPrintf(": %d %d %d\n", lineStart, indentPos, columnAtCaret);
619 if (columnOpposite == 0) // If the final line of the structure is empty
620 columnOpposite = columnAtCaret;
623 if (props->GetInt("highlight.indentation.guides"))
624 Platform::SendScintilla(win.GetID(), SCI_SETHIGHLIGHTGUIDE, Platform::Minimum(columnAtCaret, columnOpposite), 0);
628 CharacterRange AnEditor::GetSelection() {
629 CharacterRange crange;
630 crange.cpMin = SendEditor(SCI_GETSELECTIONSTART);
631 crange.cpMax = SendEditor(SCI_GETSELECTIONEND);
632 return crange;
635 void AnEditor::SetSelection(int anchor, int currentPos) {
636 SendEditor(SCI_SETSEL, anchor, currentPos);
639 bool AnEditor::iswordcharforsel(char ch) {
640 return !strchr("\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", ch);
643 void AnEditor::SelectionWord(char *word, int len) {
644 int lengthDoc = LengthDocument();
645 CharacterRange cr = GetSelection();
646 int selStart = cr.cpMin;
647 int selEnd = cr.cpMax;
648 if (selStart == selEnd) {
649 //FIXME WindowAccessor acc(wEditor.GetID(), *props);
650 #if 0
651 // Try and find a word at the caret
652 if (iswordcharforsel(acc[selStart])) {
653 while ((selStart > 0) && (iswordcharforsel(acc[selStart - 1])))
654 selStart--;
655 while ((selEnd < lengthDoc - 1) && (iswordcharforsel(acc[selEnd + 1])))
656 selEnd++;
657 if (selStart < selEnd)
658 selEnd++; // Because normal selections end one past
660 #endif
662 word[0] = '\0';
663 if ((selStart < selEnd) && ((selEnd - selStart + 1) < len)) {
664 GetRange(wEditor, selStart, selEnd, word);
668 void AnEditor::WordSelect() {
669 int lengthDoc = LengthDocument();
670 int selStart;
671 int selEnd;
673 selStart = selEnd = SendEditor(SCI_GETCURRENTPOS);
674 //FIXME WindowAccessor acc(wEditor.GetID(), *props);
675 #if 0
676 if (iswordcharforsel(acc[selStart])) {
677 while ((selStart > 0) && (iswordcharforsel(acc[selStart - 1])))
678 selStart--;
679 while ((selEnd < lengthDoc - 1) && (iswordcharforsel(acc[selEnd + 1])))
680 selEnd++;
681 if (selStart < selEnd)
682 selEnd++; // Because normal selections end one past
684 #endif
685 SetSelection(selStart, selEnd);
688 void AnEditor::LineSelect() {
689 int pos = SendEditor(SCI_GETCURRENTPOS);
690 int line = SendEditor(SCI_LINEFROMPOSITION, pos);
691 int lineStart = SendEditor(SCI_POSITIONFROMLINE, line);
692 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, line);
694 SetSelection(lineStart, lineEnd);
697 void AnEditor::SelectionIntoProperties() {
698 CharacterRange cr = GetSelection();
699 char currentSelection[1000];
700 if ((cr.cpMin < cr.cpMax) && ((cr.cpMax - cr.cpMin + 1) < static_cast<int>(sizeof(currentSelection)))) {
701 GetRange(wEditor, cr.cpMin, cr.cpMax, currentSelection);
702 int len = strlen(currentSelection);
703 if (len > 2 && iscntrl(currentSelection[len - 1]))
704 currentSelection[len - 1] = '\0';
705 if (len > 2 && iscntrl(currentSelection[len - 2]))
706 currentSelection[len - 2] = '\0';
707 props->Set("CurrentSelection", currentSelection);
709 char word[200];
710 SelectionWord(word, sizeof(word));
711 props->Set("CurrentWord", word);
714 long AnEditor::Find (long flags, char* findWhat) {
715 if (!findWhat) return -1;
716 TextToFind ft = {{0, 0}, 0, {0, 0}};
717 CharacterRange crange = GetSelection();
718 if (flags & ANEFIND_REVERSE_FLAG) {
719 ft.chrg.cpMin = crange.cpMin - 1;
720 ft.chrg.cpMax = 1;
721 } else {
722 ft.chrg.cpMin = crange.cpMax;
723 ft.chrg.cpMax = LengthDocument();
725 ft.lpstrText = findWhat;
726 ft.chrgText.cpMin = 0;
727 ft.chrgText.cpMax = 0;
728 int posFind = SendEditor(SCI_FINDTEXT, flags, reinterpret_cast<long>(&ft));
729 if (posFind >= 0) {
730 EnsureRangeVisible(ft.chrgText.cpMin, ft.chrgText.cpMax);
731 SetSelection(ft.chrgText.cpMin, ft.chrgText.cpMax);
733 return posFind;
736 void AnEditor::BookmarkToggle( int lineno ) {
737 if (lineno == -1)
743 lineno = GetCurrentLineNumber();
744 int state = SendEditor(SCI_MARKERGET, lineno);
745 if ( state & (1 << ANE_MARKER_BOOKMARK))
746 SendEditor(SCI_MARKERDELETE, lineno, ANE_MARKER_BOOKMARK);
747 else {
748 SendEditor(SCI_MARKERADD, lineno, ANE_MARKER_BOOKMARK);
752 void AnEditor::BookmarkFirst() {
753 int lineno = GetCurrentLineNumber();
754 int nextLine = SendEditor(SCI_MARKERNEXT, 0, 1 << ANE_MARKER_BOOKMARK);
755 if (nextLine < 0 || nextLine == lineno)
756 gdk_beep(); // how do I beep? -- like this ;-)
757 else {
758 SendEditor(SCI_ENSUREVISIBLE, nextLine);
759 SendEditor(SCI_GOTOLINE, nextLine);
763 void AnEditor::BookmarkPrev() {
764 int lineno = GetCurrentLineNumber();
765 int nextLine = SendEditor(SCI_MARKERPREVIOUS, lineno - 1, 1 << ANE_MARKER_BOOKMARK);
766 if (nextLine < 0 || nextLine == lineno) {
767 if(props->GetInt("editor.wrapbookmarks")) {
768 int nrOfLines = SendEditor(SCI_GETLINECOUNT, 0, 1 << ANE_MARKER_BOOKMARK);
769 int nextLine1 = SendEditor(SCI_MARKERPREVIOUS, nrOfLines, 1 << ANE_MARKER_BOOKMARK);
770 if (nextLine1 < 0 || nextLine1 == lineno) {
771 gdk_beep(); // how do I beep? -- like this ;-)
772 } else {
773 SendEditor(SCI_ENSUREVISIBLE, nextLine1);
774 SendEditor(SCI_GOTOLINE, nextLine1);
777 } else {
778 SendEditor(SCI_ENSUREVISIBLE, nextLine);
779 SendEditor(SCI_GOTOLINE, nextLine);
783 void AnEditor::BookmarkNext() {
784 int lineno = GetCurrentLineNumber();
785 int nextLine = SendEditor(SCI_MARKERNEXT, lineno + 1, 1 << ANE_MARKER_BOOKMARK);
786 if (nextLine < 0 || nextLine == lineno) {
787 if(props->GetInt("editor.wrapbookmarks")) {
788 int nextLine1 = SendEditor(SCI_MARKERNEXT, 0, 1 << ANE_MARKER_BOOKMARK);
789 if (nextLine1 < 0 || nextLine1 == lineno) {
790 gdk_beep(); // how do I beep? -- like this ;-)
791 } else {
792 SendEditor(SCI_ENSUREVISIBLE, nextLine1);
793 SendEditor(SCI_GOTOLINE, nextLine1);
796 } else {
797 SendEditor(SCI_ENSUREVISIBLE, nextLine);
798 SendEditor(SCI_GOTOLINE, nextLine);
802 void AnEditor::BookmarkLast() {
803 int lineno = GetCurrentLineNumber();
804 int nextLine = SendEditor(SCI_MARKERPREVIOUS,
805 SendEditor(SCI_GETLINECOUNT), 1 << ANE_MARKER_BOOKMARK);
806 if (nextLine < 0 || nextLine == lineno)
807 gdk_beep(); // how do I beep? -- like this ;-)
808 else {
809 SendEditor(SCI_ENSUREVISIBLE, nextLine);
810 SendEditor(SCI_GOTOLINE, nextLine);
814 void AnEditor::BookmarkClear() {
815 SendEditor(SCI_MARKERDELETEALL, ANE_MARKER_BOOKMARK);
818 bool AnEditor::GetCurrentWord(char* buffer, int length) {
819 SString linebuf;
820 GetLine(linebuf);
821 int current = GetCaretInLine();
822 return FindWordInRegion(buffer, length, linebuf, current);
825 bool AnEditor::StartBlockComment() {
826 SString fileNameForExtension = ExtensionFileName();
827 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
828 SString base("comment.block.");
829 SString comment_at_line_start("comment.block.at.line.start.");
830 base += language;
831 comment_at_line_start += language;
832 SString comment = props->Get(base.c_str());
833 if (comment == "") { // user friendly error message box
834 //SString error("Block comment variable \"");
835 //error += base;
836 //error += "\" is not defined in SciTE *.properties!";
837 //WindowMessageBox(wEditor, error, MB_OK | MB_ICONWARNING);
838 return true;
840 comment += " ";
841 SString long_comment = comment;
842 char linebuf[1000];
843 size_t comment_length = comment.length();
844 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
845 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
846 size_t caretPosition = SendEditor(SCI_GETCURRENTPOS);
847 // checking if caret is located in _beginning_ of selected block
848 bool move_caret = caretPosition < selectionEnd;
849 int selStartLine = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
850 int selEndLine = SendEditor(SCI_LINEFROMPOSITION, selectionEnd);
851 int lines = selEndLine - selStartLine;
852 size_t firstSelLineStart = SendEditor(SCI_POSITIONFROMLINE, selStartLine);
853 // "caret return" is part of the last selected line
854 if ((lines > 0) &&
855 (selectionEnd == static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE, selEndLine))))
856 selEndLine--;
857 SendEditor(SCI_BEGINUNDOACTION);
858 for (int i = selStartLine; i <= selEndLine; i++) {
859 int lineStart = SendEditor(SCI_POSITIONFROMLINE, i);
860 int lineIndent = lineStart;
861 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, i);
862 if (props->GetInt(comment_at_line_start.c_str())) {
863 GetRange(wEditor, lineIndent, lineEnd, linebuf);
864 } else {
865 lineIndent = GetLineIndentPosition(i);
866 GetRange(wEditor, lineIndent, lineEnd, linebuf);
868 // empty lines are not commented
869 if (strlen(linebuf) < 1)
870 continue;
871 if (memcmp(linebuf, comment.c_str(), comment_length - 1) == 0) {
872 if (memcmp(linebuf, long_comment.c_str(), comment_length) == 0) {
873 // removing comment with space after it
874 SendEditor(SCI_SETSEL, lineIndent, lineIndent + comment_length);
875 SendEditorString(SCI_REPLACESEL, 0, "");
876 if (i == selStartLine) // is this the first selected line?
877 selectionStart -= comment_length;
878 selectionEnd -= comment_length; // every iteration
879 continue;
880 } else {
881 // removing comment _without_ space
882 SendEditor(SCI_SETSEL, lineIndent, lineIndent + comment_length - 1);
883 SendEditorString(SCI_REPLACESEL, 0, "");
884 if (i == selStartLine) // is this the first selected line?
885 selectionStart -= (comment_length - 1);
886 selectionEnd -= (comment_length - 1); // every iteration
887 continue;
890 if (i == selStartLine) // is this the first selected line?
891 selectionStart += comment_length;
892 selectionEnd += comment_length; // every iteration
893 SendEditorString(SCI_INSERTTEXT, lineIndent, long_comment.c_str());
895 // after uncommenting selection may promote itself to the lines
896 // before the first initially selected line;
897 // another problem - if only comment symbol was selected;
898 if (selectionStart < firstSelLineStart) {
899 if (selectionStart >= selectionEnd - (comment_length - 1))
900 selectionEnd = firstSelLineStart;
901 selectionStart = firstSelLineStart;
903 if (move_caret) {
904 // moving caret to the beginning of selected block
905 SendEditor(SCI_GOTOPOS, selectionEnd);
906 SendEditor(SCI_SETCURRENTPOS, selectionStart);
907 } else {
908 SendEditor(SCI_SETSEL, selectionStart, selectionEnd);
910 SendEditor(SCI_ENDUNDOACTION);
911 return true;
914 // Return true if the selected zone can be commented
915 // Return false if it cannot be commented or has been uncommented
916 // BOX_COMMENT : box_stream = true STREAM_COMMENT : box_stream = false
917 // Uncomment if the selected zone or the cursor is inside the comment
919 bool AnEditor::CanBeCommented(bool box_stream) {
920 SString fileNameForExtension = ExtensionFileName();
921 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
922 SString start_base("comment.box.start.");
923 SString middle_base("comment.box.middle.");
924 SString end_base("comment.box.end.");
925 SString white_space(" ");
926 start_base += language;
927 middle_base += language;
928 end_base += language;
929 SString start_comment = props->Get(start_base.c_str());
930 SString middle_cmt = props->Get(middle_base.c_str());
931 SString end_comment = props->Get(end_base.c_str());
932 start_comment += white_space;
933 middle_cmt += white_space;
934 white_space += end_comment;
935 end_comment = white_space;
936 size_t start_comment_length = start_comment.length();
937 size_t end_comment_length = end_comment.length();
938 size_t middle_cmt_length = middle_cmt.length();
939 SString start_base_stream ("comment.stream.start.");
940 start_base_stream += language;
941 SString end_base_stream ("comment.stream.end.");
942 end_base_stream += language;
943 SString end_comment_stream = props->Get(end_base_stream.c_str());
944 SString white_space_stream(" ");
945 //SString end_white_space_stream(" ");
946 SString start_comment_stream = props->Get(start_base_stream.c_str());
947 start_comment_stream += white_space_stream;
948 size_t start_comment_stream_length = start_comment_stream.length();
949 white_space_stream +=end_comment_stream;
950 end_comment_stream = white_space_stream ;
951 size_t end_comment_stream_length = end_comment_stream.length();
953 char linebuf[1000];
954 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
955 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
956 if (selectionStart == selectionEnd)
957 return FALSE;
958 int line = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
959 if (line < 0)
960 return FALSE;
961 bool start1 = false, start2 = false;
962 bool end1 = false, end2 = false;
963 int lineEnd1;
964 if (box_stream)
965 lineEnd1 = selectionStart + start_comment_length;
966 else
967 lineEnd1 = selectionStart + start_comment_stream_length +1;
968 if (lineEnd1 > LengthDocument())
969 lineEnd1 = LengthDocument();
971 int lineStart1 = 0;
972 size_t start_cmt = 0, end_cmt = 0;
973 int index = 0;
974 // Find Backward StartComment
975 while (line >= 0 && start1 == false && end1 == false)
977 lineStart1 = SendEditor(SCI_POSITIONFROMLINE, line);
978 GetRange(wEditor, lineStart1, lineEnd1, linebuf);
980 for (index = lineEnd1-lineStart1; index >= 0; index--)
982 if (end1= ((end_comment_length > 1 && !memcmp(linebuf+index,
983 end_comment.c_str(), end_comment_length ))
984 || (end_comment_stream_length > 0 && !memcmp(linebuf+index,
985 end_comment_stream.c_str(), end_comment_stream_length))))
986 break;
987 if (start1=((start_comment_length > 1 && !memcmp(linebuf+index,
988 start_comment.c_str(), start_comment_length))
989 || (start_comment_stream_length > 0 && !memcmp(linebuf+index,
990 start_comment_stream.c_str(), start_comment_stream_length))))
991 break;
993 line --;
994 lineEnd1= SendEditor(SCI_GETLINEENDPOSITION, line);
996 start_cmt = index + lineStart1;
997 line = SendEditor(SCI_LINEFROMPOSITION, selectionEnd);
998 if (box_stream)
999 lineStart1 = selectionEnd - start_comment_length;
1000 else
1001 lineStart1 = selectionEnd - start_comment_stream_length;
1002 int last_line = SendEditor(SCI_GETLINECOUNT);
1003 // Find Forward EndComment
1004 while (line <= last_line && start2 == false && end2 == false)
1006 lineEnd1= SendEditor(SCI_GETLINEENDPOSITION, line);
1007 GetRange(wEditor, lineStart1, lineEnd1, linebuf);
1008 for (index = 0; index <= (lineEnd1-lineStart1); index++)
1010 if (start2= ((start_comment_length > 1 && !memcmp(linebuf+index,
1011 start_comment.c_str(), start_comment_length))
1012 || (start_comment_stream_length > 0 && !memcmp(linebuf+index,
1013 start_comment_stream.c_str(), start_comment_stream_length))))
1014 break;
1015 if (end2= ((end_comment_length > 1 && !memcmp(linebuf+index,
1016 end_comment.c_str(), end_comment_length ))
1017 || (end_comment_stream_length > 0 && !memcmp(linebuf+index,
1018 end_comment_stream.c_str(), end_comment_stream_length))))
1019 break;
1021 line ++;
1022 end_cmt = lineStart1 + index;
1023 lineStart1 = SendEditor(SCI_POSITIONFROMLINE, line);
1025 // Uncomment
1026 if(start1 || end2)
1028 if (start1 && end2)
1030 SendEditor(SCI_BEGINUNDOACTION);
1031 if (box_stream) // Box
1033 SendEditor(SCI_SETSEL, start_cmt, start_cmt +
1034 start_comment_length);
1035 end_cmt -= start_comment_length;
1037 else // Stream
1039 SendEditor(SCI_SETSEL, start_cmt, start_cmt +
1040 start_comment_stream_length);
1041 end_cmt -= start_comment_stream_length;
1043 SendEditorString(SCI_REPLACESEL, 0, "");
1044 line = SendEditor(SCI_LINEFROMPOSITION, start_cmt) + 1;
1045 last_line = SendEditor(SCI_LINEFROMPOSITION, end_cmt) ;
1046 for (int i = line; i < last_line; i++)
1048 int s = SendEditor(SCI_POSITIONFROMLINE, i);
1049 int e = SendEditor(SCI_GETLINEENDPOSITION, i);
1050 GetRange(wEditor, s, e, linebuf);
1051 if (!memcmp(linebuf, middle_cmt.c_str(), middle_cmt_length))
1053 SendEditor(SCI_SETSEL, s, s + middle_cmt_length);
1054 SendEditorString(SCI_REPLACESEL, 0, "");
1055 end_cmt -= middle_cmt_length;
1058 if (box_stream) // Box
1059 SendEditor(SCI_SETSEL, end_cmt, end_cmt + end_comment_length);
1060 else // Stream
1061 SendEditor(SCI_SETSEL, end_cmt, end_cmt + end_comment_stream_length);
1062 SendEditorString(SCI_REPLACESEL, 0, "");
1063 SendEditor(SCI_ENDUNDOACTION);
1065 return false;
1067 return true;
1071 bool AnEditor::StartBoxComment() {
1072 SString fileNameForExtension = ExtensionFileName();
1073 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
1074 SString start_base("comment.box.start.");
1075 SString middle_base("comment.box.middle.");
1076 SString end_base("comment.box.end.");
1077 SString white_space(" ");
1078 start_base += language;
1079 middle_base += language;
1080 end_base += language;
1081 SString start_comment = props->Get(start_base.c_str());
1082 SString middle_comment = props->Get(middle_base.c_str());
1083 SString end_comment = props->Get(end_base.c_str());
1084 if (start_comment == "" || middle_comment == "" || end_comment == "") {
1085 //SString error("Box comment variables \"");
1086 //error += start_base;
1087 //error += "\", \"";
1088 //error += middle_base;
1089 //error += "\"\nand \"";
1090 //error += end_base;
1091 //error += "\" are not ";
1092 //error += "defined in SciTE *.properties!";
1093 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1094 return true;
1096 start_comment += white_space;
1097 middle_comment += white_space;
1098 white_space += end_comment;
1099 end_comment = white_space;
1100 size_t start_comment_length = start_comment.length();
1101 size_t middle_comment_length = middle_comment.length();
1102 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
1103 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
1104 size_t caretPosition = SendEditor(SCI_GETCURRENTPOS);
1105 // checking if caret is located in _beginning_ of selected block
1106 bool move_caret = caretPosition < selectionEnd;
1107 size_t selStartLine = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
1108 size_t selEndLine = SendEditor(SCI_LINEFROMPOSITION, selectionEnd);
1109 size_t lines = selEndLine - selStartLine;
1110 // "caret return" is part of the last selected line
1111 if ((lines > 0) && (
1112 selectionEnd == static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE, selEndLine)))) {
1113 selEndLine--;
1114 lines--;
1115 // get rid of CRLF problems
1116 selectionEnd = SendEditor(SCI_GETLINEENDPOSITION, selEndLine);
1118 // Comment , Uncomment or Do Nothing
1119 if (CanBeCommented(true))
1121 SendEditor(SCI_BEGINUNDOACTION);
1122 // first commented line (start_comment)
1123 int lineStart = SendEditor(SCI_POSITIONFROMLINE, selStartLine);
1124 SendEditorString(SCI_INSERTTEXT, lineStart, start_comment.c_str());
1125 selectionStart += start_comment_length;
1126 // lines between first and last commented lines (middle_comment)
1127 for (size_t i = selStartLine + 1; i <= selEndLine; i++) {
1128 lineStart = SendEditor(SCI_POSITIONFROMLINE, i);
1129 SendEditorString(SCI_INSERTTEXT, lineStart, middle_comment.c_str());
1130 selectionEnd += middle_comment_length;
1132 // last commented line (end_comment)
1133 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, selEndLine);
1134 if (lines > 0) {
1135 SendEditorString(SCI_INSERTTEXT, lineEnd, "\n");
1136 SendEditorString(SCI_INSERTTEXT, lineEnd + 1, (end_comment.c_str() + 1));
1137 } else {
1138 SendEditorString(SCI_INSERTTEXT, lineEnd, end_comment.c_str());
1140 selectionEnd += (start_comment_length);
1141 if (move_caret) {
1142 // moving caret to the beginning of selected block
1143 SendEditor(SCI_GOTOPOS, selectionEnd);
1144 SendEditor(SCI_SETCURRENTPOS, selectionStart);
1145 } else {
1146 SendEditor(SCI_SETSEL, selectionStart, selectionEnd);
1148 SendEditor(SCI_ENDUNDOACTION);
1150 return true;
1153 bool AnEditor::StartStreamComment() {
1154 SString fileNameForExtension = ExtensionFileName();
1155 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
1156 SString start_base("comment.stream.start.");
1157 SString end_base("comment.stream.end.");
1158 SString white_space(" ");
1159 //SString end_white_space(" ");
1160 start_base += language;
1161 end_base += language;
1162 SString start_comment = props->Get(start_base.c_str());
1163 SString end_comment = props->Get(end_base.c_str());
1164 if (start_comment == "" || end_comment == "") {
1165 //SString error("Stream comment variables \"");
1166 //error += start_base;
1167 //error += "\" and \n\"";
1168 //error += end_base;
1169 //error += "\" are not ";
1170 //error += "defined in SciTE *.properties!";
1171 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1172 return true;
1174 start_comment += white_space;
1175 white_space += end_comment;
1176 end_comment = white_space;
1177 size_t start_comment_length = start_comment.length();
1178 size_t selectionStart = SendEditor(SCI_GETSELECTIONSTART);
1179 size_t selectionEnd = SendEditor(SCI_GETSELECTIONEND);
1180 size_t caretPosition = SendEditor(SCI_GETCURRENTPOS);
1181 // checking if caret is located in _beginning_ of selected block
1182 bool move_caret = caretPosition < selectionEnd;
1183 // if there is no selection?
1184 if (selectionEnd - selectionStart <= 0) {
1185 int selLine = SendEditor(SCI_LINEFROMPOSITION, selectionStart);
1186 int lineIndent = GetLineIndentPosition(selLine);
1187 int lineEnd = SendEditor(SCI_GETLINEENDPOSITION, selLine);
1188 if (RangeIsAllWhitespace(lineIndent, lineEnd))
1189 return true; // we are not dealing with empty lines
1190 SString linebuf;
1191 GetLine(linebuf);
1192 int current = GetCaretInLine();
1193 // checking if we are not inside a word
1194 if (!wordCharacters.contains(linebuf[current]))
1195 return true; // caret is located _between_ words
1196 int startword = current;
1197 int endword = current;
1198 int start_counter = 0;
1199 int end_counter = 0;
1200 while (startword > 0 && wordCharacters.contains(linebuf[startword - 1])) {
1201 start_counter++;
1202 startword--;
1204 // checking _beginning_ of the word
1205 if (startword == current)
1206 return true; // caret is located _before_ a word
1207 while (linebuf[endword + 1] != '\0' && wordCharacters.contains(linebuf[endword + 1])) {
1208 end_counter++;
1209 endword++;
1211 selectionStart -= start_counter;
1212 selectionEnd += (end_counter + 1);
1214 // Comment , Uncomment or Do Nothing
1215 if (CanBeCommented(false))
1217 SendEditor(SCI_BEGINUNDOACTION);
1218 SendEditorString(SCI_INSERTTEXT, selectionStart, start_comment.c_str());
1219 selectionEnd += start_comment_length;
1220 selectionStart += start_comment_length;
1221 SendEditorString(SCI_INSERTTEXT, selectionEnd, end_comment.c_str());
1222 if (move_caret) {
1223 // moving caret to the beginning of selected block
1224 SendEditor(SCI_GOTOPOS, selectionEnd);
1225 SendEditor(SCI_SETCURRENTPOS, selectionStart);
1226 } else {
1227 SendEditor(SCI_SETSEL, selectionStart, selectionEnd);
1229 SendEditor(SCI_ENDUNDOACTION);
1231 return true;
1234 #if 0
1235 SString AnEditor::GetMode(SString language) {
1236 SString mode;
1237 if (strcmp(language.c_str(), "cpp") == 0)
1239 mode += " Mode: C;";
1240 if (props->GetInt("use.tabs"))
1241 mode += " indent-tabs-mode: t;";
1242 mode += " c-basic-offset: ";
1243 mode += g_strdup_printf("%d", props->GetInt("indent.size"));
1244 mode += "; tab-width: ";
1245 mode += g_strdup_printf("%d ", props->GetInt("tabsize"));
1247 //~ Other languages
1248 //~ .....
1249 return mode;
1252 /* Insert or Modify a Comment line
1253 giving File indent */
1254 bool AnEditor::InsertCustomIndent() {
1255 #define MAXBUF 1000
1257 SString fileNameForExtension = ExtensionFileName();
1258 SString language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
1259 SString start_box_base("comment.box.start.");
1260 start_box_base += language;
1261 SString start_stream_base("comment.stream.start.");
1262 start_stream_base += language;
1263 SString end_box_base("comment.box.end.");
1264 end_box_base += language;
1265 SString end_stream_base("comment.stream.end.");
1266 end_stream_base += language;
1267 SString start_box = props->Get(start_box_base.c_str());
1268 SString start_stream = props->Get(start_stream_base.c_str());
1269 SString end_box = props->Get(end_box_base.c_str());
1270 SString end_stream = props->Get(end_stream_base.c_str());
1271 SString mark("-*-");
1272 int text_length = SendEditor(SCI_GETTEXTLENGTH);
1273 char buf[MAXBUF];
1274 int bufmax = text_length < MAXBUF ? text_length : MAXBUF;
1276 GetRange(wEditor, 0, bufmax - 1, buf);
1278 bool start_comment = false;
1279 bool indent_comment = false;
1280 int end_indent_comment = 0;
1282 for (int index = 0; index < bufmax; index++)
1284 if (!start_comment)
1286 if (memcmp(buf+index, start_box.c_str(), start_box.length()) == 0)
1288 index += (start_box.length() - 1);
1289 start_comment = true;
1290 continue;
1292 if (memcmp(buf+index, start_stream.c_str(), start_stream.length()) == 0)
1294 index += (start_stream.length() - 1);
1295 start_comment = true;
1296 continue;
1298 if (buf[index] != ' ' && buf[index] != '\t' && buf[index] != '\n')
1299 break;
1301 else
1303 if (!indent_comment)
1305 if (buf[index] == ' ' || buf[index] == '\t' || buf[index] == '\n')
1306 continue;
1307 if (memcmp(buf+index, mark.c_str(), 3) == 0)
1309 index += 3;
1310 indent_comment = true;
1312 else
1313 break;
1315 else
1317 if (memcmp(buf+index, end_box.c_str(), end_box.length()) == 0)
1319 end_indent_comment = index + end_box.length() - 1;
1320 break;
1322 if (memcmp(buf+index, end_stream.c_str(), end_stream.length()) == 0)
1324 end_indent_comment = index + end_stream.length() - 1;
1325 break;
1330 SString mode = GetMode(language);
1331 if (mode.c_str() != "")
1333 SString comment ;
1334 comment += start_stream.c_str() ;
1335 comment += " ";
1336 comment += mark.c_str();
1337 comment += mode.c_str();
1338 comment += mark.c_str();
1339 comment += " ";
1340 comment += end_stream.c_str() ;
1342 if (indent_comment)
1344 SendEditor(SCI_SETSEL, 0, end_indent_comment + 1);
1345 SendEditorString(SCI_REPLACESEL, 0, comment.c_str());
1347 else
1349 comment += "\n\n";
1350 SendEditorString(SCI_INSERTTEXT, 0, comment.c_str());
1353 return TRUE;
1356 #endif
1359 * Return the length of the given line, not counting the EOL.
1361 int AnEditor::GetLineLength(int line) {
1362 return SendEditor(SCI_GETLINEENDPOSITION, line) - SendEditor(SCI_POSITIONFROMLINE, line);
1365 int AnEditor::GetCurrentLineNumber() {
1366 CharacterRange crange = GetSelection();
1367 int selStart = crange.cpMin;
1368 return SendEditor(SCI_LINEFROMPOSITION, selStart);
1371 int AnEditor::GetCurrentScrollPosition() {
1372 int lineDisplayTop = SendEditor(SCI_GETFIRSTVISIBLELINE);
1373 return SendEditor(SCI_DOCLINEFROMVISIBLE, lineDisplayTop);
1376 // Upon a character being added, AnEditor may decide to perform some action
1377 // such as displaying a completion list.
1378 void AnEditor::CharAdded(char ch) {
1379 CharacterRange crange = GetSelection();
1380 int selStart = crange.cpMin;
1381 int selEnd = crange.cpMax;
1382 if ((selEnd == selStart) && (selStart > 0)) {
1383 int style = SendEditor(SCI_GETSTYLEAT, selStart - 1, 0);
1384 if (style != 1) {
1385 if (SendEditor(SCI_CALLTIPACTIVE)) { // calltip is active
1386 } else if (SendEditor(SCI_AUTOCACTIVE)) { // word autocompletion
1387 } else if (HandleXml(ch)) {
1388 // Handled in the routine
1389 } else { // we don't have autocompetion nor calltip active
1390 if (indentMaintain && indentAutomatic)
1391 MaintainIndentation(ch);
1398 * This routine will auto complete XML or HTML tags that are still open by closing them
1399 * @parm ch The characer we are dealing with, currently only works with the '/' character
1400 * @return True if handled, false otherwise
1402 bool AnEditor::HandleXml(char ch) {
1403 // We're looking for this char
1404 // Quit quickly if not found
1405 if (ch != '>') {
1406 return false;
1409 // This may make sense only in certain languages
1410 if (lexLanguage != SCLEX_HTML && lexLanguage != SCLEX_XML) {
1411 return false;
1414 // If the user has turned us off, quit now.
1415 // Default is off
1416 SString value = props->GetExpanded("xml.auto.close.tags");
1417 if ((value.length() == 0) || (value == "0")) {
1418 return false;
1421 // Grab the last 512 characters or so
1422 int nCaret = SendEditor(SCI_GETCURRENTPOS);
1423 char sel[512];
1424 int nMin = nCaret - (sizeof(sel) - 1);
1425 if (nMin < 0) {
1426 nMin = 0;
1429 if (nCaret - nMin < 3) {
1430 return false; // Smallest tag is 3 characters ex. <p>
1432 GetRange(wEditor, nMin, nCaret, sel);
1433 sel[sizeof(sel) - 1] = '\0';
1435 if (sel[nCaret - nMin - 2] == '/') {
1436 // User typed something like "<br/>"
1437 return false;
1440 SString strFound = FindOpenXmlTag(sel, nCaret - nMin);
1442 if (strFound.length() > 0) {
1443 SendEditor(SCI_BEGINUNDOACTION);
1444 SString toInsert = "</";
1445 toInsert += strFound;
1446 toInsert += ">";
1447 SendEditorString(SCI_REPLACESEL, 0, toInsert.c_str());
1448 SetSelection(nCaret, nCaret);
1449 SendEditor(SCI_ENDUNDOACTION);
1450 return true;
1453 return false;
1456 /** Search backward through nSize bytes looking for a '<', then return the tag if any
1457 * @return The tag name
1459 SString AnEditor::FindOpenXmlTag(const char sel[], int nSize) {
1460 SString strRet = "";
1462 if (nSize < 3) {
1463 // Smallest tag is "<p>" which is 3 characters
1464 return strRet;
1466 const char* pBegin = &sel[0];
1467 const char* pCur = &sel[nSize - 1];
1469 pCur--; // Skip past the >
1470 while (pCur > pBegin) {
1471 if (*pCur == '<') {
1472 break;
1473 } else if (*pCur == '>') {
1474 break;
1476 --pCur;
1479 if (*pCur == '<') {
1480 pCur++;
1481 while (strchr(":_-.", *pCur) || isalnum(*pCur)) {
1482 strRet += *pCur;
1483 pCur++;
1487 // Return the tag name or ""
1488 return strRet;
1491 void AnEditor::GoMatchingBrace(bool select) {
1492 int braceAtCaret = -1;
1493 int braceOpposite = -1;
1494 bool isInside = FindMatchingBracePosition(true, braceAtCaret, braceOpposite, true);
1495 // Convert the character positions into caret positions based on whether
1496 // the caret position was inside or outside the braces.
1497 if (isInside) {
1498 if (braceOpposite > braceAtCaret) {
1499 braceAtCaret++;
1500 } else {
1501 braceOpposite++;
1503 } else { // Outside
1504 if (braceOpposite > braceAtCaret) {
1505 braceOpposite++;
1506 } else {
1507 braceAtCaret++;
1510 if (braceOpposite >= 0) {
1511 EnsureRangeVisible(braceOpposite, braceOpposite);
1512 if (select) {
1513 SetSelection(braceAtCaret, braceOpposite);
1514 } else {
1515 SetSelection(braceOpposite, braceOpposite);
1520 int ControlIDOfCommand(unsigned long wParam) {
1521 return wParam & 0xffff;
1524 long AnEditor::Command(int cmdID, long wParam, long lParam) {
1525 switch (cmdID) {
1527 case ANE_INSERTTEXT:
1528 SendEditor(SCI_INSERTTEXT,wParam,lParam);
1529 break;
1531 case ANE_GETBOOKMARK_POS:
1532 return GetBookmarkLine( wParam );
1533 break; /* pleonastico */
1535 case ANE_BOOKMARK_TOGGLE_LINE:
1536 BookmarkToggle( wParam );
1537 break;
1539 case ANE_UNDO:
1540 SendEditor(SCI_UNDO);
1541 break;
1543 case ANE_REDO:
1544 SendEditor(SCI_REDO);
1545 break;
1547 case ANE_CUT:
1548 SendEditor(SCI_CUT);
1549 break;
1551 case ANE_COPY:
1552 SendEditor(SCI_COPY);
1553 break;
1555 case ANE_PASTE:
1556 SendEditor(SCI_PASTE);
1557 break;
1559 case ANE_CLEAR:
1560 SendEditor(SCI_CLEAR);
1561 break;
1563 case ANE_SELECTALL:
1564 SendEditor(SCI_SELECTALL);
1565 break;
1567 case ANE_FIND:
1568 return Find (wParam, (char*) lParam);
1570 case ANE_GOTOLINE:
1571 SendEditor(SCI_GOTOLINE, wParam);
1572 break;
1574 case ANE_SETZOOM:
1575 SendEditor(SCI_SETZOOM, wParam);
1576 break;
1578 case ANE_MATCHBRACE:
1579 GoMatchingBrace(false);
1580 break;
1582 case ANE_SELECTBLOCK:
1583 SelectBlock();
1584 break;
1586 case ANE_SELECTTOBRACE:
1587 GoMatchingBrace(true);
1588 break;
1590 case ANE_GETBLOCKSTARTLINE:
1591 return GetBlockStartLine();
1593 case ANE_GETBLOCKENDLINE:
1594 return GetBlockEndLine();
1596 case ANE_GETCURRENTWORD:
1597 return GetCurrentWord((char*)wParam, (int)lParam);
1599 case ANE_GETWORDBEFORECARAT:
1600 return GetWordBeforeCarat((char*)wParam, (int)lParam);
1602 case ANE_SHOWCALLTIP:
1603 StartCallTip_new();
1604 break;
1606 case ANE_COMPLETECALLTIP:
1607 CompleteCallTip();
1608 break;
1610 case ANE_COMPLETE:
1611 StartAutoComplete();
1612 break;
1614 case ANE_COMPLETEWORD:
1615 StartAutoCompleteWord(false);
1616 break;
1618 case ANE_TOGGLE_FOLD:
1619 FoldToggle();
1620 break;
1622 case ANE_OPEN_FOLDALL:
1623 FoldOpenAll();
1624 break;
1626 case ANE_CLOSE_FOLDALL:
1627 FoldCloseAll();
1628 break;
1630 case ANE_UPRCASE:
1631 SendEditor(SCI_UPPERCASE);
1632 break;
1634 case ANE_LWRCASE:
1635 SendEditor(SCI_LOWERCASE);
1636 break;
1638 case ANE_EXPAND:
1639 SendEditor(SCI_TOGGLEFOLD, GetCurrentLineNumber());
1640 break;
1642 case ANE_LINENUMBERMARGIN:
1643 lineNumbers = wParam;
1644 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ? lineNumbersWidth : 0);
1645 break;
1647 case ANE_SELMARGIN:
1648 margin = wParam;
1649 SendEditor(SCI_SETMARGINWIDTHN, 1, margin ? marginWidth : 0);
1650 break;
1652 case ANE_FOLDMARGIN:
1653 foldMargin = wParam;
1654 SendEditor(SCI_SETMARGINWIDTHN, 2, foldMargin ? foldMarginWidth : 0);
1655 break;
1657 case ANE_VIEWEOL:
1658 SendEditor(SCI_SETVIEWEOL, wParam);
1659 break;
1661 case ANE_EOL_CRLF:
1662 SendEditor(SCI_SETEOLMODE, SC_EOL_CRLF);
1663 break;
1665 case ANE_EOL_CR:
1666 SendEditor(SCI_SETEOLMODE, SC_EOL_CR);
1667 break;
1669 case ANE_EOL_LF:
1670 SendEditor(SCI_SETEOLMODE, SC_EOL_LF);
1671 break;
1673 case ANE_EOL_CONVERT:
1674 switch (wParam) {
1675 case ANE_EOL_CRLF:
1676 SendEditor(SCI_SETEOLMODE, SC_EOL_CRLF);
1677 SendEditor(SCI_CONVERTEOLS, SC_EOL_CRLF);
1678 break;
1679 case ANE_EOL_LF:
1680 SendEditor(SCI_SETEOLMODE, SC_EOL_LF);
1681 SendEditor(SCI_CONVERTEOLS, SC_EOL_LF);
1682 break;
1683 case ANE_EOL_CR:
1684 SendEditor(SCI_SETEOLMODE, SC_EOL_CR);
1685 SendEditor(SCI_CONVERTEOLS, SC_EOL_CR);
1686 break;
1687 default:
1688 SendEditor(SCI_CONVERTEOLS, SendEditor(SCI_GETEOLMODE));
1689 break;
1691 break;
1693 case ANE_WORDPARTLEFT:
1694 SendEditor(SCI_WORDPARTLEFT);
1695 break;
1697 case ANE_WORDPARTLEFTEXTEND:
1698 SendEditor(SCI_WORDPARTLEFTEXTEND);
1699 break;
1701 case ANE_WORDPARTRIGHT:
1702 SendEditor(SCI_WORDPARTRIGHT);
1703 break;
1705 case ANE_WORDPARTRIGHTEXTEND:
1706 SendEditor(SCI_WORDPARTRIGHTEXTEND);
1707 break;
1709 case ANE_VIEWSPACE:
1710 ViewWhitespace(wParam);
1711 break;
1713 case ANE_VIEWGUIDES:
1714 SendEditor(SCI_SETINDENTATIONGUIDES, wParam);
1715 break;
1717 case ANE_BOOKMARK_TOGGLE:
1718 BookmarkToggle();
1719 break;
1720 case ANE_BOOKMARK_FIRST:
1721 BookmarkFirst();
1722 break;
1723 case ANE_BOOKMARK_PREV:
1724 BookmarkPrev();
1725 break;
1726 case ANE_BOOKMARK_NEXT:
1727 BookmarkNext();
1728 break;
1729 case ANE_BOOKMARK_LAST:
1730 BookmarkLast();
1731 break;
1732 case ANE_BOOKMARK_CLEAR:
1733 BookmarkClear();
1734 break;
1736 case ANE_SETTABSIZE:
1737 SendEditor(SCI_SETTABWIDTH, wParam);
1738 break;
1740 case ANE_SETLANGUAGE:
1741 SetOverrideLanguage(wParam);
1742 break;
1744 case ANE_SETHILITE:
1745 ReadProperties((char*)wParam, (char **)lParam);
1746 SendEditor(SCI_COLOURISE, 0, -1);
1747 break;
1749 case ANE_SETACCELGROUP:
1750 SetAccelGroup((GtkAccelGroup*)wParam);
1751 break;
1753 case ANE_GETTEXTRANGE: {
1754 guint start, end;
1755 if(wParam == lParam) return 0;
1756 start = (guint) MINIMUM(wParam, lParam);
1757 end = (guint) MAXIMUM(wParam, lParam);
1758 gchar *buff = (gchar*) g_malloc(end-start+10);
1759 if(!buff) return 0;
1760 GetRange(start, end, buff, false);
1761 return (long) buff;
1763 break;
1765 case ANE_INDENT_INCREASE:
1766 IndentationIncrease();
1767 break;
1769 case ANE_INDENT_DECREASE:
1770 IndentationDecrease();
1771 break;
1773 case ANE_GETLENGTH:
1774 return SendEditor(SCI_GETLENGTH);
1776 case ANE_GET_LINENO:
1777 return GetCurrentLineNumber();
1779 case ANE_LINEWRAP:
1780 SetLineWrap((bool)wParam);
1781 break;
1783 case ANE_READONLY:
1784 SetReadOnly((bool)wParam);
1785 break;
1787 case ANE_GETSTYLEDTEXT: {
1788 guint start, end;
1789 if(wParam == lParam) return 0;
1790 start = (guint) MINIMUM(wParam, lParam);
1791 end = (guint) MAXIMUM(wParam, lParam);
1792 /* Allocate a bit more space to allow reading multi
1793 * byte characters more easily */
1794 gchar *buff = (gchar*) g_malloc((end-start+10)*2);
1795 if(!buff) return 0;
1796 GetRange(start, end, buff, true);
1797 memset (buff + (end-start) * 2, 0, 20);
1798 return (long) buff;
1800 break;
1801 case ANE_TEXTWIDTH:
1802 return SendEditor(SCI_TEXTWIDTH, wParam, lParam);
1803 case ANE_GETLANGUAGE:
1804 return (long) language.c_str();
1806 case ANE_BLOCKCOMMENT:
1807 return StartBlockComment();
1809 case ANE_BOXCOMMENT:
1810 return StartBoxComment();
1812 case ANE_STREAMCOMMENT:
1813 return StartStreamComment();
1815 case ANE_CUSTOMINDENT:
1816 return InsertCustomIndent();
1818 case ANE_WORDSELECT:
1819 WordSelect();
1820 break;
1822 case ANE_LINESELECT:
1823 LineSelect();
1824 break;
1826 case ANE_GETCURRENTPOS:
1827 return SendEditor(SCI_GETCURRENTPOS);
1829 case ANE_GOTOPOS:
1830 return SendEditor(SCI_GOTOPOS, wParam);
1832 case ANE_SETWRAPBOOKMARKS:
1833 // Nothing to do.
1834 break;
1836 case ANE_SETAUTOINDENTATION:
1837 indentAutomatic = wParam;
1838 break;
1840 case ANE_SETUSETABFORINDENT:
1841 SendEditor(SCI_SETUSETABS, wParam);
1842 break;
1844 case ANE_SETINDENTSIZE:
1845 indentSize = wParam;
1846 SendEditor(SCI_SETINDENT, wParam);
1847 break;
1849 case ANE_SETINDENTBRACESCHECK:
1850 bracesCheck = wParam;
1851 break;
1853 case ANE_SETINDENTOPENING:
1854 indentOpening = wParam;
1855 break;
1857 case ANE_SETINDENTCLOSING:
1858 indentClosing = wParam;
1859 break;
1861 case ANE_SETINDENTMAINTAIN:
1862 props->Set ("indent.maintain.*", wParam ? "1" : "0");
1863 indentMaintain = wParam;
1864 break;
1866 case ANE_SETTABINDENTS:
1867 SendEditor(SCI_SETTABINDENTS, wParam);
1868 break;
1870 case ANE_SETBACKSPACEUNINDENTS:
1871 SendEditor(SCI_SETBACKSPACEUNINDENTS, wParam);
1872 break;
1874 case ANE_SETFOLDSYMBOLS:
1875 SetFoldSymbols(reinterpret_cast<char *> (wParam));
1876 break;
1878 case ANE_SETFOLDUNDERLINE:
1879 if (wParam)
1880 SendEditor(SCI_SETFOLDFLAGS, props->GetInt("fold.flags"));
1881 else
1882 SendEditor(SCI_SETFOLDFLAGS, 0);
1883 break;
1884 case ANE_SETLINENUMWIDTH:
1885 lineNumbersWidth = wParam;
1886 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ? lineNumbersWidth : 0);
1887 break;
1888 case ANE_SETEDGECOLUMN:
1889 SendEditor(SCI_SETEDGECOLUMN, wParam);
1890 break;
1891 default:
1892 break;
1894 return 0;
1897 void AnEditor::FoldChanged(int line, int levelNow, int levelPrev) {
1898 if (levelNow & SC_FOLDLEVELHEADERFLAG) {
1899 SendEditor(SCI_SETFOLDEXPANDED, line, 1);
1900 } else if (levelPrev & SC_FOLDLEVELHEADERFLAG) {
1901 if (!SendEditor(SCI_GETFOLDEXPANDED, line)) {
1902 // Removing the fold from one that has been contracted so should expand
1903 // otherwise lines are left invisible with no way to make them visible
1904 Expand(line, true, false, 0, levelPrev);
1909 void AnEditor::Expand(int &line, bool doExpand, bool force, int visLevels, int level) {
1910 int lineMaxSubord = SendEditor(SCI_GETLASTCHILD, line, level);
1911 line++;
1912 while (line <= lineMaxSubord) {
1913 if (force) {
1914 if (visLevels > 0)
1915 SendEditor(SCI_SHOWLINES, line, line);
1916 else
1917 SendEditor(SCI_HIDELINES, line, line);
1918 } else {
1919 if (doExpand)
1920 SendEditor(SCI_SHOWLINES, line, line);
1922 int levelLine = level;
1923 if (levelLine ==-1)
1924 levelLine = SendEditor(SCI_GETFOLDLEVEL, line);
1925 if (levelLine & SC_FOLDLEVELHEADERFLAG) {
1926 if (force) {
1927 if (visLevels > 1)
1928 SendEditor(SCI_SETFOLDEXPANDED, line, 1);
1929 else
1930 SendEditor(SCI_SETFOLDEXPANDED, line, 0);
1931 Expand(line, doExpand, force, visLevels - 1);
1932 } else {
1933 if (doExpand && SendEditor(SCI_GETFOLDEXPANDED, line)) {
1934 Expand(line, true, force, visLevels - 1);
1935 } else {
1936 Expand(line, false, force, visLevels - 1);
1939 } else {
1940 line++;
1945 void AnEditor::FoldCode(bool expanding) {
1946 int maxLine = SendEditor (SCI_GETTEXTLENGTH);
1947 SendEditor(SCI_COLOURISE, 0, -1);
1948 for (int line = 0; line < maxLine; line++) {
1949 int level = SendEditor(SCI_GETFOLDLEVEL, line);
1950 if ((level & SC_FOLDLEVELHEADERFLAG) &&
1951 (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK))) {
1952 if (expanding) {
1953 SendEditor(SCI_SETFOLDEXPANDED, line, 1);
1954 Expand(line, true);
1955 line--;
1956 } else {
1957 int lineMaxSubord = SendEditor(SCI_GETLASTCHILD, line, -1);
1958 SendEditor(SCI_SETFOLDEXPANDED, line, 0);
1959 if (lineMaxSubord > line)
1960 SendEditor(SCI_HIDELINES, line + 1, lineMaxSubord);
1966 void AnEditor::FoldOpenAll() {
1967 FoldCode (true);
1970 void AnEditor::FoldCloseAll() {
1971 FoldCode (false);
1974 void AnEditor::FoldToggle() {
1975 int curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
1976 int level = SendEditor(SCI_GETFOLDLEVEL, curLine);
1977 if (level & SC_FOLDLEVELHEADERFLAG) {
1978 SendEditor(SCI_TOGGLEFOLD, curLine);
1979 return;
1981 int parent = SendEditor (SCI_GETFOLDPARENT, curLine);
1982 int lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
1983 if (curLine > parent && curLine <= lastChild)
1985 SendEditor(SCI_TOGGLEFOLD, parent);
1986 SendEditor(SCI_SETCURRENTPOS, SendEditor (SCI_POSITIONFROMLINE, parent));
1987 SendEditor(SCI_GOTOLINE, parent);
1989 else
1990 gdk_beep ();
1993 void AnEditor::SelectBlock () {
1994 int curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
1995 int parent = SendEditor (SCI_GETFOLDPARENT, curLine);
1996 int lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
1997 if (curLine > parent && curLine <= lastChild)
1999 gint start, end;
2000 start = SendEditor(SCI_POSITIONFROMLINE, parent);
2001 end = SendEditor(SCI_POSITIONFROMLINE, lastChild+1);
2002 SetSelection(start, end);
2004 else
2005 gdk_beep ();
2008 int AnEditor::GetBlockStartLine (int curLine) {
2009 if(curLine < 0)
2011 curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
2013 int level = SendEditor(SCI_GETFOLDLEVEL, curLine);
2014 if (level & SC_FOLDLEVELHEADERFLAG) {
2015 return curLine;
2017 int parent = -1;
2018 int lastChild = curLine;
2019 while(parent == -1)
2021 parent = SendEditor (SCI_GETFOLDPARENT, lastChild);
2022 if (parent == -1)
2024 return -1;
2026 lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
2027 if (curLine > parent && curLine <= lastChild)
2029 return parent;
2031 lastChild = parent - 1;
2032 parent = -1;
2034 return -1;
2037 int AnEditor::GetBlockEndLine (int curLine) {
2038 if(curLine < 0)
2040 curLine = SendEditor(SCI_LINEFROMPOSITION, SendEditor (SCI_GETCURRENTPOS));
2042 int level = SendEditor(SCI_GETFOLDLEVEL, curLine);
2043 if (level & SC_FOLDLEVELHEADERFLAG) {
2044 /* this may be a problem when we use this function on "start" block line */
2045 return curLine;
2047 int parent = -1;
2048 int lastChild = curLine;
2049 while(parent == -1)
2051 parent = SendEditor (SCI_GETFOLDPARENT, lastChild);
2052 if (parent == -1)
2054 return -1;
2056 lastChild = SendEditor (SCI_GETLASTCHILD, parent, -1);
2057 if (curLine > parent && curLine <= lastChild)
2059 return lastChild;
2061 lastChild = parent - 1;
2062 parent = -1;
2064 return -1;
2067 void AnEditor::EnsureRangeVisible(int posStart, int posEnd) {
2068 int lineStart = SendEditor(SCI_LINEFROMPOSITION, Platform::Minimum(posStart, posEnd));
2069 int lineEnd = SendEditor(SCI_LINEFROMPOSITION, Platform::Maximum(posStart, posEnd));
2070 for (int line = lineStart; line <= lineEnd; line++) {
2071 SendEditor(SCI_ENSUREVISIBLE, line);
2075 void AnEditor::SetLineWrap(bool wrap) {
2076 wrapLine = wrap;
2077 SendEditor(SCI_SETWRAPMODE, wrapLine ? SC_WRAP_WORD : SC_WRAP_NONE);
2078 SendEditor(SCI_SETHSCROLLBAR, !wrapLine);
2081 void AnEditor::SetReadOnly(bool readonly) {
2082 isReadOnly = readonly;
2083 SendEditor(SCI_SETREADONLY, isReadOnly);
2086 bool AnEditor::MarginClick(int position, int modifiers) {
2087 int lineClick = SendEditor(SCI_LINEFROMPOSITION, position);
2088 // SendEditor(SCI_GETFOLDLEVEL, lineClick) & SC_FOLDLEVELHEADERFLAG);
2089 if (modifiers & SCMOD_SHIFT) {
2090 FoldCloseAll();
2091 } else if (modifiers & SCMOD_CTRL) {
2092 FoldOpenAll();
2093 } else if (SendEditor(SCI_GETFOLDLEVEL, lineClick) & SC_FOLDLEVELHEADERFLAG) {
2094 if (modifiers & SCMOD_SHIFT) {
2095 // Ensure all children visible
2096 SendEditor(SCI_SETFOLDEXPANDED, lineClick, 1);
2097 Expand(lineClick, true, true, 100);
2098 } else if (modifiers & SCMOD_CTRL) {
2099 if (SendEditor(SCI_GETFOLDEXPANDED, lineClick)) {
2100 // Contract this line and all children
2101 SendEditor(SCI_SETFOLDEXPANDED, lineClick, 0);
2102 Expand(lineClick, false, true, 0);
2103 } else {
2104 // Expand this line and all children
2105 SendEditor(SCI_SETFOLDEXPANDED, lineClick, 1);
2106 Expand(lineClick, true, true, 100);
2108 } else {
2109 // Toggle this line
2110 SendEditor(SCI_TOGGLEFOLD, lineClick);
2113 return true;
2116 #if 0
2117 gint AnEditor::KeyPressEvent(GtkWidget *, GdkEventKey *event, AnEditor *anedit) {
2118 return anedit->KeyPress(event->state, event->keyval);
2120 #endif
2122 void AnEditor::NotifySignal(GtkWidget *, gint /*wParam*/, gpointer lParam, AnEditor *anedit) {
2123 anedit->Notify(reinterpret_cast<SCNotification *>(lParam));
2126 // FIXME:
2127 #if 0
2128 void
2129 eval_output_arrived_for_aneditor(GList* lines, gpointer data)
2131 // We expect lines->data to be a string of the form VARIABLE = VALUE,
2132 // and 'data' to be a pointer to an object of type
2133 // 'ExpressionEvaluationTipInfo'.
2135 if (data == NULL)
2136 return;
2138 auto_ptr<ExpressionEvaluationTipInfo> info(
2139 (ExpressionEvaluationTipInfo *) data);
2141 if (info->editor == NULL)
2142 return;
2144 if (info->editor != aneditor_get(AnEditor::focusedID))
2145 return;
2147 info->editor->EvalOutputArrived(lines, info->textPos, info->expression);
2150 void AnEditor::EvalOutputArrived(GList* lines, int textPos,
2151 const string &expression) {
2153 if (textPos <= 0)
2154 return;
2156 // Return if debug Tip has been canceled
2157 if (!debugTipOn)
2158 return;
2160 if (g_list_length(lines) == 0 || lines->data == NULL)
2161 return;
2163 string result = (char *) lines->data;
2164 string::size_type posEquals = result.find(" = ");
2165 if (posEquals != string::npos)
2166 result.replace(0, posEquals, expression);
2168 SendEditorString(SCI_CALLTIPSHOW, textPos, result.c_str());
2169 SendEditor(SCI_CALLTIPSETHLT, 0, result.length());
2172 void AnEditor::EndDebugEval() {
2173 if (debugTipOn)
2175 SendEditor(SCI_CALLTIPCANCEL);
2176 debugTipOn = false;
2180 void AnEditor::HandleDwellStart(int mousePos) {
2181 if (mousePos == -1)
2182 return;
2184 char expr[256];
2185 if (!debugger_is_active() || !debugger_is_ready())
2187 // Do not show expression tip if it can't be shown.
2188 // string s = string(expr) + ": " + _("debugger not active");
2189 // SendEditorString(SCI_CALLTIPSHOW, mousePos, s.c_str());
2190 return;
2192 // If debug tip is already running, return.
2193 if (debugTipOn)
2194 return;
2196 CharacterRange crange = GetSelection();
2197 if (crange.cpMin == crange.cpMax
2198 || mousePos < crange.cpMin
2199 || mousePos >= crange.cpMax)
2201 // There is no selection, or the mouse pointer is
2202 // out of the selection, so we search for a word
2203 // around the mouse pointer:
2204 if (!GetWordAtPosition(expr, sizeof(expr), mousePos))
2205 return;
2207 else
2209 long lensel = crange.cpMax - crange.cpMin;
2210 long max = sizeof(expr) - 1;
2211 guint end = (lensel < max ? crange.cpMax : crange.cpMin + max);
2212 GetRange(crange.cpMin, end, expr, false);
2214 // If there is any control character except TAB
2215 // in the expression, disregard it.
2216 size_t i;
2217 for (i = 0; i < end - crange.cpMin; i++)
2218 if ((unsigned char) expr[i] < ' ' && expr[i] != '\t')
2219 return;
2220 if (i < end - crange.cpMin)
2221 return;
2224 // Imitation of on_eval_ok_clicked():
2225 // The function eval_output_arrived_for_aneditor() will
2226 // be called eventually by the debugger with the result
2227 // of the print command for 'expr', and with the 'info'
2228 // pointer. That function must call delete on 'info'.
2230 // We don't turn GDB "pretty printing" on because we want
2231 // the entire value on a single line, in the case of a
2232 // struct or class.
2233 // We don't want static members of classes to clutter up
2234 // the displayed tip, however.
2236 ExpressionEvaluationTipInfo *info =
2237 new ExpressionEvaluationTipInfo(this, mousePos, expr);
2238 debugger_query_evaluate_expr_tip (expr, eval_output_arrived_for_aneditor, info);
2239 debugger_query_execute ();
2240 debugTipOn = true;
2242 #endif
2244 #if 0
2245 int AnEditor::KeyPress(unsigned int state, unsigned int keyval){
2247 unsigned int mask = GDK_SHIFT_MASK | GDK_LOCK_MASK |
2248 GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_MOD3_MASK |
2249 GDK_MOD4_MASK | GDK_MOD5_MASK;
2250 if (state & mask)
2251 return false;
2253 // Trap 'TAB' key for automatic indentation.
2254 // printf ("Key is '%c'\n", notification->ch);
2255 if ((keyval == GDK_Tab) &&
2256 (lexLanguage == SCLEX_CPP) &&
2257 (!indentMaintain) &&
2258 (props->GetInt("indent.automatic")) &&
2259 (!SendEditor(SCI_CALLTIPACTIVE)) &&
2260 (!SendEditor(SCI_AUTOCACTIVE))) {
2262 CharacterRange crange = GetSelection();
2263 int selStart = crange.cpMin;
2264 int selEnd = crange.cpMax;
2266 if (selStart == selEnd) {
2267 AutomaticIndentation('\t');
2268 return true;
2271 return false;
2273 #endif
2275 void AnEditor::Notify(SCNotification *notification) {
2276 switch (notification->nmhdr.code) {
2277 case SCN_CALLTIPCLICK:
2278 if (notification->position == 1) {
2279 call_tip_node.def_index--;
2280 if (call_tip_node.def_index < 0)
2281 call_tip_node.def_index = 0;
2283 if (notification->position == 2) {
2284 call_tip_node.def_index++;
2285 if (call_tip_node.def_index >= call_tip_node.max_def)
2286 call_tip_node.def_index = call_tip_node.max_def - 1;
2288 ResumeCallTip (false);
2289 break;
2290 case SCN_KEY: {
2291 if(!accelGroup) break;
2292 int mods = 0;
2293 if (notification->modifiers & SCMOD_SHIFT)
2294 mods |= GDK_SHIFT_MASK;
2295 if (notification->modifiers & SCMOD_CTRL)
2296 mods |= GDK_CONTROL_MASK;
2297 if (notification->modifiers & SCMOD_ALT)
2298 mods |= GDK_MOD1_MASK;
2299 gtk_accel_groups_activate(G_OBJECT (accelGroup), notification->ch,
2300 static_cast<GdkModifierType>(mods));
2303 case SCN_CHARADDED:
2304 CharAdded(static_cast<char>(notification->ch));
2305 break;
2307 case SCN_SAVEPOINTREACHED:
2308 isDirty = false;
2309 break;
2311 case SCN_SAVEPOINTLEFT:
2312 isDirty = true;
2313 break;
2315 case SCN_UPDATEUI:
2317 int pos = SendEditor(SCI_GETCURRENTPOS);
2318 BraceMatch(true);
2319 if (SendEditor(SCI_CALLTIPACTIVE) ) {
2320 // if we have a caret movement on left or right
2321 if (abs(pos - lastPos) == 1 ) {
2322 ContinueCallTip_new();
2325 lastPos = pos;
2327 break;
2329 case SCN_MODIFIED:
2330 if (notification->modificationType == SC_MOD_CHANGEFOLD) {
2331 FoldChanged(notification->line,
2332 notification->foldLevelNow, notification->foldLevelPrev);
2334 break;
2336 case SCN_MARGINCLICK:
2337 if (notification->margin == 2)
2338 MarginClick(notification->position, notification->modifiers);
2339 break;
2341 case SCN_NEEDSHOWN: {
2342 EnsureRangeVisible(notification->position, notification->position + notification->length);
2344 break;
2346 case SCN_DWELLSTART:
2347 HandleDwellStart(notification->position);
2348 break;
2350 case SCN_DWELLEND:
2351 EndDebugEval();
2352 // SendEditor(SCI_CALLTIPCANCEL);
2353 break;
2358 static int IntFromHexDigit(const char ch) {
2359 if (isdigit(ch))
2360 return ch - '0';
2361 else if (ch >= 'A' && ch <= 'F')
2362 return ch - 'A' + 10;
2363 else if (ch >= 'a' && ch <= 'f')
2364 return ch - 'a' + 10;
2365 else
2366 return 0;
2369 static Colour ColourFromString(const char *val) {
2370 int r = IntFromHexDigit(val[1]) * 16 + IntFromHexDigit(val[2]);
2371 int g = IntFromHexDigit(val[3]) * 16 + IntFromHexDigit(val[4]);
2372 int b = IntFromHexDigit(val[5]) * 16 + IntFromHexDigit(val[6]);
2373 return Colour(r, g, b);
2376 static long ColourOfProperty(PropSetFile *props, const char *key, ColourDesired colourDefault) {
2377 SString colour = props->Get(key);
2378 if (colour.length()) {
2379 return ColourFromString(colour.c_str()).AsLong();
2381 return colourDefault.AsLong();
2384 void AnEditor::SetOneStyle(Window &win, int style, const char *s) {
2385 char *val = StringDup(s);
2386 char *opt = val;
2387 while (opt) {
2388 char *cpComma = strchr(opt, ',');
2389 if (cpComma)
2390 *cpComma = '\0';
2391 char *colon = strchr(opt, ':');
2392 if (colon)
2393 *colon++ = '\0';
2394 if (0 == strcmp(opt, "italics"))
2395 Platform::SendScintilla(win.GetID(), SCI_STYLESETITALIC, style, 1);
2396 if (0 == strcmp(opt, "notitalics"))
2397 Platform::SendScintilla(win.GetID(), SCI_STYLESETITALIC, style, 0);
2398 if (0 == strcmp(opt, "bold"))
2399 Platform::SendScintilla(win.GetID(), SCI_STYLESETBOLD, style, 1);
2400 if (0 == strcmp(opt, "notbold"))
2401 Platform::SendScintilla(win.GetID(), SCI_STYLESETBOLD, style, 0);
2402 if (0 == strcmp(opt, "font"))
2403 Platform::SendScintilla(win.GetID(), SCI_STYLESETFONT, style, reinterpret_cast<long>(colon));
2404 if (0 == strcmp(opt, "fore"))
2405 Platform::SendScintilla(win.GetID(), SCI_STYLESETFORE, style, ColourFromString(colon).AsLong());
2406 if (0 == strcmp(opt, "back"))
2407 Platform::SendScintilla(win.GetID(), SCI_STYLESETBACK, style, ColourFromString(colon).AsLong());
2408 if (0 == strcmp(opt, "size"))
2409 Platform::SendScintilla(win.GetID(), SCI_STYLESETSIZE, style, atoi(colon));
2410 if (0 == strcmp(opt, "eolfilled"))
2411 Platform::SendScintilla(win.GetID(), SCI_STYLESETEOLFILLED, style, 1);
2412 if (0 == strcmp(opt, "noteolfilled"))
2413 Platform::SendScintilla(win.GetID(), SCI_STYLESETEOLFILLED, style, 0);
2414 if (0 == strcmp(opt, "underlined"))
2415 Platform::SendScintilla(win.GetID(), SCI_STYLESETUNDERLINE, style, 1);
2416 if (0 == strcmp(opt, "notunderlined"))
2417 Platform::SendScintilla(win.GetID(), SCI_STYLESETUNDERLINE, style, 0);
2418 if (0 == strcmp(opt, "case")) {
2419 if (*colon == 'u') {
2420 Platform::SendScintilla(win.GetID(), SCI_STYLESETCASE, style, SC_CASE_UPPER);
2421 } else if (*colon == 'l') {
2422 Platform::SendScintilla(win.GetID(), SCI_STYLESETCASE, style, SC_CASE_LOWER);
2423 } else {
2424 Platform::SendScintilla(win.GetID(), SCI_STYLESETCASE, style, SC_CASE_MIXED);
2427 if (0 == strcmp(opt, "visible"))
2428 Platform::SendScintilla(win.GetID(), SCI_STYLESETVISIBLE, style, 1);
2429 if (0 == strcmp(opt, "notvisible"))
2430 Platform::SendScintilla(win.GetID(), SCI_STYLESETVISIBLE, style, 0);
2431 if (0 == strcmp(opt, "changeable"))
2432 Platform::SendScintilla(win.GetID(), SCI_STYLESETCHANGEABLE, style, 1);
2433 if (0 == strcmp(opt, "notchangeable"))
2434 Platform::SendScintilla(win.GetID(), SCI_STYLESETCHANGEABLE, style, 0);
2435 if (cpComma)
2436 opt = cpComma + 1;
2437 else
2438 opt = 0;
2440 if (val)
2441 delete []val;
2442 Platform::SendScintilla(win.GetID(), SCI_STYLESETCHARACTERSET, style, characterSet);
2445 void AnEditor::SetStyleFor(Window &win, const char *lang) {
2446 for (int style = 0; style <= STYLE_MAX; style++) {
2447 if (style != STYLE_DEFAULT) {
2448 char key[200];
2449 sprintf(key, "style.%s.%0d", lang, style);
2450 SString sval = props->GetExpanded(key);
2451 // g_print ("Style for %s:%0d == %s\n", lang, style, sval.c_str());
2452 SetOneStyle(win, style, sval.c_str());
2457 void lowerCaseString(char *s) {
2458 while (*s) {
2459 *s = static_cast<char>(tolower(*s));
2460 s++;
2464 SString AnEditor::ExtensionFileName() {
2465 if (overrideExtension.length())
2466 return overrideExtension;
2467 else if (fileName[0]) {
2468 // Force extension to lower case
2469 char fileNameWithLowerCaseExtension[MAX_PATH];
2470 strcpy(fileNameWithLowerCaseExtension, fileName);
2471 char *extension = strrchr(fileNameWithLowerCaseExtension, '.');
2472 if (extension) {
2473 lowerCaseString(extension);
2475 return SString(fileNameWithLowerCaseExtension);
2476 } else
2477 return props->Get("default.file.ext");
2480 void AnEditor::ForwardPropertyToEditor(const char *key) {
2481 SString value = props->Get(key);
2482 SendEditorString(SCI_SETPROPERTY,
2483 reinterpret_cast<uptr_t>(key), value.c_str());
2486 SString AnEditor::FindLanguageProperty(const char *pattern, const char *defaultValue) {
2487 SString key = pattern;
2488 key.substitute("*", language.c_str());
2489 SString ret = props->GetExpanded(key.c_str());
2490 if (ret == "")
2491 ret = props->GetExpanded(pattern);
2492 if (ret == "")
2493 ret = defaultValue;
2494 return ret;
2497 void AnEditor::ReadProperties(const char *fileForExt, char **typedef_hl) {
2498 //DWORD dwStart = timeGetTime();
2499 if (fileForExt)
2500 strcpy (fileName, fileForExt);
2501 else
2502 fileName[0] = '\0';
2504 SString fileNameForExtension;
2505 if(overrideExtension.length())
2506 fileNameForExtension = overrideExtension;
2507 else {
2508 fileNameForExtension = fileForExt;
2511 language = props->GetNewExpand("lexer.", fileNameForExtension.c_str());
2512 SendEditorString(SCI_SETLEXERLANGUAGE, 0, language.c_str());
2513 lexLanguage = SendEditor(SCI_GETLEXER);
2515 if ((lexLanguage == SCLEX_HTML) || (lexLanguage == SCLEX_XML))
2516 SendEditor(SCI_SETSTYLEBITS, 7);
2517 else
2518 SendEditor(SCI_SETSTYLEBITS, 5);
2520 SendEditor(SCI_SETLEXER, lexLanguage);
2522 SString kw0 = props->GetNewExpand("keywords.", fileNameForExtension.c_str());
2523 SendEditorString(SCI_SETKEYWORDS, 0, kw0.c_str());
2524 SString kw2 = props->GetNewExpand("keywords3.", fileNameForExtension.c_str());
2525 SendEditorString(SCI_SETKEYWORDS, 2, kw2.c_str());
2526 /* For C/C++ projects, get list of typedefs for colorizing */
2527 if (SCLEX_CPP == lexLanguage)
2529 SString kw1 = props->GetNewExpand("keywords2.", fileNameForExtension.c_str());
2530 SString kw3 = props->GetNewExpand("keywords4.", fileNameForExtension.c_str());
2531 if (typedef_hl != NULL)
2533 if (typedef_hl[0] != NULL)
2535 kw3 += ' ';
2536 kw3 += typedef_hl[0];
2538 if (typedef_hl[1] != NULL)
2540 kw1 += ' ';
2541 kw1 += typedef_hl[1];
2544 SendEditorString(SCI_SETKEYWORDS, 3, kw3.c_str());
2545 SendEditorString(SCI_SETKEYWORDS, 1, kw1.c_str());
2547 else
2549 SString kw1 = props->GetNewExpand("keywords2.", fileNameForExtension.c_str());
2550 SendEditorString(SCI_SETKEYWORDS, 1, kw1.c_str());
2551 SString kw3 = props->GetNewExpand("keywords4.", fileNameForExtension.c_str());
2552 SendEditorString(SCI_SETKEYWORDS, 3, kw3.c_str());
2553 SString kw4 = props->GetNewExpand("keywords5.", fileNameForExtension.c_str());
2554 SendEditorString(SCI_SETKEYWORDS, 4, kw4.c_str());
2555 SString kw5 = props->GetNewExpand("keywords6.", fileNameForExtension.c_str());
2556 SendEditorString(SCI_SETKEYWORDS, 5, kw5.c_str());
2559 ForwardPropertyToEditor("fold");
2560 ForwardPropertyToEditor("fold.use.plus");
2561 ForwardPropertyToEditor("fold.comment");
2562 ForwardPropertyToEditor("fold.comment.python");
2563 ForwardPropertyToEditor("fold.compact");
2564 ForwardPropertyToEditor("fold.html");
2565 ForwardPropertyToEditor("fold.preprocessor");
2566 ForwardPropertyToEditor("fold.quotes.python");
2567 ForwardPropertyToEditor("styling.within.preprocessor");
2568 ForwardPropertyToEditor("tab.timmy.whinge.level");
2569 ForwardPropertyToEditor("asp.default.language");
2571 // codePage = props->GetInt("code.page");
2572 //if (unicodeMode != uni8Bit) {
2573 // Override properties file to ensure Unicode displayed.
2574 // codePage = SC_CP_UTF8;
2575 // }
2576 // SendEditor(SCI_SETCODEPAGE, codePage);
2578 // Use unicode everytime.
2579 SendEditor(SCI_SETCODEPAGE, SC_CP_UTF8);
2581 characterSet = props->GetInt("character.set");
2582 setlocale(LC_CTYPE, props->Get("LC_CTYPE").c_str());
2584 SendEditor(SCI_SETCARETFORE,
2585 ColourOfProperty(props, "caret.fore", ColourDesired(0, 0, 0)));
2586 SendEditor(SCI_SETCARETWIDTH, props->GetInt("caret.width", 1));
2587 SendEditor(SCI_SETMOUSEDWELLTIME, props->GetInt("dwell.period", 750), 0);
2589 SString caretLineBack = props->Get("caret.line.back");
2590 if (caretLineBack.length()) {
2591 SendEditor(SCI_SETCARETLINEVISIBLE, 1);
2592 SendEditor(SCI_SETCARETLINEBACK,
2593 ColourFromString(caretLineBack.c_str()).AsLong());
2594 } else {
2595 SendEditor(SCI_SETCARETLINEVISIBLE, 0);
2598 SString controlCharSymbol = props->Get("control.char.symbol");
2599 if (controlCharSymbol.length()) {
2600 SendEditor(SCI_SETCONTROLCHARSYMBOL, static_cast<unsigned char>(controlCharSymbol[0]));
2601 } else {
2602 SendEditor(SCI_SETCONTROLCHARSYMBOL, 0);
2605 SendEditor(SCI_CALLTIPSETBACK,
2606 ColourOfProperty(props, "calltip.back", ColourDesired(0xff, 0xff, 0xff)));
2608 SString caretPeriod = props->Get("caret.period");
2609 if (caretPeriod.length()) {
2610 SendEditor(SCI_SETCARETPERIOD, caretPeriod.value());
2613 int caretSlop = props->GetInt("caret.policy.xslop", 1) ? CARET_SLOP : 0;
2614 int caretZone = props->GetInt("caret.policy.width", 50);
2615 int caretStrict = props->GetInt("caret.policy.xstrict") ? CARET_STRICT : 0;
2616 int caretEven = props->GetInt("caret.policy.xeven", 1) ? CARET_EVEN : 0;
2617 int caretJumps = props->GetInt("caret.policy.xjumps") ? CARET_JUMPS : 0;
2618 SendEditor(SCI_SETXCARETPOLICY, caretStrict | caretSlop | caretEven | caretJumps, caretZone);
2620 caretSlop = props->GetInt("caret.policy.yslop", 1) ? CARET_SLOP : 0;
2621 caretZone = props->GetInt("caret.policy.lines");
2622 caretStrict = props->GetInt("caret.policy.ystrict") ? CARET_STRICT : 0;
2623 caretEven = props->GetInt("caret.policy.yeven", 1) ? CARET_EVEN : 0;
2624 caretJumps = props->GetInt("caret.policy.yjumps") ? CARET_JUMPS : 0;
2625 SendEditor(SCI_SETYCARETPOLICY, caretStrict | caretSlop | caretEven | caretJumps, caretZone);
2627 int visibleStrict = props->GetInt("visible.policy.strict") ? VISIBLE_STRICT : 0;
2628 int visibleSlop = props->GetInt("visible.policy.slop", 1) ? VISIBLE_SLOP : 0;
2629 int visibleLines = props->GetInt("visible.policy.lines");
2630 SendEditor(SCI_SETVISIBLEPOLICY, visibleStrict | visibleSlop, visibleLines);
2632 SendEditor(SCI_SETEDGECOLUMN, props->GetInt("edge.column", 0));
2633 SendEditor(SCI_SETEDGEMODE, props->GetInt("edge.mode", EDGE_NONE));
2634 SendEditor(SCI_SETEDGECOLOUR,
2635 ColourOfProperty(props, "edge.colour", ColourDesired(0xff, 0xda, 0xda)));
2637 SString selfore = props->Get("selection.fore");
2638 if (selfore.length()) {
2639 SendEditor(SCI_SETSELFORE, 1, ColourFromString(selfore.c_str()).AsLong());
2640 } else {
2641 SendEditor(SCI_SETSELFORE, 0, 0);
2643 SString selBack = props->Get("selection.back");
2644 if (selBack.length()) {
2645 SendEditor(SCI_SETSELBACK, 1, ColourFromString(selBack.c_str()).AsLong());
2646 } else {
2647 if (selfore.length())
2648 SendEditor(SCI_SETSELBACK, 0, 0);
2649 else // Have to show selection somehow
2650 SendEditor(SCI_SETSELBACK, 1, ColourDesired(0xC0, 0xC0, 0xC0).AsLong());
2653 SString whitespaceFore = props->Get("whitespace.fore");
2654 if (whitespaceFore.length()) {
2655 SendEditor(SCI_SETWHITESPACEFORE, 1, ColourFromString(whitespaceFore.c_str()).AsLong());
2656 } else {
2657 SendEditor(SCI_SETWHITESPACEFORE, 0, 0);
2659 SString whitespaceBack = props->Get("whitespace.back");
2660 if (whitespaceBack.length()) {
2661 SendEditor(SCI_SETWHITESPACEBACK, 1, ColourFromString(whitespaceBack.c_str()).AsLong());
2662 } else {
2663 SendEditor(SCI_SETWHITESPACEBACK, 0, 0);
2666 for (int i = 0; i < 3; i++) {
2668 SString value_str;
2669 long default_indic_type[] = {INDIC_TT, INDIC_DIAGONAL, INDIC_SQUIGGLE};
2670 const char *default_indic_color[] = {"0000FF", "#00FF00", "#FF0000"};
2671 const char *style_name[] = {"normal", "warning", "error"};
2672 char key[200];
2673 sprintf(key, "indicators.style.%s", style_name[i]);
2675 value_str = props->Get(key);
2676 if (value_str.length() > 0) {
2677 if (strcasecmp (value_str.c_str(), "underline-plain") == 0) {
2678 SendEditor(SCI_INDICSETSTYLE, i, INDIC_PLAIN);
2679 } else if (strcasecmp (value_str.c_str(), "underline-tt") == 0) {
2680 SendEditor(SCI_INDICSETSTYLE, i, INDIC_TT);
2681 } else if (strcasecmp (value_str.c_str(), "underline-squiggle") == 0) {
2682 SendEditor(SCI_INDICSETSTYLE, i, INDIC_SQUIGGLE);
2683 } else if (strcasecmp (value_str.c_str(), "strike-out") == 0) {
2684 SendEditor(SCI_INDICSETSTYLE, i, INDIC_STRIKE);
2685 } else if (strcasecmp (value_str.c_str(), "diagonal") == 0) {
2686 SendEditor(SCI_INDICSETSTYLE, i, INDIC_DIAGONAL);
2687 } else {
2688 SendEditor(SCI_INDICSETSTYLE, i, default_indic_type[i]);
2690 } else {
2691 SendEditor(SCI_INDICSETSTYLE, i, default_indic_type[i]);
2693 sprintf(key, "indicator.%d.color", i);
2694 value_str = props->GetExpanded(key);
2695 if (value_str.length()) {
2696 SendEditor(SCI_INDICSETFORE, i, ColourFromString(value_str.c_str()).AsLong());
2697 } else {
2698 SendEditor(SCI_INDICSETFORE, i, ColourFromString(default_indic_color[i]).AsLong());
2702 char bracesStyleKey[200];
2703 sprintf(bracesStyleKey, "braces.%s.style", language.c_str());
2704 bracesStyle = props->GetInt(bracesStyleKey, 0);
2706 char key[200];
2707 SString sval;
2709 sval = FindLanguageProperty("calltip.*.ignorecase");
2710 callTipIgnoreCase = sval == "1";
2712 calltipWordCharacters = FindLanguageProperty("calltip.*.word.characters",
2713 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
2715 calltipEndDefinition = FindLanguageProperty("calltip.*.end.definition");
2717 sprintf(key, "autocomplete.%s.start.characters", language.c_str());
2718 autoCompleteStartCharacters = props->GetExpanded(key);
2719 if (autoCompleteStartCharacters == "")
2720 autoCompleteStartCharacters = props->GetExpanded("autocomplete.*.start.characters");
2721 // "" is a quite reasonable value for this setting
2723 sprintf(key, "autocomplete.%s.fillups", language.c_str());
2724 autoCompleteFillUpCharacters = props->GetExpanded(key);
2725 if (autoCompleteFillUpCharacters == "")
2726 autoCompleteFillUpCharacters =
2727 props->GetExpanded("autocomplete.*.fillups");
2728 SendEditorString(SCI_AUTOCSETFILLUPS, 0,
2729 autoCompleteFillUpCharacters.c_str());
2731 sprintf(key, "autocomplete.%s.ignorecase", "*");
2732 sval = props->GetNewExpand(key, "");
2733 autoCompleteIgnoreCase = sval == "1";
2734 sprintf(key, "autocomplete.%s.ignorecase", language.c_str());
2735 sval = props->GetNewExpand(key, "");
2736 if (sval != "")
2737 autoCompleteIgnoreCase = sval == "1";
2738 SendEditor(SCI_AUTOCSETIGNORECASE, autoCompleteIgnoreCase ? 1 : 0);
2740 int autoCChooseSingle = props->GetInt("autocomplete.choose.single");
2741 SendEditor(SCI_AUTOCSETCHOOSESINGLE, autoCChooseSingle),
2743 SendEditor(SCI_AUTOCSETCANCELATSTART, 0),
2744 SendEditor(SCI_AUTOCSETDROPRESTOFWORD, 0),
2746 // Set styles
2747 // For each window set the global default style,
2748 // then the language default style,
2749 // then the other global styles,
2750 // then the other language styles
2752 SendEditor(SCI_STYLERESETDEFAULT, 0, 0);
2754 sprintf(key, "style.%s.%0d", "*", STYLE_DEFAULT);
2755 sval = props->GetNewExpand(key, "");
2756 SetOneStyle(wEditor, STYLE_DEFAULT, sval.c_str());
2758 sprintf(key, "style.%s.%0d", language.c_str(), STYLE_DEFAULT);
2759 sval = props->GetNewExpand(key, "");
2760 SetOneStyle(wEditor, STYLE_DEFAULT, sval.c_str());
2762 SendEditor(SCI_STYLECLEARALL, 0, 0);
2764 SetStyleFor(wEditor, "*");
2765 SetStyleFor(wEditor, language.c_str());
2767 if (firstPropertiesRead) {
2768 ReadPropertiesInitial();
2771 /* Gtk handles it correctly */
2772 SendEditor(SCI_SETUSEPALETTE, 0);
2774 SendEditor(SCI_SETPRINTMAGNIFICATION, props->GetInt("print.magnification"));
2775 SendEditor(SCI_SETPRINTCOLOURMODE, props->GetInt("print.colour.mode"));
2777 int blankMarginLeft = props->GetInt("blank.margin.left", 1);
2778 int blankMarginRight = props->GetInt("blank.margin.right", 1);
2779 SendEditor(SCI_SETMARGINLEFT, 0, blankMarginLeft);
2780 SendEditor(SCI_SETMARGINRIGHT, 0, blankMarginRight);
2782 SendEditor(SCI_SETMARGINWIDTHN, 1, margin ? marginWidth : 0);
2783 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ?lineNumbersWidth : 0);
2785 bufferedDraw = props->GetInt("buffered.draw", 1);
2786 SendEditor(SCI_SETBUFFEREDDRAW, bufferedDraw);
2788 SendEditor(SCI_SETLAYOUTCACHE, props->GetInt("cache.layout"));
2790 bracesCheck = props->GetInt("braces.check");
2791 bracesSloppy = props->GetInt("braces.sloppy");
2793 wordCharacters = props->GetNewExpand("word.characters.", fileNameForExtension.c_str());
2794 if (wordCharacters.length()) {
2795 SendEditorString(SCI_SETWORDCHARS, 0, wordCharacters.c_str());
2796 } else {
2797 SendEditor(SCI_SETWORDCHARS, 0, 0);
2798 wordCharacters = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2800 // Why call this??
2801 // SendEditor(SCI_MARKERDELETEALL, static_cast<unsigned long>( -1));
2803 SendEditor(SCI_SETTABINDENTS, props->GetInt("tab.indents", 1));
2804 SendEditor(SCI_SETBACKSPACEUNINDENTS, props->GetInt("backspace.unindents", 1));
2806 SendEditor(SCI_SETUSETABS, props->GetInt("use.tabs", 1));
2807 int tabSize = props->GetInt("tabsize");
2808 if (tabSize) {
2809 SendEditor(SCI_SETTABWIDTH, tabSize);
2811 indentSize = props->GetInt("indent.size");
2812 SendEditor(SCI_SETINDENT, indentSize);
2814 indentOpening = props->GetInt("indent.opening");
2815 indentClosing = props->GetInt("indent.closing");
2817 indentMaintain = props->GetNewExpand("indent.maintain.", fileNameForExtension.c_str()).value();
2819 SString lookback = props->GetNewExpand("statement.lookback.", fileNameForExtension.c_str());
2820 statementLookback = lookback.value();
2821 statementIndent = GetStyleAndWords("statement.indent.");
2822 statementEnd =GetStyleAndWords("statement.end.");
2823 blockStart = GetStyleAndWords("block.start.");
2824 blockEnd = GetStyleAndWords("block.end.");
2828 SString list;
2829 list = props->GetNewExpand("preprocessor.symbol.", fileNameForExtension.c_str());
2830 preprocessorSymbol = list[0];
2831 list = props->GetNewExpand("preprocessor.start.", fileNameForExtension.c_str());
2832 preprocCondStart.Clear();
2833 preprocCondStart.Set(list.c_str());
2834 list = props->GetNewExpand("preprocessor.middle.", fileNameForExtension.c_str());
2835 preprocCondMiddle.Clear();
2836 preprocCondMiddle.Set(list.c_str());
2837 list = props->GetNewExpand("preprocessor.end.", fileNameForExtension.c_str());
2838 preprocCondEnd.Clear();
2839 preprocCondEnd.Set(list.c_str());
2842 if (props->GetInt("vc.home.key", 1)) {
2843 AssignKey(SCK_HOME, 0, SCI_VCHOME);
2844 AssignKey(SCK_HOME, SCMOD_SHIFT, SCI_VCHOMEEXTEND);
2845 } else {
2846 AssignKey(SCK_HOME, 0, SCI_HOME);
2847 AssignKey(SCK_HOME, SCMOD_SHIFT, SCI_HOMEEXTEND);
2849 if (props->GetInt("fold.underline"))
2850 SendEditor(SCI_SETFOLDFLAGS, props->GetInt("fold.flags"));
2851 else
2852 SendEditor(SCI_SETFOLDFLAGS, 0);
2854 // To put the folder markers in the line number region
2855 //SendEditor(SCI_SETMARGINMASKN, 0, SC_MASK_FOLDERS);
2857 SendEditor(SCI_SETMODEVENTMASK, SC_MOD_CHANGEFOLD);
2859 if (0==props->GetInt("undo.redo.lazy")) {
2860 // Trap for insert/delete notifications (also fired by undo
2861 // and redo) so that the buttons can be enabled if needed.
2862 SendEditor(SCI_SETMODEVENTMASK, SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT
2863 | SC_LASTSTEPINUNDOREDO | SendEditor(SCI_GETMODEVENTMASK, 0));
2865 //SC_LASTSTEPINUNDOREDO is probably not needed in the mask; it
2866 //doesn't seem to fire as an event of its own; just modifies the
2867 //insert and delete events.
2870 // Create a margin column for the folding symbols
2871 SendEditor(SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL);
2873 SendEditor(SCI_SETMARGINWIDTHN, 2, foldMargin ? foldMarginWidth : 0);
2875 SendEditor(SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS);
2876 SendEditor(SCI_SETMARGINSENSITIVEN, 1, 1); // Breakpoints-Bookmarks
2877 SendEditor(SCI_SETMARGINSENSITIVEN, 2, 1);
2879 SString fold_symbols = props->Get("fold.symbols");
2880 SetFoldSymbols (fold_symbols);
2882 // Well, unlike scite, we want it everytime.
2883 firstPropertiesRead = true;
2886 void AnEditor::SetFoldSymbols(SString fold_symbols)
2888 if (fold_symbols.length() <= 0)
2889 fold_symbols = "plus/minus";
2890 if (strcasecmp(fold_symbols.c_str(), "arrows") == 0)
2892 // Arrow pointing right for contracted folders, arrow pointing down for expanded
2893 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_ARROWDOWN, Colour(0, 0, 0), Colour(0, 0, 0));
2894 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_ARROW, Colour(0, 0, 0), Colour(0, 0, 0));
2895 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY, Colour(0, 0, 0), Colour(0, 0, 0));
2896 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY, Colour(0, 0, 0), Colour(0, 0, 0));
2897 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2898 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2899 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2900 } else if (strcasecmp(fold_symbols.c_str(), "circular") == 0) {
2901 // Like a flattened tree control using circular headers and curved joins
2902 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2903 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2904 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2905 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2906 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2907 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2908 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2909 } else if (strcasecmp(fold_symbols.c_str(), "squares") == 0) {
2910 // Like a flattened tree control using square headers
2911 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2912 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2913 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2914 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2915 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2916 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2917 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2918 } else { // Default
2919 // Plus for contracted folders, minus for expanded
2920 DefineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2921 DefineMarker(SC_MARKNUM_FOLDER, SC_MARK_PLUS, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2922 DefineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2923 DefineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2924 DefineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2925 DefineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2926 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_EMPTY, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2930 // Anjuta: In our case, we read it everytime
2931 void AnEditor::ReadPropertiesInitial() {
2932 indentationWSVisible = props->GetInt("view.indentation.whitespace", 1);
2933 ViewWhitespace(props->GetInt("view.whitespace"));
2934 SendEditor(SCI_SETINDENTATIONGUIDES, props->GetInt("view.indentation.guides"));
2935 SendEditor(SCI_SETVIEWEOL, props->GetInt("view.eol"));
2937 SetReadOnly(props->GetInt("file.readonly", 0));
2938 SetLineWrap(props->GetInt("view.line.wrap", 1));
2940 //lineNumbersWidth = 0;
2941 /* FIXME: This is nowhere configureable
2942 SString linenums = props->Get("margin.linenumber.width");
2943 if (linenums.length())
2944 lineNumbersWidth = linenums.value(); */
2945 //lineNumbers = lineNumbersWidth;
2946 /* We do this dynamicly in text_editor_load_file now */
2947 /* if (lineNumbersWidth == 0)
2948 lineNumbersWidth = lineNumbersWidthDefault;*/
2950 marginWidth = 0;
2951 SString margwidth = props->Get("margin.marker.width");
2952 if (margwidth.length())
2953 marginWidth = margwidth.value();
2954 margin = marginWidth;
2955 if (marginWidth == 0)
2956 marginWidth = marginWidthDefault;
2958 foldMarginWidth = props->GetInt("margin.fold.width", foldMarginWidthDefault);
2959 foldMargin = foldMarginWidth;
2960 if (foldMarginWidth == 0)
2961 foldMarginWidth = foldMarginWidthDefault;
2963 lineNumbers = props->GetInt("margin.linenumber.visible", 0);
2964 SendEditor(SCI_SETMARGINWIDTHN, 0, lineNumbers ? lineNumbersWidth : 0);
2965 margin = props->GetInt("margin.marker.visible", 0);
2966 SendEditor(SCI_SETMARGINWIDTHN, 1, margin ? marginWidth : 0);
2968 foldMargin = props->GetInt("margin.fold.visible", 1);
2969 SendEditor(SCI_SETMARGINWIDTHN, 2, foldMargin ? foldMarginWidth : 0);
2972 void AnEditor::DefineMarker(int marker, int markerType, Colour fore, Colour back)
2974 SendEditor(SCI_MARKERDEFINE, marker, markerType);
2975 SendEditor(SCI_MARKERSETFORE, marker, fore.AsLong());
2976 SendEditor(SCI_MARKERSETBACK, marker, back.AsLong());
2979 int AnEditor::GetBookmarkLine( const int nLineStart )
2981 int nNextLine = SendEditor(SCI_MARKERNEXT, nLineStart+1, 1 << ANE_MARKER_BOOKMARK);
2982 //printf( "...look %d --> %d\n", nLineStart, nNextLine );
2983 if ( (nNextLine < 0) || (nNextLine == nLineStart) )
2984 return -1 ;
2985 else
2986 return nNextLine;
2989 void AnEditor::FocusInEvent(GtkWidget* widget)
2991 if (calltipShown)
2993 StartCallTip_new();
2997 void AnEditor::FocusOutEvent(GtkWidget* widget)
2999 if (SendEditor(SCI_CALLTIPACTIVE))
3001 SendEditor(SCI_CALLTIPCANCEL);
3002 calltipShown = true;
3004 else
3006 calltipShown = false;
3010 static GList* editors;
3012 static AnEditor*
3013 aneditor_get(AnEditorID id)
3015 AnEditor* ed;
3016 if(id >= g_list_length(editors))
3018 DEBUG_PRINT("%s", "Invalid AnEditorID supplied");
3019 return NULL;
3021 ed = (AnEditor*)g_list_nth_data(editors, (guint)id);
3022 if(!ed)
3024 DEBUG_PRINT("%s", "Trying to use already destroyed AnEditor Object");
3025 return NULL;
3027 return ed;
3030 AnEditorID
3031 aneditor_new(gpointer propset)
3033 AnEditor* ed = new AnEditor((PropSetFile*)propset);
3034 if (!ed)
3036 DEBUG_PRINT("%s", "Memory allocation error.");
3037 return ANE_ID_INVALID;
3039 g_signal_connect(ed->GetID(), "focus_in_event",
3040 G_CALLBACK(on_aneditor_focus_in), ed);
3041 g_signal_connect(ed->GetID(), "focus_out_event",
3042 G_CALLBACK(on_aneditor_focus_out), ed);
3043 editors = g_list_append(editors, ed);
3044 return (AnEditorID)(g_list_length(editors) - 1);
3047 void
3048 aneditor_destroy(AnEditorID id)
3050 AnEditor* ed;
3052 ed = aneditor_get(id);
3053 if(!ed) return;
3055 /* We will not remove the editor from the list */
3056 /* so that already assigned handles work properly */
3057 /* We'll simply make it NULL to indicate that the */
3058 /* editor is destroyed */
3059 g_list_nth(editors, id)->data = NULL;
3061 /* Disconnect the focus in/out signals */
3062 g_signal_handlers_disconnect_by_func (ed->GetID(),
3063 (void*)G_CALLBACK(on_aneditor_focus_in), ed);
3064 g_signal_handlers_disconnect_by_func (ed->GetID(),
3065 (void*)G_CALLBACK(on_aneditor_focus_out), ed);
3067 delete ed;
3070 GtkWidget*
3071 aneditor_get_widget(AnEditorID handle)
3073 AnEditor *ed;
3074 ed = aneditor_get(handle);
3075 if(!ed) return NULL;
3077 // Forced conversion is safe here, so do it.
3078 return (GtkWidget*)ed->GetID();
3081 glong
3082 aneditor_command(AnEditorID handle, gint command, glong wparam, glong lparam)
3084 AnEditor *ed;
3085 ed = aneditor_get(handle);
3086 if(!ed) return 0;
3087 return ed->Command(command, wparam, lparam);
3090 void
3091 aneditor_set_focused_ed_ID(AnEditorID id)
3093 AnEditor::focusedID = id;
3096 void
3097 aneditor_set_parent(AnEditorID id, AnEditorID parent_id)
3099 AnEditor *editor;
3100 AnEditor *parent;
3102 editor = aneditor_get (id);
3103 parent = aneditor_get (parent_id);
3104 editor->SetParent(parent);
3107 gint
3108 on_aneditor_focus_in (GtkWidget* widget, gpointer* unused, AnEditor* ed)
3110 ed->FocusInEvent(widget);
3111 return FALSE;
3114 gint
3115 on_aneditor_focus_out (GtkWidget* widget, gpointer * unused, AnEditor* ed)
3117 /* ed->EndDebugEval(); */
3118 ed->FocusOutEvent(widget);
3119 return FALSE;