From 4d1675426779de628bc47bee3591df76a8028435 Mon Sep 17 00:00:00 2001 From: Colomban Wendling Date: Thu, 25 Oct 2012 16:08:32 +0200 Subject: [PATCH] Update Scintilla to version 3.2.3 Closes #2909124, #3094431 and #3233160. --- scintilla/gtk/ScintillaGTK.cxx | 4 + scintilla/include/SciLexer.h | 7 ++ scintilla/include/Scintilla.iface | 7 ++ scintilla/include/ScintillaWidget.h | 4 +- scintilla/lexers/LexBash.cxx | 156 +++++++++++++++++++++++++--- scintilla/lexers/LexCPP.cxx | 15 ++- scintilla/lexers/LexOthers.cxx | 73 ------------- scintilla/lexers/LexPO.cxx | 149 ++++++++++++++++++++++++++ scintilla/lexers/LexRuby.cxx | 14 ++- scintilla/lexers/LexSQL.cxx | 33 +++--- scintilla/src/Catalogue.cxx | 2 +- scintilla/src/Document.cxx | 24 ++++- scintilla/src/Document.h | 6 +- scintilla/src/Editor.cxx | 45 ++++---- scintilla/src/Editor.h | 1 + scintilla/src/RESearch.cxx | 2 +- scintilla/src/RunStyles.cxx | 1 + scintilla/version.txt | 2 +- 18 files changed, 402 insertions(+), 143 deletions(-) create mode 100644 scintilla/lexers/LexPO.cxx diff --git a/scintilla/gtk/ScintillaGTK.cxx b/scintilla/gtk/ScintillaGTK.cxx index be007e7759..8a09b105b6 100644 --- a/scintilla/gtk/ScintillaGTK.cxx +++ b/scintilla/gtk/ScintillaGTK.cxx @@ -1213,6 +1213,10 @@ bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) { modified = true; } #endif + if (modified && (paintState == painting)) { + paintState = paintAbandoned; + } + return modified; } diff --git a/scintilla/include/SciLexer.h b/scintilla/include/SciLexer.h index 57b5cf6e7b..85ba2a1cc5 100644 --- a/scintilla/include/SciLexer.h +++ b/scintilla/include/SciLexer.h @@ -1354,6 +1354,13 @@ #define SCE_PO_MSGCTXT 6 #define SCE_PO_MSGCTXT_TEXT 7 #define SCE_PO_FUZZY 8 +#define SCE_PO_PROGRAMMER_COMMENT 9 +#define SCE_PO_REFERENCE 10 +#define SCE_PO_FLAGS 11 +#define SCE_PO_MSGID_TEXT_EOL 12 +#define SCE_PO_MSGSTR_TEXT_EOL 13 +#define SCE_PO_MSGCTXT_TEXT_EOL 14 +#define SCE_PO_ERROR 15 #define SCE_PAS_DEFAULT 0 #define SCE_PAS_IDENTIFIER 1 #define SCE_PAS_COMMENT 2 diff --git a/scintilla/include/Scintilla.iface b/scintilla/include/Scintilla.iface index ff70c0a5aa..28e21ee151 100644 --- a/scintilla/include/Scintilla.iface +++ b/scintilla/include/Scintilla.iface @@ -3924,6 +3924,13 @@ val SCE_PO_MSGSTR_TEXT=5 val SCE_PO_MSGCTXT=6 val SCE_PO_MSGCTXT_TEXT=7 val SCE_PO_FUZZY=8 +val SCE_PO_PROGRAMMER_COMMENT=9 +val SCE_PO_REFERENCE=10 +val SCE_PO_FLAGS=11 +val SCE_PO_MSGID_TEXT_EOL=12 +val SCE_PO_MSGSTR_TEXT_EOL=13 +val SCE_PO_MSGCTXT_TEXT_EOL=14 +val SCE_PO_ERROR=15 # Lexical states for SCLEX_PASCAL lex Pascal=SCLEX_PASCAL SCE_PAS_ val SCE_PAS_DEFAULT=0 diff --git a/scintilla/include/ScintillaWidget.h b/scintilla/include/ScintillaWidget.h index 021af2a30e..f8cd212b02 100644 --- a/scintilla/include/ScintillaWidget.h +++ b/scintilla/include/ScintillaWidget.h @@ -16,8 +16,8 @@ extern "C" { #endif #define SCINTILLA(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, scintilla_get_type (), ScintillaObject) -#define SCINTILLA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, scintilla_get_type (), ScintillaClass) -#define IS_SCINTILLA(obj) GTK_CHECK_TYPE (obj, scintilla_get_type ()) +#define SCINTILLA_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, scintilla_get_type (), ScintillaClass) +#define IS_SCINTILLA(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, scintilla_get_type ()) typedef struct _ScintillaObject ScintillaObject; typedef struct _ScintillaClass ScintillaClass; diff --git a/scintilla/lexers/LexBash.cxx b/scintilla/lexers/LexBash.cxx index 8cd6cc570e..2dc8707e5c 100644 --- a/scintilla/lexers/LexBash.cxx +++ b/scintilla/lexers/LexBash.cxx @@ -2,7 +2,7 @@ /** @file LexBash.cxx ** Lexer for Bash. **/ -// Copyright 2004-2010 by Neil Hodgson +// Copyright 2004-2012 by Neil Hodgson // Adapted from LexPerl by Kein-Hong Man 2004 // The License.txt file describes the conditions under which this software may be distributed. @@ -49,6 +49,17 @@ using namespace Scintilla; #define BASH_CMD_ARITH 4 #define BASH_CMD_DELIM 5 +// state constants for nested delimiter pairs, used by +// SCE_SH_STRING and SCE_SH_BACKTICKS processing +#define BASH_DELIM_LITERAL 0 +#define BASH_DELIM_STRING 1 +#define BASH_DELIM_CSTRING 2 +#define BASH_DELIM_LSTRING 3 +#define BASH_DELIM_COMMAND 4 +#define BASH_DELIM_BACKTICK 5 + +#define BASH_DELIM_STACK_MAX 7 + static inline int translateBashDigit(int ch) { if (ch >= '0' && ch <= '9') { return ch - '0'; @@ -154,6 +165,60 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, }; QuoteCls Quote; + class QuoteStackCls { // Class to manage quote pairs that nest + public: + int Count; + int Up, Down; + int Style; + int Depth; // levels pushed + int *CountStack; + int *UpStack; + int *StyleStack; + QuoteStackCls() { + Count = 0; + Up = '\0'; + Down = '\0'; + Style = 0; + Depth = 0; + CountStack = new int[BASH_DELIM_STACK_MAX]; + UpStack = new int[BASH_DELIM_STACK_MAX]; + StyleStack = new int[BASH_DELIM_STACK_MAX]; + } + void Start(int u, int s) { + Count = 1; + Up = u; + Down = opposite(Up); + Style = s; + } + void Push(int u, int s) { + if (Depth >= BASH_DELIM_STACK_MAX) + return; + CountStack[Depth] = Count; + UpStack [Depth] = Up; + StyleStack[Depth] = Style; + Depth++; + Count = 1; + Up = u; + Down = opposite(Up); + Style = s; + } + void Pop(void) { + if (Depth <= 0) + return; + Depth--; + Count = CountStack[Depth]; + Up = UpStack [Depth]; + Style = StyleStack[Depth]; + Down = opposite(Up); + } + ~QuoteStackCls() { + delete []CountStack; + delete []UpStack; + delete []StyleStack; + } + }; + QuoteStackCls QuoteStack; + int numBase = 0; int digit; unsigned int endPos = startPos + length; @@ -163,6 +228,8 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, // Always backtracks to the start of a line that is not a continuation // of the previous line (i.e. start of a bash command segment) int ln = styler.GetLine(startPos); + if (ln > 0 && startPos == static_cast(styler.LineStart(ln))) + ln--; for (;;) { startPos = styler.LineStart(ln); if (ln == 0 || styler.GetLineState(ln) == BASH_CMD_START) @@ -376,7 +443,7 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.ForwardSetState(SCE_SH_DEFAULT); } else if (sc.ch == '\\') { // skip escape prefix - } else { + } else if (!HereDoc.Quoted) { sc.SetState(SCE_SH_DEFAULT); } if (HereDoc.DelimiterLength >= HERE_DELIM_MAX - 1) { // force blowup @@ -401,8 +468,11 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, } char s[HERE_DELIM_MAX]; sc.GetCurrent(s, sizeof(s)); - if (sc.LengthCurrent() == 0) + if (sc.LengthCurrent() == 0) { // '' or "" delimiters + if (prefixws == 0 && HereDoc.Quoted && HereDoc.DelimiterLength == 0) + sc.SetState(SCE_SH_DEFAULT); break; + } if (s[strlen(s) - 1] == '\r') s[strlen(s) - 1] = '\0'; if (strcmp(HereDoc.Delimiter, s) == 0) { @@ -424,9 +494,56 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, } } break; - case SCE_SH_STRING: // delimited styles + case SCE_SH_STRING: // delimited styles, can nest case SCE_SH_BACKTICKS: - case SCE_SH_PARAM: + if (sc.ch == '\\' && QuoteStack.Up != '\\') { + if (QuoteStack.Style != BASH_DELIM_LITERAL) + sc.Forward(); + } else if (sc.ch == QuoteStack.Down) { + QuoteStack.Count--; + if (QuoteStack.Count == 0) { + if (QuoteStack.Depth > 0) { + QuoteStack.Pop(); + } else + sc.ForwardSetState(SCE_SH_DEFAULT); + } + } else if (sc.ch == QuoteStack.Up) { + QuoteStack.Count++; + } else { + if (QuoteStack.Style == BASH_DELIM_STRING || + QuoteStack.Style == BASH_DELIM_LSTRING + ) { // do nesting for "string", $"locale-string" + if (sc.ch == '`') { + QuoteStack.Push(sc.ch, BASH_DELIM_BACKTICK); + } else if (sc.ch == '$' && sc.chNext == '(') { + sc.Forward(); + QuoteStack.Push(sc.ch, BASH_DELIM_COMMAND); + } + } else if (QuoteStack.Style == BASH_DELIM_COMMAND || + QuoteStack.Style == BASH_DELIM_BACKTICK + ) { // do nesting for $(command), `command` + if (sc.ch == '\'') { + QuoteStack.Push(sc.ch, BASH_DELIM_LITERAL); + } else if (sc.ch == '\"') { + QuoteStack.Push(sc.ch, BASH_DELIM_STRING); + } else if (sc.ch == '`') { + QuoteStack.Push(sc.ch, BASH_DELIM_BACKTICK); + } else if (sc.ch == '$') { + if (sc.chNext == '\'') { + sc.Forward(); + QuoteStack.Push(sc.ch, BASH_DELIM_CSTRING); + } else if (sc.chNext == '\"') { + sc.Forward(); + QuoteStack.Push(sc.ch, BASH_DELIM_LSTRING); + } else if (sc.chNext == '(') { + sc.Forward(); + QuoteStack.Push(sc.ch, BASH_DELIM_COMMAND); + } + } + } + } + break; + case SCE_SH_PARAM: // ${parameter} if (sc.ch == '\\' && Quote.Up != '\\') { sc.Forward(); } else if (sc.ch == Quote.Down) { @@ -461,8 +578,14 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.ChangeState(SCE_SH_ERROR); } // HereDoc.Quote always == '\'' + sc.SetState(SCE_SH_HERE_Q); + } else if (HereDoc.DelimiterLength == 0) { + // no delimiter, illegal (but '' and "" are legal) + sc.ChangeState(SCE_SH_ERROR); + sc.SetState(SCE_SH_DEFAULT); + } else { + sc.SetState(SCE_SH_HERE_Q); } - sc.SetState(SCE_SH_HERE_Q); } // update cmdState about the current command segment @@ -497,13 +620,13 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_SH_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_SH_STRING); - Quote.Start(sc.ch); + QuoteStack.Start(sc.ch, BASH_DELIM_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_SH_CHARACTER); Quote.Start(sc.ch); } else if (sc.ch == '`') { sc.SetState(SCE_SH_BACKTICKS); - Quote.Start(sc.ch); + QuoteStack.Start(sc.ch, BASH_DELIM_BACKTICK); } else if (sc.ch == '$') { if (sc.Match("$((")) { sc.SetState(SCE_SH_OPERATOR); // handle '((' later @@ -513,17 +636,22 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.Forward(); if (sc.ch == '{') { sc.ChangeState(SCE_SH_PARAM); + Quote.Start(sc.ch); } else if (sc.ch == '\'') { sc.ChangeState(SCE_SH_STRING); + QuoteStack.Start(sc.ch, BASH_DELIM_CSTRING); } else if (sc.ch == '"') { sc.ChangeState(SCE_SH_STRING); - } else if (sc.ch == '(' || sc.ch == '`') { + QuoteStack.Start(sc.ch, BASH_DELIM_LSTRING); + } else if (sc.ch == '(') { + sc.ChangeState(SCE_SH_BACKTICKS); + QuoteStack.Start(sc.ch, BASH_DELIM_COMMAND); + } else if (sc.ch == '`') { // $` seen in a configure script, valid? sc.ChangeState(SCE_SH_BACKTICKS); + QuoteStack.Start(sc.ch, BASH_DELIM_BACKTICK); } else { continue; // scalar has no delimiter pair } - // fallthrough, open delim for $[{'"(`] - Quote.Start(sc.ch); } else if (sc.Match('<', '<')) { sc.SetState(SCE_SH_HERE_DELIM); HereDoc.State = 0; @@ -597,6 +725,10 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, }// sc.state } sc.Complete(); + if (sc.state == SCE_SH_HERE_Q) { + styler.ChangeLexerState(sc.currentPos, styler.Length()); + } + sc.Complete(); } static bool IsCommentLine(int line, Accessor &styler) { @@ -651,7 +783,7 @@ static void FoldBashDoc(unsigned int startPos, int length, int, WordList *[], if (ch == '<' && chNext == '<') { levelCurrent++; } - } else if (style == SCE_SH_HERE_Q && styler.StyleAt(i+1) == SCE_PL_DEFAULT) { + } else if (style == SCE_SH_HERE_Q && styler.StyleAt(i+1) == SCE_SH_DEFAULT) { levelCurrent--; } if (atEOL) { diff --git a/scintilla/lexers/LexCPP.cxx b/scintilla/lexers/LexCPP.cxx index d6efa7ee01..952037e9b1 100644 --- a/scintilla/lexers/LexCPP.cxx +++ b/scintilla/lexers/LexCPP.cxx @@ -467,6 +467,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle, int styleBeforeDCKeyword = SCE_C_DEFAULT; bool continuationLine = false; bool isIncludePreprocessor = false; + bool isStringInPreprocessor = false; int lineCurrent = styler.GetLine(startPos); if ((MaskActive(initStyle) == SCE_C_PREPROCESSOR) || @@ -578,7 +579,9 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle, break; case SCE_C_NUMBER: // We accept almost anything because of hex. and number suffixes - if (!(setWord.Contains(sc.ch) || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) { + if (!(setWord.Contains(sc.ch) + || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E' || + sc.chPrev == 'p' || sc.chPrev == 'P')))) { sc.SetState(SCE_C_DEFAULT|activitySet); } break; @@ -618,13 +621,17 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_C_DEFAULT|activitySet); } break; - case SCE_C_PREPROCESSOR: + case SCE_C_PREPROCESSOR: if (options.stylingWithinPreprocessor) { if (IsASpace(sc.ch)) { sc.SetState(SCE_C_DEFAULT|activitySet); } - } else { - if (sc.Match('/', '*')) { + } else if (isStringInPreprocessor && (sc.Match('>') || sc.Match('\"'))) { + isStringInPreprocessor = false; + } else if (!isStringInPreprocessor) { + if ((isIncludePreprocessor && sc.Match('<')) || sc.Match('\"')) { + isStringInPreprocessor = true; + } else if (sc.Match('/', '*')) { sc.SetState(SCE_C_PREPROCESSORCOMMENT|activitySet); sc.Forward(); // Eat the * } else if (sc.Match('/', '/')) { diff --git a/scintilla/lexers/LexOthers.cxx b/scintilla/lexers/LexOthers.cxx index 77c156a3ce..d27c835454 100644 --- a/scintilla/lexers/LexOthers.cxx +++ b/scintilla/lexers/LexOthers.cxx @@ -614,78 +614,6 @@ static void FoldDiffDoc(unsigned int startPos, int length, int, WordList *[], Ac } while (static_cast(startPos) + length > curLineStart); } -static void ColourisePoLine( - char *lineBuffer, - unsigned int lengthLine, - unsigned int startLine, - unsigned int endPos, - Accessor &styler) { - - unsigned int i = 0; - static unsigned int state = SCE_PO_DEFAULT; - unsigned int state_start = SCE_PO_DEFAULT; - - while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces - i++; - if (i < lengthLine) { - if (lineBuffer[i] == '#') { - // check if the comment contains any flags ("#, ") and - // then whether the flags contain "fuzzy" - if (strstart(lineBuffer, "#, ") && strstr(lineBuffer, "fuzzy")) - styler.ColourTo(endPos, SCE_PO_FUZZY); - else - styler.ColourTo(endPos, SCE_PO_COMMENT); - } else { - if (lineBuffer[0] == '"') { - // line continuation, use previous style - styler.ColourTo(endPos, state); - return; - // this implicitly also matches "msgid_plural" - } else if (strstart(lineBuffer, "msgid")) { - state_start = SCE_PO_MSGID; - state = SCE_PO_MSGID_TEXT; - } else if (strstart(lineBuffer, "msgstr")) { - state_start = SCE_PO_MSGSTR; - state = SCE_PO_MSGSTR_TEXT; - } else if (strstart(lineBuffer, "msgctxt")) { - state_start = SCE_PO_MSGCTXT; - state = SCE_PO_MSGCTXT_TEXT; - } - if (state_start != SCE_PO_DEFAULT) { - // find the next space - while ((i < lengthLine) && ! isspacechar(lineBuffer[i])) - i++; - styler.ColourTo(startLine + i - 1, state_start); - styler.ColourTo(startLine + i, SCE_PO_DEFAULT); - styler.ColourTo(endPos, state); - } - } - } else { - styler.ColourTo(endPos, SCE_PO_DEFAULT); - } -} - -static void ColourisePoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { - char lineBuffer[1024]; - styler.StartAt(startPos); - styler.StartSegment(startPos); - unsigned int linePos = 0; - unsigned int startLine = startPos; - for (unsigned int i = startPos; i < startPos + length; i++) { - lineBuffer[linePos++] = styler[i]; - if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { - // End of line (or of line buffer) met, colourise it - lineBuffer[linePos] = '\0'; - ColourisePoLine(lineBuffer, linePos, startLine, i, styler); - linePos = 0; - startLine = i + 1; - } - } - if (linePos > 0) { // Last line does not have ending characters - ColourisePoLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); - } -} - static inline bool isassignchar(unsigned char ch) { return (ch == '=') || (ch == ':'); } @@ -1498,7 +1426,6 @@ static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[ LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc); LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc); -LexerModule lmPo(SCLEX_PO, ColourisePoDoc, "po", 0, emptyWordListDesc); LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc); LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc); LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc); diff --git a/scintilla/lexers/LexPO.cxx b/scintilla/lexers/LexPO.cxx new file mode 100644 index 0000000000..ced58efe2d --- /dev/null +++ b/scintilla/lexers/LexPO.cxx @@ -0,0 +1,149 @@ +// Scintilla source code edit control +/** @file LexPO.cxx + ** Lexer for GetText Translation (PO) files. + **/ +// Copyright 2012 by Colomban Wendling +// The License.txt file describes the conditions under which this software may be distributed. + +// see https://www.gnu.org/software/gettext/manual/gettext.html#PO-Files for the syntax reference +// some details are taken from the GNU msgfmt behavior (like that indent is allows in front of lines) + +// TODO: +// * add keywords for flags (fuzzy, c-format, ...) +// * highlight formats inside c-format strings (%s, %d, etc.) +// * style for previous untranslated string? ("#|" comment) + +#include +#include +#include +#include +#include +#include + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static void ColourisePODoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { + StyleContext sc(startPos, length, initStyle, styler); + bool escaped = false; + int curLine = styler.GetLine(startPos); + // the line state holds the last state on or before the line that isn't the default style + int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : SCE_PO_DEFAULT; + + for (; sc.More(); sc.Forward()) { + // whether we should leave a state + switch (sc.state) { + case SCE_PO_COMMENT: + case SCE_PO_PROGRAMMER_COMMENT: + case SCE_PO_REFERENCE: + case SCE_PO_FLAGS: + case SCE_PO_FUZZY: + if (sc.atLineEnd) + sc.SetState(SCE_PO_DEFAULT); + else if (sc.state == SCE_PO_FLAGS && sc.Match("fuzzy")) + // here we behave like the previous parser, but this should probably be highlighted + // on its own like a keyword rather than changing the whole flags style + sc.ChangeState(SCE_PO_FUZZY); + break; + + case SCE_PO_MSGCTXT: + case SCE_PO_MSGID: + case SCE_PO_MSGSTR: + if (isspacechar(sc.ch)) + sc.SetState(SCE_PO_DEFAULT); + break; + + case SCE_PO_ERROR: + if (sc.atLineEnd) + sc.SetState(SCE_PO_DEFAULT); + break; + + case SCE_PO_MSGCTXT_TEXT: + case SCE_PO_MSGID_TEXT: + case SCE_PO_MSGSTR_TEXT: + if (sc.atLineEnd) { // invalid inside a string + if (sc.state == SCE_PO_MSGCTXT_TEXT) + sc.ChangeState(SCE_PO_MSGCTXT_TEXT_EOL); + else if (sc.state == SCE_PO_MSGID_TEXT) + sc.ChangeState(SCE_PO_MSGID_TEXT_EOL); + else if (sc.state == SCE_PO_MSGSTR_TEXT) + sc.ChangeState(SCE_PO_MSGSTR_TEXT_EOL); + sc.SetState(SCE_PO_DEFAULT); + escaped = false; + } else { + if (escaped) + escaped = false; + else if (sc.ch == '\\') + escaped = true; + else if (sc.ch == '"') + sc.ForwardSetState(SCE_PO_DEFAULT); + } + break; + } + + // whether we should enter a new state + if (sc.state == SCE_PO_DEFAULT) { + // forward to the first non-white character on the line + bool atLineStart = sc.atLineStart; + if (atLineStart) { + while (sc.More() && ! sc.atLineEnd && isspacechar(sc.ch)) + sc.Forward(); + } + + if (atLineStart && sc.ch == '#') { + if (sc.chNext == '.') + sc.SetState(SCE_PO_PROGRAMMER_COMMENT); + else if (sc.chNext == ':') + sc.SetState(SCE_PO_REFERENCE); + else if (sc.chNext == ',') + sc.SetState(SCE_PO_FLAGS); + else + sc.SetState(SCE_PO_COMMENT); + } else if (atLineStart && sc.Match("msgid")) { // includes msgid_plural + sc.SetState(SCE_PO_MSGID); + } else if (atLineStart && sc.Match("msgstr")) { // includes [] suffixes + sc.SetState(SCE_PO_MSGSTR); + } else if (atLineStart && sc.Match("msgctxt")) { + sc.SetState(SCE_PO_MSGCTXT); + } else if (sc.ch == '"') { + if (curLineState == SCE_PO_MSGCTXT || curLineState == SCE_PO_MSGCTXT_TEXT) + sc.SetState(SCE_PO_MSGCTXT_TEXT); + else if (curLineState == SCE_PO_MSGID || curLineState == SCE_PO_MSGID_TEXT) + sc.SetState(SCE_PO_MSGID_TEXT); + else if (curLineState == SCE_PO_MSGSTR || curLineState == SCE_PO_MSGSTR_TEXT) + sc.SetState(SCE_PO_MSGSTR_TEXT); + else + sc.SetState(SCE_PO_ERROR); + } else if (! isspacechar(sc.ch)) + sc.SetState(SCE_PO_ERROR); + + if (sc.state != SCE_PO_DEFAULT) + curLineState = sc.state; + } + + if (sc.atLineEnd) { + // Update the line state, so it can be seen by next line + curLine = styler.GetLine(sc.currentPos); + styler.SetLineState(curLine, curLineState); + } + } + sc.Complete(); +} + +static const char *const poWordListDesc[] = { + 0 +}; + +LexerModule lmPO(SCLEX_PO, ColourisePODoc, "po", 0, poWordListDesc); diff --git a/scintilla/lexers/LexRuby.cxx b/scintilla/lexers/LexRuby.cxx index 23115e6e09..40424aabd3 100644 --- a/scintilla/lexers/LexRuby.cxx +++ b/scintilla/lexers/LexRuby.cxx @@ -465,7 +465,9 @@ static bool sureThisIsNotHeredoc(int lt2StartPos, } prevStyle = styler.StyleAt(firstWordPosn); // If we have '<<' following a keyword, it's not a heredoc - if (prevStyle != SCE_RB_IDENTIFIER) { + if (prevStyle != SCE_RB_IDENTIFIER + && prevStyle != SCE_RB_INSTANCE_VAR + && prevStyle != SCE_RB_CLASS_VAR) { return definitely_not_a_here_doc; } int newStyle = prevStyle; @@ -495,6 +497,9 @@ static bool sureThisIsNotHeredoc(int lt2StartPos, } else { break; } + // on second and next passes, only identifiers may appear since + // class and instance variable are private + prevStyle = SCE_RB_IDENTIFIER; } // Skip next batch of white-space firstWordPosn = skipWhitespace(firstWordPosn, lt2StartPos, styler); @@ -1436,7 +1441,8 @@ static bool keywordIsAmbiguous(const char *prevWord) || !strcmp(prevWord, "do") || !strcmp(prevWord, "while") || !strcmp(prevWord, "unless") - || !strcmp(prevWord, "until")) { + || !strcmp(prevWord, "until") + || !strcmp(prevWord, "for")) { return true; } else { return false; @@ -1554,6 +1560,7 @@ static bool keywordIsModifier(const char *word, #define WHILE_BACKWARDS "elihw" #define UNTIL_BACKWARDS "litnu" +#define FOR_BACKWARDS "rof" // Nothing fancy -- look to see if we follow a while/until somewhere // on the current line @@ -1591,7 +1598,8 @@ static bool keywordDoStartsLoop(int pos, *dst = 0; // Did we see our keyword? if (!strcmp(prevWord, WHILE_BACKWARDS) - || !strcmp(prevWord, UNTIL_BACKWARDS)) { + || !strcmp(prevWord, UNTIL_BACKWARDS) + || !strcmp(prevWord, FOR_BACKWARDS)) { return true; } // We can move pos to the beginning of the keyword, and then diff --git a/scintilla/lexers/LexSQL.cxx b/scintilla/lexers/LexSQL.cxx index d9013db9b9..dc4bf6697c 100644 --- a/scintilla/lexers/LexSQL.cxx +++ b/scintilla/lexers/LexSQL.cxx @@ -122,13 +122,11 @@ public : return sqlStatesLine; } - - unsigned short int IntoSelectStatement (unsigned short int sqlStatesLine, bool found) { + unsigned short int IntoSelectStatementOrAssignment (unsigned short int sqlStatesLine, bool found) { if (found) - sqlStatesLine |= MASK_INTO_SELECT_STATEMENT; + sqlStatesLine |= MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT; else - sqlStatesLine &= ~MASK_INTO_SELECT_STATEMENT; - + sqlStatesLine &= ~MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT; return sqlStatesLine; } @@ -161,11 +159,9 @@ public : bool IsIntoExceptionBlock (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_INTO_EXCEPTION) != 0; } - - bool IsIntoSelectStatement (unsigned short int sqlStatesLine) { - return (sqlStatesLine & MASK_INTO_SELECT_STATEMENT) != 0; + bool IsIntoSelectStatementOrAssignment (unsigned short int sqlStatesLine) { + return (sqlStatesLine & MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT) != 0; } - bool IsCaseMergeWithoutWhenFound (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_CASE_MERGE_WITHOUT_WHEN_FOUND) != 0; } @@ -188,7 +184,7 @@ private : SparseState sqlStatement; enum { MASK_NESTED_CASES = 0x01FF, - MASK_INTO_SELECT_STATEMENT = 0x0200, + MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT = 0x0200, MASK_CASE_MERGE_WITHOUT_WHEN_FOUND = 0x0400, MASK_MERGE_STATEMENT = 0x0800, MASK_INTO_DECLARE = 0x1000, @@ -608,9 +604,12 @@ void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, sqlStatesCurrentLine = sqlStates.IntoMergeStatement(sqlStatesCurrentLine, false); levelNext--; } - if (sqlStates.IsIntoSelectStatement(sqlStatesCurrentLine)) - sqlStatesCurrentLine = sqlStates.IntoSelectStatement(sqlStatesCurrentLine, false); + if (sqlStates.IsIntoSelectStatementOrAssignment(sqlStatesCurrentLine)) + sqlStatesCurrentLine = sqlStates.IntoSelectStatementOrAssignment(sqlStatesCurrentLine, false); } + if (ch == ':' && chNext == '=' && !IsCommentStyle(style)) + sqlStatesCurrentLine = sqlStates.IntoSelectStatementOrAssignment(sqlStatesCurrentLine, true); + if (options.foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; @@ -666,10 +665,9 @@ void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, } else { s[j] = '\0'; } - if (!options.foldOnlyBegin && strcmp(s, "select") == 0) { - sqlStatesCurrentLine = sqlStates.IntoSelectStatement(sqlStatesCurrentLine, true); + sqlStatesCurrentLine = sqlStates.IntoSelectStatementOrAssignment(sqlStatesCurrentLine, true); } else if (strcmp(s, "if") == 0) { if (endFound) { endFound = false; @@ -719,8 +717,10 @@ void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, levelNext--; //again for the "end case;" and block when } } else if (!options.foldOnlyBegin) { - if (strcmp(s, "case") == 0) + if (strcmp(s, "case") == 0) { sqlStatesCurrentLine = sqlStates.BeginCaseBlock(sqlStatesCurrentLine); + sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, true); + } if (levelCurrent > levelNext) levelCurrent = levelNext; @@ -728,7 +728,6 @@ void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, if (!statementFound) levelNext++; - sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, true); statementFound = true; } else if (levelCurrent > levelNext) { // doesn't include this line into the folding block @@ -765,7 +764,7 @@ void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, (strcmp(s, "endif") == 0)) { endFound = true; levelNext--; - if (sqlStates.IsIntoSelectStatement(sqlStatesCurrentLine) && !sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) + if (sqlStates.IsIntoSelectStatementOrAssignment(sqlStatesCurrentLine) && !sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; if (levelNext < SC_FOLDLEVELBASE) { levelNext = SC_FOLDLEVELBASE; diff --git a/scintilla/src/Catalogue.cxx b/scintilla/src/Catalogue.cxx index a34f8342d3..257ba28ae2 100644 --- a/scintilla/src/Catalogue.cxx +++ b/scintilla/src/Catalogue.cxx @@ -109,7 +109,7 @@ int Scintilla_LinkLexers() { LINK_LEXER(lmOctave); LINK_LEXER(lmPascal); LINK_LEXER(lmPerl); - LINK_LEXER(lmPo); + LINK_LEXER(lmPO); LINK_LEXER(lmProps); LINK_LEXER(lmPython); LINK_LEXER(lmR); diff --git a/scintilla/src/Document.cxx b/scintilla/src/Document.cxx index 4ce62c45b3..1938149e7e 100644 --- a/scintilla/src/Document.cxx +++ b/scintilla/src/Document.cxx @@ -69,6 +69,7 @@ void LexInterface::Colourise(int start, int end) { Document::Document() { refCount = 0; + pcf = NULL; #ifdef _WIN32 eolMode = SC_EOL_CRLF; #else @@ -123,6 +124,8 @@ Document::~Document() { regex = 0; delete pli; pli = 0; + delete pcf; + pcf = 0; } void Document::Init() { @@ -132,6 +135,16 @@ void Document::Init() { } } +bool Document::SetDBCSCodePage(int dbcsCodePage_) { + if (dbcsCodePage != dbcsCodePage_) { + dbcsCodePage = dbcsCodePage_; + SetCaseFolder(NULL); + return true; + } else { + return false; + } +} + void Document::InsertLine(int line) { for (int j=0; j maxPos to do a backward search) @@ -1426,7 +1448,7 @@ bool Document::MatchesWordOptions(bool word, bool wordStart, int pos, int length */ long Document::FindText(int minPos, int maxPos, const char *search, bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, - int *length, CaseFolder *pcf) { + int *length) { if (*length <= 0) return minPos; if (regExp) { diff --git a/scintilla/src/Document.h b/scintilla/src/Document.h index 30c6aee1cd..36d6709375 100644 --- a/scintilla/src/Document.h +++ b/scintilla/src/Document.h @@ -212,6 +212,7 @@ class Document : PerLine, public IDocument, public ILoader { int refCount; CellBuffer cb; CharClassify charClass; + CaseFolder *pcf; char stylingMask; int endStyled; int styleClock; @@ -255,6 +256,7 @@ class Document : PerLine, public IDocument, public ILoader { int SCI_METHOD Release(); virtual void Init(); + bool SetDBCSCodePage(int dbcsCodePage_); virtual void InsertLine(int line); virtual void RemoveLine(int line); @@ -355,8 +357,10 @@ class Document : PerLine, public IDocument, public ILoader { int SCI_METHOD Length() const { return cb.Length(); } void Allocate(int newSize) { cb.Allocate(newSize); } bool MatchesWordOptions(bool word, bool wordStart, int pos, int length); + bool HasCaseFolder(void) const; + void SetCaseFolder(CaseFolder *pcf_); long FindText(int minPos, int maxPos, const char *search, bool caseSensitive, bool word, - bool wordStart, bool regExp, int flags, int *length, CaseFolder *pcf); + bool wordStart, bool regExp, int flags, int *length); const char *SubstituteByPosition(const char *text, int *length); int LinesTotal() const; diff --git a/scintilla/src/Editor.cxx b/scintilla/src/Editor.cxx index 17b899d874..bb23e9e6d7 100644 --- a/scintilla/src/Editor.cxx +++ b/scintilla/src/Editor.cxx @@ -220,6 +220,7 @@ Editor::Editor() { marginNumberPadding = 3; ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side + lastSegItalicsOffset = 2; hsStart = -1; hsEnd = -1; @@ -2243,7 +2244,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou } // Small hack to make lines that end with italics not cut off the edge of the last character if ((startseg > 0) && lastSegItalics) { - ll->positions[startseg] += 2; + ll->positions[startseg] += lastSegItalicsOffset; } ll->numCharsInLine = numCharsInLine; ll->numCharsBeforeEOL = numCharsBeforeEOL; @@ -3438,6 +3439,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { AllocateGraphics(); RefreshStyleData(); + if (paintState == paintAbandoned) + return; // Scroll bars may have changed so need redraw RefreshPixMaps(surfaceWindow); StyleToPositionInView(PositionAfterArea(rcArea)); @@ -5732,15 +5735,15 @@ long Editor::FindText( Sci_TextToFind *ft = reinterpret_cast(lParam); int lengthFound = istrlen(ft->lpstrText); - std::auto_ptr pcf(CaseFolderForEncoding()); + if (!pdoc->HasCaseFolder()) + pdoc->SetCaseFolder(CaseFolderForEncoding()); int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, (wParam & SCFIND_MATCHCASE) != 0, (wParam & SCFIND_WHOLEWORD) != 0, (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, - &lengthFound, - pcf.get()); + &lengthFound); if (pos != -1) { ft->chrgText.cpMin = pos; ft->chrgText.cpMax = pos + lengthFound; @@ -5763,19 +5766,6 @@ void Editor::SearchAnchor() { searchAnchor = SelectionStart().Position(); } -// Simple RAII wrapper for CaseFolder as std::auto_ptr is now deprecated -class ScopedCaseFolder { - CaseFolder *pcf; -public: - ScopedCaseFolder(CaseFolder *pcf_) : pcf(pcf_) { - } - ~ScopedCaseFolder() { - delete pcf; - pcf = 0; - } - CaseFolder *get() const { return pcf; } -}; - /** * Find text from current search anchor: Must call @c SearchAnchor first. * Used for next text and previous text requests. @@ -5790,7 +5780,8 @@ long Editor::SearchText( const char *txt = reinterpret_cast(lParam); int pos; int lengthFound = istrlen(txt); - ScopedCaseFolder pcf(CaseFolderForEncoding()); + if (!pdoc->HasCaseFolder()) + pdoc->SetCaseFolder(CaseFolderForEncoding()); if (iMessage == SCI_SEARCHNEXT) { pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, (wParam & SCFIND_MATCHCASE) != 0, @@ -5798,8 +5789,7 @@ long Editor::SearchText( (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, - &lengthFound, - pcf.get()); + &lengthFound); } else { pos = pdoc->FindText(searchAnchor, 0, txt, (wParam & SCFIND_MATCHCASE) != 0, @@ -5807,8 +5797,7 @@ long Editor::SearchText( (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, - &lengthFound, - pcf.get()); + &lengthFound); } if (pos != -1) { SetSelection(pos, pos + lengthFound); @@ -5841,15 +5830,15 @@ std::string Editor::CaseMapString(const std::string &s, int caseMapping) { long Editor::SearchInTarget(const char *text, int length) { int lengthFound = length; - ScopedCaseFolder pcf(CaseFolderForEncoding()); + if (!pdoc->HasCaseFolder()) + pdoc->SetCaseFolder(CaseFolderForEncoding()); int pos = pdoc->FindText(targetStart, targetEnd, text, (searchFlags & SCFIND_MATCHCASE) != 0, (searchFlags & SCFIND_WHOLEWORD) != 0, (searchFlags & SCFIND_WORDSTART) != 0, (searchFlags & SCFIND_REGEXP) != 0, searchFlags, - &lengthFound, - pcf.get()); + &lengthFound); if (pos != -1) { targetStart = pos; targetEnd = pos + lengthFound; @@ -7098,6 +7087,7 @@ void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam break; case SCI_STYLESETCHARACTERSET: vs.styles[wParam].characterSet = lParam; + pdoc->SetCaseFolder(NULL); break; case SCI_STYLESETVISIBLE: vs.styles[wParam].visible = lParam != 0; @@ -8076,8 +8066,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_SETCODEPAGE: if (ValidCodePage(wParam)) { - pdoc->dbcsCodePage = wParam; - InvalidateStyleRedraw(); + if (pdoc->SetDBCSCodePage(wParam)) { + InvalidateStyleRedraw(); + } } break; diff --git a/scintilla/src/Editor.h b/scintilla/src/Editor.h index cb1141b61c..e040bdb47e 100644 --- a/scintilla/src/Editor.h +++ b/scintilla/src/Editor.h @@ -271,6 +271,7 @@ class Editor : public DocWatcher { int marginNumberPadding; // the right-side padding of the number margin int ctrlCharPadding; // the padding around control character text blobs + int lastSegItalicsOffset; // the offset so as not to clip italic characters at EOLs Document *pdoc; diff --git a/scintilla/src/RESearch.cxx b/scintilla/src/RESearch.cxx index ffcc58d365..87f2a69857 100644 --- a/scintilla/src/RESearch.cxx +++ b/scintilla/src/RESearch.cxx @@ -788,7 +788,7 @@ int RESearch::Execute(CharacterIndexer &ci, int lp, int endp) { } case CHR: /* ordinary char: locate it fast */ c = *(ap+1); - while ((lp < endp) && (ci.CharAt(lp) != c)) + while ((lp < endp) && (static_cast(ci.CharAt(lp)) != c)) lp++; if (lp >= endp) /* if EOS, fail, else fall thru. */ return 0; diff --git a/scintilla/src/RunStyles.cxx b/scintilla/src/RunStyles.cxx index 643d2fb2d1..9c4e90a664 100644 --- a/scintilla/src/RunStyles.cxx +++ b/scintilla/src/RunStyles.cxx @@ -205,6 +205,7 @@ void RunStyles::DeleteRange(int position, int deleteLength) { if (runStart == runEnd) { // Deleting from inside one run starts->InsertText(runStart, -deleteLength); + RemoveRunIfEmpty(runStart); } else { runStart = SplitRun(position); runEnd = SplitRun(end); diff --git a/scintilla/version.txt b/scintilla/version.txt index 18fdcb2a95..3860ed9137 100644 --- a/scintilla/version.txt +++ b/scintilla/version.txt @@ -1 +1 @@ -322 +323