From 86e1cdab58e939a2c6e43767fb48dbc95e4a5c78 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Tue, 9 Jan 2018 19:08:55 +0100 Subject: [PATCH 1/6] + feature: initial version of Nim Lexer --- scintilla/include/Scintilla.iface | 12 +- scintilla/lexers/LexMatlab.cxx | 1 + scintilla/lexers/LexNim.cxx | 431 ++++++++++++++++++++++++++++++ scintilla/src/Catalogue.cxx | 1 + scintilla/src/Document.cxx | 24 +- scintilla/src/Editor.cxx | 2 + src/Notepad3.c | 4 +- src/Notepad3.rc | 1 + src/Styles.c | 39 ++- src/Styles.h | 2 +- 10 files changed, 507 insertions(+), 10 deletions(-) create mode 100644 scintilla/lexers/LexNim.cxx diff --git a/scintilla/include/Scintilla.iface b/scintilla/include/Scintilla.iface index 69139158a..889d3bc8a 100644 --- a/scintilla/include/Scintilla.iface +++ b/scintilla/include/Scintilla.iface @@ -1964,6 +1964,9 @@ set void SetSelectionMode=2422(int selectionMode,) # Get the mode of the current selection. get int GetSelectionMode=2423(,) +# Get whether or not regular caret moves will extend or reduce the selection. +get bool GetMoveExtendsSelection=2706(,) + # Retrieve the position of the start of the selection at the given line (INVALID_POSITION if no selection on this line). fun position GetLineSelStartPosition=2424(int line,) @@ -2696,15 +2699,15 @@ get int GetNamedStyles=4029(,) # Retrieve the name of a style. # Result is NUL-terminated. -fun int NameOfStyle=4030(int style, stringresult names) +fun int NameOfStyle=4030(int style, stringresult name) # Retrieve a ' ' separated list of style tags like "literal quoted string". # Result is NUL-terminated. -fun int TagsOfStyle=4031(int style, stringresult names) +fun int TagsOfStyle=4031(int style, stringresult tags) # Retrieve a description of a style. # Result is NUL-terminated. -fun int DescriptionOfStyle=4032(int style, stringresult names) +fun int DescriptionOfStyle=4032(int style, stringresult description) # Notifications # Type of modification and the action which caused the modification. @@ -2914,6 +2917,8 @@ val SCLEX_TEHEX=119 val SCLEX_JSON=120 val SCLEX_EDIFACT=121 val SCLEX_INDENT=122 +val SCLEX_AHK=200 +val SCLEX_NIM=201 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -2921,6 +2926,7 @@ val SCLEX_AUTOMATIC=1000 # Lexical states for SCLEX_PYTHON lex Python=SCLEX_PYTHON SCE_P_ lex Nimrod=SCLEX_NIMROD SCE_P_ +lex Nim=SCLEX_NIM SCE_P_ val SCE_P_DEFAULT=0 val SCE_P_COMMENTLINE=1 val SCE_P_NUMBER=2 diff --git a/scintilla/lexers/LexMatlab.cxx b/scintilla/lexers/LexMatlab.cxx index 6063623ea..a36a99502 100644 --- a/scintilla/lexers/LexMatlab.cxx +++ b/scintilla/lexers/LexMatlab.cxx @@ -64,6 +64,7 @@ static int CheckKeywordFoldPoint(char *str) { if (strcmp ("if", str) == 0 || strcmp ("for", str) == 0 || strcmp ("switch", str) == 0 || + strcmp ("while", str) == 0 || strcmp ("try", str) == 0 || strcmp ("do", str) == 0 || strcmp ("parfor", str) == 0 || diff --git a/scintilla/lexers/LexNim.cxx b/scintilla/lexers/LexNim.cxx new file mode 100644 index 000000000..311b0a26a --- /dev/null +++ b/scintilla/lexers/LexNim.cxx @@ -0,0 +1,431 @@ +// Scintilla source code edit control +// Nim lexer +// (c) 2009 Andreas Rumpf +/** @file LexNim.cxx + ** Lexer for Nim. + **/ +// Copyright 1998-2002 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#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" + +using namespace Scintilla; + +static inline bool IsAWordChar(int ch) { + return (ch >= 0x80) || isalnum(ch) || ch == '_'; +} + +static Sci_Position tillEndOfTripleQuote(Accessor &styler, Sci_Position pos, Sci_Position max) { + /* search for """ */ + for (;;) { + if (styler.SafeGetCharAt(pos, '\0') == '\0') return pos; + if (pos >= max) return pos; + if (styler.Match(pos, "\"\"\"")) { + return pos + 2; + } + pos++; + } +} + +#define CR 13 /* use both because Scite allows changing the line ending */ +#define LF 10 + +static bool inline isNewLine(int ch) { + return ch == CR || ch == LF; +} + +static Sci_Position scanString(Accessor &styler, Sci_Position pos, Sci_Position max, bool rawMode) { + for (;;) { + if (pos >= max) return pos; + char ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == CR || ch == LF || ch == '\0') return pos; + if (ch == '"') return pos; + if (ch == '\\' && !rawMode) { + pos += 2; + } else { + pos++; + } + } +} + +static Sci_Position scanChar(Accessor &styler, Sci_Position pos, Sci_Position max) { + for (;;) { + if (pos >= max) return pos; + char ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == CR || ch == LF || ch == '\0') return pos; + if (ch == '\'' && !isalnum(styler.SafeGetCharAt(pos+1, '\0')) ) + return pos; + if (ch == '\\') { + pos += 2; + } else { + pos++; + } + } +} + +static Sci_Position scanIdent(Accessor &styler, Sci_Position pos, WordList &keywords) { + char buf[100]; /* copy to lowercase and ignore underscores */ + Sci_Position i = 0; + + for (;;) { + char ch = styler.SafeGetCharAt(pos, '\0'); + if (!IsAWordChar(ch)) break; + if (ch != '_' && i < ((int)sizeof(buf))-1) { + buf[i] = static_cast(tolower(ch)); + i++; + } + pos++; + } + buf[i] = '\0'; + /* look for keyword */ + if (keywords.InList(buf)) { + styler.ColourTo(pos-1, SCE_P_WORD); + } else { + styler.ColourTo(pos-1, SCE_P_IDENTIFIER); + } + return pos; +} + +static Sci_Position scanNumber(Accessor &styler, Sci_Position pos) { + char ch, ch2; + ch = styler.SafeGetCharAt(pos, '\0'); + ch2 = styler.SafeGetCharAt(pos+1, '\0'); + if (ch == '0' && (ch2 == 'b' || ch2 == 'B')) { + /* binary number: */ + pos += 2; + for (;;) { + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '_' || (ch >= '0' && ch <= '1')) ++pos; + else break; + } + } else if (ch == '0' && + (ch2 == 'o' || ch2 == 'O' || ch2 == 'c' || ch2 == 'C')) { + /* octal number: */ + pos += 2; + for (;;) { + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '_' || (ch >= '0' && ch <= '7')) ++pos; + else break; + } + } else if (ch == '0' && (ch2 == 'x' || ch2 == 'X')) { + /* hexadecimal number: */ + pos += 2; + for (;;) { + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '_' || (ch >= '0' && ch <= '9') + || (ch >= 'a' && ch <= 'f') + || (ch >= 'A' && ch <= 'F')) ++pos; + else break; + } + } else { + // skip decimal part: + for (;;) { + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; + else break; + } + ch2 = styler.SafeGetCharAt(pos+1, '\0'); + if (ch == '.' && ch2 >= '0' && ch2 <= '9') { + ++pos; // skip '.' + for (;;) { + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; + else break; + } + } + if (ch == 'e' || ch == 'E') { + ++pos; + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '-' || ch == '+') ++pos; + for (;;) { + ch = styler.SafeGetCharAt(pos, '\0'); + if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; + else break; + } + } + } + if (ch == '\'') { + /* a type suffix: */ + pos++; + for (;;) { + ch = styler.SafeGetCharAt(pos); + if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') || ch == '_') ++pos; + else break; + } + } + styler.ColourTo(pos-1, SCE_P_NUMBER); + return pos; +} + +/* rewritten from scratch, because I couldn't get rid of the bugs... + (A character based approach sucks!) +*/ +static void ColouriseNimDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, + WordList *keywordlists[], Accessor &styler) { + Sci_Position pos = startPos; + Sci_Position max = startPos + length; + char ch; + WordList &keywords = *keywordlists[0]; + + styler.StartAt(startPos); + styler.StartSegment(startPos); + + switch (initStyle) { + /* check where we are: */ + case SCE_P_TRIPLEDOUBLE: + pos = tillEndOfTripleQuote(styler, pos, max); + styler.ColourTo(pos, SCE_P_TRIPLEDOUBLE); + pos++; + break; + default: /* nothing to do: */ + break; + } + while (pos < max) { + ch = styler.SafeGetCharAt(pos, '\0'); + switch (ch) { + case '\0': return; + case '#': { + bool doccomment = (styler.SafeGetCharAt(pos+1) == '#'); + while (pos < max && !isNewLine(styler.SafeGetCharAt(pos, LF))) pos++; + if (doccomment) + styler.ColourTo(pos, SCE_C_COMMENTLINEDOC); + else + styler.ColourTo(pos, SCE_P_COMMENTLINE); + } break; + case 'r': case 'R': { + if (styler.SafeGetCharAt(pos+1) == '"') { + pos = scanString(styler, pos+2, max, true); + styler.ColourTo(pos, SCE_P_STRING); + pos++; + } else { + pos = scanIdent(styler, pos, keywords); + } + } break; + case '"': + if (styler.Match(pos+1, "\"\"")) { + pos = tillEndOfTripleQuote(styler, pos+3, max); + styler.ColourTo(pos, SCE_P_TRIPLEDOUBLE); + } else { + pos = scanString(styler, pos+1, max, false); + styler.ColourTo(pos, SCE_P_STRING); + } + pos++; + break; + case '\'': + pos = scanChar(styler, pos+1, max); + styler.ColourTo(pos, SCE_P_CHARACTER); + pos++; + break; + default: // identifers, numbers, operators, whitespace + if (ch >= '0' && ch <= '9') { + pos = scanNumber(styler, pos); + } else if (IsAWordChar(ch)) { + pos = scanIdent(styler, pos, keywords); + } else if (ch == '`') { + pos++; + while (pos < max) { + ch = styler.SafeGetCharAt(pos, LF); + if (ch == '`') { + ++pos; + break; + } + if (ch == CR || ch == LF) break; + ++pos; + } + styler.ColourTo(pos, SCE_P_IDENTIFIER); + } else if (strchr("()[]{}:=;-\\/&%$!+<>|^?,.*~@", ch)) { + styler.ColourTo(pos, SCE_P_OPERATOR); + pos++; + } else { + styler.ColourTo(pos, SCE_P_DEFAULT); + pos++; + } + break; + } + } +} + +static bool IsCommentLine(Sci_Position line, Accessor &styler) { + Sci_Position pos = styler.LineStart(line); + Sci_Position eol_pos = styler.LineStart(line + 1) - 1; + for (Sci_Position i = pos; i < eol_pos; i++) { + char ch = styler[i]; + if (ch == '#') + return true; + else if (ch != ' ' && ch != '\t') + return false; + } + return false; +} + +static bool IsQuoteLine(Sci_Position line, Accessor &styler) { + int style = styler.StyleAt(styler.LineStart(line)) & 31; + return ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE)); +} + + +static void FoldNimDoc(Sci_PositionU startPos, Sci_Position length, + int /*initStyle - unused*/, + WordList *[], Accessor &styler) { + const Sci_Position maxPos = startPos + length; + const Sci_Position maxLines = styler.GetLine(maxPos - 1); // Requested last line + const Sci_Position docLines = styler.GetLine(styler.Length() - 1); // Available last line + const bool foldComment = styler.GetPropertyInt("fold.comment.nim") != 0; + const bool foldQuotes = styler.GetPropertyInt("fold.quotes.nim") != 0; + + // Backtrack to previous non-blank line so we can determine indent level + // for any white space lines (needed esp. within triple quoted strings) + // and so we can fix any preceding fold level (which is why we go back + // at least one line in all cases) + int spaceFlags = 0; + Sci_Position lineCurrent = styler.GetLine(startPos); + int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); + while (lineCurrent > 0) { + lineCurrent--; + indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) && + (!IsCommentLine(lineCurrent, styler)) && + (!IsQuoteLine(lineCurrent, styler))) + break; + } + int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; + + // Set up initial loop state + startPos = styler.LineStart(lineCurrent); + int prev_state = SCE_P_DEFAULT & 31; + if (lineCurrent >= 1) + prev_state = styler.StyleAt(startPos - 1) & 31; + int prevQuote = foldQuotes && ((prev_state == SCE_P_TRIPLE) || + (prev_state == SCE_P_TRIPLEDOUBLE)); + int prevComment = 0; + if (lineCurrent >= 1) + prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler); + + // Process all characters to end of requested range or end of any triple quote + // or comment that hangs over the end of the range. Cap processing in all cases + // to end of document (in case of unclosed quote or comment at end). + while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || + prevQuote || prevComment)) { + + // Gather info + int lev = indentCurrent; + Sci_Position lineNext = lineCurrent + 1; + int indentNext = indentCurrent; + int quote = false; + if (lineNext <= docLines) { + // Information about next line is only available if not at end of document + indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); + int style = styler.StyleAt(styler.LineStart(lineNext)) & 31; + quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE)); + } + const int quote_start = (quote && !prevQuote); + const int quote_continue = (quote && prevQuote); + const int comment = foldComment && IsCommentLine(lineCurrent, styler); + const int comment_start = (comment && !prevComment && (lineNext <= docLines) && + IsCommentLine(lineNext, styler) && + (lev > SC_FOLDLEVELBASE)); + const int comment_continue = (comment && prevComment); + if ((!quote || !prevQuote) && !comment) + indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; + if (quote) + indentNext = indentCurrentLevel; + if (indentNext & SC_FOLDLEVELWHITEFLAG) + indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel; + + if (quote_start) { + // Place fold point at start of triple quoted string + lev |= SC_FOLDLEVELHEADERFLAG; + } else if (quote_continue || prevQuote) { + // Add level to rest of lines in the string + lev = lev + 1; + } else if (comment_start) { + // Place fold point at start of a block of comments + lev |= SC_FOLDLEVELHEADERFLAG; + } else if (comment_continue) { + // Add level to rest of lines in the block + lev = lev + 1; + } + + // Skip past any blank lines for next indent level info; we skip also + // comments (all comments, not just those starting in column 0) + // which effectively folds them into surrounding code rather + // than screwing up folding. + + while (!quote && + (lineNext < docLines) && + ((indentNext & SC_FOLDLEVELWHITEFLAG) || + (lineNext <= docLines && IsCommentLine(lineNext, styler)))) { + + lineNext++; + indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); + } + + const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK; + const int levelBeforeComments = + Maximum(indentCurrentLevel,levelAfterComments); + + // Now set all the indent levels on the lines we skipped + // Do this from end to start. Once we encounter one line + // which is indented more than the line after the end of + // the comment-block, use the level of the block before + + Sci_Position skipLine = lineNext; + int skipLevel = levelAfterComments; + + while (--skipLine > lineCurrent) { + int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL); + + if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments) + skipLevel = levelBeforeComments; + + int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG; + + styler.SetLevel(skipLine, skipLevel | whiteFlag); + } + + // Set fold header on non-quote/non-comment line + if (!quote && !comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) { + if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < + (indentNext & SC_FOLDLEVELNUMBERMASK)) + lev |= SC_FOLDLEVELHEADERFLAG; + } + + // Keep track of triple quote and block comment state of previous line + prevQuote = quote; + prevComment = comment_start || comment_continue; + + // Set fold level for this line and move to next line + styler.SetLevel(lineCurrent, lev); + indentCurrent = indentNext; + lineCurrent = lineNext; + } + + // NOTE: Cannot set level of last line here because indentCurrent doesn't have + // header flag set; the loop above is crafted to take care of this case! + //styler.SetLevel(lineCurrent, indentCurrent); +} + +static const char * const nimWordListDesc[] = { + "Keywords", + 0 +}; + +LexerModule lmNim(SCLEX_NIM, ColouriseNimDoc, "nim", FoldNimDoc, + nimWordListDesc); diff --git a/scintilla/src/Catalogue.cxx b/scintilla/src/Catalogue.cxx index 089c4003d..c6cb2c674 100644 --- a/scintilla/src/Catalogue.cxx +++ b/scintilla/src/Catalogue.cxx @@ -141,6 +141,7 @@ int Scintilla_LinkLexers() { //LINK_LEXER(lmMSSQL); //LINK_LEXER(lmMySQL); //LINK_LEXER(lmNimrod); + LINK_LEXER(lmNim); //LINK_LEXER(lmNncrontab); LINK_LEXER(lmNsis); LINK_LEXER(lmNull); diff --git a/scintilla/src/Document.cxx b/scintilla/src/Document.cxx index 08efa9ec2..81d022097 100644 --- a/scintilla/src/Document.cxx +++ b/scintilla/src/Document.cxx @@ -2600,8 +2600,14 @@ public: #ifndef NO_CXX11_REGEX -class ByteIterator : public std::iterator { +class ByteIterator { public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef char value_type; + typedef ptrdiff_t difference_type; + typedef char* pointer; + typedef char& reference; + const Document *doc; Sci::Position position; ByteIterator(const Document *doc_ = 0, Sci::Position position_ = 0) : doc(doc_), position(position_) { @@ -2663,7 +2669,7 @@ public: // On Windows, report non-BMP characters as 2 separate surrogates as that // matches wregex since it is based on wchar_t. -class UTF8Iterator : public std::iterator { +class UTF8Iterator { // These 3 fields determine the iterator position and are used for comparisons const Document *doc; Sci::Position position; @@ -2673,6 +2679,12 @@ class UTF8Iterator : public std::iterator { +class UTF8Iterator { const Document *doc; Sci::Position position; public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef wchar_t value_type; + typedef ptrdiff_t difference_type; + typedef wchar_t* pointer; + typedef wchar_t& reference; + UTF8Iterator(const Document *doc_=0, Sci::Position position_=0) : doc(doc_), position(position_) { } UTF8Iterator(const UTF8Iterator &other) NOEXCEPT { diff --git a/scintilla/src/Editor.cxx b/scintilla/src/Editor.cxx index f09247e3f..816b50534 100644 --- a/scintilla/src/Editor.cxx +++ b/scintilla/src/Editor.cxx @@ -7628,6 +7628,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { default: // ?! return SC_SEL_STREAM; } + case SCI_GETMOVEEXTENDSSELECTION: + return sel.MoveExtends(); case SCI_GETLINESELSTARTPOSITION: case SCI_GETLINESELENDPOSITION: { SelectionSegment segmentLine( diff --git a/src/Notepad3.c b/src/Notepad3.c index dc7256967..53995d10a 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -2358,7 +2358,7 @@ void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam) i == SCLEX_SQL || i == SCLEX_PERL || i == SCLEX_PYTHON || i == SCLEX_PROPERTIES ||i == SCLEX_CONF || i == SCLEX_POWERSHELL || i == SCLEX_BATCH || i == SCLEX_DIFF || i == SCLEX_BASH || i == SCLEX_TCL || i == SCLEX_AU3 || i == SCLEX_LATEX || i == SCLEX_AHK || i == SCLEX_RUBY || i == SCLEX_CMAKE || i == SCLEX_MARKDOWN || - i == SCLEX_YAML || i == SCLEX_REGISTRY)); + i == SCLEX_YAML || i == SCLEX_REGISTRY || i == SCLEX_NIM)); EnableCmd(hmenu,IDM_EDIT_INSERT_ENCODING,*mEncoding[Encoding_Current(CPI_GET)].pszParseNames); @@ -3776,6 +3776,7 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) case SCLEX_AVS: case SCLEX_YAML: case SCLEX_COFFEESCRIPT: + case SCLEX_NIM: BeginWaitCursor(NULL); EditToggleLineComments(g_hwndEdit,L"#",TRUE); EndWaitCursor(); @@ -3843,6 +3844,7 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) case SCLEX_YAML: case SCLEX_JSON: case SCLEX_REGISTRY: + case SCLEX_NIM: break; case SCLEX_HTML: case SCLEX_XML: diff --git a/src/Notepad3.rc b/src/Notepad3.rc index 0664ff9c2..96494adbf 100644 --- a/src/Notepad3.rc +++ b/src/Notepad3.rc @@ -1706,6 +1706,7 @@ BEGIN 63041 "YAML" 63042 "Coffeescript" 63043 "MATLAB" + 63044 "Nim Source Code" END STRINGTABLE diff --git a/src/Styles.c b/src/Styles.c index 5936b5879..9e5061c66 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -2797,6 +2797,35 @@ EDITLEXER lexAwk = { SCLEX_PYTHON, 63024, L"Awk Script", L"awk", L"", &KeyWords { -1, 00000, L"", L"", L"" } } }; + +KEYWORDLIST KeyWords_Nim = { + "addr and as asm atomic bind block break case cast concept const continue converter " + "defer discard distinct div do elif else end enum except export finally for from func " + "generic if import in include interface is isnot iterator let macro method mixin mod " + "nil not notin object of or out proc ptr raise ref return shl shr static " + "template try tuple type using var when while with without xor yield", + "", "", "", "", "", "", "", "" }; + + +EDITLEXER lexNim = { SCLEX_NIM, 63044, L"Nim Source Code", L"nim", L"", &KeyWords_Nim,{ + { STYLE_DEFAULT, 63126, L"Default", L"", L"" }, + //{ SCE_P_DEFAULT, 63126, L"Default", L"", L"" }, + { MULTI_STYLE(SCE_P_COMMENTLINE,SCE_P_COMMENTBLOCK,SCE_C_COMMENTLINEDOC,0), 63127, L"Comment", L"fore:#880000", L"" }, + { SCE_P_WORD, 63128, L"Keyword", L" bold; fore:#000088", L"" }, + { SCE_P_IDENTIFIER, 63129, L"Identifier", L"", L"" }, + { MULTI_STYLE(SCE_P_STRING,SCE_P_STRINGEOL,0,0), 63211, L"String double quoted", L"fore:#008800", L"" }, + { SCE_P_CHARACTER, 63212, L"String single quoted", L"fore:#008800", L"" }, + { SCE_P_TRIPLEDOUBLE, 63244, L"String triple double quotes", L"fore:#008800", L"" }, + { SCE_P_TRIPLE, 63245, L"String triple single quotes", L"fore:#008800", L"" }, + { SCE_P_NUMBER, 63130, L"Number", L"fore:#FF4000", L"" }, + { SCE_P_OPERATOR, 63132, L"Operator", L"bold; fore:#666600", L"" }, + //{ SCE_P_DEFNAME, 63247, L"Function name", L"fore:#660066", L"" }, + //{ SCE_P_CLASSNAME, 63246, L"Class name", L"fore:#660066", L"" }, + { -1, 00000, L"", L"", L"" } } }; + + + + // This array holds all the lexers... // Don't forget to change the number of the lexer for HTML and XML // in Notepad2.c ParseCommandLine() if you change this array! @@ -2829,6 +2858,7 @@ static PEDITLEXER pLexArray[NUMLEXERS] = &lexMAK, // Makefiles &lexMARKDOWN, // Markdown &lexMATLAB, // MATLAB + &lexNim, // Nim &lexNSIS, // NSIS Script &lexPAS, // Pascal Source Code &lexPL, // Perl Script @@ -4248,10 +4278,15 @@ void Style_SetIndentGuides(HWND hwnd,BOOL bShow) int iIndentView = SC_IV_NONE; if (bShow) { if (!flagSimpleIndentGuides) { - if (SendMessage(hwnd,SCI_GETLEXER,0,0) == SCLEX_PYTHON) + switch (SendMessage(hwnd, SCI_GETLEXER, 0, 0)) { + case SCLEX_PYTHON: + case SCLEX_NIM: iIndentView = SC_IV_LOOKFORWARD; - else + break; + default: iIndentView = SC_IV_LOOKBOTH; + break; + } } else iIndentView = SC_IV_REAL; diff --git a/src/Styles.h b/src/Styles.h index 0e766109f..d97282e3d 100644 --- a/src/Styles.h +++ b/src/Styles.h @@ -59,7 +59,7 @@ typedef struct _editlexer // Number of Lexers in pLexArray -#define NUMLEXERS 44 +#define NUMLEXERS 45 #define MAX_NUM_OF_STYLES_PER_LEXER 64 From aca5bb46e3fbc3888f9dadfa7f2ba4c1156b7e3e Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Wed, 10 Jan 2018 00:23:53 +0100 Subject: [PATCH 2/6] + add: scintilla project and header for Nim lexer + performance: non visible styling during idle time + performance: cache page instead of line only --- scintilla/Scintilla.vcxproj | 1 + scintilla/Scintilla.vcxproj.filters | 3 +++ scintilla/include/SciLexer.h | 1 + scintilla/include/Scintilla.h | 1 + src/Edit.c | 3 +++ src/Notepad3.c | 2 ++ src/Styles.c | 3 ++- 7 files changed, 13 insertions(+), 1 deletion(-) diff --git a/scintilla/Scintilla.vcxproj b/scintilla/Scintilla.vcxproj index fa344ba44..bd769691f 100644 --- a/scintilla/Scintilla.vcxproj +++ b/scintilla/Scintilla.vcxproj @@ -271,6 +271,7 @@ + diff --git a/scintilla/Scintilla.vcxproj.filters b/scintilla/Scintilla.vcxproj.filters index 87dc4d580..f51a20f50 100644 --- a/scintilla/Scintilla.vcxproj.filters +++ b/scintilla/Scintilla.vcxproj.filters @@ -441,6 +441,9 @@ onigmo + + lexers + diff --git a/scintilla/include/SciLexer.h b/scintilla/include/SciLexer.h index b3bf96956..00415438b 100644 --- a/scintilla/include/SciLexer.h +++ b/scintilla/include/SciLexer.h @@ -136,6 +136,7 @@ #define SCLEX_EDIFACT 121 #define SCLEX_INDENT 122 #define SCLEX_AHK 200 +#define SCLEX_NIM 201 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 diff --git a/scintilla/include/Scintilla.h b/scintilla/include/Scintilla.h index f21216c6b..c7dd9d545 100644 --- a/scintilla/include/Scintilla.h +++ b/scintilla/include/Scintilla.h @@ -759,6 +759,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_SEL_THIN 3 #define SCI_SETSELECTIONMODE 2422 #define SCI_GETSELECTIONMODE 2423 +#define SCI_GETMOVEEXTENDSSELECTION 2706 #define SCI_GETLINESELSTARTPOSITION 2424 #define SCI_GETLINESELENDPOSITION 2425 #define SCI_LINEDOWNRECTEXTEND 2426 diff --git a/src/Edit.c b/src/Edit.c index 633525424..b196cdae9 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -182,6 +182,8 @@ HWND EditCreate(HWND hwndParent) SendMessage(hwnd,SCI_SETADDITIONALCARETSBLINK,FALSE,0); SendMessage(hwnd,SCI_SETADDITIONALCARETSVISIBLE,FALSE,0); SendMessage(hwnd,SCI_SETVIRTUALSPACEOPTIONS, (bDenyVirtualSpaceAccess ? SCVS_NONE : SCVS_RECTANGULARSELECTION), 0); + SendMessage(hwnd,SCI_SETLAYOUTCACHE,SC_CACHE_PAGE,0); + SendMessage(hwnd,SCI_ASSIGNCMDKEY,(SCK_NEXT + (SCMOD_CTRL << 16)),SCI_PARADOWN); SendMessage(hwnd,SCI_ASSIGNCMDKEY,(SCK_PRIOR + (SCMOD_CTRL << 16)),SCI_PARAUP); @@ -6838,6 +6840,7 @@ BOOL FileVars_Apply(HWND hwnd,LPFILEVARS lpfv) { bWordWrap = lpfv->fWordWrap; else bWordWrap = bWordWrapG; + if (!bWordWrap) SendMessage(g_hwndEdit,SCI_SETWRAPMODE,SC_WRAP_NONE,0); else diff --git a/src/Notepad3.c b/src/Notepad3.c index 53995d10a..565556bb6 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -1307,6 +1307,7 @@ LRESULT MsgCreate(HWND hwnd,WPARAM wParam,LPARAM lParam) SendMessage(g_hwndEdit,SCI_SETWRAPMODE,SC_WRAP_NONE,0); else SendMessage(g_hwndEdit,SCI_SETWRAPMODE,(iWordWrapMode == 0) ? SC_WRAP_WORD : SC_WRAP_CHAR,0); + if (iWordWrapIndent == 5) SendMessage(g_hwndEdit,SCI_SETWRAPINDENTMODE,SC_WRAPINDENT_SAME,0); else if (iWordWrapIndent == 6) @@ -1347,6 +1348,7 @@ LRESULT MsgCreate(HWND hwnd,WPARAM wParam,LPARAM lParam) SendMessage(g_hwndEdit,SCI_SETEDGEMODE,(iLongLineMode == EDGE_LINE)?EDGE_LINE:EDGE_BACKGROUND,0); else SendMessage(g_hwndEdit,SCI_SETEDGEMODE,EDGE_NONE,0); + SendMessage(g_hwndEdit,SCI_SETEDGECOLUMN,iLongLinesLimit,0); // Margins diff --git a/src/Styles.c b/src/Styles.c index 9e5061c66..02a658fed 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -3736,7 +3736,7 @@ void Style_SetUrlHotSpot(HWND hwnd, BOOL bHotSpot) const WCHAR* lpszStyleHotSpot = lexStandard.Styles[STDLEXID(STY_URL_HOTSPOT)].szValue; SendMessage(hwnd, SCI_STYLESETHOTSPOT, iStyleHotSpot, (LPARAM)TRUE); - SendMessage(hwnd, SCI_SETHOTSPOTSINGLELINE, TRUE, 0); + SendMessage(hwnd, SCI_SETHOTSPOTSINGLELINE, FALSE, 0); // Font Style_SetStyles(hwnd, iStyleHotSpot, lpszStyleHotSpot); @@ -3765,6 +3765,7 @@ void Style_SetUrlHotSpot(HWND hwnd, BOOL bHotSpot) Style_SetStyles(hwnd, iStyleHotSpot, lpszStyleHotSpot); + SendMessage(hwnd, SCI_SETHOTSPOTSINGLELINE, TRUE, 0); SendMessage(hwnd, SCI_STYLESETHOTSPOT, iStyleHotSpot, (LPARAM)FALSE); } From a155d597f47736c453bdf3b54db2b3b265e3a282 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Wed, 10 Jan 2018 00:32:54 +0100 Subject: [PATCH 3/6] + change: option "after visible" for styling in background (idle time) --- src/Styles.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Styles.c b/src/Styles.c index 02a658fed..88d2ffaf9 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -3216,7 +3216,8 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew) { WCHAR* wchStandardStyleStrg = lexStandard.Styles[STDLEXID(STY_DEFAULT)].szValue; // Idle Styling (very large text) - SendMessage(hwnd, SCI_SETIDLESTYLING, SC_IDLESTYLING_ALL, 0); + SendMessage(hwnd, SCI_SETIDLESTYLING, SC_IDLESTYLING_AFTERVISIBLE, 0); + //SendMessage(hwnd, SCI_SETIDLESTYLING, SC_IDLESTYLING_ALL, 0); // Default Values are always set SendMessage(hwnd, SCI_STYLERESETDEFAULT, 0, 0); From 074b6f834429026ef0e239e83eba3f480f156cb3 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Wed, 10 Jan 2018 00:55:44 +0100 Subject: [PATCH 4/6] + update: compiler version 191225834 (VS2017 V.15.5.3) --- src/Version.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Version.h b/src/Version.h index 1f3fe256a..6e2134aae 100644 --- a/src/Version.h +++ b/src/Version.h @@ -59,7 +59,9 @@ // Compiler specific #if defined(_MSC_VER) #if (_MSC_VER >= 1912) - #if(_MSC_FULL_VER >= 191225831) + #if(_MSC_FULL_VER >= 191225834) + #define VER_CPL "Microsoft Visual C++ 2017 Version 15.5.3" + #elif(_MSC_FULL_VER >= 191225831) #define VER_CPL "Microsoft Visual C++ 2017 Version 15.5.2" #elif(_MSC_FULL_VER >= 191225830) #define VER_CPL "Microsoft Visual C++ 2017 Version 15.5" From 91a6805de79b23025e5b7585a025058ec5aaf8c4 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Wed, 10 Jan 2018 01:29:00 +0100 Subject: [PATCH 5/6] + fix: loosing state of "Transform Backslashes" while switching regex/wildcard search --- src/Edit.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Edit.c b/src/Edit.c index b196cdae9..15e844874 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -4342,6 +4342,7 @@ INT_PTR CALLBACK EditFindReplaceDlgProcW(HWND hwnd,UINT umsg,WPARAM wParam,LPARA static int iSaveMarkOcc = -1; static BOOL bSaveOccVisible = FALSE; + static BOOL bSaveTFBackSlashes = FALSE; switch(umsg) { @@ -4456,8 +4457,12 @@ INT_PTR CALLBACK EditFindReplaceDlgProcW(HWND hwnd,UINT umsg,WPARAM wParam,LPARA if (lpefr->fuFlags & SCFIND_WORDSTART) CheckDlgButton(hwnd, IDC_FINDSTART, BST_CHECKED); - if (lpefr->bTransformBS) + if (lpefr->bTransformBS) { + bSaveTFBackSlashes = lpefr->bTransformBS; CheckDlgButton(hwnd, IDC_FINDTRANSFORMBS, BST_CHECKED); + } + else + bSaveTFBackSlashes = FALSE; if (lpefr->fuFlags & SCFIND_REGEXP) { CheckDlgButton(hwnd, IDC_FINDREGEXP, BST_CHECKED); @@ -4707,6 +4712,7 @@ INT_PTR CALLBACK EditFindReplaceDlgProcW(HWND hwnd,UINT umsg,WPARAM wParam,LPARA DialogEnableWindow(hwnd, IDC_DOT_MATCH_ALL, FALSE); DialogEnableWindow(hwnd, IDC_FINDTRANSFORMBS, TRUE); + lpefr->bTransformBS = bSaveTFBackSlashes; CheckDlgButton(hwnd, IDC_FINDTRANSFORMBS, (lpefr->bTransformBS) ? BST_CHECKED : BST_UNCHECKED); } bFlagsChanged = TRUE; @@ -4738,7 +4744,6 @@ INT_PTR CALLBACK EditFindReplaceDlgProcW(HWND hwnd,UINT umsg,WPARAM wParam,LPARA CheckDlgButton(hwnd, IDC_FINDTRANSFORMBS, BST_CHECKED); // transform BS handled by regex DialogEnableWindow(hwnd, IDC_FINDTRANSFORMBS, FALSE); - } else { // unchecked @@ -4747,6 +4752,7 @@ INT_PTR CALLBACK EditFindReplaceDlgProcW(HWND hwnd,UINT umsg,WPARAM wParam,LPARA lpefr->fuFlags &= ~(SCFIND_DOT_MATCH_ALL); DialogEnableWindow(hwnd, IDC_FINDTRANSFORMBS, TRUE); + lpefr->bTransformBS = bSaveTFBackSlashes; CheckDlgButton(hwnd, IDC_FINDTRANSFORMBS, (lpefr->bTransformBS) ? BST_CHECKED : BST_UNCHECKED); } bFlagsChanged = TRUE; @@ -4756,9 +4762,11 @@ INT_PTR CALLBACK EditFindReplaceDlgProcW(HWND hwnd,UINT umsg,WPARAM wParam,LPARA case IDC_FINDTRANSFORMBS: if (IsDlgButtonChecked(hwnd, IDC_FINDTRANSFORMBS) == BST_CHECKED) { lpefr->bTransformBS = TRUE; + bSaveTFBackSlashes = TRUE; } else { lpefr->bTransformBS = FALSE; + bSaveTFBackSlashes = FALSE; } bFlagsChanged = TRUE; EditSetTimerMarkAll(hwnd); From 1f4320849fff9b18c8bf5bded4796be8686bb5c1 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Wed, 10 Jan 2018 02:26:26 +0100 Subject: [PATCH 6/6] + fix: block "mark occurrences" event on transaction pair: (SCI_TARGETFROMSELECTIO, SCI_REPLACETARGET) --- src/Notepad3.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/Notepad3.c b/src/Notepad3.c index 565556bb6..c954043ef 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -322,6 +322,7 @@ static DWORD DropFilesProc(CLIPFORMAT cf, HGLOBAL hData, HWND hWnd, DWORD dwKeyS static volatile LONG g_lTimerBits = 0; #define TIMER_BIT_MARK_OCC 1L #define TIMER_BIT_UPDATE_HYPER 2L +#define BLOCK_BIT_MARK_OCC 4L #define TEST_AND_SET(B) InterlockedBitTestAndSet(&g_lTimerBits, B) #define TEST_AND_RESET(B) InterlockedBitTestAndReset(&g_lTimerBits, B) @@ -2546,24 +2547,27 @@ LRESULT MsgSysCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) void __fastcall MarkAllOccurrencesTimer() { if (iMarkOccurrences != 0) { - if (bMarkOccurrencesMatchVisible) - { - // get visible lines for update - int iFirstVisibleLine = SciCall_DocLineFromVisible(SciCall_GetFirstVisibleLine()); + if (!TEST_AND_SET(BLOCK_BIT_MARK_OCC)) { + TEST_AND_RESET(BLOCK_BIT_MARK_OCC); + if (bMarkOccurrencesMatchVisible) + { + // get visible lines for update + int iFirstVisibleLine = SciCall_DocLineFromVisible(SciCall_GetFirstVisibleLine()); - int iStartLine = max(0, (iFirstVisibleLine - SciCall_LinesOnScreen())); - int iEndLine = min((iFirstVisibleLine + (SciCall_LinesOnScreen() << 1)), (SciCall_GetLineCount() - 1)); + int iStartLine = max(0, (iFirstVisibleLine - SciCall_LinesOnScreen())); + int iEndLine = min((iFirstVisibleLine + (SciCall_LinesOnScreen() << 1)), (SciCall_GetLineCount() - 1)); - int iPosStart = SciCall_PositionFromLine(iStartLine); - int iPosEnd = SciCall_GetLineEndPosition(iEndLine); + int iPosStart = SciCall_PositionFromLine(iStartLine); + int iPosEnd = SciCall_GetLineEndPosition(iEndLine); - // !!! don't clear all marks, else this method is re-called - // !!! on UpdateUI notification on drawing indicator mark - EditMarkAll(g_hwndEdit, NULL, bMarkOccurrencesCurrentWord, iPosStart, iPosEnd, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords); - } - else { - EditMarkAll(g_hwndEdit, NULL, bMarkOccurrencesCurrentWord, 0, SciCall_GetTextLength(), bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords); - UpdateStatusbar(); + // !!! don't clear all marks, else this method is re-called + // !!! on UpdateUI notification on drawing indicator mark + EditMarkAll(g_hwndEdit, NULL, bMarkOccurrencesCurrentWord, iPosStart, iPosEnd, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords); + } + else { + EditMarkAll(g_hwndEdit, NULL, bMarkOccurrencesCurrentWord, 0, SciCall_GetTextLength(), bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords); + UpdateStatusbar(); + } } } } @@ -3487,8 +3491,10 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) { BeginWaitCursor(NULL); int token = BeginSelUndoAction(); + TEST_AND_SET(BLOCK_BIT_MARK_OCC); SendMessage(g_hwndEdit,SCI_TARGETFROMSELECTION,0,0); SendMessage(g_hwndEdit,SCI_LINESSPLIT,0,0); + TEST_AND_RESET(BLOCK_BIT_MARK_OCC); EndSelUndoAction(token); EndWaitCursor(); } @@ -3499,8 +3505,10 @@ LRESULT MsgCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) { BeginWaitCursor(NULL); int token = BeginSelUndoAction(); + TEST_AND_SET(BLOCK_BIT_MARK_OCC); SendMessage(g_hwndEdit,SCI_TARGETFROMSELECTION,0,0); SendMessage(g_hwndEdit,SCI_LINESJOIN,0,0); + TEST_AND_RESET(BLOCK_BIT_MARK_OCC); EditJoinLinesEx(g_hwndEdit); EndSelUndoAction(token); EndWaitCursor();