1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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
) {
49 lexLanguage
= SCLEX_CPP
;
54 statementLookback = 10;
56 indentMaintain
= true;
57 indentAutomatic
= true;
76 allowMenuActions
= true;
81 capturedMouse
= false;
82 firstPropertiesRead
= true;
83 splitVertical
= false;
90 indentationWSVisible
= true;
92 autoCompleteIgnoreCase
= false;
93 callTipIgnoreCase
= false;
94 autoCCausedByOnlyOne
= false;
95 // startCalltipWord = 0;
98 SetCallTipDefaults( );
99 call_tip_node_queue
= g_queue_new();
102 autocompletion
= NULL
;
105 marginWidth
= marginWidthDefault
;
107 foldMarginWidth
= foldMarginWidthDefault
;
109 lineNumbersWidth
= lineNumbersWidthDefault
;
113 calltipShown
= false;
114 // debugTipOn = false;
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);
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 */
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
));
176 void AnEditor::SetParent(AnEditor
*parent
)
178 long pdoc
= parent
->SendEditor(SCI_GETDOCPOINTER
, 0, 0);
179 SendEditor(SCI_SETDOCPOINTER
, 0, pdoc
);
184 sv_get_node_type (TMTag
*tag
)
188 if (!tag
|| (tm_tag_file_t
== tag
->type
))
191 access
= tag
->atts
.entry
.access
;
196 case tm_tag_struct_t
:
200 case tm_tag_function_t
:
201 case tm_tag_prototype_t
:
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
;
214 return sv_function_t
;
216 case tm_tag_member_t
:
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
;
229 return sv_variable_t
;
232 case tm_tag_externvar_t
:
233 case tm_tag_variable_t
:
234 return sv_variable_t
;
237 case tm_tag_macro_with_arg_t
:
249 AnEditor::SetAccelGroup(GtkAccelGroup
* 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
);
269 SendEditor(SCI_SETVIEWWS
, SCWS_VISIBLEAFTERINDENT
);
271 SendEditor(SCI_SETVIEWWS
, SCWS_INVISIBLE
);
274 StyleAndWords
AnEditor::GetStyleAndWords(const char *base
) {
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(), ' ');
281 sw
.words
= space
+ 1;
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
) {
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
;
322 line
= GetCurrentLineNumber();
323 caret
= GetCaretInLine();
324 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
325 lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
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;
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());
348 if(text
[current
- 1] == ';' ||
349 text
[current
- 1] == '{' || text
[current
- 1] == '}')
357 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
358 lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
359 len
= lineEnd
- lineStart
;
369 void AnEditor::GetRange(Window
&win
, int start
, int end
, char *text
) {
371 tr
.chrg
.cpMin
= start
;
374 Platform::SendScintilla(win
.GetID(), SCI_GETTEXTRANGE
, 0, reinterpret_cast<long>(&tr
));
377 void AnEditor::GetRange(guint start
, guint end
, gchar
*text
, gboolean styled
) {
379 tr
.chrg
.cpMin
= start
;
383 SendEditor (SCI_GETSTYLEDTEXT
, 0, reinterpret_cast<long>(&tr
));
385 SendEditor (SCI_GETTEXTRANGE
, 0, reinterpret_cast<long>(&tr
));
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
;
402 while (isspacechar(*currChar
) && *currChar
) {
405 if (preprocessorSymbol
&& (*currChar
== preprocessorSymbol
)) {
407 while (isspacechar(*currChar
) && *currChar
) {
410 while (!isspacechar(*currChar
) && *currChar
) {
411 word
[i
++] = *currChar
++;
414 if (preprocCondStart
.InList(word
)) {
417 if (preprocCondMiddle
.InList(word
)) {
420 if (preprocCondEnd
.InList(word
)) {
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;
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
)) {
450 } else if (level
> 0 && ((direction
== 1 && status
== ppcEnd
) || (direction
== -1 && status
== ppcStart
))) {
452 } else if (level
== 0 && (status
== condEnd1
|| status
== condEnd2
)) {
461 * Find if there is a preprocessor condition after or before the caret position,
462 * @return @c true if inside a preprocessor condition.
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.
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;
480 curLine
= SendEditor(SCI_LINEFROMPOSITION
, mppcAtCaret
);
481 GetLine(line
, curLine
);
482 status
= IsLinePreprocessorCondition(line
.c_str());
487 isInside
= FindMatchingPreprocessorCondition(curLine
, 1, ppcMiddle
, ppcEnd
);
489 mppcMatch
= mppcAtCaret
;
495 isInside
= FindMatchingPreprocessorCondition(curLine
, 1, ppcMiddle
, ppcEnd
);
497 isInside
= FindMatchingPreprocessorCondition(curLine
, -1, ppcStart
, ppcMiddle
);
502 mppcMatch
= mppcAtCaret
;
505 isInside
= FindMatchingPreprocessorCondition(curLine
, -1, ppcStart
, ppcMiddle
);
508 default: // Should be noPPC
511 isInside
= FindMatchingPreprocessorCondition(curLine
, 1, ppcMiddle
, ppcEnd
);
513 isInside
= FindMatchingPreprocessorCondition(curLine
, -1, ppcStart
, ppcMiddle
);
519 mppcMatch
= SendEditor(SCI_POSITIONFROMLINE
, curLine
);
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);
542 char charBefore
= '\0';
543 char styleBefore
= '\0';
544 //FIXME WindowAccessor acc(win.GetID(), *props);
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;
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
;
569 if (lexLanguage
== SCLEX_PYTHON
&& ':' == charAfter
) {
570 braceAtCaret
= caretPos
;
574 if (braceAtCaret
>= 0) {
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
);
580 braceOpposite
= Platform::SendScintilla(win
.GetID(), SCI_BRACEMATCH
, braceAtCaret
, 0);
582 if (braceOpposite
> braceAtCaret
) {
592 void AnEditor::BraceMatch(bool editor
) {
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);
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
);
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);
651 // Try and find a word at the caret
652 if (iswordcharforsel(acc
[selStart
])) {
653 while ((selStart
> 0) && (iswordcharforsel(acc
[selStart
- 1])))
655 while ((selEnd
< lengthDoc
- 1) && (iswordcharforsel(acc
[selEnd
+ 1])))
657 if (selStart
< selEnd
)
658 selEnd
++; // Because normal selections end one past
663 if ((selStart
< selEnd
) && ((selEnd
- selStart
+ 1) < len
)) {
664 GetRange(wEditor
, selStart
, selEnd
, word
);
668 void AnEditor::WordSelect() {
669 int lengthDoc
= LengthDocument();
673 selStart
= selEnd
= SendEditor(SCI_GETCURRENTPOS
);
674 //FIXME WindowAccessor acc(wEditor.GetID(), *props);
676 if (iswordcharforsel(acc
[selStart
])) {
677 while ((selStart
> 0) && (iswordcharforsel(acc
[selStart
- 1])))
679 while ((selEnd
< lengthDoc
- 1) && (iswordcharforsel(acc
[selEnd
+ 1])))
681 if (selStart
< selEnd
)
682 selEnd
++; // Because normal selections end one past
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
);
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;
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
));
730 EnsureRangeVisible(ft
.chrgText
.cpMin
, ft
.chrgText
.cpMax
);
731 SetSelection(ft
.chrgText
.cpMin
, ft
.chrgText
.cpMax
);
736 void AnEditor::BookmarkToggle( int lineno
) {
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
);
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 ;-)
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 ;-)
773 SendEditor(SCI_ENSUREVISIBLE
, nextLine1
);
774 SendEditor(SCI_GOTOLINE
, nextLine1
);
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 ;-)
792 SendEditor(SCI_ENSUREVISIBLE
, nextLine1
);
793 SendEditor(SCI_GOTOLINE
, nextLine1
);
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 ;-)
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
) {
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.");
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 \"");
836 //error += "\" is not defined in SciTE *.properties!";
837 //WindowMessageBox(wEditor, error, MB_OK | MB_ICONWARNING);
841 SString long_comment
= comment
;
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
855 (selectionEnd
== static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE
, 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
);
865 lineIndent
= GetLineIndentPosition(i
);
866 GetRange(wEditor
, lineIndent
, lineEnd
, linebuf
);
868 // empty lines are not commented
869 if (strlen(linebuf
) < 1)
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
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
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
;
904 // moving caret to the beginning of selected block
905 SendEditor(SCI_GOTOPOS
, selectionEnd
);
906 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
908 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
910 SendEditor(SCI_ENDUNDOACTION
);
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();
954 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
955 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
956 if (selectionStart
== selectionEnd
)
958 int line
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
961 bool start1
= false, start2
= false;
962 bool end1
= false, end2
= false;
965 lineEnd1
= selectionStart
+ start_comment_length
;
967 lineEnd1
= selectionStart
+ start_comment_stream_length
+1;
968 if (lineEnd1
> LengthDocument())
969 lineEnd1
= LengthDocument();
972 size_t start_cmt
= 0, end_cmt
= 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
))))
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
))))
994 lineEnd1
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
996 start_cmt
= index
+ lineStart1
;
997 line
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
999 lineStart1
= selectionEnd
- start_comment_length
;
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
))))
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
))))
1022 end_cmt
= lineStart1
+ index
;
1023 lineStart1
= SendEditor(SCI_POSITIONFROMLINE
, line
);
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
;
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
);
1061 SendEditor(SCI_SETSEL
, end_cmt
, end_cmt
+ end_comment_stream_length
);
1062 SendEditorString(SCI_REPLACESEL
, 0, "");
1063 SendEditor(SCI_ENDUNDOACTION
);
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);
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
)))) {
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
);
1135 SendEditorString(SCI_INSERTTEXT
, lineEnd
, "\n");
1136 SendEditorString(SCI_INSERTTEXT
, lineEnd
+ 1, (end_comment
.c_str() + 1));
1138 SendEditorString(SCI_INSERTTEXT
, lineEnd
, end_comment
.c_str());
1140 selectionEnd
+= (start_comment_length
);
1142 // moving caret to the beginning of selected block
1143 SendEditor(SCI_GOTOPOS
, selectionEnd
);
1144 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
1146 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
1148 SendEditor(SCI_ENDUNDOACTION
);
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);
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
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])) {
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])) {
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());
1223 // moving caret to the beginning of selected block
1224 SendEditor(SCI_GOTOPOS
, selectionEnd
);
1225 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
1227 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
1229 SendEditor(SCI_ENDUNDOACTION
);
1235 SString
AnEditor::GetMode(SString language
) {
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"));
1252 /* Insert or Modify a Comment line
1253 giving File indent */
1254 bool AnEditor::InsertCustomIndent() {
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
);
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
++)
1286 if (memcmp(buf
+index
, start_box
.c_str(), start_box
.length()) == 0)
1288 index
+= (start_box
.length() - 1);
1289 start_comment
= true;
1292 if (memcmp(buf
+index
, start_stream
.c_str(), start_stream
.length()) == 0)
1294 index
+= (start_stream
.length() - 1);
1295 start_comment
= true;
1298 if (buf
[index
] != ' ' && buf
[index
] != '\t' && buf
[index
] != '\n')
1303 if (!indent_comment
)
1305 if (buf
[index
] == ' ' || buf
[index
] == '\t' || buf
[index
] == '\n')
1307 if (memcmp(buf
+index
, mark
.c_str(), 3) == 0)
1310 indent_comment
= true;
1317 if (memcmp(buf
+index
, end_box
.c_str(), end_box
.length()) == 0)
1319 end_indent_comment
= index
+ end_box
.length() - 1;
1322 if (memcmp(buf
+index
, end_stream
.c_str(), end_stream
.length()) == 0)
1324 end_indent_comment
= index
+ end_stream
.length() - 1;
1330 SString mode
= GetMode(language
);
1331 if (mode
.c_str() != "")
1334 comment
+= start_stream
.c_str() ;
1336 comment
+= mark
.c_str();
1337 comment
+= mode
.c_str();
1338 comment
+= mark
.c_str();
1340 comment
+= end_stream
.c_str() ;
1344 SendEditor(SCI_SETSEL
, 0, end_indent_comment
+ 1);
1345 SendEditorString(SCI_REPLACESEL
, 0, comment
.c_str());
1350 SendEditorString(SCI_INSERTTEXT
, 0, comment
.c_str());
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);
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
1409 // This may make sense only in certain languages
1410 if (lexLanguage
!= SCLEX_HTML
&& lexLanguage
!= SCLEX_XML
) {
1414 // If the user has turned us off, quit now.
1416 SString value
= props
->GetExpanded("xml.auto.close.tags");
1417 if ((value
.length() == 0) || (value
== "0")) {
1421 // Grab the last 512 characters or so
1422 int nCaret
= SendEditor(SCI_GETCURRENTPOS
);
1424 int nMin
= nCaret
- (sizeof(sel
) - 1);
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/>"
1440 SString strFound
= FindOpenXmlTag(sel
, nCaret
- nMin
);
1442 if (strFound
.length() > 0) {
1443 SendEditor(SCI_BEGINUNDOACTION
);
1444 SString toInsert
= "</";
1445 toInsert
+= strFound
;
1447 SendEditorString(SCI_REPLACESEL
, 0, toInsert
.c_str());
1448 SetSelection(nCaret
, nCaret
);
1449 SendEditor(SCI_ENDUNDOACTION
);
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
= "";
1463 // Smallest tag is "<p>" which is 3 characters
1466 const char* pBegin
= &sel
[0];
1467 const char* pCur
= &sel
[nSize
- 1];
1469 pCur
--; // Skip past the >
1470 while (pCur
> pBegin
) {
1473 } else if (*pCur
== '>') {
1481 while (strchr(":_-.", *pCur
) || isalnum(*pCur
)) {
1487 // Return the tag name or ""
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.
1498 if (braceOpposite
> braceAtCaret
) {
1504 if (braceOpposite
> braceAtCaret
) {
1510 if (braceOpposite
>= 0) {
1511 EnsureRangeVisible(braceOpposite
, braceOpposite
);
1513 SetSelection(braceAtCaret
, braceOpposite
);
1515 SetSelection(braceOpposite
, braceOpposite
);
1520 int ControlIDOfCommand(unsigned long wParam
) {
1521 return wParam
& 0xffff;
1524 long AnEditor::Command(int cmdID
, long wParam
, long lParam
) {
1527 case ANE_INSERTTEXT
:
1528 SendEditor(SCI_INSERTTEXT
,wParam
,lParam
);
1531 case ANE_GETBOOKMARK_POS
:
1532 return GetBookmarkLine( wParam
);
1533 break; /* pleonastico */
1535 case ANE_BOOKMARK_TOGGLE_LINE
:
1536 BookmarkToggle( wParam
);
1540 SendEditor(SCI_UNDO
);
1544 SendEditor(SCI_REDO
);
1548 SendEditor(SCI_CUT
);
1552 SendEditor(SCI_COPY
);
1556 SendEditor(SCI_PASTE
);
1560 SendEditor(SCI_CLEAR
);
1564 SendEditor(SCI_SELECTALL
);
1568 return Find (wParam
, (char*) lParam
);
1571 SendEditor(SCI_GOTOLINE
, wParam
);
1575 SendEditor(SCI_SETZOOM
, wParam
);
1578 case ANE_MATCHBRACE
:
1579 GoMatchingBrace(false);
1582 case ANE_SELECTBLOCK
:
1586 case ANE_SELECTTOBRACE
:
1587 GoMatchingBrace(true);
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
:
1606 case ANE_COMPLETECALLTIP
:
1611 StartAutoComplete();
1614 case ANE_COMPLETEWORD:
1615 StartAutoCompleteWord(false);
1618 case ANE_TOGGLE_FOLD
:
1622 case ANE_OPEN_FOLDALL
:
1626 case ANE_CLOSE_FOLDALL
:
1631 SendEditor(SCI_UPPERCASE
);
1635 SendEditor(SCI_LOWERCASE
);
1639 SendEditor(SCI_TOGGLEFOLD
, GetCurrentLineNumber());
1642 case ANE_LINENUMBERMARGIN
:
1643 lineNumbers
= wParam
;
1644 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
1649 SendEditor(SCI_SETMARGINWIDTHN
, 1, margin
? marginWidth
: 0);
1652 case ANE_FOLDMARGIN
:
1653 foldMargin
= wParam
;
1654 SendEditor(SCI_SETMARGINWIDTHN
, 2, foldMargin
? foldMarginWidth
: 0);
1658 SendEditor(SCI_SETVIEWEOL
, wParam
);
1662 SendEditor(SCI_SETEOLMODE
, SC_EOL_CRLF
);
1666 SendEditor(SCI_SETEOLMODE
, SC_EOL_CR
);
1670 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
1673 case ANE_EOL_CONVERT
:
1676 SendEditor(SCI_SETEOLMODE
, SC_EOL_CRLF
);
1677 SendEditor(SCI_CONVERTEOLS
, SC_EOL_CRLF
);
1680 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
1681 SendEditor(SCI_CONVERTEOLS
, SC_EOL_LF
);
1684 SendEditor(SCI_SETEOLMODE
, SC_EOL_CR
);
1685 SendEditor(SCI_CONVERTEOLS
, SC_EOL_CR
);
1688 SendEditor(SCI_CONVERTEOLS
, SendEditor(SCI_GETEOLMODE
));
1693 case ANE_WORDPARTLEFT
:
1694 SendEditor(SCI_WORDPARTLEFT
);
1697 case ANE_WORDPARTLEFTEXTEND
:
1698 SendEditor(SCI_WORDPARTLEFTEXTEND
);
1701 case ANE_WORDPARTRIGHT
:
1702 SendEditor(SCI_WORDPARTRIGHT
);
1705 case ANE_WORDPARTRIGHTEXTEND
:
1706 SendEditor(SCI_WORDPARTRIGHTEXTEND
);
1710 ViewWhitespace(wParam
);
1713 case ANE_VIEWGUIDES
:
1714 SendEditor(SCI_SETINDENTATIONGUIDES
, wParam
);
1717 case ANE_BOOKMARK_TOGGLE
:
1720 case ANE_BOOKMARK_FIRST
:
1723 case ANE_BOOKMARK_PREV
:
1726 case ANE_BOOKMARK_NEXT
:
1729 case ANE_BOOKMARK_LAST
:
1732 case ANE_BOOKMARK_CLEAR
:
1736 case ANE_SETTABSIZE
:
1737 SendEditor(SCI_SETTABWIDTH
, wParam
);
1740 case ANE_SETLANGUAGE
:
1741 SetOverrideLanguage(wParam
);
1745 ReadProperties((char*)wParam
, (char **)lParam
);
1746 SendEditor(SCI_COLOURISE
, 0, -1);
1749 case ANE_SETACCELGROUP
:
1750 SetAccelGroup((GtkAccelGroup
*)wParam
);
1753 case ANE_GETTEXTRANGE
: {
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);
1760 GetRange(start
, end
, buff
, false);
1765 case ANE_INDENT_INCREASE
:
1766 IndentationIncrease();
1769 case ANE_INDENT_DECREASE
:
1770 IndentationDecrease();
1774 return SendEditor(SCI_GETLENGTH
);
1776 case ANE_GET_LINENO
:
1777 return GetCurrentLineNumber();
1780 SetLineWrap((bool)wParam
);
1784 SetReadOnly((bool)wParam
);
1787 case ANE_GETSTYLEDTEXT
: {
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);
1796 GetRange(start
, end
, buff
, true);
1797 memset (buff
+ (end
-start
) * 2, 0, 20);
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
:
1822 case ANE_LINESELECT
:
1826 case ANE_GETCURRENTPOS
:
1827 return SendEditor(SCI_GETCURRENTPOS
);
1830 return SendEditor(SCI_GOTOPOS
, wParam
);
1832 case ANE_SETWRAPBOOKMARKS
:
1836 case ANE_SETAUTOINDENTATION
:
1837 indentAutomatic
= wParam
;
1840 case ANE_SETUSETABFORINDENT
:
1841 SendEditor(SCI_SETUSETABS
, wParam
);
1844 case ANE_SETINDENTSIZE
:
1845 indentSize
= wParam
;
1846 SendEditor(SCI_SETINDENT
, wParam
);
1849 case ANE_SETINDENTBRACESCHECK
:
1850 bracesCheck
= wParam
;
1853 case ANE_SETINDENTOPENING:
1854 indentOpening = wParam;
1857 case ANE_SETINDENTCLOSING:
1858 indentClosing = wParam;
1861 case ANE_SETINDENTMAINTAIN
:
1862 props
->Set ("indent.maintain.*", wParam
? "1" : "0");
1863 indentMaintain
= wParam
;
1866 case ANE_SETTABINDENTS
:
1867 SendEditor(SCI_SETTABINDENTS
, wParam
);
1870 case ANE_SETBACKSPACEUNINDENTS
:
1871 SendEditor(SCI_SETBACKSPACEUNINDENTS
, wParam
);
1874 case ANE_SETFOLDSYMBOLS
:
1875 SetFoldSymbols(reinterpret_cast<char *> (wParam
));
1878 case ANE_SETFOLDUNDERLINE
:
1880 SendEditor(SCI_SETFOLDFLAGS
, props
->GetInt("fold.flags"));
1882 SendEditor(SCI_SETFOLDFLAGS
, 0);
1884 case ANE_SETLINENUMWIDTH
:
1885 lineNumbersWidth
= wParam
;
1886 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
1888 case ANE_SETEDGECOLUMN
:
1889 SendEditor(SCI_SETEDGECOLUMN
, wParam
);
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
);
1912 while (line
<= lineMaxSubord
) {
1915 SendEditor(SCI_SHOWLINES
, line
, line
);
1917 SendEditor(SCI_HIDELINES
, line
, line
);
1920 SendEditor(SCI_SHOWLINES
, line
, line
);
1922 int levelLine
= level
;
1924 levelLine
= SendEditor(SCI_GETFOLDLEVEL
, line
);
1925 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
1928 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
1930 SendEditor(SCI_SETFOLDEXPANDED
, line
, 0);
1931 Expand(line
, doExpand
, force
, visLevels
- 1);
1933 if (doExpand
&& SendEditor(SCI_GETFOLDEXPANDED
, line
)) {
1934 Expand(line
, true, force
, visLevels
- 1);
1936 Expand(line
, false, force
, visLevels
- 1);
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
))) {
1953 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
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() {
1970 void AnEditor::FoldCloseAll() {
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
);
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
);
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
)
2000 start
= SendEditor(SCI_POSITIONFROMLINE
, parent
);
2001 end
= SendEditor(SCI_POSITIONFROMLINE
, lastChild
+1);
2002 SetSelection(start
, end
);
2008 int AnEditor::GetBlockStartLine (int curLine
) {
2011 curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
2013 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
2014 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2018 int lastChild
= curLine
;
2021 parent
= SendEditor (SCI_GETFOLDPARENT
, lastChild
);
2026 lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2027 if (curLine
> parent
&& curLine
<= lastChild
)
2031 lastChild
= parent
- 1;
2037 int AnEditor::GetBlockEndLine (int curLine
) {
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 */
2048 int lastChild
= curLine
;
2051 parent
= SendEditor (SCI_GETFOLDPARENT
, lastChild
);
2056 lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2057 if (curLine
> parent
&& curLine
<= lastChild
)
2061 lastChild
= parent
- 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
) {
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
) {
2091 } else if (modifiers
& SCMOD_CTRL
) {
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);
2104 // Expand this line and all children
2105 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 1);
2106 Expand(lineClick
, true, true, 100);
2110 SendEditor(SCI_TOGGLEFOLD
, lineClick
);
2117 gint
AnEditor::KeyPressEvent(GtkWidget
*, GdkEventKey
*event
, AnEditor
*anedit
) {
2118 return anedit
->KeyPress(event
->state
, event
->keyval
);
2122 void AnEditor::NotifySignal(GtkWidget
*, gint
/*wParam*/, gpointer lParam
, AnEditor
*anedit
) {
2123 anedit
->Notify(reinterpret_cast<SCNotification
*>(lParam
));
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'.
2138 auto_ptr
<ExpressionEvaluationTipInfo
> info(
2139 (ExpressionEvaluationTipInfo
*) data
);
2141 if (info
->editor
== NULL
)
2144 if (info
->editor
!= aneditor_get(AnEditor::focusedID
))
2147 info
->editor
->EvalOutputArrived(lines
, info
->textPos
, info
->expression
);
2150 void AnEditor::EvalOutputArrived(GList
* lines
, int textPos
,
2151 const string
&expression
) {
2156 // Return if debug Tip has been canceled
2160 if (g_list_length(lines
) == 0 || lines
->data
== NULL
)
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() {
2175 SendEditor(SCI_CALLTIPCANCEL
);
2180 void AnEditor::HandleDwellStart(int mousePos
) {
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());
2192 // If debug tip is already running, 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
))
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.
2217 for (i
= 0; i
< end
- crange
.cpMin
; i
++)
2218 if ((unsigned char) expr
[i
] < ' ' && expr
[i
] != '\t')
2220 if (i
< end
- crange
.cpMin
)
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
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 ();
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
;
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');
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);
2291 if(!accelGroup
) break;
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
));
2304 CharAdded(static_cast<char>(notification
->ch
));
2307 case SCN_SAVEPOINTREACHED
:
2311 case SCN_SAVEPOINTLEFT
:
2317 int pos
= SendEditor(SCI_GETCURRENTPOS
);
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();
2330 if (notification
->modificationType
== SC_MOD_CHANGEFOLD
) {
2331 FoldChanged(notification
->line
,
2332 notification
->foldLevelNow
, notification
->foldLevelPrev
);
2336 case SCN_MARGINCLICK
:
2337 if (notification
->margin
== 2)
2338 MarginClick(notification
->position
, notification
->modifiers
);
2341 case SCN_NEEDSHOWN
: {
2342 EnsureRangeVisible(notification
->position
, notification
->position
+ notification
->length
);
2346 case SCN_DWELLSTART:
2347 HandleDwellStart(notification->position);
2352 // SendEditor(SCI_CALLTIPCANCEL);
2358 static int IntFromHexDigit(const char ch
) {
2361 else if (ch
>= 'A' && ch
<= 'F')
2362 return ch
- 'A' + 10;
2363 else if (ch
>= 'a' && ch
<= 'f')
2364 return ch
- 'a' + 10;
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
);
2388 char *cpComma
= strchr(opt
, ',');
2391 char *colon
= strchr(opt
, ':');
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
);
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);
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
) {
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
) {
2459 *s
= static_cast<char>(tolower(*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
, '.');
2473 lowerCaseString(extension
);
2475 return SString(fileNameWithLowerCaseExtension
);
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());
2491 ret
= props
->GetExpanded(pattern
);
2497 void AnEditor::ReadProperties(const char *fileForExt
, char **typedef_hl
) {
2498 //DWORD dwStart = timeGetTime();
2500 strcpy (fileName
, fileForExt
);
2504 SString fileNameForExtension
;
2505 if(overrideExtension
.length())
2506 fileNameForExtension
= overrideExtension
;
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);
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
)
2536 kw3
+= typedef_hl
[0];
2538 if (typedef_hl
[1] != NULL
)
2541 kw1
+= typedef_hl
[1];
2544 SendEditorString(SCI_SETKEYWORDS
, 3, kw3
.c_str());
2545 SendEditorString(SCI_SETKEYWORDS
, 1, kw1
.c_str());
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;
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());
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]));
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());
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());
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());
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());
2663 SendEditor(SCI_SETWHITESPACEBACK
, 0, 0);
2666 for (int i
= 0; i
< 3; i
++) {
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"};
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
);
2688 SendEditor(SCI_INDICSETSTYLE
, i
, default_indic_type
[i
]);
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());
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);
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
, "");
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),
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());
2797 SendEditor(SCI_SETWORDCHARS
, 0, 0);
2798 wordCharacters
= "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
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");
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.");
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
);
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"));
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));
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;*/
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
) )
2989 void AnEditor::FocusInEvent(GtkWidget
* widget
)
2997 void AnEditor::FocusOutEvent(GtkWidget
* widget
)
2999 if (SendEditor(SCI_CALLTIPACTIVE
))
3001 SendEditor(SCI_CALLTIPCANCEL
);
3002 calltipShown
= true;
3006 calltipShown
= false;
3010 static GList
* editors
;
3013 aneditor_get(AnEditorID id
)
3016 if(id
>= g_list_length(editors
))
3018 DEBUG_PRINT("%s", "Invalid AnEditorID supplied");
3021 ed
= (AnEditor
*)g_list_nth_data(editors
, (guint
)id
);
3024 DEBUG_PRINT("%s", "Trying to use already destroyed AnEditor Object");
3031 aneditor_new(gpointer propset
)
3033 AnEditor
* ed
= new AnEditor((PropSetFile
*)propset
);
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);
3048 aneditor_destroy(AnEditorID id
)
3052 ed
= aneditor_get(id
);
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
);
3071 aneditor_get_widget(AnEditorID handle
)
3074 ed
= aneditor_get(handle
);
3075 if(!ed
) return NULL
;
3077 // Forced conversion is safe here, so do it.
3078 return (GtkWidget
*)ed
->GetID();
3082 aneditor_command(AnEditorID handle
, gint command
, glong wparam
, glong lparam
)
3085 ed
= aneditor_get(handle
);
3087 return ed
->Command(command
, wparam
, lparam
);
3091 aneditor_set_focused_ed_ID(AnEditorID id
)
3093 AnEditor::focusedID
= id
;
3097 aneditor_set_parent(AnEditorID id
, AnEditorID parent_id
)
3102 editor
= aneditor_get (id
);
3103 parent
= aneditor_get (parent_id
);
3104 editor
->SetParent(parent
);
3108 on_aneditor_focus_in (GtkWidget
* widget
, gpointer
* unused
, AnEditor
* ed
)
3110 ed
->FocusInEvent(widget
);
3115 on_aneditor_focus_out (GtkWidget
* widget
, gpointer
* unused
, AnEditor
* ed
)
3117 /* ed->EndDebugEval(); */
3118 ed
->FocusOutEvent(widget
);