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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
75 allowMenuActions
= true;
80 capturedMouse
= false;
81 firstPropertiesRead
= true;
82 splitVertical
= false;
89 indentationWSVisible
= true;
91 autoCompleteIgnoreCase
= false;
92 callTipIgnoreCase
= false;
93 autoCCausedByOnlyOne
= false;
94 // startCalltipWord = 0;
97 SetCallTipDefaults( );
98 call_tip_node_queue
= g_queue_new();
101 autocompletion
= NULL
;
104 marginWidth
= marginWidthDefault
;
106 foldMarginWidth
= foldMarginWidthDefault
;
108 lineNumbersWidth
= lineNumbersWidthDefault
;
112 calltipShown
= false;
118 wEditor
= scintilla_new();
119 g_object_ref (G_OBJECT (wEditor
.GetID()));
120 gtk_object_sink (GTK_OBJECT (wEditor
.GetID()));
121 scintilla_set_id(SCINTILLA(wEditor
.GetID()), 0);
123 fnEditor
= reinterpret_cast<SciFnDirect
>(Platform::SendScintilla(
124 wEditor
.GetID(), SCI_GETDIRECTFUNCTION
, 0, 0));
126 ptrEditor
= Platform::SendScintilla(wEditor
.GetID(),
127 SCI_GETDIRECTPOINTER
, 0, 0);
129 g_signal_connect(wEditor
.GetID(), "sci-notify", G_CALLBACK(NotifySignal
), this);
131 /* We will handle all accels ourself */
132 /* SendEditor(SCI_CLEARALLCMDKEYS); */
134 /*We have got our own popup menu */
135 SendEditor(SCI_USEPOPUP
, false);
136 /* Set default editor mode */
137 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
140 // Trap 'TAB' key for automatic indentation.
141 // SendEditor (SCI_ASSIGNCMDKEY, SCK_TAB, SCI_NULL);
142 g_signal_connect (wEditor
.GetID(), "key-press-event",
143 G_CALLBACK (KeyPressEvent
), this);
145 /* Register images to be used for autocomplete */
150 PixAndType pix_list
[] = {
151 { sv_none_t
, sv_unknown_xpm
}
152 , { sv_class_t
, sv_class_xpm
}
153 , { sv_struct_t
, sv_struct_xpm
}
154 , { sv_union_t
, sv_struct_xpm
}
155 , { sv_function_t
, sv_function_xpm
}
156 , { sv_macro_t
, sv_macro_xpm
}
157 , { sv_variable_t
, sv_variable_xpm
}
158 , { sv_private_func_t
, sv_private_fun_xpm
}
159 , { sv_private_var_t
, sv_private_var_xpm
}
160 , { sv_protected_func_t
, sv_protected_fun_xpm
}
161 , { sv_protected_var_t
, sv_protected_var_xpm
}
162 , { sv_public_func_t
, sv_public_fun_xpm
}
163 , { sv_public_var_t
, sv_public_var_xpm
}
165 for (guint i
= 0; i
< (sizeof(pix_list
)/sizeof(pix_list
[0])); ++i
)
167 SendEditor(SCI_REGISTERIMAGE
, (long) pix_list
[i
].type
168 , reinterpret_cast<long>(pix_list
[i
].xpm_data
));
173 void AnEditor::SetParent(AnEditor
*parent
)
175 long pdoc
= parent
->SendEditor(SCI_GETDOCPOINTER
, 0, 0);
176 SendEditor(SCI_SETDOCPOINTER
, 0, pdoc
);
181 sv_get_node_type (TMTag
*tag
)
185 if (!tag
|| (tm_tag_file_t
== tag
->type
))
188 access
= tag
->atts
.entry
.access
;
193 case tm_tag_struct_t
:
197 case tm_tag_function_t
:
198 case tm_tag_prototype_t
:
201 case TAG_ACCESS_PRIVATE
:
202 return sv_private_func_t
;
204 case TAG_ACCESS_PROTECTED
:
205 return sv_protected_func_t
;
207 case TAG_ACCESS_PUBLIC
:
208 return sv_public_func_t
;
211 return sv_function_t
;
213 case tm_tag_member_t
:
216 case TAG_ACCESS_PRIVATE
:
217 return sv_private_var_t
;
219 case TAG_ACCESS_PROTECTED
:
220 return sv_protected_var_t
;
222 case TAG_ACCESS_PUBLIC
:
223 return sv_public_var_t
;
226 return sv_variable_t
;
229 case tm_tag_externvar_t
:
230 case tm_tag_variable_t
:
231 return sv_variable_t
;
234 case tm_tag_macro_with_arg_t
:
246 AnEditor::SetAccelGroup(GtkAccelGroup
* acl
) {
250 AnEditor::~AnEditor() {
251 g_object_unref (G_OBJECT (wEditor
.GetID()));
254 long AnEditor::SendEditor(unsigned int msg
, unsigned long wParam
, long lParam
) {
255 return fnEditor(ptrEditor
, msg
, wParam
, lParam
);
258 long AnEditor::SendEditorString(unsigned int msg
, unsigned long wParam
, const char *s
) {
259 return SendEditor(msg
, wParam
, reinterpret_cast<long>(s
));
262 void AnEditor::ViewWhitespace(bool view
) {
263 if (view
&& indentationWSVisible
)
264 SendEditor(SCI_SETVIEWWS
, SCWS_VISIBLEALWAYS
);
266 SendEditor(SCI_SETVIEWWS
, SCWS_VISIBLEAFTERINDENT
);
268 SendEditor(SCI_SETVIEWWS
, SCWS_INVISIBLE
);
271 StyleAndWords
AnEditor::GetStyleAndWords(const char *base
) {
273 SString fileNameForExtension
= ExtensionFileName();
274 SString sAndW
= props
->GetNewExpand(base
, fileNameForExtension
.c_str());
275 sw
.styleNumber
= sAndW
.value();
276 const char *space
= strchr(sAndW
.c_str(), ' ');
278 sw
.words
= space
+ 1;
282 void AnEditor::AssignKey(int key
, int mods
, int cmd
) {
283 SendEditor(SCI_ASSIGNCMDKEY
,
284 Platform::LongFromTwoShorts(static_cast<short>(key
),
285 static_cast<short>(mods
)), cmd
);
288 void AnEditor::SetOverrideLanguage(int ID
) {
289 overrideExtension
= extList
[ID
- TE_LEXER_BASE
];
292 int AnEditor::LengthDocument() {
293 return SendEditor(SCI_GETLENGTH
);
296 int AnEditor::GetCaretInLine() {
297 int caret
= SendEditor(SCI_GETCURRENTPOS
);
298 int line
= SendEditor(SCI_LINEFROMPOSITION
, caret
);
299 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
300 return caret
- lineStart
;
303 void AnEditor::GetLine(SString
& text
, int line
) {
305 line
= GetCurrentLineNumber();
306 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
307 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
308 int len
= lineEnd
- lineStart
+ 1;
309 char *text_buffer
= SString::StringAllocate (len
);
310 GetRange(wEditor
, lineStart
, lineEnd
, text_buffer
);
311 text_buffer
[len
] = '\0';
312 text
.attach(text_buffer
, len
);
315 int AnEditor::GetFullLine(SString
& text
, int line
) {
316 int caret
, lineStart
, lineEnd
;
319 line
= GetCurrentLineNumber();
320 caret
= GetCaretInLine();
321 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
322 lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
326 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
327 lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
328 caret
= lineEnd
- lineStart
- 1;
330 int count
= 25, current
;
331 int len
= lineEnd
- lineStart
+ 1;
336 char *text_buffer
= SString::StringAllocate (len
+ text
.length());
337 GetRange(wEditor
, lineStart
, lineEnd
, text_buffer
);
338 memcpy(text_buffer
+ len
- 1, text
.c_str(), text
.length());
339 text_buffer
[len
+ text
.length()] = '\0';
340 text
.attach(text_buffer
, len
+ text
.length());
345 if(text
[current
- 1] == ';' ||
346 text
[current
- 1] == '{' || text
[current
- 1] == '}')
354 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
355 lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
356 len
= lineEnd
- lineStart
;
366 void AnEditor::GetRange(Window
&win
, int start
, int end
, char *text
) {
368 tr
.chrg
.cpMin
= start
;
371 Platform::SendScintilla(win
.GetID(), SCI_GETTEXTRANGE
, 0, reinterpret_cast<long>(&tr
));
374 void AnEditor::GetRange(guint start
, guint end
, gchar
*text
, gboolean styled
) {
376 tr
.chrg
.cpMin
= start
;
380 SendEditor (SCI_GETSTYLEDTEXT
, 0, reinterpret_cast<long>(&tr
));
382 SendEditor (SCI_GETTEXTRANGE
, 0, reinterpret_cast<long>(&tr
));
388 * Check if the given line is a preprocessor condition line.
389 * @return The kind of preprocessor condition (enum values).
391 int AnEditor::IsLinePreprocessorCondition(const char *line
) {
392 const char *currChar
= line
;
399 while (isspacechar(*currChar
) && *currChar
) {
402 if (preprocessorSymbol
&& (*currChar
== preprocessorSymbol
)) {
404 while (isspacechar(*currChar
) && *currChar
) {
407 while (!isspacechar(*currChar
) && *currChar
) {
408 word
[i
++] = *currChar
++;
411 if (preprocCondStart
.InList(word
)) {
414 if (preprocCondMiddle
.InList(word
)) {
417 if (preprocCondEnd
.InList(word
)) {
425 * Search a matching preprocessor condition line.
426 * @return @c true if the end condition are meet.
427 * Also set curLine to the line where one of these conditions is mmet.
429 bool AnEditor::FindMatchingPreprocessorCondition(
430 int &curLine
, ///< Number of the line where to start the search
431 int direction
, ///< Direction of search: 1 = forward, -1 = backward
432 int condEnd1
, ///< First status of line for which the search is OK
433 int condEnd2
) { ///< Second one
435 bool isInside
= false;
437 int status
, level
= 0;
438 int maxLines
= SendEditor(SCI_GETLINECOUNT
);
440 while (curLine
< maxLines
&& curLine
> 0 && !isInside
) {
441 curLine
+= direction
; // Increment or decrement
442 GetLine(line
, curLine
);
443 status
= IsLinePreprocessorCondition(line
.c_str());
445 if ((direction
== 1 && status
== ppcStart
) || (direction
== -1 && status
== ppcEnd
)) {
447 } else if (level
> 0 && ((direction
== 1 && status
== ppcEnd
) || (direction
== -1 && status
== ppcStart
))) {
449 } else if (level
== 0 && (status
== condEnd1
|| status
== condEnd2
)) {
458 * Find if there is a preprocessor condition after or before the caret position,
459 * @return @c true if inside a preprocessor condition.
462 // Borland warns that isInside is assigned a value that is never used in this method.
463 // This is OK so turn off the warning just for this method.
466 bool AnEditor::FindMatchingPreprocCondPosition(
467 bool isForward
, ///< @c true if search forward
468 int &mppcAtCaret
, ///< Matching preproc. cond.: current position of caret
469 int &mppcMatch
) { ///< Matching preproc. cond.: matching position
471 bool isInside
= false;
477 curLine
= SendEditor(SCI_LINEFROMPOSITION
, mppcAtCaret
);
478 GetLine(line
, curLine
);
479 status
= IsLinePreprocessorCondition(line
.c_str());
484 isInside
= FindMatchingPreprocessorCondition(curLine
, 1, ppcMiddle
, ppcEnd
);
486 mppcMatch
= mppcAtCaret
;
492 isInside
= FindMatchingPreprocessorCondition(curLine
, 1, ppcMiddle
, ppcEnd
);
494 isInside
= FindMatchingPreprocessorCondition(curLine
, -1, ppcStart
, ppcMiddle
);
499 mppcMatch
= mppcAtCaret
;
502 isInside
= FindMatchingPreprocessorCondition(curLine
, -1, ppcStart
, ppcMiddle
);
505 default: // Should be noPPC
508 isInside
= FindMatchingPreprocessorCondition(curLine
, 1, ppcMiddle
, ppcEnd
);
510 isInside
= FindMatchingPreprocessorCondition(curLine
, -1, ppcStart
, ppcMiddle
);
516 mppcMatch
= SendEditor(SCI_POSITIONFROMLINE
, curLine
);
527 * Find if there is a brace next to the caret, checking before caret first, then
528 * after caret. If brace found also find its matching brace.
529 * @return @c true if inside a bracket pair.
531 bool AnEditor::FindMatchingBracePosition(bool editor
, int &braceAtCaret
, int &braceOpposite
, bool sloppy
) {
532 bool isInside
= false;
533 // Window &win = editor ? wEditor : wOutput;
534 Window
&win
= wEditor
;
535 int bracesStyleCheck
= editor
? bracesStyle
: 0;
536 int caretPos
= Platform::SendScintilla(win
.GetID(), SCI_GETCURRENTPOS
, 0, 0);
539 char charBefore
= '\0';
540 char styleBefore
= '\0';
541 WindowAccessor
acc(win
.GetID(), *props
);
543 charBefore
= acc
[caretPos
- 1];
544 styleBefore
= static_cast<char>(acc
.StyleAt(caretPos
- 1) & 31);
546 // Priority goes to character before caret
547 if (charBefore
&& strchr("[](){}", charBefore
) &&
548 ((styleBefore
== bracesStyleCheck
) || (!bracesStyle
))) {
549 braceAtCaret
= caretPos
- 1;
551 bool colonMode
= false;
552 if (lexLanguage
== SCLEX_PYTHON
&& ':' == charBefore
) {
553 braceAtCaret
= caretPos
- 1;
557 if (sloppy
&& (braceAtCaret
< 0)) {
558 // No brace found so check other side
559 char charAfter
= acc
[caretPos
];
560 char styleAfter
= static_cast<char>(acc
.StyleAt(caretPos
) & 31);
561 if (charAfter
&& strchr("[](){}", charAfter
) && (styleAfter
== bracesStyleCheck
)) {
562 braceAtCaret
= caretPos
;
565 if (lexLanguage
== SCLEX_PYTHON
&& ':' == charAfter
) {
566 braceAtCaret
= caretPos
;
570 if (braceAtCaret
>= 0) {
572 int lineStart
= Platform::SendScintilla(win
.GetID(), SCI_LINEFROMPOSITION
, braceAtCaret
);
573 int lineMaxSubord
= Platform::SendScintilla(win
.GetID(), SCI_GETLASTCHILD
, lineStart
, -1);
574 braceOpposite
= Platform::SendScintilla(win
.GetID(), SCI_GETLINEENDPOSITION
, lineMaxSubord
);
576 braceOpposite
= Platform::SendScintilla(win
.GetID(), SCI_BRACEMATCH
, braceAtCaret
, 0);
578 if (braceOpposite
> braceAtCaret
) {
587 void AnEditor::BraceMatch(bool editor
) {
590 int braceAtCaret
= -1;
591 int braceOpposite
= -1;
592 FindMatchingBracePosition(editor
, braceAtCaret
, braceOpposite
, bracesSloppy
);
593 // Window &win = editor ? wEditor : wOutput;
594 Window
&win
= wEditor
;
595 if ((braceAtCaret
!= -1) && (braceOpposite
== -1)) {
596 Platform::SendScintilla(win
.GetID(), SCI_BRACEBADLIGHT
, braceAtCaret
, 0);
597 SendEditor(SCI_SETHIGHLIGHTGUIDE
, 0);
599 char chBrace
= static_cast<char>(Platform::SendScintilla(
600 win
.GetID(), SCI_GETCHARAT
, braceAtCaret
, 0));
601 Platform::SendScintilla(win
.GetID(), SCI_BRACEHIGHLIGHT
, braceAtCaret
, braceOpposite
);
602 int columnAtCaret
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, braceAtCaret
, 0);
603 int columnOpposite
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, braceOpposite
, 0);
604 if (chBrace
== ':') {
605 int lineStart
= Platform::SendScintilla(win
.GetID(), SCI_LINEFROMPOSITION
, braceAtCaret
);
606 int indentPos
= Platform::SendScintilla(win
.GetID(), SCI_GETLINEINDENTPOSITION
, lineStart
, 0);
607 int indentPosNext
= Platform::SendScintilla(win
.GetID(), SCI_GETLINEINDENTPOSITION
, lineStart
+ 1, 0);
608 columnAtCaret
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, indentPos
, 0);
609 int columnAtCaretNext
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, indentPosNext
, 0);
610 int indentSize
= Platform::SendScintilla(win
.GetID(), SCI_GETINDENT
);
611 if (columnAtCaretNext
- indentSize
> 1)
612 columnAtCaret
= columnAtCaretNext
- indentSize
;
613 //Platform::DebugPrintf(": %d %d %d\n", lineStart, indentPos, columnAtCaret);
614 if (columnOpposite
== 0) // If the final line of the structure is empty
615 columnOpposite
= columnAtCaret
;
618 if (props
->GetInt("highlight.indentation.guides"))
619 Platform::SendScintilla(win
.GetID(), SCI_SETHIGHLIGHTGUIDE
, Platform::Minimum(columnAtCaret
, columnOpposite
), 0);
623 CharacterRange
AnEditor::GetSelection() {
624 CharacterRange crange
;
625 crange
.cpMin
= SendEditor(SCI_GETSELECTIONSTART
);
626 crange
.cpMax
= SendEditor(SCI_GETSELECTIONEND
);
630 void AnEditor::SetSelection(int anchor
, int currentPos
) {
631 SendEditor(SCI_SETSEL
, anchor
, currentPos
);
634 bool AnEditor::iswordcharforsel(char ch
) {
635 return !strchr("\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", ch
);
638 void AnEditor::SelectionWord(char *word
, int len
) {
639 int lengthDoc
= LengthDocument();
640 CharacterRange cr
= GetSelection();
641 int selStart
= cr
.cpMin
;
642 int selEnd
= cr
.cpMax
;
643 if (selStart
== selEnd
) {
644 WindowAccessor
acc(wEditor
.GetID(), *props
);
645 // Try and find a word at the caret
646 if (iswordcharforsel(acc
[selStart
])) {
647 while ((selStart
> 0) && (iswordcharforsel(acc
[selStart
- 1])))
649 while ((selEnd
< lengthDoc
- 1) && (iswordcharforsel(acc
[selEnd
+ 1])))
651 if (selStart
< selEnd
)
652 selEnd
++; // Because normal selections end one past
656 if ((selStart
< selEnd
) && ((selEnd
- selStart
+ 1) < len
)) {
657 GetRange(wEditor
, selStart
, selEnd
, word
);
661 void AnEditor::WordSelect() {
662 int lengthDoc
= LengthDocument();
666 selStart
= selEnd
= SendEditor(SCI_GETCURRENTPOS
);
667 WindowAccessor
acc(wEditor
.GetID(), *props
);
668 if (iswordcharforsel(acc
[selStart
])) {
669 while ((selStart
> 0) && (iswordcharforsel(acc
[selStart
- 1])))
671 while ((selEnd
< lengthDoc
- 1) && (iswordcharforsel(acc
[selEnd
+ 1])))
673 if (selStart
< selEnd
)
674 selEnd
++; // Because normal selections end one past
676 SetSelection(selStart
, selEnd
);
679 void AnEditor::LineSelect() {
680 int pos
= SendEditor(SCI_GETCURRENTPOS
);
681 int line
= SendEditor(SCI_LINEFROMPOSITION
, pos
);
682 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
683 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
685 SetSelection(lineStart
, lineEnd
);
688 void AnEditor::SelectionIntoProperties() {
689 CharacterRange cr
= GetSelection();
690 char currentSelection
[1000];
691 if ((cr
.cpMin
< cr
.cpMax
) && ((cr
.cpMax
- cr
.cpMin
+ 1) < static_cast<int>(sizeof(currentSelection
)))) {
692 GetRange(wEditor
, cr
.cpMin
, cr
.cpMax
, currentSelection
);
693 int len
= strlen(currentSelection
);
694 if (len
> 2 && iscntrl(currentSelection
[len
- 1]))
695 currentSelection
[len
- 1] = '\0';
696 if (len
> 2 && iscntrl(currentSelection
[len
- 2]))
697 currentSelection
[len
- 2] = '\0';
698 props
->Set("CurrentSelection", currentSelection
);
701 SelectionWord(word
, sizeof(word
));
702 props
->Set("CurrentWord", word
);
705 long AnEditor::Find (long flags
, char* findWhat
) {
706 if (!findWhat
) return -1;
707 TextToFind ft
= {{0, 0}, 0, {0, 0}};
708 CharacterRange crange
= GetSelection();
709 if (flags
& ANEFIND_REVERSE_FLAG
) {
710 ft
.chrg
.cpMin
= crange
.cpMin
- 1;
713 ft
.chrg
.cpMin
= crange
.cpMax
;
714 ft
.chrg
.cpMax
= LengthDocument();
716 ft
.lpstrText
= findWhat
;
717 ft
.chrgText
.cpMin
= 0;
718 ft
.chrgText
.cpMax
= 0;
719 int posFind
= SendEditor(SCI_FINDTEXT
, flags
, reinterpret_cast<long>(&ft
));
721 EnsureRangeVisible(ft
.chrgText
.cpMin
, ft
.chrgText
.cpMax
);
722 SetSelection(ft
.chrgText
.cpMin
, ft
.chrgText
.cpMax
);
727 void AnEditor::BookmarkToggle( int lineno
) {
729 lineno
= GetCurrentLineNumber();
730 int state
= SendEditor(SCI_MARKERGET
, lineno
);
731 if ( state
& (1 << ANE_MARKER_BOOKMARK
))
732 SendEditor(SCI_MARKERDELETE
, lineno
, ANE_MARKER_BOOKMARK
);
734 SendEditor(SCI_MARKERADD
, lineno
, ANE_MARKER_BOOKMARK
);
738 void AnEditor::BookmarkFirst() {
739 int lineno
= GetCurrentLineNumber();
740 int nextLine
= SendEditor(SCI_MARKERNEXT
, 0, 1 << ANE_MARKER_BOOKMARK
);
741 if (nextLine
< 0 || nextLine
== lineno
)
742 gdk_beep(); // how do I beep? -- like this ;-)
744 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
745 SendEditor(SCI_GOTOLINE
, nextLine
);
749 void AnEditor::BookmarkPrev() {
750 int lineno
= GetCurrentLineNumber();
751 int nextLine
= SendEditor(SCI_MARKERPREVIOUS
, lineno
- 1, 1 << ANE_MARKER_BOOKMARK
);
752 if (nextLine
< 0 || nextLine
== lineno
) {
753 if(props
->GetInt("editor.wrapbookmarks")) {
754 int nrOfLines
= SendEditor(SCI_GETLINECOUNT
, 0, 1 << ANE_MARKER_BOOKMARK
);
755 int nextLine
= SendEditor(SCI_MARKERPREVIOUS
, nrOfLines
, 1 << ANE_MARKER_BOOKMARK
);
756 if (nextLine
< 0 || nextLine
== lineno
) {
757 gdk_beep(); // how do I beep? -- like this ;-)
759 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
760 SendEditor(SCI_GOTOLINE
, nextLine
);
764 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
765 SendEditor(SCI_GOTOLINE
, nextLine
);
769 void AnEditor::BookmarkNext() {
770 int lineno
= GetCurrentLineNumber();
771 int nextLine
= SendEditor(SCI_MARKERNEXT
, lineno
+ 1, 1 << ANE_MARKER_BOOKMARK
);
772 if (nextLine
< 0 || nextLine
== lineno
) {
773 if(props
->GetInt("editor.wrapbookmarks")) {
774 int nextLine
= SendEditor(SCI_MARKERNEXT
, 0, 1 << ANE_MARKER_BOOKMARK
);
775 if (nextLine
< 0 || nextLine
== lineno
) {
776 gdk_beep(); // how do I beep? -- like this ;-)
778 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
779 SendEditor(SCI_GOTOLINE
, nextLine
);
783 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
784 SendEditor(SCI_GOTOLINE
, nextLine
);
788 void AnEditor::BookmarkLast() {
789 int lineno
= GetCurrentLineNumber();
790 int nextLine
= SendEditor(SCI_MARKERPREVIOUS
,
791 SendEditor(SCI_GETLINECOUNT
), 1 << ANE_MARKER_BOOKMARK
);
792 if (nextLine
< 0 || nextLine
== lineno
)
793 gdk_beep(); // how do I beep? -- like this ;-)
795 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
796 SendEditor(SCI_GOTOLINE
, nextLine
);
800 void AnEditor::BookmarkClear() {
801 SendEditor(SCI_MARKERDELETEALL
, ANE_MARKER_BOOKMARK
);
804 bool AnEditor::GetCurrentWord(char* buffer
, int length
) {
807 int current
= GetCaretInLine();
808 return FindWordInRegion(buffer
, length
, linebuf
, current
);
811 bool AnEditor::StartBlockComment() {
812 SString fileNameForExtension
= ExtensionFileName();
813 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
814 SString
base("comment.block.");
815 SString
comment_at_line_start("comment.block.at.line.start.");
817 comment_at_line_start
+= language
;
818 SString comment
= props
->Get(base
.c_str());
819 if (comment
== "") { // user friendly error message box
820 //SString error("Block comment variable \"");
822 //error += "\" is not defined in SciTE *.properties!";
823 //WindowMessageBox(wEditor, error, MB_OK | MB_ICONWARNING);
827 SString long_comment
= comment
;
829 size_t comment_length
= comment
.length();
830 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
831 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
832 size_t caretPosition
= SendEditor(SCI_GETCURRENTPOS
);
833 // checking if caret is located in _beginning_ of selected block
834 bool move_caret
= caretPosition
< selectionEnd
;
835 int selStartLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
836 int selEndLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
837 int lines
= selEndLine
- selStartLine
;
838 size_t firstSelLineStart
= SendEditor(SCI_POSITIONFROMLINE
, selStartLine
);
839 // "caret return" is part of the last selected line
841 (selectionEnd
== static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE
, selEndLine
))))
843 SendEditor(SCI_BEGINUNDOACTION
);
844 for (int i
= selStartLine
; i
<= selEndLine
; i
++) {
845 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, i
);
846 int lineIndent
= lineStart
;
847 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, i
);
848 if (props
->GetInt(comment_at_line_start
.c_str())) {
849 GetRange(wEditor
, lineIndent
, lineEnd
, linebuf
);
851 lineIndent
= GetLineIndentPosition(i
);
852 GetRange(wEditor
, lineIndent
, lineEnd
, linebuf
);
854 // empty lines are not commented
855 if (strlen(linebuf
) < 1)
857 if (memcmp(linebuf
, comment
.c_str(), comment_length
- 1) == 0) {
858 if (memcmp(linebuf
, long_comment
.c_str(), comment_length
) == 0) {
859 // removing comment with space after it
860 SendEditor(SCI_SETSEL
, lineIndent
, lineIndent
+ comment_length
);
861 SendEditorString(SCI_REPLACESEL
, 0, "");
862 if (i
== selStartLine
) // is this the first selected line?
863 selectionStart
-= comment_length
;
864 selectionEnd
-= comment_length
; // every iteration
867 // removing comment _without_ space
868 SendEditor(SCI_SETSEL
, lineIndent
, lineIndent
+ comment_length
- 1);
869 SendEditorString(SCI_REPLACESEL
, 0, "");
870 if (i
== selStartLine
) // is this the first selected line?
871 selectionStart
-= (comment_length
- 1);
872 selectionEnd
-= (comment_length
- 1); // every iteration
876 if (i
== selStartLine
) // is this the first selected line?
877 selectionStart
+= comment_length
;
878 selectionEnd
+= comment_length
; // every iteration
879 SendEditorString(SCI_INSERTTEXT
, lineIndent
, long_comment
.c_str());
881 // after uncommenting selection may promote itself to the lines
882 // before the first initially selected line;
883 // another problem - if only comment symbol was selected;
884 if (selectionStart
< firstSelLineStart
) {
885 if (selectionStart
>= selectionEnd
- (comment_length
- 1))
886 selectionEnd
= firstSelLineStart
;
887 selectionStart
= firstSelLineStart
;
890 // moving caret to the beginning of selected block
891 SendEditor(SCI_GOTOPOS
, selectionEnd
);
892 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
894 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
896 SendEditor(SCI_ENDUNDOACTION
);
900 // Return true if the selected zone can be commented
901 // Return false if it cannot be commented or has been uncommented
902 // BOX_COMMENT : box_stream = true STREAM_COMMENT : box_stream = false
903 // Uncomment if the selected zone or the cursor is inside the comment
905 bool AnEditor::CanBeCommented(bool box_stream
) {
906 SString fileNameForExtension
= ExtensionFileName();
907 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
908 SString
start_base("comment.box.start.");
909 SString
middle_base("comment.box.middle.");
910 SString
end_base("comment.box.end.");
911 SString
white_space(" ");
912 start_base
+= language
;
913 middle_base
+= language
;
914 end_base
+= language
;
915 SString start_comment
= props
->Get(start_base
.c_str());
916 SString middle_cmt
= props
->Get(middle_base
.c_str());
917 SString end_comment
= props
->Get(end_base
.c_str());
918 start_comment
+= white_space
;
919 middle_cmt
+= white_space
;
920 white_space
+= end_comment
;
921 end_comment
= white_space
;
922 size_t start_comment_length
= start_comment
.length();
923 size_t end_comment_length
= end_comment
.length();
924 size_t middle_cmt_length
= middle_cmt
.length();
925 SString
start_base_stream ("comment.stream.start.");
926 start_base_stream
+= language
;
927 SString
end_base_stream ("comment.stream.end.");
928 end_base_stream
+= language
;
929 SString end_comment_stream
= props
->Get(end_base_stream
.c_str());
930 SString
white_space_stream(" ");
931 //SString end_white_space_stream(" ");
932 SString start_comment_stream
= props
->Get(start_base_stream
.c_str());
933 start_comment_stream
+= white_space_stream
;
934 size_t start_comment_stream_length
= start_comment_stream
.length();
935 white_space_stream
+=end_comment_stream
;
936 end_comment_stream
= white_space_stream
;
937 size_t end_comment_stream_length
= end_comment_stream
.length();
940 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
941 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
942 if (selectionStart
== selectionEnd
)
944 int line
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
947 bool start1
= false, start2
= false;
948 bool end1
= false, end2
= false;
951 lineEnd1
= selectionStart
+ start_comment_length
;
953 lineEnd1
= selectionStart
+ start_comment_stream_length
+1;
954 if (lineEnd1
> LengthDocument())
955 lineEnd1
= LengthDocument();
958 size_t start_cmt
= 0, end_cmt
= 0;
960 // Find Backward StartComment
961 while (line
>= 0 && start1
== false && end1
== false)
963 lineStart1
= SendEditor(SCI_POSITIONFROMLINE
, line
);
964 GetRange(wEditor
, lineStart1
, lineEnd1
, linebuf
);
966 for (index
= lineEnd1
-lineStart1
; index
>= 0; index
--)
968 if (end1
= ((end_comment_length
> 1 && !memcmp(linebuf
+index
,
969 end_comment
.c_str(), end_comment_length
))
970 || (end_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
971 end_comment_stream
.c_str(), end_comment_stream_length
))))
973 if (start1
=((start_comment_length
> 1 && !memcmp(linebuf
+index
,
974 start_comment
.c_str(), start_comment_length
))
975 || (start_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
976 start_comment_stream
.c_str(), start_comment_stream_length
))))
980 lineEnd1
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
982 start_cmt
= index
+ lineStart1
;
983 line
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
985 lineStart1
= selectionEnd
- start_comment_length
;
987 lineStart1
= selectionEnd
- start_comment_stream_length
;
988 int last_line
= SendEditor(SCI_GETLINECOUNT
);
989 // Find Forward EndComment
990 while (line
<= last_line
&& start2
== false && end2
== false)
992 lineEnd1
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
993 GetRange(wEditor
, lineStart1
, lineEnd1
, linebuf
);
994 for (index
= 0; index
<= (lineEnd1
-lineStart1
); index
++)
996 if (start2
= ((start_comment_length
> 1 && !memcmp(linebuf
+index
,
997 start_comment
.c_str(), start_comment_length
))
998 || (start_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
999 start_comment_stream
.c_str(), start_comment_stream_length
))))
1001 if (end2
= ((end_comment_length
> 1 && !memcmp(linebuf
+index
,
1002 end_comment
.c_str(), end_comment_length
))
1003 || (end_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
1004 end_comment_stream
.c_str(), end_comment_stream_length
))))
1008 end_cmt
= lineStart1
+ index
;
1009 lineStart1
= SendEditor(SCI_POSITIONFROMLINE
, line
);
1016 SendEditor(SCI_BEGINUNDOACTION
);
1017 if (box_stream
) // Box
1019 SendEditor(SCI_SETSEL
, start_cmt
, start_cmt
+
1020 start_comment_length
);
1021 end_cmt
-= start_comment_length
;
1025 SendEditor(SCI_SETSEL
, start_cmt
, start_cmt
+
1026 start_comment_stream_length
);
1027 end_cmt
-= start_comment_stream_length
;
1029 SendEditorString(SCI_REPLACESEL
, 0, "");
1030 line
= SendEditor(SCI_LINEFROMPOSITION
, start_cmt
) + 1;
1031 last_line
= SendEditor(SCI_LINEFROMPOSITION
, end_cmt
) ;
1032 for (int i
= line
; i
< last_line
; i
++)
1034 int s
= SendEditor(SCI_POSITIONFROMLINE
, i
);
1035 int e
= SendEditor(SCI_GETLINEENDPOSITION
, i
);
1036 GetRange(wEditor
, s
, e
, linebuf
);
1037 if (!memcmp(linebuf
, middle_cmt
.c_str(), middle_cmt_length
))
1039 SendEditor(SCI_SETSEL
, s
, s
+ middle_cmt_length
);
1040 SendEditorString(SCI_REPLACESEL
, 0, "");
1041 end_cmt
-= middle_cmt_length
;
1044 if (box_stream
) // Box
1045 SendEditor(SCI_SETSEL
, end_cmt
, end_cmt
+ end_comment_length
);
1047 SendEditor(SCI_SETSEL
, end_cmt
, end_cmt
+ end_comment_stream_length
);
1048 SendEditorString(SCI_REPLACESEL
, 0, "");
1049 SendEditor(SCI_ENDUNDOACTION
);
1057 bool AnEditor::StartBoxComment() {
1058 SString fileNameForExtension
= ExtensionFileName();
1059 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
1060 SString
start_base("comment.box.start.");
1061 SString
middle_base("comment.box.middle.");
1062 SString
end_base("comment.box.end.");
1063 SString
white_space(" ");
1064 start_base
+= language
;
1065 middle_base
+= language
;
1066 end_base
+= language
;
1067 SString start_comment
= props
->Get(start_base
.c_str());
1068 SString middle_comment
= props
->Get(middle_base
.c_str());
1069 SString end_comment
= props
->Get(end_base
.c_str());
1070 if (start_comment
== "" || middle_comment
== "" || end_comment
== "") {
1071 //SString error("Box comment variables \"");
1072 //error += start_base;
1073 //error += "\", \"";
1074 //error += middle_base;
1075 //error += "\"\nand \"";
1076 //error += end_base;
1077 //error += "\" are not ";
1078 //error += "defined in SciTE *.properties!";
1079 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1082 start_comment
+= white_space
;
1083 middle_comment
+= white_space
;
1084 white_space
+= end_comment
;
1085 end_comment
= white_space
;
1086 size_t start_comment_length
= start_comment
.length();
1087 size_t middle_comment_length
= middle_comment
.length();
1088 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
1089 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
1090 size_t caretPosition
= SendEditor(SCI_GETCURRENTPOS
);
1091 // checking if caret is located in _beginning_ of selected block
1092 bool move_caret
= caretPosition
< selectionEnd
;
1093 size_t selStartLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
1094 size_t selEndLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
1095 size_t lines
= selEndLine
- selStartLine
;
1096 // "caret return" is part of the last selected line
1097 if ((lines
> 0) && (
1098 selectionEnd
== static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE
, selEndLine
)))) {
1101 // get rid of CRLF problems
1102 selectionEnd
= SendEditor(SCI_GETLINEENDPOSITION
, selEndLine
);
1104 // Comment , Uncomment or Do Nothing
1105 if (CanBeCommented(true))
1107 SendEditor(SCI_BEGINUNDOACTION
);
1108 // first commented line (start_comment)
1109 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, selStartLine
);
1110 SendEditorString(SCI_INSERTTEXT
, lineStart
, start_comment
.c_str());
1111 selectionStart
+= start_comment_length
;
1112 // lines between first and last commented lines (middle_comment)
1113 for (size_t i
= selStartLine
+ 1; i
<= selEndLine
; i
++) {
1114 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, i
);
1115 SendEditorString(SCI_INSERTTEXT
, lineStart
, middle_comment
.c_str());
1116 selectionEnd
+= middle_comment_length
;
1118 // last commented line (end_comment)
1119 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, selEndLine
);
1121 SendEditorString(SCI_INSERTTEXT
, lineEnd
, "\n");
1122 SendEditorString(SCI_INSERTTEXT
, lineEnd
+ 1, (end_comment
.c_str() + 1));
1124 SendEditorString(SCI_INSERTTEXT
, lineEnd
, end_comment
.c_str());
1126 selectionEnd
+= (start_comment_length
);
1128 // moving caret to the beginning of selected block
1129 SendEditor(SCI_GOTOPOS
, selectionEnd
);
1130 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
1132 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
1134 SendEditor(SCI_ENDUNDOACTION
);
1139 bool AnEditor::StartStreamComment() {
1140 SString fileNameForExtension
= ExtensionFileName();
1141 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
1142 SString
start_base("comment.stream.start.");
1143 SString
end_base("comment.stream.end.");
1144 SString
white_space(" ");
1145 //SString end_white_space(" ");
1146 start_base
+= language
;
1147 end_base
+= language
;
1148 SString start_comment
= props
->Get(start_base
.c_str());
1149 SString end_comment
= props
->Get(end_base
.c_str());
1150 if (start_comment
== "" || end_comment
== "") {
1151 //SString error("Stream comment variables \"");
1152 //error += start_base;
1153 //error += "\" and \n\"";
1154 //error += end_base;
1155 //error += "\" are not ";
1156 //error += "defined in SciTE *.properties!";
1157 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1160 start_comment
+= white_space
;
1161 white_space
+= end_comment
;
1162 end_comment
= white_space
;
1163 size_t start_comment_length
= start_comment
.length();
1164 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
1165 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
1166 size_t caretPosition
= SendEditor(SCI_GETCURRENTPOS
);
1167 // checking if caret is located in _beginning_ of selected block
1168 bool move_caret
= caretPosition
< selectionEnd
;
1169 // if there is no selection?
1170 if (selectionEnd
- selectionStart
<= 0) {
1171 int selLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
1172 int lineIndent
= GetLineIndentPosition(selLine
);
1173 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, selLine
);
1174 if (RangeIsAllWhitespace(lineIndent
, lineEnd
))
1175 return true; // we are not dealing with empty lines
1178 int current
= GetCaretInLine();
1179 // checking if we are not inside a word
1180 if (!wordCharacters
.contains(linebuf
[current
]))
1181 return true; // caret is located _between_ words
1182 int startword
= current
;
1183 int endword
= current
;
1184 int start_counter
= 0;
1185 int end_counter
= 0;
1186 while (startword
> 0 && wordCharacters
.contains(linebuf
[startword
- 1])) {
1190 // checking _beginning_ of the word
1191 if (startword
== current
)
1192 return true; // caret is located _before_ a word
1193 while (linebuf
[endword
+ 1] != '\0' && wordCharacters
.contains(linebuf
[endword
+ 1])) {
1197 selectionStart
-= start_counter
;
1198 selectionEnd
+= (end_counter
+ 1);
1200 // Comment , Uncomment or Do Nothing
1201 if (CanBeCommented(false))
1203 SendEditor(SCI_BEGINUNDOACTION
);
1204 SendEditorString(SCI_INSERTTEXT
, selectionStart
, start_comment
.c_str());
1205 selectionEnd
+= start_comment_length
;
1206 selectionStart
+= start_comment_length
;
1207 SendEditorString(SCI_INSERTTEXT
, selectionEnd
, end_comment
.c_str());
1209 // moving caret to the beginning of selected block
1210 SendEditor(SCI_GOTOPOS
, selectionEnd
);
1211 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
1213 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
1215 SendEditor(SCI_ENDUNDOACTION
);
1221 SString
AnEditor::GetMode(SString language
) {
1223 if (strcmp(language
.c_str(), "cpp") == 0)
1225 mode
+= " Mode: C;";
1226 if (props
->GetInt("use.tabs"))
1227 mode
+= " indent-tabs-mode: t;";
1228 mode
+= " c-basic-offset: ";
1229 mode
+= g_strdup_printf("%d", props
->GetInt("indent.size"));
1230 mode
+= "; tab-width: ";
1231 mode
+= g_strdup_printf("%d ", props
->GetInt("tabsize"));
1238 /* Insert or Modify a Comment line
1239 giving File indent */
1240 bool AnEditor::InsertCustomIndent() {
1243 SString fileNameForExtension
= ExtensionFileName();
1244 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
1245 SString
start_box_base("comment.box.start.");
1246 start_box_base
+= language
;
1247 SString
start_stream_base("comment.stream.start.");
1248 start_stream_base
+= language
;
1249 SString
end_box_base("comment.box.end.");
1250 end_box_base
+= language
;
1251 SString
end_stream_base("comment.stream.end.");
1252 end_stream_base
+= language
;
1253 SString start_box
= props
->Get(start_box_base
.c_str());
1254 SString start_stream
= props
->Get(start_stream_base
.c_str());
1255 SString end_box
= props
->Get(end_box_base
.c_str());
1256 SString end_stream
= props
->Get(end_stream_base
.c_str());
1257 SString
mark("-*-");
1258 int text_length
= SendEditor(SCI_GETTEXTLENGTH
);
1260 int bufmax
= text_length
< MAXBUF
? text_length
: MAXBUF
;
1262 GetRange(wEditor
, 0, bufmax
- 1, buf
);
1264 bool start_comment
= false;
1265 bool indent_comment
= false;
1266 int end_indent_comment
= 0;
1268 for (int index
= 0; index
< bufmax
; index
++)
1272 if (memcmp(buf
+index
, start_box
.c_str(), start_box
.length()) == 0)
1274 index
+= (start_box
.length() - 1);
1275 start_comment
= true;
1278 if (memcmp(buf
+index
, start_stream
.c_str(), start_stream
.length()) == 0)
1280 index
+= (start_stream
.length() - 1);
1281 start_comment
= true;
1284 if (buf
[index
] != ' ' && buf
[index
] != '\t' && buf
[index
] != '\n')
1289 if (!indent_comment
)
1291 if (buf
[index
] == ' ' || buf
[index
] == '\t' || buf
[index
] == '\n')
1293 if (memcmp(buf
+index
, mark
.c_str(), 3) == 0)
1296 indent_comment
= true;
1303 if (memcmp(buf
+index
, end_box
.c_str(), end_box
.length()) == 0)
1305 end_indent_comment
= index
+ end_box
.length() - 1;
1308 if (memcmp(buf
+index
, end_stream
.c_str(), end_stream
.length()) == 0)
1310 end_indent_comment
= index
+ end_stream
.length() - 1;
1316 SString mode
= GetMode(language
);
1317 if (mode
.c_str() != "")
1320 comment
+= start_stream
.c_str() ;
1322 comment
+= mark
.c_str();
1323 comment
+= mode
.c_str();
1324 comment
+= mark
.c_str();
1326 comment
+= end_stream
.c_str() ;
1330 SendEditor(SCI_SETSEL
, 0, end_indent_comment
+ 1);
1331 SendEditorString(SCI_REPLACESEL
, 0, comment
.c_str());
1336 SendEditorString(SCI_INSERTTEXT
, 0, comment
.c_str());
1345 * Return the length of the given line, not counting the EOL.
1347 int AnEditor::GetLineLength(int line
) {
1348 return SendEditor(SCI_GETLINEENDPOSITION
, line
) - SendEditor(SCI_POSITIONFROMLINE
, line
);
1351 int AnEditor::GetCurrentLineNumber() {
1352 CharacterRange crange
= GetSelection();
1353 int selStart
= crange
.cpMin
;
1354 return SendEditor(SCI_LINEFROMPOSITION
, selStart
);
1357 int AnEditor::GetCurrentScrollPosition() {
1358 int lineDisplayTop
= SendEditor(SCI_GETFIRSTVISIBLELINE
);
1359 return SendEditor(SCI_DOCLINEFROMVISIBLE
, lineDisplayTop
);
1362 // Upon a character being added, AnEditor may decide to perform some action
1363 // such as displaying a completion list.
1364 void AnEditor::CharAdded(char ch
) {
1365 CharacterRange crange
= GetSelection();
1366 int selStart
= crange
.cpMin
;
1367 int selEnd
= crange
.cpMax
;
1368 if ((selEnd
== selStart
) && (selStart
> 0)) {
1369 int style
= SendEditor(SCI_GETSTYLEAT
, selStart
- 1, 0);
1371 if (SendEditor(SCI_CALLTIPACTIVE
)) { // calltip is active
1372 if (ch
== ')') { // close our calltip
1376 if (braceCount
< 1) { // shutdown at all
1378 SendEditor(SCI_CALLTIPCANCEL
);
1383 } else if (ch
== '(') { // a new calltip is encountered?...
1388 // here it is, we continue the calltip
1389 //ContinueCallTip();
1390 ContinueCallTip_new();
1392 } else if (SendEditor(SCI_AUTOCACTIVE
)) { // word autocompletion
1397 } else if (ch
== ')') {
1399 } else if (!wordCharacters
.contains(ch
)) {
1400 SendEditor(SCI_AUTOCCANCEL
);
1401 if (autocompletion
) {
1402 g_completion_free (autocompletion
);
1403 autocompletion
= NULL
;
1405 } else if (autoCCausedByOnlyOne
) {
1406 StartAutoCompleteWord(props
->GetInt("autocompleteword.automatic"));
1408 StartAutoCompleteWord(0);
1410 } else if (HandleXml(ch
)) {
1411 // Handled in the routine
1413 else { // we don't have autocompetion nor calltip active
1414 if (autocompletion
) {
1415 g_completion_free (autocompletion
);
1416 autocompletion
= NULL
;
1423 // check whether we have some left nodes in call_tip_node_queue: this
1424 // can happen if we hit the "down key" when calltip is active
1427 if ( g_queue_is_empty( call_tip_node_queue
) != TRUE
)
1430 // ok, let's start a new calltip
1433 autoCCausedByOnlyOne
= false;
1435 MaintainIndentation(ch
);
1437 else if (props->GetInt("indent.automatic"))
1438 AutomaticIndentation(ch);
1440 if (autoCompleteStartCharacters
.contains(ch
)) {
1441 StartAutoComplete();
1442 } else if (props
->GetInt("autocompleteword.automatic") &&
1443 !StartAutoCompleteRecordsFields(ch
) &&
1444 wordCharacters
.contains(ch
)) {
1446 StartAutoCompleteWord(props
->GetInt("autocompleteword.automatic"));
1447 autoCCausedByOnlyOne
= SendEditor(SCI_AUTOCACTIVE
);
1456 * This routine will auto complete XML or HTML tags that are still open by closing them
1457 * @parm ch The characer we are dealing with, currently only works with the '/' character
1458 * @return True if handled, false otherwise
1460 bool AnEditor::HandleXml(char ch
) {
1461 // We're looking for this char
1462 // Quit quickly if not found
1467 // This may make sense only in certain languages
1468 if (lexLanguage
!= SCLEX_HTML
&& lexLanguage
!= SCLEX_XML
&&
1469 lexLanguage
!= SCLEX_ASP
&& lexLanguage
!= SCLEX_PHP
) {
1473 // If the user has turned us off, quit now.
1475 SString value
= props
->GetExpanded("xml.auto.close.tags");
1476 if ((value
.length() == 0) || (value
== "0")) {
1480 // Grab the last 512 characters or so
1481 int nCaret
= SendEditor(SCI_GETCURRENTPOS
);
1483 int nMin
= nCaret
- (sizeof(sel
) - 1);
1488 if (nCaret
- nMin
< 3) {
1489 return false; // Smallest tag is 3 characters ex. <p>
1491 GetRange(wEditor
, nMin
, nCaret
, sel
);
1492 sel
[sizeof(sel
) - 1] = '\0';
1494 if (sel
[nCaret
- nMin
- 2] == '/') {
1495 // User typed something like "<br/>"
1499 SString strFound
= FindOpenXmlTag(sel
, nCaret
- nMin
);
1501 if (strFound
.length() > 0) {
1502 SendEditor(SCI_BEGINUNDOACTION
);
1503 SString toInsert
= "</";
1504 toInsert
+= strFound
;
1506 SendEditorString(SCI_REPLACESEL
, 0, toInsert
.c_str());
1507 SetSelection(nCaret
, nCaret
);
1508 SendEditor(SCI_ENDUNDOACTION
);
1515 /** Search backward through nSize bytes looking for a '<', then return the tag if any
1516 * @return The tag name
1518 SString
AnEditor::FindOpenXmlTag(const char sel
[], int nSize
) {
1519 SString strRet
= "";
1522 // Smallest tag is "<p>" which is 3 characters
1525 const char* pBegin
= &sel
[0];
1526 const char* pCur
= &sel
[nSize
- 1];
1528 pCur
--; // Skip past the >
1529 while (pCur
> pBegin
) {
1532 } else if (*pCur
== '>') {
1540 while (strchr(":_-.", *pCur
) || isalnum(*pCur
)) {
1546 // Return the tag name or ""
1550 void AnEditor::GoMatchingBrace(bool select
) {
1551 int braceAtCaret
= -1;
1552 int braceOpposite
= -1;
1553 bool isInside
= FindMatchingBracePosition(true, braceAtCaret
, braceOpposite
, true);
1554 // Convert the character positions into caret positions based on whether
1555 // the caret position was inside or outside the braces.
1557 if (braceOpposite
> braceAtCaret
) {
1563 if (braceOpposite
> braceAtCaret
) {
1569 if (braceOpposite
>= 0) {
1570 EnsureRangeVisible(braceOpposite
, braceOpposite
);
1572 SetSelection(braceAtCaret
, braceOpposite
);
1574 SetSelection(braceOpposite
, braceOpposite
);
1579 int ControlIDOfCommand(unsigned long wParam
) {
1580 return wParam
& 0xffff;
1583 long AnEditor::Command(int cmdID
, long wParam
, long lParam
) {
1586 case ANE_INSERTTEXT
:
1587 SendEditor(SCI_INSERTTEXT
,wParam
,lParam
);
1590 case ANE_GETBOOKMARK_POS
:
1591 return GetBookmarkLine( wParam
);
1592 break; /* pleonastico */
1594 case ANE_BOOKMARK_TOGGLE_LINE
:
1595 BookmarkToggle( wParam
);
1599 SendEditor(SCI_UNDO
);
1603 SendEditor(SCI_REDO
);
1607 SendEditor(SCI_CUT
);
1611 SendEditor(SCI_COPY
);
1615 SendEditor(SCI_PASTE
);
1619 SendEditor(SCI_CLEAR
);
1623 SendEditor(SCI_SELECTALL
);
1627 return Find (wParam
, (char*) lParam
);
1630 SendEditor(SCI_GOTOLINE
, wParam
);
1634 SendEditor(SCI_SETZOOM
, wParam
);
1637 case ANE_MATCHBRACE
:
1638 GoMatchingBrace(false);
1641 case ANE_SELECTBLOCK
:
1645 case ANE_SELECTTOBRACE
:
1646 GoMatchingBrace(true);
1649 case ANE_GETBLOCKSTARTLINE
:
1650 return GetBlockStartLine();
1652 case ANE_GETBLOCKENDLINE
:
1653 return GetBlockEndLine();
1655 case ANE_GETCURRENTWORD
:
1656 return GetCurrentWord((char*)wParam
, (int)lParam
);
1658 case ANE_SHOWCALLTIP
:
1662 case ANE_COMPLETECALLTIP
:
1667 StartAutoComplete();
1670 case ANE_COMPLETEWORD
:
1671 StartAutoCompleteWord(false);
1674 case ANE_TOGGLE_FOLD
:
1678 case ANE_OPEN_FOLDALL
:
1682 case ANE_CLOSE_FOLDALL
:
1687 SendEditor(SCI_UPPERCASE
);
1691 SendEditor(SCI_LOWERCASE
);
1695 SendEditor(SCI_TOGGLEFOLD
, GetCurrentLineNumber());
1698 case ANE_LINENUMBERMARGIN
:
1699 lineNumbers
= wParam
;
1700 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
1705 SendEditor(SCI_SETMARGINWIDTHN
, 1, margin
? marginWidth
: 0);
1708 case ANE_FOLDMARGIN
:
1709 foldMargin
= wParam
;
1710 SendEditor(SCI_SETMARGINWIDTHN
, 2, foldMargin
? foldMarginWidth
: 0);
1714 SendEditor(SCI_SETVIEWEOL
, wParam
);
1718 SendEditor(SCI_SETEOLMODE
, SC_EOL_CRLF
);
1722 SendEditor(SCI_SETEOLMODE
, SC_EOL_CR
);
1726 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
1729 case ANE_EOL_CONVERT
:
1732 SendEditor(SCI_SETEOLMODE
, SC_EOL_CRLF
);
1733 SendEditor(SCI_CONVERTEOLS
, SC_EOL_CRLF
);
1736 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
1737 SendEditor(SCI_CONVERTEOLS
, SC_EOL_LF
);
1740 SendEditor(SCI_SETEOLMODE
, SC_EOL_CR
);
1741 SendEditor(SCI_CONVERTEOLS
, SC_EOL_CR
);
1744 SendEditor(SCI_CONVERTEOLS
, SendEditor(SCI_GETEOLMODE
));
1749 case ANE_WORDPARTLEFT
:
1750 SendEditor(SCI_WORDPARTLEFT
);
1753 case ANE_WORDPARTLEFTEXTEND
:
1754 SendEditor(SCI_WORDPARTLEFTEXTEND
);
1757 case ANE_WORDPARTRIGHT
:
1758 SendEditor(SCI_WORDPARTRIGHT
);
1761 case ANE_WORDPARTRIGHTEXTEND
:
1762 SendEditor(SCI_WORDPARTRIGHTEXTEND
);
1766 ViewWhitespace(wParam
);
1769 case ANE_VIEWGUIDES
:
1770 SendEditor(SCI_SETINDENTATIONGUIDES
, wParam
);
1773 case ANE_BOOKMARK_TOGGLE
:
1776 case ANE_BOOKMARK_FIRST
:
1779 case ANE_BOOKMARK_PREV
:
1782 case ANE_BOOKMARK_NEXT
:
1785 case ANE_BOOKMARK_LAST
:
1788 case ANE_BOOKMARK_CLEAR
:
1792 case ANE_SETTABSIZE
:
1793 SendEditor(SCI_SETTABWIDTH
, wParam
);
1796 case ANE_SETLANGUAGE
:
1797 SetOverrideLanguage(wParam
);
1801 ReadProperties((char*)wParam
);
1802 SendEditor(SCI_COLOURISE
, 0, -1);
1805 case ANE_SETACCELGROUP
:
1806 SetAccelGroup((GtkAccelGroup
*)wParam
);
1809 case ANE_GETTEXTRANGE
: {
1811 if(wParam
== lParam
) return 0;
1812 start
= (guint
) MINIMUM(wParam
, lParam
);
1813 end
= (guint
) MAXIMUM(wParam
, lParam
);
1814 gchar
*buff
= (gchar
*) g_malloc(end
-start
+10);
1816 GetRange(start
, end
, buff
, false);
1821 case ANE_INDENT_INCREASE
:
1822 IndentationIncrease();
1825 case ANE_INDENT_DECREASE
:
1826 IndentationDecrease();
1830 return SendEditor(SCI_GETLENGTH
);
1832 case ANE_GET_LINENO
:
1833 return GetCurrentLineNumber();
1836 SetLineWrap((bool)wParam
);
1840 SetReadOnly((bool)wParam
);
1843 case ANE_GETSTYLEDTEXT
: {
1845 if(wParam
== lParam
) return 0;
1846 start
= (guint
) MINIMUM(wParam
, lParam
);
1847 end
= (guint
) MAXIMUM(wParam
, lParam
);
1848 gchar
*buff
= (gchar
*) g_malloc((end
-start
+10)*2);
1850 GetRange(start
, end
, buff
, true);
1855 return SendEditor(SCI_TEXTWIDTH
, wParam
, lParam
);
1856 case ANE_GETLANGUAGE
:
1857 return (long) language
.c_str();
1859 case ANE_BLOCKCOMMENT
:
1860 return StartBlockComment();
1862 case ANE_BOXCOMMENT
:
1863 return StartBoxComment();
1865 case ANE_STREAMCOMMENT
:
1866 return StartStreamComment();
1868 case ANE_CUSTOMINDENT:
1869 return InsertCustomIndent();
1871 case ANE_WORDSELECT
:
1875 case ANE_LINESELECT
:
1879 case ANE_GETCURRENTPOS
:
1880 return SendEditor(SCI_GETCURRENTPOS
);
1883 return SendEditor(SCI_GOTOPOS
, wParam
);
1885 case ANE_SETWRAPBOOKMARKS
:
1889 case ANE_SETAUTOINDENTATION:
1893 case ANE_SETUSETABFORINDENT
:
1894 SendEditor(SCI_SETUSETABS
, wParam
);
1897 case ANE_SETINDENTSIZE
:
1898 indentSize
= wParam
;
1899 SendEditor(SCI_SETINDENT
, wParam
);
1902 case ANE_SETINDENTBRACESCHECK
:
1903 bracesCheck
= wParam
;
1906 case ANE_SETINDENTOPENING:
1907 indentOpening = wParam;
1910 case ANE_SETINDENTCLOSING:
1911 indentClosing = wParam;
1914 case ANE_SETINDENTMAINTAIN
:
1916 props
->Set ("indent.maintain.*", "1");
1918 props
->Set ("indent.opening.*", "0");
1919 indentMaintain
= wParam
;
1922 case ANE_SETTABINDENTS
:
1923 SendEditor(SCI_SETTABINDENTS
, wParam
);
1926 case ANE_SETBACKSPACEUNINDENTS
:
1927 SendEditor(SCI_SETBACKSPACEUNINDENTS
, wParam
);
1930 case ANE_SETFOLDSYMBOLS
:
1931 SetFoldSymbols(reinterpret_cast<char *> (wParam
));
1934 case ANE_SETFOLDUNDERLINE
:
1936 SendEditor(SCI_SETFOLDFLAGS
, props
->GetInt("fold.flags"));
1938 SendEditor(SCI_SETFOLDFLAGS
, 0);
1940 case ANE_SETLINENUMWIDTH
:
1941 lineNumbersWidth
= wParam
;
1942 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
1944 case ANE_SETEDGECOLUMN
:
1945 SendEditor(SCI_SETEDGECOLUMN
, wParam
);
1953 void AnEditor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
1954 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
1955 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
1956 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
1957 if (!SendEditor(SCI_GETFOLDEXPANDED
, line
)) {
1958 // Removing the fold from one that has been contracted so should expand
1959 // otherwise lines are left invisible with no way to make them visible
1960 Expand(line
, true, false, 0, levelPrev
);
1965 void AnEditor::Expand(int &line
, bool doExpand
, bool force
, int visLevels
, int level
) {
1966 int lineMaxSubord
= SendEditor(SCI_GETLASTCHILD
, line
, level
);
1968 while (line
<= lineMaxSubord
) {
1971 SendEditor(SCI_SHOWLINES
, line
, line
);
1973 SendEditor(SCI_HIDELINES
, line
, line
);
1976 SendEditor(SCI_SHOWLINES
, line
, line
);
1978 int levelLine
= level
;
1980 levelLine
= SendEditor(SCI_GETFOLDLEVEL
, line
);
1981 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
1984 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
1986 SendEditor(SCI_SETFOLDEXPANDED
, line
, 0);
1987 Expand(line
, doExpand
, force
, visLevels
- 1);
1989 if (doExpand
&& SendEditor(SCI_GETFOLDEXPANDED
, line
)) {
1990 Expand(line
, true, force
, visLevels
- 1);
1992 Expand(line
, false, force
, visLevels
- 1);
2001 void AnEditor::FoldCode(bool expanding
) {
2002 int maxLine
= SendEditor (SCI_GETTEXTLENGTH
);
2003 SendEditor(SCI_COLOURISE
, 0, -1);
2004 for (int line
= 0; line
< maxLine
; line
++) {
2005 int level
= SendEditor(SCI_GETFOLDLEVEL
, line
);
2006 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
2007 (SC_FOLDLEVELBASE
== (level
& SC_FOLDLEVELNUMBERMASK
))) {
2009 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
2013 int lineMaxSubord
= SendEditor(SCI_GETLASTCHILD
, line
, -1);
2014 SendEditor(SCI_SETFOLDEXPANDED
, line
, 0);
2015 if (lineMaxSubord
> line
)
2016 SendEditor(SCI_HIDELINES
, line
+ 1, lineMaxSubord
);
2022 void AnEditor::FoldOpenAll() {
2026 void AnEditor::FoldCloseAll() {
2030 void AnEditor::FoldToggle() {
2031 int curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
2032 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
2033 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2034 SendEditor(SCI_TOGGLEFOLD
, curLine
);
2037 int parent
= SendEditor (SCI_GETFOLDPARENT
, curLine
);
2038 int lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2039 if (curLine
> parent
&& curLine
<= lastChild
)
2041 SendEditor(SCI_TOGGLEFOLD
, parent
);
2042 SendEditor(SCI_SETCURRENTPOS
, SendEditor (SCI_POSITIONFROMLINE
, parent
));
2043 SendEditor(SCI_GOTOLINE
, parent
);
2049 void AnEditor::SelectBlock () {
2050 int curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
2051 int parent
= SendEditor (SCI_GETFOLDPARENT
, curLine
);
2052 int lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2053 if (curLine
> parent
&& curLine
<= lastChild
)
2056 start
= SendEditor(SCI_POSITIONFROMLINE
, parent
);
2057 end
= SendEditor(SCI_POSITIONFROMLINE
, lastChild
+1);
2058 SetSelection(start
, end
);
2064 int AnEditor::GetBlockStartLine (int curLine
) {
2067 curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
2069 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
2070 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2074 int lastChild
= curLine
;
2077 parent
= SendEditor (SCI_GETFOLDPARENT
, lastChild
);
2082 lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2083 if (curLine
> parent
&& curLine
<= lastChild
)
2087 lastChild
= parent
- 1;
2093 int AnEditor::GetBlockEndLine (int curLine
) {
2096 curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
2098 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
2099 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2100 /* this may be a problem when we use this function on "start" block line */
2104 int lastChild
= curLine
;
2107 parent
= SendEditor (SCI_GETFOLDPARENT
, lastChild
);
2112 lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2113 if (curLine
> parent
&& curLine
<= lastChild
)
2117 lastChild
= parent
- 1;
2123 void AnEditor::EnsureRangeVisible(int posStart
, int posEnd
) {
2124 int lineStart
= SendEditor(SCI_LINEFROMPOSITION
, Platform::Minimum(posStart
, posEnd
));
2125 int lineEnd
= SendEditor(SCI_LINEFROMPOSITION
, Platform::Maximum(posStart
, posEnd
));
2126 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2127 SendEditor(SCI_ENSUREVISIBLE
, line
);
2131 void AnEditor::SetLineWrap(bool wrap
) {
2133 SendEditor(SCI_SETWRAPMODE
, wrapLine
? SC_WRAP_WORD
: SC_WRAP_NONE
);
2134 SendEditor(SCI_SETHSCROLLBAR
, !wrapLine
);
2137 void AnEditor::SetReadOnly(bool readonly
) {
2138 isReadOnly
= readonly
;
2139 SendEditor(SCI_SETREADONLY
, isReadOnly
);
2142 bool AnEditor::MarginClick(int position
, int modifiers
) {
2143 int lineClick
= SendEditor(SCI_LINEFROMPOSITION
, position
);
2144 // SendEditor(SCI_GETFOLDLEVEL, lineClick) & SC_FOLDLEVELHEADERFLAG);
2145 if (modifiers
& SCMOD_SHIFT
) {
2147 } else if (modifiers
& SCMOD_CTRL
) {
2149 } else if (SendEditor(SCI_GETFOLDLEVEL
, lineClick
) & SC_FOLDLEVELHEADERFLAG
) {
2150 if (modifiers
& SCMOD_SHIFT
) {
2151 // Ensure all children visible
2152 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 1);
2153 Expand(lineClick
, true, true, 100);
2154 } else if (modifiers
& SCMOD_CTRL
) {
2155 if (SendEditor(SCI_GETFOLDEXPANDED
, lineClick
)) {
2156 // Contract this line and all children
2157 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 0);
2158 Expand(lineClick
, false, true, 0);
2160 // Expand this line and all children
2161 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 1);
2162 Expand(lineClick
, true, true, 100);
2166 SendEditor(SCI_TOGGLEFOLD
, lineClick
);
2173 gint
AnEditor::KeyPressEvent(GtkWidget
*, GdkEventKey
*event
, AnEditor
*anedit
) {
2174 return anedit
->KeyPress(event
->state
, event
->keyval
);
2178 void AnEditor::NotifySignal(GtkWidget
*, gint
/*wParam*/, gpointer lParam
, AnEditor
*anedit
) {
2179 anedit
->Notify(reinterpret_cast<SCNotification
*>(lParam
));
2185 eval_output_arrived_for_aneditor(GList
* lines
, gpointer data
)
2187 // We expect lines->data to be a string of the form VARIABLE = VALUE,
2188 // and 'data' to be a pointer to an object of type
2189 // 'ExpressionEvaluationTipInfo'.
2194 auto_ptr
<ExpressionEvaluationTipInfo
> info(
2195 (ExpressionEvaluationTipInfo
*) data
);
2197 if (info
->editor
== NULL
)
2200 if (info
->editor
!= aneditor_get(AnEditor::focusedID
))
2203 info
->editor
->EvalOutputArrived(lines
, info
->textPos
, info
->expression
);
2207 void AnEditor::EvalOutputArrived(GList
* lines
, int textPos
,
2208 const string
&expression
) {
2213 // Return if debug Tip has been canceled
2217 if (g_list_length(lines
) == 0 || lines
->data
== NULL
)
2220 string result
= (char *) lines
->data
;
2221 string::size_type posEquals
= result
.find(" = ");
2222 if (posEquals
!= string::npos
)
2223 result
.replace(0, posEquals
, expression
);
2225 SendEditorString(SCI_CALLTIPSHOW
, textPos
, result
.c_str());
2226 SendEditor(SCI_CALLTIPSETHLT
, 0, result
.length());
2229 void AnEditor::EndDebugEval() {
2232 SendEditor(SCI_CALLTIPCANCEL
);
2237 void AnEditor::HandleDwellStart(int mousePos
) {
2244 if (!debugger_is_active() || !debugger_is_ready())
2246 // Do not show expression tip if it can't be shown.
2247 // string s = string(expr) + ": " + _("debugger not active");
2248 // SendEditorString(SCI_CALLTIPSHOW, mousePos, s.c_str());
2252 // If debug tip is already running, return.
2256 CharacterRange crange
= GetSelection();
2257 if (crange
.cpMin
== crange
.cpMax
2258 || mousePos
< crange
.cpMin
2259 || mousePos
>= crange
.cpMax
)
2261 // There is no selection, or the mouse pointer is
2262 // out of the selection, so we search for a word
2263 // around the mouse pointer:
2264 if (!GetWordAtPosition(expr
, sizeof(expr
), mousePos
))
2269 long lensel
= crange
.cpMax
- crange
.cpMin
;
2270 long max
= sizeof(expr
) - 1;
2271 guint end
= (lensel
< max
? crange
.cpMax
: crange
.cpMin
+ max
);
2272 GetRange(crange
.cpMin
, end
, expr
, false);
2274 // If there is any control character except TAB
2275 // in the expression, disregard it.
2277 for (i
= 0; i
< end
- crange
.cpMin
; i
++)
2278 if ((unsigned char) expr
[i
] < ' ' && expr
[i
] != '\t')
2280 if (i
< end
- crange
.cpMin
)
2284 // Imitation of on_eval_ok_clicked():
2285 // The function eval_output_arrived_for_aneditor() will
2286 // be called eventually by the debugger with the result
2287 // of the print command for 'expr', and with the 'info'
2288 // pointer. That function must call delete on 'info'.
2290 // We don't turn GDB "pretty printing" on because we want
2291 // the entire value on a single line, in the case of a
2293 // We don't want static members of classes to clutter up
2294 // the displayed tip, however.
2298 ExpressionEvaluationTipInfo
*info
=
2299 new ExpressionEvaluationTipInfo(this, mousePos
, expr
);
2300 debugger_query_evaluate_expr_tip (expr
, eval_output_arrived_for_aneditor
, info
);
2301 debugger_query_execute ();
2307 int AnEditor::KeyPress(unsigned int state
, unsigned int keyval
){
2309 unsigned int mask
= GDK_SHIFT_MASK
| GDK_LOCK_MASK
|
2310 GDK_CONTROL_MASK
| GDK_MOD1_MASK
| GDK_MOD3_MASK
|
2311 GDK_MOD4_MASK
| GDK_MOD5_MASK
;
2315 // Trap 'TAB' key for automatic indentation.
2316 // printf ("Key is '%c'\n", notification->ch);
2317 if ((keyval
== GDK_Tab
) &&
2318 (lexLanguage
== SCLEX_CPP
) &&
2319 (!indentMaintain
) &&
2320 (props
->GetInt("indent.automatic")) &&
2321 (!SendEditor(SCI_CALLTIPACTIVE
)) &&
2322 (!SendEditor(SCI_AUTOCACTIVE
))) {
2324 CharacterRange crange
= GetSelection();
2325 int selStart
= crange
.cpMin
;
2326 int selEnd
= crange
.cpMax
;
2328 if (selStart
== selEnd
) {
2329 AutomaticIndentation('\t');
2337 void AnEditor::Notify(SCNotification
*notification
) {
2338 switch (notification
->nmhdr
.code
) {
2339 case SCN_CALLTIPCLICK
:
2340 if (notification
->position
== 1) {
2341 call_tip_node
.def_index
--;
2342 if (call_tip_node
.def_index
< 0)
2343 call_tip_node
.def_index
= 0;
2345 if (notification
->position
== 2) {
2346 call_tip_node
.def_index
++;
2347 if (call_tip_node
.def_index
>= call_tip_node
.max_def
)
2348 call_tip_node
.def_index
= call_tip_node
.max_def
- 1;
2350 ResumeCallTip (false);
2353 if(!accelGroup
) break;
2355 if (notification
->modifiers
& SCMOD_SHIFT
)
2356 mods
|= GDK_SHIFT_MASK
;
2357 if (notification
->modifiers
& SCMOD_CTRL
)
2358 mods
|= GDK_CONTROL_MASK
;
2359 if (notification
->modifiers
& SCMOD_ALT
)
2360 mods
|= GDK_MOD1_MASK
;
2361 gtk_accel_groups_activate(G_OBJECT (accelGroup
), notification
->ch
,
2362 static_cast<GdkModifierType
>(mods
));
2366 CharAdded(static_cast<char>(notification
->ch
));
2369 case SCN_SAVEPOINTREACHED
:
2373 case SCN_SAVEPOINTLEFT
:
2379 int pos
= SendEditor(SCI_GETCURRENTPOS
);
2381 if (SendEditor(SCI_CALLTIPACTIVE
) ) {
2382 // if we have a caret movement on left or right
2383 if (abs(pos
- lastPos
) == 1 ) {
2384 ContinueCallTip_new();
2392 if (notification
->modificationType
== SC_MOD_CHANGEFOLD
) {
2393 FoldChanged(notification
->line
,
2394 notification
->foldLevelNow
, notification
->foldLevelPrev
);
2398 case SCN_MARGINCLICK
:
2399 if (notification
->margin
== 2)
2400 MarginClick(notification
->position
, notification
->modifiers
);
2403 case SCN_NEEDSHOWN
: {
2404 EnsureRangeVisible(notification
->position
, notification
->position
+ notification
->length
);
2408 case SCN_DWELLSTART
:
2409 HandleDwellStart(notification
->position
);
2414 // SendEditor(SCI_CALLTIPCANCEL);
2420 static int IntFromHexDigit(const char ch
) {
2423 else if (ch
>= 'A' && ch
<= 'F')
2424 return ch
- 'A' + 10;
2425 else if (ch
>= 'a' && ch
<= 'f')
2426 return ch
- 'a' + 10;
2431 static Colour
ColourFromString(const char *val
) {
2432 int r
= IntFromHexDigit(val
[1]) * 16 + IntFromHexDigit(val
[2]);
2433 int g
= IntFromHexDigit(val
[3]) * 16 + IntFromHexDigit(val
[4]);
2434 int b
= IntFromHexDigit(val
[5]) * 16 + IntFromHexDigit(val
[6]);
2435 return Colour(r
, g
, b
);
2438 static long ColourOfProperty(PropSet
*props
, const char *key
, ColourDesired colourDefault
) {
2439 SString colour
= props
->Get(key
);
2440 if (colour
.length()) {
2441 return ColourFromString(colour
.c_str()).AsLong();
2443 return colourDefault
.AsLong();
2446 void AnEditor::SetOneStyle(Window
&win
, int style
, const char *s
) {
2447 char *val
= StringDup(s
);
2450 char *cpComma
= strchr(opt
, ',');
2453 char *colon
= strchr(opt
, ':');
2456 if (0 == strcmp(opt
, "italics"))
2457 Platform::SendScintilla(win
.GetID(), SCI_STYLESETITALIC
, style
, 1);
2458 if (0 == strcmp(opt
, "notitalics"))
2459 Platform::SendScintilla(win
.GetID(), SCI_STYLESETITALIC
, style
, 0);
2460 if (0 == strcmp(opt
, "bold"))
2461 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBOLD
, style
, 1);
2462 if (0 == strcmp(opt
, "notbold"))
2463 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBOLD
, style
, 0);
2464 if (0 == strcmp(opt
, "font"))
2465 Platform::SendScintilla(win
.GetID(), SCI_STYLESETFONT
, style
, reinterpret_cast<long>(colon
));
2466 if (0 == strcmp(opt
, "fore"))
2467 Platform::SendScintilla(win
.GetID(), SCI_STYLESETFORE
, style
, ColourFromString(colon
).AsLong());
2468 if (0 == strcmp(opt
, "back"))
2469 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBACK
, style
, ColourFromString(colon
).AsLong());
2470 if (0 == strcmp(opt
, "size"))
2471 Platform::SendScintilla(win
.GetID(), SCI_STYLESETSIZE
, style
, atoi(colon
));
2472 if (0 == strcmp(opt
, "eolfilled"))
2473 Platform::SendScintilla(win
.GetID(), SCI_STYLESETEOLFILLED
, style
, 1);
2474 if (0 == strcmp(opt
, "noteolfilled"))
2475 Platform::SendScintilla(win
.GetID(), SCI_STYLESETEOLFILLED
, style
, 0);
2476 if (0 == strcmp(opt
, "underlined"))
2477 Platform::SendScintilla(win
.GetID(), SCI_STYLESETUNDERLINE
, style
, 1);
2478 if (0 == strcmp(opt
, "notunderlined"))
2479 Platform::SendScintilla(win
.GetID(), SCI_STYLESETUNDERLINE
, style
, 0);
2480 if (0 == strcmp(opt
, "case")) {
2481 if (*colon
== 'u') {
2482 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCASE
, style
, SC_CASE_UPPER
);
2483 } else if (*colon
== 'l') {
2484 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCASE
, style
, SC_CASE_LOWER
);
2486 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCASE
, style
, SC_CASE_MIXED
);
2489 if (0 == strcmp(opt
, "visible"))
2490 Platform::SendScintilla(win
.GetID(), SCI_STYLESETVISIBLE
, style
, 1);
2491 if (0 == strcmp(opt
, "notvisible"))
2492 Platform::SendScintilla(win
.GetID(), SCI_STYLESETVISIBLE
, style
, 0);
2493 if (0 == strcmp(opt
, "changeable"))
2494 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCHANGEABLE
, style
, 1);
2495 if (0 == strcmp(opt
, "notchangeable"))
2496 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCHANGEABLE
, style
, 0);
2504 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCHARACTERSET
, style
, characterSet
);
2507 void AnEditor::SetStyleFor(Window
&win
, const char *lang
) {
2508 for (int style
= 0; style
<= STYLE_MAX
; style
++) {
2509 if (style
!= STYLE_DEFAULT
) {
2511 sprintf(key
, "style.%s.%0d", lang
, style
);
2512 SString sval
= props
->GetExpanded(key
);
2513 // g_print ("Style for %s:%0d == %s\n", lang, style, sval.c_str());
2514 SetOneStyle(win
, style
, sval
.c_str());
2519 void lowerCaseString(char *s
) {
2521 *s
= static_cast<char>(tolower(*s
));
2526 SString
AnEditor::ExtensionFileName() {
2527 if (overrideExtension
.length())
2528 return overrideExtension
;
2529 else if (fileName
[0]) {
2530 // Force extension to lower case
2531 char fileNameWithLowerCaseExtension
[MAX_PATH
];
2532 strcpy(fileNameWithLowerCaseExtension
, fileName
);
2533 char *extension
= strrchr(fileNameWithLowerCaseExtension
, '.');
2535 lowerCaseString(extension
);
2537 return SString(fileNameWithLowerCaseExtension
);
2539 return props
->Get("default.file.ext");
2542 void AnEditor::ForwardPropertyToEditor(const char *key
) {
2543 SString value
= props
->Get(key
);
2544 SendEditorString(SCI_SETPROPERTY
,
2545 reinterpret_cast<uptr_t
>(key
), value
.c_str());
2548 SString
AnEditor::FindLanguageProperty(const char *pattern
, const char *defaultValue
) {
2549 SString key
= pattern
;
2550 key
.substitute("*", language
.c_str());
2551 SString ret
= props
->GetExpanded(key
.c_str());
2553 ret
= props
->GetExpanded(pattern
);
2559 void AnEditor::ReadProperties(const char *fileForExt
) {
2560 //DWORD dwStart = timeGetTime();
2562 strcpy (fileName
, fileForExt
);
2566 SString fileNameForExtension
;
2567 if(overrideExtension
.length())
2568 fileNameForExtension
= overrideExtension
;
2570 fileNameForExtension
= fileForExt
;
2573 language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
2574 SendEditorString(SCI_SETLEXERLANGUAGE
, 0, language
.c_str());
2575 lexLanguage
= SendEditor(SCI_GETLEXER
);
2577 if ((lexLanguage
== SCLEX_HTML
) || (lexLanguage
== SCLEX_XML
))
2578 SendEditor(SCI_SETSTYLEBITS
, 7);
2580 SendEditor(SCI_SETSTYLEBITS
, 5);
2582 SendEditor(SCI_SETLEXER
, lexLanguage
);
2584 SString kw0
= props
->GetNewExpand("keywords.", fileNameForExtension
.c_str());
2585 SendEditorString(SCI_SETKEYWORDS
, 0, kw0
.c_str());
2586 SString kw2
= props
->GetNewExpand("keywords3.", fileNameForExtension
.c_str());
2587 SendEditorString(SCI_SETKEYWORDS
, 2, kw2
.c_str());
2588 /* For C/C++ projects, get list of typedefs for colorizing */
2589 if (SCLEX_CPP
== lexLanguage
)
2591 const TMWorkspace
*workspace
= tm_get_workspace();
2593 /* Assign global keywords */
2594 if ((workspace
) && (workspace
->global_tags
))
2596 GPtrArray
*g_typedefs
= tm_tags_extract(workspace
->global_tags
2597 , tm_tag_typedef_t
| tm_tag_struct_t
| tm_tag_class_t
);
2598 if ((g_typedefs
) && (g_typedefs
->len
> 0))
2600 GString
*s
= g_string_sized_new(g_typedefs
->len
* 10);
2601 for (guint i
= 0; i
< g_typedefs
->len
; ++i
)
2603 if (!(TM_TAG(g_typedefs
->pdata
[i
])->atts
.entry
.scope
))
2605 g_string_append(s
, TM_TAG(g_typedefs
->pdata
[i
])->name
);
2606 g_string_append_c(s
, ' ');
2609 SendEditorString(SCI_SETKEYWORDS
, 3, s
->str
);
2610 g_string_free(s
, TRUE
);
2612 g_ptr_array_free(g_typedefs
, TRUE
);
2615 /* Assign project keywords */
2616 if ((workspace
) && (workspace
->work_object
.tags_array
))
2618 GPtrArray
*typedefs
= tm_tags_extract(workspace
->work_object
.tags_array
2619 , tm_tag_typedef_t
| tm_tag_struct_t
| tm_tag_class_t
);
2620 if ((typedefs
) && (typedefs
->len
> 0))
2622 GString
*s
= g_string_sized_new(typedefs
->len
* 10);
2623 for (guint i
= 0; i
< typedefs
->len
; ++i
)
2625 if (!(TM_TAG(typedefs
->pdata
[i
])->atts
.entry
.scope
))
2627 if (TM_TAG(typedefs
->pdata
[i
])->name
)
2629 g_string_append(s
, TM_TAG(typedefs
->pdata
[i
])->name
);
2630 g_string_append_c(s
, ' ');
2634 SendEditorString(SCI_SETKEYWORDS
, 1, s
->str
);
2635 g_string_free(s
, TRUE
);
2637 g_ptr_array_free(typedefs
, TRUE
);
2642 SString kw1
= props
->GetNewExpand("keywords2.", fileNameForExtension
.c_str());
2643 SendEditorString(SCI_SETKEYWORDS
, 1, kw1
.c_str());
2644 SString kw3
= props
->GetNewExpand("keywords4.", fileNameForExtension
.c_str());
2645 SendEditorString(SCI_SETKEYWORDS
, 3, kw3
.c_str());
2646 SString kw4
= props
->GetNewExpand("keywords5.", fileNameForExtension
.c_str());
2647 SendEditorString(SCI_SETKEYWORDS
, 4, kw4
.c_str());
2648 SString kw5
= props
->GetNewExpand("keywords6.", fileNameForExtension
.c_str());
2649 SendEditorString(SCI_SETKEYWORDS
, 5, kw5
.c_str());
2652 ForwardPropertyToEditor("fold");
2653 ForwardPropertyToEditor("fold.use.plus");
2654 ForwardPropertyToEditor("fold.comment");
2655 ForwardPropertyToEditor("fold.comment.python");
2656 ForwardPropertyToEditor("fold.compact");
2657 ForwardPropertyToEditor("fold.html");
2658 ForwardPropertyToEditor("fold.preprocessor");
2659 ForwardPropertyToEditor("fold.quotes.python");
2660 ForwardPropertyToEditor("styling.within.preprocessor");
2661 ForwardPropertyToEditor("tab.timmy.whinge.level");
2662 ForwardPropertyToEditor("asp.default.language");
2664 // codePage = props->GetInt("code.page");
2665 //if (unicodeMode != uni8Bit) {
2666 // Override properties file to ensure Unicode displayed.
2667 // codePage = SC_CP_UTF8;
2669 // SendEditor(SCI_SETCODEPAGE, codePage);
2671 // Use unicode everytime.
2672 SendEditor(SCI_SETCODEPAGE
, SC_CP_UTF8
);
2674 characterSet
= props
->GetInt("character.set");
2675 setlocale(LC_CTYPE
, props
->Get("LC_CTYPE").c_str());
2677 SendEditor(SCI_SETCARETFORE
,
2678 ColourOfProperty(props
, "caret.fore", ColourDesired(0, 0, 0)));
2679 SendEditor(SCI_SETCARETWIDTH
, props
->GetInt("caret.width", 1));
2680 SendEditor(SCI_SETMOUSEDWELLTIME
, props
->GetInt("dwell.period", 750), 0);
2682 SString caretLineBack
= props
->Get("caret.line.back");
2683 if (caretLineBack
.length()) {
2684 SendEditor(SCI_SETCARETLINEVISIBLE
, 1);
2685 SendEditor(SCI_SETCARETLINEBACK
,
2686 ColourFromString(caretLineBack
.c_str()).AsLong());
2688 SendEditor(SCI_SETCARETLINEVISIBLE
, 0);
2691 SString controlCharSymbol
= props
->Get("control.char.symbol");
2692 if (controlCharSymbol
.length()) {
2693 SendEditor(SCI_SETCONTROLCHARSYMBOL
, static_cast<unsigned char>(controlCharSymbol
[0]));
2695 SendEditor(SCI_SETCONTROLCHARSYMBOL
, 0);
2698 SendEditor(SCI_CALLTIPSETBACK
,
2699 ColourOfProperty(props
, "calltip.back", ColourDesired(0xff, 0xff, 0xff)));
2701 SString caretPeriod
= props
->Get("caret.period");
2702 if (caretPeriod
.length()) {
2703 SendEditor(SCI_SETCARETPERIOD
, caretPeriod
.value());
2706 int caretSlop
= props
->GetInt("caret.policy.xslop", 1) ? CARET_SLOP
: 0;
2707 int caretZone
= props
->GetInt("caret.policy.width", 50);
2708 int caretStrict
= props
->GetInt("caret.policy.xstrict") ? CARET_STRICT
: 0;
2709 int caretEven
= props
->GetInt("caret.policy.xeven", 1) ? CARET_EVEN
: 0;
2710 int caretJumps
= props
->GetInt("caret.policy.xjumps") ? CARET_JUMPS
: 0;
2711 SendEditor(SCI_SETXCARETPOLICY
, caretStrict
| caretSlop
| caretEven
| caretJumps
, caretZone
);
2713 caretSlop
= props
->GetInt("caret.policy.yslop", 1) ? CARET_SLOP
: 0;
2714 caretZone
= props
->GetInt("caret.policy.lines");
2715 caretStrict
= props
->GetInt("caret.policy.ystrict") ? CARET_STRICT
: 0;
2716 caretEven
= props
->GetInt("caret.policy.yeven", 1) ? CARET_EVEN
: 0;
2717 caretJumps
= props
->GetInt("caret.policy.yjumps") ? CARET_JUMPS
: 0;
2718 SendEditor(SCI_SETYCARETPOLICY
, caretStrict
| caretSlop
| caretEven
| caretJumps
, caretZone
);
2720 int visibleStrict
= props
->GetInt("visible.policy.strict") ? VISIBLE_STRICT
: 0;
2721 int visibleSlop
= props
->GetInt("visible.policy.slop", 1) ? VISIBLE_SLOP
: 0;
2722 int visibleLines
= props
->GetInt("visible.policy.lines");
2723 SendEditor(SCI_SETVISIBLEPOLICY
, visibleStrict
| visibleSlop
, visibleLines
);
2725 SendEditor(SCI_SETEDGECOLUMN
, props
->GetInt("edge.column", 0));
2726 SendEditor(SCI_SETEDGEMODE
, props
->GetInt("edge.mode", EDGE_NONE
));
2727 SendEditor(SCI_SETEDGECOLOUR
,
2728 ColourOfProperty(props
, "edge.colour", ColourDesired(0xff, 0xda, 0xda)));
2730 SString selfore
= props
->Get("selection.fore");
2731 if (selfore
.length()) {
2732 SendEditor(SCI_SETSELFORE
, 1, ColourFromString(selfore
.c_str()).AsLong());
2734 SendEditor(SCI_SETSELFORE
, 0, 0);
2736 SString selBack
= props
->Get("selection.back");
2737 if (selBack
.length()) {
2738 SendEditor(SCI_SETSELBACK
, 1, ColourFromString(selBack
.c_str()).AsLong());
2740 if (selfore
.length())
2741 SendEditor(SCI_SETSELBACK
, 0, 0);
2742 else // Have to show selection somehow
2743 SendEditor(SCI_SETSELBACK
, 1, ColourDesired(0xC0, 0xC0, 0xC0).AsLong());
2746 SString whitespaceFore
= props
->Get("whitespace.fore");
2747 if (whitespaceFore
.length()) {
2748 SendEditor(SCI_SETWHITESPACEFORE
, 1, ColourFromString(whitespaceFore
.c_str()).AsLong());
2750 SendEditor(SCI_SETWHITESPACEFORE
, 0, 0);
2752 SString whitespaceBack
= props
->Get("whitespace.back");
2753 if (whitespaceBack
.length()) {
2754 SendEditor(SCI_SETWHITESPACEBACK
, 1, ColourFromString(whitespaceBack
.c_str()).AsLong());
2756 SendEditor(SCI_SETWHITESPACEBACK
, 0, 0);
2759 for (int i
= 0; i
< 3; i
++) {
2762 long default_indic_type
[] = {INDIC_TT
, INDIC_DIAGONAL
, INDIC_SQUIGGLE
};
2763 char *default_indic_color
[] = {"0000FF", "#00FF00", "#FF0000"};
2764 char *style_name
[] = {"normal", "warning", "error"};
2766 sprintf(key
, "indicators.style.%s", style_name
[i
]);
2768 value_str
= props
->Get(key
);
2769 if (value_str
.length() > 0) {
2770 if (strcasecmp (value_str
.c_str(), "underline-plain") == 0) {
2771 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_PLAIN
);
2772 } else if (strcasecmp (value_str
.c_str(), "underline-tt") == 0) {
2773 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_TT
);
2774 } else if (strcasecmp (value_str
.c_str(), "underline-squiggle") == 0) {
2775 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_SQUIGGLE
);
2776 } else if (strcasecmp (value_str
.c_str(), "strike-out") == 0) {
2777 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_STRIKE
);
2778 } else if (strcasecmp (value_str
.c_str(), "diagonal") == 0) {
2779 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_DIAGONAL
);
2781 SendEditor(SCI_INDICSETSTYLE
, i
, default_indic_type
[i
]);
2784 SendEditor(SCI_INDICSETSTYLE
, i
, default_indic_type
[i
]);
2786 sprintf(key
, "indicator.%d.color", i
);
2787 value_str
= props
->GetExpanded(key
);
2788 if (value_str
.length()) {
2789 SendEditor(SCI_INDICSETFORE
, i
, ColourFromString(value_str
.c_str()).AsLong());
2791 SendEditor(SCI_INDICSETFORE
, i
, ColourFromString(default_indic_color
[i
]).AsLong());
2795 char bracesStyleKey
[200];
2796 sprintf(bracesStyleKey
, "braces.%s.style", language
.c_str());
2797 bracesStyle
= props
->GetInt(bracesStyleKey
, 0);
2802 sval
= FindLanguageProperty("calltip.*.ignorecase");
2803 callTipIgnoreCase
= sval
== "1";
2805 calltipWordCharacters
= FindLanguageProperty("calltip.*.word.characters",
2806 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
2808 calltipEndDefinition
= FindLanguageProperty("calltip.*.end.definition");
2810 sprintf(key
, "autocomplete.%s.start.characters", language
.c_str());
2811 autoCompleteStartCharacters
= props
->GetExpanded(key
);
2812 if (autoCompleteStartCharacters
== "")
2813 autoCompleteStartCharacters
= props
->GetExpanded("autocomplete.*.start.characters");
2814 // "" is a quite reasonable value for this setting
2816 sprintf(key
, "autocomplete.%s.fillups", language
.c_str());
2817 autoCompleteFillUpCharacters
= props
->GetExpanded(key
);
2818 if (autoCompleteFillUpCharacters
== "")
2819 autoCompleteFillUpCharacters
=
2820 props
->GetExpanded("autocomplete.*.fillups");
2821 SendEditorString(SCI_AUTOCSETFILLUPS
, 0,
2822 autoCompleteFillUpCharacters
.c_str());
2824 sprintf(key
, "autocomplete.%s.ignorecase", "*");
2825 sval
= props
->GetNewExpand(key
, "");
2826 autoCompleteIgnoreCase
= sval
== "1";
2827 sprintf(key
, "autocomplete.%s.ignorecase", language
.c_str());
2828 sval
= props
->GetNewExpand(key
, "");
2830 autoCompleteIgnoreCase
= sval
== "1";
2831 SendEditor(SCI_AUTOCSETIGNORECASE
, autoCompleteIgnoreCase
? 1 : 0);
2833 int autoCChooseSingle
= props
->GetInt("autocomplete.choose.single");
2834 SendEditor(SCI_AUTOCSETCHOOSESINGLE
, autoCChooseSingle
),
2836 SendEditor(SCI_AUTOCSETCANCELATSTART
, 0),
2837 SendEditor(SCI_AUTOCSETDROPRESTOFWORD
, 0),
2840 // For each window set the global default style,
2841 // then the language default style,
2842 // then the other global styles,
2843 // then the other language styles
2845 SendEditor(SCI_STYLERESETDEFAULT
, 0, 0);
2847 sprintf(key
, "style.%s.%0d", "*", STYLE_DEFAULT
);
2848 sval
= props
->GetNewExpand(key
, "");
2849 SetOneStyle(wEditor
, STYLE_DEFAULT
, sval
.c_str());
2851 sprintf(key
, "style.%s.%0d", language
.c_str(), STYLE_DEFAULT
);
2852 sval
= props
->GetNewExpand(key
, "");
2853 SetOneStyle(wEditor
, STYLE_DEFAULT
, sval
.c_str());
2855 SendEditor(SCI_STYLECLEARALL
, 0, 0);
2857 SetStyleFor(wEditor
, "*");
2858 SetStyleFor(wEditor
, language
.c_str());
2860 if (firstPropertiesRead
) {
2861 ReadPropertiesInitial();
2864 /* Gtk handles it correctly */
2865 SendEditor(SCI_SETUSEPALETTE
, 0);
2867 SendEditor(SCI_SETPRINTMAGNIFICATION
, props
->GetInt("print.magnification"));
2868 SendEditor(SCI_SETPRINTCOLOURMODE
, props
->GetInt("print.colour.mode"));
2870 int blankMarginLeft
= props
->GetInt("blank.margin.left", 1);
2871 int blankMarginRight
= props
->GetInt("blank.margin.right", 1);
2872 SendEditor(SCI_SETMARGINLEFT
, 0, blankMarginLeft
);
2873 SendEditor(SCI_SETMARGINRIGHT
, 0, blankMarginRight
);
2875 SendEditor(SCI_SETMARGINWIDTHN
, 1, margin
? marginWidth
: 0);
2876 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
?lineNumbersWidth
: 0);
2878 bufferedDraw
= props
->GetInt("buffered.draw", 1);
2879 SendEditor(SCI_SETBUFFEREDDRAW
, bufferedDraw
);
2881 SendEditor(SCI_SETLAYOUTCACHE
, props
->GetInt("cache.layout"));
2883 bracesCheck
= props
->GetInt("braces.check");
2884 bracesSloppy
= props
->GetInt("braces.sloppy");
2886 wordCharacters
= props
->GetNewExpand("word.characters.", fileNameForExtension
.c_str());
2887 if (wordCharacters
.length()) {
2888 SendEditorString(SCI_SETWORDCHARS
, 0, wordCharacters
.c_str());
2890 SendEditor(SCI_SETWORDCHARS
, 0, 0);
2891 wordCharacters
= "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2894 // SendEditor(SCI_MARKERDELETEALL, static_cast<unsigned long>( -1));
2896 SendEditor(SCI_SETTABINDENTS
, props
->GetInt("tab.indents", 1));
2897 SendEditor(SCI_SETBACKSPACEUNINDENTS
, props
->GetInt("backspace.unindents", 1));
2899 SendEditor(SCI_SETUSETABS
, props
->GetInt("use.tabs", 1));
2900 int tabSize
= props
->GetInt("tabsize");
2902 SendEditor(SCI_SETTABWIDTH
, tabSize
);
2904 indentSize
= props
->GetInt("indent.size");
2905 SendEditor(SCI_SETINDENT
, indentSize
);
2907 indentOpening = props->GetInt("indent.opening");
2908 indentClosing = props->GetInt("indent.closing");
2910 indentMaintain
= props
->GetNewExpand("indent.maintain.", fileNameForExtension
.c_str()).value();
2912 SString lookback = props->GetNewExpand("statement.lookback.", fileNameForExtension.c_str());
2913 statementLookback = lookback.value();
2914 statementIndent = GetStyleAndWords("statement.indent.");
2915 statementEnd =GetStyleAndWords("statement.end.");
2916 blockStart = GetStyleAndWords("block.start.");
2917 blockEnd = GetStyleAndWords("block.end.");
2922 list = props->GetNewExpand("preprocessor.symbol.", fileNameForExtension.c_str());
2923 preprocessorSymbol = list[0];
2924 list = props->GetNewExpand("preprocessor.start.", fileNameForExtension.c_str());
2925 preprocCondStart.Clear();
2926 preprocCondStart.Set(list.c_str());
2927 list = props->GetNewExpand("preprocessor.middle.", fileNameForExtension.c_str());
2928 preprocCondMiddle.Clear();
2929 preprocCondMiddle.Set(list.c_str());
2930 list = props->GetNewExpand("preprocessor.end.", fileNameForExtension.c_str());
2931 preprocCondEnd.Clear();
2932 preprocCondEnd.Set(list.c_str());
2935 if (props
->GetInt("vc.home.key", 1)) {
2936 AssignKey(SCK_HOME
, 0, SCI_VCHOME
);
2937 AssignKey(SCK_HOME
, SCMOD_SHIFT
, SCI_VCHOMEEXTEND
);
2939 AssignKey(SCK_HOME
, 0, SCI_HOME
);
2940 AssignKey(SCK_HOME
, SCMOD_SHIFT
, SCI_HOMEEXTEND
);
2942 if (props
->GetInt("fold.underline"))
2943 SendEditor(SCI_SETFOLDFLAGS
, props
->GetInt("fold.flags"));
2945 SendEditor(SCI_SETFOLDFLAGS
, 0);
2947 // To put the folder markers in the line number region
2948 //SendEditor(SCI_SETMARGINMASKN, 0, SC_MASK_FOLDERS);
2950 SendEditor(SCI_SETMODEVENTMASK
, SC_MOD_CHANGEFOLD
);
2952 if (0==props
->GetInt("undo.redo.lazy")) {
2953 // Trap for insert/delete notifications (also fired by undo
2954 // and redo) so that the buttons can be enabled if needed.
2955 SendEditor(SCI_SETMODEVENTMASK
, SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
2956 | SC_LASTSTEPINUNDOREDO
| SendEditor(SCI_GETMODEVENTMASK
, 0));
2958 //SC_LASTSTEPINUNDOREDO is probably not needed in the mask; it
2959 //doesn't seem to fire as an event of its own; just modifies the
2960 //insert and delete events.
2963 // Create a margin column for the folding symbols
2964 SendEditor(SCI_SETMARGINTYPEN
, 2, SC_MARGIN_SYMBOL
);
2966 SendEditor(SCI_SETMARGINWIDTHN
, 2, foldMargin
? foldMarginWidth
: 0);
2968 SendEditor(SCI_SETMARGINMASKN
, 2, SC_MASK_FOLDERS
);
2969 SendEditor(SCI_SETMARGINSENSITIVEN
, 1, 1); // Breakpoints-Bookmarks
2970 SendEditor(SCI_SETMARGINSENSITIVEN
, 2, 1);
2972 SString fold_symbols
= props
->Get("fold.symbols");
2973 SetFoldSymbols (fold_symbols
);
2975 // Well, unlike scite, we want it everytime.
2976 firstPropertiesRead
= true;
2979 void AnEditor::SetFoldSymbols(SString fold_symbols
)
2981 if (fold_symbols
.length() <= 0)
2982 fold_symbols
= "plus/minus";
2983 if (strcasecmp(fold_symbols
.c_str(), "arrows") == 0)
2985 // Arrow pointing right for contracted folders, arrow pointing down for expanded
2986 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_ARROWDOWN
, Colour(0, 0, 0), Colour(0, 0, 0));
2987 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_ARROW
, Colour(0, 0, 0), Colour(0, 0, 0));
2988 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_EMPTY
, Colour(0, 0, 0), Colour(0, 0, 0));
2989 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_EMPTY
, Colour(0, 0, 0), Colour(0, 0, 0));
2990 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2991 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2992 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2993 } else if (strcasecmp(fold_symbols
.c_str(), "circular") == 0) {
2994 // Like a flattened tree control using circular headers and curved joins
2995 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_CIRCLEMINUS
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2996 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_CIRCLEPLUS
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2997 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_VLINE
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2998 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_LCORNERCURVE
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2999 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_CIRCLEPLUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
3000 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_CIRCLEMINUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
3001 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_TCORNERCURVE
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
3002 } else if (strcasecmp(fold_symbols
.c_str(), "squares") == 0) {
3003 // Like a flattened tree control using square headers
3004 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_BOXMINUS
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3005 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_BOXPLUS
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3006 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_VLINE
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3007 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_LCORNER
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3008 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_BOXPLUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3009 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_BOXMINUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3010 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_TCORNER
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
3012 // Plus for contracted folders, minus for expanded
3013 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_MINUS
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3014 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_PLUS
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3015 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3016 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3017 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3018 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3019 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
3023 // Anjuta: In our case, we read it everytime
3024 void AnEditor::ReadPropertiesInitial() {
3025 indentationWSVisible
= props
->GetInt("view.indentation.whitespace", 1);
3026 ViewWhitespace(props
->GetInt("view.whitespace"));
3027 SendEditor(SCI_SETINDENTATIONGUIDES
, props
->GetInt("view.indentation.guides"));
3028 SendEditor(SCI_SETVIEWEOL
, props
->GetInt("view.eol"));
3030 SetReadOnly(props
->GetInt("file.readonly", 0));
3031 SetLineWrap(props
->GetInt("view.line.wrap", 1));
3033 //lineNumbersWidth = 0;
3034 /* FIXME: This is nowhere configureable
3035 SString linenums = props->Get("margin.linenumber.width");
3036 if (linenums.length())
3037 lineNumbersWidth = linenums.value(); */
3038 //lineNumbers = lineNumbersWidth;
3039 /* We do this dynamicly in text_editor_load_file now */
3040 /* if (lineNumbersWidth == 0)
3041 lineNumbersWidth = lineNumbersWidthDefault;*/
3044 SString margwidth
= props
->Get("margin.marker.width");
3045 if (margwidth
.length())
3046 marginWidth
= margwidth
.value();
3047 margin
= marginWidth
;
3048 if (marginWidth
== 0)
3049 marginWidth
= marginWidthDefault
;
3051 foldMarginWidth
= props
->GetInt("margin.fold.width", foldMarginWidthDefault
);
3052 foldMargin
= foldMarginWidth
;
3053 if (foldMarginWidth
== 0)
3054 foldMarginWidth
= foldMarginWidthDefault
;
3056 lineNumbers
= props
->GetInt("margin.linenumber.visible", 0);
3057 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
3058 margin
= props
->GetInt("margin.marker.visible", 0);
3059 SendEditor(SCI_SETMARGINWIDTHN
, 1, margin
? marginWidth
: 0);
3061 foldMargin
= props
->GetInt("margin.fold.visible", 1);
3062 SendEditor(SCI_SETMARGINWIDTHN
, 2, foldMargin
? foldMarginWidth
: 0);
3065 void AnEditor::DefineMarker(int marker
, int markerType
, Colour fore
, Colour back
)
3067 SendEditor(SCI_MARKERDEFINE
, marker
, markerType
);
3068 SendEditor(SCI_MARKERSETFORE
, marker
, fore
.AsLong());
3069 SendEditor(SCI_MARKERSETBACK
, marker
, back
.AsLong());
3072 int AnEditor::GetBookmarkLine( const int nLineStart
)
3074 int nNextLine
= SendEditor(SCI_MARKERNEXT
, nLineStart
+1, 1 << ANE_MARKER_BOOKMARK
);
3075 //printf( "...look %d --> %d\n", nLineStart, nNextLine );
3076 if ( (nNextLine
< 0) || (nNextLine
== nLineStart
) )
3082 void AnEditor::FocusInEvent(GtkWidget
* widget
)
3090 void AnEditor::FocusOutEvent(GtkWidget
* widget
)
3092 if (SendEditor(SCI_CALLTIPACTIVE
))
3094 SendEditor(SCI_CALLTIPCANCEL
);
3095 calltipShown
= true;
3099 calltipShown
= false;
3103 static GList
* editors
;
3106 aneditor_get(AnEditorID id
)
3109 if(id
>= g_list_length(editors
))
3111 DEBUG_PRINT("Invalid AnEditorID supplied");
3114 ed
= (AnEditor
*)g_list_nth_data(editors
, (guint
)id
);
3117 DEBUG_PRINT("Trying to use already destroyed AnEditor Object");
3124 aneditor_new(gpointer propset
)
3126 AnEditor
* ed
= new AnEditor((PropSetFile
*)propset
);
3129 DEBUG_PRINT("Memory allocation error.");
3130 return ANE_ID_INVALID
;
3132 g_signal_connect(ed
->GetID(), "focus_in_event",
3133 G_CALLBACK(on_aneditor_focus_in
), ed
);
3134 g_signal_connect(ed
->GetID(), "focus_out_event",
3135 G_CALLBACK(on_aneditor_focus_out
), ed
);
3136 editors
= g_list_append(editors
, ed
);
3137 return (AnEditorID
)(g_list_length(editors
) - 1);
3141 aneditor_destroy(AnEditorID id
)
3145 ed
= aneditor_get(id
);
3148 /* We will not remove the editor from the list */
3149 /* so that already assigned handles work properly */
3150 /* We'll simply make it NULL to indicate that the */
3151 /* editor is destroyed */
3152 g_list_nth(editors
, id
)->data
= NULL
;
3154 /* Disconnect the focus in/out signals */
3155 g_signal_handlers_disconnect_by_func (ed
->GetID(),
3156 (void*)G_CALLBACK(on_aneditor_focus_in
), ed
);
3157 g_signal_handlers_disconnect_by_func (ed
->GetID(),
3158 (void*)G_CALLBACK(on_aneditor_focus_out
), ed
);
3164 aneditor_get_widget(AnEditorID handle
)
3167 ed
= aneditor_get(handle
);
3168 if(!ed
) return NULL
;
3170 // Forced conversion is safe here, so do it.
3171 return (GtkWidget
*)ed
->GetID();
3175 aneditor_command(AnEditorID handle
, gint command
, glong wparam
, glong lparam
)
3178 ed
= aneditor_get(handle
);
3180 return ed
->Command(command
, wparam
, lparam
);
3184 aneditor_set_focused_ed_ID(AnEditorID id
)
3186 AnEditor::focusedID
= id
;
3190 aneditor_set_parent(AnEditorID id
, AnEditorID parent_id
)
3195 editor
= aneditor_get (id
);
3196 parent
= aneditor_get (parent_id
);
3197 editor
->SetParent(parent
);
3201 on_aneditor_focus_in (GtkWidget
* widget
, gpointer
* unused
, AnEditor
* ed
)
3203 ed
->FocusInEvent(widget
);
3208 on_aneditor_focus_out (GtkWidget
* widget
, gpointer
* unused
, AnEditor
* ed
)
3211 ed
->FocusOutEvent(widget
);