Mercurial > octave
view libgui/languages/build_ts/octave-qsci/qsciscintilla.cpp @ 31537:5ceb4bfcdb0f stable
add tools and files for updating the gui's language files for translation
* libgui/languages/build_ts/README.md: readme for updating language files
* libgui/languages/build_ts/octave-qsci: QScintilla source files for
languages without translation provided by QScintilla
* libgui/languages/build_ts/octave-qt: Qt source files for languages
without translation provided by Qt
author | Torsten Lilge <ttl-octave@mailbox.org> |
---|---|
date | Thu, 24 Nov 2022 06:48:25 +0100 |
parents | |
children | dd5ece3664ed |
line wrap: on
line source
// 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) 2019 Riverbank Computing Limited <info@riverbankcomputing.com> // // This file is part of QScintilla. // // This file may be used under the terms of the GNU General Public License // version 3.0 as published by the Free Software Foundation and appearing in // the file LICENSE included in the packaging of this file. Please review the // following information to ensure the GNU General Public License version 3.0 // requirements will be met: http://www.gnu.org/copyleft/gpl.html. // // If you do not wish to use this file under the terms of the GPL version 3.0 // then you may purchase a commercial license. For more information contact // info@riverbankcomputing.com. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "Qsci/qsciscintilla.h" #include <string.h> #include <QAction> #include <QApplication> #include <QColor> #include <QEvent> #include <QImage> #include <QIODevice> #include <QKeyEvent> #include <QKeySequence> #include <QMenu> #include <QPoint> #include "Qsci/qsciabstractapis.h" #include "Qsci/qscicommandset.h" #include "Qsci/qscilexer.h" #include "Qsci/qscistyle.h" #include "Qsci/qscistyledtext.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 list separators for auto-completion and user lists. const char acSeparator = '\x03'; const char userSeparator = '\x04'; // 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"; // Forward declarations. static QColor asQColor(long sci_colour); // The ctor. QsciScintilla::QsciScintilla(QWidget *parent) : QsciScintillaBase(parent), allocatedMarkers(0), allocatedIndicators(7), oldPos(-1), selText(false), fold(NoFoldStyle), foldmargin(2), autoInd(false), braceMode(NoBraceMatch), acSource(AcsNone), acThresh(-1), wchars(defaultWordChars), call_tips_position(CallTipsBelowText), call_tips_style(CallTipsNoContext), maxCallTips(-1), use_single(AcusNever), explicit_fillups(""), fillups_enabled(false) { connect(this,SIGNAL(SCN_MODIFYATTEMPTRO()), SIGNAL(modificationAttempted())); connect(this,SIGNAL(SCN_MODIFIED(int,int,const char *,int,int,int,int,int,int,int)), SLOT(handleModified(int,int,const char *,int,int,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_INDICATORCLICK(int,int)), SLOT(handleIndicatorClick(int,int))); connect(this,SIGNAL(SCN_INDICATORRELEASE(int,int)), SLOT(handleIndicatorRelease(int,int))); connect(this,SIGNAL(SCN_MARGINCLICK(int,int,int)), SLOT(handleMarginClick(int,int,int))); connect(this,SIGNAL(SCN_MARGINRIGHTCLICK(int,int,int)), SLOT(handleMarginRightClick(int,int,int))); connect(this,SIGNAL(SCN_SAVEPOINTREACHED()), SLOT(handleSavePointReached())); connect(this,SIGNAL(SCN_SAVEPOINTLEFT()), SLOT(handleSavePointLeft())); connect(this,SIGNAL(SCN_UPDATEUI(int)), SLOT(handleUpdateUI(int))); connect(this,SIGNAL(QSCN_SELCHANGED(bool)), SLOT(handleSelectionChanged(bool))); connect(this,SIGNAL(SCN_AUTOCSELECTION(const char *,int)), SLOT(handleAutoCompletionSelection())); 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. QPalette pal = QApplication::palette(); setColor(pal.text().color()); setPaper(pal.base().color()); setSelectionForegroundColor(pal.highlightedText().color()); setSelectionBackgroundColor(pal.highlight().color()); #if defined(Q_OS_WIN) setEolMode(EolWindows); #else // Note that EolMac is pre-OS/X. 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); setMatchedBraceForegroundColor(Qt::blue); setUnmatchedBraceForegroundColor(Qt::red); setAnnotationDisplay(AnnotationStandard); 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); // The default behaviour is unexpected. SendScintilla(SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR, SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE); // Create the standard command set. stdCmds = new QsciCommandSet(this); doc.display(this,0); } // The dtor. QsciScintilla::~QsciScintilla() { // Detach any current lexer. detachLexer(); doc.undisplay(this); delete stdCmds; } // Return the current text colour. QColor QsciScintilla::color() const { return nl_text_colour; } // Set the text colour. void QsciScintilla::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 overwrite mode. bool QsciScintilla::overwriteMode() const { return SendScintilla(SCI_GETOVERTYPE); } // Set the overwrite mode. void QsciScintilla::setOverwriteMode(bool overwrite) { SendScintilla(SCI_SETOVERTYPE, overwrite); } // Return the current paper colour. QColor QsciScintilla::paper() const { return nl_paper_colour; } // Set the paper colour. void QsciScintilla::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 QsciScintilla::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); QWidget::setFont(f); } } // Enable/disable auto-indent. void QsciScintilla::setAutoIndent(bool autoindent) { autoInd = autoindent; } // Set the brace matching mode. void QsciScintilla::setBraceMatching(BraceMatch bm) { braceMode = bm; } // Handle the addition of a character. void QsciScintilla::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 seems to // be handled correctly elsewhere. if (isListActive() && isStartChar(ch)) { cancelList(); startAutoCompletion(acSource, false, use_single == AcusAlways); return; } // Handle call tips. if (call_tips_style != CallTipsNone && !lex.isNull() && 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() && acSource != AcsNone) { if (isStartChar(ch)) startAutoCompletion(acSource, false, use_single == AcusAlways); else if (acThresh >= 1 && isWordCharacter(ch)) startAutoCompletion(acSource, true, use_single == AcusAlways); } } // See if a call tip is active. bool QsciScintilla::isCallTipActive() const { return SendScintilla(SCI_CALLTIPACTIVE); } // Handle a possible change to any current call tip. void QsciScintilla::callTip() { QsciAbstractAPIs *apis = lex->apis(); if (!apis) return; int pos, commas = 0; bool found = false; char ch; pos = SendScintilla(SCI_GETCURRENTPOS); // Move backwards through the line looking for the start of the current // call tip and working out which argument it is. while ((ch = getCharacter(pos)) != '\0') { if (ch == ',') ++commas; else if (ch == ')') { int depth = 1; // Ignore everything back to the start of the corresponding // parenthesis. while ((ch = getCharacter(pos)) != '\0') { if (ch == ')') ++depth; else if (ch == '(' && --depth == 0) break; } } else if (ch == '(') { found = true; break; } } // Cancel any existing call tip. SendScintilla(SCI_CALLTIPCANCEL); // Done if there is no new call tip to set. if (!found) return; QStringList context = apiContext(pos, pos, ctPos); if (context.isEmpty()) return; // The last word is complete, not partial. context << QString(); ct_cursor = 0; ct_shifts.clear(); ct_entries = apis->callTips(context, commas, call_tips_style, ct_shifts); int nr_entries = ct_entries.count(); if (nr_entries == 0) return; if (maxCallTips > 0 && maxCallTips < nr_entries) { ct_entries = ct_entries.mid(0, maxCallTips); nr_entries = maxCallTips; } int shift; QString ct; int nr_shifts = ct_shifts.count(); if (maxCallTips < 0 && nr_entries > 1) { shift = (nr_shifts > 0 ? ct_shifts.first() : 0); ct = ct_entries[0]; ct.prepend('\002'); } else { if (nr_shifts > nr_entries) nr_shifts = nr_entries; // Find the biggest shift. shift = 0; for (int i = 0; i < nr_shifts; ++i) { int sh = ct_shifts[i]; if (shift < sh) shift = sh; } ct = ct_entries.join("\n"); } ScintillaBytes ct_bytes = textAsBytes(ct); const char *cts = ScintillaBytesConstData(ct_bytes); SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), cts); // Done if there is more than one call tip. if (nr_entries > 1) return; // Highlight the current argument. const char *astart; if (commas == 0) astart = strchr(cts, '('); else for (astart = strchr(cts, ','); astart && --commas > 0; astart = strchr(astart + 1, ',')) ; if (!astart || !*++astart) return; // The end is at the next comma or unmatched closing parenthesis. const char *aend; int depth = 0; for (aend = astart; *aend; ++aend) { char ch = *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 - cts, aend - cts); } // Handle a call tip click. void QsciScintilla::handleCallTipClick(int dir) { int nr_entries = ct_entries.count(); // Move the cursor while bounds checking. if (dir == 1) { if (ct_cursor - 1 < 0) return; --ct_cursor; } else if (dir == 2) { if (ct_cursor + 1 >= nr_entries) return; ++ct_cursor; } else return; int shift = (ct_shifts.count() > ct_cursor ? ct_shifts[ct_cursor] : 0); QString ct = ct_entries[ct_cursor]; // Add the arrows. if (ct_cursor < nr_entries - 1) ct.prepend('\002'); if (ct_cursor > 0) ct.prepend('\001'); SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), ct.toLatin1().data()); } // Shift the position of the call tip (to take any context into account) but // don't go before the start of the line. int QsciScintilla::adjustedCallTipPosition(int ctshift) const { int ct = ctPos; if (ctshift) { int ctmin = SendScintilla(SCI_POSITIONFROMLINE, SendScintilla(SCI_LINEFROMPOSITION, ct)); if (ct - ctshift < ctmin) ct = ctmin; } return ct; } // Return the list of words that make up the context preceding the given // position. The list will only have more than one element if there is a lexer // set and it defines start strings. If so, then the last element might be // empty if a start string has just been typed. On return pos is at the start // of the context. QStringList QsciScintilla::apiContext(int pos, int &context_start, int &last_word_start) { enum { Either, Separator, Word }; QStringList words; int good_pos = pos, expecting = Either; last_word_start = -1; while (pos > 0) { if (getSeparator(pos)) { if (expecting == Either) words.prepend(QString()); else if (expecting == Word) break; good_pos = pos; expecting = Word; } else { QString word = getWord(pos); if (word.isEmpty() || expecting == Separator) break; words.prepend(word); good_pos = pos; expecting = Separator; // Return the position of the start of the last word if required. if (last_word_start < 0) last_word_start = pos; } // Strip any preceding spaces (mainly around operators). char ch; while ((ch = getCharacter(pos)) != '\0') { // This is the same definition of space that Scintilla uses. if (ch != ' ' && (ch < 0x09 || ch > 0x0d)) { ++pos; break; } } } // A valid sequence always starts with a word and so should be expecting a // separator. if (expecting != Separator) words.clear(); context_start = good_pos; return words; } // Try and get a lexer's word separator from the text before the current // position. Return true if one was found and adjust the position accordingly. bool QsciScintilla::getSeparator(int &pos) const { int opos = pos; // Go through each separator. for (int i = 0; i < wseps.count(); ++i) { const QString &ws = wseps[i]; // Work backwards. uint l; for (l = ws.length(); l; --l) { char ch = getCharacter(pos); if (ch == '\0' || ws.at(l - 1) != ch) break; } if (!l) return true; // Reset for the next separator. pos = opos; } return false; } // Try and get a word from the text before the current position. Return the // word if one was found and adjust the position accordingly. QString QsciScintilla::getWord(int &pos) const { QString word; bool numeric = true; char ch; while ((ch = getCharacter(pos)) != '\0') { if (!isWordCharacter(ch)) { ++pos; break; } if (ch < '0' || ch > '9') numeric = false; word.prepend(ch); } // We don't auto-complete numbers. if (numeric) word.truncate(0); return word; } // Get the "next" character (ie. the one before the current position) in the // current line. The character will be '\0' if there are no more. char QsciScintilla::getCharacter(int &pos) const { if (pos <= 0) return '\0'; char ch = SendScintilla(SCI_GETCHARAT, --pos); // Don't go past the end of the previous line. if (ch == '\n' || ch == '\r') { ++pos; return '\0'; } return ch; } // See if a character is an auto-completion start character, ie. the last // character of a word separator. bool QsciScintilla::isStartChar(char ch) const { QString s = QChar(ch); for (int i = 0; i < wseps.count(); ++i) if (wseps[i].endsWith(s)) return true; return false; } // Possibly start auto-completion. void QsciScintilla::startAutoCompletion(AutoCompletionSource acs, bool checkThresh, bool choose_single) { int start, ignore; QStringList context = apiContext(SendScintilla(SCI_GETCURRENTPOS), start, ignore); if (context.isEmpty()) return; // Get the last word's raw data and length. ScintillaBytes s = textAsBytes(context.last()); const char *last_data = ScintillaBytesConstData(s); int last_len = s.length(); if (checkThresh && last_len < acThresh) return; // Generate the string representing the valid words to select from. QStringList wlist; if ((acs == AcsAll || acs == AcsAPIs) && !lex.isNull()) { QsciAbstractAPIs *apis = lex->apis(); if (apis) apis->updateAutoCompletionList(context, wlist); } if (acs == AcsAll || acs == AcsDocument) { int sflags = SCFIND_WORDSTART; if (!SendScintilla(SCI_AUTOCGETIGNORECASE)) sflags |= SCFIND_MATCHCASE; SendScintilla(SCI_SETSEARCHFLAGS, sflags); int pos = 0; int dlen = SendScintilla(SCI_GETLENGTH); int caret = SendScintilla(SCI_GETCURRENTPOS); int clen = caret - start; char *orig_context = new char[clen + 1]; SendScintilla(SCI_GETTEXTRANGE, start, caret, orig_context); for (;;) { int fstart; SendScintilla(SCI_SETTARGETSTART, pos); SendScintilla(SCI_SETTARGETEND, dlen); if ((fstart = SendScintilla(SCI_SEARCHINTARGET, clen, orig_context)) < 0) break; // Move past the root part. pos = fstart + clen; // Skip if this is the context we are auto-completing. if (pos == caret) continue; // Get the rest of this word. QString w = last_data; while (pos < dlen) { char ch = SendScintilla(SCI_GETCHARAT, pos); if (!isWordCharacter(ch)) break; w += ch; ++pos; } // Add the word if it isn't already there. if (!w.isEmpty()) { bool keep; // If there are APIs then check if the word is already present // as an API word (i.e. with a trailing space). if (acs == AcsAll) { QString api_w = w; api_w.append(' '); keep = !wlist.contains(api_w); } else { keep = true; } if (keep && !wlist.contains(w)) wlist.append(w); } } delete []orig_context; } if (wlist.isEmpty()) return; wlist.sort(); SendScintilla(SCI_AUTOCSETCHOOSESINGLE, choose_single); SendScintilla(SCI_AUTOCSETSEPARATOR, acSeparator); ScintillaBytes wlist_s = textAsBytes(wlist.join(QChar(acSeparator))); SendScintilla(SCI_AUTOCSHOW, last_len, ScintillaBytesConstData(wlist_s)); } // Maintain the indentation of the previous line. void QsciScintilla::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 QsciScintilla::autoIndentation(char ch, long pos) { int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos); int ind_width = indentWidth(); long curr_line_start = SendScintilla(SCI_POSITIONFROMLINE, curr_line); const char *block_start = lex->blockStart(); bool start_single = (block_start && qstrlen(block_start) == 1); const char *block_end = lex->blockEnd(); bool end_single = (block_end && qstrlen(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) - ind_width); } 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) - ind_width); } else if (ch == '\r' || ch == '\n') { // Don't auto-indent the line (ie. preserve its existing indentation) // if we have inserted a new line above by pressing return at the start // of this line - in other words, if the previous line is empty. long prev_line_length = SendScintilla(SCI_GETLINEENDPOSITION, curr_line - 1) - SendScintilla(SCI_POSITIONFROMLINE, curr_line - 1); if (prev_line_length != 0) autoIndentLine(pos, curr_line, blockIndent(curr_line - 1)); } } // Set the indentation for a line. void QsciScintilla::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 QsciScintilla::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 = indentWidth(); 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 QsciScintilla::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. QsciScintilla::IndentState QsciScintilla::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 QsciScintilla::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 QsciScintilla::isUtf8() const { return (SendScintilla(SCI_GETCODEPAGE) == SC_CP_UTF8); } // Set the code page. void QsciScintilla::setUtf8(bool cp) { SendScintilla(SCI_SETCODEPAGE, (cp ? SC_CP_UTF8 : 0)); } // Return the end-of-line mode. QsciScintilla::EolMode QsciScintilla::eolMode() const { return (EolMode)SendScintilla(SCI_GETEOLMODE); } // Set the end-of-line mode. void QsciScintilla::setEolMode(EolMode mode) { SendScintilla(SCI_SETEOLMODE, mode); } // Convert the end-of-lines to a particular mode. void QsciScintilla::convertEols(EolMode mode) { SendScintilla(SCI_CONVERTEOLS, mode); } // Add an edge column. void QsciScintilla::addEdgeColumn(int colnr, const QColor &col) { SendScintilla(SCI_MULTIEDGEADDLINE, colnr, col); } // Clear all multi-edge columns. void QsciScintilla::clearEdgeColumns() { SendScintilla(SCI_MULTIEDGECLEARALL); } // Return the edge colour. QColor QsciScintilla::edgeColor() const { return asQColor(SendScintilla(SCI_GETEDGECOLOUR)); } // Set the edge colour. void QsciScintilla::setEdgeColor(const QColor &col) { SendScintilla(SCI_SETEDGECOLOUR, col); } // Return the edge column. int QsciScintilla::edgeColumn() const { return SendScintilla(SCI_GETEDGECOLUMN); } // Set the edge column. void QsciScintilla::setEdgeColumn(int colnr) { SendScintilla(SCI_SETEDGECOLUMN, colnr); } // Return the edge mode. QsciScintilla::EdgeMode QsciScintilla::edgeMode() const { return (EdgeMode)SendScintilla(SCI_GETEDGEMODE); } // Set the edge mode. void QsciScintilla::setEdgeMode(EdgeMode mode) { SendScintilla(SCI_SETEDGEMODE, mode); } // Return the end-of-line visibility. bool QsciScintilla::eolVisibility() const { return SendScintilla(SCI_GETVIEWEOL); } // Set the end-of-line visibility. void QsciScintilla::setEolVisibility(bool visible) { SendScintilla(SCI_SETVIEWEOL, visible); } // Return the extra ascent. int QsciScintilla::extraAscent() const { return SendScintilla(SCI_GETEXTRAASCENT); } // Set the extra ascent. void QsciScintilla::setExtraAscent(int extra) { SendScintilla(SCI_SETEXTRAASCENT, extra); } // Return the extra descent. int QsciScintilla::extraDescent() const { return SendScintilla(SCI_GETEXTRADESCENT); } // Set the extra descent. void QsciScintilla::setExtraDescent(int extra) { SendScintilla(SCI_SETEXTRADESCENT, extra); } // Return the whitespace size. int QsciScintilla::whitespaceSize() const { return SendScintilla(SCI_GETWHITESPACESIZE); } // Set the whitespace size. void QsciScintilla::setWhitespaceSize(int size) { SendScintilla(SCI_SETWHITESPACESIZE, size); } // Set the whitespace background colour. void QsciScintilla::setWhitespaceBackgroundColor(const QColor &col) { SendScintilla(SCI_SETWHITESPACEBACK, col.isValid(), col); } // Set the whitespace foreground colour. void QsciScintilla::setWhitespaceForegroundColor(const QColor &col) { SendScintilla(SCI_SETWHITESPACEFORE, col.isValid(), col); } // Return the whitespace visibility. QsciScintilla::WhitespaceVisibility QsciScintilla::whitespaceVisibility() const { return (WhitespaceVisibility)SendScintilla(SCI_GETVIEWWS); } // Set the whitespace visibility. void QsciScintilla::setWhitespaceVisibility(WhitespaceVisibility mode) { SendScintilla(SCI_SETVIEWWS, mode); } // Return the tab draw mode. QsciScintilla::TabDrawMode QsciScintilla::tabDrawMode() const { return (TabDrawMode)SendScintilla(SCI_GETTABDRAWMODE); } // Set the tab draw mode. void QsciScintilla::setTabDrawMode(TabDrawMode mode) { SendScintilla(SCI_SETTABDRAWMODE, mode); } // Return the line wrap mode. QsciScintilla::WrapMode QsciScintilla::wrapMode() const { return (WrapMode)SendScintilla(SCI_GETWRAPMODE); } // Set the line wrap mode. void QsciScintilla::setWrapMode(WrapMode mode) { SendScintilla(SCI_SETLAYOUTCACHE, (mode == WrapNone ? SC_CACHE_CARET : SC_CACHE_DOCUMENT)); SendScintilla(SCI_SETWRAPMODE, mode); } // Return the line wrap indent mode. QsciScintilla::WrapIndentMode QsciScintilla::wrapIndentMode() const { return (WrapIndentMode)SendScintilla(SCI_GETWRAPINDENTMODE); } // Set the line wrap indent mode. void QsciScintilla::setWrapIndentMode(WrapIndentMode mode) { SendScintilla(SCI_SETWRAPINDENTMODE, mode); } // Set the line wrap visual flags. void QsciScintilla::setWrapVisualFlags(WrapVisualFlag endFlag, WrapVisualFlag startFlag, int indent) { int flags = SC_WRAPVISUALFLAG_NONE; int loc = SC_WRAPVISUALFLAGLOC_DEFAULT; switch (endFlag) { case WrapFlagNone: break; case WrapFlagByText: flags |= SC_WRAPVISUALFLAG_END; loc |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT; break; case WrapFlagByBorder: flags |= SC_WRAPVISUALFLAG_END; break; case WrapFlagInMargin: flags |= SC_WRAPVISUALFLAG_MARGIN; break; } switch (startFlag) { case WrapFlagNone: break; case WrapFlagByText: flags |= SC_WRAPVISUALFLAG_START; loc |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT; break; case WrapFlagByBorder: flags |= SC_WRAPVISUALFLAG_START; break; case WrapFlagInMargin: flags |= SC_WRAPVISUALFLAG_MARGIN; break; } SendScintilla(SCI_SETWRAPVISUALFLAGS, flags); SendScintilla(SCI_SETWRAPVISUALFLAGSLOCATION, loc); SendScintilla(SCI_SETWRAPSTARTINDENT, indent); } // Set the folding style. void QsciScintilla::setFolding(FoldStyle folding, int margin) { fold = folding; foldmargin = margin; if (folding == NoFoldStyle) { SendScintilla(SCI_SETMARGINWIDTHN, margin, 0L); return; } int mask = SendScintilla(SCI_GETMODEVENTMASK); SendScintilla(SCI_SETMODEVENTMASK, mask | SC_MOD_CHANGEFOLD); SendScintilla(SCI_SETFOLDFLAGS, SC_FOLDFLAG_LINEAFTER_CONTRACTED); SendScintilla(SCI_SETMARGINTYPEN, margin, (long)SC_MARGIN_SYMBOL); SendScintilla(SCI_SETMARGINMASKN, margin, SC_MASK_FOLDERS); SendScintilla(SCI_SETMARGINSENSITIVEN, margin, 1); // Set the marker symbols to use. switch (folding) { case NoFoldStyle: break; 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, margin, defaultFoldMarginWidth); } // Clear all current folds. void QsciScintilla::clearFolds() { recolor(); int maxLine = SendScintilla(SCI_GETLINECOUNT); for (int line = 0; line < maxLine; line++) { int level = SendScintilla(SCI_GETFOLDLEVEL, line); if (level & SC_FOLDLEVELHEADERFLAG) { SendScintilla(SCI_SETFOLDEXPANDED, line, 1); foldExpand(line, true, false, 0, level); line--; } } } // Set up a folder marker. void QsciScintilla::setFoldMarker(int marknr, int mark) { SendScintilla(SCI_MARKERDEFINE, marknr, mark); if (mark != SC_MARK_EMPTY) { SendScintilla(SCI_MARKERSETFORE, marknr, QColor(Qt::white)); SendScintilla(SCI_MARKERSETBACK, marknr, QColor(Qt::black)); } } // Handle a click in the fold margin. This is mostly taken from SciTE. void QsciScintilla::foldClick(int lineClick, int bstate) { bool shift = bstate & Qt::ShiftModifier; bool ctrl = bstate & Qt::ControlModifier; if (shift && ctrl) { foldAll(); return; } int levelClick = SendScintilla(SCI_GETFOLDLEVEL, lineClick); if (levelClick & SC_FOLDLEVELHEADERFLAG) { if (shift) { // Ensure all children are visible. SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1); foldExpand(lineClick, true, true, 100, levelClick); } else if (ctrl) { 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 QsciScintilla::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 QsciScintilla::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 QsciScintilla::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 QsciScintilla::foldLine(int line) { SendScintilla(SCI_TOGGLEFOLD, line); } // Return the list of folded lines. QList<int> QsciScintilla::contractedFolds() const { QList<int> folds; int linenr = 0, fold_line; while ((fold_line = SendScintilla(SCI_CONTRACTEDFOLDNEXT, linenr)) >= 0) { folds.append(fold_line); linenr = fold_line + 1; } return folds; } // Set the fold state from a list. void QsciScintilla::setContractedFolds(const QList<int> &folds) { for (int i = 0; i < folds.count(); ++i) { int line = folds[i]; int last_line = SendScintilla(SCI_GETLASTCHILD, line, -1); SendScintilla(SCI_SETFOLDEXPANDED, line, 0L); SendScintilla(SCI_HIDELINES, line + 1, last_line); } } // Handle the SCN_MODIFIED notification. void QsciScintilla::handleModified(int pos, int mtype, const char *text, int len, int added, int line, int foldNow, int foldPrev, int token, int annotationLinesAdded) { Q_UNUSED(pos); Q_UNUSED(text); Q_UNUSED(len); Q_UNUSED(token); Q_UNUSED(annotationLinesAdded); if (mtype & SC_MOD_CHANGEFOLD) { if (fold) foldChanged(line, foldNow, foldPrev); } if (mtype & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { emit textChanged(); if (added != 0) emit linesChanged(); } } // Zoom in a number of points. void QsciScintilla::zoomIn(int range) { zoomTo(SendScintilla(SCI_GETZOOM) + range); } // Zoom in a single point. void QsciScintilla::zoomIn() { SendScintilla(SCI_ZOOMIN); } // Zoom out a number of points. void QsciScintilla::zoomOut(int range) { zoomTo(SendScintilla(SCI_GETZOOM) - range); } // Zoom out a single point. void QsciScintilla::zoomOut() { SendScintilla(SCI_ZOOMOUT); } // Set the zoom to a number of points. void QsciScintilla::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 QsciScintilla::findFirst(const QString &expr, bool re, bool cs, bool wo, bool wrap, bool forward, int line, int index, bool show, bool posix, bool cxx11) { if (expr.isEmpty()) { findState.status = FindState::Idle; return false; } findState.status = FindState::Finding; findState.expr = expr; findState.wrap = wrap; findState.forward = forward; findState.flags = (cs ? SCFIND_MATCHCASE : 0) | (wo ? SCFIND_WHOLEWORD : 0) | (re ? SCFIND_REGEXP : 0) | (posix ? SCFIND_POSIX : 0) | (cxx11 ? SCFIND_CXX11REGEX : 0); if (line < 0 || index < 0) findState.startpos = SendScintilla(SCI_GETCURRENTPOS); else findState.startpos = positionFromLineIndex(line, index); if (forward) findState.endpos = SendScintilla(SCI_GETLENGTH); else findState.endpos = 0; findState.show = show; return doFind(); } // Find the first occurrence of a string in the current selection. bool QsciScintilla::findFirstInSelection(const QString &expr, bool re, bool cs, bool wo, bool forward, bool show, bool posix, bool cxx11) { if (expr.isEmpty()) { findState.status = FindState::Idle; return false; } findState.status = FindState::FindingInSelection; findState.expr = expr; findState.wrap = false; findState.forward = forward; findState.flags = (cs ? SCFIND_MATCHCASE : 0) | (wo ? SCFIND_WHOLEWORD : 0) | (re ? SCFIND_REGEXP : 0) | (posix ? SCFIND_POSIX : 0) | (cxx11 ? SCFIND_CXX11REGEX : 0); findState.startpos_orig = SendScintilla(SCI_GETSELECTIONSTART); findState.endpos_orig = SendScintilla(SCI_GETSELECTIONEND); if (forward) { findState.startpos = findState.startpos_orig; findState.endpos = findState.endpos_orig; } else { findState.startpos = findState.endpos_orig; findState.endpos = findState.startpos_orig; } findState.show = show; return doFind(); } // Cancel any current search. void QsciScintilla::cancelFind() { findState.status = FindState::Idle; } // Find the next occurrence of a string. bool QsciScintilla::findNext() { if (findState.status == FindState::Idle) return false; return doFind(); } // Do the hard work of the find methods. bool QsciScintilla::doFind() { SendScintilla(SCI_SETSEARCHFLAGS, findState.flags); int 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) { // Restore the original selection. if (findState.status == FindState::FindingInSelection) SendScintilla(SCI_SETSEL, findState.startpos_orig, findState.endpos_orig); findState.status = FindState::Idle; 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; return true; } // Do a simple find between the start and end positions. int QsciScintilla::simpleFind() { if (findState.startpos == findState.endpos) return -1; SendScintilla(SCI_SETTARGETSTART, findState.startpos); SendScintilla(SCI_SETTARGETEND, findState.endpos); ScintillaBytes s = textAsBytes(findState.expr); return SendScintilla(SCI_SEARCHINTARGET, s.length(), ScintillaBytesConstData(s)); } // Replace the text found with the previous find method. void QsciScintilla::replace(const QString &replaceStr) { if (findState.status == FindState::Idle) return; long start = SendScintilla(SCI_GETSELECTIONSTART); long orig_len = SendScintilla(SCI_GETSELECTIONEND) - start; SendScintilla(SCI_TARGETFROMSELECTION); int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET; ScintillaBytes s = textAsBytes(replaceStr); long len = SendScintilla(cmd, -1, ScintillaBytesConstData(s)); // Reset the selection. SendScintilla(SCI_SETSELECTIONSTART, start); SendScintilla(SCI_SETSELECTIONEND, start + len); // Fix the original selection. findState.endpos_orig += (len - orig_len); if (findState.forward) findState.startpos = start + len; } // Query the modified state. bool QsciScintilla::isModified() const { return doc.isModified(); } // Set the modified state. void QsciScintilla::setModified(bool m) { if (!m) SendScintilla(SCI_SETSAVEPOINT); } // Handle the SCN_INDICATORCLICK notification. void QsciScintilla::handleIndicatorClick(int pos, int modifiers) { int state = mapModifiers(modifiers); int line, index; lineIndexFromPosition(pos, &line, &index); emit indicatorClicked(line, index, Qt::KeyboardModifiers(state)); } // Handle the SCN_INDICATORRELEASE notification. void QsciScintilla::handleIndicatorRelease(int pos, int modifiers) { int state = mapModifiers(modifiers); int line, index; lineIndexFromPosition(pos, &line, &index); emit indicatorReleased(line, index, Qt::KeyboardModifiers(state)); } // Handle the SCN_MARGINCLICK notification. void QsciScintilla::handleMarginClick(int pos, int modifiers, int margin) { int state = mapModifiers(modifiers); int line = SendScintilla(SCI_LINEFROMPOSITION, pos); if (fold && margin == foldmargin) foldClick(line, state); else emit marginClicked(margin, line, Qt::KeyboardModifiers(state)); } // Handle the SCN_MARGINRIGHTCLICK notification. void QsciScintilla::handleMarginRightClick(int pos, int modifiers, int margin) { int state = mapModifiers(modifiers); int line = SendScintilla(SCI_LINEFROMPOSITION, pos); emit marginRightClicked(margin, line, Qt::KeyboardModifiers(state)); } // Handle the SCN_SAVEPOINTREACHED notification. void QsciScintilla::handleSavePointReached() { doc.setModified(false); emit modificationChanged(false); } // Handle the SCN_SAVEPOINTLEFT notification. void QsciScintilla::handleSavePointLeft() { doc.setModified(true); emit modificationChanged(true); } // Handle the QSCN_SELCHANGED signal. void QsciScintilla::handleSelectionChanged(bool yes) { selText = yes; emit copyAvailable(yes); emit selectionChanged(); } // Get the current selection. void QsciScintilla::getSelection(int *lineFrom, int *indexFrom, int *lineTo, int *indexTo) const { if (selText) { lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONSTART), lineFrom, indexFrom); lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONEND), lineTo, indexTo); } else *lineFrom = *indexFrom = *lineTo = *indexTo = -1; } // Sets the current selection. void QsciScintilla::setSelection(int lineFrom, int indexFrom, int lineTo, int indexTo) { SendScintilla(SCI_SETSEL, positionFromLineIndex(lineFrom, indexFrom), positionFromLineIndex(lineTo, indexTo)); } // Set the background colour of selected text. void QsciScintilla::setSelectionBackgroundColor(const QColor &col) { int alpha = col.alpha(); if (alpha == 255) alpha = SC_ALPHA_NOALPHA; SendScintilla(SCI_SETSELBACK, 1, col); SendScintilla(SCI_SETSELALPHA, alpha); } // Set the foreground colour of selected text. void QsciScintilla::setSelectionForegroundColor(const QColor &col) { SendScintilla(SCI_SETSELFORE, 1, col); } // Reset the background colour of selected text to the default. void QsciScintilla::resetSelectionBackgroundColor() { SendScintilla(SCI_SETSELALPHA, SC_ALPHA_NOALPHA); SendScintilla(SCI_SETSELBACK, 0UL); } // Reset the foreground colour of selected text to the default. void QsciScintilla::resetSelectionForegroundColor() { SendScintilla(SCI_SETSELFORE, 0UL); } // Set the fill to the end-of-line for the selection. void QsciScintilla::setSelectionToEol(bool filled) { SendScintilla(SCI_SETSELEOLFILLED, filled); } // Return the fill to the end-of-line for the selection. bool QsciScintilla::selectionToEol() const { return SendScintilla(SCI_GETSELEOLFILLED); } // Set the width of the caret. void QsciScintilla::setCaretWidth(int width) { SendScintilla(SCI_SETCARETWIDTH, width); } // Set the width of the frame of the line containing the caret. void QsciScintilla::setCaretLineFrameWidth(int width) { SendScintilla(SCI_SETCARETLINEFRAME, width); } // Set the foreground colour of the caret. void QsciScintilla::setCaretForegroundColor(const QColor &col) { SendScintilla(SCI_SETCARETFORE, col); } // Set the background colour of the line containing the caret. void QsciScintilla::setCaretLineBackgroundColor(const QColor &col) { int alpha = col.alpha(); if (alpha == 255) alpha = SC_ALPHA_NOALPHA; SendScintilla(SCI_SETCARETLINEBACK, col); SendScintilla(SCI_SETCARETLINEBACKALPHA, alpha); } // Set the state of the background colour of the line containing the caret. void QsciScintilla::setCaretLineVisible(bool enable) { SendScintilla(SCI_SETCARETLINEVISIBLE, enable); } // Set the background colour of a hotspot area. void QsciScintilla::setHotspotBackgroundColor(const QColor &col) { SendScintilla(SCI_SETHOTSPOTACTIVEBACK, 1, col); } // Set the foreground colour of a hotspot area. void QsciScintilla::setHotspotForegroundColor(const QColor &col) { SendScintilla(SCI_SETHOTSPOTACTIVEFORE, 1, col); } // Reset the background colour of a hotspot area to the default. void QsciScintilla::resetHotspotBackgroundColor() { SendScintilla(SCI_SETHOTSPOTACTIVEBACK, 0UL); } // Reset the foreground colour of a hotspot area to the default. void QsciScintilla::resetHotspotForegroundColor() { SendScintilla(SCI_SETHOTSPOTACTIVEFORE, 0UL); } // Set the underline of a hotspot area. void QsciScintilla::setHotspotUnderline(bool enable) { SendScintilla(SCI_SETHOTSPOTACTIVEUNDERLINE, enable); } // Set the wrapping of a hotspot area. void QsciScintilla::setHotspotWrap(bool enable) { SendScintilla(SCI_SETHOTSPOTSINGLELINE, !enable); } // Query the read-only state. bool QsciScintilla::isReadOnly() const { return SendScintilla(SCI_GETREADONLY); } // Set the read-only state. void QsciScintilla::setReadOnly(bool ro) { setAttribute(Qt::WA_InputMethodEnabled, !ro); SendScintilla(SCI_SETREADONLY, ro); } // Append the given text. void QsciScintilla::append(const QString &text) { bool ro = ensureRW(); ScintillaBytes s = textAsBytes(text); SendScintilla(SCI_APPENDTEXT, s.length(), ScintillaBytesConstData(s)); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Insert the given text at the current position. void QsciScintilla::insert(const QString &text) { insertAtPos(text, -1); } // Insert the given text at the given line and offset. void QsciScintilla::insertAt(const QString &text, int line, int index) { insertAtPos(text, positionFromLineIndex(line, index)); } // Insert the given text at the given position. void QsciScintilla::insertAtPos(const QString &text, int pos) { bool ro = ensureRW(); SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_INSERTTEXT, pos, ScintillaBytesConstData(textAsBytes(text))); SendScintilla(SCI_ENDUNDOACTION); setReadOnly(ro); } // Begin a sequence of undoable actions. void QsciScintilla::beginUndoAction() { SendScintilla(SCI_BEGINUNDOACTION); } // End a sequence of undoable actions. void QsciScintilla::endUndoAction() { SendScintilla(SCI_ENDUNDOACTION); } // Redo a sequence of actions. void QsciScintilla::redo() { SendScintilla(SCI_REDO); } // Undo a sequence of actions. void QsciScintilla::undo() { SendScintilla(SCI_UNDO); } // See if there is something to redo. bool QsciScintilla::isRedoAvailable() const { return SendScintilla(SCI_CANREDO); } // See if there is something to undo. bool QsciScintilla::isUndoAvailable() const { return SendScintilla(SCI_CANUNDO); } // Return the number of lines. int QsciScintilla::lines() const { return SendScintilla(SCI_GETLINECOUNT); } // Return the line at a position. int QsciScintilla::lineAt(const QPoint &pos) const { 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 QsciScintilla::lineLength(int line) const { if (line < 0 || line >= SendScintilla(SCI_GETLINECOUNT)) return -1; return SendScintilla(SCI_LINELENGTH, line); } // Return the length of the current text. int QsciScintilla::length() const { return SendScintilla(SCI_GETTEXTLENGTH); } // Remove any selected text. void QsciScintilla::removeSelectedText() { SendScintilla(SCI_REPLACESEL, ""); } // Replace any selected text. void QsciScintilla::replaceSelectedText(const QString &text) { SendScintilla(SCI_REPLACESEL, ScintillaBytesConstData(textAsBytes(text))); } // Return the current selected text. QString QsciScintilla::selectedText() const { if (!selText) return QString(); char *buf = new char[SendScintilla(SCI_GETSELECTIONEND) - SendScintilla(SCI_GETSELECTIONSTART) + 1]; SendScintilla(SCI_GETSELTEXT, buf); QString qs = bytesAsText(buf); delete[] buf; return qs; } // Return the current text. QString QsciScintilla::text() const { int buflen = length() + 1; char *buf = new char[buflen]; SendScintilla(SCI_GETTEXT, buflen, buf); QString qs = bytesAsText(buf); delete[] buf; return qs; } // Return the text of a line. QString QsciScintilla::text(int line) const { 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 = bytesAsText(buf); delete[] buf; return qs; } // Return the text between two positions. QString QsciScintilla::text(int start, int end) const { char *buf = new char[end - start + 1]; SendScintilla(SCI_GETTEXTRANGE, start, end, buf); QString text = bytesAsText(buf); delete[] buf; return text; } // Return the text as encoded bytes between two positions. QByteArray QsciScintilla::bytes(int start, int end) const { QByteArray bytes(end - start + 1, '\0'); SendScintilla(SCI_GETTEXTRANGE, start, end, bytes.data()); return bytes; } // Set the given text. void QsciScintilla::setText(const QString &text) { bool ro = ensureRW(); SendScintilla(SCI_SETTEXT, ScintillaBytesConstData(textAsBytes(text))); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Get the cursor position void QsciScintilla::getCursorPosition(int *line, int *index) const { lineIndexFromPosition(SendScintilla(SCI_GETCURRENTPOS), line, index); } // Set the cursor position void QsciScintilla::setCursorPosition(int line, int index) { SendScintilla(SCI_GOTOPOS, positionFromLineIndex(line, index)); } // Ensure the cursor is visible. void QsciScintilla::ensureCursorVisible() { SendScintilla(SCI_SCROLLCARET); } // Ensure a line is visible. void QsciScintilla::ensureLineVisible(int line) { SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, line); } // Copy text to the clipboard. void QsciScintilla::copy() { SendScintilla(SCI_COPY); } // Cut text to the clipboard. void QsciScintilla::cut() { SendScintilla(SCI_CUT); } // Paste text from the clipboard. void QsciScintilla::paste() { SendScintilla(SCI_PASTE); } // Select all text, or deselect any selected text. void QsciScintilla::selectAll(bool select) { if (select) SendScintilla(SCI_SELECTALL); else SendScintilla(SCI_SETANCHOR, SendScintilla(SCI_GETCURRENTPOS)); } // Delete all text. void QsciScintilla::clear() { bool ro = ensureRW(); SendScintilla(SCI_CLEARALL); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Return the indentation of a line. int QsciScintilla::indentation(int line) const { return SendScintilla(SCI_GETLINEINDENTATION, line); } // Set the indentation of a line. void QsciScintilla::setIndentation(int line, int indentation) { SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_SETLINEINDENTATION, line, indentation); SendScintilla(SCI_ENDUNDOACTION); } // Indent a line. void QsciScintilla::indent(int line) { setIndentation(line, indentation(line) + indentWidth()); } // Unindent a line. void QsciScintilla::unindent(int line) { int newIndent = indentation(line) - indentWidth(); if (newIndent < 0) newIndent = 0; setIndentation(line, newIndent); } // Return the indentation of the current line. int QsciScintilla::currentIndent() const { return indentation(SendScintilla(SCI_LINEFROMPOSITION, SendScintilla(SCI_GETCURRENTPOS))); } // Return the current indentation width. int QsciScintilla::indentWidth() const { int w = indentationWidth(); if (w == 0) w = tabWidth(); return w; } // Return the state of indentation guides. bool QsciScintilla::indentationGuides() const { return (SendScintilla(SCI_GETINDENTATIONGUIDES) != SC_IV_NONE); } // Enable and disable indentation guides. void QsciScintilla::setIndentationGuides(bool enable) { int iv; if (!enable) iv = SC_IV_NONE; else if (lex.isNull()) iv = SC_IV_REAL; else iv = lex->indentationGuideView(); SendScintilla(SCI_SETINDENTATIONGUIDES, iv); } // Set the background colour of indentation guides. void QsciScintilla::setIndentationGuidesBackgroundColor(const QColor &col) { SendScintilla(SCI_STYLESETBACK, STYLE_INDENTGUIDE, col); } // Set the foreground colour of indentation guides. void QsciScintilla::setIndentationGuidesForegroundColor(const QColor &col) { SendScintilla(SCI_STYLESETFORE, STYLE_INDENTGUIDE, col); } // Return the indentation width. int QsciScintilla::indentationWidth() const { return SendScintilla(SCI_GETINDENT); } // Set the indentation width. void QsciScintilla::setIndentationWidth(int width) { SendScintilla(SCI_SETINDENT, width); } // Return the tab width. int QsciScintilla::tabWidth() const { return SendScintilla(SCI_GETTABWIDTH); } // Set the tab width. void QsciScintilla::setTabWidth(int width) { SendScintilla(SCI_SETTABWIDTH, width); } // Return the effect of the backspace key. bool QsciScintilla::backspaceUnindents() const { return SendScintilla(SCI_GETBACKSPACEUNINDENTS); } // Set the effect of the backspace key. void QsciScintilla::setBackspaceUnindents(bool unindents) { SendScintilla(SCI_SETBACKSPACEUNINDENTS, unindents); } // Return the effect of the tab key. bool QsciScintilla::tabIndents() const { return SendScintilla(SCI_GETTABINDENTS); } // Set the effect of the tab key. void QsciScintilla::setTabIndents(bool indents) { SendScintilla(SCI_SETTABINDENTS, indents); } // Return the indentation use of tabs. bool QsciScintilla::indentationsUseTabs() const { return SendScintilla(SCI_GETUSETABS); } // Set the indentation use of tabs. void QsciScintilla::setIndentationsUseTabs(bool tabs) { SendScintilla(SCI_SETUSETABS, tabs); } // Return the number of margins. int QsciScintilla::margins() const { return SendScintilla(SCI_GETMARGINS); } // Set the number of margins. void QsciScintilla::setMargins(int margins) { SendScintilla(SCI_SETMARGINS, margins); } // Return the margin background colour. QColor QsciScintilla::marginBackgroundColor(int margin) const { return asQColor(SendScintilla(SCI_GETMARGINBACKN, margin)); } // Set the margin background colour. void QsciScintilla::setMarginBackgroundColor(int margin, const QColor &col) { SendScintilla(SCI_SETMARGINBACKN, margin, col); } // Return the margin options. int QsciScintilla::marginOptions() const { return SendScintilla(SCI_GETMARGINOPTIONS); } // Set the margin options. void QsciScintilla::setMarginOptions(int options) { SendScintilla(SCI_SETMARGINOPTIONS, options); } // Return the margin type. QsciScintilla::MarginType QsciScintilla::marginType(int margin) const { return (MarginType)SendScintilla(SCI_GETMARGINTYPEN, margin); } // Set the margin type. void QsciScintilla::setMarginType(int margin, QsciScintilla::MarginType type) { SendScintilla(SCI_SETMARGINTYPEN, margin, type); } // Clear margin text. void QsciScintilla::clearMarginText(int line) { if (line < 0) SendScintilla(SCI_MARGINTEXTCLEARALL); else SendScintilla(SCI_MARGINSETTEXT, line, (const char *)0); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QString &text, int style) { int style_offset = SendScintilla(SCI_MARGINGETSTYLEOFFSET); SendScintilla(SCI_MARGINSETTEXT, line, ScintillaBytesConstData(textAsBytes(text))); SendScintilla(SCI_MARGINSETSTYLE, line, style - style_offset); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QString &text, const QsciStyle &style) { style.apply(this); setMarginText(line, text, style.style()); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QsciStyledText &text) { text.apply(this); setMarginText(line, text.text(), text.style()); } // Annotate a line. void QsciScintilla::setMarginText(int line, const QList<QsciStyledText> &text) { char *styles; ScintillaBytes styled_text = styleText(text, &styles, SendScintilla(SCI_MARGINGETSTYLEOFFSET)); SendScintilla(SCI_MARGINSETTEXT, line, ScintillaBytesConstData(styled_text)); SendScintilla(SCI_MARGINSETSTYLES, line, styles); delete[] styles; } // Return the state of line numbers in a margin. bool QsciScintilla::marginLineNumbers(int margin) const { return SendScintilla(SCI_GETMARGINTYPEN, margin); } // Enable and disable line numbers in a margin. void QsciScintilla::setMarginLineNumbers(int margin, bool lnrs) { SendScintilla(SCI_SETMARGINTYPEN, margin, lnrs ? SC_MARGIN_NUMBER : SC_MARGIN_SYMBOL); } // Return the marker mask of a margin. int QsciScintilla::marginMarkerMask(int margin) const { return SendScintilla(SCI_GETMARGINMASKN, margin); } // Set the marker mask of a margin. void QsciScintilla::setMarginMarkerMask(int margin,int mask) { SendScintilla(SCI_SETMARGINMASKN, margin, mask); } // Return the state of a margin's sensitivity. bool QsciScintilla::marginSensitivity(int margin) const { return SendScintilla(SCI_GETMARGINSENSITIVEN, margin); } // Enable and disable a margin's sensitivity. void QsciScintilla::setMarginSensitivity(int margin,bool sens) { SendScintilla(SCI_SETMARGINSENSITIVEN, margin, sens); } // Return the width of a margin. int QsciScintilla::marginWidth(int margin) const { return SendScintilla(SCI_GETMARGINWIDTHN, margin); } // Set the width of a margin. void QsciScintilla::setMarginWidth(int margin, int width) { SendScintilla(SCI_SETMARGINWIDTHN, margin, width); } // Set the width of a margin to the width of some text. void QsciScintilla::setMarginWidth(int margin, const QString &s) { int width = SendScintilla(SCI_TEXTWIDTH, STYLE_LINENUMBER, ScintillaBytesConstData(textAsBytes(s))); setMarginWidth(margin, width); } // Set the background colour of all margins. void QsciScintilla::setMarginsBackgroundColor(const QColor &col) { handleStylePaperChange(col, STYLE_LINENUMBER); } // Set the foreground colour of all margins. void QsciScintilla::setMarginsForegroundColor(const QColor &col) { handleStyleColorChange(col, STYLE_LINENUMBER); } // Set the font of all margins. void QsciScintilla::setMarginsFont(const QFont &f) { setStylesFont(f, STYLE_LINENUMBER); } // Define an indicator. int QsciScintilla::indicatorDefine(IndicatorStyle style, int indicatorNumber) { checkIndicator(indicatorNumber); if (indicatorNumber >= 0) SendScintilla(SCI_INDICSETSTYLE, indicatorNumber, static_cast<long>(style)); return indicatorNumber; } // Return the state of an indicator being drawn under the text. bool QsciScintilla::indicatorDrawUnder(int indicatorNumber) const { if (indicatorNumber < 0 || indicatorNumber >= INDIC_IME) return false; return SendScintilla(SCI_INDICGETUNDER, indicatorNumber); } // Set the state of indicators being drawn under the text. void QsciScintilla::setIndicatorDrawUnder(bool under, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETUNDER, i, under); } else { SendScintilla(SCI_INDICSETUNDER, indicatorNumber, under); } } } // Set the indicator foreground colour. void QsciScintilla::setIndicatorForegroundColor(const QColor &col, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int alpha = col.alpha(); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) { SendScintilla(SCI_INDICSETFORE, i, col); SendScintilla(SCI_INDICSETALPHA, i, alpha); } } else { SendScintilla(SCI_INDICSETFORE, indicatorNumber, col); SendScintilla(SCI_INDICSETALPHA, indicatorNumber, alpha); } } } // Set the indicator hover foreground colour. void QsciScintilla::setIndicatorHoverForegroundColor(const QColor &col, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETHOVERFORE, i, col); } else { SendScintilla(SCI_INDICSETHOVERFORE, indicatorNumber, col); } } } // Set the indicator hover style. void QsciScintilla::setIndicatorHoverStyle(IndicatorStyle style, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETHOVERSTYLE, i, static_cast<long>(style)); } else { SendScintilla(SCI_INDICSETHOVERSTYLE, indicatorNumber, static_cast<long>(style)); } } } // Set the indicator outline colour. void QsciScintilla::setIndicatorOutlineColor(const QColor &col, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int alpha = col.alpha(); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) SendScintilla(SCI_INDICSETOUTLINEALPHA, i, alpha); } else { SendScintilla(SCI_INDICSETOUTLINEALPHA, indicatorNumber, alpha); } } } // Fill a range with an indicator. void QsciScintilla::fillIndicatorRange(int lineFrom, int indexFrom, int lineTo, int indexTo, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int start = positionFromLineIndex(lineFrom, indexFrom); int finish = positionFromLineIndex(lineTo, indexTo); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) { SendScintilla(SCI_SETINDICATORCURRENT, i); SendScintilla(SCI_INDICATORFILLRANGE, start, finish - start); } } else { SendScintilla(SCI_SETINDICATORCURRENT, indicatorNumber); SendScintilla(SCI_INDICATORFILLRANGE, start, finish - start); } } } // Clear a range with an indicator. void QsciScintilla::clearIndicatorRange(int lineFrom, int indexFrom, int lineTo, int indexTo, int indicatorNumber) { if (indicatorNumber < INDIC_IME) { int start = positionFromLineIndex(lineFrom, indexFrom); int finish = positionFromLineIndex(lineTo, indexTo); // We ignore allocatedIndicators to allow any indicators defined // elsewhere (e.g. in lexers) to be set. if (indicatorNumber < 0) { for (int i = 0; i < INDIC_IME; ++i) { SendScintilla(SCI_SETINDICATORCURRENT, i); SendScintilla(SCI_INDICATORCLEARRANGE, start, finish - start); } } else { SendScintilla(SCI_SETINDICATORCURRENT, indicatorNumber); SendScintilla(SCI_INDICATORCLEARRANGE, start, finish - start); } } } // Define a marker based on a symbol. int QsciScintilla::markerDefine(MarkerSymbol sym, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) SendScintilla(SCI_MARKERDEFINE, markerNumber, static_cast<long>(sym)); return markerNumber; } // Define a marker based on a character. int QsciScintilla::markerDefine(char ch, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) SendScintilla(SCI_MARKERDEFINE, markerNumber, static_cast<long>(SC_MARK_CHARACTER) + ch); return markerNumber; } // Define a marker based on a QPixmap. int QsciScintilla::markerDefine(const QPixmap &pm, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) SendScintilla(SCI_MARKERDEFINEPIXMAP, markerNumber, pm); return markerNumber; } // Define a marker based on a QImage. int QsciScintilla::markerDefine(const QImage &im, int markerNumber) { checkMarker(markerNumber); if (markerNumber >= 0) { SendScintilla(SCI_RGBAIMAGESETHEIGHT, im.height()); SendScintilla(SCI_RGBAIMAGESETWIDTH, im.width()); SendScintilla(SCI_MARKERDEFINERGBAIMAGE, markerNumber, im); } return markerNumber; } // Add a marker to a line. int QsciScintilla::markerAdd(int linenr, int markerNumber) { if (markerNumber < 0 || markerNumber > MARKER_MAX || (allocatedMarkers & (1 << markerNumber)) == 0) return -1; return SendScintilla(SCI_MARKERADD, linenr, markerNumber); } // Get the marker mask for a line. unsigned QsciScintilla::markersAtLine(int linenr) const { return SendScintilla(SCI_MARKERGET, linenr); } // Delete a marker from a line. void QsciScintilla::markerDelete(int linenr, int markerNumber) { if (markerNumber <= MARKER_MAX) { if (markerNumber < 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 << markerNumber)) SendScintilla(SCI_MARKERDELETE, linenr, markerNumber); } } // Delete a marker from the text. void QsciScintilla::markerDeleteAll(int markerNumber) { if (markerNumber <= MARKER_MAX) { if (markerNumber < 0) SendScintilla(SCI_MARKERDELETEALL, -1); else if (allocatedMarkers & (1 << markerNumber)) SendScintilla(SCI_MARKERDELETEALL, markerNumber); } } // Delete a marker handle from the text. void QsciScintilla::markerDeleteHandle(int mhandle) { SendScintilla(SCI_MARKERDELETEHANDLE, mhandle); } // Return the line containing a marker instance. int QsciScintilla::markerLine(int mhandle) const { return SendScintilla(SCI_MARKERLINEFROMHANDLE, mhandle); } // Search forwards for a marker. int QsciScintilla::markerFindNext(int linenr, unsigned mask) const { return SendScintilla(SCI_MARKERNEXT, linenr, mask); } // Search backwards for a marker. int QsciScintilla::markerFindPrevious(int linenr, unsigned mask) const { return SendScintilla(SCI_MARKERPREVIOUS, linenr, mask); } // Set the marker background colour. void QsciScintilla::setMarkerBackgroundColor(const QColor &col, int markerNumber) { if (markerNumber <= MARKER_MAX) { int alpha = col.alpha(); // An opaque background would make the text invisible. if (alpha == 255) alpha = SC_ALPHA_NOALPHA; if (markerNumber < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) { SendScintilla(SCI_MARKERSETBACK, m, col); SendScintilla(SCI_MARKERSETALPHA, m, alpha); } am >>= 1; } } else if (allocatedMarkers & (1 << markerNumber)) { SendScintilla(SCI_MARKERSETBACK, markerNumber, col); SendScintilla(SCI_MARKERSETALPHA, markerNumber, alpha); } } } // Set the marker foreground colour. void QsciScintilla::setMarkerForegroundColor(const QColor &col, int markerNumber) { if (markerNumber <= MARKER_MAX) { if (markerNumber < 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 << markerNumber)) { SendScintilla(SCI_MARKERSETFORE, markerNumber, col); } } } // Check a marker, allocating a marker number if necessary. void QsciScintilla::checkMarker(int &markerNumber) { allocateId(markerNumber, allocatedMarkers, 0, MARKER_MAX); } // Check an indicator, allocating an indicator number if necessary. void QsciScintilla::checkIndicator(int &indicatorNumber) { allocateId(indicatorNumber, allocatedIndicators, INDIC_CONTAINER, INDIC_IME - 1); } // Make sure an identifier is valid and allocate it if necessary. void QsciScintilla::allocateId(int &id, unsigned &allocated, int min, int max) { if (id >= 0) { // Note that we allow existing identifiers to be explicitly redefined. if (id > max) id = -1; } else { unsigned aids = allocated >> min; // Find the smallest unallocated identifier. for (id = min; id <= max; ++id) { if ((aids & 1) == 0) break; aids >>= 1; } } // Allocate the identifier if it is valid. if (id >= 0) allocated |= (1 << id); } // Reset the fold margin colours. void QsciScintilla::resetFoldMarginColors() { SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 0, 0L); SendScintilla(SCI_SETFOLDMARGINCOLOUR, 0, 0L); } // Set the fold margin colours. void QsciScintilla::setFoldMarginColors(const QColor &fore, const QColor &back) { SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 1, fore); SendScintilla(SCI_SETFOLDMARGINCOLOUR, 1, back); } // Set the call tips background colour. void QsciScintilla::setCallTipsBackgroundColor(const QColor &col) { SendScintilla(SCI_CALLTIPSETBACK, col); } // Set the call tips foreground colour. void QsciScintilla::setCallTipsForegroundColor(const QColor &col) { SendScintilla(SCI_CALLTIPSETFORE, col); } // Set the call tips highlight colour. void QsciScintilla::setCallTipsHighlightColor(const QColor &col) { SendScintilla(SCI_CALLTIPSETFOREHLT, col); } // Set the matched brace background colour. void QsciScintilla::setMatchedBraceBackgroundColor(const QColor &col) { SendScintilla(SCI_STYLESETBACK, STYLE_BRACELIGHT, col); } // Set the matched brace foreground colour. void QsciScintilla::setMatchedBraceForegroundColor(const QColor &col) { SendScintilla(SCI_STYLESETFORE, STYLE_BRACELIGHT, col); } // Set the matched brace indicator. void QsciScintilla::setMatchedBraceIndicator(int indicatorNumber) { SendScintilla(SCI_BRACEHIGHLIGHTINDICATOR, 1, indicatorNumber); } // Reset the matched brace indicator. void QsciScintilla::resetMatchedBraceIndicator() { SendScintilla(SCI_BRACEHIGHLIGHTINDICATOR, 0, 0L); } // Set the unmatched brace background colour. void QsciScintilla::setUnmatchedBraceBackgroundColor(const QColor &col) { SendScintilla(SCI_STYLESETBACK, STYLE_BRACEBAD, col); } // Set the unmatched brace foreground colour. void QsciScintilla::setUnmatchedBraceForegroundColor(const QColor &col) { SendScintilla(SCI_STYLESETFORE, STYLE_BRACEBAD, col); } // Set the unmatched brace indicator. void QsciScintilla::setUnmatchedBraceIndicator(int indicatorNumber) { SendScintilla(SCI_BRACEBADLIGHTINDICATOR, 1, indicatorNumber); } // Reset the unmatched brace indicator. void QsciScintilla::resetUnmatchedBraceIndicator() { SendScintilla(SCI_BRACEBADLIGHTINDICATOR, 0, 0L); } // Detach any lexer. void QsciScintilla::detachLexer() { if (!lex.isNull()) { lex->setEditor(0); lex->disconnect(this); SendScintilla(SCI_STYLERESETDEFAULT); SendScintilla(SCI_STYLECLEARALL); } } // Set the lexer. void QsciScintilla::setLexer(QsciLexer *lexer) { // Detach any current lexer. detachLexer(); // Connect up the new lexer. lex = lexer; if (lex) { SendScintilla(SCI_CLEARDOCUMENTSTYLE); if (lex->lexer()) SendScintilla(SCI_SETLEXERLANGUAGE, lex->lexer()); else SendScintilla(SCI_SETLEXER, lex->lexerId()); lex->setEditor(this); 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_SETPROPERTY, "fold", "1"); SendScintilla(SCI_SETPROPERTY, "fold.html", "1"); // 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) kw = ""; SendScintilla(SCI_SETKEYWORDS, k, kw); } // Initialise each style. Do the default first so its (possibly // incorrect) font setting gets reset when style 0 is set. setLexerStyle(STYLE_DEFAULT); for (int s = 0; s <= STYLE_MAX; ++s) if (!lex->description(s).isEmpty()) setLexerStyle(s); // Initialise the properties. lex->refreshProperties(); // Set the auto-completion fillups and word separators. setAutoCompletionFillupsEnabled(fillups_enabled); wseps = lex->autoCompletionWordSeparators(); wchars = lex->wordCharacters(); if (!wchars) wchars = defaultWordChars; SendScintilla(SCI_AUTOCSETIGNORECASE, !lex->caseSensitive()); recolor(); } else { SendScintilla(SCI_SETLEXER, SCLEX_CONTAINER); setColor(nl_text_colour); setPaper(nl_paper_colour); SendScintilla(SCI_AUTOCSETFILLUPS, ""); SendScintilla(SCI_AUTOCSETIGNORECASE, false); wseps.clear(); wchars = defaultWordChars; } } // Set a particular style of the current lexer. void QsciScintilla::setLexerStyle(int style) { handleStyleColorChange(lex->color(style), style); handleStyleEolFillChange(lex->eolFill(style), style); handleStyleFontChange(lex->font(style), style); handleStylePaperChange(lex->paper(style), style); } // Get the current lexer. QsciLexer *QsciScintilla::lexer() const { return lex; } // Handle a change in lexer style foreground colour. void QsciScintilla::handleStyleColorChange(const QColor &c, int style) { SendScintilla(SCI_STYLESETFORE, style, c); } // Handle a change in lexer style end-of-line fill. void QsciScintilla::handleStyleEolFillChange(bool eolfill, int style) { SendScintilla(SCI_STYLESETEOLFILLED, style, eolfill); } // Handle a change in lexer style font. void QsciScintilla::handleStyleFontChange(const QFont &f, int style) { setStylesFont(f, style); if (style == lex->braceStyle()) { setStylesFont(f, STYLE_BRACELIGHT); setStylesFont(f, STYLE_BRACEBAD); } } // Set the font for a style. void QsciScintilla::setStylesFont(const QFont &f, int style) { SendScintilla(SCI_STYLESETFONT, style, f.family().toLatin1().data()); SendScintilla(SCI_STYLESETSIZEFRACTIONAL, style, long(f.pointSizeF() * SC_FONT_SIZE_MULTIPLIER)); // Pass the Qt weight via the back door. SendScintilla(SCI_STYLESETWEIGHT, style, -f.weight()); SendScintilla(SCI_STYLESETITALIC, style, f.italic()); SendScintilla(SCI_STYLESETUNDERLINE, style, f.underline()); // Tie the font settings of the default style to that of style 0 (the style // conventionally used for whitespace by lexers). This is needed so that // fold marks, indentations, edge columns etc are set properly. if (style == 0) setStylesFont(f, STYLE_DEFAULT); } // Handle a change in lexer style background colour. void QsciScintilla::handleStylePaperChange(const QColor &c, int style) { SendScintilla(SCI_STYLESETBACK, style, c); } // Handle a change in lexer property. void QsciScintilla::handlePropertyChange(const char *prop, const char *val) { SendScintilla(SCI_SETPROPERTY, prop, val); } // Handle a change to the user visible user interface. void QsciScintilla::handleUpdateUI(int) { int 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 QsciScintilla::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 QsciScintilla::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, we should really use a virtual. if (!lex.isNull() && qstrcmp(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 QsciScintilla::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, 0L); if (other > brace) isInside = !isInside; } return isInside; } // Move to the matching brace. void QsciScintilla::moveToMatchingBrace() { gotoMatchingBrace(false); } // Select to the matching brace. void QsciScintilla::selectToMatchingBrace() { gotoMatchingBrace(true); } // Move to the matching brace and optionally select the text. void QsciScintilla::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. int QsciScintilla::positionFromLineIndex(int line, int index) const { int 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 QsciScintilla::lineIndexFromPosition(int position, int *line, int *index) const { int lin = SendScintilla(SCI_LINEFROMPOSITION, position); int linpos = SendScintilla(SCI_POSITIONFROMLINE, lin); int indx = 0; // Allow for multi-byte characters. while (linpos < position) { int new_linpos = SendScintilla(SCI_POSITIONAFTER, linpos); // If the position hasn't moved then we must be at the end of the text // (which implies that the position passed was beyond the end of the // text). if (new_linpos == linpos) break; linpos = new_linpos; ++indx; } *line = lin; *index = indx; } // Set the source of the automatic auto-completion list. void QsciScintilla::setAutoCompletionSource(AutoCompletionSource source) { acSource = source; } // Set the threshold for automatic auto-completion. void QsciScintilla::setAutoCompletionThreshold(int thresh) { acThresh = thresh; } // Set the auto-completion word separators if there is no current lexer. void QsciScintilla::setAutoCompletionWordSeparators(const QStringList &separators) { if (lex.isNull()) wseps = separators; } // Explicitly auto-complete from all sources. void QsciScintilla::autoCompleteFromAll() { startAutoCompletion(AcsAll, false, use_single != AcusNever); } // Explicitly auto-complete from the APIs. void QsciScintilla::autoCompleteFromAPIs() { startAutoCompletion(AcsAPIs, false, use_single != AcusNever); } // Explicitly auto-complete from the document. void QsciScintilla::autoCompleteFromDocument() { startAutoCompletion(AcsDocument, false, use_single != AcusNever); } // Check if a character can be in a word. bool QsciScintilla::isWordCharacter(char ch) const { return (strchr(wchars, ch) != NULL); } // Return the set of valid word characters. const char *QsciScintilla::wordCharacters() const { return wchars; } // Recolour the document. void QsciScintilla::recolor(int start, int end) { SendScintilla(SCI_COLOURISE, start, end); } // Registered a QPixmap image. void QsciScintilla::registerImage(int id, const QPixmap &pm) { SendScintilla(SCI_REGISTERIMAGE, id, pm); } // Registered a QImage image. void QsciScintilla::registerImage(int id, const QImage &im) { SendScintilla(SCI_RGBAIMAGESETHEIGHT, im.height()); SendScintilla(SCI_RGBAIMAGESETWIDTH, im.width()); SendScintilla(SCI_REGISTERRGBAIMAGE, id, im); } // Clear all registered images. void QsciScintilla::clearRegisteredImages() { SendScintilla(SCI_CLEARREGISTEREDIMAGES); } // Enable auto-completion fill-ups. void QsciScintilla::setAutoCompletionFillupsEnabled(bool enable) { const char *fillups; if (!enable) fillups = ""; else if (!lex.isNull()) fillups = lex->autoCompletionFillups(); else fillups = explicit_fillups.data(); SendScintilla(SCI_AUTOCSETFILLUPS, fillups); fillups_enabled = enable; } // See if auto-completion fill-ups are enabled. bool QsciScintilla::autoCompletionFillupsEnabled() const { return fillups_enabled; } // Set the fill-up characters for auto-completion if there is no current lexer. void QsciScintilla::setAutoCompletionFillups(const char *fillups) { explicit_fillups = fillups; setAutoCompletionFillupsEnabled(fillups_enabled); } // Set the case sensitivity for auto-completion. void QsciScintilla::setAutoCompletionCaseSensitivity(bool cs) { SendScintilla(SCI_AUTOCSETIGNORECASE, !cs); } // Return the case sensitivity for auto-completion. bool QsciScintilla::autoCompletionCaseSensitivity() const { return !SendScintilla(SCI_AUTOCGETIGNORECASE); } // Set the replace word mode for auto-completion. void QsciScintilla::setAutoCompletionReplaceWord(bool replace) { SendScintilla(SCI_AUTOCSETDROPRESTOFWORD, replace); } // Return the replace word mode for auto-completion. bool QsciScintilla::autoCompletionReplaceWord() const { return SendScintilla(SCI_AUTOCGETDROPRESTOFWORD); } // Set the single item mode for auto-completion. void QsciScintilla::setAutoCompletionUseSingle(AutoCompletionUseSingle single) { use_single = single; } // Return the single item mode for auto-completion. QsciScintilla::AutoCompletionUseSingle QsciScintilla::autoCompletionUseSingle() const { return use_single; } // Set the single item mode for auto-completion (deprecated). void QsciScintilla::setAutoCompletionShowSingle(bool single) { use_single = (single ? AcusExplicit : AcusNever); } // Return the single item mode for auto-completion (deprecated). bool QsciScintilla::autoCompletionShowSingle() const { return (use_single != AcusNever); } // Set current call tip position. void QsciScintilla::setCallTipsPosition(CallTipsPosition position) { SendScintilla(SCI_CALLTIPSETPOSITION, (position == CallTipsAboveText)); call_tips_position = position; } // Set current call tip style. void QsciScintilla::setCallTipsStyle(CallTipsStyle style) { call_tips_style = style; } // Set maximum number of call tips displayed. void QsciScintilla::setCallTipsVisible(int nr) { maxCallTips = nr; } // Set the document to display. void QsciScintilla::setDocument(const QsciDocument &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 QsciScintilla::ensureRW() { bool ro = isReadOnly(); if (ro) setReadOnly(false); return ro; } // Return the number of the first visible line. int QsciScintilla::firstVisibleLine() const { return SendScintilla(SCI_GETFIRSTVISIBLELINE); } // Set the number of the first visible line. void QsciScintilla::setFirstVisibleLine(int linenr) { SendScintilla(SCI_SETFIRSTVISIBLELINE, linenr); } // Return the height in pixels of the text in a particular line. int QsciScintilla::textHeight(int linenr) const { return SendScintilla(SCI_TEXTHEIGHT, linenr); } // See if auto-completion or user list is active. bool QsciScintilla::isListActive() const { return SendScintilla(SCI_AUTOCACTIVE); } // Cancel any current auto-completion or user list. void QsciScintilla::cancelList() { SendScintilla(SCI_AUTOCCANCEL); } // Handle a selection from the auto-completion list. void QsciScintilla::handleAutoCompletionSelection() { if (!lex.isNull()) { QsciAbstractAPIs *apis = lex->apis(); if (apis) apis->autoCompletionSelected(acSelection); } } // Display a user list. void QsciScintilla::showUserList(int id, const QStringList &list) { // Sanity check to make sure auto-completion doesn't get confused. if (id <= 0) return; SendScintilla(SCI_AUTOCSETSEPARATOR, userSeparator); ScintillaBytes s = textAsBytes(list.join(QChar(userSeparator))); SendScintilla(SCI_USERLISTSHOW, id, ScintillaBytesConstData(s)); } // Translate the SCN_USERLISTSELECTION notification into something more useful. void QsciScintilla::handleUserListSelection(const char *text, int id) { emit userListActivated(id, QString(text)); // Make sure the editor hasn't been deactivated as a side effect. activateWindow(); } // Return the case sensitivity of any lexer. bool QsciScintilla::caseSensitive() const { return lex.isNull() ? true : lex->caseSensitive(); } // Return true if the current list is an auto-completion list rather than a // user list. bool QsciScintilla::isAutoCompletionList() const { return (SendScintilla(SCI_AUTOCGETSEPARATOR) == acSeparator); } // Read the text from a QIODevice. bool QsciScintilla::read(QIODevice *io) { const int min_size = 1024 * 8; int buf_size = min_size; char *buf = new char[buf_size]; int data_len = 0; bool ok = true; qint64 part; // Read the whole lot in so we don't have to worry about character // boundaries. do { // Make sure there is a minimum amount of room. if (buf_size - data_len < min_size) { buf_size *= 2; char *new_buf = new char[buf_size * 2]; memcpy(new_buf, buf, data_len); delete[] buf; buf = new_buf; } part = io->read(buf + data_len, buf_size - data_len - 1); data_len += part; } while (part > 0); if (part < 0) ok = false; else { buf[data_len] = '\0'; bool ro = ensureRW(); SendScintilla(SCI_SETTEXT, buf); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } delete[] buf; return ok; } // Write the text to a QIODevice. bool QsciScintilla::write(QIODevice *io) const { const char *buf = reinterpret_cast<const char *>(SendScintillaPtrResult(SCI_GETCHARACTERPOINTER)); const char *bp = buf; uint buflen = qstrlen(buf); while (buflen > 0) { qint64 part = io->write(bp, buflen); if (part < 0) return false; bp += part; buflen -= part; } return true; } // Return the word at the given coordinates. QString QsciScintilla::wordAtLineIndex(int line, int index) const { return wordAtPosition(positionFromLineIndex(line, index)); } // Return the word at the given coordinates. QString QsciScintilla::wordAtPoint(const QPoint &point) const { long close_pos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, point.x(), point.y()); return wordAtPosition(close_pos); } // Return the word at the given position. QString QsciScintilla::wordAtPosition(int position) const { if (position < 0) return QString(); long start_pos = SendScintilla(SCI_WORDSTARTPOSITION, position, true); long end_pos = SendScintilla(SCI_WORDENDPOSITION, position, true); if (start_pos >= end_pos) return QString(); return text(start_pos, end_pos); } // Return the display style for annotations. QsciScintilla::AnnotationDisplay QsciScintilla::annotationDisplay() const { return (AnnotationDisplay)SendScintilla(SCI_ANNOTATIONGETVISIBLE); } // Set the display style for annotations. void QsciScintilla::setAnnotationDisplay(QsciScintilla::AnnotationDisplay display) { SendScintilla(SCI_ANNOTATIONSETVISIBLE, display); setScrollBars(); } // Clear annotations. void QsciScintilla::clearAnnotations(int line) { if (line >= 0) SendScintilla(SCI_ANNOTATIONSETTEXT, line, (const char *)0); else SendScintilla(SCI_ANNOTATIONCLEARALL); setScrollBars(); } // Annotate a line. void QsciScintilla::annotate(int line, const QString &text, int style) { int style_offset = SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET); ScintillaBytes s = textAsBytes(text); SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaBytesConstData(s)); SendScintilla(SCI_ANNOTATIONSETSTYLE, line, style - style_offset); setScrollBars(); } // Annotate a line. void QsciScintilla::annotate(int line, const QString &text, const QsciStyle &style) { style.apply(this); annotate(line, text, style.style()); } // Annotate a line. void QsciScintilla::annotate(int line, const QsciStyledText &text) { text.apply(this); annotate(line, text.text(), text.style()); } // Annotate a line. void QsciScintilla::annotate(int line, const QList<QsciStyledText> &text) { char *styles; ScintillaBytes styled_text = styleText(text, &styles, SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET)); SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaBytesConstData(styled_text)); SendScintilla(SCI_ANNOTATIONSETSTYLES, line, styles); delete[] styles; } // Get the annotation for a line, if any. QString QsciScintilla::annotation(int line) const { char *buf = new char[SendScintilla(SCI_ANNOTATIONGETTEXT, line, (const char *)0) + 1]; buf[SendScintilla(SCI_ANNOTATIONGETTEXT, line, buf)] = '\0'; QString qs = bytesAsText(buf); delete[] buf; return qs; } // Convert a list of styled text to the low-level arrays. QsciScintillaBase::ScintillaBytes QsciScintilla::styleText(const QList<QsciStyledText> &styled_text, char **styles, int style_offset) { QString text; int i; // Build the full text. for (i = 0; i < styled_text.count(); ++i) { const QsciStyledText &st = styled_text[i]; st.apply(this); text.append(st.text()); } ScintillaBytes s = textAsBytes(text); // There is a style byte for every byte. char *sp = *styles = new char[s.length()]; for (i = 0; i < styled_text.count(); ++i) { const QsciStyledText &st = styled_text[i]; ScintillaBytes part = textAsBytes(st.text()); int part_length = part.length(); for (int c = 0; c < part_length; ++c) *sp++ = (char)(st.style() - style_offset); } return s; } // Convert Scintilla modifiers to the Qt equivalent. int QsciScintilla::mapModifiers(int modifiers) { int state = 0; if (modifiers & SCMOD_SHIFT) state |= Qt::ShiftModifier; if (modifiers & SCMOD_CTRL) state |= Qt::ControlModifier; if (modifiers & SCMOD_ALT) state |= Qt::AltModifier; if (modifiers & (SCMOD_SUPER | SCMOD_META)) state |= Qt::MetaModifier; return state; } // Re-implemented to handle shortcut overrides. bool QsciScintilla::event(QEvent *e) { if (e->type() == QEvent::ShortcutOverride && !isReadOnly()) { QKeyEvent *ke = static_cast<QKeyEvent *>(e); if (ke->key()) { // We want ordinary characters. if ((ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier || ke->modifiers() == Qt::KeypadModifier) && ke->key() < Qt::Key_Escape) { ke->accept(); return true; } // We want any key that is bound. QsciCommand *cmd = stdCmds->boundTo(ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)); if (cmd) { ke->accept(); return true; } } } return QsciScintillaBase::event(e); } // Re-implemented to zoom when the Control modifier is pressed. void QsciScintilla::wheelEvent(QWheelEvent *e) { #if defined(Q_OS_MAC) const Qt::KeyboardModifier zoom_modifier = Qt::MetaModifier; #else const Qt::KeyboardModifier zoom_modifier = Qt::ControlModifier; #endif if ((e->modifiers() & zoom_modifier) != 0) { if (e->delta() > 0) zoomIn(); else zoomOut(); } else { QsciScintillaBase::wheelEvent(e); } } // Re-implemented to handle chenges to the enabled state. void QsciScintilla::changeEvent(QEvent *e) { QsciScintillaBase::changeEvent(e); if (e->type() != QEvent::EnabledChange) return; if (isEnabled()) SendScintilla(SCI_SETCARETSTYLE, CARETSTYLE_LINE); else SendScintilla(SCI_SETCARETSTYLE, CARETSTYLE_INVISIBLE); QColor fore = palette().color(QPalette::Disabled, QPalette::Text); QColor back = palette().color(QPalette::Disabled, QPalette::Base); if (lex.isNull()) { if (isEnabled()) { fore = nl_text_colour; back = nl_paper_colour; } SendScintilla(SCI_STYLESETFORE, 0, fore); // 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, back); SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, back); } else { setEnabledColors(STYLE_DEFAULT, fore, back); for (int s = 0; s <= STYLE_MAX; ++s) if (!lex->description(s).isNull()) setEnabledColors(s, fore, back); } } // Set the foreground and background colours for a style. void QsciScintilla::setEnabledColors(int style, QColor &fore, QColor &back) { if (isEnabled()) { fore = lex->color(style); back = lex->paper(style); } handleStyleColorChange(fore, style); handleStylePaperChange(back, style); } // Re-implemented to implement a more Qt-like context menu. void QsciScintilla::contextMenuEvent(QContextMenuEvent *e) { if (contextMenuNeeded(e->x(), e->y())) { QMenu *menu = createStandardContextMenu(); if (menu) { menu->setAttribute(Qt::WA_DeleteOnClose); menu->popup(e->globalPos()); } } } // Create an instance of the standard context menu. QMenu *QsciScintilla::createStandardContextMenu() { bool read_only = isReadOnly(); bool has_selection = hasSelectedText(); QMenu *menu = new QMenu(this); QAction *action; if (!read_only) { action = menu->addAction(tr("&Undo"), this, SLOT(undo())); set_shortcut(action, QsciCommand::Undo); action->setEnabled(isUndoAvailable()); action = menu->addAction(tr("&Redo"), this, SLOT(redo())); set_shortcut(action, QsciCommand::Redo); action->setEnabled(isRedoAvailable()); menu->addSeparator(); action = menu->addAction(tr("Cu&t"), this, SLOT(cut())); set_shortcut(action, QsciCommand::SelectionCut); action->setEnabled(has_selection); } action = menu->addAction(tr("&Copy"), this, SLOT(copy())); set_shortcut(action, QsciCommand::SelectionCopy); action->setEnabled(has_selection); if (!read_only) { action = menu->addAction(tr("&Paste"), this, SLOT(paste())); set_shortcut(action, QsciCommand::Paste); action->setEnabled(SendScintilla(SCI_CANPASTE)); action = menu->addAction(tr("Delete"), this, SLOT(delete_selection())); action->setEnabled(has_selection); } if (!menu->isEmpty()) menu->addSeparator(); action = menu->addAction(tr("Select All"), this, SLOT(selectAll())); set_shortcut(action, QsciCommand::SelectAll); action->setEnabled(length() != 0); return menu; } // Set the shortcut for an action using any current key binding. void QsciScintilla::set_shortcut(QAction *action, QsciCommand::Command cmd_id) const { QsciCommand *cmd = stdCmds->find(cmd_id); if (cmd && cmd->key()) action->setShortcut(QKeySequence(cmd->key())); } // Delete the current selection. void QsciScintilla::delete_selection() { SendScintilla(SCI_CLEAR); } // Convert a Scintilla colour to a QColor. static QColor asQColor(long sci_colour) { return QColor( ((int)sci_colour) & 0x00ff, ((int)(sci_colour >> 8)) & 0x00ff, ((int)(sci_colour >> 16)) & 0x00ff); } // Set the scroll width. void QsciScintilla::setScrollWidth(int pixelWidth) { SendScintilla(SCI_SETSCROLLWIDTH, pixelWidth); } // Get the scroll width. int QsciScintilla::scrollWidth() const { return SendScintilla(SCI_GETSCROLLWIDTH); } // Set scroll width tracking. void QsciScintilla::setScrollWidthTracking(bool enabled) { SendScintilla(SCI_SETSCROLLWIDTHTRACKING, enabled); } // Get scroll width tracking. bool QsciScintilla::scrollWidthTracking() const { return SendScintilla(SCI_GETSCROLLWIDTHTRACKING); }