diff --git a/Build/Changes.txt b/Build/Changes.txt index cd9defe8e..6a5bef4ff 100644 --- a/Build/Changes.txt +++ b/Build/Changes.txt @@ -33,13 +33,14 @@ UCD - (UCD)ARDET is an Encoding Detector Library ======================================================== -Current BETA/RC Version 5.21.515.(build_#) (2021-05-15) +Current BETA/RC Version 5.21.525.(build_#) (2021-05-25) ======================================================== -------------------------------------------------------- NEW: -------------------------------------------------------- [.###.#]- . +[.525.1]- Add "Julia" lexer (new in Lexilla). [.506.1]- Base64 Encoding/Decoding. [.428.1]- Custom ChooseColor resource definition. [.426.1]- Prepare Application Manifest for to grant Identity for non-package desktop apps. @@ -71,6 +72,7 @@ NEW: CHANGES: -------------------------------------------------------- [.###.#]- . +[.525.1]- Update Lexilla Lib (bug fixes for Lexer: Markdown, Cmd/Batch). [.515.1]- "grepWinNP3" based on current grepWin ver (boost v1.76 , upd: sktoolslib). [.515.1]- Add some more coding fonts to prefer over Consolas (if installed). [.515.1]- Linker: hardware-enforced stack-protection. @@ -117,7 +119,7 @@ CHANGES: [.301.1]- Enable Dark Mode feature for Win10 v21H1 insider beta. [.301.1]- EOL-Mode: status-bar double-click : inverted cyclic change rotation CRLF -> LF -> CR. [.515.1]- Update grepWinNP3 (GRE) version 2.1.7.37 (2021-05.14). -[.429.1]- Update Oniguruma Regex (ONI) engine version 7.0.0 (2021-04-26). +[.525.1]- Update Oniguruma Regex (ONI) engine version 7.0.0 (2021-05-17). [.429.1]- Update Lexilla Library (LEX) version 5.0.2 (2021-04-23). [.429.1]- Update Scintilla Library (SCI) version 5.0.2 (2021-04-23). diff --git a/Build/minipath.ini b/Build/minipath.ini index 6a1b8db18..1f820be99 100644 --- a/Build/minipath.ini +++ b/Build/minipath.ini @@ -75,6 +75,7 @@ Go Source Code=*.go ;Java Source Code=*.java;*.jad;*.aidl;*.bsh JavaScript=*.js;*.jse;*.jsm;*.as;*.mjs;*.qs ;JSON=*.json;*.har;*.ipynb;*.wxcp;*.jshintrc;*.eslintrc;*.babelrc;*.prettierrc;*.stylelintrc;*.jsonld;*.jsonc;*.arcconfig;*.arclint;*.jscop +;Julia Script=*.jl ;Kotlin Source Code=*.kt;*.kts;*.ktm ;LaTeX Files=*.tex;*.latex;*.sty;*.texi;*.texinfo;*.txi ;Lua Script=*.lua;*.wlua;*.nse;*.luadoc;*.luax diff --git a/Versions/day.txt b/Versions/day.txt index 3cda32fc2..642ea6f49 100644 --- a/Versions/day.txt +++ b/Versions/day.txt @@ -1 +1 @@ -515 +525 diff --git a/grepWinNP3/grepWinNP3.vcxproj b/grepWinNP3/grepWinNP3.vcxproj index 2ecb845bc..3ab69b143 100644 --- a/grepWinNP3/grepWinNP3.vcxproj +++ b/grepWinNP3/grepWinNP3.vcxproj @@ -146,7 +146,7 @@ stdc17 - true + DebugFull Windows MachineX86 shlwapi.lib;Urlmon.lib;UxTheme.lib;%(AdditionalDependencies) @@ -174,7 +174,7 @@ stdc17 - true + DebugFull Windows shlwapi.lib;Urlmon.lib;UxTheme.lib;%(AdditionalDependencies) true diff --git a/language/common_res.h b/language/common_res.h index f9787957c..4ebb11455 100644 --- a/language/common_res.h +++ b/language/common_res.h @@ -953,6 +953,7 @@ #define IDS_LEX_PRISM_CSV 63050 #define IDS_LEX_DART_SRC 63051 #define IDS_LEX_KOTLIN_SRC 63052 +#define IDS_LEX_JULIA_SCR 63053 #define IDS_LEX_STD_STYLE 63100 #define IDS_LEX_STD_MARGIN 63101 diff --git a/language/np3_de_de/lexer_de_de.rc b/language/np3_de_de/lexer_de_de.rc index ad2cd8b49..4976da051 100644 --- a/language/np3_de_de/lexer_de_de.rc +++ b/language/np3_de_de/lexer_de_de.rc @@ -127,6 +127,7 @@ BEGIN IDS_LEX_TOML_CFG "TOML" IDS_LEX_DART_SRC "Dart Source Code" IDS_LEX_KOTLIN_SRC "Kotlin Source Code" + IDS_LEX_JULIA_SCR "Julia Script" END STRINGTABLE diff --git a/language/np3_en_us/lexer_en_us.rc b/language/np3_en_us/lexer_en_us.rc index ff2acb922..ed5c19439 100644 --- a/language/np3_en_us/lexer_en_us.rc +++ b/language/np3_en_us/lexer_en_us.rc @@ -127,6 +127,7 @@ BEGIN IDS_LEX_TOML_CFG "TOML" IDS_LEX_DART_SRC "Dart Source Code" IDS_LEX_KOTLIN_SRC "Kotlin Source Code" + IDS_LEX_JULIA_SCR "Julia Script" END STRINGTABLE diff --git a/lexilla/Lexilla.vcxproj b/lexilla/Lexilla.vcxproj index 44354b00c..dd2e7b6bf 100644 --- a/lexilla/Lexilla.vcxproj +++ b/lexilla/Lexilla.vcxproj @@ -66,6 +66,7 @@ + @@ -231,13 +232,14 @@ true Precise MultiThreadedDebug - true + false false false true stdc17 + ProgramDatabase Console @@ -338,12 +340,13 @@ true Precise MultiThreadedDebug - true + false false false true stdc17 + ProgramDatabase Console diff --git a/lexilla/Lexilla.vcxproj.filters b/lexilla/Lexilla.vcxproj.filters index 165038154..b9ef5702e 100644 --- a/lexilla/Lexilla.vcxproj.filters +++ b/lexilla/Lexilla.vcxproj.filters @@ -263,6 +263,9 @@ lexers_x + + lexers + diff --git a/lexilla/cppcheck.suppress b/lexilla/cppcheck.suppress index 5f7befe90..84e6ef1a8 100644 --- a/lexilla/cppcheck.suppress +++ b/lexilla/cppcheck.suppress @@ -32,7 +32,9 @@ constParameter:lexilla/lexers/LexBash.cxx uninitMemberVar:lexilla/lexers/LexBash.cxx variableScope:lexilla/lexers/LexBash.cxx variableScope:lexilla/lexers/LexBatch.cxx +knownConditionTrueFalse:lexilla/lexers/LexBatch.cxx knownConditionTrueFalse:lexilla/lexers/LexBibTeX.cxx +constStatement:lexilla/lexers/LexCaml.cxx variableScope:lexilla/lexers/LexCmake.cxx knownConditionTrueFalse:lexilla/lexers/LexCmake.cxx constParameter:lexilla/lexers/LexCLW.cxx @@ -52,6 +54,9 @@ constParameter:lexilla/lexers/LexHaskell.cxx constParameter:lexilla/lexers/LexHex.cxx constParameter:lexilla/lexers/LexHTML.cxx variableScope:lexilla/lexers/LexInno.cxx +variableScope:lexilla/lexers/LexJulia.cxx +constParameter:lexilla/lexers/LexJulia.cxx +unreadVariable:lexilla/lexers/LexJulia.cxx variableScope:lexilla/lexers/LexLaTeX.cxx constParameter:lexilla/lexers/LexLaTeX.cxx constParameter:lexilla/lexers/LexLisp.cxx diff --git a/lexilla/doc/LexillaHistory.html b/lexilla/doc/LexillaHistory.html index 1d165658a..9fce1314e 100644 --- a/lexilla/doc/LexillaHistory.html +++ b/lexilla/doc/LexillaHistory.html @@ -562,6 +562,9 @@ Derek Brown Robert Di Pardo + riQQ + YX Hao + Bertrand Lacoste

Releases

@@ -576,16 +579,37 @@ Add namespace feature with GetNameSpace function.
  • + Add Julia lexer. + Feature #1380. +
  • +
  • Fix transition to comment for --> inside JavaScript string. Bug #2207.
  • + Fix variable expansion in Batch. + Issue #4. +
  • +
  • + Fix empty link titles in Markdown. + Bug #2235. + Also fix detection of whether the previous line had content which treated '\n' and '\r\n' line endings differently. +
  • +
  • + Remove nested comment and long string support as these were removed from Lua. + Bug #2205. +
  • +
  • Update to Unicode 13. Feature #1379.
  • AddStaticLexerModule function adds a static lexer to Lexilla's list.
  • +
  • + On Win32 enable hardware-enforced stack protection. + Feature #1405. +
  • Release 5.0.2 diff --git a/lexilla/include/LexicalStyles.iface b/lexilla/include/LexicalStyles.iface index 5c276c161..0852c400b 100644 --- a/lexilla/include/LexicalStyles.iface +++ b/lexilla/include/LexicalStyles.iface @@ -141,6 +141,7 @@ val SCLEX_DATAFLEX=129 val SCLEX_HOLLYWOOD=130 val SCLEX_RAKU=131 val SCLEX_FSHARP=132 +val SCLEX_JULIA=133 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -1047,6 +1048,28 @@ val SCE_ERLANG_MODULES_ATT=24 val SCE_ERLANG_UNKNOWN=31 # Lexical states for SCLEX_OCTAVE are identical to MatLab lex Octave=SCLEX_OCTAVE SCE_MATLAB_ +# Lexical states for SCLEX_JULIA +lex Julia=SCLEX_JULIA SCE_JULIA_ +val SCE_JULIA_DEFAULT=0 +val SCE_JULIA_COMMENT=1 +val SCE_JULIA_NUMBER=2 +val SCE_JULIA_KEYWORD1=3 +val SCE_JULIA_KEYWORD2=4 +val SCE_JULIA_KEYWORD3=5 +val SCE_JULIA_CHAR=6 +val SCE_JULIA_OPERATOR=7 +val SCE_JULIA_BRACKET=8 +val SCE_JULIA_IDENTIFIER=9 +val SCE_JULIA_STRING=10 +val SCE_JULIA_SYMBOL=11 +val SCE_JULIA_MACRO=12 +val SCE_JULIA_STRINGINTERP=13 +val SCE_JULIA_DOCSTRING=14 +val SCE_JULIA_STRINGLITERAL=15 +val SCE_JULIA_COMMAND=16 +val SCE_JULIA_COMMANDLITERAL=17 +val SCE_JULIA_TYPEANNOT=18 +val SCE_JULIA_LEXERROR=19 # Lexical states for SCLEX_MSSQL lex MSSQL=SCLEX_MSSQL SCE_MSSQL_ val SCE_MSSQL_DEFAULT=0 diff --git a/lexilla/include/SciLexer.h b/lexilla/include/SciLexer.h index e64a578d7..a3ba58129 100644 --- a/lexilla/include/SciLexer.h +++ b/lexilla/include/SciLexer.h @@ -145,6 +145,7 @@ #define SCLEX_HOLLYWOOD 130 #define SCLEX_RAKU 131 #define SCLEX_FSHARP 132 +#define SCLEX_JULIA 133 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -932,6 +933,26 @@ #define SCE_ERLANG_MODULES 23 #define SCE_ERLANG_MODULES_ATT 24 #define SCE_ERLANG_UNKNOWN 31 +#define SCE_JULIA_DEFAULT 0 +#define SCE_JULIA_COMMENT 1 +#define SCE_JULIA_NUMBER 2 +#define SCE_JULIA_KEYWORD1 3 +#define SCE_JULIA_KEYWORD2 4 +#define SCE_JULIA_KEYWORD3 5 +#define SCE_JULIA_CHAR 6 +#define SCE_JULIA_OPERATOR 7 +#define SCE_JULIA_BRACKET 8 +#define SCE_JULIA_IDENTIFIER 9 +#define SCE_JULIA_STRING 10 +#define SCE_JULIA_SYMBOL 11 +#define SCE_JULIA_MACRO 12 +#define SCE_JULIA_STRINGINTERP 13 +#define SCE_JULIA_DOCSTRING 14 +#define SCE_JULIA_STRINGLITERAL 15 +#define SCE_JULIA_COMMAND 16 +#define SCE_JULIA_COMMANDLITERAL 17 +#define SCE_JULIA_TYPEANNOT 18 +#define SCE_JULIA_LEXERROR 19 #define SCE_MSSQL_DEFAULT 0 #define SCE_MSSQL_COMMENT 1 #define SCE_MSSQL_LINE_COMMENT 2 diff --git a/lexilla/lexers/LexBatch.cxx b/lexilla/lexers/LexBatch.cxx index 9775c2174..123ed712d 100644 --- a/lexilla/lexers/LexBatch.cxx +++ b/lexilla/lexers/LexBatch.cxx @@ -423,14 +423,54 @@ static void ColouriseBatchDoc( // Reset Offset to re-process remainder of word offset -= (wbl - 2); // Check for Expanded Argument (%~...) / Variable (%%~...) + // Expanded Argument: %~[] + // Expanded Variable: %%~[] + // Path operators are exclusively alphabetic. + // Expanded arguments have a single digit at the end. + // Expanded variables have a single identifier character as variable name. } else if (((wbl > 1) && (wordBuffer[1] == '~')) || ((wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] == '~'))) { // Check for External Command / Program if (cmdLoc == offset - wbl) { cmdLoc = offset - (wbl - wbo); } - // Colorize Expanded Argument / Variable - styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); + bool isArgument = (wordBuffer[1] == '~'); + if (isArgument) { + Sci_PositionU expansionStopOffset = 2; + bool isValid = false; + for (; expansionStopOffset < wbl; expansionStopOffset++) { + if (isArgument && Is0To9(wordBuffer[expansionStopOffset])) { + expansionStopOffset++; + isValid = true; + wbo = expansionStopOffset; + // Colorize Expanded Argument + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); + break; + } + } + if (!isValid) { + // not a valid expanded argument or variable + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); + } + // Expanded Variable + } else { + // start after ~ + wbo = 3; + // Search to end of word for another % (can be a long path) + while ((wbo < wbl) && + (wordBuffer[wbo] != '%') && + (!IsBOperator(wordBuffer[wbo])) && + (!IsBSeparator(wordBuffer[wbo]))) { + wbo++; + } + if (wbo > 3) { + // Colorize Expanded Variable + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); + } else { + // not a valid expanded argument or variable + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); + } + } // Reset Offset to re-process remainder of word offset -= (wbl - wbo); // Check for Environment Variable (%x...%) diff --git a/lexilla/lexers/LexJulia.cxx b/lexilla/lexers/LexJulia.cxx new file mode 100644 index 000000000..a41b0e700 --- /dev/null +++ b/lexilla/lexers/LexJulia.cxx @@ -0,0 +1,1220 @@ +// Scintilla source code edit control +// Encoding: UTF-8 +/** @file LexJulia.cxx + ** Lexer for Julia. + ** Reusing code from LexMatlab, LexPython and LexRust + ** + ** Written by Bertrand Lacoste + ** + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "PropSetSimple.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "CharacterCategory.h" +#include "LexerModule.h" +#include "OptionSet.h" +#include "DefaultLexer.h" + +using namespace Scintilla; +using namespace Lexilla; + +static const int NUM_JULIA_KEYWORD_LISTS = 4; +static const int MAX_JULIA_IDENT_CHARS = 1023; + +// Options used for LexerJulia +struct OptionsJulia { + bool fold; + bool foldComment; + bool foldCompact; + bool foldDocstring; + bool highlightTypeannotation; + bool highlightLexerror; + OptionsJulia() { + fold = true; + foldComment = true; + foldCompact = false; + foldDocstring = true; + highlightTypeannotation = true; + highlightLexerror = true; + } +}; + +static const char * const juliaWordLists[NUM_JULIA_KEYWORD_LISTS + 1] = { + "Primary keywords and identifiers", + "Built in types", + "Other keywords", + "Raw string literals", + 0, +}; + +struct OptionSetJulia : public OptionSet { + OptionSetJulia() { + DefineProperty("fold", &OptionsJulia::fold); + + DefineProperty("fold.compact", &OptionsJulia::foldCompact); + + DefineProperty("fold.comment", &OptionsJulia::foldComment); + + DefineProperty("fold.docstring", &OptionsJulia::foldDocstring); + + DefineProperty("highlight.typeannotation", &OptionsJulia::highlightTypeannotation, + "This option enables Julia highlighting of type after :: as type annotation instead of parsing from the keyword lists."); + + DefineProperty("highlight.lexerror", &OptionsJulia::highlightLexerror, + "This option enables Julia highlighting of syntax error int character or number definition."); + + DefineWordListSets(juliaWordLists); + } +}; + +class LexerJulia : public DefaultLexer { + WordList keywords[NUM_JULIA_KEYWORD_LISTS]; + OptionsJulia options; + OptionSetJulia osJulia; +public: + LexerJulia() : DefaultLexer("julia", SCLEX_JULIA) { + } + virtual ~LexerJulia() { + } + void SCI_METHOD Release() override { + delete this; + } + int SCI_METHOD Version() const override { + return lvRelease5; + } + const char * SCI_METHOD PropertyNames() override { + return osJulia.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) override { + return osJulia.PropertyType(name); + } + const char * SCI_METHOD DescribeProperty(const char *name) override { + return osJulia.DescribeProperty(name); + } + Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; + const char * SCI_METHOD PropertyGet(const char *key) override { + return osJulia.PropertyGet(key); + } + const char * SCI_METHOD DescribeWordListSets() override { + return osJulia.DescribeWordListSets(); + } + Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override; + void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; + void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override; + void * SCI_METHOD PrivateCall(int, void *) override { + return 0; + } + static ILexer5 *LexerFactoryJulia() { + return new LexerJulia(); + } +}; + +Sci_Position SCI_METHOD LexerJulia::PropertySet(const char *key, const char *val) { + if (osJulia.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +Sci_Position SCI_METHOD LexerJulia::WordListSet(int n, const char *wl) { + Sci_Position firstModification = -1; + if (n < NUM_JULIA_KEYWORD_LISTS) { + WordList *wordListN = &keywords[n]; + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +static inline bool IsJuliaOperator(int ch) { + if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || + ch == '-' || ch == '+' || ch == '=' || ch == '|' || + ch == '<' || ch == '>' || ch == '/' || ch == '~' || + ch == '\\' ) { + return true; + } + return false; +} + +// The list contains non-ascii unary operators +static inline bool IsJuliaUnaryOperator (int ch) { + if (ch == 0x00ac || ch == 0x221a || ch == 0x221b || + ch == 0x221c || ch == 0x22c6 || ch == 0x00b1 || + ch == 0x2213 ) { + return true; + } + return false; +} + +static inline bool IsJuliaParen (int ch) { + if (ch == '(' || ch == ')' || ch == '{' || ch == '}' || + ch == '[' || ch == ']' ) { + return true; + } + return false; +} + +// Unicode parsing from Julia source code: +// https://github.com/JuliaLang/julia/blob/master/src/flisp/julia_extensions.c +// keep the same function name to be easy to find again +static int is_wc_cat_id_start(uint32_t wc) { + const CharacterCategory cat = CategoriseCharacter((int) wc); + + return (cat == ccLu || cat == ccLl || + cat == ccLt || cat == ccLm || + cat == ccLo || cat == ccNl || + cat == ccSc || // allow currency symbols + // other symbols, but not arrows or replacement characters + (cat == ccSo && !(wc >= 0x2190 && wc <= 0x21FF) && + wc != 0xfffc && wc != 0xfffd) || + + // math symbol (category Sm) whitelist + (wc >= 0x2140 && wc <= 0x2a1c && + ((wc >= 0x2140 && wc <= 0x2144) || // ⅀, ⅁, ⅂, ⅃, ⅄ + wc == 0x223f || wc == 0x22be || wc == 0x22bf || // ∿, ⊾, ⊿ + wc == 0x22a4 || wc == 0x22a5 || // ⊤ ⊥ + + (wc >= 0x2202 && wc <= 0x2233 && + (wc == 0x2202 || wc == 0x2205 || wc == 0x2206 || // ∂, ∅, ∆ + wc == 0x2207 || wc == 0x220e || wc == 0x220f || // ∇, ∎, ∏ + wc == 0x2210 || wc == 0x2211 || // ∐, ∑ + wc == 0x221e || wc == 0x221f || // ∞, ∟ + wc >= 0x222b)) || // ∫, ∬, ∭, ∮, ∯, ∰, ∱, ∲, ∳ + + (wc >= 0x22c0 && wc <= 0x22c3) || // N-ary big ops: ⋀, ⋁, ⋂, ⋃ + (wc >= 0x25F8 && wc <= 0x25ff) || // ◸, ◹, ◺, ◻, ◼, ◽, ◾, ◿ + + (wc >= 0x266f && + (wc == 0x266f || wc == 0x27d8 || wc == 0x27d9 || // ♯, ⟘, ⟙ + (wc >= 0x27c0 && wc <= 0x27c1) || // ⟀, ⟁ + (wc >= 0x29b0 && wc <= 0x29b4) || // ⦰, ⦱, ⦲, ⦳, ⦴ + (wc >= 0x2a00 && wc <= 0x2a06) || // ⨀, ⨁, ⨂, ⨃, ⨄, ⨅, ⨆ + (wc >= 0x2a09 && wc <= 0x2a16) || // ⨉, ⨊, ⨋, ⨌, ⨍, ⨎, ⨏, ⨐, ⨑, ⨒, ⨓, ⨔, ⨕, ⨖ + wc == 0x2a1b || wc == 0x2a1c)))) || // ⨛, ⨜ + + (wc >= 0x1d6c1 && // variants of \nabla and \partial + (wc == 0x1d6c1 || wc == 0x1d6db || + wc == 0x1d6fb || wc == 0x1d715 || + wc == 0x1d735 || wc == 0x1d74f || + wc == 0x1d76f || wc == 0x1d789 || + wc == 0x1d7a9 || wc == 0x1d7c3)) || + + // super- and subscript +-=() + (wc >= 0x207a && wc <= 0x207e) || + (wc >= 0x208a && wc <= 0x208e) || + + // angle symbols + (wc >= 0x2220 && wc <= 0x2222) || // ∠, ∡, ∢ + (wc >= 0x299b && wc <= 0x29af) || // ⦛, ⦜, ⦝, ⦞, ⦟, ⦠, ⦡, ⦢, ⦣, ⦤, ⦥, ⦦, ⦧, ⦨, ⦩, ⦪, ⦫, ⦬, ⦭, ⦮, ⦯ + + // Other_ID_Start + wc == 0x2118 || wc == 0x212E || // ℘, ℮ + (wc >= 0x309B && wc <= 0x309C) || // katakana-hiragana sound marks + + // bold-digits and double-struck digits + (wc >= 0x1D7CE && wc <= 0x1D7E1)); // 𝟎 through 𝟗 (inclusive), 𝟘 through 𝟡 (inclusive) +} + +static inline bool IsIdentifierFirstCharacter (int ch) { + if (IsASCII(ch)) { + return (bool) (isalpha(ch) || ch == '_'); + } + if (ch < 0xA1 || ch > 0x10ffff) { + return false; + } + + return is_wc_cat_id_start((uint32_t) ch); +} + +static inline bool IsIdentifierCharacter (int ch) { + if (IsASCII(ch)) { + return (bool) (isalnum(ch) || ch == '_' || ch == '!'); + } + if (ch < 0xA1 || ch > 0x10ffff) { + return false; + } + + if (is_wc_cat_id_start((uint32_t) ch)) { + return true; + } + + const CharacterCategory cat = CategoriseCharacter(ch); + + if (cat == ccMn || cat == ccMc || + cat == ccNd || cat == ccPc || + cat == ccSk || cat == ccMe || + cat == ccNo || + // primes (single, double, triple, their reverses, and quadruple) + (ch >= 0x2032 && ch <= 0x2037) || (ch == 0x2057)) { + return true; + } + return false; +} + +// keep the same function name to be easy to find again +static const uint32_t opsuffs[] = { + 0x00b2, // ² + 0x00b3, // ³ + 0x00b9, // ¹ + 0x02b0, // ʰ + 0x02b2, // ʲ + 0x02b3, // ʳ + 0x02b7, // ʷ + 0x02b8, // ʸ + 0x02e1, // ˡ + 0x02e2, // ˢ + 0x02e3, // ˣ + 0x1d2c, // ᴬ + 0x1d2e, // ᴮ + 0x1d30, // ᴰ + 0x1d31, // ᴱ + 0x1d33, // ᴳ + 0x1d34, // ᴴ + 0x1d35, // ᴵ + 0x1d36, // ᴶ + 0x1d37, // ᴷ + 0x1d38, // ᴸ + 0x1d39, // ᴹ + 0x1d3a, // ᴺ + 0x1d3c, // ᴼ + 0x1d3e, // ᴾ + 0x1d3f, // ᴿ + 0x1d40, // ᵀ + 0x1d41, // ᵁ + 0x1d42, // ᵂ + 0x1d43, // ᵃ + 0x1d47, // ᵇ + 0x1d48, // ᵈ + 0x1d49, // ᵉ + 0x1d4d, // ᵍ + 0x1d4f, // ᵏ + 0x1d50, // ᵐ + 0x1d52, // ᵒ + 0x1d56, // ᵖ + 0x1d57, // ᵗ + 0x1d58, // ᵘ + 0x1d5b, // ᵛ + 0x1d5d, // ᵝ + 0x1d5e, // ᵞ + 0x1d5f, // ᵟ + 0x1d60, // ᵠ + 0x1d61, // ᵡ + 0x1d62, // ᵢ + 0x1d63, // ᵣ + 0x1d64, // ᵤ + 0x1d65, // ᵥ + 0x1d66, // ᵦ + 0x1d67, // ᵧ + 0x1d68, // ᵨ + 0x1d69, // ᵩ + 0x1d6a, // ᵪ + 0x1d9c, // ᶜ + 0x1da0, // ᶠ + 0x1da5, // ᶥ + 0x1da6, // ᶦ + 0x1dab, // ᶫ + 0x1db0, // ᶰ + 0x1db8, // ᶸ + 0x1dbb, // ᶻ + 0x1dbf, // ᶿ + 0x2032, // ′ + 0x2033, // ″ + 0x2034, // ‴ + 0x2035, // ‵ + 0x2036, // ‶ + 0x2037, // ‷ + 0x2057, // ⁗ + 0x2070, // ⁰ + 0x2071, // ⁱ + 0x2074, // ⁴ + 0x2075, // ⁵ + 0x2076, // ⁶ + 0x2077, // ⁷ + 0x2078, // ⁸ + 0x2079, // ⁹ + 0x207a, // ⁺ + 0x207b, // ⁻ + 0x207c, // ⁼ + 0x207d, // ⁽ + 0x207e, // ⁾ + 0x207f, // ⁿ + 0x2080, // ₀ + 0x2081, // ₁ + 0x2082, // ₂ + 0x2083, // ₃ + 0x2084, // ₄ + 0x2085, // ₅ + 0x2086, // ₆ + 0x2087, // ₇ + 0x2088, // ₈ + 0x2089, // ₉ + 0x208a, // ₊ + 0x208b, // ₋ + 0x208c, // ₌ + 0x208d, // ₍ + 0x208e, // ₎ + 0x2090, // ₐ + 0x2091, // ₑ + 0x2092, // ₒ + 0x2093, // ₓ + 0x2095, // ₕ + 0x2096, // ₖ + 0x2097, // ₗ + 0x2098, // ₘ + 0x2099, // ₙ + 0x209a, // ₚ + 0x209b, // ₛ + 0x209c, // ₜ + 0x2c7c, // ⱼ + 0x2c7d, // ⱽ + 0xa71b, // ꜛ + 0xa71c, // ꜜ + 0xa71d // ꜝ +}; +static const size_t opsuffs_len = sizeof(opsuffs) / (sizeof(uint32_t)); + +// keep the same function name to be easy to find again +static bool jl_op_suffix_char(uint32_t wc) { + if (wc < 0xA1 || wc > 0x10ffff) { + return false; + } + const CharacterCategory cat = CategoriseCharacter((int) wc); + if (cat == ccMn || cat == ccMc || + cat == ccMe) { + return true; + } + + for (size_t i = 0; i < opsuffs_len; ++i) { + if (wc == opsuffs[i]) { + return true; + } + } + return false; +} + +// keep the same function name to be easy to find again +static bool never_id_char(uint32_t wc) { + const CharacterCategory cat = CategoriseCharacter((int) wc); + return ( + // spaces and control characters: + (cat >= ccZs && cat <= ccCs) || + + // ASCII and Latin1 non-connector punctuation + (wc < 0xff && + cat >= ccPd && cat <= ccPo) || + + wc == '`' || + + // mathematical brackets + (wc >= 0x27e6 && wc <= 0x27ef) || + // angle, corner, and lenticular brackets + (wc >= 0x3008 && wc <= 0x3011) || + // tortoise shell, square, and more lenticular brackets + (wc >= 0x3014 && wc <= 0x301b) || + // fullwidth parens + (wc == 0xff08 || wc == 0xff09) || + // fullwidth square brackets + (wc == 0xff3b || wc == 0xff3d)); +} + + +static bool IsOperatorFirstCharacter (int ch) { + if (IsASCII(ch)) { + if (IsJuliaOperator(ch) || + ch == '!' || ch == '?' || + ch == ':' || ch == ';' || + ch == ',' || ch == '.' ) { + return true; + }else { + return false; + } + } else if (is_wc_cat_id_start((uint32_t) ch)) { + return false; + } else if (IsJuliaUnaryOperator(ch) || + ! never_id_char((uint32_t) ch)) { + return true; + } + return false; +} + +static bool IsOperatorCharacter (int ch) { + if (IsOperatorFirstCharacter(ch) || + (!IsASCII(ch) && jl_op_suffix_char((uint32_t) ch)) ) { + return true; + } + return false; +} + +static bool CheckBoundsIndexing(char *str) { + if (strcmp("begin", str) == 0 || strcmp("end", str) == 0 ) { + return true; + } + return false; +} + +static int CheckKeywordFoldPoint(char *str) { + if (strcmp ("if", str) == 0 || + strcmp ("for", str) == 0 || + strcmp ("while", str) == 0 || + strcmp ("try", str) == 0 || + strcmp ("do", str) == 0 || + strcmp ("begin", str) == 0 || + strcmp ("let", str) == 0 || + strcmp ("baremodule", str) == 0 || + strcmp ("quote", str) == 0 || + strcmp ("module", str) == 0 || + strcmp ("struct", str) == 0 || + strcmp ("type", str) == 0 || + strcmp ("macro", str) == 0 || + strcmp ("function", str) == 0) { + return 1; + } + if (strcmp("end", str) == 0) { + return -1; + } + return 0; +} + + +static bool IsTripleStringState(LexAccessor &styler, Sci_Position i) { + char ch = styler.SafeGetCharAt(i, 0); + char chNext = styler.SafeGetCharAt(i + 1, 0); + char chNextNext = styler.SafeGetCharAt(i + 2, 0); + + if (ch == '\"' && chNext == '\"' && chNextNext == '\"') { + return true; + } + return false; +} + +static bool IsNumberExpon(int ch, int base) { + if ((base == 10 && (ch == 'e' || ch == 'E' || ch == 'f')) || + (base == 16 && (ch == 'p' || ch == 'P'))) { + return true; + } + return false; +} + +/* Scans a sequence of digits, returning true if it found any. */ +static bool ScanDigits(StyleContext& sc, int base, bool allow_sep) { + bool found = false; + for (;;) { + if (IsADigit(sc.chNext, base) || (allow_sep && sc.chNext == '_')) { + found = true; + sc.Forward(); + } else { + break; + } + } + return found; +} + +static inline bool ScanNHexas(StyleContext &sc, int max) { + int n = 0; + bool error = false; + + sc.Forward(); + if (!IsADigit(sc.ch, 16)) { + error = true; + } else { + while (IsADigit(sc.ch, 16) && n < max) { + sc.Forward(); + n++; + } + } + return error; +} + +static void resumeCharacter(StyleContext &sc, bool lexerror) { + bool error = false; + + // ''' case + if (sc.chPrev == '\'' && sc.ch == '\'' && sc.chNext == '\'') { + sc.Forward(); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + return; + } else if (lexerror && sc.chPrev == '\'' && sc.ch == '\'') { + sc.ChangeState(SCE_JULIA_LEXERROR); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + + // Escape characters + } else if (sc.ch == '\\') { + sc.Forward(); + if (sc.ch == '\'' || sc.ch == '\\' ) { + sc.Forward(); + } else if (sc.ch == 'n' || sc.ch == 't' || sc.ch == 'a' || + sc.ch == 'b' || sc.ch == 'e' || sc.ch == 'f' || + sc.ch == 'r' || sc.ch == 'v' ) { + sc.Forward(); + } else if (sc.ch == 'x') { + error |= ScanNHexas(sc, 2); + } else if (sc.ch == 'u') { + error |= ScanNHexas(sc, 4); + } else if (sc.ch == 'U') { + error |= ScanNHexas(sc, 8); + } else if (IsADigit(sc.ch, 8)) { + int n = 1; + int max = 3; + sc.Forward(); + while (IsADigit(sc.ch, 8) && n < max) { + sc.Forward(); + n++; + } + } + + if (lexerror) { + if (sc.ch != '\'') { + error = true; + while (sc.ch != '\'' && sc.ch != EOF && + sc.ch != '\r' && sc.ch != '\n') { + sc.Forward(); + } + } + + if (error) { + sc.ChangeState(SCE_JULIA_LEXERROR); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } + } + } else if (lexerror) { + if (sc.ch < 0x20 || sc.ch > 0x10ffff) { + error = true; + } else { + // single character + sc.Forward(); + + if (sc.ch != '\'') { + error = true; + while (sc.ch != '\'' && sc.ch != EOF && + sc.ch != '\r' && sc.ch != '\n') { + sc.Forward(); + } + } + } + + if (error) { + sc.ChangeState(SCE_JULIA_LEXERROR); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } + } + + // closing quote + if (sc.ch == '\'') { + if (sc.chNext == '\'') { + sc.Forward(); + } else { + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } + } +} + +static inline bool IsACharacter(StyleContext &sc) { + return (sc.chPrev == '\'' && sc.chNext == '\''); +} + +static void ScanParenInterpolation(StyleContext &sc) { + // TODO: no syntax highlighting inside a string interpolation + + // Level of nested parenthesis + int interp_level = 0; + + // If true, it is inside a string and parenthesis are not counted. + bool allow_paren_string = false; + + + // check for end of states + for (; sc.More(); sc.Forward()) { + // TODO: check corner cases for nested string interpolation + // TODO: check corner cases with Command inside interpolation + + if ( sc.ch == '\"' && sc.chPrev != '\\') { + // Toggle the string environment (parenthesis are not counted inside a string) + allow_paren_string = !allow_paren_string; + } else if ( !allow_paren_string ) { + if ( sc.ch == '(' && !IsACharacter(sc) ) { + interp_level ++; + } else if ( sc.ch == ')' && !IsACharacter(sc) && interp_level > 0 ) { + interp_level --; + if (interp_level == 0) { + // Exit interpolation + return; + } + } + } + } +} + +/* + * Resume parsing a String or Command, bounded by the `quote` character (\" or \`) + * The `triple` argument specifies if it is a triple-quote String or Command. + * Interpolation is detected (with `$`), and parsed if `allow_interp` is true. + */ +static void resumeStringLike(StyleContext &sc, int quote, bool triple, bool allow_interp, bool full_highlight) { + int stylePrev = sc.state; + bool checkcurrent = false; + + // Escape characters + if (sc.ch == '\\') { + if (sc.chNext == quote || sc.chNext == '\\' || sc.chNext == '$') { + sc.Forward(); + } + } else if (allow_interp && sc.ch == '$') { + // If the interpolation is only of a variable, do not change state + if (sc.chNext == '(') { + if (full_highlight) { + sc.SetState(SCE_JULIA_STRINGINTERP); + } else { + sc.ForwardSetState(SCE_JULIA_STRINGINTERP); + } + ScanParenInterpolation(sc); + sc.ForwardSetState(stylePrev); + + checkcurrent = true; + + } else if (full_highlight && IsIdentifierFirstCharacter(sc.chNext)) { + sc.SetState(SCE_JULIA_STRINGINTERP); + sc.Forward(); + sc.Forward(); + for (; sc.More(); sc.Forward()) { + if (! IsIdentifierCharacter(sc.ch)) { + break; + } + } + sc.SetState(stylePrev); + + checkcurrent = true; + } + + if (checkcurrent) { + // Check that the current character is not a special char, + // otherwise it will be skipped + resumeStringLike(sc, quote, triple, allow_interp, full_highlight); + } + + } else if (sc.ch == quote) { + if (triple) { + if (sc.chNext == quote && sc.GetRelativeCharacter(2) == quote) { + // Move to the end of the triple quotes + Sci_PositionU nextIndex = sc.currentPos + 2; + while (nextIndex > sc.currentPos && sc.More()) { + sc.Forward(); + } + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } + } else { + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } + } +} + +static void resumeCommand(StyleContext &sc, bool triple, bool allow_interp) { + return resumeStringLike(sc, '`', triple, allow_interp, true); +} + +static void resumeString(StyleContext &sc, bool triple, bool allow_interp) { + return resumeStringLike(sc, '"', triple, allow_interp, true); +} + +static void resumeNumber (StyleContext &sc, int base, bool &with_dot, bool lexerror) { + if (IsNumberExpon(sc.ch, base)) { + if (isdigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-') { + sc.Forward(); + // Capture all digits + ScanDigits(sc, 10, false); + sc.Forward(); + } + sc.SetState(SCE_JULIA_DEFAULT); + } else if (sc.ch == '.' && sc.chNext == '.') { + // Interval operator `..` + sc.SetState(SCE_JULIA_OPERATOR); + sc.Forward(); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } else if (sc.ch == '.' && !with_dot) { + with_dot = true; + ScanDigits(sc, base, true); + } else if (IsADigit(sc.ch, base) || sc.ch == '_') { + ScanDigits(sc, base, true); + } else if (isdigit(sc.ch) && !IsADigit(sc.ch, base)) { + if (lexerror) { + sc.ChangeState(SCE_JULIA_LEXERROR); + } + ScanDigits(sc, 10, false); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } else { + sc.SetState(SCE_JULIA_DEFAULT); + } +} + +static void resumeOperator (StyleContext &sc) { + if (sc.chNext == ':' && (sc.ch == ':' || sc.ch == '<' || + (sc.ch == '>' && (sc.chPrev != '-' && sc.chPrev != '=')))) { + // Case `:a=>:b` + sc.Forward(); + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } else if (sc.ch == ':') { + // Case `foo(:baz,:baz)` or `:one+:two` + // Let the default case switch decide if it is a symbol + sc.SetState(SCE_JULIA_DEFAULT); + } else if (sc.ch == '\'') { + sc.SetState(SCE_JULIA_DEFAULT); + } else if ((sc.ch == '.' && sc.chPrev != '.') || IsIdentifierFirstCharacter(sc.ch) || + (! (sc.chPrev == '.' && IsOperatorFirstCharacter(sc.ch)) && + ! IsOperatorCharacter(sc.ch)) ) { + sc.SetState(SCE_JULIA_DEFAULT); + } +} + +void SCI_METHOD LexerJulia::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { + PropSetSimple props; + Accessor styler(pAccess, &props); + Sci_Position pos = startPos; + + styler.StartAt(pos); + styler.StartSegment(pos); + + // boolean for when the ' is allowed to be transpose vs the start/end + // of a string + bool transpose = false; + + // boolean for when the docstring has triple quotes + bool istripledocstring = false; + + // boolean for if the string is a raw string, no interpolation + bool israwstring = false; + + // count of brackets as boolean for when end could be an operator not a keyword + int indexing_level = 0; + + // level of nested list comprehension + int list_comprehension = 0; + + // boolean for triple backtick + bool triple_backtick = false; + + // base for parsing number + int base = 10; + + // number has a float dot ? + bool with_dot = false; + + // use the line state of each line to store the block comment depth + Sci_Position curLine = styler.GetLine(startPos); + int commentDepth = curLine > 0 ? styler.GetLineState(curLine-1) : 0; + + + StyleContext sc(startPos, length, initStyle, styler); + + for (; sc.More(); sc.Forward()) { + + if (sc.atLineStart) { + // set the line state to the current commentDepth + curLine = styler.GetLine(sc.currentPos); + styler.SetLineState(curLine, commentDepth); + } + + //// check for end of states + switch (sc.state) { + case SCE_JULIA_BRACKET: + sc.SetState(SCE_JULIA_DEFAULT); + break; + case SCE_JULIA_OPERATOR: + resumeOperator(sc); + break; + case SCE_JULIA_TYPEANNOT: + // Highlight the next identifier, if option is set + if (options.highlightTypeannotation) { + if (! IsIdentifierCharacter(sc.ch)) { + sc.SetState(SCE_JULIA_DEFAULT); + } + } else { + sc.SetState(SCE_JULIA_DEFAULT); + } + break; + case SCE_JULIA_IDENTIFIER: + // String literal + if (sc.ch == '\"') { + // Check if it is a raw string literal + char s[MAX_JULIA_IDENT_CHARS + 1]; + sc.GetCurrent(s, sizeof(s)); + + // Check if the string is in the Raw String Literals list + if (keywords[NUM_JULIA_KEYWORD_LISTS - 1].InList(s)) { + //if (IsRawStringLiteral(s)) { + israwstring = true; + } else { + israwstring = false; + } + + sc.ChangeState(SCE_JULIA_STRINGLITERAL); + sc.SetState(SCE_JULIA_DEFAULT); + + } else if (sc.ch == '`') { + sc.ChangeState(SCE_JULIA_COMMANDLITERAL); + sc.SetState(SCE_JULIA_DEFAULT); + + // Continue if the character is an identifier character + } else if (! IsIdentifierCharacter(sc.ch)) { + char s[MAX_JULIA_IDENT_CHARS + 1]; + sc.GetCurrent(s, sizeof(s)); + + // Treat the keywords differently if we are indexing or not + if ( indexing_level > 0 && CheckBoundsIndexing(s)) { + // Inside [], (), `begin` and `end` are numbers not block keywords + sc.ChangeState(SCE_JULIA_NUMBER); + transpose = false; + + } else { + // Ignore the last index of NUM_JULIA_KEYWORD_LISTS that is + // used for Raw string literals. + for (int ii = 0; ii < NUM_JULIA_KEYWORD_LISTS - 1; ii++) { + if (keywords[ii].InList(s)) { + sc.ChangeState(SCE_JULIA_KEYWORD1 + ii); + transpose = false; + break; + } + } + } + sc.SetState(SCE_JULIA_DEFAULT); + + // TODO: recognize begin-end blocks inside list comprehension + // b = [(begin n%2; n*2 end) for n in 1:10] + // TODO: recognize better comprehension for-if to avoid problem with code-folding + // c = [(if isempty(a); missing else first(b) end) for (a, b) in zip(l1, l2)] + } + break; + case SCE_JULIA_NUMBER: + resumeNumber(sc, base, with_dot, options.highlightLexerror); + break; + case SCE_JULIA_CHAR: + resumeCharacter(sc, options.highlightLexerror); + break; + case SCE_JULIA_DOCSTRING: + resumeString(sc, true, !israwstring); + if (sc.state == SCE_JULIA_DEFAULT && israwstring) { + israwstring = false; + } + break; + case SCE_JULIA_STRING: + resumeString(sc, false, !israwstring); + if (sc.state == SCE_JULIA_DEFAULT && israwstring) { + israwstring = false; + } + break; + case SCE_JULIA_COMMAND: + resumeCommand(sc, triple_backtick, true); + break; + case SCE_JULIA_MACRO: + if (isspace(sc.ch) || ! IsIdentifierCharacter(sc.ch)) { + sc.SetState(SCE_JULIA_DEFAULT); + } + break; + case SCE_JULIA_SYMBOL: + if (! IsIdentifierCharacter(sc.ch)) { + sc.SetState(SCE_JULIA_DEFAULT); + } + break; + case SCE_JULIA_COMMENT: + if( commentDepth > 0 ) { + // end or start of a nested a block comment + if ( sc.ch == '=' && sc.chNext == '#') { + commentDepth --; + curLine = styler.GetLine(sc.currentPos); + styler.SetLineState(curLine, commentDepth); + sc.Forward(); + + if (commentDepth == 0) { + sc.ForwardSetState(SCE_JULIA_DEFAULT); + } + } else if( sc.ch == '#' && sc.chNext == '=') { + commentDepth ++; + curLine = styler.GetLine(sc.currentPos); + styler.SetLineState(curLine, commentDepth); + sc.Forward(); + } + } else { + // single line comment + if (sc.atLineEnd || sc.ch == '\r' || sc.ch == '\n') { + sc.SetState(SCE_JULIA_DEFAULT); + transpose = false; + } + } + break; + } + + // check start of a new state + if (sc.state == SCE_JULIA_DEFAULT) { + if (sc.ch == '#') { + // increment depth if we are a block comment + if(sc.chNext == '=') { + commentDepth ++; + } + curLine = styler.GetLine(sc.currentPos); + styler.SetLineState(curLine, commentDepth); + sc.SetState(SCE_JULIA_COMMENT); + } else if (sc.ch == '!') { + sc.SetState(SCE_JULIA_OPERATOR); + } else if (sc.ch == '\'') { + if (transpose) { + sc.SetState(SCE_JULIA_OPERATOR); + } else { + sc.SetState(SCE_JULIA_CHAR); + } + } else if (sc.ch == '\"') { + istripledocstring = (sc.chNext == '\"' && sc.GetRelativeCharacter(2) == '\"'); + if (istripledocstring) { + sc.SetState(SCE_JULIA_DOCSTRING); + // Move to the end of the triple quotes + Sci_PositionU nextIndex = sc.currentPos + 2; + while (nextIndex > sc.currentPos && sc.More()) { + sc.Forward(); + } + } else { + sc.SetState(SCE_JULIA_STRING); + } + } else if (sc.ch == '`') { + triple_backtick = (sc.chNext == '`' && sc.GetRelativeCharacter(2) == '`'); + sc.SetState(SCE_JULIA_COMMAND); + if (triple_backtick) { + // Move to the end of the triple backticks + Sci_PositionU nextIndex = sc.currentPos + 2; + while (nextIndex > sc.currentPos && sc.More()) { + sc.Forward(); + } + } + } else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) { + base = 10; + with_dot = false; + transpose = true; + sc.SetState(SCE_JULIA_NUMBER); + if (sc.ch == '0') { + if (sc.chNext == 'x') { + sc.Forward(); + base = 16; + if (sc.chNext == '.') { + sc.Forward(); + with_dot = true; + } + } else if (sc.chNext == 'o') { + sc.Forward(); + base = 8; + } else if (sc.chNext == 'b') { + sc.Forward(); + base = 2; + } + } else if (sc.ch == '.') { + with_dot = true; + } + } else if (IsIdentifierFirstCharacter(sc.ch)) { + sc.SetState(SCE_JULIA_IDENTIFIER); + transpose = true; + } else if (sc.ch == '@') { + sc.SetState(SCE_JULIA_MACRO); + transpose = false; + + // Several parsing of operators, should keep the order of `if` blocks + } else if ((sc.ch == ':' || sc.ch == '<' || sc.ch == '>') && sc.chNext == ':') { + sc.SetState(SCE_JULIA_TYPEANNOT); + sc.Forward(); + // Highlight the next identifier, if option is set + if (options.highlightTypeannotation) { + if (IsIdentifierFirstCharacter(sc.chNext)) { + sc.Forward(); + } + } + } else if (sc.ch == ':') { + // TODO: improve detection of range + // should be solved with begin-end parsing + // `push!(arr, s1 :s2)` and `a[begin :end] + if (IsIdentifierFirstCharacter(sc.chNext) && + ! IsIdentifierCharacter(sc.chPrev) && + sc.chPrev != ')' && sc.chPrev != ']' ) { + sc.SetState(SCE_JULIA_SYMBOL); + } else { + sc.SetState(SCE_JULIA_OPERATOR); + } + } else if (IsJuliaParen(sc.ch)) { + if (sc.ch == '[') { + list_comprehension ++; + indexing_level ++; + } else if (sc.ch == ']' && (indexing_level > 0)) { + list_comprehension --; + indexing_level --; + } else if (sc.ch == '(') { + list_comprehension ++; + } else if (sc.ch == ')' && (list_comprehension > 0)) { + list_comprehension --; + } + + if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') { + transpose = true; + } else { + transpose = false; + } + sc.SetState(SCE_JULIA_BRACKET); + } else if (IsOperatorFirstCharacter(sc.ch)) { + transpose = false; + sc.SetState(SCE_JULIA_OPERATOR); + } else { + transpose = false; + } + } + } + sc.Complete(); +} + +void SCI_METHOD LexerJulia::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) { + + if (!options.fold) + return; + + LexAccessor styler(pAccess); + + // level of nested brackets + int indexing_level = 0; + // level of nested parenthesis or brackets + int list_comprehension = 0; + // isdocstring + bool isdocstring = false; + + Sci_PositionU endPos = startPos + length; + int visibleChars = 0; + Sci_Position lineCurrent = styler.GetLine(startPos); + int levelCurrent = SC_FOLDLEVELBASE; + if (lineCurrent > 0) + levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; + Sci_PositionU lineStartNext = styler.LineStart(lineCurrent+1); + int levelNext = levelCurrent; + char chNext = styler[startPos]; + int styleNext = styler.StyleAt(startPos); + int style = initStyle; + char word[100]; + int wordlen = 0; + for (Sci_PositionU i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + style = styleNext; + styleNext = styler.StyleAt(i + 1); + bool atEOL = i == (lineStartNext-1); + + // a start/end of comment block + if (options.foldComment && style == SCE_JULIA_COMMENT) { + // start of block comment + if (ch == '#' && chNext == '=') { + levelNext ++; + } + // end of block comment + if (ch == '=' && chNext == '#' && levelNext > 0) { + levelNext --; + } + } + + // list comprehension allow `for`/`if` without `end` + if (style == SCE_JULIA_BRACKET) { + if (ch == '[') { + list_comprehension ++; + indexing_level ++; + levelNext ++; + } else if (ch == ']') { + list_comprehension --; + indexing_level --; + levelNext --; + } else if (ch == '(') { + list_comprehension ++; + levelNext ++; + } else if (ch == ')') { + list_comprehension --; + levelNext --; + } + // check non-negative + if (indexing_level < 0) { + indexing_level = 0; + } + if (list_comprehension < 0) { + list_comprehension = 0; + } + } + + // keyword + if (style == SCE_JULIA_KEYWORD1) { + word[wordlen++] = static_cast(ch); + if (wordlen == 100) { // prevent overflow + word[0] = '\0'; + wordlen = 1; + } + if (styleNext != SCE_JULIA_KEYWORD1) { + word[wordlen] = '\0'; + wordlen = 0; + if (list_comprehension <= 0 && indexing_level <= 0) { + levelNext += CheckKeywordFoldPoint(word); + } + } + + } + + // Docstring + if (options.foldDocstring && style == SCE_JULIA_DOCSTRING) { + if (visibleChars==0 && IsTripleStringState(styler, i) && styler.StyleAt(i + 3) == SCE_JULIA_DOCSTRING ) { + levelNext ++; + isdocstring = true; + } else if (isdocstring && styleNext != SCE_JULIA_DOCSTRING && levelNext > 0) { + isdocstring = false; + levelNext --; + } + } + + // check non-negative level + if (levelNext < 0) { + levelNext = 0; + } + + if (!IsASpace(ch)) + visibleChars++; + if (atEOL || (i == endPos-1)) { + int levelUse = levelCurrent; + int lev = levelUse | levelNext << 16; + if (visibleChars == 0 && options.foldCompact) + lev |= SC_FOLDLEVELWHITEFLAG; + if (levelUse < levelNext) + lev |= SC_FOLDLEVELHEADERFLAG; + if (lev != styler.LevelAt(lineCurrent)) { + styler.SetLevel(lineCurrent, lev); + } + lineCurrent++; + lineStartNext = styler.LineStart(lineCurrent+1); + levelCurrent = levelNext; + if (atEOL && (i == static_cast(styler.Length() - 1))) { + // There is an empty line at end of file so give it same level and empty + styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG); + } + visibleChars = 0; + } + } +} + +LexerModule lmJulia(SCLEX_JULIA, LexerJulia::LexerFactoryJulia, "julia", juliaWordLists); diff --git a/lexilla/lexers/LexLua.cxx b/lexilla/lexers/LexLua.cxx index 5017a322e..9c0385c19 100644 --- a/lexilla/lexers/LexLua.cxx +++ b/lexilla/lexers/LexLua.cxx @@ -69,17 +69,15 @@ static void ColouriseLuaDoc( CharacterSet setEscapeSkip(CharacterSet::setNone, "\"'\\"); Sci_Position currentLine = styler.GetLine(startPos); - // Initialize long string [[ ... ]] or block comment --[[ ... ]] nesting level, + // Initialize long string [[ ... ]] or block comment --[[ ... ]], // if we are inside such a string. Block comment was introduced in Lua 5.0, // blocks with separators [=[ ... ]=] in Lua 5.1. // Continuation of a string (\z whitespace escaping) is controlled by stringWs. - int nestLevel = 0; int sepCount = 0; int stringWs = 0; if (initStyle == SCE_LUA_LITERALSTRING || initStyle == SCE_LUA_COMMENT || initStyle == SCE_LUA_STRING || initStyle == SCE_LUA_CHARACTER) { const int lineState = styler.GetLineState(currentLine - 1); - nestLevel = lineState >> 9; sepCount = lineState & 0xFF; stringWs = lineState & 0x100; } @@ -110,7 +108,7 @@ static void ColouriseLuaDoc( case SCE_LUA_STRING: case SCE_LUA_CHARACTER: // Inside a literal string, block comment or string, we set the line state - styler.SetLineState(currentLine, (nestLevel << 9) | stringWs | sepCount); + styler.SetLineState(currentLine, stringWs | sepCount); break; default: // Reset the line state @@ -254,25 +252,11 @@ static void ColouriseLuaDoc( sc.ChangeState(SCE_LUA_STRINGEOL); sc.ForwardSetState(SCE_LUA_DEFAULT); } - } else if (sc.state == SCE_LUA_LITERALSTRING || sc.state == SCE_LUA_COMMENT) { - if (sc.ch == '[') { - const int sep = LongDelimCheck(sc); - if (sep == 1 && sepCount == 1) { // [[-only allowed to nest - nestLevel++; - sc.Forward(); - } - } else if (sc.ch == ']') { - int sep = LongDelimCheck(sc); - if (sep == 1 && sepCount == 1) { // un-nest with ]]-only - nestLevel--; - sc.Forward(); - if (nestLevel == 0) { - sc.ForwardSetState(SCE_LUA_DEFAULT); - } - } else if (sep > 1 && sep == sepCount) { // ]=]-style delim - sc.Forward(sep); - sc.ForwardSetState(SCE_LUA_DEFAULT); - } + } else if (sc.ch == ']' && (sc.state == SCE_LUA_LITERALSTRING || sc.state == SCE_LUA_COMMENT)) { + const int sep = LongDelimCheck(sc); + if (sep == sepCount) { // ]=]-style delim + sc.Forward(sep); + sc.ForwardSetState(SCE_LUA_DEFAULT); } } @@ -356,7 +340,6 @@ static void ColouriseLuaDoc( if (sepCount == 0) { sc.SetState(SCE_LUA_OPERATOR); } else { - nestLevel = 1; sc.SetState(SCE_LUA_LITERALSTRING); sc.Forward(sepCount); } @@ -366,7 +349,6 @@ static void ColouriseLuaDoc( sc.Forward(2); sepCount = LongDelimCheck(sc); if (sepCount > 0) { - nestLevel = 1; sc.ChangeState(SCE_LUA_COMMENT); sc.Forward(sepCount); } @@ -384,7 +366,7 @@ static void ColouriseLuaDoc( sc.Complete(); } -static void FoldLuaDoc(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[], +static void FoldLuaDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler) { const Sci_PositionU lengthDoc = startPos + length; int visibleChars = 0; @@ -393,12 +375,14 @@ static void FoldLuaDoc(Sci_PositionU startPos, Sci_Position length, int /* initS int levelCurrent = levelPrev; char chNext = styler[startPos]; const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + int style = initStyle; int styleNext = styler.StyleAt(startPos); for (Sci_PositionU i = startPos; i < lengthDoc; i++) { const char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); - const int style = styleNext; + const int stylePrev = style; + style = styleNext; styleNext = styler.StyleAt(i + 1); const bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_LUA_WORD) { @@ -426,9 +410,9 @@ static void FoldLuaDoc(Sci_PositionU startPos, Sci_Position length, int /* initS levelCurrent--; } } else if (style == SCE_LUA_LITERALSTRING || style == SCE_LUA_COMMENT) { - if (ch == '[') { + if (stylePrev != style) { levelCurrent++; - } else if (ch == ']') { + } else if (styleNext != style) { levelCurrent--; } } diff --git a/lexilla/lexers/LexMarkdown.cxx b/lexilla/lexers/LexMarkdown.cxx index db5563c25..90a9cfcec 100644 --- a/lexilla/lexers/LexMarkdown.cxx +++ b/lexilla/lexers/LexMarkdown.cxx @@ -76,38 +76,25 @@ static bool FollowToLineEnd(const int ch, const int state, const Sci_PositionU e // Set the state on text section from current to length characters, // then set the rest until the newline to default, except for any characters matching token - -#if 0 -constexpr bool IsHdrToken(const int ch, const int tok) noexcept { - return ((ch == tok) || (ch == ' ') || (ch == '\n') || (ch == '\r')); -} - static void SetStateAndZoom(const int state, const Sci_Position length, const int token, StyleContext &sc) { sc.SetState(state); sc.Forward(length); - bool tokenState = true; - while (sc.More() && !sc.atLineStart) { - if (IsHdrToken(sc.ch, token) && !tokenState) { + sc.SetState(SCE_MARKDOWN_DEFAULT); + sc.Forward(); + bool started = false; + while (sc.More() && !IsNewline(sc.ch)) { + if (sc.ch == token && !started) { sc.SetState(state); - tokenState = true; + started = true; } - else if (!IsHdrToken(sc.ch, token) && tokenState) { - sc.SetState(SCE_MARKDOWN_HDRTEXT); - tokenState = false; + else if (sc.ch != token) { + sc.SetState(SCE_MARKDOWN_DEFAULT); + started = false; } sc.Forward(); } sc.SetState(SCE_MARKDOWN_LINE_BEGIN); } -#endif - -static void SetStateAndZoom(const int state, const Sci_Position length, const int token, StyleContext &sc) { - (void)(token); - sc.SetState(state); - sc.Forward(length); - while (sc.More() && !sc.atLineStart) { sc.Forward(); } - sc.SetState(SCE_MARKDOWN_LINE_BEGIN); -} // Does the previous line have more than spaces and tabs? static bool HasPrevLineContent(StyleContext &sc) { @@ -116,9 +103,10 @@ static bool HasPrevLineContent(StyleContext &sc) { while ((--i + (Sci_Position)sc.currentPos) >= 0 && !IsNewline(sc.GetRelative(i))) ; while ((--i + (Sci_Position)sc.currentPos) >= 0) { - if (IsNewline(sc.GetRelative(i))) + const int ch = sc.GetRelative(i); + if (ch == '\n') break; - if (!IsASpaceOrTab(sc.GetRelative(i))) + if (!((ch == '\r' || IsASpaceOrTab(ch)))) return true; } return false; @@ -252,36 +240,24 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int } else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) { // Header - if (sc.Match("######")) { - SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc); - freezeCursor = true; - } - else if (sc.Match("#####")) { - SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc); - freezeCursor = true; - } - else if (sc.Match("####")) { - SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); - freezeCursor = true; - } - else if (sc.Match("###")) { - SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc); - freezeCursor = true; - } - else if (sc.Match("##")) { - SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc); - freezeCursor = true; - } + if (sc.Match("######")) + SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc); + else if (sc.Match("#####")) + SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc); + else if (sc.Match("####")) + SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); + else if (sc.Match("###")) + SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc); + else if (sc.Match("##")) + SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc); else if (sc.Match("#")) { // Catch the special case of an unordered list if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { precharCount = 0; sc.SetState(SCE_MARKDOWN_PRECHAR); } - else { - SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc); - freezeCursor = true; - } + else + SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc); } // Code block else if (sc.Match("~~~")) { @@ -313,12 +289,12 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int } // The header lasts until the newline - else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 || - sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 || - sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) { - if (IsNewline(sc.ch)) - sc.SetState(SCE_MARKDOWN_LINE_BEGIN); - } + else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 || + sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 || + sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) { + if (IsNewline(sc.ch)) + sc.SetState(SCE_MARKDOWN_LINE_BEGIN); + } // New state only within the initial whitespace if (sc.state == SCE_MARKDOWN_PRECHAR) { @@ -366,21 +342,22 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int // Any link if (sc.state == SCE_MARKDOWN_LINK) { if (sc.Match("](") && sc.GetRelative(-1) != '\\') { - sc.Forward(); + sc.Forward(2); isLinkNameDetecting = true; } else if (sc.Match("]:") && sc.GetRelative(-1) != '\\') { - sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); + sc.Forward(2); + sc.SetState(SCE_MARKDOWN_DEFAULT); } else if (!isLinkNameDetecting && sc.ch == ']' && sc.GetRelative(-1) != '\\') { - sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); - freezeCursor = true; + sc.Forward(); + sc.SetState(SCE_MARKDOWN_DEFAULT); } else if (isLinkNameDetecting && sc.ch == ')' && sc.GetRelative(-1) != '\\') { - sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); - freezeCursor = true; - isLinkNameDetecting = false; - } + sc.Forward(); + sc.SetState(SCE_MARKDOWN_DEFAULT); + isLinkNameDetecting = false; + } } // New state anywhere in doc @@ -392,7 +369,7 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int // Links and Images if (sc.Match("![")) { sc.SetState(SCE_MARKDOWN_LINK); - sc.Forward(); + sc.Forward(1); } else if (sc.ch == '[' && sc.GetRelative(-1) != '\\') { sc.SetState(SCE_MARKDOWN_LINK); @@ -409,7 +386,7 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int else if (sc.Match("**") && sc.GetRelative(2) != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_STRONG1); sc.Forward(); - } + } else if (sc.Match("__") && sc.GetRelative(2) != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_STRONG2); sc.Forward(); @@ -431,12 +408,10 @@ static void ColorizeMarkdownDoc(Sci_PositionU startPos, Sci_Position length, int sc.SetState(SCE_MARKDOWN_LINE_BEGIN); } } - // Advance if not holding back the cursor for this iteration. if (!freezeCursor) sc.Forward(); - else - freezeCursor = false; + freezeCursor = false; } sc.Complete(); } diff --git a/lexilla/scripts/LexFacer.py b/lexilla/scripts/LexFacer.py index e0153f92b..4b4f7dec2 100644 --- a/lexilla/scripts/LexFacer.py +++ b/lexilla/scripts/LexFacer.py @@ -9,8 +9,7 @@ import os, pathlib, sys sys.path.append(os.path.join("..", "..", "scintilla", "scripts")) import Face - -from FileGenerator import UpdateFile, Generate, Regenerate, UpdateLineInFile, lineEnd +import FileGenerator def printLexHFile(f): out = [] @@ -21,10 +20,10 @@ def printLexHFile(f): out.append("#define " + name + " " + v["Value"]) return out -def RegenerateAll(root, showMaxID): +def RegenerateAll(root, _showMaxID): f = Face.Face() f.ReadFromFile(root / "include/LexicalStyles.iface") - Regenerate(root / "include/SciLexer.h", "/* ", printLexHFile(f)) + FileGenerator.Regenerate(root / "include/SciLexer.h", "/* ", printLexHFile(f)) if __name__ == "__main__": RegenerateAll(pathlib.Path(__file__).resolve().parent.parent, True) diff --git a/lexilla/scripts/LexillaData.py b/lexilla/scripts/LexillaData.py index e2a07b12d..d76dd3866 100644 --- a/lexilla/scripts/LexillaData.py +++ b/lexilla/scripts/LexillaData.py @@ -173,7 +173,7 @@ def FindCredits(historyFile): credit = l[4:-5] if "") + urlplus, _bracket, end = rest.partition(">") name = end.split("<")[0] url = urlplus[1:-1] credit = title.strip() diff --git a/lexilla/src/Lexilla.cxx b/lexilla/src/Lexilla.cxx index 5874ed30f..3f763f205 100644 --- a/lexilla/src/Lexilla.cxx +++ b/lexilla/src/Lexilla.cxx @@ -48,6 +48,7 @@ extern LexerModule lmDiff; extern LexerModule lmHTML; extern LexerModule lmInno; extern LexerModule lmJSON; +extern LexerModule lmJulia; extern LexerModule lmKotlin; extern LexerModule lmLatex; extern LexerModule lmLua; @@ -112,6 +113,7 @@ void AddEachLexer() { &lmHTML, &lmInno, &lmJSON, + &lmJulia, &lmKotlin, &lmLatex, &lmLua, diff --git a/lexilla/src/Lexilla/Lexilla.xcodeproj/project.pbxproj b/lexilla/src/Lexilla/Lexilla.xcodeproj/project.pbxproj index a558e71e9..c0cf0f9fd 100644 --- a/lexilla/src/Lexilla/Lexilla.xcodeproj/project.pbxproj +++ b/lexilla/src/Lexilla/Lexilla.xcodeproj/project.pbxproj @@ -158,6 +158,7 @@ F6224FEE88B39060046EEBB0 /* LexerUtils.cxx in Sources */ = {isa = PBXBuildFile; fileRef = B70142AEAD02FCCC38C95437 /* LexerUtils.cxx */; }; 20734B2BAC0066B302C5F572 /* LexKotlin.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 4B244DD685C45BD626DFCBFA /* LexKotlin.cxx */; }; 173A4B628003CD6778153F13 /* LexTOML.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 8FE446A1AD4BC789488C9865 /* LexTOML.cxx */; }; + 98684028BA6245805B2034D1 /* LexJulia.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 9AA44B1D90573293F9570B5E /* LexJulia.cxx */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -314,6 +315,7 @@ B70142AEAD02FCCC38C95437 /* LexerUtils.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexerUtils.cxx; path = ../../lexers/LexerUtils.cxx; sourceTree = SOURCE_ROOT; }; 4B244DD685C45BD626DFCBFA /* LexKotlin.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexKotlin.cxx; path = ../../lexers/LexKotlin.cxx; sourceTree = SOURCE_ROOT; }; 8FE446A1AD4BC789488C9865 /* LexTOML.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexTOML.cxx; path = ../../lexers/LexTOML.cxx; sourceTree = SOURCE_ROOT; }; + 9AA44B1D90573293F9570B5E /* LexJulia.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexJulia.cxx; path = ../../lexers/LexJulia.cxx; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -413,6 +415,7 @@ 28BA72EA24E34D9300272C2D /* LexIndent.cxx */, 28BA730524E34D9400272C2D /* LexInno.cxx */, 28BA733024E34D9600272C2D /* LexJSON.cxx */, + 9AA44B1D90573293F9570B5E /* LexJulia.cxx */, 28BA731124E34D9500272C2D /* LexKix.cxx */, 4B244DD685C45BD626DFCBFA /* LexKotlin.cxx */, 28BA72F824E34D9300272C2D /* LexKVIrc.cxx */, @@ -736,6 +739,7 @@ F6224FEE88B39060046EEBB0 /* LexerUtils.cxx in Sources */, 20734B2BAC0066B302C5F572 /* LexKotlin.cxx in Sources */, 173A4B628003CD6778153F13 /* LexTOML.cxx in Sources */, + 98684028BA6245805B2034D1 /* LexJulia.cxx in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lexilla/src/deps.mak b/lexilla/src/deps.mak index 7c71ff364..0117c408f 100644 --- a/lexilla/src/deps.mak +++ b/lexilla/src/deps.mak @@ -277,6 +277,22 @@ LexInno.o: \ ../lexlib/StyleContext.h \ ../lexlib/CharacterSet.h \ ../lexlib/LexerModule.h +LexJulia.o: \ + ../lexers/LexJulia.cxx \ + ../../scintilla/include/ILexer.h \ + ../../scintilla/include/Sci_Position.h \ + ../../scintilla/include/Scintilla.h \ + ../include/SciLexer.h \ + ../lexlib/PropSetSimple.h \ + ../lexlib/WordList.h \ + ../lexlib/LexAccessor.h \ + ../lexlib/Accessor.h \ + ../lexlib/StyleContext.h \ + ../lexlib/CharacterSet.h \ + ../lexlib/CharacterCategory.h \ + ../lexlib/LexerModule.h \ + ../lexlib/OptionSet.h \ + ../lexlib/DefaultLexer.h LexLaTeX.o: \ ../lexers/LexLaTeX.cxx \ ../../scintilla/include/ILexer.h \ diff --git a/lexilla/src/lexilla.mak b/lexilla/src/lexilla.mak index c2ea2f36b..f3ed76304 100644 --- a/lexilla/src/lexilla.mak +++ b/lexilla/src/lexilla.mak @@ -27,17 +27,20 @@ SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.02 !ELSE SUBSYSTEM=-SUBSYSTEM:WINDOWS,5.01 !ENDIF -!ELSEIFDEF ARM64 +!ELSE +CETCOMPAT=-CETCOMPAT +!IFDEF ARM64 ADD_DEFINE=-D_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1 SUBSYSTEM=-SUBSYSTEM:WINDOWS,10.00 !ENDIF +!ENDIF CRTFLAGS=-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 -D_CRT_SECURE_NO_DEPRECATE=1 -D_SCL_SECURE_NO_WARNINGS=1 $(ADD_DEFINE) CXXFLAGS=-Zi -TP -MP -W4 -EHsc -std:c++17 $(CRTFLAGS) CXXDEBUG=-Od -MTd -DDEBUG CXXNDEBUG=-O1 -MT -DNDEBUG -GL NAME=-Fo -LDFLAGS=-OPT:REF -LTCG -IGNORE:4197 -DEBUG $(SUBSYSTEM) +LDFLAGS=-OPT:REF -LTCG -IGNORE:4197 -DEBUG $(SUBSYSTEM) $(CETCOMPAT) LDDEBUG= LIBS= NOLOGO=-nologo @@ -85,6 +88,7 @@ LEX_OBJS=\ $(DIR_O)\LexDiff.obj \ $(DIR_O)\LexHTML.obj \ $(DIR_O)\LexInno.obj \ + $(DIR_O)\LexJulia.obj \ $(DIR_O)\LexLaTeX.obj \ $(DIR_O)\LexLua.obj \ $(DIR_O)\LexMake.obj \ diff --git a/lexilla/src/nmdeps.mak b/lexilla/src/nmdeps.mak index 1e06bb45f..eedf90866 100644 --- a/lexilla/src/nmdeps.mak +++ b/lexilla/src/nmdeps.mak @@ -277,6 +277,22 @@ $(DIR_O)/LexInno.obj: \ ../lexlib/StyleContext.h \ ../lexlib/CharacterSet.h \ ../lexlib/LexerModule.h +$(DIR_O)/LexJulia.obj: \ + ../lexers/LexJulia.cxx \ + ../../scintilla/include/ILexer.h \ + ../../scintilla/include/Sci_Position.h \ + ../../scintilla/include/Scintilla.h \ + ../include/SciLexer.h \ + ../lexlib/PropSetSimple.h \ + ../lexlib/WordList.h \ + ../lexlib/LexAccessor.h \ + ../lexlib/Accessor.h \ + ../lexlib/StyleContext.h \ + ../lexlib/CharacterSet.h \ + ../lexlib/CharacterCategory.h \ + ../lexlib/LexerModule.h \ + ../lexlib/OptionSet.h \ + ../lexlib/DefaultLexer.h $(DIR_O)/LexLaTeX.obj: \ ../lexers/LexLaTeX.cxx \ ../../scintilla/include/ILexer.h \ diff --git a/minipath/minipath.vcxproj b/minipath/minipath.vcxproj index 40252bc2c..5272904ee 100644 --- a/minipath/minipath.vcxproj +++ b/minipath/minipath.vcxproj @@ -143,7 +143,7 @@ /MACHINE:I386 %(AdditionalOptions) shlwapi.lib;muiload.lib;psapi.lib;legacy_stdio_definitions.lib;%(AdditionalDependencies) true - true + DebugFull Windows Default diff --git a/res/Notepad3.exe.manifest.conf b/res/Notepad3.exe.manifest.conf index 58e467391..89db2d3d0 100644 --- a/res/Notepad3.exe.manifest.conf +++ b/res/Notepad3.exe.manifest.conf @@ -3,7 +3,7 @@ Notepad3 beta diff --git a/scintilla/Scintilla.vcxproj b/scintilla/Scintilla.vcxproj index dd46b0665..f239ae90d 100644 --- a/scintilla/Scintilla.vcxproj +++ b/scintilla/Scintilla.vcxproj @@ -169,7 +169,7 @@ include;src;../lexilla/inclide;../oniguruma/src;%(AdditionalIncludeDirectories) EnableFastChecks - EditAndContinue + ProgramDatabase true Disabled NotUsing @@ -183,7 +183,7 @@ Precise stdcpp17 - true + false false true stdc17 @@ -210,7 +210,7 @@ true Precise stdcpp17 - true + false false true diff --git a/src/DarkMode/DarkMode.cpp b/src/DarkMode/DarkMode.cpp index 6fe494635..d950b2057 100644 --- a/src/DarkMode/DarkMode.cpp +++ b/src/DarkMode/DarkMode.cpp @@ -73,7 +73,7 @@ constexpr bool CheckBuildNumber(DWORD buildNumber) case 19042: // Win10 v20H2 case 19043: // Win10 v21H1 Insider Beta and Release Preview Channels [2021-04-28] // unknown, if working with these version(s) :-O - case 21382: // Win10 v21H2 Insider Dev Channel [2021-05-11] + case 21387: // Win10 v21H2 Insider Dev Channel [2021-05-18] return true; default: // not supported diff --git a/src/Notepad3.c b/src/Notepad3.c index 2be106e15..7904609c6 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -1569,7 +1569,7 @@ HWND InitInstance(const HINSTANCE hInstance, LPCWSTR pszCmdLine, int nCmdShow) if (s_lpSchemeArg) { Style_SetLexerFromName(Globals.hwndEdit,Paths.CurrentFile,s_lpSchemeArg); LocalFree(s_lpSchemeArg); // StrDup() - } else if ((s_iInitialLexer >= 0) && (s_iInitialLexer < NUMLEXERS)) { + } else if ((s_iInitialLexer >= 0) && (s_iInitialLexer < Style_NumOfLexers())) { Style_SetLexerFromID(Globals.hwndEdit, s_iInitialLexer); } s_flagLexerSpecified = false; @@ -3156,7 +3156,7 @@ LRESULT MsgCopyData(HWND hwnd, WPARAM wParam, LPARAM lParam) StringCchCopy(wchExt, COUNTOF(wchExt), L"."); StringCchCopyN(CharNext(wchExt), 32, StrEnd(¶ms->wchData, 0) + 1, 31); Style_SetLexerFromName(Globals.hwndEdit, ¶ms->wchData, wchExt); - } else if (params->iInitialLexer >= 0 && params->iInitialLexer < NUMLEXERS) { + } else if (params->iInitialLexer >= 0 && params->iInitialLexer < Style_NumOfLexers()) { Style_SetLexerFromID(Globals.hwndEdit, params->iInitialLexer); } } diff --git a/src/Notepad3.vcxproj b/src/Notepad3.vcxproj index a37c1d6e4..249db3606 100644 --- a/src/Notepad3.vcxproj +++ b/src/Notepad3.vcxproj @@ -174,7 +174,7 @@ ntdll.lib;comctl32.lib;imm32.lib;shlwapi.lib;muiload.lib;scintilla.lib;lexilla.lib;%(AdditionalDependencies) - Debug + DebugFull Windows MachineX86 $(IntermediateOutputPath);%(AdditionalLibraryDirectories) @@ -248,7 +248,7 @@ ntdll.lib;comctl32.lib;imm32.lib;shlwapi.lib;muiload.lib;scintilla.lib;lexilla.lib;%(AdditionalDependencies) - Debug + DebugFull Windows MachineX64 $(IntermediateOutputPath);%(AdditionalLibraryDirectories) @@ -624,6 +624,7 @@ + diff --git a/src/Notepad3.vcxproj.filters b/src/Notepad3.vcxproj.filters index 4c58e3279..4f4fc78cf 100644 --- a/src/Notepad3.vcxproj.filters +++ b/src/Notepad3.vcxproj.filters @@ -414,6 +414,9 @@ Source Files\StyleLexers + + Source Files\StyleLexers + diff --git a/src/StyleLexers/EditLexer.h b/src/StyleLexers/EditLexer.h index aeb95a53a..3e01f2c83 100644 --- a/src/StyleLexers/EditLexer.h +++ b/src/StyleLexers/EditLexer.h @@ -113,6 +113,7 @@ extern EDITLEXER lexINNO; // Inno Setup Script extern EDITLEXER lexJAVA; // Java Source Code extern EDITLEXER lexJS; // JavaScript extern EDITLEXER lexJSON; // JSON +extern EDITLEXER lexJulia; // Julia extern EDITLEXER lexKotlin; // Kotlin extern EDITLEXER lexLATEX; // LaTeX Files extern EDITLEXER lexLUA; // Lua Script diff --git a/src/StyleLexers/styleLexJulia.c b/src/StyleLexers/styleLexJulia.c new file mode 100644 index 000000000..b045bc995 --- /dev/null +++ b/src/StyleLexers/styleLexJulia.c @@ -0,0 +1,88 @@ +#include "StyleLexers.h" + +// ---------------------------------------------------------------------------- + +//KEYWORDLIST KeyWords_Julia = EMPTY_KEYWORDLIST; +KEYWORDLIST KeyWords_Julia = +{ + // 0 Primary keywords and identifiers + "abstract baremodule begin break catch const continue do else elseif end export finally for function global " + "if import in isa let local macro module mutable primitive quote return struct try type using var where while " + + , // 1 Built in types + "AbstractArray AbstractArrayStyle AbstractChannel AbstractChar AbstractDict AbstractDisplay AbstractFloat " + "AbstractIrrational AbstractLock AbstractLogger AbstractMatrix AbstractRNG AbstractRange " + "AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange " + "AbstractVecOrMat AbstractVector AbstractWorkerPool Adjoint Anonymous Any ArgumentError Array ArrayStyle " + "AssertionError AsyncCondition Atomic " + "Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitSet BitVector Bool BoundsError " + "BroadcastStyle " + "CFunction CapturedException CartesianIndex CartesianIndices Cchar Cdouble Cfloat Channel Char Cint Cintmax_t " + "Clong Clonglong ClusterManager Cmd " + "Colon Complex ComplexF16 ComplexF32 ComplexF64 CompositeException CompoundPeriod Condition ConsoleLogger Cptrdiff_t " + "Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring " + "DataType Date DateFormat DateTime Day DefaultArrayStyle DenseArray DenseMatrix DenseVecOrMat DenseVector " + "Diagonal Dict DimensionMismatch Dims DivideError DomainError " + "EOFError Enum EnvDict ErrorException Event Exception ExponentialBackOff Expr Float16 Float32 Float64 Function Future " + "Givens GlobalRef Hermitian Hour " + "IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IdDict ImmutableDict IndexCartesian IndexLinear IndexStyle InexactError " + "InitError Instant Int Int128 Int16 Int32 Int64 Int8 Integer InterruptException InvalidStateException Irrational " + "IteratorEltype IteratorSize " + "KeyError LinRange LineNumberNode LinearIndices LoadError LogLevel LowerTriangular " + "MIME Matrix MersenneTwister Method MethodError Microsecond Millisecond Minute Missing MissingException Module Month " + "Mutex " + "NTuple NamedTuple Nanosecond Nothing NullLogger Number OneTo OrdinalRange OutOfMemoryError OverflowError " + "Pair Pairs PartialQuickSort Period PermutedDimsArray Pipe PipeBuffer PosDefException ProcessFailedException Ptr " + "QR QRCompactWY QRPivoted QuoteNode " + "Random RandomDevice Rational RawFD " + "ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RoundingMode " + "Second SegmentationFault Semaphore Serialization Set SharedArray SharedMatrix SharedVector " + "Signed SimpleLogger SingularException Some SparseMatrixCSC SparseVector SpinLock " + "StackFrame StackOverflowError StackTrace Stateful StepRange StepRangeLen " + "StridedArray StridedMatrix StridedVecOrMat StridedVector String StringIndexError SubArray SubString SubstitutionString " + "SymTridiagonal Symbol Symmetric SystemError " + "TCPSocket Task TextDisplay Time TimeType Timer TmStruct Transpose Tridiagonal Tuple Type TypeError TypeVar " + "UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UTInstant " + "UndefInitializer UndefKeywordError UndefRefError UndefVarError " + "UniformScaling Union UnionAll UnitLowerTriangular UnitRange UnitUpperTriangular Unsigned UpperTriangular " + "Val Vararg VecElement VecOrMat Vector VersionNumber WeakKeyDict WeakRef Week WorkerConfig WorkerPool Year " + + , // 2 Other keywords + "allocated assert async boundscheck cfunction debug deprecate distributed dump " + "elapsed enum error eval evalpoly everywhere fastmath fetch generated gensym goto " + "inbounds inferred info inline isdefined label logmsg lower macroexpand macroexpand1 noinline nospecialize " + "polly preserve printf profile propagate_inbounds pure show spawn spawnat specialize sprintf static sync " + "task test test_broken test_deprecated test_logs test_nowarn test_skip test_throws test_warn testset threads " + "time timed timev " + "view views warn " + + , // 3 Raw string literals + "raw " + + , NULL +}; + + +EDITLEXER lexJulia = +{ + SCLEX_JULIA, "julia", IDS_LEX_JULIA_SCR, L"Julia Script", L"jl", L"", + &KeyWords_Julia, { + { { STYLE_DEFAULT }, IDS_LEX_STR_63126, L"Default", L"", L"" }, + //{ {SCE_JULIA_DEFAULT}, IDS_LEX_STR_63126, L"Default", L"", L"" }, + { { SCE_JULIA_COMMENT }, IDS_LEX_STR_63127, L"Comment", L"fore:#608060", L"" }, + { { SCE_JULIA_NUMBER }, IDS_LEX_STR_63130, L"Number", L"fore:#FF0000", L"" }, + { { SCE_JULIA_KEYWORD1 }, IDS_LEX_STR_63128, L"Keyword", L"bold; fore:#0000FF", L"" }, + { { MULTI_STYLE(SCE_JULIA_KEYWORD2, SCE_JULIA_KEYWORD3, 0, 0) }, IDS_LEX_STR_63260, L"Keyword 2nd", L"bold; fore:#8A008A", L"" }, + { { MULTI_STYLE(SCE_JULIA_CHAR, SCE_JULIA_STRING, 0, 0) }, IDS_LEX_STR_63131, L"String", L"fore:#BB2F00", L"" }, + { { MULTI_STYLE(SCE_JULIA_OPERATOR, SCE_JULIA_BRACKET, 0, 0) }, IDS_LEX_STR_63132, L"Operator", L"fore:#B53A00", L"" }, + { { SCE_JULIA_IDENTIFIER }, IDS_LEX_STR_63129, L"Identifier", L"fore:#00007B", L"" }, + { { SCE_JULIA_SYMBOL }, IDS_LEX_STR_63293, L"Symbol", L"fore:#C0A030", L"" }, + { { SCE_JULIA_MACRO }, IDS_LEX_STR_63280, L"Macro Def", L"fore:#0080FF", L"" }, + { { SCE_JULIA_DOCSTRING }, IDS_LEX_STR_63259, L"Comment Doc", L"fore:#808080", L"" }, + { { MULTI_STYLE(SCE_JULIA_STRINGINTERP, SCE_JULIA_STRINGLITERAL, 0, 0) }, IDS_LEX_STR_63301, L"Literal String", L"fore:#B000B0", L"" }, + { { MULTI_STYLE(SCE_JULIA_COMMAND, SCE_JULIA_COMMANDLITERAL, 0, 0) }, IDS_LEX_STR_63236, L"Command", L"bold; fore:#0000DD", L"" }, + { { SCE_JULIA_TYPEANNOT }, IDS_LEX_STR_63370, L"Annotation", L"fore:#FF8000", L"" }, + { { SCE_JULIA_LEXERROR }, IDS_LEX_STR_63252, L"Parsing Error", L"fore:#FFFF00; back:#A00000; eolfilled", L"" }, + EDITLEXER_SENTINEL + } +}; diff --git a/src/Styles.c b/src/Styles.c index 1c39567f9..94c6fcf8f 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -27,6 +27,8 @@ #include "Lexilla.h" #include "lexers_x/SciXLexer.h" +#include "uthash/utarray.h" + #include "Edit.h" #include "Dialogs.h" #include "Encoding.h" @@ -49,7 +51,7 @@ extern COLORREF g_colorCustom[16]; // 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! -static PEDITLEXER g_pLexArray[NUMLEXERS] = { +static PEDITLEXER g_pLexArray[] = { &lexStandard, // Default Text &lexStandard2nd, // 2nd Default Text &lexTEXT, // Pure Text Files (Constants.StdDefaultLexerID = 2) @@ -76,6 +78,7 @@ static PEDITLEXER g_pLexArray[NUMLEXERS] = { &lexJAVA, // Java Source Code &lexJS, // JavaScript &lexJSON, // JSON + &lexJulia, // Julia &lexKotlin, // Kotlin &lexLATEX, // LaTeX Files &lexLUA, // Lua Script @@ -105,6 +108,10 @@ static PEDITLEXER g_pLexArray[NUMLEXERS] = { &lexYAML, // YAML }; +int Style_NumOfLexers() { + return COUNTOF(g_pLexArray); +} + // Currently used lexer static PEDITLEXER s_pLexCurrent = &lexStandard; @@ -3968,6 +3975,19 @@ static void _UpdateTitleText(HWND hwnd) } +static void _style_copy(void* _dst, const void* _src) { + LPCWSTR const * src = (LPWSTR const *)_src; + LPCWSTR * dst = (LPWSTR *)_dst; + *dst = *src ? StrDup(*src) : NULL; +} + +static void _style_dtor(void *_elt) { + LPWSTR * const elt = (LPWSTR *)_elt; + if (*elt) { LocalFree(*elt); } +} + +static UT_icd _style_icd = { sizeof(LPWSTR), NULL, _style_copy, _style_dtor }; + INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { static HWND hwndTV; @@ -3980,9 +4000,9 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar static HBRUSH hbrBack = { 0 }; static bool bIsStyleSelected = false; static bool bWarnedNoIniFile = false; - static WCHAR* Style_StylesBackup[NUMLEXERS * AVG_NUM_OF_STYLES_PER_LEXER]; static WCHAR tchTmpBuffer[max(BUFSIZE_STYLE_VALUE, BUFZIZE_STYLE_EXTENTIONS)] = {L'\0'}; + static UT_array *pStylesBackup = NULL; switch (umsg) { case WM_INITDIALOG: { @@ -3993,6 +4013,12 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar _UpdateTitleText(hwnd); + if (pStylesBackup) { + utarray_free(pStylesBackup); + pStylesBackup = NULL; + } + utarray_new(pStylesBackup, &_style_icd); + #ifdef D_NP3_WIN10_DARK_MODE if (UseDarkMode()) { SetExplorerTheme(GetDlgItem(hwnd, IDOK)); @@ -4018,14 +4044,13 @@ INT_PTR CALLBACK Style_CustomizeSchemesDlgProc(HWND hwnd, UINT umsg, WPARAM wPar SetDlgItemText(hwnd, IDC_STYLEEDIT_HELP, tchTmpBuffer); // Backup Styles - ZeroMemory(&Style_StylesBackup, NUMLEXERS * AVG_NUM_OF_STYLES_PER_LEXER * sizeof(WCHAR*)); - int cnt = 0; for (int iLexer = 0; iLexer < COUNTOF(g_pLexArray); ++iLexer) { - Style_StylesBackup[cnt++] = StrDup(g_pLexArray[iLexer]->szExtensions); - int i = 0; + LPCWSTR const pExt = g_pLexArray[iLexer]->szExtensions; + utarray_push_back(pStylesBackup, &pExt); + int i = 0; while (g_pLexArray[iLexer]->Styles[i].iStyle != -1) { - Style_StylesBackup[cnt++] = StrDup(g_pLexArray[iLexer]->Styles[i].szValue); - ++i; + LPCWSTR const pVal = g_pLexArray[iLexer]->Styles[i++].szValue; + utarray_push_back(pStylesBackup, &pVal); } } @@ -4222,23 +4247,11 @@ CASE_WM_CTLCOLOR_SET: DeleteBitmapButton(hwnd, IDC_NEXTSTYLE); // free old backup - int cnt = 0; - for (int iLexer = 0; iLexer < COUNTOF(g_pLexArray); ++iLexer) { - if (Style_StylesBackup[cnt]) { - LocalFree(Style_StylesBackup[cnt]); // StrDup() - Style_StylesBackup[cnt] = NULL; - } - ++cnt; - int i = 0; - while (g_pLexArray[iLexer]->Styles[i].iStyle != -1) { - if (Style_StylesBackup[cnt]) { - LocalFree(Style_StylesBackup[cnt]); // StrDup() - Style_StylesBackup[cnt] = NULL; - } - ++cnt; - ++i; - } + if (pStylesBackup) { + utarray_free(pStylesBackup); + pStylesBackup = NULL; } + if (hFontTitle) { DeleteObject(hFontTitle); hFontTitle = NULL; @@ -4618,19 +4631,18 @@ CASE_WM_CTLCOLOR_SET: _ApplyDialogItemText(hwnd, pCurrentLexer, pCurrentStyle, iCurStyleIdx, bIsStyleSelected); // Restore Styles from Backup - int cnt = 0; + LPWSTR * pStyle = (LPWSTR*)utarray_front(pStylesBackup); for (int iLexer = 0; iLexer < COUNTOF(g_pLexArray); ++iLexer) { - StringCchCopy(g_pLexArray[iLexer]->szExtensions, COUNTOF(g_pLexArray[iLexer]->szExtensions), Style_StylesBackup[cnt]); - - ++cnt; + StringCchCopy(g_pLexArray[iLexer]->szExtensions, COUNTOF(g_pLexArray[iLexer]->szExtensions), *pStyle); + pStyle = (LPWSTR*)utarray_next(pStylesBackup, (void*)pStyle); int i = 0; - while (g_pLexArray[iLexer]->Styles[i].iStyle != -1) { + while (pStyle && (g_pLexArray[iLexer]->Styles[i].iStyle != -1)) { // normalize tchTmpBuffer[0] = L'\0'; // clear - Style_CopyStyles_IfNotDefined(Style_StylesBackup[cnt], tchTmpBuffer, COUNTOF(tchTmpBuffer)); + Style_CopyStyles_IfNotDefined(*pStyle, tchTmpBuffer, COUNTOF(tchTmpBuffer)); StringCchCopy(g_pLexArray[iLexer]->Styles[i].szValue, COUNTOF(g_pLexArray[iLexer]->Styles[i].szValue), tchTmpBuffer); - ++cnt; ++i; + pStyle = (LPWSTR*)utarray_next(pStylesBackup, (void*)pStyle); } } Style_ResetCurrentLexer(Globals.hwndEdit); diff --git a/src/Styles.h b/src/Styles.h index 675a04792..c74b82178 100644 --- a/src/Styles.h +++ b/src/Styles.h @@ -27,9 +27,7 @@ #define MARGIN_SCI_FOLDING 2 #define NUMBER_OF_MARGINS 3 -// Number of Lexers in pLexArray -#define NUMLEXERS 53 -#define AVG_NUM_OF_STYLES_PER_LEXER 20 +int Style_NumOfLexers(); // Number of Lexers in pLexArray #define Theme_FactoryLightMode (0U) #define Theme_FactoryDarkMode (1U) diff --git a/src/VersionEx.h b/src/VersionEx.h index 4cd5c3b6d..f00c75c0f 100644 --- a/src/VersionEx.h +++ b/src/VersionEx.h @@ -8,7 +8,7 @@ #define SAPPNAME "Notepad3" #define VERSION_MAJOR 5 #define VERSION_MINOR 21 -#define VERSION_REV 515 +#define VERSION_REV 525 #define VERSION_BUILD 1 #define SCINTILLA_VER 502 #define LEXILLA_VER 502 diff --git a/test/test_files/StyleLexers/styleLexJulia/x.jl b/test/test_files/StyleLexers/styleLexJulia/x.jl new file mode 100644 index 000000000..b3e531abf --- /dev/null +++ b/test/test_files/StyleLexers/styleLexJulia/x.jl @@ -0,0 +1,434 @@ + +# Comment here +const bar = '\n' + +""" + test_fun(a::Int) +For test only +""" +function test_fun(a::Int, b::T) where T <: Number + println(a) + println("foo $(bar)") +end + +@enum Unicode α=1 β=2 + +res = [√i for i in 1:10] + +#= Dummy function =# +test_fun²(:sym, true, raw"test", `echo 1`) + +# function to calculate the volume of a sphere +function sphere_vol(r) + # julia allows Unicode names (in UTF-8 encoding) + # so either "pi" or the symbol π can be used + return 4/3*pi*r^3 +end + +# functions can also be defined more succinctly +quadratic(a, sqr_term, b) = (-b + sqr_term) / 2a + +# calculates x for 0 = a*x^2+b*x+c, arguments types can be defined in function definitions +function quadratic2(a::Float64, b::Float64, c::Float64) + # unlike other languages 2a is equivalent to 2*a + # a^2 is used instead of a**2 or pow(a,2) + sqr_term = sqrt(b^2-4a*c) + r1 = quadratic(a, sqr_term, b) + r2 = quadratic(a, -sqr_term, b) + # multiple values can be returned from a function using tuples + # if the return keyword is omitted, the last term is returned + r1, r2 +end + +vol = sphere_vol(3) +# @printf allows number formatting but does not automatically append the \n to statements, see below +using Printf +@printf "volume = %0.3f\n" vol +#> volume = 113.097 + +quad1, quad2 = quadratic2(2.0, -2.0, -12.0) +println("result 1: ", quad1) +#> result 1: 3.0 +println("result 2: ", quad2) +#> result 2: -2.0 + +s1 = "The quick brown fox jumps over the lazy dog α,β,γ" + +# search returns the first index of a char +i = findfirst(isequal('b'), s1) +println(i) +#> 11 +# the second argument is equivalent to the second argument of split, see below + +# or a range if called with another string +r = findfirst("brown", s1) +println(r) +#> 11:15 + + +# string replace is done thus: +r = replace(s1, "brown" => "red") +show(r); println() +#> "The quick red fox jumps over the lazy dog α,β,γ" + +# search and replace can also take a regular expressions by preceding the string with 'r' +r = findfirst(r"b[\w]*n", s1) +println(r) +#> 11:15 + +# again with a regular expression +r = replace(s1, r"b[\w]*n" => "red") +show(r); println() +#> "The quick red fox jumps over the lazy dog α,β,γ" + +# there are also functions for regular expressions that return RegexMatch types +# match scans left to right for the first match (specified starting index optional) +r = match(r"b[\w]*n", s1) +println(r) +#> RegexMatch("brown") + +# RegexMatch types have a property match that holds the matched string +show(r.match); println() +#> "brown" + +# eachmatch returns an iterator over all the matches +r = eachmatch(r"[\w]{4,}", s1) +for i in r print("\"$(i.match)\" ") end +#> "quick" "brown" "jumps" "over" "lazy" +println() + + +r = collect(m.match for m = eachmatch(r"[\w]{4,}", s1)) +println(r) +#> SubString{String}["quick", "brown", "jumps", "over", "lazy"] + +# a string can be repeated using the repeat function, +# or more succinctly with the ^ syntax: +r = "hello "^3 +show(r); println() #> "hello hello hello " + +# the strip function works the same as python: +# e.g., with one argument it strips the outer whitespace +r = strip("hello ") +show(r); println() #> "hello" +# or with a second argument of an array of chars it strips any of them; +r = strip("hello ", ['h', ' ']) +show(r); println() #> "ello" +# (note the array is of chars and not strings) + +# similarly split works in basically the same way as python: +r = split("hello, there,bob", ',') +show(r); println() #> SubString{String}["hello", " there", "bob"] +r = split("hello, there,bob", ", ") +show(r); println() #> SubString{String}["hello", "there,bob"] +r = split("hello, there,bob", [',', ' '], limit=0, keepempty=false) +show(r); println() #> SubString{String}["hello", "there", "bob"] +# (the last two arguements are limit and include_empty, see docs) + +# the opposite of split: join is simply +r = join(collect(1:10), ", ") +println(r) #> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + +function printsum(a) + # summary generates a summary of an object + println(summary(a), ": ", repr(a)) +end + +# arrays can be initialised directly: +a1 = [1,2,3] +printsum(a1) +#> 3-element Array{Int64,1}: [1, 2, 3] + +# or initialised empty: +a2 = [] +printsum(a2) +#> 0-element Array{Any,1}: Any[] + +# since this array has no type, functions like push! (see below) don't work +# instead arrays can be initialised with a type: +a3 = Int64[] +printsum(a3) +#> 0-element Array{Int64,1}: Int64[] + +# ranges are different from arrays: +a4 = 1:20 +printsum(a4) +#> 20-element UnitRange{Int64}: 1:20 + +# however they can be used to create arrays thus: +a4 = collect(1:20) +printsum(a4) +#> 20-element Array{Int64,1}: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, +#> 15, 16, 17, 18, 19, 20] + +# arrays can also be generated from comprehensions: +a5 = [2^i for i = 1:10] +printsum(a5) +#> 10-element Array{Int64,1}: [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + +# arrays can be any type, so arrays of arrays can be created: +a6 = (Array{Int64, 1})[] +printsum(a6) +#> 0-element Array{Array{Int64,1},1}: Array{Int64,1}[] +# (note this is a "jagged array" (i.e., an array of arrays), not a multidimensional array, +# these are not covered here) + +# Julia provided a number of "Dequeue" functions, the most common +# for appending to the end of arrays is push! +# ! at the end of a function name indicates that the first argument is updated. + +push!(a1, 4) +printsum(a1) +#> 4-element Array{Int64,1}: [1, 2, 3, 4] + +# push!(a2, 1) would cause error: + +push!(a3, 1) +printsum(a3) #> 1-element Array{Int64,1}: [1] +#> 1-element Array{Int64,1}: [1] + +push!(a6, [1,2,3]) +printsum(a6) +#> 1-element Array{Array{Int64,1},1}: Array{Int64,1}[[1, 2, 3]] + +# using repeat() to create arrays +# you must use the keywords "inner" and "outer" +# all arguments must be arrays (not ranges) +a7 = repeat(a1,inner=[2],outer=[1]) +printsum(a7) +#> 8-element Array{Int64,1}: [1, 1, 2, 2, 3, 3, 4, 4] +a8 = repeat(collect(4:-1:1),inner=[1],outer=[2]) +printsum(a8) +#> 8-element Array{Int64,1}: [4, 3, 2, 1, 4, 3, 2, 1] + +# try, catch can be used to deal with errors as with many other languages +try + push!(a,1) +catch err + showerror(stdout, err, backtrace());println() +end +#> UndefVarError: a not defined +#> Stacktrace: +#> [1] top-level scope at C:\JuliaByExample\src\error_handling.jl:5 +#> [2] include at .\boot.jl:317 [inlined] +#> [3] include_relative(::Module, ::String) at .\loading.jl:1038 +#> [4] include(::Module, ::String) at .\sysimg.jl:29 +#> [5] exec_options(::Base.JLOptions) at .\client.jl:229 +#> [6] _start() at .\client.jl:421 +println("Continuing after error") +#> Continuing after error + +# repeat can be useful to expand a grid +# as in R's expand.grid() function: + +m1 = hcat(repeat([1,2],inner=[1],outer=[3*2]), + repeat([1,2,3],inner=[2],outer=[2]), + repeat([1,2,3,4],inner=[3],outer=[1])) +printsum(m1) +#> 12×3 Array{Int64,2}: [1 1 1; 2 1 1; 1 2 1; 2 2 2; 1 3 2; 2 3 2; 1 1 3; 2 1 3; +#> 1 2 3; 2 2 4; 1 3 4; 2 3 4] + +# for simple repetitions of arrays, +# use repeat +m2 = repeat(m1,1,2) # replicate a9 once into dim1 and twice into dim2 +println("size: ", size(m2)) +#> size: (12, 6) + +m3 = repeat(m1,2,1) # replicate a9 twice into dim1 and once into dim2 +println("size: ", size(m3)) +#> size: (24, 3) + +# Julia comprehensions are another way to easily create +# multidimensional arrays + +m4 = [i+j+k for i=1:2, j=1:3, k=1:2] # creates a 2x3x2 array of Int64 +m5 = ["Hi Im # $(i+2*(j-1 + 3*(k-1)))" for i=1:2, j=1:3, k=1:2] +# expressions are very flexible +# you can specify the type of the array by just +# placing it in front of the expression + +import LegacyStrings +m5 = LegacyStrings.ASCIIString["Hi Im element # $(i+2*(j-1 + 3*(k-1)))" for i=1:2, j=1:3, k=1:2] +printsum(m5) +#> 2×3×2 Array{LegacyStrings.ASCIIString,3}: LegacyStrings.ASCIIString[ +#> "Hi Im element # 1" "Hi Im element # 3" "Hi Im element # 5"; +#> "Hi Im element # 2" "Hi Im element # 4" "Hi Im element # 6"] +#> +#> LegacyStrings.ASCIIString["Hi Im element # 7" "Hi Im element # 9" +#> "Hi Im element # 11"; "Hi Im element # 8" "Hi Im element # 10" "Hi Im element # 12"] + +# Array reductions +# many functions in Julia have an array method +# to be applied to specific dimensions of an array: + +sum(m4, dims=3) # takes the sum over the third dimension +sum(m4, dims=(1,3)) # sum over first and third dim + +maximum(m4, dims=2) # find the max elt along dim 2 +findmax(m4, dims=3) # find the max elt and its index along dim 3 + # (available only in very recent Julia versions) + +# Broadcasting +# when you combine arrays of different sizes in an operation, +# an attempt is made to "spread" or "broadcast" the smaller array +# so that the sizes match up. broadcast operators are preceded by a dot: + +m4 .+ 3 # add 3 to all elements +m4 .+ [1,2] # adds vector [1,2] to all elements along first dim + +# slices and views +m4=m4[:,:,1] # holds dim 3 fixed +m4[:,2,:] # that's a 2x1x2 array. not very intuititive to look at + +# get rid of dimensions with size 1: +dropdims(m4[:,2,:], dims=2) # that's better + +# assign new values to a certain view +m4[:,:,1] = rand(1:6,2,3) +printsum(m4) +#> 2×3 Array{Int64,2}: [3 5 3; 1 3 5] + +# (for more examples of try, catch see Error Handling above) +try + # this will cause an error, you have to assign the correct type + m4[:,:,1] = rand(2,3) +catch err + println(err) +end +#> InexactError(:Int64, Int64, 0.7603891754678744) + +try + # this will cause an error, you have to assign the right shape + m4[:,:,1] = rand(1:6,3,2) +catch err + println(err) +end +#> DimensionMismatch("tried to assign 3×2 array to 2×3×1 destination") + +# dicts can be initialised directly: +a1 = Dict(1=>"one", 2=>"two") +printsum(a1) +#> Dict{Int64,String} with 2 entries: Dict(2=>"two",1=>"one") + +# then added to: +a1[3]="three" +printsum(a1) +#> Dict{Int64,String} with 3 entries: Dict(2=>"two",3=>"three",1=>"one") +# (note dicts cannot be assumed to keep their original order) + +# dicts may also be created with the type explicitly set +a2 = Dict{Int64, AbstractString}() +a2[0]="zero" +printsum(a2) +#> Dict{Int64,AbstractString} with 1 entry: Dict{Int64,AbstractString}(0=>"zero") + +# dicts, like arrays, may also be created from comprehensions +using Printf +a3 = Dict([i => @sprintf("%d", i) for i = 1:10]) +printsum(a3) +#> Dict{Int64,String} with 10 entries: Dict(7=>"7",4=>"4",9=>"9",10=>"10", +#> 2=>"2",3=>"3",5=>"5",8=>"8",6=>"6",1=>"1") + +# as you would expect, Julia comes with all the normal helper functions +# for dicts, e.g., haskey +println(haskey(a1,1)) #> true + +# which is equivalent to +println(1 in keys(a1)) #> true +# where keys creates an iterator over the keys of the dictionary + +# similar to keys, values get iterators over the dict's values: +printsum(values(a1)) +#> Base.ValueIterator for a Dict{Int64,String} with 3 entries: ["two", "three", "one"] + +# use collect to get an array: +printsum(collect(values(a1))) +#> 3-element Array{String,1}: ["two", "three", "one"] + +if true + println("It's true!") +else + println("It's false!") +end +#> It's true! + +if false + println("It's true!") +else + println("It's false!") +end +#> It's false! + +# Numbers can be compared with opperators like <, >, ==, != + +1 == 1. +#> true + +1 > 2 +#> false + +"foo" != "bar" +#> true + +# and many functions return boolean values + +occursin("that", "this and that") +#> true + +# More complex logical statments can be achieved with `elseif` + +function checktype(x) + if x isa Int + println("Look! An Int!") + elseif x isa AbstractFloat + println("Look! A Float!") + elseif x isa Complex + println("Whoa, that's complex!") + else + println("I have no idea what that is") + end +end + +checktype(2) +#> Look! An Int! + +checktype(√2) +#> Look! A Float! + +checktype(√Complex(-2)) +#> Whoa, that's complex! + +checktype("who am I?") +#> I have no idea what that is + +# For simple logical statements, one can be more terse using the "ternary operator", +# which takes the form `predicate ? do_if_true : do_if_false` + +1 > 2 ? println("that's true!") : println("that's false!") +#> that's false! + +noisy_sqrt(x) = x ≥ 0 ? sqrt(x) : "That's negative!" +noisy_sqrt(4) +#> 2.0 +noisy_sqrt(-4) +#> That's negative! + +# "Short-circuit evaluation" offers another option for conditional statements. +# The opperators `&&` for AND and `||` for OR only evaluate the right-hand +# statement if necessary based on the predicate. +# Logically, if I want to know if `42 == 0 AND x < y`, +# it doesn't matter what `x` and `y` are, since the first statement is false. +# This can be exploited to only evaluate a statement if something is true - +# the second statement doesn't even have to be boolean! + +everything = 42 +everything < 100 && println("that's true!") +#> "that's true!" +everything == 0 && println("that's true!") +#> false + +√everything > 0 || println("that's false!") +#> true +√everything == everything || println("that's false!") +#> that's false! +