summaryrefslogtreecommitdiffstats
path: root/qt/qextscintilla.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-11-30 11:36:13 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-11-30 11:36:13 -0600
commit664e37abfe5c796c1279b8295fb030f126b0a7d8 (patch)
tree85f4e661e5c615f01ee1cdf51ca1250b96efe315 /qt/qextscintilla.cpp
downloadtqscintilla-664e37abfe5c796c1279b8295fb030f126b0a7d8.tar.gz
tqscintilla-664e37abfe5c796c1279b8295fb030f126b0a7d8.zip
Initial import of qscintilla from 2007
Diffstat (limited to 'qt/qextscintilla.cpp')
-rw-r--r--qt/qextscintilla.cpp3031
1 files changed, 3031 insertions, 0 deletions
diff --git a/qt/qextscintilla.cpp b/qt/qextscintilla.cpp
new file mode 100644
index 0000000..7d3290c
--- /dev/null
+++ b/qt/qextscintilla.cpp
@@ -0,0 +1,3031 @@
+// This module implements the "official" high-level API of the Qt port of
+// Scintilla. It is modelled on QTextEdit - a method of the same name should
+// behave in the same way.
+//
+// Copyright (c) 2006
+// Riverbank Computing Limited <info@riverbankcomputing.co.uk>
+//
+// This file is part of QScintilla.
+//
+// This copy of QScintilla is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option) any
+// later version.
+//
+// QScintilla is supplied in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// QScintilla; see the file LICENSE. If not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#include <string.h>
+#include <qapplication.h>
+#include <qcolor.h>
+
+#include "qextscintilla.h"
+#include "qextscintillalexer.h"
+#include "qextscintillaapis.h"
+#include "qextscintillacommandset.h"
+
+
+// Make sure these match the values in Scintilla.h. We don't #include that
+// file because it just causes more clashes.
+#define KEYWORDSET_MAX 8
+#define MARKER_MAX 31
+
+
+// The default fold margin width.
+static const int defaultFoldMarginWidth = 14;
+
+// The default set of characters that make up a word.
+static const char *defaultWordChars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+
+// The ctor.
+QextScintilla::QextScintilla(QWidget *parent,const char *name,WFlags f)
+ : QextScintillaBase(parent,name,f), allocatedMarkers(0), oldPos(-1),
+ selText(FALSE), fold(NoFoldStyle), autoInd(FALSE),
+ braceMode(NoBraceMatch), acSource(AcsDocument), acThresh(-1),
+ acStart(""), acAPIs(0), ctAPIs(0), maxCallTips(-1),
+ showSingle(FALSE), modified(FALSE), explicit_fillups(FALSE),
+ fillups_enabled(FALSE), saved_fillups("")
+{
+ connect(this,SIGNAL(SCN_MODIFYATTEMPTRO()),
+ SIGNAL(modificationAttempted()));
+
+ connect(this,SIGNAL(SCN_MODIFIED(int,int,const char *,int,int,int,int,int)),
+ SLOT(handleModified(int,int,const char *,int,int,int,int,int)));
+ connect(this,SIGNAL(SCN_CALLTIPCLICK(int)),
+ SLOT(handleCallTipClick(int)));
+ connect(this,SIGNAL(SCN_CHARADDED(int)),
+ SLOT(handleCharAdded(int)));
+ connect(this,SIGNAL(SCN_MARGINCLICK(int,int,int)),
+ SLOT(handleMarginClick(int,int,int)));
+ connect(this,SIGNAL(SCN_SAVEPOINTREACHED()),
+ SLOT(handleSavePointReached()));
+ connect(this,SIGNAL(SCN_SAVEPOINTLEFT()),
+ SLOT(handleSavePointLeft()));
+ connect(this,SIGNAL(SCN_UPDATEUI()),
+ SLOT(handleUpdateUI()));
+ connect(this,SIGNAL(QSCN_SELCHANGED(bool)),
+ SLOT(handleSelectionChanged(bool)));
+ connect(this,SIGNAL(SCN_USERLISTSELECTION(const char *,int)),
+ SLOT(handleUserListSelection(const char *,int)));
+
+ // Set the default font.
+ setFont(QApplication::font());
+
+ // Set the default fore and background colours.
+ QColorGroup cg = QApplication::palette().active();
+ setColor(cg.text());
+ setPaper(cg.base());
+
+#if defined(Q_OS_WIN)
+ setEolMode(EolWindows);
+#elif defined(Q_OS_MAC)
+ setEolMode(EolMac);
+#else
+ setEolMode(EolUnix);
+#endif
+
+ // Capturing the mouse seems to cause problems on multi-head systems.
+ // Qt should do the right thing anyway.
+ SendScintilla(SCI_SETMOUSEDOWNCAPTURES,0UL);
+
+ SendScintilla(SCI_SETPROPERTY,"fold","1");
+
+ setMatchedBraceForegroundColor(blue);
+ setUnmatchedBraceForegroundColor(red);
+
+ setLexer();
+
+ // Set the visible policy. These are the same as SciTE's defaults
+ // which, presumably, are sensible.
+ SendScintilla(SCI_SETVISIBLEPOLICY,VISIBLE_STRICT|VISIBLE_SLOP,4);
+
+ // Create the standard command set.
+ stdCmds = new QextScintillaCommandSet(this);
+
+ doc.display(this,0);
+}
+
+
+// The dtor.
+QextScintilla::~QextScintilla()
+{
+ doc.undisplay(this);
+ delete stdCmds;
+}
+
+
+// Return the current text colour.
+QColor QextScintilla::color() const
+{
+ return nl_text_colour;
+}
+
+
+// Set the text colour.
+void QextScintilla::setColor(const QColor &c)
+{
+ if (lex.isNull())
+ {
+ // Assume style 0 applies to everything so that we don't need to use
+ // SCI_STYLECLEARALL which clears everything.
+ SendScintilla(SCI_STYLESETFORE, 0, c);
+ nl_text_colour = c;
+ }
+}
+
+
+// Return the current paper colour.
+QColor QextScintilla::paper() const
+{
+ return nl_paper_colour;
+}
+
+
+// Set the paper colour.
+void QextScintilla::setPaper(const QColor &c)
+{
+ if (lex.isNull())
+ {
+ // Assume style 0 applies to everything so that we don't need to use
+ // SCI_STYLECLEARALL which clears everything. We still have to set the
+ // default style as well for the background without any text.
+ SendScintilla(SCI_STYLESETBACK, 0, c);
+ SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, c);
+ nl_paper_colour = c;
+ }
+}
+
+
+// Set the default font.
+void QextScintilla::setFont(const QFont &f)
+{
+ if (lex.isNull())
+ {
+ // Assume style 0 applies to everything so that we don't need to use
+ // SCI_STYLECLEARALL which clears everything.
+ setStylesFont(f, 0);
+ nl_font = f;
+ }
+}
+
+
+// Enable/disable auto-indent.
+void QextScintilla::setAutoIndent(bool autoindent)
+{
+ autoInd = autoindent;
+}
+
+
+// Set the brace matching mode.
+void QextScintilla::setBraceMatching(BraceMatch bm)
+{
+ braceMode = bm;
+}
+
+
+// Handle the addition of a character.
+void QextScintilla::handleCharAdded(int ch)
+{
+ // Ignore if there is a selection.
+ long pos = SendScintilla(SCI_GETSELECTIONSTART);
+
+ if (pos != SendScintilla(SCI_GETSELECTIONEND) || pos == 0)
+ return;
+
+ // If auto-completion is already active then see if this character is a
+ // start character. If it is then create a new list which will be a
+ // subset of the current one. The case where it isn't a start
+ // character seem to be handled correctly elsewhere.
+ if (isListActive())
+ {
+ if (isAutoCStartChar(ch))
+ {
+ cancelList();
+ startAutoCompletion(acSource, FALSE, FALSE);
+ }
+
+ return;
+ }
+
+ // Handle call tips.
+ if (strchr("(),", ch) != NULL)
+ callTip();
+
+ // Handle auto-indentation.
+ if (autoInd)
+ if (lex.isNull() || (lex -> autoIndentStyle() & AiMaintain))
+ maintainIndentation(ch,pos);
+ else
+ autoIndentation(ch,pos);
+
+ // See if we might want to start auto-completion.
+ if (!isCallTipActive())
+ if (isAutoCStartChar(ch))
+ startAutoCompletion(acSource, FALSE, FALSE);
+ else if (acThresh >= 1 && isWordChar(ch))
+ startAutoCompletion(acSource, TRUE, FALSE);
+}
+
+
+// See if a call tip is active.
+bool QextScintilla::isCallTipActive()
+{
+ return SendScintilla(SCI_CALLTIPACTIVE);
+}
+
+
+// Handle a possible change to any current call tip.
+void QextScintilla::callTip()
+{
+ if (!ctAPIs)
+ return;
+
+ long pos = SendScintilla(SCI_GETCURRENTPOS);
+ long linenr = SendScintilla(SCI_LINEFROMPOSITION,pos);
+ long linelen = SendScintilla(SCI_LINELENGTH,linenr);
+
+ char *lbuf = new char[linelen + 1];
+
+ int loff = SendScintilla(SCI_GETCURLINE,linelen + 1,lbuf);
+
+ int commas = 0, start = -1;
+
+ // Move backwards through the line looking for the start of the current
+ // call tip and working out which argument it is.
+ while (loff > 0)
+ {
+ char ch = lbuf[--loff];
+
+ if (ch == ',')
+ ++commas;
+ else if (ch == ')')
+ {
+ int depth = 1;
+
+ // Ignore everything back to the start of the
+ // corresponding parenthesis.
+ while (loff > 0)
+ {
+ ch = lbuf[--loff];
+
+ if (ch == ')')
+ ++depth;
+ else if (ch == '(' && --depth == 0)
+ break;
+ }
+ }
+ else if (ch == '(' && loff > 0)
+ {
+ if (isWordChar(lbuf[loff - 1]))
+ {
+ // The parenthesis is preceded by a word so
+ // find the start of that word.
+ lbuf[loff--] = '\0';
+
+ while (loff >= 0)
+ {
+ if (!isWordChar(lbuf[loff]) && !isAutoCStartChar(lbuf[loff]))
+ break;
+
+ --loff;
+ }
+
+ start = loff + 1;
+ break;
+ }
+
+ // We are between parentheses that do not correspond to
+ // a call tip, so reset the argument count.
+ commas = 0;
+ }
+ }
+
+ // Cancel any existing call tip.
+ SendScintilla(SCI_CALLTIPCANCEL);
+
+ // Done if there is no new call tip to set.
+ if (start < 0)
+ {
+ delete []lbuf;
+ return;
+ }
+
+ QString ct = ctAPIs -> callTips(&lbuf[start],maxCallTips,commas);
+
+ delete []lbuf;
+
+ if (ct.isEmpty())
+ return;
+
+ ctpos = SendScintilla(SCI_POSITIONFROMLINE,linenr) + start;
+
+ SendScintilla(SCI_CALLTIPSHOW,ctpos,ct.latin1());
+
+ // Done if there is more than one line in the call tip or there isn't a
+ // down arrow at the start.
+ if (ct[0] == '\002' || ct.find('\n') >= 0)
+ return;
+
+ // Highlight the current argument.
+ int astart;
+
+ if (commas == 0)
+ astart = ct.find('(');
+ else
+ {
+ astart = -1;
+
+ do
+ astart = ct.find(',',astart + 1);
+ while (astart >= 0 && --commas > 0);
+ }
+
+ int len = ct.length();
+
+ if (astart < 0 || ++astart == len)
+ return;
+
+ // The end is at the next comma or unmatched closing parenthesis.
+ int aend, depth = 0;
+
+ for (aend = astart; aend < len; ++aend)
+ {
+ QChar ch = ct.at(aend);
+
+ if (ch == ',' && depth == 0)
+ break;
+ else if (ch == '(')
+ ++depth;
+ else if (ch == ')')
+ {
+ if (depth == 0)
+ break;
+
+ --depth;
+ }
+ }
+
+ if (astart != aend)
+ SendScintilla(SCI_CALLTIPSETHLT,astart,aend);
+}
+
+
+// Handle a call tip click.
+void QextScintilla::handleCallTipClick(int dir)
+{
+ if (!ctAPIs)
+ return;
+
+ QString ct = ctAPIs -> callTipsNextPrev(dir);
+
+ if (ct.isNull())
+ return;
+
+ SendScintilla(SCI_CALLTIPSHOW,ctpos,ct.latin1());
+}
+
+
+// Possibly start auto-completion.
+void QextScintilla::startAutoCompletion(AutoCompletionSource acs,
+ bool checkThresh, bool single)
+{
+ // Get the current line.
+ long len = SendScintilla(SCI_GETCURLINE) + 1;
+
+ char *line = new char[len];
+
+ int wend = SendScintilla(SCI_GETCURLINE, len, line);
+
+ // Find the start of the auto-completion text.
+ int wstart = wend;
+ bool numeric = true;
+
+ while (wstart > 0)
+ {
+ char ch = line[wstart - 1];
+
+ // Don't auto-complete numbers.
+ if (ch < '0' || ch > '9')
+ numeric = false;
+
+ if (!isWordChar(ch) && !isAutoCStartChar(ch))
+ break;
+
+ --wstart;
+ }
+
+ int wlen = wend - wstart;
+
+ if (numeric || wlen == 0 || (checkThresh && wlen < acThresh))
+ return;
+
+ // Isolate the auto-completion text.
+ char *word = &line[wstart];
+ line[wend] = '\0';
+
+ // Generate the string representing the valid words to select from.
+ QStringList wlist;
+ bool cs = !SendScintilla(SCI_AUTOCGETIGNORECASE);
+
+ if (acs == AcsAll || acs == AcsDocument)
+ {
+ SendScintilla(SCI_SETSEARCHFLAGS,SCFIND_WORDSTART | (cs ? SCFIND_MATCHCASE : 0));
+
+ long pos = 0;
+ long dlen = SendScintilla(SCI_GETLENGTH);
+ long caret = SendScintilla(SCI_GETCURRENTPOS);
+ QString root(word);
+
+ for (;;)
+ {
+ long fstart;
+
+ SendScintilla(SCI_SETTARGETSTART,pos);
+ SendScintilla(SCI_SETTARGETEND,dlen);
+
+ if ((fstart = SendScintilla(SCI_SEARCHINTARGET,wlen,word)) < 0)
+ break;
+
+ // Move past the root part.
+ pos = fstart + wlen;
+
+ // Skip if this is the word we are auto-completing.
+ if (pos == caret)
+ continue;
+
+ // Get the rest of this word.
+ QString w(root);
+
+ while (pos < dlen)
+ {
+ char ch = SendScintilla(SCI_GETCHARAT,pos);
+
+ if (!isWordChar(ch))
+ break;
+
+ w += ch;
+
+ ++pos;
+ }
+
+ // Add the word if it isn't already there.
+ if (wlist.findIndex(w) < 0)
+ wlist.append(w);
+ }
+ }
+
+ if ((acs == AcsAll || acs == AcsAPIs) && acAPIs)
+ acAPIs->autoCompletionList(word, cs, wlist);
+
+ delete []line;
+
+ if (wlist.isEmpty())
+ return;
+
+ wlist.sort();
+
+ const char sep = '\x03';
+
+ SendScintilla(SCI_AUTOCSETCHOOSESINGLE,single);
+ SendScintilla(SCI_AUTOCSETSEPARATOR, sep);
+ SendScintilla(SCI_AUTOCSHOW, wlen, wlist.join(QChar(sep)).latin1());
+}
+
+
+// Check if a character is an auto-completion start character.
+bool QextScintilla::isAutoCStartChar(char ch) const
+{
+ const char *start_chars = 0;
+
+ if (!lex.isNull())
+ start_chars = lex->autoCompletionStartCharacters();
+
+ if (!start_chars)
+ start_chars = acStart;
+
+ return (strchr(start_chars, ch) != NULL);
+}
+
+
+// Maintain the indentation of the previous line.
+void QextScintilla::maintainIndentation(char ch,long pos)
+{
+ if (ch != '\r' && ch != '\n')
+ return;
+
+ int curr_line = SendScintilla(SCI_LINEFROMPOSITION,pos);
+
+ // Get the indentation of the preceding non-zero length line.
+ int ind = 0;
+
+ for (int line = curr_line - 1; line >= 0; --line)
+ {
+ if (SendScintilla(SCI_GETLINEENDPOSITION,line) >
+ SendScintilla(SCI_POSITIONFROMLINE,line))
+ {
+ ind = indentation(line);
+ break;
+ }
+ }
+
+ if (ind > 0)
+ autoIndentLine(pos,curr_line,ind);
+}
+
+
+// Implement auto-indentation.
+void QextScintilla::autoIndentation(char ch,long pos)
+{
+ int curr_line = SendScintilla(SCI_LINEFROMPOSITION,pos);
+ int ind_width = indentationWidth();
+ long curr_line_start = SendScintilla(SCI_POSITIONFROMLINE,curr_line);
+
+ const char *block_start = lex -> blockStart();
+ bool start_single = (block_start && strlen(block_start) == 1);
+
+ const char *block_end = lex -> blockEnd();
+ bool end_single = (block_end && strlen(block_end) == 1);
+
+ if (end_single && block_end[0] == ch)
+ {
+ if ((lex -> autoIndentStyle() & AiClosing) && rangeIsWhitespace(curr_line_start,pos - 1))
+ autoIndentLine(pos,curr_line,blockIndent(curr_line - 1) - indentationWidth());
+ }
+ else if (start_single && block_start[0] == ch)
+ {
+ // De-indent if we have already indented because the previous
+ // line was a start of block keyword.
+ if ((lex->autoIndentStyle() & AiOpening) && curr_line > 0 && getIndentState(curr_line - 1) == isKeywordStart && rangeIsWhitespace(curr_line_start, pos - 1))
+ autoIndentLine(pos,curr_line,blockIndent(curr_line - 1) - indentationWidth());
+ }
+ else if (ch == '\r' || ch == '\n')
+ autoIndentLine(pos,curr_line,blockIndent(curr_line - 1));
+}
+
+
+// Set the indentation for a line.
+void QextScintilla::autoIndentLine(long pos,int line,int indent)
+{
+ if (indent < 0)
+ return;
+
+ long pos_before = SendScintilla(SCI_GETLINEINDENTPOSITION,line);
+ SendScintilla(SCI_SETLINEINDENTATION,line,indent);
+ long pos_after = SendScintilla(SCI_GETLINEINDENTPOSITION,line);
+ long new_pos = -1;
+
+ if (pos_after > pos_before)
+ new_pos = pos + (pos_after - pos_before);
+ else if (pos_after < pos_before && pos >= pos_after)
+ if (pos >= pos_before)
+ new_pos = pos + (pos_after - pos_before);
+ else
+ new_pos = pos_after;
+
+ if (new_pos >= 0)
+ SendScintilla(SCI_SETSEL,new_pos,new_pos);
+}
+
+
+// Return the indentation of the block defined by the given line (or something
+// significant before).
+int QextScintilla::blockIndent(int line)
+{
+ if (line < 0)
+ return 0;
+
+ // Handle the trvial case.
+ if (!lex -> blockStartKeyword() && !lex -> blockStart() && !lex -> blockEnd())
+ return indentation(line);
+
+ int line_limit = line - lex -> blockLookback();
+
+ if (line_limit < 0)
+ line_limit = 0;
+
+ for (int l = line; l >= line_limit; --l)
+ {
+ IndentState istate = getIndentState(l);
+
+ if (istate != isNone)
+ {
+ int ind_width = indentationWidth();
+ int ind = indentation(l);
+
+ if (istate == isBlockStart)
+ {
+ if (lex -> autoIndentStyle() & AiOpening)
+ ind += ind_width;
+ }
+ else if (istate == isBlockEnd)
+ {
+ if (!(lex -> autoIndentStyle() & AiClosing))
+ ind -= ind_width;
+
+ if (ind < 0)
+ ind = 0;
+ }
+ else if (line == l)
+ ind += ind_width;
+
+ return ind;
+ }
+ }
+
+ return indentation(line);
+}
+
+
+// Return TRUE if all characters starting at spos up to, but not including
+// epos, are spaces or tabs.
+bool QextScintilla::rangeIsWhitespace(long spos,long epos)
+{
+ while (spos < epos)
+ {
+ char ch = SendScintilla(SCI_GETCHARAT,spos);
+
+ if (ch != ' ' && ch != '\t')
+ return FALSE;
+
+ ++spos;
+ }
+
+ return TRUE;
+}
+
+
+// Returns the indentation state of a line.
+QextScintilla::IndentState QextScintilla::getIndentState(int line)
+{
+ IndentState istate;
+
+ // Get the styled text.
+ long spos = SendScintilla(SCI_POSITIONFROMLINE,line);
+ long epos = SendScintilla(SCI_POSITIONFROMLINE,line + 1);
+
+ char *text = new char[(epos - spos + 1) * 2];
+
+ SendScintilla(SCI_GETSTYLEDTEXT,spos,epos,text);
+
+ int style, bstart_off, bend_off;
+
+ // Block start/end takes precedence over keywords.
+ const char *bstart_words = lex->blockStart(&style);
+ bstart_off = findStyledWord(text, style, bstart_words);
+
+ const char *bend_words = lex->blockEnd(&style);
+ bend_off = findStyledWord(text, style, bend_words);
+
+ // If there is a block start but no block end characters then ignore it
+ // unless the block start is the last significant thing on the line,
+ // ie. assume Python-like blocking.
+ if (bstart_off >= 0 && !bend_words)
+ for (int i = bstart_off * 2; text[i] != '\0'; i += 2)
+ if (!QChar(text[i]).isSpace())
+ return isNone;
+
+ if (bstart_off > bend_off)
+ istate = isBlockStart;
+ else if (bend_off > bstart_off)
+ istate = isBlockEnd;
+ else
+ {
+ const char *words = lex->blockStartKeyword(&style);
+
+ istate = (findStyledWord(text,style,words) >= 0) ? isKeywordStart : isNone;
+ }
+
+ delete[] text;
+
+ return istate;
+}
+
+
+// text is a pointer to some styled text (ie. a character byte followed by a
+// style byte). style is a style number. words is a space separated list of
+// words. Returns the position in the text immediately after the last one of
+// the words with the style. The reason we are after the last, and not the
+// first, occurance is that we are looking for words that start and end a block
+// where the latest one is the most significant.
+int QextScintilla::findStyledWord(const char *text,int style,const char *words)
+{
+ if (!words)
+ return -1;
+
+ // Find the range of text with the style we are looking for.
+ const char *stext;
+
+ for (stext = text; stext[1] != style; stext += 2)
+ if (stext[0] == '\0')
+ return -1;
+
+ // Move to the last character.
+ const char *etext = stext;
+
+ while (etext[2] != '\0')
+ etext += 2;
+
+ // Backtrack until we find the style. There will be one.
+ while (etext[1] != style)
+ etext -= 2;
+
+ // Look for each word in turn.
+ while (words[0] != '\0')
+ {
+ // Find the end of the word.
+ const char *eword = words;
+
+ while (eword[1] != ' ' && eword[1] != '\0')
+ ++eword;
+
+ // Now search the text backwards.
+ const char *wp = eword;
+
+ for (const char *tp = etext; tp >= stext; tp -= 2)
+ {
+ if (tp[0] != wp[0] || tp[1] != style)
+ {
+ // Reset the search.
+ wp = eword;
+ continue;
+ }
+
+ // See if all the word has matched.
+ if (wp-- == words)
+ return ((tp - text) / 2) + (eword - words) + 1;
+ }
+
+ // Move to the start of the next word if there is one.
+ words = eword + 1;
+
+ if (words[0] == ' ')
+ ++words;
+ }
+
+ return -1;
+}
+
+
+// Return TRUE if the code page is UTF8.
+bool QextScintilla::isUtf8()
+{
+ return (SendScintilla(SCI_GETCODEPAGE) == SC_CP_UTF8);
+}
+
+
+// Set the code page.
+void QextScintilla::setUtf8(bool cp)
+{
+ SendScintilla(SCI_SETCODEPAGE,(cp ? SC_CP_UTF8 : 0));
+}
+
+
+// Return the end-of-line mode.
+QextScintilla::EolMode QextScintilla::eolMode()
+{
+ return (EolMode)SendScintilla(SCI_GETEOLMODE);
+}
+
+
+// Set the end-of-line mode.
+void QextScintilla::setEolMode(EolMode mode)
+{
+ SendScintilla(SCI_SETEOLMODE,mode);
+}
+
+
+// Convert the end-of-lines to a particular mode.
+void QextScintilla::convertEols(EolMode mode)
+{
+ SendScintilla(SCI_CONVERTEOLS,mode);
+}
+
+
+// Return the edge colour.
+QColor QextScintilla::edgeColor()
+{
+ long res = SendScintilla(SCI_GETEDGECOLOUR);
+
+ return QColor((int)res, ((int)(res >> 8)) & 0x00ff, ((int)(res >> 16)) & 0x00ff);
+}
+
+
+// Set the edge colour.
+void QextScintilla::setEdgeColor(const QColor &col)
+{
+ SendScintilla(SCI_SETEDGECOLOUR,col);
+}
+
+
+// Return the edge column.
+int QextScintilla::edgeColumn()
+{
+ return SendScintilla(SCI_GETEDGECOLUMN);
+}
+
+
+// Set the edge column.
+void QextScintilla::setEdgeColumn(int colnr)
+{
+ SendScintilla(SCI_SETEDGECOLUMN,colnr);
+}
+
+
+// Return the edge mode.
+QextScintilla::EdgeMode QextScintilla::edgeMode()
+{
+ return (EdgeMode)SendScintilla(SCI_GETEDGEMODE);
+}
+
+
+// Set the edge mode.
+void QextScintilla::setEdgeMode(EdgeMode mode)
+{
+ SendScintilla(SCI_SETEDGEMODE,mode);
+}
+
+
+// Return the end-of-line visibility.
+bool QextScintilla::eolVisibility()
+{
+ return SendScintilla(SCI_GETVIEWEOL);
+}
+
+
+// Set the end-of-line visibility.
+void QextScintilla::setEolVisibility(bool visible)
+{
+ SendScintilla(SCI_SETVIEWEOL,visible);
+}
+
+
+// Return the whitespace visibility.
+QextScintilla::WhitespaceVisibility QextScintilla::whitespaceVisibility()
+{
+ return (WhitespaceVisibility)SendScintilla(SCI_GETVIEWWS);
+}
+
+
+// Set the whitespace visibility.
+void QextScintilla::setWhitespaceVisibility(WhitespaceVisibility mode)
+{
+ SendScintilla(SCI_SETVIEWWS,mode);
+}
+
+
+// Return the line wrap mode.
+QextScintilla::WrapMode QextScintilla::wrapMode()
+{
+ return (WrapMode)SendScintilla(SCI_GETWRAPMODE);
+}
+
+
+// Set the line wrap mode.
+void QextScintilla::setWrapMode(WrapMode mode)
+{
+ SendScintilla(SCI_SETLAYOUTCACHE, (mode == WrapNone ? SC_CACHE_CARET : SC_CACHE_DOCUMENT));
+ SendScintilla(SCI_SETWRAPMODE, mode);
+}
+
+
+// Set the line wrap visual flags.
+void QextScintilla::setWrapVisualFlags(WrapVisualFlag eflag,
+ WrapVisualFlag sflag, int sindent)
+{
+ int flags = SC_WRAPVISUALFLAG_NONE;
+ int loc = SC_WRAPVISUALFLAGLOC_DEFAULT;
+
+ if (eflag == WrapFlagByText)
+ {
+ flags |= SC_WRAPVISUALFLAG_END;
+ loc |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT;
+ }
+ else if (eflag == WrapFlagByBorder)
+ flags |= SC_WRAPVISUALFLAG_END;
+
+ if (sflag == WrapFlagByText)
+ {
+ flags |= SC_WRAPVISUALFLAG_START;
+ loc |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT;
+ }
+ else if (sflag == WrapFlagByBorder)
+ flags |= SC_WRAPVISUALFLAG_START;
+
+ SendScintilla(SCI_SETWRAPVISUALFLAGS, flags);
+ SendScintilla(SCI_SETWRAPVISUALFLAGSLOCATION, loc);
+ SendScintilla(SCI_SETWRAPSTARTINDENT, sindent);
+}
+
+
+// Set the folding style.
+void QextScintilla::setFolding(FoldStyle folding)
+{
+ fold = folding;
+
+ if (folding == NoFoldStyle)
+ {
+ SendScintilla(SCI_SETMARGINWIDTHN,2,0L);
+ return;
+ }
+
+ int mask = SendScintilla(SCI_GETMODEVENTMASK);
+ SendScintilla(SCI_SETMODEVENTMASK,mask | SC_MOD_CHANGEFOLD);
+
+ SendScintilla(SCI_SETFOLDFLAGS,SC_FOLDFLAG_LINEAFTER_CONTRACTED);
+
+ SendScintilla(SCI_SETMARGINTYPEN,2,(long)SC_MARGIN_SYMBOL);
+ SendScintilla(SCI_SETMARGINMASKN,2,SC_MASK_FOLDERS);
+ SendScintilla(SCI_SETMARGINSENSITIVEN,2,1);
+
+ // Set the marker symbols to use.
+ switch (folding)
+ {
+ case PlainFoldStyle:
+ setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_MINUS);
+ setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_PLUS);
+ setFoldMarker(SC_MARKNUM_FOLDERSUB);
+ setFoldMarker(SC_MARKNUM_FOLDERTAIL);
+ setFoldMarker(SC_MARKNUM_FOLDEREND);
+ setFoldMarker(SC_MARKNUM_FOLDEROPENMID);
+ setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL);
+
+ break;
+
+ case CircledFoldStyle:
+ setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_CIRCLEMINUS);
+ setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_CIRCLEPLUS);
+ setFoldMarker(SC_MARKNUM_FOLDERSUB);
+ setFoldMarker(SC_MARKNUM_FOLDERTAIL);
+ setFoldMarker(SC_MARKNUM_FOLDEREND);
+ setFoldMarker(SC_MARKNUM_FOLDEROPENMID);
+ setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL);
+
+ break;
+
+ case BoxedFoldStyle:
+ setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_BOXMINUS);
+ setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_BOXPLUS);
+ setFoldMarker(SC_MARKNUM_FOLDERSUB);
+ setFoldMarker(SC_MARKNUM_FOLDERTAIL);
+ setFoldMarker(SC_MARKNUM_FOLDEREND);
+ setFoldMarker(SC_MARKNUM_FOLDEROPENMID);
+ setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL);
+
+ break;
+
+ case CircledTreeFoldStyle:
+ setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_CIRCLEMINUS);
+ setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_CIRCLEPLUS);
+ setFoldMarker(SC_MARKNUM_FOLDERSUB,SC_MARK_VLINE);
+ setFoldMarker(SC_MARKNUM_FOLDERTAIL,SC_MARK_LCORNERCURVE);
+ setFoldMarker(SC_MARKNUM_FOLDEREND,SC_MARK_CIRCLEPLUSCONNECTED);
+ setFoldMarker(SC_MARKNUM_FOLDEROPENMID,SC_MARK_CIRCLEMINUSCONNECTED);
+ setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL,SC_MARK_TCORNERCURVE);
+
+ break;
+
+ case BoxedTreeFoldStyle:
+ setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_BOXMINUS);
+ setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_BOXPLUS);
+ setFoldMarker(SC_MARKNUM_FOLDERSUB,SC_MARK_VLINE);
+ setFoldMarker(SC_MARKNUM_FOLDERTAIL,SC_MARK_LCORNER);
+ setFoldMarker(SC_MARKNUM_FOLDEREND,SC_MARK_BOXPLUSCONNECTED);
+ setFoldMarker(SC_MARKNUM_FOLDEROPENMID,SC_MARK_BOXMINUSCONNECTED);
+ setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL,SC_MARK_TCORNER);
+
+ break;
+ }
+
+ SendScintilla(SCI_SETMARGINWIDTHN,2,defaultFoldMarginWidth);
+}
+
+
+// Set up a folder marker.
+void QextScintilla::setFoldMarker(int marknr,int mark)
+{
+ SendScintilla(SCI_MARKERDEFINE,marknr,mark);
+
+ if (mark != SC_MARK_EMPTY)
+ {
+ SendScintilla(SCI_MARKERSETFORE,marknr,white);
+ SendScintilla(SCI_MARKERSETBACK,marknr,black);
+ }
+}
+
+
+// Handle a click in the fold margin. This is mostly taken from SciTE.
+void QextScintilla::foldClick(int lineClick,int bstate)
+{
+ if ((bstate & ShiftButton) && (bstate & ControlButton))
+ {
+ foldAll();
+ return;
+ }
+
+ int levelClick = SendScintilla(SCI_GETFOLDLEVEL,lineClick);
+
+ if (levelClick & SC_FOLDLEVELHEADERFLAG)
+ {
+ if (bstate & ShiftButton)
+ {
+ // Ensure all children are visible.
+ SendScintilla(SCI_SETFOLDEXPANDED,lineClick,1);
+ foldExpand(lineClick,TRUE,TRUE,100,levelClick);
+ }
+ else if (bstate & ControlButton)
+ {
+ if (SendScintilla(SCI_GETFOLDEXPANDED,lineClick))
+ {
+ // Contract this line and all its children.
+ SendScintilla(SCI_SETFOLDEXPANDED,lineClick,0L);
+ foldExpand(lineClick,FALSE,TRUE,0,levelClick);
+ }
+ else
+ {
+ // Expand this line and all its children.
+ SendScintilla(SCI_SETFOLDEXPANDED,lineClick,1);
+ foldExpand(lineClick,TRUE,TRUE,100,levelClick);
+ }
+ }
+ else
+ {
+ // Toggle this line.
+ SendScintilla(SCI_TOGGLEFOLD,lineClick);
+ }
+ }
+}
+
+
+// Do the hard work of hiding and showing lines. This is mostly taken from
+// SciTE.
+void QextScintilla::foldExpand(int &line,bool doExpand,bool force,
+ int visLevels,int level)
+{
+ int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD,line,level & SC_FOLDLEVELNUMBERMASK);
+
+ line++;
+
+ while (line <= lineMaxSubord)
+ {
+ if (force)
+ {
+ if (visLevels > 0)
+ SendScintilla(SCI_SHOWLINES,line,line);
+ else
+ SendScintilla(SCI_HIDELINES,line,line);
+ }
+ else if (doExpand)
+ SendScintilla(SCI_SHOWLINES,line,line);
+
+ int levelLine = level;
+
+ if (levelLine == -1)
+ levelLine = SendScintilla(SCI_GETFOLDLEVEL,line);
+
+ if (levelLine & SC_FOLDLEVELHEADERFLAG)
+ {
+ if (force)
+ {
+ if (visLevels > 1)
+ SendScintilla(SCI_SETFOLDEXPANDED,line,1);
+ else
+ SendScintilla(SCI_SETFOLDEXPANDED,line,0L);
+
+ foldExpand(line,doExpand,force,visLevels - 1);
+ }
+ else if (doExpand)
+ {
+ if (!SendScintilla(SCI_GETFOLDEXPANDED,line))
+ SendScintilla(SCI_SETFOLDEXPANDED,line,1);
+
+ foldExpand(line,TRUE,force,visLevels - 1);
+ }
+ else
+ foldExpand(line,FALSE,force,visLevels - 1);
+ }
+ else
+ line++;
+ }
+}
+
+
+// Fully expand (if there is any line currently folded) all text. Otherwise,
+// fold all text. This is mostly taken from SciTE.
+void QextScintilla::foldAll(bool children)
+{
+ recolor();
+
+ int maxLine = SendScintilla(SCI_GETLINECOUNT);
+ bool expanding = TRUE;
+
+ for (int lineSeek = 0; lineSeek < maxLine; lineSeek++)
+ {
+ if (SendScintilla(SCI_GETFOLDLEVEL,lineSeek) & SC_FOLDLEVELHEADERFLAG)
+ {
+ expanding = !SendScintilla(SCI_GETFOLDEXPANDED,lineSeek);
+ break;
+ }
+ }
+
+ for (int line = 0; line < maxLine; line++)
+ {
+ int level = SendScintilla(SCI_GETFOLDLEVEL,line);
+
+ if (!(level & SC_FOLDLEVELHEADERFLAG))
+ continue;
+
+ if (children ||
+ (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK)))
+ {
+ if (expanding)
+ {
+ SendScintilla(SCI_SETFOLDEXPANDED,line,1);
+ foldExpand(line,TRUE,FALSE,0,level);
+ line--;
+ }
+ else
+ {
+ int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD,line,-1);
+
+ SendScintilla(SCI_SETFOLDEXPANDED,line,0L);
+
+ if (lineMaxSubord > line)
+ SendScintilla(SCI_HIDELINES,line + 1,lineMaxSubord);
+ }
+ }
+ }
+}
+
+
+// Handle a fold change. This is mostly taken from SciTE.
+void QextScintilla::foldChanged(int line,int levelNow,int levelPrev)
+{
+ if (levelNow & SC_FOLDLEVELHEADERFLAG)
+ {
+ if (!(levelPrev & SC_FOLDLEVELHEADERFLAG))
+ SendScintilla(SCI_SETFOLDEXPANDED,line,1);
+ }
+ else if (levelPrev & SC_FOLDLEVELHEADERFLAG)
+ {
+ if (!SendScintilla(SCI_GETFOLDEXPANDED,line))
+ {
+ // Removing the fold from one that has been contracted
+ // so should expand. Otherwise lines are left
+ // invisible with no way to make them visible.
+ foldExpand(line,TRUE,FALSE,0,levelPrev);
+ }
+ }
+}
+
+
+// Toggle the fold for a line if it contains a fold marker.
+void QextScintilla::foldLine(int line)
+{
+ SendScintilla(SCI_TOGGLEFOLD,line);
+}
+
+
+// Handle the SCN_MODIFIED notification.
+void QextScintilla::handleModified(int pos,int mtype,const char *text,int len,
+ int added,int line,int foldNow,int foldPrev)
+{
+ if (mtype & SC_MOD_CHANGEFOLD)
+ {
+ if (fold)
+ foldChanged(line,foldNow,foldPrev);
+ }
+ else if (mtype & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT))
+ emit textChanged();
+}
+
+
+// Zoom in a number of points.
+void QextScintilla::zoomIn(int range)
+{
+ zoomTo(SendScintilla(SCI_GETZOOM) + range);
+}
+
+
+// Zoom in a single point.
+void QextScintilla::zoomIn()
+{
+ SendScintilla(SCI_ZOOMIN);
+}
+
+
+// Zoom out a number of points.
+void QextScintilla::zoomOut(int range)
+{
+ zoomTo(SendScintilla(SCI_GETZOOM) - range);
+}
+
+
+// Zoom out a single point.
+void QextScintilla::zoomOut()
+{
+ SendScintilla(SCI_ZOOMOUT);
+}
+
+
+// Set the zoom to a number of points.
+void QextScintilla::zoomTo(int size)
+{
+ if (size < -10)
+ size = -10;
+ else if (size > 20)
+ size = 20;
+
+ SendScintilla(SCI_SETZOOM,size);
+}
+
+
+// Find the first occurrence of a string.
+bool QextScintilla::findFirst(const QString &expr,bool re,bool cs,bool wo,
+ bool wrap,bool forward,int line,int index,
+ bool show)
+{
+ findState.inProgress = FALSE;
+
+ if (expr.isEmpty())
+ return FALSE;
+
+ findState.expr = expr;
+ findState.wrap = wrap;
+ findState.forward = forward;
+
+ findState.flags = (cs ? SCFIND_MATCHCASE : 0) |
+ (wo ? SCFIND_WHOLEWORD : 0) |
+ (re ? SCFIND_REGEXP : 0);
+
+ if (line < 0 || index < 0)
+ findState.startpos = SendScintilla(SCI_GETCURRENTPOS);
+ else
+ findState.startpos = posFromLineIndex(line,index);
+
+ if (forward)
+ findState.endpos = SendScintilla(SCI_GETLENGTH);
+ else
+ findState.endpos = 0;
+
+ findState.show = show;
+
+ return doFind();
+}
+
+
+// Find the next occurrence of a string.
+bool QextScintilla::findNext()
+{
+ if (!findState.inProgress)
+ return FALSE;
+
+ return doFind();
+}
+
+
+// Do the hard work of findFirst() and findNext().
+bool QextScintilla::doFind()
+{
+ SendScintilla(SCI_SETSEARCHFLAGS,findState.flags);
+
+ long pos = simpleFind();
+
+ // See if it was found. If not and wraparound is wanted, try again.
+ if (pos == -1 && findState.wrap)
+ {
+ if (findState.forward)
+ {
+ findState.startpos = 0;
+ findState.endpos = SendScintilla(SCI_GETLENGTH);
+ }
+ else
+ {
+ findState.startpos = SendScintilla(SCI_GETLENGTH);
+ findState.endpos = 0;
+ }
+
+ pos = simpleFind();
+ }
+
+ if (pos == -1)
+ {
+ findState.inProgress = FALSE;
+ return FALSE;
+ }
+
+ // It was found.
+ long targstart = SendScintilla(SCI_GETTARGETSTART);
+ long targend = SendScintilla(SCI_GETTARGETEND);
+
+ // Ensure the text found is visible if required.
+ if (findState.show)
+ {
+ int startLine = SendScintilla(SCI_LINEFROMPOSITION,targstart);
+ int endLine = SendScintilla(SCI_LINEFROMPOSITION,targend);
+
+ for (int i = startLine; i <= endLine; ++i)
+ SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY,i);
+ }
+
+ // Now set the selection.
+ SendScintilla(SCI_SETSEL,targstart,targend);
+
+ // Finally adjust the start position so that we don't find the same one
+ // again.
+ if (findState.forward)
+ findState.startpos = targend;
+ else if ((findState.startpos = targstart - 1) < 0)
+ findState.startpos = 0;
+
+ findState.inProgress = TRUE;
+ return TRUE;
+}
+
+
+// Do a simple find between the start and end positions.
+long QextScintilla::simpleFind()
+{
+ if (findState.startpos == findState.endpos)
+ return -1;
+
+ SendScintilla(SCI_SETTARGETSTART,findState.startpos);
+ SendScintilla(SCI_SETTARGETEND,findState.endpos);
+
+ long pos;
+
+ if (isUtf8())
+ {
+ QCString s = findState.expr.utf8();
+
+ pos = SendScintilla(SCI_SEARCHINTARGET,s.length(),s.data());
+ }
+ else
+ {
+ const char *s = findState.expr.latin1();
+
+ pos = SendScintilla(SCI_SEARCHINTARGET,strlen(s),s);
+ }
+
+ return pos;
+}
+
+
+// Replace the text found with the previous findFirst() or findNext().
+void QextScintilla::replace(const QString &replaceStr)
+{
+ if (!findState.inProgress)
+ return;
+
+ long start = SendScintilla(SCI_GETSELECTIONSTART);
+
+ SendScintilla(SCI_TARGETFROMSELECTION);
+
+ long len;
+ int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET;
+
+ if (isUtf8())
+ len = SendScintilla(cmd,-1,replaceStr.utf8().data());
+ else
+ len = SendScintilla(cmd,-1,replaceStr.latin1());
+
+ // Reset the selection.
+ SendScintilla(SCI_SETSELECTIONSTART,start);
+ SendScintilla(SCI_SETSELECTIONEND,start + len);
+
+ if (findState.forward)
+ findState.startpos = start + len;
+}
+
+
+// Query the modified state.
+bool QextScintilla::isModified()
+{
+ // We don't use SCI_GETMODIFY as it seems to be buggy in Scintilla
+ // v1.61.
+ return modified;
+}
+
+
+// Set the modified state.
+void QextScintilla::setModified(bool m)
+{
+ if (!m)
+ SendScintilla(SCI_SETSAVEPOINT);
+}
+
+
+// Handle the SCN_MARGINCLICK notification.
+void QextScintilla::handleMarginClick(int pos,int modifiers,int margin)
+{
+ int state = 0;
+
+ if (modifiers & SCMOD_SHIFT)
+ state |= ShiftButton;
+
+ if (modifiers & SCMOD_CTRL)
+ state |= ControlButton;
+
+ if (modifiers & SCMOD_ALT)
+ state |= AltButton;
+
+ int line = SendScintilla(SCI_LINEFROMPOSITION,pos);
+
+ if (fold && margin == 2)
+ foldClick(line,state);
+ else
+ emit marginClicked(margin,line,(ButtonState)state);
+}
+
+
+// Handle the SCN_SAVEPOINTREACHED notification.
+void QextScintilla::handleSavePointReached()
+{
+ if (modified)
+ {
+ modified = FALSE;
+ emit modificationChanged(FALSE);
+ }
+}
+
+
+// Handle the SCN_SAVEPOINTLEFT notification.
+void QextScintilla::handleSavePointLeft()
+{
+ if (!modified)
+ {
+ modified = TRUE;
+ emit modificationChanged(TRUE);
+ }
+}
+
+
+// Handle the QSCN_SELCHANGED signal.
+void QextScintilla::handleSelectionChanged(bool yes)
+{
+ selText = yes;
+
+ emit copyAvailable(yes);
+ emit selectionChanged();
+}
+
+
+// Get the current selection.
+void QextScintilla::getSelection(int *lineFrom,int *indexFrom,
+ int *lineTo,int *indexTo)
+{
+ if (selText)
+ {
+ lineIndexFromPos(SendScintilla(SCI_GETSELECTIONSTART),
+ lineFrom,indexFrom);
+ lineIndexFromPos(SendScintilla(SCI_GETSELECTIONEND),
+ lineTo,indexTo);
+ }
+ else
+ *lineFrom = *indexFrom = *lineTo = *indexTo = -1;
+}
+
+
+// Sets the current selection.
+void QextScintilla::setSelection(int lineFrom,int indexFrom,
+ int lineTo,int indexTo)
+{
+ SendScintilla(SCI_SETSELECTIONSTART,posFromLineIndex(lineFrom,indexFrom));
+ SendScintilla(SCI_SETSELECTIONEND,posFromLineIndex(lineTo,indexTo));
+}
+
+
+// Set the background colour of selected text.
+void QextScintilla::setSelectionBackgroundColor(const QColor &col)
+{
+ SendScintilla(SCI_SETSELBACK,1,col);
+
+ int alpha = qAlpha(col.rgb());
+
+ if (alpha < 255)
+ SendScintilla(SCI_SETSELALPHA, alpha);
+}
+
+
+// Set the foreground colour of selected text.
+void QextScintilla::setSelectionForegroundColor(const QColor &col)
+{
+ SendScintilla(SCI_SETSELFORE,1,col);
+}
+
+
+// Reset the background colour of selected text to the default.
+void QextScintilla::resetSelectionBackgroundColor()
+{
+ SendScintilla(SCI_SETSELALPHA, SC_ALPHA_NOALPHA);
+ SendScintilla(SCI_SETSELBACK,0UL);
+}
+
+
+// Reset the foreground colour of selected text to the default.
+void QextScintilla::resetSelectionForegroundColor()
+{
+ SendScintilla(SCI_SETSELFORE,0UL);
+}
+
+
+// Set the width of the caret.
+void QextScintilla::setCaretWidth(int width)
+{
+ SendScintilla(SCI_SETCARETWIDTH,width);
+}
+
+
+// Set the foreground colour of the caret.
+void QextScintilla::setCaretForegroundColor(const QColor &col)
+{
+ SendScintilla(SCI_SETCARETFORE,col);
+}
+
+
+// Set the background colour of the line containing the caret.
+void QextScintilla::setCaretLineBackgroundColor(const QColor &col)
+{
+ SendScintilla(SCI_SETCARETLINEBACK,col);
+
+ int alpha = qAlpha(col.rgb());
+
+ if (alpha < 255)
+ SendScintilla(SCI_SETCARETLINEBACKALPHA, alpha);
+}
+
+
+// Set the state of the background colour of the line containing the caret.
+void QextScintilla::setCaretLineVisible(bool enable)
+{
+ SendScintilla(SCI_SETCARETLINEVISIBLE,enable);
+}
+
+
+// Query the read-only state.
+bool QextScintilla::isReadOnly()
+{
+ return SendScintilla(SCI_GETREADONLY);
+}
+
+
+// Set the read-only state.
+void QextScintilla::setReadOnly(bool ro)
+{
+ SendScintilla(SCI_SETREADONLY,ro);
+}
+
+
+// Append the given text.
+void QextScintilla::append(const QString &text)
+{
+ bool ro = ensureRW();
+
+ if (isUtf8())
+ {
+ QCString s = text.utf8();
+
+ SendScintilla(SCI_APPENDTEXT,s.length(),s.data());
+ }
+ else
+ {
+ const char *s = text.latin1();
+
+ SendScintilla(SCI_APPENDTEXT,strlen(s),s);
+ }
+
+ SendScintilla(SCI_EMPTYUNDOBUFFER);
+
+ setReadOnly(ro);
+}
+
+
+// Insert the given text at the current position.
+void QextScintilla::insert(const QString &text)
+{
+ bool ro = ensureRW();
+
+ SendScintilla(SCI_BEGINUNDOACTION);
+
+ if (isUtf8())
+ SendScintilla(SCI_INSERTTEXT,-1,text.utf8().data());
+ else
+ SendScintilla(SCI_INSERTTEXT,-1,text.latin1());
+
+ SendScintilla(SCI_ENDUNDOACTION);
+
+ setReadOnly(ro);
+}
+
+
+// Insert the given text at the given position.
+void QextScintilla::insertAt(const QString &text,int line,int index)
+{
+ bool ro = ensureRW();
+ long position = posFromLineIndex(line,index);
+
+ SendScintilla(SCI_BEGINUNDOACTION);
+
+ if (isUtf8())
+ SendScintilla(SCI_INSERTTEXT,position,text.utf8().data());
+ else
+ SendScintilla(SCI_INSERTTEXT,position,text.latin1());
+
+ SendScintilla(SCI_ENDUNDOACTION);
+
+ setReadOnly(ro);
+}
+
+
+// Begin a sequence of undoable actions.
+void QextScintilla::beginUndoAction()
+{
+ SendScintilla(SCI_BEGINUNDOACTION);
+}
+
+
+// End a sequence of undoable actions.
+void QextScintilla::endUndoAction()
+{
+ SendScintilla(SCI_ENDUNDOACTION);
+}
+
+
+// Redo a sequence of actions.
+void QextScintilla::redo()
+{
+ SendScintilla(SCI_REDO);
+}
+
+
+// Undo a sequence of actions.
+void QextScintilla::undo()
+{
+ SendScintilla(SCI_UNDO);
+}
+
+
+// See if there is something to redo.
+bool QextScintilla::isRedoAvailable()
+{
+ return SendScintilla(SCI_CANREDO);
+}
+
+
+// See if there is something to undo.
+bool QextScintilla::isUndoAvailable()
+{
+ return SendScintilla(SCI_CANUNDO);
+}
+
+
+// Return the number of lines.
+int QextScintilla::lines()
+{
+ return SendScintilla(SCI_GETLINECOUNT);
+}
+
+
+// Return the line at a position.
+int QextScintilla::lineAt(const QPoint &pos)
+{
+ long chpos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE,pos.x(),pos.y());
+
+ if (chpos < 0)
+ return -1;
+
+ return SendScintilla(SCI_LINEFROMPOSITION,chpos);
+}
+
+
+// Return the length of a line.
+int QextScintilla::lineLength(int line)
+{
+ if (line < 0 || line >= SendScintilla(SCI_GETLINECOUNT))
+ return -1;
+
+ return SendScintilla(SCI_LINELENGTH,line);
+}
+
+
+// Return the length of the current text.
+int QextScintilla::length()
+{
+ return SendScintilla(SCI_GETTEXTLENGTH);
+}
+
+
+// Remove any selected text.
+void QextScintilla::removeSelectedText()
+{
+ SendScintilla(SCI_REPLACESEL,"");
+}
+
+
+// Return the current selected text.
+QString QextScintilla::selectedText()
+{
+ if (!selText)
+ return QString();
+
+ // Scintilla doesn't tell us the length of the selected text so we use
+ // the length of the whole document.
+ char *buf = new char[length() + 1];
+
+ SendScintilla(SCI_GETSELTEXT,buf);
+
+ QString qs = convertText(buf);
+ delete[] buf;
+
+ return qs;
+}
+
+
+// Return the current text.
+QString QextScintilla::text()
+{
+ int buflen = length() + 1;
+ char *buf = new char[buflen];
+
+ SendScintilla(SCI_GETTEXT,buflen,buf);
+
+ QString qs = convertText(buf);
+ delete[] buf;
+
+ return qs;
+}
+
+
+// Return the text of a line.
+QString QextScintilla::text(int line)
+{
+ int line_len = lineLength(line);
+
+ if (line_len < 1)
+ return QString();
+
+ char *buf = new char[line_len + 1];
+
+ SendScintilla(SCI_GETLINE,line,buf);
+ buf[line_len] = '\0';
+
+ QString qs = convertText(buf);
+ delete[] buf;
+
+ return qs;
+}
+
+
+// Set the given text.
+void QextScintilla::setText(const QString &text)
+{
+ bool ro = ensureRW();
+
+ if (isUtf8())
+ SendScintilla(SCI_SETTEXT,text.utf8().data());
+ else
+ SendScintilla(SCI_SETTEXT,text.latin1());
+
+ SendScintilla(SCI_EMPTYUNDOBUFFER);
+
+ setReadOnly(ro);
+}
+
+
+// Get the cursor position
+void QextScintilla::getCursorPosition(int *line,int *index)
+{
+ long pos = SendScintilla(SCI_GETCURRENTPOS);
+ long lin = SendScintilla(SCI_LINEFROMPOSITION,pos);
+ long linpos = SendScintilla(SCI_POSITIONFROMLINE,lin);
+
+ *line = lin;
+ *index = pos - linpos;
+}
+
+
+// Set the cursor position
+void QextScintilla::setCursorPosition(int line,int index)
+{
+ SendScintilla(SCI_GOTOPOS,posFromLineIndex(line,index));
+}
+
+
+// Ensure the cursor is visible.
+void QextScintilla::ensureCursorVisible()
+{
+ SendScintilla(SCI_SCROLLCARET);
+}
+
+
+// Ensure a line is visible.
+void QextScintilla::ensureLineVisible(int line)
+{
+ SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY,line);
+}
+
+
+// Copy text to the clipboard.
+void QextScintilla::copy()
+{
+ SendScintilla(SCI_COPY);
+}
+
+
+// Cut text to the clipboard.
+void QextScintilla::cut()
+{
+ SendScintilla(SCI_CUT);
+}
+
+
+// Paste text from the clipboard.
+void QextScintilla::paste()
+{
+ SendScintilla(SCI_PASTE);
+}
+
+
+// Select all text, or deselect any selected text.
+void QextScintilla::selectAll(bool select)
+{
+ if (selText)
+ SendScintilla(SCI_SETANCHOR,SendScintilla(SCI_GETCURRENTPOS));
+ else
+ SendScintilla(SCI_SELECTALL);
+}
+
+
+// Delete all text.
+void QextScintilla::clear()
+{
+ bool ro = ensureRW();
+
+ SendScintilla(SCI_BEGINUNDOACTION);
+ SendScintilla(SCI_CLEARALL);
+ SendScintilla(SCI_ENDUNDOACTION);
+
+ setReadOnly(ro);
+}
+
+
+// Return the indentation of a line.
+int QextScintilla::indentation(int line)
+{
+ return SendScintilla(SCI_GETLINEINDENTATION,line);
+}
+
+
+// Set the indentation of a line.
+void QextScintilla::setIndentation(int line,int indentation)
+{
+ SendScintilla(SCI_BEGINUNDOACTION);
+ SendScintilla(SCI_SETLINEINDENTATION,line,indentation);
+ SendScintilla(SCI_ENDUNDOACTION);
+}
+
+
+// Indent a line.
+void QextScintilla::indent(int line)
+{
+ setIndentation(line,indentation(line) + indentWidth());
+}
+
+
+// Unindent a line.
+void QextScintilla::unindent(int line)
+{
+ int newIndent = indentation(line) - indentWidth();
+
+ if (newIndent < 0)
+ newIndent = 0;
+
+ setIndentation(line,newIndent);
+}
+
+
+// Return the indentation of the current line.
+int QextScintilla::currentIndent()
+{
+ return indentation(SendScintilla(SCI_LINEFROMPOSITION,SendScintilla(SCI_GETCURRENTPOS)));
+}
+
+
+// Return the current indentation width.
+int QextScintilla::indentWidth()
+{
+ int w = indentationWidth();
+
+ if (w == 0)
+ w = tabWidth();
+
+ return w;
+}
+
+
+// Return the state of indentation guides.
+bool QextScintilla::indentationGuides()
+{
+ return SendScintilla(SCI_GETINDENTATIONGUIDES);
+}
+
+
+// Enable and disable indentation guides.
+void QextScintilla::setIndentationGuides(bool enable)
+{
+ SendScintilla(SCI_SETINDENTATIONGUIDES,enable);
+}
+
+
+// Set the background colour of indentation guides.
+void QextScintilla::setIndentationGuidesBackgroundColor(const QColor &col)
+{
+ SendScintilla(SCI_STYLESETBACK,STYLE_INDENTGUIDE,col);
+}
+
+
+// Set the foreground colour of indentation guides.
+void QextScintilla::setIndentationGuidesForegroundColor(const QColor &col)
+{
+ SendScintilla(SCI_STYLESETFORE,STYLE_INDENTGUIDE,col);
+}
+
+
+// Return the indentation width.
+int QextScintilla::indentationWidth()
+{
+ return SendScintilla(SCI_GETINDENT);
+}
+
+
+// Set the indentation width.
+void QextScintilla::setIndentationWidth(int width)
+{
+ SendScintilla(SCI_SETINDENT,width);
+}
+
+
+// Return the tab width.
+int QextScintilla::tabWidth()
+{
+ return SendScintilla(SCI_GETTABWIDTH);
+}
+
+
+// Set the tab width.
+void QextScintilla::setTabWidth(int width)
+{
+ SendScintilla(SCI_SETTABWIDTH,width);
+}
+
+
+// Return the effect of the backspace key.
+bool QextScintilla::backspaceUnindents()
+{
+ return SendScintilla(SCI_GETBACKSPACEUNINDENTS);
+}
+
+
+// Set the effect of the backspace key.
+void QextScintilla::setBackspaceUnindents(bool unindents)
+{
+ SendScintilla(SCI_SETBACKSPACEUNINDENTS,unindents);
+}
+
+
+// Return the effect of the tab key.
+bool QextScintilla::tabIndents()
+{
+ return SendScintilla(SCI_GETTABINDENTS);
+}
+
+
+// Set the effect of the tab key.
+void QextScintilla::setTabIndents(bool indents)
+{
+ SendScintilla(SCI_SETTABINDENTS,indents);
+}
+
+
+// Return the indentation use of tabs.
+bool QextScintilla::indentationsUseTabs()
+{
+ return SendScintilla(SCI_GETUSETABS);
+}
+
+
+// Set the indentation use of tabs.
+void QextScintilla::setIndentationsUseTabs(bool tabs)
+{
+ SendScintilla(SCI_SETUSETABS,tabs);
+}
+
+
+// Return the state of line numbers in a margin.
+bool QextScintilla::marginLineNumbers(int margin)
+{
+ return SendScintilla(SCI_GETMARGINTYPEN,margin);
+}
+
+
+// Enable and disable line numbers in a margin.
+void QextScintilla::setMarginLineNumbers(int margin,bool lnrs)
+{
+ SendScintilla(SCI_SETMARGINTYPEN,margin,lnrs ? SC_MARGIN_NUMBER : 0);
+}
+
+
+// Return the marker mask of a margin.
+int QextScintilla::marginMarkerMask(int margin)
+{
+ return SendScintilla(SCI_GETMARGINMASKN,margin);
+}
+
+
+// Set the marker mask of a margin.
+void QextScintilla::setMarginMarkerMask(int margin,int mask)
+{
+ SendScintilla(SCI_SETMARGINMASKN,margin,mask);
+}
+
+
+// Return the state of a margin's sensitivity.
+bool QextScintilla::marginSensitivity(int margin)
+{
+ return SendScintilla(SCI_GETMARGINSENSITIVEN,margin);
+}
+
+
+// Enable and disable a margin's sensitivity.
+void QextScintilla::setMarginSensitivity(int margin,bool sens)
+{
+ SendScintilla(SCI_SETMARGINSENSITIVEN,margin,sens);
+}
+
+
+// Return the width of a margin.
+int QextScintilla::marginWidth(int margin)
+{
+ return SendScintilla(SCI_GETMARGINWIDTHN,margin);
+}
+
+
+// Set the width of a margin.
+void QextScintilla::setMarginWidth(int margin,int width)
+{
+ SendScintilla(SCI_SETMARGINWIDTHN,margin,width);
+}
+
+
+// Set the width of a margin to the width of some text.
+void QextScintilla::setMarginWidth(int margin,const QString &s)
+{
+ int width;
+
+ if (isUtf8())
+ width = SendScintilla(SCI_TEXTWIDTH,STYLE_LINENUMBER,s.utf8().data());
+ else
+ width = SendScintilla(SCI_TEXTWIDTH,STYLE_LINENUMBER,s.latin1());
+
+ setMarginWidth(margin,width);
+}
+
+
+// Set the background colour of all margins.
+void QextScintilla::setMarginsBackgroundColor(const QColor &col)
+{
+ handleStylePaperChange(col,STYLE_LINENUMBER);
+}
+
+
+// Set the foreground colour of all margins.
+void QextScintilla::setMarginsForegroundColor(const QColor &col)
+{
+ handleStyleColorChange(col,STYLE_LINENUMBER);
+}
+
+
+// Set the font of all margins.
+void QextScintilla::setMarginsFont(const QFont &f)
+{
+ setStylesFont(f,STYLE_LINENUMBER);
+}
+
+
+// Define a marker based on a symbol.
+int QextScintilla::markerDefine(MarkerSymbol sym,int mnr)
+{
+ checkMarker(mnr);
+
+ if (mnr >= 0)
+ SendScintilla(SCI_MARKERDEFINE,mnr,static_cast<long>(sym));
+
+ return mnr;
+}
+
+
+// Define a marker based on a character.
+int QextScintilla::markerDefine(char ch,int mnr)
+{
+ checkMarker(mnr);
+
+ if (mnr >= 0)
+ SendScintilla(SCI_MARKERDEFINE,mnr,static_cast<long>(SC_MARK_CHARACTER) + ch);
+
+ return mnr;
+}
+
+
+// Define a marker based on a QPixmap.
+int QextScintilla::markerDefine(const QPixmap *pm,int mnr)
+{
+ checkMarker(mnr);
+
+ if (mnr >= 0)
+ SendScintilla(SCI_MARKERDEFINEPIXMAP,mnr,pm);
+
+ return mnr;
+}
+
+
+// Add a marker to a line.
+int QextScintilla::markerAdd(int linenr,int mnr)
+{
+ if (mnr < 0 || mnr > MARKER_MAX || (allocatedMarkers & (1 << mnr)) == 0)
+ return -1;
+
+ return SendScintilla(SCI_MARKERADD,linenr,mnr);
+}
+
+
+// Get the marker mask for a line.
+unsigned QextScintilla::markersAtLine(int linenr)
+{
+ return SendScintilla(SCI_MARKERGET,linenr);
+}
+
+
+// Delete a marker from a line.
+void QextScintilla::markerDelete(int linenr,int mnr)
+{
+ if (mnr <= MARKER_MAX)
+ {
+ if (mnr < 0)
+ {
+ unsigned am = allocatedMarkers;
+
+ for (int m = 0; m <= MARKER_MAX; ++m)
+ {
+ if (am & 1)
+ SendScintilla(SCI_MARKERDELETE,linenr,m);
+
+ am >>= 1;
+ }
+ }
+ else if (allocatedMarkers & (1 << mnr))
+ SendScintilla(SCI_MARKERDELETE,linenr,mnr);
+ }
+}
+
+
+// Delete a marker from the text.
+void QextScintilla::markerDeleteAll(int mnr)
+{
+ if (mnr <= MARKER_MAX)
+ {
+ if (mnr < 0)
+ SendScintilla(SCI_MARKERDELETEALL,-1);
+ else if (allocatedMarkers & (1 << mnr))
+ SendScintilla(SCI_MARKERDELETEALL,mnr);
+ }
+}
+
+
+// Delete a marker handle from the text.
+void QextScintilla::markerDeleteHandle(int mhandle)
+{
+ SendScintilla(SCI_MARKERDELETEHANDLE,mhandle);
+}
+
+
+// Return the line containing a marker instance.
+int QextScintilla::markerLine(int mhandle)
+{
+ return SendScintilla(SCI_MARKERLINEFROMHANDLE,mhandle);
+}
+
+
+// Search forwards for a marker.
+int QextScintilla::markerFindNext(int linenr,unsigned mask)
+{
+ return SendScintilla(SCI_MARKERNEXT,linenr,mask);
+}
+
+
+// Search backwards for a marker.
+int QextScintilla::markerFindPrevious(int linenr,unsigned mask)
+{
+ return SendScintilla(SCI_MARKERPREVIOUS,linenr,mask);
+}
+
+
+// Set the marker background colour.
+void QextScintilla::setMarkerBackgroundColor(const QColor &col,int mnr)
+{
+ if (mnr <= MARKER_MAX)
+ {
+ int alpha = qAlpha(col.rgb());
+
+ if (mnr < 0)
+ {
+ unsigned am = allocatedMarkers;
+
+ for (int m = 0; m <= MARKER_MAX; ++m)
+ {
+ if (am & 1)
+ {
+ SendScintilla(SCI_MARKERSETBACK,m,col);
+
+ if (alpha < 255)
+ SendScintilla(SCI_MARKERSETALPHA, m, alpha);
+ }
+
+ am >>= 1;
+ }
+ }
+ else if (allocatedMarkers & (1 << mnr))
+ {
+ SendScintilla(SCI_MARKERSETBACK,mnr,col);
+
+ if (alpha < 255)
+ SendScintilla(SCI_MARKERSETALPHA, mnr, alpha);
+ }
+ }
+}
+
+
+// Set the marker foreground colour.
+void QextScintilla::setMarkerForegroundColor(const QColor &col,int mnr)
+{
+ if (mnr <= MARKER_MAX)
+ {
+ if (mnr < 0)
+ {
+ unsigned am = allocatedMarkers;
+
+ for (int m = 0; m <= MARKER_MAX; ++m)
+ {
+ if (am & 1)
+ SendScintilla(SCI_MARKERSETFORE,m,col);
+
+ am >>= 1;
+ }
+ }
+ else if (allocatedMarkers & (1 << mnr))
+ SendScintilla(SCI_MARKERSETFORE,mnr,col);
+ }
+}
+
+
+// Check a marker, allocating a marker number if necessary.
+void QextScintilla::checkMarker(int &mnr)
+{
+ if (mnr >= 0)
+ {
+ // Check the explicit marker number isn't already allocated.
+ if (mnr > MARKER_MAX || allocatedMarkers & (1 << mnr))
+ mnr = -1;
+ }
+ else
+ {
+ unsigned am = allocatedMarkers;
+
+ // Find the smallest unallocated marker number.
+ for (mnr = 0; mnr <= MARKER_MAX; ++mnr)
+ {
+ if ((am & 1) == 0)
+ break;
+
+ am >>= 1;
+ }
+ }
+
+ // Define the marker if it is valid.
+ if (mnr >= 0)
+ allocatedMarkers |= (1 << mnr);
+}
+
+
+// Reset the fold margin colours.
+void QextScintilla::resetFoldMarginColors()
+{
+ SendScintilla(SCI_SETFOLDMARGINHICOLOUR,0,0L);
+ SendScintilla(SCI_SETFOLDMARGINCOLOUR,0,0L);
+}
+
+
+// Set the fold margin colours.
+void QextScintilla::setFoldMarginColors(const QColor &fore,const QColor &back)
+{
+ SendScintilla(SCI_SETFOLDMARGINHICOLOUR,1,fore);
+ SendScintilla(SCI_SETFOLDMARGINCOLOUR,1,back);
+}
+
+
+// Set the call tips background colour.
+void QextScintilla::setCallTipsBackgroundColor(const QColor &col)
+{
+ SendScintilla(SCI_CALLTIPSETBACK,col);
+}
+
+
+// Set the call tips foreground colour.
+void QextScintilla::setCallTipsForegroundColor(const QColor &col)
+{
+ SendScintilla(SCI_CALLTIPSETFORE,col);
+}
+
+
+// Set the call tips highlight colour.
+void QextScintilla::setCallTipsHighlightColor(const QColor &col)
+{
+ SendScintilla(SCI_CALLTIPSETFOREHLT,col);
+}
+
+
+// Set the matched brace background colour.
+void QextScintilla::setMatchedBraceBackgroundColor(const QColor &col)
+{
+ SendScintilla(SCI_STYLESETBACK,STYLE_BRACELIGHT,col);
+}
+
+
+// Set the matched brace foreground colour.
+void QextScintilla::setMatchedBraceForegroundColor(const QColor &col)
+{
+ SendScintilla(SCI_STYLESETFORE,STYLE_BRACELIGHT,col);
+}
+
+
+// Set the unmatched brace background colour.
+void QextScintilla::setUnmatchedBraceBackgroundColor(const QColor &col)
+{
+ SendScintilla(SCI_STYLESETBACK,STYLE_BRACEBAD,col);
+}
+
+
+// Set the unmatched brace foreground colour.
+void QextScintilla::setUnmatchedBraceForegroundColor(const QColor &col)
+{
+ SendScintilla(SCI_STYLESETFORE,STYLE_BRACEBAD,col);
+}
+
+
+// Set the lexer.
+void QextScintilla::setLexer(QextScintillaLexer *lexer)
+{
+ // Disconnect any previous lexer.
+ if (!lex.isNull())
+ {
+ lex -> disconnect(this);
+
+ SendScintilla(SCI_STYLERESETDEFAULT);
+ }
+
+ // Connect up the new lexer.
+ lex = lexer;
+
+ if (lex)
+ {
+ int bits = SendScintilla(SCI_GETSTYLEBITSNEEDED);
+ int nrStyles = 1 << bits;
+
+ SendScintilla(SCI_SETSTYLEBITS,bits);
+
+ connect(lex,SIGNAL(colorChanged(const QColor &,int)),
+ SLOT(handleStyleColorChange(const QColor &,int)));
+ connect(lex,SIGNAL(eolFillChanged(bool,int)),
+ SLOT(handleStyleEolFillChange(bool,int)));
+ connect(lex,SIGNAL(fontChanged(const QFont &,int)),
+ SLOT(handleStyleFontChange(const QFont &,int)));
+ connect(lex,SIGNAL(paperChanged(const QColor &,int)),
+ SLOT(handleStylePaperChange(const QColor &,int)));
+ connect(lex,SIGNAL(propertyChanged(const char *,const char *)),
+ SLOT(handlePropertyChange(const char *,const char *)));
+
+ SendScintilla(SCI_SETLEXERLANGUAGE,lex -> lexer());
+
+ // Set the keywords. Scintilla allows for sets numbered 0 to
+ // KEYWORDSET_MAX (although the lexers only seem to exploit 0
+ // to KEYWORDSET_MAX - 1). We number from 1 in line with
+ // SciTE's property files.
+ for (int k = 0; k <= KEYWORDSET_MAX; ++k)
+ {
+ const char *kw = lex -> keywords(k + 1);
+
+ if (kw)
+ SendScintilla(SCI_SETKEYWORDS,k,kw);
+ }
+
+ // Initialise each style.
+ for (int s = 0; s < nrStyles; ++s)
+ {
+ if (lex -> description(s).isNull())
+ continue;
+
+ handleStyleColorChange(lex -> color(s),s);
+ handleStyleEolFillChange(lex -> eolFill(s),s);
+ handleStyleFontChange(lex -> font(s),s);
+ handleStylePaperChange(lex -> paper(s),s);
+ }
+
+ // Initialise the properties.
+ lex -> refreshProperties();
+
+ // Set the auto-completion fillups if they haven't been
+ // explcitly set.
+ if (fillups_enabled && !explicit_fillups)
+ SendScintilla(SCI_AUTOCSETFILLUPS, lex->autoCompletionFillups());
+ }
+ else
+ {
+ SendScintilla(SCI_SETLEXER,SCLEX_NULL);
+
+ setColor(nl_text_colour);
+ setPaper(nl_paper_colour);
+ setFont(nl_font);
+ }
+}
+
+
+// Get the current lexer.
+QextScintillaLexer *QextScintilla::lexer() const
+{
+ return lex;
+}
+
+
+// Handle a change in lexer style foreground colour.
+void QextScintilla::handleStyleColorChange(const QColor &c,int style)
+{
+ SendScintilla(SCI_STYLESETFORE,style,c);
+}
+
+
+// Handle a change in lexer style end-of-line fill.
+void QextScintilla::handleStyleEolFillChange(bool eolfill,int style)
+{
+ SendScintilla(SCI_STYLESETEOLFILLED,style,eolfill);
+}
+
+
+// Handle a change in lexer style font.
+void QextScintilla::handleStyleFontChange(const QFont &f,int style)
+{
+ setStylesFont(f,style);
+
+ if (style == lex->defaultStyle())
+ setStylesFont(f, STYLE_DEFAULT);
+
+ if (style == lex -> braceStyle())
+ {
+ setStylesFont(f,STYLE_BRACELIGHT);
+ setStylesFont(f,STYLE_BRACEBAD);
+ }
+}
+
+
+// Set the font for a style.
+void QextScintilla::setStylesFont(const QFont &f,int style)
+{
+ SendScintilla(SCI_STYLESETFONT,style,f.family().latin1());
+ SendScintilla(SCI_STYLESETSIZE,style,f.pointSize());
+ SendScintilla(SCI_STYLESETBOLD,style,f.bold());
+ SendScintilla(SCI_STYLESETITALIC,style,f.italic());
+ SendScintilla(SCI_STYLESETUNDERLINE,style,f.underline());
+}
+
+
+// Handle a change in lexer style background colour.
+void QextScintilla::handleStylePaperChange(const QColor &c,int style)
+{
+ SendScintilla(SCI_STYLESETBACK,style,c);
+}
+
+
+// Handle a change in lexer property.
+void QextScintilla::handlePropertyChange(const char *prop,const char *val)
+{
+ SendScintilla(SCI_SETPROPERTY,prop,val);
+}
+
+
+// Handle a change to the user visible user interface.
+void QextScintilla::handleUpdateUI()
+{
+ long newPos = SendScintilla(SCI_GETCURRENTPOS);
+
+ if (newPos != oldPos)
+ {
+ oldPos = newPos;
+
+ int line = SendScintilla(SCI_LINEFROMPOSITION,newPos);
+ int col = SendScintilla(SCI_GETCOLUMN,newPos);
+
+ emit cursorPositionChanged(line,col);
+ }
+
+ if (braceMode != NoBraceMatch)
+ braceMatch();
+}
+
+
+// Handle brace matching.
+void QextScintilla::braceMatch()
+{
+ long braceAtCaret, braceOpposite;
+
+ findMatchingBrace(braceAtCaret,braceOpposite,braceMode);
+
+ if (braceAtCaret >= 0 && braceOpposite < 0)
+ {
+ SendScintilla(SCI_BRACEBADLIGHT,braceAtCaret);
+ SendScintilla(SCI_SETHIGHLIGHTGUIDE,0UL);
+ }
+ else
+ {
+ char chBrace = SendScintilla(SCI_GETCHARAT,braceAtCaret);
+
+ SendScintilla(SCI_BRACEHIGHLIGHT,braceAtCaret,braceOpposite);
+
+ long columnAtCaret = SendScintilla(SCI_GETCOLUMN,braceAtCaret);
+ long columnOpposite = SendScintilla(SCI_GETCOLUMN,braceOpposite);
+
+ if (chBrace == ':')
+ {
+ long lineStart = SendScintilla(SCI_LINEFROMPOSITION,braceAtCaret);
+ long indentPos = SendScintilla(SCI_GETLINEINDENTPOSITION,lineStart);
+ long indentPosNext = SendScintilla(SCI_GETLINEINDENTPOSITION,lineStart + 1);
+
+ columnAtCaret = SendScintilla(SCI_GETCOLUMN,indentPos);
+
+ long columnAtCaretNext = SendScintilla(SCI_GETCOLUMN,indentPosNext);
+ long indentSize = SendScintilla(SCI_GETINDENT);
+
+ if (columnAtCaretNext - indentSize > 1)
+ columnAtCaret = columnAtCaretNext - indentSize;
+
+ if (columnOpposite == 0)
+ columnOpposite = columnAtCaret;
+ }
+
+ long column = columnAtCaret;
+
+ if (column > columnOpposite)
+ column = columnOpposite;
+
+ SendScintilla(SCI_SETHIGHLIGHTGUIDE,column);
+ }
+}
+
+
+// Check if the character at a position is a brace.
+long QextScintilla::checkBrace(long pos,int brace_style,bool &colonMode)
+{
+ long brace_pos = -1;
+ char ch = SendScintilla(SCI_GETCHARAT,pos);
+
+ if (ch == ':')
+ {
+ // A bit of a hack.
+ if (!lex.isNull() && strcmp(lex -> lexer(),"python") == 0)
+ {
+ brace_pos = pos;
+ colonMode = TRUE;
+ }
+ }
+ else if (ch && strchr("[](){}<>",ch))
+ {
+ if (brace_style < 0)
+ brace_pos = pos;
+ else
+ {
+ int style = SendScintilla(SCI_GETSTYLEAT,pos) & 0x1f;
+
+ if (style == brace_style)
+ brace_pos = pos;
+ }
+ }
+
+ return brace_pos;
+}
+
+
+// Find a brace and it's match. Return TRUE if the current position is inside
+// a pair of braces.
+bool QextScintilla::findMatchingBrace(long &brace,long &other,BraceMatch mode)
+{
+ bool colonMode = FALSE;
+ int brace_style = (lex.isNull() ? -1 : lex -> braceStyle());
+
+ brace = -1;
+ other = -1;
+
+ long caretPos = SendScintilla(SCI_GETCURRENTPOS);
+
+ if (caretPos > 0)
+ brace = checkBrace(caretPos - 1,brace_style,colonMode);
+
+ bool isInside = FALSE;
+
+ if (brace < 0 && mode == SloppyBraceMatch)
+ {
+ brace = checkBrace(caretPos,brace_style,colonMode);
+
+ if (brace >= 0 && !colonMode)
+ isInside = TRUE;
+ }
+
+ if (brace >= 0)
+ {
+ if (colonMode)
+ {
+ // Find the end of the Python indented block.
+ long lineStart = SendScintilla(SCI_LINEFROMPOSITION,brace);
+ long lineMaxSubord = SendScintilla(SCI_GETLASTCHILD,lineStart,-1);
+
+ other = SendScintilla(SCI_GETLINEENDPOSITION,lineMaxSubord);
+ }
+ else
+ other = SendScintilla(SCI_BRACEMATCH,brace);
+
+ if (other > brace)
+ isInside = !isInside;
+ }
+
+ return isInside;
+}
+
+
+// Move to the matching brace.
+void QextScintilla::moveToMatchingBrace()
+{
+ gotoMatchingBrace(FALSE);
+}
+
+
+// Select to the matching brace.
+void QextScintilla::selectToMatchingBrace()
+{
+ gotoMatchingBrace(TRUE);
+}
+
+
+// Move to the matching brace and optionally select the text.
+void QextScintilla::gotoMatchingBrace(bool select)
+{
+ long braceAtCaret;
+ long braceOpposite;
+
+ bool isInside = findMatchingBrace(braceAtCaret,braceOpposite,SloppyBraceMatch);
+
+ if (braceOpposite >= 0)
+ {
+ // Convert the character positions into caret positions based
+ // on whether the caret position was inside or outside the
+ // braces.
+ if (isInside)
+ {
+ if (braceOpposite > braceAtCaret)
+ braceAtCaret++;
+ else
+ braceOpposite++;
+ }
+ else
+ {
+ if (braceOpposite > braceAtCaret)
+ braceOpposite++;
+ else
+ braceAtCaret++;
+ }
+
+ ensureLineVisible(SendScintilla(SCI_LINEFROMPOSITION,braceOpposite));
+
+ if (select)
+ SendScintilla(SCI_SETSEL,braceAtCaret,braceOpposite);
+ else
+ SendScintilla(SCI_SETSEL,braceOpposite,braceOpposite);
+ }
+}
+
+
+// Return a position from a line number and an index within the line.
+long QextScintilla::posFromLineIndex(int line,int index)
+{
+ long pos = SendScintilla(SCI_POSITIONFROMLINE,line);
+
+ // Allow for multi-byte characters.
+ for(int i = 0; i < index; i++)
+ pos = SendScintilla(SCI_POSITIONAFTER,pos);
+
+ return pos;
+}
+
+
+// Return a line number and an index within the line from a position.
+void QextScintilla::lineIndexFromPos(long pos,int *line,int *index)
+{
+ long lin = SendScintilla(SCI_LINEFROMPOSITION,pos);
+ long linpos = SendScintilla(SCI_POSITIONFROMLINE,lin);
+
+ *line = lin;
+ *index = pos - linpos;
+}
+
+
+// Convert a Scintilla string to a Qt Unicode string.
+QString QextScintilla::convertText(const char *s)
+{
+ if (isUtf8())
+ return QString::fromUtf8(s);
+
+ QString qs;
+
+ qs.setLatin1(s);
+
+ return qs;
+}
+
+
+// Set the source of the auto-completion list.
+void QextScintilla::setAutoCompletionSource(AutoCompletionSource source)
+{
+ acSource = source;
+}
+
+
+// Set the threshold for automatic auto-completion.
+void QextScintilla::setAutoCompletionThreshold(int thresh)
+{
+ acThresh = thresh;
+}
+
+
+// Set the auto-completion start characters.
+void QextScintilla::setAutoCompletionStartCharacters(const char *start)
+{
+ acStart = start;
+}
+
+
+// Set the APIs for auto-completion.
+void QextScintilla::setAutoCompletionAPIs(QextScintillaAPIs *apis)
+{
+ acAPIs = apis;
+}
+
+
+// Explicitly auto-complete from all sources.
+void QextScintilla::autoCompleteFromAll()
+{
+ startAutoCompletion(AcsAll, FALSE, showSingle);
+}
+
+
+// Explicitly auto-complete from the APIs.
+void QextScintilla::autoCompleteFromAPIs()
+{
+ startAutoCompletion(AcsAPIs, FALSE, showSingle);
+}
+
+
+// Explicitly auto-complete from the document.
+void QextScintilla::autoCompleteFromDocument()
+{
+ // If we are not in a word then ignore.
+ if (currentCharInWord())
+ startAutoCompletion(AcsDocument, FALSE, showSingle);
+}
+
+
+// Return TRUE if the current character (ie. the one before the carat) is part
+// of a word.
+bool QextScintilla::currentCharInWord()
+{
+ long pos = SendScintilla(SCI_GETCURRENTPOS);
+
+ if (pos <= 0)
+ return FALSE;
+
+ return isWordChar(SendScintilla(SCI_GETCHARAT,pos - 1));
+}
+
+
+// Check if a character can be in a word.
+bool QextScintilla::isWordChar(char ch) const
+{
+ const char *word_chars = 0;
+
+ if (!lex.isNull())
+ word_chars = lex->wordCharacters();
+
+ if (!word_chars)
+ word_chars = defaultWordChars;
+
+ return (strchr(word_chars, ch) != NULL);
+}
+
+
+// Recolour the document.
+void QextScintilla::recolor(int start,int end)
+{
+ SendScintilla(SCI_COLOURISE,start,end);
+}
+
+
+// Registered an image.
+void QextScintilla::registerImage(int id,const QPixmap *pm)
+{
+ SendScintilla(SCI_REGISTERIMAGE,id,pm);
+}
+
+
+// Clear all registered images.
+void QextScintilla::clearRegisteredImages()
+{
+ SendScintilla(SCI_CLEARREGISTEREDIMAGES);
+}
+
+
+// Set the fill-up characters for auto-completion.
+void QextScintilla::setAutoCompletionFillups(const char *fillups)
+{
+ if (!fillups)
+ fillups = "";
+
+ SendScintilla(SCI_AUTOCSETFILLUPS, fillups);
+ fillups_enabled = explicit_fillups = TRUE;
+
+ // Save them in case we need to reenable them at some point.
+ saved_fillups = fillups;
+}
+
+
+// Enable/disable fill-ups for auto-completion.
+void QextScintilla::setAutoCompletionFillupsEnabled(bool enabled)
+{
+ const char *fillups;
+
+ if (!enabled)
+ fillups = "";
+ else if (!explicit_fillups && !lex.isNull())
+ fillups = lex->autoCompletionFillups();
+ else
+ fillups = saved_fillups.data();
+
+ SendScintilla(SCI_AUTOCSETFILLUPS, fillups);
+ fillups_enabled = enabled;
+}
+
+
+// Return the state of fill-ups for auto-completion.
+bool QextScintilla::autoCompletionFillupsEnabled()
+{
+ return fillups_enabled;
+}
+
+
+// Set the case sensitivity for auto-completion.
+void QextScintilla::setAutoCompletionCaseSensitivity(bool cs)
+{
+ SendScintilla(SCI_AUTOCSETIGNORECASE,!cs);
+}
+
+
+// Return the case sensitivity for auto-completion.
+bool QextScintilla::autoCompletionCaseSensitivity()
+{
+ return !SendScintilla(SCI_AUTOCGETIGNORECASE);
+}
+
+
+// Set the replace word mode for auto-completion.
+void QextScintilla::setAutoCompletionReplaceWord(bool replace)
+{
+ SendScintilla(SCI_AUTOCSETDROPRESTOFWORD,replace);
+}
+
+
+// Return the replace word mode for auto-completion.
+bool QextScintilla::autoCompletionReplaceWord()
+{
+ return SendScintilla(SCI_AUTOCGETDROPRESTOFWORD);
+}
+
+
+// Set the single item mode for auto-completion.
+void QextScintilla::setAutoCompletionShowSingle(bool single)
+{
+ showSingle = single;
+}
+
+
+// Return the single item mode for auto-completion.
+bool QextScintilla::autoCompletionShowSingle()
+{
+ return showSingle;
+}
+
+
+// Set the APIs for call tips.
+void QextScintilla::setCallTipsAPIs(QextScintillaAPIs *apis)
+{
+ ctAPIs = apis;
+}
+
+
+// Set maximum number of call tips displayed.
+void QextScintilla::setCallTipsVisible(int nr)
+{
+ maxCallTips = nr;
+}
+
+
+// Set the document to display.
+void QextScintilla::setDocument(const QextScintillaDocument &document)
+{
+ if (doc.pdoc != document.pdoc)
+ {
+ doc.undisplay(this);
+ doc.attach(document);
+ doc.display(this,&document);
+ }
+}
+
+
+// Ensure the document is read-write and return True if was was read-only.
+bool QextScintilla::ensureRW()
+{
+ bool ro = isReadOnly();
+
+ if (ro)
+ setReadOnly(FALSE);
+
+ return ro;
+}
+
+
+// Return the number of the first visible line.
+int QextScintilla::firstVisibleLine()
+{
+ return SendScintilla(SCI_GETFIRSTVISIBLELINE);
+}
+
+
+// Return the height in pixels of the text in a particular line.
+int QextScintilla::textHeight(int linenr)
+{
+ return SendScintilla(SCI_TEXTHEIGHT, linenr);
+}
+
+
+// See if auto-completion or user list is active.
+bool QextScintilla::isListActive()
+{
+ return SendScintilla(SCI_AUTOCACTIVE);
+}
+
+
+// Cancel any current auto-completion or user list.
+void QextScintilla::cancelList()
+{
+ SendScintilla(SCI_AUTOCCANCEL);
+}
+
+
+// Display a user list.
+void QextScintilla::showUserList(int id, const QStringList &list)
+{
+ // Sanity check to make sure auto-completion doesn't get confused.
+ if (id <= 0)
+ return;
+
+ const char sep = '\x03';
+
+ SendScintilla(SCI_AUTOCSETSEPARATOR, sep);
+ SendScintilla(SCI_USERLISTSHOW, id, list.join(QChar(sep)).latin1());
+}
+
+
+// Translate the SCN_USERLISTSELECTION notification into something more useful.
+void QextScintilla::handleUserListSelection(const char *text, int id)
+{
+ emit userListActivated(id, QString(text));
+}