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';
547 GetRange (caretPos
- 1, caretPos
+ 1, buffer
, true);
548 charBefore
= buffer
[0];
549 styleBefore
= buffer
[1];
553 GetRange (caretPos
, caretPos
+ 1, buffer
+ 2, true);
556 // Priority goes to character before caret
557 if (charBefore
&& strchr("[](){}", charBefore
) &&
558 ((styleBefore
== bracesStyleCheck
) || (!bracesStyle
))) {
559 braceAtCaret
= caretPos
- 1;
561 bool colonMode
= false;
562 if (lexLanguage
== SCLEX_PYTHON
&& ':' == charBefore
) {
563 braceAtCaret
= caretPos
- 1;
567 if (sloppy
&& (braceAtCaret
< 0)) {
568 // No brace found so check other side
569 char charAfter
= buffer
[2];
570 char styleAfter
= buffer
[3] & 31;
571 if (charAfter
&& strchr("[](){}", charAfter
) && (styleAfter
== bracesStyleCheck
)) {
572 braceAtCaret
= caretPos
;
575 if (lexLanguage
== SCLEX_PYTHON
&& ':' == charAfter
) {
576 braceAtCaret
= caretPos
;
580 if (braceAtCaret
>= 0) {
582 int lineStart
= Platform::SendScintilla(win
.GetID(), SCI_LINEFROMPOSITION
, braceAtCaret
);
583 int lineMaxSubord
= Platform::SendScintilla(win
.GetID(), SCI_GETLASTCHILD
, lineStart
, -1);
584 braceOpposite
= Platform::SendScintilla(win
.GetID(), SCI_GETLINEENDPOSITION
, lineMaxSubord
);
586 braceOpposite
= Platform::SendScintilla(win
.GetID(), SCI_BRACEMATCH
, braceAtCaret
, 0);
588 if (braceOpposite
> braceAtCaret
) {
598 void AnEditor::BraceMatch(bool editor
) {
601 int braceAtCaret
= -1;
602 int braceOpposite
= -1;
603 FindMatchingBracePosition(editor
, braceAtCaret
, braceOpposite
, bracesSloppy
);
604 // Window &win = editor ? wEditor : wOutput;
605 Window
&win
= wEditor
;
606 if ((braceAtCaret
!= -1) && (braceOpposite
== -1)) {
607 Platform::SendScintilla(win
.GetID(), SCI_BRACEBADLIGHT
, braceAtCaret
, 0);
608 SendEditor(SCI_SETHIGHLIGHTGUIDE
, 0);
610 char chBrace
= static_cast<char>(Platform::SendScintilla(
611 win
.GetID(), SCI_GETCHARAT
, braceAtCaret
, 0));
612 Platform::SendScintilla(win
.GetID(), SCI_BRACEHIGHLIGHT
, braceAtCaret
, braceOpposite
);
613 int columnAtCaret
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, braceAtCaret
, 0);
614 int columnOpposite
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, braceOpposite
, 0);
615 if (chBrace
== ':') {
616 int lineStart
= Platform::SendScintilla(win
.GetID(), SCI_LINEFROMPOSITION
, braceAtCaret
);
617 int indentPos
= Platform::SendScintilla(win
.GetID(), SCI_GETLINEINDENTPOSITION
, lineStart
, 0);
618 int indentPosNext
= Platform::SendScintilla(win
.GetID(), SCI_GETLINEINDENTPOSITION
, lineStart
+ 1, 0);
619 columnAtCaret
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, indentPos
, 0);
620 int columnAtCaretNext
= Platform::SendScintilla(win
.GetID(), SCI_GETCOLUMN
, indentPosNext
, 0);
621 int indentationSize
= Platform::SendScintilla(win
.GetID(), SCI_GETINDENT
);
622 if (columnAtCaretNext
- indentationSize
> 1)
623 columnAtCaret
= columnAtCaretNext
- indentationSize
;
624 //Platform::DebugPrintf(": %d %d %d\n", lineStart, indentPos, columnAtCaret);
625 if (columnOpposite
== 0) // If the final line of the structure is empty
626 columnOpposite
= columnAtCaret
;
629 if (props
->GetInt("highlight.indentation.guides"))
630 Platform::SendScintilla(win
.GetID(), SCI_SETHIGHLIGHTGUIDE
, Platform::Minimum(columnAtCaret
, columnOpposite
), 0);
634 CharacterRange
AnEditor::GetSelection() {
635 CharacterRange crange
;
636 crange
.cpMin
= SendEditor(SCI_GETSELECTIONSTART
);
637 crange
.cpMax
= SendEditor(SCI_GETSELECTIONEND
);
641 void AnEditor::SetSelection(int anchor
, int currentPos
) {
642 SendEditor(SCI_SETSEL
, anchor
, currentPos
);
645 bool AnEditor::iswordcharforsel(char ch
) {
646 return !strchr("\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", ch
);
649 void AnEditor::WordSelect() {
650 int lengthDoc
= LengthDocument();
658 selStart
= selEnd
= SendEditor(SCI_GETCURRENTPOS
);
659 line
= SendEditor(SCI_LINEFROMPOSITION
, selStart
);
660 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
661 lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
663 buffer
= new char [lineEnd
- lineStart
+ 1];
664 GetRange(wEditor
, lineStart
, lineEnd
, buffer
);
666 if (iswordcharforsel(buffer
[selStart
- lineStart
])) {
667 while ((selStart
> lineStart
) && (iswordcharforsel(buffer
[selStart
- 1 - lineStart
])))
669 while ((selEnd
< lineEnd
- 1) && (iswordcharforsel(buffer
[selEnd
+ 1 + lineStart
])))
671 if (selStart
< selEnd
)
672 selEnd
++; // Because normal selections end one past
675 SetSelection(selStart
, selEnd
);
678 void AnEditor::LineSelect() {
679 int pos
= SendEditor(SCI_GETCURRENTPOS
);
680 int line
= SendEditor(SCI_LINEFROMPOSITION
, pos
);
681 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, line
);
682 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
684 SetSelection(lineStart
, lineEnd
);
687 long AnEditor::Find (long flags
, char* findWhat
) {
688 if (!findWhat
) return -1;
689 TextToFind ft
= {{0, 0}, 0, {0, 0}};
690 CharacterRange crange
= GetSelection();
691 if (flags
& ANEFIND_REVERSE_FLAG
) {
692 ft
.chrg
.cpMin
= crange
.cpMin
- 1;
695 ft
.chrg
.cpMin
= crange
.cpMax
;
696 ft
.chrg
.cpMax
= LengthDocument();
698 ft
.lpstrText
= findWhat
;
699 ft
.chrgText
.cpMin
= 0;
700 ft
.chrgText
.cpMax
= 0;
701 int posFind
= SendEditor(SCI_FINDTEXT
, flags
, reinterpret_cast<long>(&ft
));
703 EnsureRangeVisible(ft
.chrgText
.cpMin
, ft
.chrgText
.cpMax
);
704 SetSelection(ft
.chrgText
.cpMin
, ft
.chrgText
.cpMax
);
709 void AnEditor::BookmarkToggle( int lineno
) {
716 lineno
= GetCurrentLineNumber();
717 int state
= SendEditor(SCI_MARKERGET
, lineno
);
718 if ( state
& (1 << ANE_MARKER_BOOKMARK
))
719 SendEditor(SCI_MARKERDELETE
, lineno
, ANE_MARKER_BOOKMARK
);
721 SendEditor(SCI_MARKERADD
, lineno
, ANE_MARKER_BOOKMARK
);
725 void AnEditor::BookmarkFirst() {
726 int lineno
= GetCurrentLineNumber();
727 int nextLine
= SendEditor(SCI_MARKERNEXT
, 0, 1 << ANE_MARKER_BOOKMARK
);
728 if (nextLine
< 0 || nextLine
== lineno
)
729 gdk_beep(); // how do I beep? -- like this ;-)
731 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
732 SendEditor(SCI_GOTOLINE
, nextLine
);
736 void AnEditor::BookmarkPrev() {
737 int lineno
= GetCurrentLineNumber();
738 int nextLine
= SendEditor(SCI_MARKERPREVIOUS
, lineno
- 1, 1 << ANE_MARKER_BOOKMARK
);
739 if (nextLine
< 0 || nextLine
== lineno
) {
740 if(props
->GetInt("editor.wrapbookmarks")) {
741 int nrOfLines
= SendEditor(SCI_GETLINECOUNT
, 0, 1 << ANE_MARKER_BOOKMARK
);
742 int nextLine1
= SendEditor(SCI_MARKERPREVIOUS
, nrOfLines
, 1 << ANE_MARKER_BOOKMARK
);
743 if (nextLine1
< 0 || nextLine1
== lineno
) {
744 gdk_beep(); // how do I beep? -- like this ;-)
746 SendEditor(SCI_ENSUREVISIBLE
, nextLine1
);
747 SendEditor(SCI_GOTOLINE
, nextLine1
);
751 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
752 SendEditor(SCI_GOTOLINE
, nextLine
);
756 void AnEditor::BookmarkNext() {
757 int lineno
= GetCurrentLineNumber();
758 int nextLine
= SendEditor(SCI_MARKERNEXT
, lineno
+ 1, 1 << ANE_MARKER_BOOKMARK
);
759 if (nextLine
< 0 || nextLine
== lineno
) {
760 if(props
->GetInt("editor.wrapbookmarks")) {
761 int nextLine1
= SendEditor(SCI_MARKERNEXT
, 0, 1 << ANE_MARKER_BOOKMARK
);
762 if (nextLine1
< 0 || nextLine1
== lineno
) {
763 gdk_beep(); // how do I beep? -- like this ;-)
765 SendEditor(SCI_ENSUREVISIBLE
, nextLine1
);
766 SendEditor(SCI_GOTOLINE
, nextLine1
);
770 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
771 SendEditor(SCI_GOTOLINE
, nextLine
);
775 void AnEditor::BookmarkLast() {
776 int lineno
= GetCurrentLineNumber();
777 int nextLine
= SendEditor(SCI_MARKERPREVIOUS
,
778 SendEditor(SCI_GETLINECOUNT
), 1 << ANE_MARKER_BOOKMARK
);
779 if (nextLine
< 0 || nextLine
== lineno
)
780 gdk_beep(); // how do I beep? -- like this ;-)
782 SendEditor(SCI_ENSUREVISIBLE
, nextLine
);
783 SendEditor(SCI_GOTOLINE
, nextLine
);
787 void AnEditor::BookmarkClear() {
788 SendEditor(SCI_MARKERDELETEALL
, ANE_MARKER_BOOKMARK
);
791 bool AnEditor::GetCurrentWord(char* buffer
, int length
) {
794 int current
= GetCaretInLine();
795 return FindWordInRegion(buffer
, length
, linebuf
, current
);
798 bool AnEditor::StartBlockComment() {
799 SString fileNameForExtension
= ExtensionFileName();
800 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
801 SString
base("comment.block.");
802 SString
comment_at_line_start("comment.block.at.line.start.");
804 comment_at_line_start
+= language
;
805 SString comment
= props
->Get(base
.c_str());
806 if (comment
== "") { // user friendly error message box
807 //SString error("Block comment variable \"");
809 //error += "\" is not defined in SciTE *.properties!";
810 //WindowMessageBox(wEditor, error, MB_OK | MB_ICONWARNING);
814 SString long_comment
= comment
;
816 size_t comment_length
= comment
.length();
817 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
818 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
819 size_t caretPosition
= SendEditor(SCI_GETCURRENTPOS
);
820 // checking if caret is located in _beginning_ of selected block
821 bool move_caret
= caretPosition
< selectionEnd
;
822 int selStartLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
823 int selEndLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
824 int lines
= selEndLine
- selStartLine
;
825 size_t firstSelLineStart
= SendEditor(SCI_POSITIONFROMLINE
, selStartLine
);
826 // "caret return" is part of the last selected line
828 (selectionEnd
== static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE
, selEndLine
))))
830 SendEditor(SCI_BEGINUNDOACTION
);
831 for (int i
= selStartLine
; i
<= selEndLine
; i
++) {
832 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, i
);
833 int lineIndent
= lineStart
;
834 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, i
);
835 if (props
->GetInt(comment_at_line_start
.c_str())) {
836 GetRange(wEditor
, lineIndent
, lineEnd
, linebuf
);
838 lineIndent
= GetLineIndentPosition(i
);
839 GetRange(wEditor
, lineIndent
, lineEnd
, linebuf
);
841 // empty lines are not commented
842 if (strlen(linebuf
) < 1)
844 if (memcmp(linebuf
, comment
.c_str(), comment_length
- 1) == 0) {
845 if (memcmp(linebuf
, long_comment
.c_str(), comment_length
) == 0) {
846 // removing comment with space after it
847 SendEditor(SCI_SETSEL
, lineIndent
, lineIndent
+ comment_length
);
848 SendEditorString(SCI_REPLACESEL
, 0, "");
849 if (i
== selStartLine
) // is this the first selected line?
850 selectionStart
-= comment_length
;
851 selectionEnd
-= comment_length
; // every iteration
854 // removing comment _without_ space
855 SendEditor(SCI_SETSEL
, lineIndent
, lineIndent
+ comment_length
- 1);
856 SendEditorString(SCI_REPLACESEL
, 0, "");
857 if (i
== selStartLine
) // is this the first selected line?
858 selectionStart
-= (comment_length
- 1);
859 selectionEnd
-= (comment_length
- 1); // every iteration
863 if (i
== selStartLine
) // is this the first selected line?
864 selectionStart
+= comment_length
;
865 selectionEnd
+= comment_length
; // every iteration
866 SendEditorString(SCI_INSERTTEXT
, lineIndent
, long_comment
.c_str());
868 // after uncommenting selection may promote itself to the lines
869 // before the first initially selected line;
870 // another problem - if only comment symbol was selected;
871 if (selectionStart
< firstSelLineStart
) {
872 if (selectionStart
>= selectionEnd
- (comment_length
- 1))
873 selectionEnd
= firstSelLineStart
;
874 selectionStart
= firstSelLineStart
;
877 // moving caret to the beginning of selected block
878 SendEditor(SCI_GOTOPOS
, selectionEnd
);
879 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
881 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
883 SendEditor(SCI_ENDUNDOACTION
);
887 // Return true if the selected zone can be commented
888 // Return false if it cannot be commented or has been uncommented
889 // BOX_COMMENT : box_stream = true STREAM_COMMENT : box_stream = false
890 // Uncomment if the selected zone or the cursor is inside the comment
892 bool AnEditor::CanBeCommented(bool box_stream
) {
893 SString fileNameForExtension
= ExtensionFileName();
894 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
895 SString
start_base("comment.box.start.");
896 SString
middle_base("comment.box.middle.");
897 SString
end_base("comment.box.end.");
898 SString
white_space(" ");
899 start_base
+= language
;
900 middle_base
+= language
;
901 end_base
+= language
;
902 SString start_comment
= props
->Get(start_base
.c_str());
903 SString middle_cmt
= props
->Get(middle_base
.c_str());
904 SString end_comment
= props
->Get(end_base
.c_str());
905 start_comment
+= white_space
;
906 middle_cmt
+= white_space
;
907 white_space
+= end_comment
;
908 end_comment
= white_space
;
909 size_t start_comment_length
= start_comment
.length();
910 size_t end_comment_length
= end_comment
.length();
911 size_t middle_cmt_length
= middle_cmt
.length();
912 SString
start_base_stream ("comment.stream.start.");
913 start_base_stream
+= language
;
914 SString
end_base_stream ("comment.stream.end.");
915 end_base_stream
+= language
;
916 SString end_comment_stream
= props
->Get(end_base_stream
.c_str());
917 SString
white_space_stream(" ");
918 //SString end_white_space_stream(" ");
919 SString start_comment_stream
= props
->Get(start_base_stream
.c_str());
920 start_comment_stream
+= white_space_stream
;
921 size_t start_comment_stream_length
= start_comment_stream
.length();
922 white_space_stream
+=end_comment_stream
;
923 end_comment_stream
= white_space_stream
;
924 size_t end_comment_stream_length
= end_comment_stream
.length();
927 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
928 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
929 if (selectionStart
== selectionEnd
)
931 int line
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
934 bool start1
= false, start2
= false;
935 bool end1
= false, end2
= false;
938 lineEnd1
= selectionStart
+ start_comment_length
;
940 lineEnd1
= selectionStart
+ start_comment_stream_length
+1;
941 if (lineEnd1
> LengthDocument())
942 lineEnd1
= LengthDocument();
945 size_t start_cmt
= 0, end_cmt
= 0;
947 // Find Backward StartComment
948 while (line
>= 0 && start1
== false && end1
== false)
950 lineStart1
= SendEditor(SCI_POSITIONFROMLINE
, line
);
951 GetRange(wEditor
, lineStart1
, lineEnd1
, linebuf
);
953 for (index
= lineEnd1
-lineStart1
; index
>= 0; index
--)
955 if (end1
= ((end_comment_length
> 1 && !memcmp(linebuf
+index
,
956 end_comment
.c_str(), end_comment_length
))
957 || (end_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
958 end_comment_stream
.c_str(), end_comment_stream_length
))))
960 if (start1
=((start_comment_length
> 1 && !memcmp(linebuf
+index
,
961 start_comment
.c_str(), start_comment_length
))
962 || (start_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
963 start_comment_stream
.c_str(), start_comment_stream_length
))))
967 lineEnd1
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
969 start_cmt
= index
+ lineStart1
;
970 line
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
972 lineStart1
= selectionEnd
- start_comment_length
;
974 lineStart1
= selectionEnd
- start_comment_stream_length
;
975 int last_line
= SendEditor(SCI_GETLINECOUNT
);
976 // Find Forward EndComment
977 while (line
<= last_line
&& start2
== false && end2
== false)
979 lineEnd1
= SendEditor(SCI_GETLINEENDPOSITION
, line
);
980 GetRange(wEditor
, lineStart1
, lineEnd1
, linebuf
);
981 for (index
= 0; index
<= (lineEnd1
-lineStart1
); index
++)
983 if (start2
= ((start_comment_length
> 1 && !memcmp(linebuf
+index
,
984 start_comment
.c_str(), start_comment_length
))
985 || (start_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
986 start_comment_stream
.c_str(), start_comment_stream_length
))))
988 if (end2
= ((end_comment_length
> 1 && !memcmp(linebuf
+index
,
989 end_comment
.c_str(), end_comment_length
))
990 || (end_comment_stream_length
> 0 && !memcmp(linebuf
+index
,
991 end_comment_stream
.c_str(), end_comment_stream_length
))))
995 end_cmt
= lineStart1
+ index
;
996 lineStart1
= SendEditor(SCI_POSITIONFROMLINE
, line
);
1003 SendEditor(SCI_BEGINUNDOACTION
);
1004 if (box_stream
) // Box
1006 SendEditor(SCI_SETSEL
, start_cmt
, start_cmt
+
1007 start_comment_length
);
1008 end_cmt
-= start_comment_length
;
1012 SendEditor(SCI_SETSEL
, start_cmt
, start_cmt
+
1013 start_comment_stream_length
);
1014 end_cmt
-= start_comment_stream_length
;
1016 SendEditorString(SCI_REPLACESEL
, 0, "");
1017 line
= SendEditor(SCI_LINEFROMPOSITION
, start_cmt
) + 1;
1018 last_line
= SendEditor(SCI_LINEFROMPOSITION
, end_cmt
) ;
1019 for (int i
= line
; i
< last_line
; i
++)
1021 int s
= SendEditor(SCI_POSITIONFROMLINE
, i
);
1022 int e
= SendEditor(SCI_GETLINEENDPOSITION
, i
);
1023 GetRange(wEditor
, s
, e
, linebuf
);
1024 if (!memcmp(linebuf
, middle_cmt
.c_str(), middle_cmt_length
))
1026 SendEditor(SCI_SETSEL
, s
, s
+ middle_cmt_length
);
1027 SendEditorString(SCI_REPLACESEL
, 0, "");
1028 end_cmt
-= middle_cmt_length
;
1031 if (box_stream
) // Box
1032 SendEditor(SCI_SETSEL
, end_cmt
, end_cmt
+ end_comment_length
);
1034 SendEditor(SCI_SETSEL
, end_cmt
, end_cmt
+ end_comment_stream_length
);
1035 SendEditorString(SCI_REPLACESEL
, 0, "");
1036 SendEditor(SCI_ENDUNDOACTION
);
1044 bool AnEditor::StartBoxComment() {
1045 SString fileNameForExtension
= ExtensionFileName();
1046 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
1047 SString
start_base("comment.box.start.");
1048 SString
middle_base("comment.box.middle.");
1049 SString
end_base("comment.box.end.");
1050 SString
white_space(" ");
1051 start_base
+= language
;
1052 middle_base
+= language
;
1053 end_base
+= language
;
1054 SString start_comment
= props
->Get(start_base
.c_str());
1055 SString middle_comment
= props
->Get(middle_base
.c_str());
1056 SString end_comment
= props
->Get(end_base
.c_str());
1057 if (start_comment
== "" || middle_comment
== "" || end_comment
== "") {
1058 //SString error("Box comment variables \"");
1059 //error += start_base;
1060 //error += "\", \"";
1061 //error += middle_base;
1062 //error += "\"\nand \"";
1063 //error += end_base;
1064 //error += "\" are not ";
1065 //error += "defined in SciTE *.properties!";
1066 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1069 start_comment
+= white_space
;
1070 middle_comment
+= white_space
;
1071 white_space
+= end_comment
;
1072 end_comment
= white_space
;
1073 size_t start_comment_length
= start_comment
.length();
1074 size_t middle_comment_length
= middle_comment
.length();
1075 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
1076 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
1077 size_t caretPosition
= SendEditor(SCI_GETCURRENTPOS
);
1078 // checking if caret is located in _beginning_ of selected block
1079 bool move_caret
= caretPosition
< selectionEnd
;
1080 size_t selStartLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
1081 size_t selEndLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionEnd
);
1082 size_t lines
= selEndLine
- selStartLine
;
1083 // "caret return" is part of the last selected line
1084 if ((lines
> 0) && (
1085 selectionEnd
== static_cast<size_t>(SendEditor(SCI_POSITIONFROMLINE
, selEndLine
)))) {
1088 // get rid of CRLF problems
1089 selectionEnd
= SendEditor(SCI_GETLINEENDPOSITION
, selEndLine
);
1091 // Comment , Uncomment or Do Nothing
1092 if (CanBeCommented(true))
1094 SendEditor(SCI_BEGINUNDOACTION
);
1095 // first commented line (start_comment)
1096 int lineStart
= SendEditor(SCI_POSITIONFROMLINE
, selStartLine
);
1097 SendEditorString(SCI_INSERTTEXT
, lineStart
, start_comment
.c_str());
1098 selectionStart
+= start_comment_length
;
1099 // lines between first and last commented lines (middle_comment)
1100 for (size_t i
= selStartLine
+ 1; i
<= selEndLine
; i
++) {
1101 lineStart
= SendEditor(SCI_POSITIONFROMLINE
, i
);
1102 SendEditorString(SCI_INSERTTEXT
, lineStart
, middle_comment
.c_str());
1103 selectionEnd
+= middle_comment_length
;
1105 // last commented line (end_comment)
1106 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, selEndLine
);
1108 SendEditorString(SCI_INSERTTEXT
, lineEnd
, "\n");
1109 SendEditorString(SCI_INSERTTEXT
, lineEnd
+ 1, (end_comment
.c_str() + 1));
1111 SendEditorString(SCI_INSERTTEXT
, lineEnd
, end_comment
.c_str());
1113 selectionEnd
+= (start_comment_length
);
1115 // moving caret to the beginning of selected block
1116 SendEditor(SCI_GOTOPOS
, selectionEnd
);
1117 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
1119 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
1121 SendEditor(SCI_ENDUNDOACTION
);
1126 bool AnEditor::StartStreamComment() {
1127 SString fileNameForExtension
= ExtensionFileName();
1128 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
1129 SString
start_base("comment.stream.start.");
1130 SString
end_base("comment.stream.end.");
1131 SString
white_space(" ");
1132 //SString end_white_space(" ");
1133 start_base
+= language
;
1134 end_base
+= language
;
1135 SString start_comment
= props
->Get(start_base
.c_str());
1136 SString end_comment
= props
->Get(end_base
.c_str());
1137 if (start_comment
== "" || end_comment
== "") {
1138 //SString error("Stream comment variables \"");
1139 //error += start_base;
1140 //error += "\" and \n\"";
1141 //error += end_base;
1142 //error += "\" are not ";
1143 //error += "defined in SciTE *.properties!";
1144 //WindowMessageBox(wSciTE, error, MB_OK | MB_ICONWARNING);
1147 start_comment
+= white_space
;
1148 white_space
+= end_comment
;
1149 end_comment
= white_space
;
1150 size_t start_comment_length
= start_comment
.length();
1151 size_t selectionStart
= SendEditor(SCI_GETSELECTIONSTART
);
1152 size_t selectionEnd
= SendEditor(SCI_GETSELECTIONEND
);
1153 size_t caretPosition
= SendEditor(SCI_GETCURRENTPOS
);
1154 // checking if caret is located in _beginning_ of selected block
1155 bool move_caret
= caretPosition
< selectionEnd
;
1156 // if there is no selection?
1157 if (selectionEnd
- selectionStart
<= 0) {
1158 int selLine
= SendEditor(SCI_LINEFROMPOSITION
, selectionStart
);
1159 int lineIndent
= GetLineIndentPosition(selLine
);
1160 int lineEnd
= SendEditor(SCI_GETLINEENDPOSITION
, selLine
);
1161 if (RangeIsAllWhitespace(lineIndent
, lineEnd
))
1162 return true; // we are not dealing with empty lines
1165 int current
= GetCaretInLine();
1166 // checking if we are not inside a word
1167 if (!wordCharacters
.contains(linebuf
[current
]))
1168 return true; // caret is located _between_ words
1169 int startword
= current
;
1170 int endword
= current
;
1171 int start_counter
= 0;
1172 int end_counter
= 0;
1173 while (startword
> 0 && wordCharacters
.contains(linebuf
[startword
- 1])) {
1177 // checking _beginning_ of the word
1178 if (startword
== current
)
1179 return true; // caret is located _before_ a word
1180 while (linebuf
[endword
+ 1] != '\0' && wordCharacters
.contains(linebuf
[endword
+ 1])) {
1184 selectionStart
-= start_counter
;
1185 selectionEnd
+= (end_counter
+ 1);
1187 // Comment , Uncomment or Do Nothing
1188 if (CanBeCommented(false))
1190 SendEditor(SCI_BEGINUNDOACTION
);
1191 SendEditorString(SCI_INSERTTEXT
, selectionStart
, start_comment
.c_str());
1192 selectionEnd
+= start_comment_length
;
1193 selectionStart
+= start_comment_length
;
1194 SendEditorString(SCI_INSERTTEXT
, selectionEnd
, end_comment
.c_str());
1196 // moving caret to the beginning of selected block
1197 SendEditor(SCI_GOTOPOS
, selectionEnd
);
1198 SendEditor(SCI_SETCURRENTPOS
, selectionStart
);
1200 SendEditor(SCI_SETSEL
, selectionStart
, selectionEnd
);
1202 SendEditor(SCI_ENDUNDOACTION
);
1208 SString
AnEditor::GetMode(SString language
) {
1210 if (strcmp(language
.c_str(), "cpp") == 0)
1212 mode
+= " Mode: C;";
1213 if (props
->GetInt("use.tabs"))
1214 mode
+= " indent-tabs-mode: t;";
1215 mode
+= " c-basic-offset: ";
1216 mode
+= g_strdup_printf("%d", props
->GetInt("indent.size"));
1217 mode
+= "; tab-width: ";
1218 mode
+= g_strdup_printf("%d ", props
->GetInt("tabsize"));
1225 /* Insert or Modify a Comment line
1226 giving File indent */
1227 bool AnEditor::InsertCustomIndent() {
1230 SString fileNameForExtension
= ExtensionFileName();
1231 SString language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
1232 SString
start_box_base("comment.box.start.");
1233 start_box_base
+= language
;
1234 SString
start_stream_base("comment.stream.start.");
1235 start_stream_base
+= language
;
1236 SString
end_box_base("comment.box.end.");
1237 end_box_base
+= language
;
1238 SString
end_stream_base("comment.stream.end.");
1239 end_stream_base
+= language
;
1240 SString start_box
= props
->Get(start_box_base
.c_str());
1241 SString start_stream
= props
->Get(start_stream_base
.c_str());
1242 SString end_box
= props
->Get(end_box_base
.c_str());
1243 SString end_stream
= props
->Get(end_stream_base
.c_str());
1244 SString
mark("-*-");
1245 int text_length
= SendEditor(SCI_GETTEXTLENGTH
);
1247 int bufmax
= text_length
< MAXBUF
? text_length
: MAXBUF
;
1249 GetRange(wEditor
, 0, bufmax
- 1, buf
);
1251 bool start_comment
= false;
1252 bool indent_comment
= false;
1253 int end_indent_comment
= 0;
1255 for (int index
= 0; index
< bufmax
; index
++)
1259 if (memcmp(buf
+index
, start_box
.c_str(), start_box
.length()) == 0)
1261 index
+= (start_box
.length() - 1);
1262 start_comment
= true;
1265 if (memcmp(buf
+index
, start_stream
.c_str(), start_stream
.length()) == 0)
1267 index
+= (start_stream
.length() - 1);
1268 start_comment
= true;
1271 if (buf
[index
] != ' ' && buf
[index
] != '\t' && buf
[index
] != '\n')
1276 if (!indent_comment
)
1278 if (buf
[index
] == ' ' || buf
[index
] == '\t' || buf
[index
] == '\n')
1280 if (memcmp(buf
+index
, mark
.c_str(), 3) == 0)
1283 indent_comment
= true;
1290 if (memcmp(buf
+index
, end_box
.c_str(), end_box
.length()) == 0)
1292 end_indent_comment
= index
+ end_box
.length() - 1;
1295 if (memcmp(buf
+index
, end_stream
.c_str(), end_stream
.length()) == 0)
1297 end_indent_comment
= index
+ end_stream
.length() - 1;
1303 SString mode
= GetMode(language
);
1304 if (mode
.c_str() != "")
1307 comment
+= start_stream
.c_str() ;
1309 comment
+= mark
.c_str();
1310 comment
+= mode
.c_str();
1311 comment
+= mark
.c_str();
1313 comment
+= end_stream
.c_str() ;
1317 SendEditor(SCI_SETSEL
, 0, end_indent_comment
+ 1);
1318 SendEditorString(SCI_REPLACESEL
, 0, comment
.c_str());
1323 SendEditorString(SCI_INSERTTEXT
, 0, comment
.c_str());
1332 * Return the length of the given line, not counting the EOL.
1334 int AnEditor::GetLineLength(int line
) {
1335 return SendEditor(SCI_GETLINEENDPOSITION
, line
) - SendEditor(SCI_POSITIONFROMLINE
, line
);
1338 int AnEditor::GetCurrentLineNumber() {
1339 CharacterRange crange
= GetSelection();
1340 int selStart
= crange
.cpMin
;
1341 return SendEditor(SCI_LINEFROMPOSITION
, selStart
);
1344 int AnEditor::GetCurrentScrollPosition() {
1345 int lineDisplayTop
= SendEditor(SCI_GETFIRSTVISIBLELINE
);
1346 return SendEditor(SCI_DOCLINEFROMVISIBLE
, lineDisplayTop
);
1349 // Upon a character being added, AnEditor may decide to perform some action
1350 // such as displaying a completion list.
1351 void AnEditor::CharAdded(char ch
) {
1352 CharacterRange crange
= GetSelection();
1353 int selStart
= crange
.cpMin
;
1354 int selEnd
= crange
.cpMax
;
1355 if ((selEnd
== selStart
) && (selStart
> 0)) {
1356 int style
= SendEditor(SCI_GETSTYLEAT
, selStart
- 1, 0);
1358 if (SendEditor(SCI_CALLTIPACTIVE
)) { // calltip is active
1359 } else if (SendEditor(SCI_AUTOCACTIVE
)) { // word autocompletion
1360 } else if (HandleXml(ch
)) {
1361 // Handled in the routine
1362 } else { // we don't have autocompetion nor calltip active
1363 if (indentMaintain
&& indentAutomatic
)
1364 MaintainIndentation(ch
);
1371 * This routine will auto complete XML or HTML tags that are still open by closing them
1372 * @parm ch The characer we are dealing with, currently only works with the '/' character
1373 * @return True if handled, false otherwise
1375 bool AnEditor::HandleXml(char ch
) {
1376 // We're looking for this char
1377 // Quit quickly if not found
1382 // This may make sense only in certain languages
1383 if (lexLanguage
!= SCLEX_HTML
&& lexLanguage
!= SCLEX_XML
) {
1387 // If the user has turned us off, quit now.
1389 SString value
= props
->GetExpanded("xml.auto.close.tags");
1390 if ((value
.length() == 0) || (value
== "0")) {
1394 // Grab the last 512 characters or so
1395 int nCaret
= SendEditor(SCI_GETCURRENTPOS
);
1397 int nMin
= nCaret
- (sizeof(sel
) - 1);
1402 if (nCaret
- nMin
< 3) {
1403 return false; // Smallest tag is 3 characters ex. <p>
1405 GetRange(wEditor
, nMin
, nCaret
, sel
);
1406 sel
[sizeof(sel
) - 1] = '\0';
1408 if (sel
[nCaret
- nMin
- 2] == '/') {
1409 // User typed something like "<br/>"
1413 SString strFound
= FindOpenXmlTag(sel
, nCaret
- nMin
);
1415 if (strFound
.length() > 0) {
1416 SendEditor(SCI_BEGINUNDOACTION
);
1417 SString toInsert
= "</";
1418 toInsert
+= strFound
;
1420 SendEditorString(SCI_REPLACESEL
, 0, toInsert
.c_str());
1421 SetSelection(nCaret
, nCaret
);
1422 SendEditor(SCI_ENDUNDOACTION
);
1429 /** Search backward through nSize bytes looking for a '<', then return the tag if any
1430 * @return The tag name
1432 SString
AnEditor::FindOpenXmlTag(const char sel
[], int nSize
) {
1433 SString strRet
= "";
1436 // Smallest tag is "<p>" which is 3 characters
1439 const char* pBegin
= &sel
[0];
1440 const char* pCur
= &sel
[nSize
- 1];
1442 pCur
--; // Skip past the >
1443 while (pCur
> pBegin
) {
1446 } else if (*pCur
== '>') {
1454 while (strchr(":_-.", *pCur
) || isalnum(*pCur
)) {
1460 // Return the tag name or ""
1464 void AnEditor::GoMatchingBrace(bool select
) {
1465 int braceAtCaret
= -1;
1466 int braceOpposite
= -1;
1467 bool isInside
= FindMatchingBracePosition(true, braceAtCaret
, braceOpposite
, true);
1468 // Convert the character positions into caret positions based on whether
1469 // the caret position was inside or outside the braces.
1471 if (braceOpposite
> braceAtCaret
) {
1477 if (braceOpposite
> braceAtCaret
) {
1483 if (braceOpposite
>= 0) {
1484 EnsureRangeVisible(braceOpposite
, braceOpposite
);
1486 SetSelection(braceAtCaret
, braceOpposite
);
1488 SetSelection(braceOpposite
, braceOpposite
);
1493 int ControlIDOfCommand(unsigned long wParam
) {
1494 return wParam
& 0xffff;
1497 long AnEditor::Command(int cmdID
, long wParam
, long lParam
) {
1500 case ANE_INSERTTEXT
:
1501 SendEditor(SCI_INSERTTEXT
,wParam
,lParam
);
1504 case ANE_GETBOOKMARK_POS
:
1505 return GetBookmarkLine( wParam
);
1506 break; /* pleonastico */
1508 case ANE_BOOKMARK_TOGGLE_LINE
:
1509 BookmarkToggle( wParam
);
1513 SendEditor(SCI_UNDO
);
1517 SendEditor(SCI_REDO
);
1521 SendEditor(SCI_CUT
);
1525 SendEditor(SCI_COPY
);
1529 SendEditor(SCI_PASTE
);
1533 SendEditor(SCI_CLEAR
);
1537 SendEditor(SCI_SELECTALL
);
1541 return Find (wParam
, (char*) lParam
);
1544 SendEditor(SCI_GOTOLINE
, wParam
);
1548 SendEditor(SCI_SETZOOM
, wParam
);
1551 case ANE_MATCHBRACE
:
1552 GoMatchingBrace(false);
1555 case ANE_SELECTBLOCK
:
1559 case ANE_SELECTTOBRACE
:
1560 GoMatchingBrace(true);
1563 case ANE_GETBLOCKSTARTLINE
:
1564 return GetBlockStartLine();
1566 case ANE_GETBLOCKENDLINE
:
1567 return GetBlockEndLine();
1569 case ANE_GETCURRENTWORD
:
1570 return GetCurrentWord((char*)wParam
, (int)lParam
);
1572 case ANE_GETWORDBEFORECARAT
:
1573 return GetWordBeforeCarat((char*)wParam
, (int)lParam
);
1575 case ANE_SHOWCALLTIP
:
1579 case ANE_COMPLETECALLTIP
:
1584 StartAutoComplete();
1587 case ANE_COMPLETEWORD:
1588 StartAutoCompleteWord(false);
1591 case ANE_TOGGLE_FOLD
:
1595 case ANE_OPEN_FOLDALL
:
1599 case ANE_CLOSE_FOLDALL
:
1604 SendEditor(SCI_UPPERCASE
);
1608 SendEditor(SCI_LOWERCASE
);
1612 SendEditor(SCI_TOGGLEFOLD
, GetCurrentLineNumber());
1615 case ANE_LINENUMBERMARGIN
:
1616 lineNumbers
= wParam
;
1617 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
1622 SendEditor(SCI_SETMARGINWIDTHN
, 1, margin
? marginWidth
: 0);
1625 case ANE_FOLDMARGIN
:
1626 foldMargin
= wParam
;
1627 SendEditor(SCI_SETMARGINWIDTHN
, 2, foldMargin
? foldMarginWidth
: 0);
1631 SendEditor(SCI_SETVIEWEOL
, wParam
);
1635 SendEditor(SCI_SETEOLMODE
, SC_EOL_CRLF
);
1639 SendEditor(SCI_SETEOLMODE
, SC_EOL_CR
);
1643 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
1646 case ANE_EOL_CONVERT
:
1649 SendEditor(SCI_SETEOLMODE
, SC_EOL_CRLF
);
1650 SendEditor(SCI_CONVERTEOLS
, SC_EOL_CRLF
);
1653 SendEditor(SCI_SETEOLMODE
, SC_EOL_LF
);
1654 SendEditor(SCI_CONVERTEOLS
, SC_EOL_LF
);
1657 SendEditor(SCI_SETEOLMODE
, SC_EOL_CR
);
1658 SendEditor(SCI_CONVERTEOLS
, SC_EOL_CR
);
1661 SendEditor(SCI_CONVERTEOLS
, SendEditor(SCI_GETEOLMODE
));
1666 case ANE_WORDPARTLEFT
:
1667 SendEditor(SCI_WORDPARTLEFT
);
1670 case ANE_WORDPARTLEFTEXTEND
:
1671 SendEditor(SCI_WORDPARTLEFTEXTEND
);
1674 case ANE_WORDPARTRIGHT
:
1675 SendEditor(SCI_WORDPARTRIGHT
);
1678 case ANE_WORDPARTRIGHTEXTEND
:
1679 SendEditor(SCI_WORDPARTRIGHTEXTEND
);
1683 ViewWhitespace(wParam
);
1686 case ANE_VIEWGUIDES
:
1687 SendEditor(SCI_SETINDENTATIONGUIDES
, wParam
);
1690 case ANE_BOOKMARK_TOGGLE
:
1693 case ANE_BOOKMARK_FIRST
:
1696 case ANE_BOOKMARK_PREV
:
1699 case ANE_BOOKMARK_NEXT
:
1702 case ANE_BOOKMARK_LAST
:
1705 case ANE_BOOKMARK_CLEAR
:
1709 case ANE_SETTABSIZE
:
1710 SendEditor(SCI_SETTABWIDTH
, wParam
);
1713 case ANE_SETLANGUAGE
:
1714 SetOverrideLanguage(wParam
);
1718 ReadProperties((char*)wParam
, (char **)lParam
);
1719 SendEditor(SCI_COLOURISE
, 0, -1);
1722 case ANE_SETACCELGROUP
:
1723 SetAccelGroup((GtkAccelGroup
*)wParam
);
1726 case ANE_GETTEXTRANGE
: {
1728 if(wParam
== lParam
) return 0;
1729 start
= (guint
) MINIMUM(wParam
, lParam
);
1730 end
= (guint
) MAXIMUM(wParam
, lParam
);
1731 gchar
*buff
= (gchar
*) g_malloc(end
-start
+10);
1733 GetRange(start
, end
, buff
, false);
1738 case ANE_INDENT_INCREASE
:
1739 IndentationIncrease();
1742 case ANE_INDENT_DECREASE
:
1743 IndentationDecrease();
1747 return SendEditor(SCI_GETLENGTH
);
1749 case ANE_GET_LINENO
:
1750 return GetCurrentLineNumber();
1753 SetLineWrap((bool)wParam
);
1757 SetReadOnly((bool)wParam
);
1760 case ANE_GETSTYLEDTEXT
: {
1762 if(wParam
== lParam
) return 0;
1763 start
= (guint
) MINIMUM(wParam
, lParam
);
1764 end
= (guint
) MAXIMUM(wParam
, lParam
);
1765 /* Allocate a bit more space to allow reading multi
1766 * byte characters more easily */
1767 gchar
*buff
= (gchar
*) g_malloc((end
-start
+10)*2);
1769 GetRange(start
, end
, buff
, true);
1770 memset (buff
+ (end
-start
) * 2, 0, 20);
1775 return SendEditor(SCI_TEXTWIDTH
, wParam
, lParam
);
1776 case ANE_GETLANGUAGE
:
1777 return (long) language
.c_str();
1779 case ANE_BLOCKCOMMENT
:
1780 return StartBlockComment();
1782 case ANE_BOXCOMMENT
:
1783 return StartBoxComment();
1785 case ANE_STREAMCOMMENT
:
1786 return StartStreamComment();
1788 case ANE_CUSTOMINDENT:
1789 return InsertCustomIndent();
1791 case ANE_WORDSELECT
:
1795 case ANE_LINESELECT
:
1799 case ANE_GETCURRENTPOS
:
1800 return SendEditor(SCI_GETCURRENTPOS
);
1803 return SendEditor(SCI_GOTOPOS
, wParam
);
1805 case ANE_SETWRAPBOOKMARKS
:
1809 case ANE_SETAUTOINDENTATION
:
1810 indentAutomatic
= wParam
;
1813 case ANE_SETUSETABFORINDENT
:
1814 SendEditor(SCI_SETUSETABS
, wParam
);
1817 case ANE_SETINDENTSIZE
:
1818 indentSize
= wParam
;
1819 SendEditor(SCI_SETINDENT
, wParam
);
1822 case ANE_SETINDENTBRACESCHECK
:
1823 bracesCheck
= wParam
;
1826 case ANE_SETINDENTOPENING:
1827 indentOpening = wParam;
1830 case ANE_SETINDENTCLOSING:
1831 indentClosing = wParam;
1834 case ANE_SETINDENTMAINTAIN
:
1835 props
->Set ("indent.maintain.*", wParam
? "1" : "0");
1836 indentMaintain
= wParam
;
1839 case ANE_SETTABINDENTS
:
1840 SendEditor(SCI_SETTABINDENTS
, wParam
);
1843 case ANE_SETBACKSPACEUNINDENTS
:
1844 SendEditor(SCI_SETBACKSPACEUNINDENTS
, wParam
);
1847 case ANE_SETFOLDSYMBOLS
:
1848 SetFoldSymbols(reinterpret_cast<char *> (wParam
));
1851 case ANE_SETFOLDUNDERLINE
:
1853 SendEditor(SCI_SETFOLDFLAGS
, props
->GetInt("fold.flags"));
1855 SendEditor(SCI_SETFOLDFLAGS
, 0);
1857 case ANE_SETLINENUMWIDTH
:
1858 lineNumbersWidth
= wParam
;
1859 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
? lineNumbersWidth
: 0);
1861 case ANE_SETEDGECOLUMN
:
1862 SendEditor(SCI_SETEDGECOLUMN
, wParam
);
1870 void AnEditor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
1871 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
1872 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
1873 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
1874 if (!SendEditor(SCI_GETFOLDEXPANDED
, line
)) {
1875 // Removing the fold from one that has been contracted so should expand
1876 // otherwise lines are left invisible with no way to make them visible
1877 Expand(line
, true, false, 0, levelPrev
);
1882 void AnEditor::Expand(int &line
, bool doExpand
, bool force
, int visLevels
, int level
) {
1883 int lineMaxSubord
= SendEditor(SCI_GETLASTCHILD
, line
, level
);
1885 while (line
<= lineMaxSubord
) {
1888 SendEditor(SCI_SHOWLINES
, line
, line
);
1890 SendEditor(SCI_HIDELINES
, line
, line
);
1893 SendEditor(SCI_SHOWLINES
, line
, line
);
1895 int levelLine
= level
;
1897 levelLine
= SendEditor(SCI_GETFOLDLEVEL
, line
);
1898 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
1901 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
1903 SendEditor(SCI_SETFOLDEXPANDED
, line
, 0);
1904 Expand(line
, doExpand
, force
, visLevels
- 1);
1906 if (doExpand
&& SendEditor(SCI_GETFOLDEXPANDED
, line
)) {
1907 Expand(line
, true, force
, visLevels
- 1);
1909 Expand(line
, false, force
, visLevels
- 1);
1918 void AnEditor::FoldCode(bool expanding
) {
1919 int maxLine
= SendEditor (SCI_GETTEXTLENGTH
);
1920 SendEditor(SCI_COLOURISE
, 0, -1);
1921 for (int line
= 0; line
< maxLine
; line
++) {
1922 int level
= SendEditor(SCI_GETFOLDLEVEL
, line
);
1923 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
1924 (SC_FOLDLEVELBASE
== (level
& SC_FOLDLEVELNUMBERMASK
))) {
1926 SendEditor(SCI_SETFOLDEXPANDED
, line
, 1);
1930 int lineMaxSubord
= SendEditor(SCI_GETLASTCHILD
, line
, -1);
1931 SendEditor(SCI_SETFOLDEXPANDED
, line
, 0);
1932 if (lineMaxSubord
> line
)
1933 SendEditor(SCI_HIDELINES
, line
+ 1, lineMaxSubord
);
1939 void AnEditor::FoldOpenAll() {
1943 void AnEditor::FoldCloseAll() {
1947 void AnEditor::FoldToggle() {
1948 int curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
1949 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
1950 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1951 SendEditor(SCI_TOGGLEFOLD
, curLine
);
1954 int parent
= SendEditor (SCI_GETFOLDPARENT
, curLine
);
1955 int lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
1956 if (curLine
> parent
&& curLine
<= lastChild
)
1958 SendEditor(SCI_TOGGLEFOLD
, parent
);
1959 SendEditor(SCI_SETCURRENTPOS
, SendEditor (SCI_POSITIONFROMLINE
, parent
));
1960 SendEditor(SCI_GOTOLINE
, parent
);
1966 void AnEditor::SelectBlock () {
1967 int curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
1968 int parent
= SendEditor (SCI_GETFOLDPARENT
, curLine
);
1969 int lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
1970 if (curLine
> parent
&& curLine
<= lastChild
)
1973 start
= SendEditor(SCI_POSITIONFROMLINE
, parent
);
1974 end
= SendEditor(SCI_POSITIONFROMLINE
, lastChild
+1);
1975 SetSelection(start
, end
);
1981 int AnEditor::GetBlockStartLine (int curLine
) {
1984 curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
1986 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
1987 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1991 int lastChild
= curLine
;
1994 parent
= SendEditor (SCI_GETFOLDPARENT
, lastChild
);
1999 lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2000 if (curLine
> parent
&& curLine
<= lastChild
)
2004 lastChild
= parent
- 1;
2010 int AnEditor::GetBlockEndLine (int curLine
) {
2013 curLine
= SendEditor(SCI_LINEFROMPOSITION
, SendEditor (SCI_GETCURRENTPOS
));
2015 int level
= SendEditor(SCI_GETFOLDLEVEL
, curLine
);
2016 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2017 /* this may be a problem when we use this function on "start" block line */
2021 int lastChild
= curLine
;
2024 parent
= SendEditor (SCI_GETFOLDPARENT
, lastChild
);
2029 lastChild
= SendEditor (SCI_GETLASTCHILD
, parent
, -1);
2030 if (curLine
> parent
&& curLine
<= lastChild
)
2034 lastChild
= parent
- 1;
2040 void AnEditor::EnsureRangeVisible(int posStart
, int posEnd
) {
2041 int lineStart
= SendEditor(SCI_LINEFROMPOSITION
, Platform::Minimum(posStart
, posEnd
));
2042 int lineEnd
= SendEditor(SCI_LINEFROMPOSITION
, Platform::Maximum(posStart
, posEnd
));
2043 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2044 SendEditor(SCI_ENSUREVISIBLE
, line
);
2048 void AnEditor::SetLineWrap(bool wrap
) {
2050 SendEditor(SCI_SETWRAPMODE
, wrapLine
? SC_WRAP_WORD
: SC_WRAP_NONE
);
2051 SendEditor(SCI_SETHSCROLLBAR
, !wrapLine
);
2054 void AnEditor::SetReadOnly(bool readonly
) {
2055 isReadOnly
= readonly
;
2056 SendEditor(SCI_SETREADONLY
, isReadOnly
);
2059 bool AnEditor::MarginClick(int position
, int modifiers
) {
2060 int lineClick
= SendEditor(SCI_LINEFROMPOSITION
, position
);
2061 // SendEditor(SCI_GETFOLDLEVEL, lineClick) & SC_FOLDLEVELHEADERFLAG);
2062 if (modifiers
& SCMOD_SHIFT
) {
2064 } else if (modifiers
& SCMOD_CTRL
) {
2066 } else if (SendEditor(SCI_GETFOLDLEVEL
, lineClick
) & SC_FOLDLEVELHEADERFLAG
) {
2067 if (modifiers
& SCMOD_SHIFT
) {
2068 // Ensure all children visible
2069 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 1);
2070 Expand(lineClick
, true, true, 100);
2071 } else if (modifiers
& SCMOD_CTRL
) {
2072 if (SendEditor(SCI_GETFOLDEXPANDED
, lineClick
)) {
2073 // Contract this line and all children
2074 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 0);
2075 Expand(lineClick
, false, true, 0);
2077 // Expand this line and all children
2078 SendEditor(SCI_SETFOLDEXPANDED
, lineClick
, 1);
2079 Expand(lineClick
, true, true, 100);
2083 SendEditor(SCI_TOGGLEFOLD
, lineClick
);
2090 gint
AnEditor::KeyPressEvent(GtkWidget
*, GdkEventKey
*event
, AnEditor
*anedit
) {
2091 return anedit
->KeyPress(event
->state
, event
->keyval
);
2095 void AnEditor::NotifySignal(GtkWidget
*, gint
/*wParam*/, gpointer lParam
, AnEditor
*anedit
) {
2096 anedit
->Notify(reinterpret_cast<SCNotification
*>(lParam
));
2102 eval_output_arrived_for_aneditor(GList
* lines
, gpointer data
)
2104 // We expect lines->data to be a string of the form VARIABLE = VALUE,
2105 // and 'data' to be a pointer to an object of type
2106 // 'ExpressionEvaluationTipInfo'.
2111 auto_ptr
<ExpressionEvaluationTipInfo
> info(
2112 (ExpressionEvaluationTipInfo
*) data
);
2114 if (info
->editor
== NULL
)
2117 if (info
->editor
!= aneditor_get(AnEditor::focusedID
))
2120 info
->editor
->EvalOutputArrived(lines
, info
->textPos
, info
->expression
);
2123 void AnEditor::EvalOutputArrived(GList
* lines
, int textPos
,
2124 const string
&expression
) {
2129 // Return if debug Tip has been canceled
2133 if (g_list_length(lines
) == 0 || lines
->data
== NULL
)
2136 string result
= (char *) lines
->data
;
2137 string::size_type posEquals
= result
.find(" = ");
2138 if (posEquals
!= string::npos
)
2139 result
.replace(0, posEquals
, expression
);
2141 SendEditorString(SCI_CALLTIPSHOW
, textPos
, result
.c_str());
2142 SendEditor(SCI_CALLTIPSETHLT
, 0, result
.length());
2145 void AnEditor::EndDebugEval() {
2148 SendEditor(SCI_CALLTIPCANCEL
);
2153 void AnEditor::HandleDwellStart(int mousePos
) {
2158 if (!debugger_is_active() || !debugger_is_ready())
2160 // Do not show expression tip if it can't be shown.
2161 // string s = string(expr) + ": " + _("debugger not active");
2162 // SendEditorString(SCI_CALLTIPSHOW, mousePos, s.c_str());
2165 // If debug tip is already running, return.
2169 CharacterRange crange
= GetSelection();
2170 if (crange
.cpMin
== crange
.cpMax
2171 || mousePos
< crange
.cpMin
2172 || mousePos
>= crange
.cpMax
)
2174 // There is no selection, or the mouse pointer is
2175 // out of the selection, so we search for a word
2176 // around the mouse pointer:
2177 if (!GetWordAtPosition(expr
, sizeof(expr
), mousePos
))
2182 long lensel
= crange
.cpMax
- crange
.cpMin
;
2183 long max
= sizeof(expr
) - 1;
2184 guint end
= (lensel
< max
? crange
.cpMax
: crange
.cpMin
+ max
);
2185 GetRange(crange
.cpMin
, end
, expr
, false);
2187 // If there is any control character except TAB
2188 // in the expression, disregard it.
2190 for (i
= 0; i
< end
- crange
.cpMin
; i
++)
2191 if ((unsigned char) expr
[i
] < ' ' && expr
[i
] != '\t')
2193 if (i
< end
- crange
.cpMin
)
2197 // Imitation of on_eval_ok_clicked():
2198 // The function eval_output_arrived_for_aneditor() will
2199 // be called eventually by the debugger with the result
2200 // of the print command for 'expr', and with the 'info'
2201 // pointer. That function must call delete on 'info'.
2203 // We don't turn GDB "pretty printing" on because we want
2204 // the entire value on a single line, in the case of a
2206 // We don't want static members of classes to clutter up
2207 // the displayed tip, however.
2209 ExpressionEvaluationTipInfo
*info
=
2210 new ExpressionEvaluationTipInfo(this, mousePos
, expr
);
2211 debugger_query_evaluate_expr_tip (expr
, eval_output_arrived_for_aneditor
, info
);
2212 debugger_query_execute ();
2218 int AnEditor::KeyPress(unsigned int state
, unsigned int keyval
){
2220 unsigned int mask
= GDK_SHIFT_MASK
| GDK_LOCK_MASK
|
2221 GDK_CONTROL_MASK
| GDK_MOD1_MASK
| GDK_MOD3_MASK
|
2222 GDK_MOD4_MASK
| GDK_MOD5_MASK
;
2226 // Trap 'TAB' key for automatic indentation.
2227 // printf ("Key is '%c'\n", notification->ch);
2228 if ((keyval
== GDK_Tab
) &&
2229 (lexLanguage
== SCLEX_CPP
) &&
2230 (!indentMaintain
) &&
2231 (props
->GetInt("indent.automatic")) &&
2232 (!SendEditor(SCI_CALLTIPACTIVE
)) &&
2233 (!SendEditor(SCI_AUTOCACTIVE
))) {
2235 CharacterRange crange
= GetSelection();
2236 int selStart
= crange
.cpMin
;
2237 int selEnd
= crange
.cpMax
;
2239 if (selStart
== selEnd
) {
2240 AutomaticIndentation('\t');
2248 void AnEditor::Notify(SCNotification
*notification
) {
2249 switch (notification
->nmhdr
.code
) {
2250 case SCN_CALLTIPCLICK
:
2251 if (notification
->position
== 1) {
2252 call_tip_node
.def_index
--;
2253 if (call_tip_node
.def_index
< 0)
2254 call_tip_node
.def_index
= 0;
2256 if (notification
->position
== 2) {
2257 call_tip_node
.def_index
++;
2258 if (call_tip_node
.def_index
>= call_tip_node
.max_def
)
2259 call_tip_node
.def_index
= call_tip_node
.max_def
- 1;
2261 ResumeCallTip (false);
2264 if(!accelGroup
) break;
2266 if (notification
->modifiers
& SCMOD_SHIFT
)
2267 mods
|= GDK_SHIFT_MASK
;
2268 if (notification
->modifiers
& SCMOD_CTRL
)
2269 mods
|= GDK_CONTROL_MASK
;
2270 if (notification
->modifiers
& SCMOD_ALT
)
2271 mods
|= GDK_MOD1_MASK
;
2272 gtk_accel_groups_activate(G_OBJECT (accelGroup
), notification
->ch
,
2273 static_cast<GdkModifierType
>(mods
));
2277 CharAdded(static_cast<char>(notification
->ch
));
2280 case SCN_SAVEPOINTREACHED
:
2284 case SCN_SAVEPOINTLEFT
:
2290 int pos
= SendEditor(SCI_GETCURRENTPOS
);
2292 if (SendEditor(SCI_CALLTIPACTIVE
) ) {
2293 // if we have a caret movement on left or right
2294 if (abs(pos
- lastPos
) == 1 ) {
2295 ContinueCallTip_new();
2303 if (notification
->modificationType
== SC_MOD_CHANGEFOLD
) {
2304 FoldChanged(notification
->line
,
2305 notification
->foldLevelNow
, notification
->foldLevelPrev
);
2309 case SCN_MARGINCLICK
:
2310 if (notification
->margin
== 2)
2311 MarginClick(notification
->position
, notification
->modifiers
);
2314 case SCN_NEEDSHOWN
: {
2315 EnsureRangeVisible(notification
->position
, notification
->position
+ notification
->length
);
2319 case SCN_DWELLSTART:
2320 HandleDwellStart(notification->position);
2325 // SendEditor(SCI_CALLTIPCANCEL);
2331 static int IntFromHexDigit(const char ch
) {
2334 else if (ch
>= 'A' && ch
<= 'F')
2335 return ch
- 'A' + 10;
2336 else if (ch
>= 'a' && ch
<= 'f')
2337 return ch
- 'a' + 10;
2342 static Colour
ColourFromString(const char *val
) {
2343 int r
= IntFromHexDigit(val
[1]) * 16 + IntFromHexDigit(val
[2]);
2344 int g
= IntFromHexDigit(val
[3]) * 16 + IntFromHexDigit(val
[4]);
2345 int b
= IntFromHexDigit(val
[5]) * 16 + IntFromHexDigit(val
[6]);
2346 return Colour(r
, g
, b
);
2349 static long ColourOfProperty(PropSetFile
*props
, const char *key
, ColourDesired colourDefault
) {
2350 SString colour
= props
->Get(key
);
2351 if (colour
.length()) {
2352 return ColourFromString(colour
.c_str()).AsLong();
2354 return colourDefault
.AsLong();
2357 void AnEditor::SetGtkStyle(Window
&win
, int style
) {
2358 GtkWidgetPath
*path
;
2359 GtkStyleContext
*context
;
2363 /* Get theme style information for view widget */
2364 context
= gtk_style_context_new ();
2365 gtk_style_context_set_parent (context
, gtk_widget_get_style_context (GTK_WIDGET (win
.GetID())));
2366 path
= gtk_widget_path_copy (gtk_widget_get_path (GTK_WIDGET (win
.GetID())));
2367 gtk_widget_path_append_type (path
, GTK_TYPE_TEXT_VIEW
);
2368 gtk_style_context_set_path (context
, path
);
2369 gtk_widget_path_free (path
);
2370 gtk_style_context_add_class (context
, GTK_STYLE_CLASS_VIEW
);
2371 gtk_style_context_get_color (context
, GTK_STATE_FLAG_NORMAL
, &fore
);
2372 gtk_style_context_get_background_color (context
, GTK_STATE_FLAG_NORMAL
, &back
);
2373 g_object_unref (context
);
2375 Platform::SendScintilla(win
.GetID(), SCI_STYLESETFORE
, style
, (gint
)(fore
.red
* 255) | ((gint
)(fore
.green
* 255) << 8) | ((gint
)(fore
.blue
*255) << 16));
2376 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBACK
, style
, (gint
)(back
.red
* 255) | ((gint
)(back
.green
* 255) << 8) | ((gint
)(back
.blue
*255) << 16));
2379 void AnEditor::SetOneStyle(Window
&win
, int style
, const char *s
) {
2380 char *val
= StringDup(s
);
2383 char *cpComma
= strchr(opt
, ',');
2386 char *colon
= strchr(opt
, ':');
2389 if (0 == strcmp(opt
, "italics"))
2390 Platform::SendScintilla(win
.GetID(), SCI_STYLESETITALIC
, style
, 1);
2391 if (0 == strcmp(opt
, "notitalics"))
2392 Platform::SendScintilla(win
.GetID(), SCI_STYLESETITALIC
, style
, 0);
2393 if (0 == strcmp(opt
, "bold"))
2394 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBOLD
, style
, 1);
2395 if (0 == strcmp(opt
, "notbold"))
2396 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBOLD
, style
, 0);
2397 if (0 == strcmp(opt
, "font"))
2398 Platform::SendScintilla(win
.GetID(), SCI_STYLESETFONT
, style
, reinterpret_cast<long>(colon
));
2399 if (0 == strcmp(opt
, "fore"))
2400 Platform::SendScintilla(win
.GetID(), SCI_STYLESETFORE
, style
, ColourFromString(colon
).AsLong());
2401 if (0 == strcmp(opt
, "back"))
2402 Platform::SendScintilla(win
.GetID(), SCI_STYLESETBACK
, style
, ColourFromString(colon
).AsLong());
2403 if (0 == strcmp(opt
, "size"))
2404 Platform::SendScintilla(win
.GetID(), SCI_STYLESETSIZE
, style
, atoi(colon
));
2405 if (0 == strcmp(opt
, "eolfilled"))
2406 Platform::SendScintilla(win
.GetID(), SCI_STYLESETEOLFILLED
, style
, 1);
2407 if (0 == strcmp(opt
, "noteolfilled"))
2408 Platform::SendScintilla(win
.GetID(), SCI_STYLESETEOLFILLED
, style
, 0);
2409 if (0 == strcmp(opt
, "underlined"))
2410 Platform::SendScintilla(win
.GetID(), SCI_STYLESETUNDERLINE
, style
, 1);
2411 if (0 == strcmp(opt
, "notunderlined"))
2412 Platform::SendScintilla(win
.GetID(), SCI_STYLESETUNDERLINE
, style
, 0);
2413 if (0 == strcmp(opt
, "case")) {
2414 if (*colon
== 'u') {
2415 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCASE
, style
, SC_CASE_UPPER
);
2416 } else if (*colon
== 'l') {
2417 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCASE
, style
, SC_CASE_LOWER
);
2419 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCASE
, style
, SC_CASE_MIXED
);
2422 if (0 == strcmp(opt
, "visible"))
2423 Platform::SendScintilla(win
.GetID(), SCI_STYLESETVISIBLE
, style
, 1);
2424 if (0 == strcmp(opt
, "notvisible"))
2425 Platform::SendScintilla(win
.GetID(), SCI_STYLESETVISIBLE
, style
, 0);
2426 if (0 == strcmp(opt
, "changeable"))
2427 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCHANGEABLE
, style
, 1);
2428 if (0 == strcmp(opt
, "notchangeable"))
2429 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCHANGEABLE
, style
, 0);
2437 Platform::SendScintilla(win
.GetID(), SCI_STYLESETCHARACTERSET
, style
, characterSet
);
2440 void AnEditor::SetStyleFor(Window
&win
, const char *lang
) {
2441 for (int style
= 0; style
<= STYLE_MAX
; style
++) {
2442 if (style
!= STYLE_DEFAULT
) {
2444 sprintf(key
, "style.%s.%0d", lang
, style
);
2445 SString sval
= props
->GetExpanded(key
);
2446 // g_print ("Style for %s:%0d == %s\n", lang, style, sval.c_str());
2447 SetOneStyle(win
, style
, sval
.c_str());
2452 void AnEditor::UpdateStyle(void) {
2457 SendEditor(SCI_STYLERESETDEFAULT
, 0, 0);
2459 SetGtkStyle(wEditor
, STYLE_DEFAULT
);
2461 sprintf(key
, "style.%s.%0d", "*", STYLE_DEFAULT
);
2462 sval
= props
->GetNewExpand(key
, "");
2463 SetOneStyle(wEditor
, STYLE_DEFAULT
, sval
.c_str());
2465 sprintf(key
, "style.%s.%0d", language
.c_str(), STYLE_DEFAULT
);
2466 sval
= props
->GetNewExpand(key
, "");
2467 SetOneStyle(wEditor
, STYLE_DEFAULT
, sval
.c_str());
2469 SendEditor(SCI_STYLECLEARALL
, 0, 0);
2471 SetStyleFor(wEditor
, "*");
2472 SetStyleFor(wEditor
, language
.c_str());
2475 void lowerCaseString(char *s
) {
2477 *s
= static_cast<char>(tolower(*s
));
2482 SString
AnEditor::ExtensionFileName() {
2483 if (overrideExtension
.length())
2484 return overrideExtension
;
2485 else if (fileName
[0]) {
2486 // Force extension to lower case
2487 char fileNameWithLowerCaseExtension
[MAX_PATH
];
2488 strcpy(fileNameWithLowerCaseExtension
, fileName
);
2489 char *extension
= strrchr(fileNameWithLowerCaseExtension
, '.');
2491 lowerCaseString(extension
);
2493 return SString(fileNameWithLowerCaseExtension
);
2495 return props
->Get("default.file.ext");
2498 void AnEditor::ForwardPropertyToEditor(const char *key
) {
2499 SString value
= props
->Get(key
);
2500 SendEditorString(SCI_SETPROPERTY
,
2501 reinterpret_cast<uptr_t
>(key
), value
.c_str());
2504 SString
AnEditor::FindLanguageProperty(const char *pattern
, const char *defaultValue
) {
2505 SString key
= pattern
;
2506 key
.substitute("*", language
.c_str());
2507 SString ret
= props
->GetExpanded(key
.c_str());
2509 ret
= props
->GetExpanded(pattern
);
2515 void AnEditor::ReadProperties(const char *fileForExt
, char **typedef_hl
) {
2516 //DWORD dwStart = timeGetTime();
2517 int blink_time
= 500;
2520 strcpy (fileName
, fileForExt
);
2524 SString fileNameForExtension
;
2525 if(overrideExtension
.length())
2526 fileNameForExtension
= overrideExtension
;
2528 fileNameForExtension
= fileForExt
;
2531 language
= props
->GetNewExpand("lexer.", fileNameForExtension
.c_str());
2532 SendEditorString(SCI_SETLEXERLANGUAGE
, 0, language
.c_str());
2533 lexLanguage
= SendEditor(SCI_GETLEXER
);
2535 if ((lexLanguage
== SCLEX_HTML
) || (lexLanguage
== SCLEX_XML
))
2536 SendEditor(SCI_SETSTYLEBITS
, 7);
2538 SendEditor(SCI_SETSTYLEBITS
, 5);
2540 SendEditor(SCI_SETLEXER
, lexLanguage
);
2542 SString kw0
= props
->GetNewExpand("keywords.", fileNameForExtension
.c_str());
2543 SendEditorString(SCI_SETKEYWORDS
, 0, kw0
.c_str());
2544 SString kw2
= props
->GetNewExpand("keywords3.", fileNameForExtension
.c_str());
2545 SendEditorString(SCI_SETKEYWORDS
, 2, kw2
.c_str());
2546 /* For C/C++ projects, get list of typedefs for colorizing */
2547 if (SCLEX_CPP
== lexLanguage
)
2549 SString kw1
= props
->GetNewExpand("keywords2.", fileNameForExtension
.c_str());
2550 SString kw3
= props
->GetNewExpand("keywords4.", fileNameForExtension
.c_str());
2551 if (typedef_hl
!= NULL
)
2553 if (typedef_hl
[0] != NULL
)
2556 kw3
+= typedef_hl
[0];
2558 if (typedef_hl
[1] != NULL
)
2561 kw1
+= typedef_hl
[1];
2564 SendEditorString(SCI_SETKEYWORDS
, 3, kw3
.c_str());
2565 SendEditorString(SCI_SETKEYWORDS
, 1, kw1
.c_str());
2569 SString kw1
= props
->GetNewExpand("keywords2.", fileNameForExtension
.c_str());
2570 SendEditorString(SCI_SETKEYWORDS
, 1, kw1
.c_str());
2571 SString kw3
= props
->GetNewExpand("keywords4.", fileNameForExtension
.c_str());
2572 SendEditorString(SCI_SETKEYWORDS
, 3, kw3
.c_str());
2573 SString kw4
= props
->GetNewExpand("keywords5.", fileNameForExtension
.c_str());
2574 SendEditorString(SCI_SETKEYWORDS
, 4, kw4
.c_str());
2575 SString kw5
= props
->GetNewExpand("keywords6.", fileNameForExtension
.c_str());
2576 SendEditorString(SCI_SETKEYWORDS
, 5, kw5
.c_str());
2579 ForwardPropertyToEditor("fold");
2580 ForwardPropertyToEditor("fold.use.plus");
2581 ForwardPropertyToEditor("fold.comment");
2582 ForwardPropertyToEditor("fold.comment.python");
2583 ForwardPropertyToEditor("fold.compact");
2584 ForwardPropertyToEditor("fold.html");
2585 ForwardPropertyToEditor("fold.preprocessor");
2586 ForwardPropertyToEditor("fold.quotes.python");
2587 ForwardPropertyToEditor("styling.within.preprocessor");
2588 ForwardPropertyToEditor("tab.timmy.whinge.level");
2589 ForwardPropertyToEditor("asp.default.language");
2591 // codePage = props->GetInt("code.page");
2592 //if (unicodeMode != uni8Bit) {
2593 // Override properties file to ensure Unicode displayed.
2594 // codePage = SC_CP_UTF8;
2596 // SendEditor(SCI_SETCODEPAGE, codePage);
2598 // Use unicode everytime.
2599 SendEditor(SCI_SETCODEPAGE
, SC_CP_UTF8
);
2601 characterSet
= props
->GetInt("character.set");
2602 setlocale(LC_CTYPE
, props
->Get("LC_CTYPE").c_str());
2604 SendEditor(SCI_SETCARETFORE
,
2605 ColourOfProperty(props
, "caret.fore", ColourDesired(0, 0, 0)));
2606 SendEditor(SCI_SETCARETWIDTH
, props
->GetInt("caret.width", 1));
2607 SendEditor(SCI_SETMOUSEDWELLTIME
, props
->GetInt("dwell.period", 750), 0);
2609 SString caretLineBack
= props
->Get("caret.line.back");
2610 if (caretLineBack
.length()) {
2611 SendEditor(SCI_SETCARETLINEVISIBLE
, 1);
2612 SendEditor(SCI_SETCARETLINEBACK
,
2613 ColourFromString(caretLineBack
.c_str()).AsLong());
2615 SendEditor(SCI_SETCARETLINEVISIBLE
, 0);
2618 SString controlCharSymbol
= props
->Get("control.char.symbol");
2619 if (controlCharSymbol
.length()) {
2620 SendEditor(SCI_SETCONTROLCHARSYMBOL
, static_cast<unsigned char>(controlCharSymbol
[0]));
2622 SendEditor(SCI_SETCONTROLCHARSYMBOL
, 0);
2625 SendEditor(SCI_CALLTIPSETBACK
,
2626 ColourOfProperty(props
, "calltip.back", ColourDesired(0xff, 0xff, 0xff)));
2628 SString caretPeriod
= props
->Get("caret.period");
2629 if (caretPeriod
.length()) {
2630 blink_time
= caretPeriod
.value();
2633 GtkSettings
*settings
= gtk_settings_get_default();
2636 g_object_get(G_OBJECT (settings
),
2637 "gtk-cursor-blink", &blink
,
2638 "gtk-cursor-blink-time", &blink_time
,
2641 if (!blink
) blink_time
= 0;
2643 SendEditor(SCI_SETCARETPERIOD
, blink_time
);
2645 int caretSlop
= props
->GetInt("caret.policy.xslop", 1) ? CARET_SLOP
: 0;
2646 int caretZone
= props
->GetInt("caret.policy.width", 50);
2647 int caretStrict
= props
->GetInt("caret.policy.xstrict") ? CARET_STRICT
: 0;
2648 int caretEven
= props
->GetInt("caret.policy.xeven", 1) ? CARET_EVEN
: 0;
2649 int caretJumps
= props
->GetInt("caret.policy.xjumps") ? CARET_JUMPS
: 0;
2650 SendEditor(SCI_SETXCARETPOLICY
, caretStrict
| caretSlop
| caretEven
| caretJumps
, caretZone
);
2652 caretSlop
= props
->GetInt("caret.policy.yslop", 1) ? CARET_SLOP
: 0;
2653 caretZone
= props
->GetInt("caret.policy.lines");
2654 caretStrict
= props
->GetInt("caret.policy.ystrict") ? CARET_STRICT
: 0;
2655 caretEven
= props
->GetInt("caret.policy.yeven", 1) ? CARET_EVEN
: 0;
2656 caretJumps
= props
->GetInt("caret.policy.yjumps") ? CARET_JUMPS
: 0;
2657 SendEditor(SCI_SETYCARETPOLICY
, caretStrict
| caretSlop
| caretEven
| caretJumps
, caretZone
);
2659 int visibleStrict
= props
->GetInt("visible.policy.strict") ? VISIBLE_STRICT
: 0;
2660 int visibleSlop
= props
->GetInt("visible.policy.slop", 1) ? VISIBLE_SLOP
: 0;
2661 int visibleLines
= props
->GetInt("visible.policy.lines");
2662 SendEditor(SCI_SETVISIBLEPOLICY
, visibleStrict
| visibleSlop
, visibleLines
);
2664 SendEditor(SCI_SETEDGECOLUMN
, props
->GetInt("edge.column", 0));
2665 SendEditor(SCI_SETEDGEMODE
, props
->GetInt("edge.mode", EDGE_NONE
));
2666 SendEditor(SCI_SETEDGECOLOUR
,
2667 ColourOfProperty(props
, "edge.colour", ColourDesired(0xff, 0xda, 0xda)));
2669 SString selfore
= props
->Get("selection.fore");
2670 if (selfore
.length()) {
2671 SendEditor(SCI_SETSELFORE
, 1, ColourFromString(selfore
.c_str()).AsLong());
2673 SendEditor(SCI_SETSELFORE
, 0, 0);
2675 SString selBack
= props
->Get("selection.back");
2676 if (selBack
.length()) {
2677 SendEditor(SCI_SETSELBACK
, 1, ColourFromString(selBack
.c_str()).AsLong());
2679 if (selfore
.length())
2680 SendEditor(SCI_SETSELBACK
, 0, 0);
2681 else // Have to show selection somehow
2682 SendEditor(SCI_SETSELBACK
, 1, ColourDesired(0xC0, 0xC0, 0xC0).AsLong());
2685 SString whitespaceFore
= props
->Get("whitespace.fore");
2686 if (whitespaceFore
.length()) {
2687 SendEditor(SCI_SETWHITESPACEFORE
, 1, ColourFromString(whitespaceFore
.c_str()).AsLong());
2689 SendEditor(SCI_SETWHITESPACEFORE
, 0, 0);
2691 SString whitespaceBack
= props
->Get("whitespace.back");
2692 if (whitespaceBack
.length()) {
2693 SendEditor(SCI_SETWHITESPACEBACK
, 1, ColourFromString(whitespaceBack
.c_str()).AsLong());
2695 SendEditor(SCI_SETWHITESPACEBACK
, 0, 0);
2698 for (int i
= 0; i
< 3; i
++) {
2701 long default_indic_type
[] = {INDIC_TT
, INDIC_DIAGONAL
, INDIC_SQUIGGLE
};
2702 const char *default_indic_color
[] = {"0000FF", "#00FF00", "#FF0000"};
2704 sprintf(key
, "indicator.%d.style", i
);
2706 value_str
= props
->Get(key
);
2707 if (value_str
.length() > 0) {
2708 if (strcasecmp (value_str
.c_str(), "underline-plain") == 0) {
2709 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_PLAIN
);
2710 } else if (strcasecmp (value_str
.c_str(), "underline-tt") == 0) {
2711 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_TT
);
2712 } else if (strcasecmp (value_str
.c_str(), "underline-squiggle") == 0) {
2713 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_SQUIGGLE
);
2714 } else if (strcasecmp (value_str
.c_str(), "strike-out") == 0) {
2715 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_STRIKE
);
2716 } else if (strcasecmp (value_str
.c_str(), "diagonal") == 0) {
2717 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_DIAGONAL
);
2718 } else if (strcasecmp (value_str
.c_str(), "hidden") == 0) {
2719 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_HIDDEN
);
2720 } else if (strcasecmp (value_str
.c_str(), "box") == 0) {
2721 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_BOX
);
2722 } else if (strcasecmp (value_str
.c_str(), "roundbox") == 0) {
2723 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_ROUNDBOX
);
2724 } else if (strcasecmp (value_str
.c_str(), "straightbox") == 0) {
2725 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_STRAIGHTBOX
);
2726 } else if (strcasecmp (value_str
.c_str(), "underline-dash") == 0) {
2727 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_DASH
);
2728 } else if (strcasecmp (value_str
.c_str(), "underline-dots") == 0) {
2729 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_DOTS
);
2730 } else if (strcasecmp (value_str
.c_str(), "underline-low-squiggle") == 0) {
2731 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_SQUIGGLELOW
);
2732 } else if (strcasecmp (value_str
.c_str(), "dotbox") == 0) {
2733 SendEditor(SCI_INDICSETSTYLE
, i
, INDIC_DOTBOX
);
2735 SendEditor(SCI_INDICSETSTYLE
, i
, default_indic_type
[i
]);
2738 SendEditor(SCI_INDICSETSTYLE
, i
, default_indic_type
[i
]);
2740 sprintf(key
, "indicator.%d.color", i
);
2741 value_str
= props
->GetExpanded(key
);
2742 if (value_str
.length()) {
2743 SendEditor(SCI_INDICSETFORE
, i
, ColourFromString(value_str
.c_str()).AsLong());
2745 SendEditor(SCI_INDICSETFORE
, i
, ColourFromString(default_indic_color
[i
]).AsLong());
2748 sprintf(key
, "indicator.%d.under", i
);
2749 value_str
= props
->GetExpanded(key
);
2750 if (value_str
.length()) {
2751 SendEditor(SCI_INDICSETUNDER
, i
, props
->GetInt(key
));
2754 sprintf(key
, "indicator.%d.alpha", i
);
2755 value_str
= props
->GetExpanded(key
);
2756 if (value_str
.length()) {
2757 SendEditor(SCI_INDICSETALPHA
, i
, props
->GetInt(key
));
2761 char bracesStyleKey
[200];
2762 sprintf(bracesStyleKey
, "braces.%s.style", language
.c_str());
2763 bracesStyle
= props
->GetInt(bracesStyleKey
, 0);
2768 sval
= FindLanguageProperty("calltip.*.ignorecase");
2769 callTipIgnoreCase
= sval
== "1";
2771 calltipWordCharacters
= FindLanguageProperty("calltip.*.word.characters",
2772 "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
2774 calltipEndDefinition
= FindLanguageProperty("calltip.*.end.definition");
2776 sprintf(key
, "autocomplete.%s.start.characters", language
.c_str());
2777 autoCompleteStartCharacters
= props
->GetExpanded(key
);
2778 if (autoCompleteStartCharacters
== "")
2779 autoCompleteStartCharacters
= props
->GetExpanded("autocomplete.*.start.characters");
2780 // "" is a quite reasonable value for this setting
2782 sprintf(key
, "autocomplete.%s.fillups", language
.c_str());
2783 autoCompleteFillUpCharacters
= props
->GetExpanded(key
);
2784 if (autoCompleteFillUpCharacters
== "")
2785 autoCompleteFillUpCharacters
=
2786 props
->GetExpanded("autocomplete.*.fillups");
2787 SendEditorString(SCI_AUTOCSETFILLUPS
, 0,
2788 autoCompleteFillUpCharacters
.c_str());
2790 sprintf(key
, "autocomplete.%s.ignorecase", "*");
2791 sval
= props
->GetNewExpand(key
, "");
2792 autoCompleteIgnoreCase
= sval
== "1";
2793 sprintf(key
, "autocomplete.%s.ignorecase", language
.c_str());
2794 sval
= props
->GetNewExpand(key
, "");
2796 autoCompleteIgnoreCase
= sval
== "1";
2797 SendEditor(SCI_AUTOCSETIGNORECASE
, autoCompleteIgnoreCase
? 1 : 0);
2799 int autoCChooseSingle
= props
->GetInt("autocomplete.choose.single");
2800 SendEditor(SCI_AUTOCSETCHOOSESINGLE
, autoCChooseSingle
),
2802 SendEditor(SCI_AUTOCSETCANCELATSTART
, 0),
2803 SendEditor(SCI_AUTOCSETDROPRESTOFWORD
, 0),
2806 // For each window set the global default style,
2807 // then the language default style,
2808 // then the other global styles,
2809 // then the other language styles
2813 if (firstPropertiesRead
) {
2814 ReadPropertiesInitial();
2817 /* Gtk handles it correctly */
2818 SendEditor(SCI_SETPRINTMAGNIFICATION
, props
->GetInt("print.magnification"));
2819 SendEditor(SCI_SETPRINTCOLOURMODE
, props
->GetInt("print.colour.mode"));
2821 int blankMarginLeft
= props
->GetInt("blank.margin.left", 1);
2822 int blankMarginRight
= props
->GetInt("blank.margin.right", 1);
2823 SendEditor(SCI_SETMARGINLEFT
, 0, blankMarginLeft
);
2824 SendEditor(SCI_SETMARGINRIGHT
, 0, blankMarginRight
);
2826 SendEditor(SCI_SETMARGINWIDTHN
, 1, margin
? marginWidth
: 0);
2827 SendEditor(SCI_SETMARGINWIDTHN
, 0, lineNumbers
?lineNumbersWidth
: 0);
2829 bufferedDraw
= props
->GetInt("buffered.draw", 1);
2830 SendEditor(SCI_SETBUFFEREDDRAW
, bufferedDraw
);
2832 SendEditor(SCI_SETLAYOUTCACHE
, props
->GetInt("cache.layout"));
2834 bracesCheck
= props
->GetInt("braces.check");
2835 bracesSloppy
= props
->GetInt("braces.sloppy");
2837 wordCharacters
= props
->GetNewExpand("word.characters.", fileNameForExtension
.c_str());
2838 if (wordCharacters
.length()) {
2839 SendEditorString(SCI_SETWORDCHARS
, 0, wordCharacters
.c_str());
2841 SendEditor(SCI_SETWORDCHARS
, 0, 0);
2842 wordCharacters
= "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2845 // SendEditor(SCI_MARKERDELETEALL, static_cast<unsigned long>( -1));
2847 SendEditor(SCI_SETTABINDENTS
, props
->GetInt("tab.indents", 1));
2848 SendEditor(SCI_SETBACKSPACEUNINDENTS
, props
->GetInt("backspace.unindents", 1));
2850 SendEditor(SCI_SETUSETABS
, props
->GetInt("use.tabs", 1));
2851 int tabSize
= props
->GetInt("tabsize");
2853 SendEditor(SCI_SETTABWIDTH
, tabSize
);
2855 indentSize
= props
->GetInt("indent.size");
2856 SendEditor(SCI_SETINDENT
, indentSize
);
2858 indentOpening = props->GetInt("indent.opening");
2859 indentClosing = props->GetInt("indent.closing");
2861 indentMaintain
= props
->GetNewExpand("indent.maintain.", fileNameForExtension
.c_str()).value();
2863 SString lookback = props->GetNewExpand("statement.lookback.", fileNameForExtension.c_str());
2864 statementLookback = lookback.value();
2865 statementIndent = GetStyleAndWords("statement.indent.");
2866 statementEnd =GetStyleAndWords("statement.end.");
2867 blockStart = GetStyleAndWords("block.start.");
2868 blockEnd = GetStyleAndWords("block.end.");
2873 list = props->GetNewExpand("preprocessor.symbol.", fileNameForExtension.c_str());
2874 preprocessorSymbol = list[0];
2875 list = props->GetNewExpand("preprocessor.start.", fileNameForExtension.c_str());
2876 preprocCondStart.Clear();
2877 preprocCondStart.Set(list.c_str());
2878 list = props->GetNewExpand("preprocessor.middle.", fileNameForExtension.c_str());
2879 preprocCondMiddle.Clear();
2880 preprocCondMiddle.Set(list.c_str());
2881 list = props->GetNewExpand("preprocessor.end.", fileNameForExtension.c_str());
2882 preprocCondEnd.Clear();
2883 preprocCondEnd.Set(list.c_str());
2886 if (props
->GetInt("vc.home.key", 1)) {
2887 AssignKey(SCK_HOME
, 0, SCI_VCHOME
);
2888 AssignKey(SCK_HOME
, SCMOD_SHIFT
, SCI_VCHOMEEXTEND
);
2890 AssignKey(SCK_HOME
, 0, SCI_HOME
);
2891 AssignKey(SCK_HOME
, SCMOD_SHIFT
, SCI_HOMEEXTEND
);
2893 if (props
->GetInt("fold.underline"))
2894 SendEditor(SCI_SETFOLDFLAGS
, props
->GetInt("fold.flags"));
2896 SendEditor(SCI_SETFOLDFLAGS
, 0);
2898 // To put the folder markers in the line number region
2899 //SendEditor(SCI_SETMARGINMASKN, 0, SC_MASK_FOLDERS);
2901 SendEditor(SCI_SETMODEVENTMASK
, SC_MOD_CHANGEFOLD
);
2903 if (0==props
->GetInt("undo.redo.lazy")) {
2904 // Trap for insert/delete notifications (also fired by undo
2905 // and redo) so that the buttons can be enabled if needed.
2906 SendEditor(SCI_SETMODEVENTMASK
, SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
2907 | SC_LASTSTEPINUNDOREDO
| SendEditor(SCI_GETMODEVENTMASK
, 0));
2909 //SC_LASTSTEPINUNDOREDO is probably not needed in the mask; it
2910 //doesn't seem to fire as an event of its own; just modifies the
2911 //insert and delete events.
2914 // Create a margin column for the folding symbols
2915 SendEditor(SCI_SETMARGINTYPEN
, 2, SC_MARGIN_SYMBOL
);
2917 SendEditor(SCI_SETMARGINWIDTHN
, 2, foldMargin
? foldMarginWidth
: 0);
2919 SendEditor(SCI_SETMARGINMASKN
, 2, SC_MASK_FOLDERS
);
2920 SendEditor(SCI_SETMARGINSENSITIVEN
, 1, 1); // Breakpoints-Bookmarks
2921 SendEditor(SCI_SETMARGINSENSITIVEN
, 2, 1);
2923 SString fold_symbols
= props
->Get("fold.symbols");
2924 SetFoldSymbols (fold_symbols
);
2926 // Well, unlike scite, we want it everytime.
2927 firstPropertiesRead
= true;
2930 void AnEditor::SetFoldSymbols(SString fold_symbols
)
2932 if (fold_symbols
.length() <= 0)
2933 fold_symbols
= "plus/minus";
2934 if (strcasecmp(fold_symbols
.c_str(), "arrows") == 0)
2936 // Arrow pointing right for contracted folders, arrow pointing down for expanded
2937 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_ARROWDOWN
, Colour(0, 0, 0), Colour(0, 0, 0));
2938 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_ARROW
, Colour(0, 0, 0), Colour(0, 0, 0));
2939 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_EMPTY
, Colour(0, 0, 0), Colour(0, 0, 0));
2940 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_EMPTY
, Colour(0, 0, 0), Colour(0, 0, 0));
2941 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2942 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2943 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2944 } else if (strcasecmp(fold_symbols
.c_str(), "circular") == 0) {
2945 // Like a flattened tree control using circular headers and curved joins
2946 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_CIRCLEMINUS
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2947 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_CIRCLEPLUS
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2948 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_VLINE
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2949 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_LCORNERCURVE
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2950 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_CIRCLEPLUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2951 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_CIRCLEMINUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2952 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_TCORNERCURVE
, Colour(0xff, 0xff, 0xff), Colour(0x40, 0x40, 0x40));
2953 } else if (strcasecmp(fold_symbols
.c_str(), "squares") == 0) {
2954 // Like a flattened tree control using square headers
2955 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_BOXMINUS
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2956 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_BOXPLUS
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2957 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_VLINE
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2958 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_LCORNER
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2959 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_BOXPLUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2960 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_BOXMINUSCONNECTED
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2961 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_TCORNER
, Colour(0xff, 0xff, 0xff), Colour(0x80, 0x80, 0x80));
2963 // Plus for contracted folders, minus for expanded
2964 DefineMarker(SC_MARKNUM_FOLDEROPEN
, SC_MARK_MINUS
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2965 DefineMarker(SC_MARKNUM_FOLDER
, SC_MARK_PLUS
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2966 DefineMarker(SC_MARKNUM_FOLDERSUB
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2967 DefineMarker(SC_MARKNUM_FOLDERTAIL
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2968 DefineMarker(SC_MARKNUM_FOLDEREND
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2969 DefineMarker(SC_MARKNUM_FOLDEROPENMID
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2970 DefineMarker(SC_MARKNUM_FOLDERMIDTAIL
, SC_MARK_EMPTY
, Colour(0xff, 0xff, 0xff), Colour(0, 0, 0));
2974 // Anjuta: In our case, we read it everytime
2975 void AnEditor::ReadPropertiesInitial() {
2976 indentationWSVisible
= props
->GetInt("view.indentation.whitespace", 1);
2978 ViewWhitespace(props
->GetInt(VIEW_WHITE_SPACES
));
2979 SendEditor(SCI_SETINDENTATIONGUIDES
, props
->GetInt(VIEW_INDENTATION_GUIDES
));
2980 SendEditor(SCI_SETVIEWEOL
, props
->GetInt(VIEW_EOL
));
2982 SetReadOnly(props
->GetInt("file.readonly", 0));
2983 SetLineWrap(props
->GetInt(VIEW_LINE_WRAP
, 1));
2985 //lineNumbersWidth = 0;
2986 /* FIXME: This is nowhere configureable
2987 SString linenums = props->Get("margin.linenumber.width");
2988 if (linenums.length())
2989 lineNumbersWidth = linenums.value(); */
2990 //lineNumbers = lineNumbersWidth;
2991 /* We do this dynamicly in text_editor_load_file now */
2992 /* if (lineNumbersWidth == 0)
2993 lineNumbersWidth = lineNumbersWidthDefault;*/
2996 SString margwidth
= props
->Get("margin.marker.width");
2997 if (margwidth
.length())
2998 marginWidth
= margwidth
.value();
2999 margin
= marginWidth
;
3000 if (marginWidth
== 0)
3001 marginWidth
= marginWidthDefault
;
3003 foldMarginWidth
= props
->GetInt("margin.fold.width", foldMarginWidthDefault
);
3004 foldMargin
= foldMarginWidth
;
3005 if (foldMarginWidth
== 0)
3006 foldMarginWidth
= foldMarginWidthDefault
;
3008 lineNumbers
= props
->GetInt(VIEW_LINENUMBERS_MARGIN
, 0);
3009 margin
= props
->GetInt(VIEW_MARKER_MARGIN
, 0);
3010 foldMargin
= props
->GetInt(VIEW_FOLD_MARGIN
, 1);
3013 void AnEditor::DefineMarker(int marker
, int markerType
, Colour fore
, Colour back
)
3015 SendEditor(SCI_MARKERDEFINE
, marker
, markerType
);
3016 SendEditor(SCI_MARKERSETFORE
, marker
, fore
.AsLong());
3017 SendEditor(SCI_MARKERSETBACK
, marker
, back
.AsLong());
3020 int AnEditor::GetBookmarkLine( const int nLineStart
)
3022 int nNextLine
= SendEditor(SCI_MARKERNEXT
, nLineStart
+1, 1 << ANE_MARKER_BOOKMARK
);
3023 //printf( "...look %d --> %d\n", nLineStart, nNextLine );
3024 if ( (nNextLine
< 0) || (nNextLine
== nLineStart
) )
3030 void AnEditor::FocusInEvent(GtkWidget
* widget
)
3038 void AnEditor::FocusOutEvent(GtkWidget
* widget
)
3040 if (SendEditor(SCI_CALLTIPACTIVE
))
3042 SendEditor(SCI_CALLTIPCANCEL
);
3043 calltipShown
= true;
3047 calltipShown
= false;
3051 static GList
* editors
;
3054 aneditor_get(AnEditorID id
)
3057 if(id
>= g_list_length(editors
))
3059 DEBUG_PRINT("%s", "Invalid AnEditorID supplied");
3062 ed
= (AnEditor
*)g_list_nth_data(editors
, (guint
)id
);
3065 DEBUG_PRINT("%s", "Trying to use already destroyed AnEditor Object");
3072 aneditor_new(gpointer propset
)
3074 AnEditor
* ed
= new AnEditor((PropSetFile
*)propset
);
3077 DEBUG_PRINT("%s", "Memory allocation error.");
3078 return ANE_ID_INVALID
;
3080 g_signal_connect(ed
->GetID(), "focus_in_event",
3081 G_CALLBACK(on_aneditor_focus_in
), ed
);
3082 g_signal_connect(ed
->GetID(), "focus_out_event",
3083 G_CALLBACK(on_aneditor_focus_out
), ed
);
3084 editors
= g_list_append(editors
, ed
);
3085 return (AnEditorID
)(g_list_length(editors
) - 1);
3089 aneditor_destroy(AnEditorID id
)
3093 ed
= aneditor_get(id
);
3096 /* We will not remove the editor from the list */
3097 /* so that already assigned handles work properly */
3098 /* We'll simply make it NULL to indicate that the */
3099 /* editor is destroyed */
3100 g_list_nth(editors
, id
)->data
= NULL
;
3102 /* Disconnect the focus in/out signals */
3103 g_signal_handlers_disconnect_by_func (ed
->GetID(),
3104 (void*)G_CALLBACK(on_aneditor_focus_in
), ed
);
3105 g_signal_handlers_disconnect_by_func (ed
->GetID(),
3106 (void*)G_CALLBACK(on_aneditor_focus_out
), ed
);
3112 aneditor_get_widget(AnEditorID handle
)
3115 ed
= aneditor_get(handle
);
3116 if(!ed
) return NULL
;
3118 // Forced conversion is safe here, so do it.
3119 return (GtkWidget
*)ed
->GetID();
3123 aneditor_command(AnEditorID handle
, gint command
, glong wparam
, glong lparam
)
3126 ed
= aneditor_get(handle
);
3128 return ed
->Command(command
, wparam
, lparam
);
3132 aneditor_set_focused_ed_ID(AnEditorID id
)
3134 AnEditor::focusedID
= id
;
3138 aneditor_set_parent(AnEditorID id
, AnEditorID parent_id
)
3143 editor
= aneditor_get (id
);
3144 parent
= aneditor_get (parent_id
);
3145 editor
->SetParent(parent
);
3149 on_aneditor_focus_in (GtkWidget
* widget
, gpointer
* unused
, AnEditor
* ed
)
3151 ed
->FocusInEvent(widget
);
3156 on_aneditor_focus_out (GtkWidget
* widget
, gpointer
* unused
, AnEditor
* ed
)
3158 /* ed->EndDebugEval(); */
3159 ed
->FocusOutEvent(widget
);