From df10f78c31a5e4608e0a80681b0eb6dbd29715a6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Granjoux?= Date: Sun, 22 May 2011 18:42:46 +0200 Subject: [PATCH] scintilla: Update scintilla with changeset 3662:1d1c06df8a2f using gtk+3 --- configure.ac | 10 +- plugins/Makefile.am | 4 +- plugins/scintilla/aneditor-indent.cxx | 4 +- plugins/scintilla/aneditor-priv.h | 1 - plugins/scintilla/aneditor.cxx | 14 +- plugins/scintilla/scintilla/Accessor.cxx | 79 ++ plugins/scintilla/scintilla/Accessor.h | 35 + plugins/scintilla/scintilla/AutoComplete.cxx | 15 +- plugins/scintilla/scintilla/AutoComplete.h | 6 +- plugins/scintilla/scintilla/CallTip.cxx | 9 +- plugins/scintilla/scintilla/CallTip.h | 4 +- plugins/scintilla/scintilla/Catalogue.cxx | 186 +++ plugins/scintilla/scintilla/Catalogue.h | 26 + plugins/scintilla/scintilla/CellBuffer.cxx | 45 +- plugins/scintilla/scintilla/CellBuffer.h | 21 +- plugins/scintilla/scintilla/CharClassify.cxx | 38 +- plugins/scintilla/scintilla/CharClassify.h | 15 +- plugins/scintilla/scintilla/CharacterSet.cxx | 61 + plugins/scintilla/scintilla/CharacterSet.h | 104 +- plugins/scintilla/scintilla/ContractionState.cxx | 21 +- plugins/scintilla/scintilla/ContractionState.h | 1 + plugins/scintilla/scintilla/Converter.h | 19 +- plugins/scintilla/scintilla/Decoration.h | 4 +- plugins/scintilla/scintilla/Document.cxx | 748 ++++++++-- plugins/scintilla/scintilla/Document.h | 167 ++- plugins/scintilla/scintilla/DocumentAccessor.cxx | 199 --- plugins/scintilla/scintilla/DocumentAccessor.h | 77 -- plugins/scintilla/scintilla/Editor.cxx | 1186 ++++++++++++---- plugins/scintilla/scintilla/Editor.h | 79 +- plugins/scintilla/scintilla/ExternalLexer.cxx | 122 +- plugins/scintilla/scintilla/ExternalLexer.h | 42 +- plugins/scintilla/scintilla/Indicator.cxx | 4 +- plugins/scintilla/scintilla/Indicator.h | 3 +- plugins/scintilla/scintilla/KeyWords.cxx | 429 ------ plugins/scintilla/scintilla/LexA68k.cxx | 318 +++++ plugins/scintilla/scintilla/LexAPDL.cxx | 15 +- plugins/scintilla/scintilla/LexASY.cxx | 27 +- plugins/scintilla/scintilla/LexAU3.cxx | 135 +- plugins/scintilla/scintilla/LexAVE.cxx | 19 +- plugins/scintilla/scintilla/LexAbaqus.cxx | 15 +- plugins/scintilla/scintilla/LexAccessor.h | 175 +++ plugins/scintilla/scintilla/LexAda.cxx | 14 +- plugins/scintilla/scintilla/LexAsm.cxx | 338 ++++- plugins/scintilla/scintilla/LexAsn1.cxx | 15 +- plugins/scintilla/scintilla/LexBaan.cxx | 15 +- plugins/scintilla/scintilla/LexBash.cxx | 280 +++- plugins/scintilla/scintilla/LexBasic.cxx | 383 +++-- plugins/scintilla/scintilla/LexBullant.cxx | 19 +- plugins/scintilla/scintilla/LexCLW.cxx | 45 +- plugins/scintilla/scintilla/LexCOBOL.cxx | 21 +- plugins/scintilla/scintilla/LexCPP.cxx | 926 +++++++++++-- plugins/scintilla/scintilla/LexCSS.cxx | 35 +- plugins/scintilla/scintilla/LexCaml.cxx | 29 +- plugins/scintilla/scintilla/LexCmake.cxx | 18 +- plugins/scintilla/scintilla/LexConf.cxx | 28 +- plugins/scintilla/scintilla/LexCrontab.cxx | 24 +- plugins/scintilla/scintilla/LexCsound.cxx | 24 +- plugins/scintilla/scintilla/LexD.cxx | 289 +++- plugins/scintilla/scintilla/LexEScript.cxx | 15 +- plugins/scintilla/scintilla/LexEiffel.cxx | 17 +- plugins/scintilla/scintilla/LexErlang.cxx | 26 +- plugins/scintilla/scintilla/LexFlagship.cxx | 382 +++-- plugins/scintilla/scintilla/LexForth.cxx | 19 +- plugins/scintilla/scintilla/LexFortran.cxx | 19 +- plugins/scintilla/scintilla/LexGAP.cxx | 17 +- plugins/scintilla/scintilla/LexGen.py | 304 ++++ plugins/scintilla/scintilla/LexGui4Cli.cxx | 15 +- plugins/scintilla/scintilla/LexHTML.cxx | 236 +++- plugins/scintilla/scintilla/LexHaskell.cxx | 267 ++-- plugins/scintilla/scintilla/LexInno.cxx | 27 +- plugins/scintilla/scintilla/LexKix.cxx | 15 +- plugins/scintilla/scintilla/LexLisp.cxx | 19 +- plugins/scintilla/scintilla/LexLout.cxx | 15 +- plugins/scintilla/scintilla/LexLua.cxx | 59 +- plugins/scintilla/scintilla/LexMMIXAL.cxx | 17 +- plugins/scintilla/scintilla/LexMPT.cxx | 32 +- plugins/scintilla/scintilla/LexMSSQL.cxx | 16 +- plugins/scintilla/scintilla/LexMagik.cxx | 15 +- plugins/scintilla/scintilla/LexMarkdown.cxx | 76 +- plugins/scintilla/scintilla/LexMatlab.cxx | 15 +- plugins/scintilla/scintilla/LexMetapost.cxx | 31 +- plugins/scintilla/scintilla/LexModula.cxx | 743 ++++++++++ plugins/scintilla/scintilla/LexMySQL.cxx | 215 +-- plugins/scintilla/scintilla/LexNimrod.cxx | 33 +- plugins/scintilla/scintilla/LexNsis.cxx | 18 +- plugins/scintilla/scintilla/LexOpal.cxx | 71 +- plugins/scintilla/scintilla/LexOthers.cxx | 75 +- plugins/scintilla/scintilla/LexPB.cxx | 15 +- plugins/scintilla/scintilla/LexPLM.cxx | 15 +- plugins/scintilla/scintilla/LexPOV.cxx | 15 +- plugins/scintilla/scintilla/LexPS.cxx | 17 +- plugins/scintilla/scintilla/LexPascal.cxx | 162 +-- plugins/scintilla/scintilla/LexPerl.cxx | 1000 ++++++++------ plugins/scintilla/scintilla/LexPowerPro.cxx | 396 +++--- plugins/scintilla/scintilla/LexPowerShell.cxx | 44 +- plugins/scintilla/scintilla/LexProgress.cxx | 19 +- plugins/scintilla/scintilla/LexPython.cxx | 51 +- plugins/scintilla/scintilla/LexR.cxx | 19 +- plugins/scintilla/scintilla/LexRebol.cxx | 15 +- plugins/scintilla/scintilla/LexRuby.cxx | 168 ++- plugins/scintilla/scintilla/LexSML.cxx | 30 +- plugins/scintilla/scintilla/LexSQL.cxx | 540 ++++++-- plugins/scintilla/scintilla/LexScriptol.cxx | 21 +- plugins/scintilla/scintilla/LexSmalltalk.cxx | 33 +- plugins/scintilla/scintilla/LexSorcus.cxx | 135 +- plugins/scintilla/scintilla/LexSpecman.cxx | 13 +- plugins/scintilla/scintilla/LexSpice.cxx | 14 +- plugins/scintilla/scintilla/LexTACL.cxx | 15 +- plugins/scintilla/scintilla/LexTADS3.cxx | 27 +- plugins/scintilla/scintilla/LexTAL.cxx | 17 +- plugins/scintilla/scintilla/LexTCL.cxx | 29 +- plugins/scintilla/scintilla/LexTeX.cxx | 55 +- plugins/scintilla/scintilla/LexTxt2tags.cxx | 480 +++++++ plugins/scintilla/scintilla/LexVB.cxx | 15 +- plugins/scintilla/scintilla/LexVHDL.cxx | 60 +- plugins/scintilla/scintilla/LexVerilog.cxx | 40 +- plugins/scintilla/scintilla/LexYAML.cxx | 17 +- plugins/scintilla/scintilla/LexerBase.cxx | 92 ++ plugins/scintilla/scintilla/LexerBase.h | 41 + plugins/scintilla/scintilla/LexerModule.cxx | 121 ++ plugins/scintilla/scintilla/LexerModule.h | 82 ++ plugins/scintilla/scintilla/LexerNoExceptions.cxx | 68 + plugins/scintilla/scintilla/LexerNoExceptions.h | 32 + plugins/scintilla/scintilla/LexerSimple.cxx | 57 + plugins/scintilla/scintilla/LexerSimple.h | 30 + plugins/scintilla/scintilla/LineMarker.cxx | 140 +- plugins/scintilla/scintilla/LineMarker.h | 13 +- plugins/scintilla/scintilla/Makefile.am | 51 +- plugins/scintilla/scintilla/OptionSet.h | 142 ++ plugins/scintilla/scintilla/Partitioning.h | 7 +- plugins/scintilla/scintilla/PerLine.cxx | 19 +- plugins/scintilla/scintilla/PerLine.h | 4 +- plugins/scintilla/scintilla/PlatGTK.cxx | 855 +++++++----- plugins/scintilla/scintilla/PositionCache.cxx | 93 +- plugins/scintilla/scintilla/PositionCache.h | 29 +- .../scintilla/{PropSet.cxx => PropSetSimple.cxx} | 27 +- plugins/scintilla/scintilla/PropSetSimple.h | 4 +- plugins/scintilla/scintilla/RESearch.cxx | 98 +- plugins/scintilla/scintilla/RunStyles.cxx | 4 +- plugins/scintilla/scintilla/SVector.h | 14 +- plugins/scintilla/scintilla/ScintillaBase.cxx | 301 ++-- plugins/scintilla/scintilla/ScintillaBase.h | 17 +- plugins/scintilla/scintilla/ScintillaGTK.cxx | 1460 ++++++++++---------- plugins/scintilla/scintilla/Selection.cxx | 13 +- plugins/scintilla/scintilla/Selection.h | 9 +- plugins/scintilla/scintilla/SparseState.h | 110 ++ plugins/scintilla/scintilla/SplitVector.h | 29 +- plugins/scintilla/scintilla/Style.cxx | 133 +- plugins/scintilla/scintilla/Style.h | 64 +- plugins/scintilla/scintilla/StyleContext.cxx | 9 +- plugins/scintilla/scintilla/StyleContext.h | 51 +- plugins/scintilla/scintilla/UniConversion.cxx | 16 +- plugins/scintilla/scintilla/UniConversion.h | 3 +- plugins/scintilla/scintilla/ViewStyle.cxx | 157 ++- plugins/scintilla/scintilla/ViewStyle.h | 22 + plugins/scintilla/scintilla/WindowAccessor.cxx | 191 --- plugins/scintilla/scintilla/WordList.cxx | 205 +++ plugins/scintilla/scintilla/WordList.h | 41 + plugins/scintilla/scintilla/XPM.cxx | 8 +- plugins/scintilla/scintilla/XPM.h | 12 +- plugins/scintilla/scintilla/include/HFacer.py | 1 + plugins/scintilla/scintilla/include/ILexer.h | 69 + plugins/scintilla/scintilla/include/Platform.h | 20 +- plugins/scintilla/scintilla/include/SciLexer.h | 91 +- plugins/scintilla/scintilla/include/Scintilla.h | 104 +- .../scintilla/scintilla/include/Scintilla.iface | 223 ++- .../scintilla/scintilla/include/ScintillaWidget.h | 12 +- plugins/scintilla/scintilla/lexers.make | 14 + plugins/scintilla/scintilla/test-scintilla.cxx | 42 +- plugins/scintilla/style-editor.c | 4 +- plugins/scintilla/text_editor_cbs.c | 15 +- 171 files changed, 13135 insertions(+), 5605 deletions(-) create mode 100644 plugins/scintilla/scintilla/Accessor.cxx create mode 100644 plugins/scintilla/scintilla/Accessor.h create mode 100644 plugins/scintilla/scintilla/Catalogue.cxx create mode 100644 plugins/scintilla/scintilla/Catalogue.h create mode 100644 plugins/scintilla/scintilla/CharacterSet.cxx delete mode 100644 plugins/scintilla/scintilla/DocumentAccessor.cxx delete mode 100644 plugins/scintilla/scintilla/DocumentAccessor.h delete mode 100644 plugins/scintilla/scintilla/KeyWords.cxx create mode 100644 plugins/scintilla/scintilla/LexA68k.cxx create mode 100644 plugins/scintilla/scintilla/LexAccessor.h mode change 100755 => 100644 plugins/scintilla/scintilla/LexAda.cxx mode change 100755 => 100644 plugins/scintilla/scintilla/LexCrontab.cxx mode change 100755 => 100644 plugins/scintilla/scintilla/LexEiffel.cxx create mode 100755 plugins/scintilla/scintilla/LexGen.py mode change 100755 => 100644 plugins/scintilla/scintilla/LexLisp.cxx create mode 100644 plugins/scintilla/scintilla/LexModula.cxx mode change 100755 => 100644 plugins/scintilla/scintilla/LexRuby.cxx create mode 100644 plugins/scintilla/scintilla/LexTxt2tags.cxx create mode 100644 plugins/scintilla/scintilla/LexerBase.cxx create mode 100644 plugins/scintilla/scintilla/LexerBase.h create mode 100644 plugins/scintilla/scintilla/LexerModule.cxx create mode 100644 plugins/scintilla/scintilla/LexerModule.h create mode 100644 plugins/scintilla/scintilla/LexerNoExceptions.cxx create mode 100644 plugins/scintilla/scintilla/LexerNoExceptions.h create mode 100644 plugins/scintilla/scintilla/LexerSimple.cxx create mode 100644 plugins/scintilla/scintilla/LexerSimple.h create mode 100644 plugins/scintilla/scintilla/OptionSet.h rename plugins/scintilla/scintilla/{PropSet.cxx => PropSetSimple.cxx} (88%) create mode 100644 plugins/scintilla/scintilla/SparseState.h mode change 100755 => 100644 plugins/scintilla/scintilla/StyleContext.cxx mode change 100755 => 100644 plugins/scintilla/scintilla/StyleContext.h delete mode 100644 plugins/scintilla/scintilla/WindowAccessor.cxx create mode 100644 plugins/scintilla/scintilla/WordList.cxx create mode 100644 plugins/scintilla/scintilla/WordList.h mode change 100755 => 100644 plugins/scintilla/scintilla/XPM.cxx mode change 100755 => 100644 plugins/scintilla/scintilla/XPM.h create mode 100644 plugins/scintilla/scintilla/include/ILexer.h mode change 100755 => 100644 plugins/scintilla/scintilla/include/Scintilla.iface diff --git a/configure.ac b/configure.ac index 1ab6372..f722a3b 100644 --- a/configure.ac +++ b/configure.ac @@ -3,9 +3,9 @@ dnl Created by Anjuta application wizard. AC_PREREQ(2.59) -m4_define(anjuta_major_version, 2) -m4_define(anjuta_minor_version, 32) -m4_define(anjuta_micro_version, 1) +m4_define(anjuta_major_version, 3) +m4_define(anjuta_minor_version, 0) +m4_define(anjuta_micro_version, 0) m4_define(anjuta_nano_version, 0) m4_define(anjuta_version, anjuta_major_version.anjuta_minor_version.anjuta_micro_version.anjuta_nano_version) @@ -29,7 +29,7 @@ AC_LANG_C ANJUTA_REQUIRED=anjuta_major_version.anjuta_minor_version.0 BINUTILS_REQUIRED=2.15.92 LIBGRAPHVIZ_REQUIRED=1.0 -GTK_REQUIRED=2.17.10 +GTK_REQUIRED=3.0.0 GLIB_REQUIRED=2.16.0 GCONF_REQUIRED=2.12.0 GNOME_REQUIRED=2.12.0 @@ -102,7 +102,7 @@ dnl maintainer mode AM_MAINTAINER_MODE dnl Check for libanjuta -PKG_CHECK_MODULES(LIBANJUTA, [libanjuta-1.0 >= $ANJUTA_REQUIRED]) +PKG_CHECK_MODULES(LIBANJUTA, [libanjuta-3.0 >= $ANJUTA_REQUIRED]) dnl Check for libgnome PKG_CHECK_MODULES(GNOME, libgnomecanvas-2.0 >= $GNOME_REQUIRED) diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 4499e74..e49a311 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1 +1,3 @@ -SUBDIRS = valgrind scratchbox profiler scintilla sample1 +#SUBDIRS = valgrind scratchbox profiler scintilla sample1 +# Only the following plugins are supported on Gtk+3 +SUBDIRS = scratchbox scintilla sample1 diff --git a/plugins/scintilla/aneditor-indent.cxx b/plugins/scintilla/aneditor-indent.cxx index 5fbddb9..9983ac3 100644 --- a/plugins/scintilla/aneditor-indent.cxx +++ b/plugins/scintilla/aneditor-indent.cxx @@ -90,11 +90,13 @@ int AnEditor::GetLineIndentPosition(int line) { } bool AnEditor::RangeIsAllWhitespace(int start, int end) { - WindowAccessor acc(wEditor.GetID(), *props); + //FIXME WindowAccessor acc(wEditor.GetID(), *props); +#if 0 for (int i = start;i < end;i++) { if ((acc[i] != ' ') && (acc[i] != '\t')) return false; } +#endif return true; } diff --git a/plugins/scintilla/aneditor-priv.h b/plugins/scintilla/aneditor-priv.h index 6867b0a..b31da0c 100644 --- a/plugins/scintilla/aneditor-priv.h +++ b/plugins/scintilla/aneditor-priv.h @@ -41,7 +41,6 @@ #include "Platform.h" #include "PropSet.h" #include "Accessor.h" -#include "WindowAccessor.h" #include "KeyWords.h" #include "Scintilla.h" #include "ScintillaWidget.h" diff --git a/plugins/scintilla/aneditor.cxx b/plugins/scintilla/aneditor.cxx index b5b92c7..7246059 100644 --- a/plugins/scintilla/aneditor.cxx +++ b/plugins/scintilla/aneditor.cxx @@ -118,7 +118,7 @@ AnEditor::AnEditor(PropSetFile* p) { wEditor = scintilla_new(); g_object_ref (G_OBJECT (wEditor.GetID())); - gtk_object_sink (GTK_OBJECT (wEditor.GetID())); + g_object_ref_sink (G_OBJECT (wEditor.GetID())); scintilla_set_id(SCINTILLA(wEditor.GetID()), 0); fnEditor = reinterpret_cast(Platform::SendScintilla( @@ -541,7 +541,8 @@ bool AnEditor::FindMatchingBracePosition(bool editor, int &braceAtCaret, int &br braceOpposite = -1; char charBefore = '\0'; char styleBefore = '\0'; - WindowAccessor acc(win.GetID(), *props); + //FIXME WindowAccessor acc(win.GetID(), *props); +#if 0 if (caretPos > 0) { charBefore = acc[caretPos - 1]; styleBefore = static_cast(acc.StyleAt(caretPos - 1) & 31); @@ -584,6 +585,7 @@ bool AnEditor::FindMatchingBracePosition(bool editor, int &braceAtCaret, int &br isInside = !isAfter; } } +#endif return isInside; } @@ -644,7 +646,8 @@ void AnEditor::SelectionWord(char *word, int len) { int selStart = cr.cpMin; int selEnd = cr.cpMax; if (selStart == selEnd) { - WindowAccessor acc(wEditor.GetID(), *props); + //FIXME WindowAccessor acc(wEditor.GetID(), *props); +#if 0 // Try and find a word at the caret if (iswordcharforsel(acc[selStart])) { while ((selStart > 0) && (iswordcharforsel(acc[selStart - 1]))) @@ -654,6 +657,7 @@ void AnEditor::SelectionWord(char *word, int len) { if (selStart < selEnd) selEnd++; // Because normal selections end one past } +#endif } word[0] = '\0'; if ((selStart < selEnd) && ((selEnd - selStart + 1) < len)) { @@ -667,7 +671,8 @@ void AnEditor::WordSelect() { int selEnd; selStart = selEnd = SendEditor(SCI_GETCURRENTPOS); - WindowAccessor acc(wEditor.GetID(), *props); + //FIXME WindowAccessor acc(wEditor.GetID(), *props); +#if 0 if (iswordcharforsel(acc[selStart])) { while ((selStart > 0) && (iswordcharforsel(acc[selStart - 1]))) selStart--; @@ -676,6 +681,7 @@ void AnEditor::WordSelect() { if (selStart < selEnd) selEnd++; // Because normal selections end one past } +#endif SetSelection(selStart, selEnd); } diff --git a/plugins/scintilla/scintilla/Accessor.cxx b/plugins/scintilla/scintilla/Accessor.cxx new file mode 100644 index 0000000..5adaaa2 --- /dev/null +++ b/plugins/scintilla/scintilla/Accessor.cxx @@ -0,0 +1,79 @@ +// Scintilla source code edit control +/** @file KeyWords.cxx + ** Colourise for particular languages. + **/ +// 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 "PropSetSimple.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +Accessor::Accessor(IDocument *pAccess_, PropSetSimple *pprops_) : LexAccessor(pAccess_), pprops(pprops_) { +} + +int Accessor::GetPropertyInt(const char *key, int defaultValue) { + return pprops->GetInt(key, defaultValue); +} + +int Accessor::IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader) { + int end = Length(); + int spaceFlags = 0; + + // Determines the indentation level of the current line and also checks for consistent + // indentation compared to the previous line. + // Indentation is judged consistent when the indentation whitespace of each line lines + // the same or the indentation of one line is a prefix of the other. + + int pos = LineStart(line); + char ch = (*this)[pos]; + int indent = 0; + bool inPrevPrefix = line > 0; + int posPrev = inPrevPrefix ? LineStart(line-1) : 0; + while ((ch == ' ' || ch == '\t') && (pos < end)) { + if (inPrevPrefix) { + char chPrev = (*this)[posPrev++]; + if (chPrev == ' ' || chPrev == '\t') { + if (chPrev != ch) + spaceFlags |= wsInconsistent; + } else { + inPrevPrefix = false; + } + } + if (ch == ' ') { + spaceFlags |= wsSpace; + indent++; + } else { // Tab + spaceFlags |= wsTab; + if (spaceFlags & wsSpace) + spaceFlags |= wsSpaceTab; + indent = (indent / 8 + 1) * 8; + } + ch = (*this)[++pos]; + } + + *flags = spaceFlags; + indent += SC_FOLDLEVELBASE; + // if completely empty line or the start of a comment... + if ((ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') || + (pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos))) + return indent | SC_FOLDLEVELWHITEFLAG; + else + return indent; +} diff --git a/plugins/scintilla/scintilla/Accessor.h b/plugins/scintilla/scintilla/Accessor.h new file mode 100644 index 0000000..2f28c1a --- /dev/null +++ b/plugins/scintilla/scintilla/Accessor.h @@ -0,0 +1,35 @@ +// Scintilla source code edit control +/** @file Accessor.h + ** Interfaces between Scintilla and lexers. + **/ +// Copyright 1998-2010 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef ACCESSOR_H +#define ACCESSOR_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +enum { wsSpace = 1, wsTab = 2, wsSpaceTab = 4, wsInconsistent=8}; + +class Accessor; +class WordList; +class PropSetSimple; + +typedef bool (*PFNIsCommentLeader)(Accessor &styler, int pos, int len); + +class Accessor : public LexAccessor { +public: + PropSetSimple *pprops; + Accessor(IDocument *pAccess_, PropSetSimple *pprops_); + int GetPropertyInt(const char *, int defaultValue=0); + int IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/plugins/scintilla/scintilla/AutoComplete.cxx b/plugins/scintilla/scintilla/AutoComplete.cxx index 86c64df..f6a291f 100644 --- a/plugins/scintilla/scintilla/AutoComplete.cxx +++ b/plugins/scintilla/scintilla/AutoComplete.cxx @@ -8,10 +8,11 @@ #include #include #include +#include #include "Platform.h" -#include "CharClassify.h" +#include "CharacterSet.h" #include "AutoComplete.h" #ifdef SCI_NAMESPACE @@ -43,12 +44,12 @@ AutoComplete::~AutoComplete() { } } -bool AutoComplete::Active() { +bool AutoComplete::Active() const { return active; } -void AutoComplete::Start(Window &parent, int ctrlID, - int position, Point location, int startLen_, +void AutoComplete::Start(Window &parent, int ctrlID, + int position, Point location, int startLen_, int lineHeight, bool unicodeMode) { if (active) { Cancel(); @@ -82,7 +83,7 @@ void AutoComplete::SetSeparator(char separator_) { separator = separator_; } -char AutoComplete::GetSeparator() { +char AutoComplete::GetSeparator() const { return separator; } @@ -90,7 +91,7 @@ void AutoComplete::SetTypesep(char separator_) { typesep = separator_; } -char AutoComplete::GetTypesep() { +char AutoComplete::GetTypesep() const { return typesep; } @@ -128,11 +129,11 @@ void AutoComplete::Select(const char *word) { size_t lenWord = strlen(word); int location = -1; const int maxItemLen=1000; - char item[maxItemLen]; int start = 0; // lower bound of the api array block to search int end = lb->Length() - 1; // upper bound of the api array block to search while ((start <= end) && (location == -1)) { // Binary searching loop int pivot = (start + end) / 2; + char item[maxItemLen]; lb->GetValue(pivot, item, maxItemLen); int cond; if (ignoreCase) diff --git a/plugins/scintilla/scintilla/AutoComplete.h b/plugins/scintilla/scintilla/AutoComplete.h index b10cdce..f48cb05 100644 --- a/plugins/scintilla/scintilla/AutoComplete.h +++ b/plugins/scintilla/scintilla/AutoComplete.h @@ -36,7 +36,7 @@ public: ~AutoComplete(); /// Is the auto completion list displayed? - bool Active(); + bool Active() const; /// Display the auto completion list positioned to be near a character position void Start(Window &parent, int ctrlID, int position, Point location, @@ -52,11 +52,11 @@ public: /// The separator character is used when interpreting the list in SetList void SetSeparator(char separator_); - char GetSeparator(); + char GetSeparator() const; /// The typesep character is used for seperating the word from the type void SetTypesep(char separator_); - char GetTypesep(); + char GetTypesep() const; /// The list string contains a sequence of words separated by the separator character void SetList(const char *list); diff --git a/plugins/scintilla/scintilla/CallTip.cxx b/plugins/scintilla/scintilla/CallTip.cxx index 3ea2d48..cdc30fc 100644 --- a/plugins/scintilla/scintilla/CallTip.cxx +++ b/plugins/scintilla/scintilla/CallTip.cxx @@ -29,6 +29,7 @@ CallTip::CallTip() { rectUp = PRectangle(0,0,0,0); rectDown = PRectangle(0,0,0,0); lineHeight = 1; + offsetMain = 0; startHighlight = 0; endHighlight = 0; tabSize = 0; @@ -45,6 +46,8 @@ CallTip::CallTip() { colourSel.desired = ColourDesired(0, 0, 0x80); colourShade.desired = ColourDesired(0, 0, 0); colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0); + codePage = 0; + clickPlace = 0; } CallTip::~CallTip() { @@ -68,7 +71,7 @@ static bool IsArrowCharacter(char ch) { } // We ignore tabs unless a tab width has been set. -bool CallTip::IsTabCharacter(char ch) { +bool CallTip::IsTabCharacter(char ch) const { return (tabSize > 0) && (ch == '\t'); } @@ -95,9 +98,9 @@ void CallTip::DrawChunk(Surface *surface, int &x, const char *s, int maxEnd = 0; const int numEnds = 10; int ends[numEnds + 2]; - for (int i=0;i 0) ends[maxEnd++] = i; ends[maxEnd++] = i+1; diff --git a/plugins/scintilla/scintilla/CallTip.h b/plugins/scintilla/scintilla/CallTip.h index a64755f..a9ba82e 100644 --- a/plugins/scintilla/scintilla/CallTip.h +++ b/plugins/scintilla/scintilla/CallTip.h @@ -33,7 +33,7 @@ class CallTip { int posStart, int posEnd, int ytext, PRectangle rcClient, bool highlight, bool draw); int PaintContents(Surface *surfaceWindow, bool draw); - bool IsTabCharacter(char c); + bool IsTabCharacter(char c) const; int NextTabPos(int x); public: @@ -61,7 +61,7 @@ public: /// Setup the calltip and return a rectangle of the area required. PRectangle CallTipStart(int pos, Point pt, const char *defn, - const char *faceName, int size, int codePage_, + const char *faceName, int size, int codePage_, int characterSet, Window &wParent); void CallTipCancel(); diff --git a/plugins/scintilla/scintilla/Catalogue.cxx b/plugins/scintilla/scintilla/Catalogue.cxx new file mode 100644 index 0000000..00785d5 --- /dev/null +++ b/plugins/scintilla/scintilla/Catalogue.cxx @@ -0,0 +1,186 @@ +// Scintilla source code edit control +/** @file KeyWords.cxx + ** Colourise for particular languages. + **/ +// 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 + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "LexerModule.h" +#include "Catalogue.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static std::vector lexerCatalogue; +static int nextLanguage = SCLEX_AUTOMATIC+1; + +const LexerModule *Catalogue::Find(int language) { + Scintilla_LinkLexers(); + for (std::vector::iterator it=lexerCatalogue.begin(); + it != lexerCatalogue.end(); ++it) { + if ((*it)->GetLanguage() == language) { + return *it; + } + } + return 0; +} + +const LexerModule *Catalogue::Find(const char *languageName) { + Scintilla_LinkLexers(); + if (languageName) { + for (std::vector::iterator it=lexerCatalogue.begin(); + it != lexerCatalogue.end(); ++it) { + if ((*it)->languageName && (0 == strcmp((*it)->languageName, languageName))) { + return *it; + } + } + } + return 0; +} + +void Catalogue::AddLexerModule(LexerModule *plm) { + if (plm->GetLanguage() == SCLEX_AUTOMATIC) { + plm->language = nextLanguage; + nextLanguage++; + } + lexerCatalogue.push_back(plm); +} + +// Alternative historical name for Scintilla_LinkLexers +int wxForceScintillaLexers(void) { + return Scintilla_LinkLexers(); +} + +// To add or remove a lexer, add or remove its file and run LexGen.py. + +// Force a reference to all of the Scintilla lexers so that the linker will +// not remove the code of the lexers. +int Scintilla_LinkLexers() { + + static int initialised = 0; + if (initialised) + return 0; + initialised = 1; + +// Shorten the code that declares a lexer and ensures it is linked in by calling a method. +#define LINK_LEXER(lexer) extern LexerModule lexer; Catalogue::AddLexerModule(&lexer); + +//++Autogenerated -- run src/LexGen.py to regenerate +//**\(\tLINK_LEXER(\*);\n\) + LINK_LEXER(lmA68k); + LINK_LEXER(lmAbaqus); + LINK_LEXER(lmAda); + LINK_LEXER(lmAns1); + LINK_LEXER(lmAPDL); + LINK_LEXER(lmAsm); + LINK_LEXER(lmASY); + LINK_LEXER(lmAU3); + LINK_LEXER(lmAVE); + LINK_LEXER(lmBaan); + LINK_LEXER(lmBash); + LINK_LEXER(lmBatch); + LINK_LEXER(lmBlitzBasic); + LINK_LEXER(lmBullant); + LINK_LEXER(lmCaml); + LINK_LEXER(lmClw); + LINK_LEXER(lmClwNoCase); + LINK_LEXER(lmCmake); + LINK_LEXER(lmCOBOL); + LINK_LEXER(lmConf); + LINK_LEXER(lmCPP); + LINK_LEXER(lmCPPNoCase); + LINK_LEXER(lmCsound); + LINK_LEXER(lmCss); + LINK_LEXER(lmD); + LINK_LEXER(lmDiff); + LINK_LEXER(lmEiffel); + LINK_LEXER(lmEiffelkw); + LINK_LEXER(lmErlang); + LINK_LEXER(lmErrorList); + LINK_LEXER(lmESCRIPT); + LINK_LEXER(lmF77); + LINK_LEXER(lmFlagShip); + LINK_LEXER(lmForth); + LINK_LEXER(lmFortran); + LINK_LEXER(lmFreeBasic); + LINK_LEXER(lmGAP); + LINK_LEXER(lmGui4Cli); + LINK_LEXER(lmHaskell); + LINK_LEXER(lmHTML); + LINK_LEXER(lmInno); + LINK_LEXER(lmKix); + LINK_LEXER(lmLatex); + LINK_LEXER(lmLISP); + LINK_LEXER(lmLot); + LINK_LEXER(lmLout); + LINK_LEXER(lmLua); + LINK_LEXER(lmMagikSF); + LINK_LEXER(lmMake); + LINK_LEXER(lmMarkdown); + LINK_LEXER(lmMatlab); + LINK_LEXER(lmMETAPOST); + LINK_LEXER(lmMMIXAL); + LINK_LEXER(lmModula); + LINK_LEXER(lmMSSQL); + LINK_LEXER(lmMySQL); + LINK_LEXER(lmNimrod); + LINK_LEXER(lmNncrontab); + LINK_LEXER(lmNsis); + LINK_LEXER(lmNull); + LINK_LEXER(lmOctave); + LINK_LEXER(lmOpal); + LINK_LEXER(lmPascal); + LINK_LEXER(lmPB); + LINK_LEXER(lmPerl); + LINK_LEXER(lmPHPSCRIPT); + LINK_LEXER(lmPLM); + LINK_LEXER(lmPo); + LINK_LEXER(lmPOV); + LINK_LEXER(lmPowerPro); + LINK_LEXER(lmPowerShell); + LINK_LEXER(lmProgress); + LINK_LEXER(lmProps); + LINK_LEXER(lmPS); + LINK_LEXER(lmPureBasic); + LINK_LEXER(lmPython); + LINK_LEXER(lmR); + LINK_LEXER(lmREBOL); + LINK_LEXER(lmRuby); + LINK_LEXER(lmScriptol); + LINK_LEXER(lmSmalltalk); + LINK_LEXER(lmSML); + LINK_LEXER(lmSorc); + LINK_LEXER(lmSpecman); + LINK_LEXER(lmSpice); + LINK_LEXER(lmSQL); + LINK_LEXER(lmTACL); + LINK_LEXER(lmTADS3); + LINK_LEXER(lmTAL); + LINK_LEXER(lmTCL); + LINK_LEXER(lmTeX); + LINK_LEXER(lmTxt2tags); + LINK_LEXER(lmVB); + LINK_LEXER(lmVBScript); + LINK_LEXER(lmVerilog); + LINK_LEXER(lmVHDL); + LINK_LEXER(lmXML); + LINK_LEXER(lmYAML); + +//--Autogenerated -- end of automatically generated section + + return 1; +} diff --git a/plugins/scintilla/scintilla/Catalogue.h b/plugins/scintilla/scintilla/Catalogue.h new file mode 100644 index 0000000..7fea37d --- /dev/null +++ b/plugins/scintilla/scintilla/Catalogue.h @@ -0,0 +1,26 @@ +// Scintilla source code edit control +/** @file Catalogue.h + ** Lexer infrastructure. + **/ +// Copyright 1998-2010 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CATALOGUE_H +#define CATALOGUE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class Catalogue { +public: + static const LexerModule *Find(int language); + static const LexerModule *Find(const char *languageName); + static void AddLexerModule(LexerModule *plm); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/plugins/scintilla/scintilla/CellBuffer.cxx b/plugins/scintilla/scintilla/CellBuffer.cxx index be04403..19f6670 100644 --- a/plugins/scintilla/scintilla/CellBuffer.cxx +++ b/plugins/scintilla/scintilla/CellBuffer.cxx @@ -44,9 +44,11 @@ void LineVector::InsertText(int line, int delta) { starts.InsertText(line, delta); } -void LineVector::InsertLine(int line, int position) { +void LineVector::InsertLine(int line, int position, bool lineStart) { starts.InsertPartition(line, position); if (perLine) { + if ((line > 0) && lineStart) + line--; perLine->InsertLine(line); } } @@ -197,7 +199,7 @@ void UndoHistory::AppendAction(actionType at, int position, char *data, int leng // Insertions must be immediately after to coalesce currentAction++; } else if (at == removeAction) { - if ((lengthData == 1) || (lengthData == 2)){ + if ((lengthData == 1) || (lengthData == 2)) { if ((position + lengthData) == actPrevious->position) { ; // Backspace -> OK } else if (position == actPrevious->position) { @@ -339,7 +341,7 @@ char CellBuffer::CharAt(int position) const { return substance.ValueAt(position); } -void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) { +void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) const { if (lengthRetrieve < 0) return; if (position < 0) @@ -349,17 +351,27 @@ void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) { lengthRetrieve, substance.Length()); return; } - - for (int i=0; i style.Length()) { + Platform::DebugPrintf("Bad GetStyleRange %d for %d of %d\n", position, + lengthRetrieve, style.Length()); + return; + } + style.GetRange(reinterpret_cast(buffer), position, lengthRetrieve); +} + +const char *CellBuffer::BufferPointer() { return substance.BufferPointer(); } @@ -455,7 +467,7 @@ int CellBuffer::LineStart(int line) const { return lv.LineStart(line); } -bool CellBuffer::IsReadOnly() { +bool CellBuffer::IsReadOnly() const { return readOnly; } @@ -473,8 +485,8 @@ bool CellBuffer::IsSavePoint() { // Without undo -void CellBuffer::InsertLine(int line, int position) { - lv.InsertLine(line, position); +void CellBuffer::InsertLine(int line, int position, bool lineStart) { + lv.InsertLine(line, position, lineStart); } void CellBuffer::RemoveLine(int line) { @@ -490,27 +502,28 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength style.InsertValue(position, insertLength, 0); int lineInsert = lv.LineFromPosition(position) + 1; + bool atLineStart = lv.LineStart(lineInsert-1) == position; // Point all the lines after the insertion point further along in the buffer lv.InsertText(lineInsert-1, insertLength); char chPrev = substance.ValueAt(position - 1); char chAfter = substance.ValueAt(position + insertLength); if (chPrev == '\r' && chAfter == '\n') { // Splitting up a crlf pair at position - InsertLine(lineInsert, position); + InsertLine(lineInsert, position, false); lineInsert++; } char ch = ' '; for (int i = 0; i < insertLength; i++) { ch = s[i]; if (ch == '\r') { - InsertLine(lineInsert, (position + i) + 1); + InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } else if (ch == '\n') { if (chPrev == '\r') { // Patch up what was end of line lv.SetLineStart(lineInsert - 1, (position + i) + 1); } else { - InsertLine(lineInsert, (position + i) + 1); + InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } } @@ -586,7 +599,7 @@ bool CellBuffer::SetUndoCollection(bool collectUndo) { return collectingUndo; } -bool CellBuffer::IsCollectingUndo() { +bool CellBuffer::IsCollectingUndo() const { return collectingUndo; } diff --git a/plugins/scintilla/scintilla/CellBuffer.h b/plugins/scintilla/scintilla/CellBuffer.h index 3381c19..a82a397 100644 --- a/plugins/scintilla/scintilla/CellBuffer.h +++ b/plugins/scintilla/scintilla/CellBuffer.h @@ -37,7 +37,7 @@ public: void SetPerLine(PerLine *pl); void InsertText(int line, int delta); - void InsertLine(int line, int position); + void InsertLine(int line, int position, bool lineStart); void SetLineStart(int line, int position); void RemoveLine(int line); int Lines() const { @@ -142,6 +142,10 @@ private: LineVector lv; + /// Actions without undo + void BasicInsertString(int position, const char *s, int insertLength); + void BasicDeleteChars(int position, int deleteLength); + public: CellBuffer(); @@ -149,8 +153,9 @@ public: /// Retrieving positions outside the range of the buffer works and returns 0 char CharAt(int position) const; - void GetCharRange(char *buffer, int position, int lengthRetrieve); - char StyleAt(int position); + void GetCharRange(char *buffer, int position, int lengthRetrieve) const; + char StyleAt(int position) const; + void GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const; const char *BufferPointer(); int Length() const; @@ -159,7 +164,7 @@ public: int Lines() const; int LineStart(int line) const; int LineFromPosition(int pos) const { return lv.LineFromPosition(pos); } - void InsertLine(int line, int position); + void InsertLine(int line, int position, bool lineStart); void RemoveLine(int line); const char *InsertString(int position, const char *s, int insertLength, bool &startSequence); @@ -170,7 +175,7 @@ public: const char *DeleteChars(int position, int deleteLength, bool &startSequence); - bool IsReadOnly(); + bool IsReadOnly() const; void SetReadOnly(bool set); /// The save point is a marker in the undo stack where the container has stated that @@ -178,12 +183,8 @@ public: void SetSavePoint(); bool IsSavePoint(); - /// Actions without undo - void BasicInsertString(int position, const char *s, int insertLength); - void BasicDeleteChars(int position, int deleteLength); - bool SetUndoCollection(bool collectUndo); - bool IsCollectingUndo(); + bool IsCollectingUndo() const; void BeginUndoAction(); void EndUndoAction(); void AddUndoAction(int token, bool mayCoalesce); diff --git a/plugins/scintilla/scintilla/CharClassify.cxx b/plugins/scintilla/scintilla/CharClassify.cxx index bbd25a0..c16af45 100644 --- a/plugins/scintilla/scintilla/CharClassify.cxx +++ b/plugins/scintilla/scintilla/CharClassify.cxx @@ -10,6 +10,10 @@ #include "CharClassify.h" +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER #pragma warning(disable: 4514) @@ -42,37 +46,3 @@ void CharClassify::SetCharClasses(const unsigned char *chars, cc newCharClass) { } } } - -int CompareCaseInsensitive(const char *a, const char *b) { - while (*a && *b) { - if (*a != *b) { - char upperA = MakeUpperCase(*a); - char upperB = MakeUpperCase(*b); - if (upperA != upperB) - return upperA - upperB; - } - a++; - b++; - } - // Either *a or *b is nul - return *a - *b; -} - -int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { - while (*a && *b && len) { - if (*a != *b) { - char upperA = MakeUpperCase(*a); - char upperB = MakeUpperCase(*b); - if (upperA != upperB) - return upperA - upperB; - } - a++; - b++; - len--; - } - if (len == 0) - return 0; - else - // Either *a or *b is nul - return *a - *b; -} diff --git a/plugins/scintilla/scintilla/CharClassify.h b/plugins/scintilla/scintilla/CharClassify.h index d746fe0..e8b798e 100644 --- a/plugins/scintilla/scintilla/CharClassify.h +++ b/plugins/scintilla/scintilla/CharClassify.h @@ -8,6 +8,10 @@ #ifndef CHARCLASSIFY_H #define CHARCLASSIFY_H +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + class CharClassify { public: CharClassify(); @@ -23,15 +27,8 @@ private: unsigned char charClass[maxChar]; // not type cc to save space }; -// These functions are implemented because each platform calls them something different. -int CompareCaseInsensitive(const char *a, const char *b); -int CompareNCaseInsensitive(const char *a, const char *b, size_t len); - -inline char MakeUpperCase(char ch) { - if (ch < 'a' || ch > 'z') - return ch; - else - return static_cast(ch - 'a' + 'A'); +#ifdef SCI_NAMESPACE } +#endif #endif diff --git a/plugins/scintilla/scintilla/CharacterSet.cxx b/plugins/scintilla/scintilla/CharacterSet.cxx new file mode 100644 index 0000000..35669df --- /dev/null +++ b/plugins/scintilla/scintilla/CharacterSet.cxx @@ -0,0 +1,61 @@ +// Scintilla source code edit control +/** @file CharacterSet.cxx + ** Simple case functions for ASCII. + ** Lexer infrastructure. + **/ +// Copyright 1998-2010 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include + +#include "CharacterSet.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +int CompareCaseInsensitive(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + } + // Either *a or *b is nul + return *a - *b; +} + +int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { + while (*a && *b && len) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + len--; + } + if (len == 0) + return 0; + else + // Either *a or *b is nul + return *a - *b; +} + +#ifdef SCI_NAMESPACE +} +#endif diff --git a/plugins/scintilla/scintilla/CharacterSet.h b/plugins/scintilla/scintilla/CharacterSet.h index 4e8ffbd..ba42ea3 100644 --- a/plugins/scintilla/scintilla/CharacterSet.h +++ b/plugins/scintilla/scintilla/CharacterSet.h @@ -5,6 +5,13 @@ // Copyright 2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. +#ifndef CHARACTERSET_H +#define CHARACTERSET_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + class CharacterSet { int size; bool valueAfter; @@ -39,20 +46,103 @@ public: size = 0; } void Add(int val) { - PLATFORM_ASSERT(val >= 0); - PLATFORM_ASSERT(val < size); + assert(val >= 0); + assert(val < size); bset[val] = true; } - void AddString(const char *CharacterSet) { - for (const char *cp=CharacterSet; *cp; cp++) { + void AddString(const char *setToAdd) { + for (const char *cp=setToAdd; *cp; cp++) { int val = static_cast(*cp); - PLATFORM_ASSERT(val >= 0); - PLATFORM_ASSERT(val < size); + assert(val >= 0); + assert(val < size); bset[val] = true; } } bool Contains(int val) const { - PLATFORM_ASSERT(val >= 0); + assert(val >= 0); + if (val < 0) return false; return (val < size) ? bset[val] : valueAfter; } }; + +// Functions for classifying characters + +inline bool IsASpace(int ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +inline bool IsASpaceOrTab(int ch) { + return (ch == ' ') || (ch == '\t'); +} + +inline bool IsADigit(int ch) { + return (ch >= '0') && (ch <= '9'); +} + +inline bool IsADigit(int ch, int base) { + if (base <= 10) { + return (ch >= '0') && (ch < '0' + base); + } else { + return ((ch >= '0') && (ch <= '9')) || + ((ch >= 'A') && (ch < 'A' + base - 10)) || + ((ch >= 'a') && (ch < 'a' + base - 10)); + } +} + +inline bool IsASCII(int ch) { + return ch < 0x80; +} + +inline bool IsAlphaNumeric(int ch) { + return + ((ch >= '0') && (ch <= '9')) || + ((ch >= 'a') && (ch <= 'z')) || + ((ch >= 'A') && (ch <= 'Z')); +} + +/** + * Check if a character is a space. + * This is ASCII specific but is safe with chars >= 0x80. + */ +inline bool isspacechar(int ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +inline bool iswordchar(int ch) { + return IsASCII(ch) && (IsAlphaNumeric(ch) || ch == '.' || ch == '_'); +} + +inline bool iswordstart(int ch) { + return IsASCII(ch) && (IsAlphaNumeric(ch) || ch == '_'); +} + +inline bool isoperator(int ch) { + if (IsASCII(ch) && IsAlphaNumeric(ch)) + return false; + if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || + ch == '(' || ch == ')' || ch == '-' || ch == '+' || + ch == '=' || ch == '|' || ch == '{' || ch == '}' || + ch == '[' || ch == ']' || ch == ':' || ch == ';' || + ch == '<' || ch == '>' || ch == ',' || ch == '/' || + ch == '?' || ch == '!' || ch == '.' || ch == '~') + return true; + return false; +} + +// Simple case functions for ASCII. + +inline char MakeUpperCase(char ch) { + if (ch < 'a' || ch > 'z') + return ch; + else + return static_cast(ch - 'a' + 'A'); +} + +int CompareCaseInsensitive(const char *a, const char *b); +int CompareNCaseInsensitive(const char *a, const char *b, size_t len); + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/plugins/scintilla/scintilla/ContractionState.cxx b/plugins/scintilla/scintilla/ContractionState.cxx index 08de5cf..8a1b486 100644 --- a/plugins/scintilla/scintilla/ContractionState.cxx +++ b/plugins/scintilla/scintilla/ContractionState.cxx @@ -193,6 +193,23 @@ bool ContractionState::SetExpanded(int lineDoc, bool expanded_) { } } +int ContractionState::ContractedNext(int lineDocStart) const { + if (OneToOne()) { + return -1; + } else { + Check(); + if (!expanded->ValueAt(lineDocStart)) { + return lineDocStart; + } else { + int lineDocNextChange = expanded->EndRun(lineDocStart); + if (lineDocNextChange < LinesInDoc()) + return lineDocNextChange; + else + return -1; + } + } +} + int ContractionState::GetHeight(int lineDoc) const { if (OneToOne()) { return 1; @@ -232,11 +249,11 @@ void ContractionState::ShowAll() { void ContractionState::Check() const { #ifdef CHECK_CORRECTNESS - for (int vline = 0;vline < LinesDisplayed(); vline++) { + for (int vline = 0; vline < LinesDisplayed(); vline++) { const int lineDoc = DocFromDisplay(vline); PLATFORM_ASSERT(GetVisible(lineDoc)); } - for (int lineDoc = 0;lineDoc < LinesInDoc(); lineDoc++) { + for (int lineDoc = 0; lineDoc < LinesInDoc(); lineDoc++) { const int displayThis = DisplayFromDoc(lineDoc); const int displayNext = DisplayFromDoc(lineDoc + 1); const int height = displayNext - displayThis; diff --git a/plugins/scintilla/scintilla/ContractionState.h b/plugins/scintilla/scintilla/ContractionState.h index ba62975..8e7b39b 100644 --- a/plugins/scintilla/scintilla/ContractionState.h +++ b/plugins/scintilla/scintilla/ContractionState.h @@ -51,6 +51,7 @@ public: bool GetExpanded(int lineDoc) const; bool SetExpanded(int lineDoc, bool expanded); + int ContractedNext(int lineDocStart) const; int GetHeight(int lineDoc) const; bool SetHeight(int lineDoc, int height); diff --git a/plugins/scintilla/scintilla/Converter.h b/plugins/scintilla/scintilla/Converter.h index d3038a2..8e7e3e9 100644 --- a/plugins/scintilla/scintilla/Converter.h +++ b/plugins/scintilla/scintilla/Converter.h @@ -3,12 +3,7 @@ // Copyright 2004 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. -#include -#if GTK_MAJOR_VERSION >= 2 - typedef GIConv ConverterHandle; -#else - typedef iconv_t ConverterHandle; -#endif +typedef GIConv ConverterHandle; const ConverterHandle iconvhBad = (ConverterHandle)(-1); // Since various versions of iconv can not agree on whether the src argument // is char ** or const char ** provide a templatised adaptor. @@ -24,11 +19,7 @@ size_t iconv_adaptor(size_t(*f_iconv)(ConverterHandle, T, size_t *, char **, siz class Converter { ConverterHandle iconvh; void OpenHandle(const char *fullDestination, const char *charSetSource) { -#if GTK_MAJOR_VERSION >= 2 iconvh = g_iconv_open(fullDestination, charSetSource); -#else - iconvh = iconv_open(fullDestination, charSetSource); -#endif } bool Succeeded() const { return iconvh != iconvhBad; @@ -65,11 +56,7 @@ public: } void Close() { if (Succeeded()) { -#if GTK_MAJOR_VERSION >= 2 g_iconv_close(iconvh); -#else - iconv_close(iconvh); -#endif iconvh = iconvhBad; } } @@ -77,11 +64,7 @@ public: if (!Succeeded()) { return (size_t)(-1); } else { -#if GTK_MAJOR_VERSION >= 2 return iconv_adaptor(g_iconv, iconvh, src, srcleft, dst, dstleft); -#else - return iconv_adaptor(iconv, iconvh, src, srcleft, dst, dstleft); -#endif } } }; diff --git a/plugins/scintilla/scintilla/Decoration.h b/plugins/scintilla/scintilla/Decoration.h index 2809641..fedff97 100644 --- a/plugins/scintilla/scintilla/Decoration.h +++ b/plugins/scintilla/scintilla/Decoration.h @@ -40,10 +40,10 @@ public: ~DecorationList(); void SetCurrentIndicator(int indicator); - int GetCurrentIndicator() { return currentIndicator; } + int GetCurrentIndicator() const { return currentIndicator; } void SetCurrentValue(int value); - int GetCurrentValue() { return currentValue; } + int GetCurrentValue() const { return currentValue; } // Returns true if some values may have changed bool FillRange(int &position, int value, int &fillLength); diff --git a/plugins/scintilla/scintilla/Document.cxx b/plugins/scintilla/scintilla/Document.cxx index a5d1adb..7b718f2 100644 --- a/plugins/scintilla/scintilla/Document.cxx +++ b/plugins/scintilla/scintilla/Document.cxx @@ -2,26 +2,34 @@ /** @file Document.cxx ** Text document that handles notifications, DBCS, styling, words and end of line. **/ -// Copyright 1998-2003 by Neil Hodgson +// Copyright 1998-2011 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 "Platform.h" +#include "ILexer.h" #include "Scintilla.h" + #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "CellBuffer.h" #include "PerLine.h" #include "CharClassify.h" +#include "CharacterSet.h" #include "Decoration.h" #include "Document.h" #include "RESearch.h" +#include "UniConversion.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -48,9 +56,38 @@ static inline bool IsUpperCase(char ch) { return isascii(ch) && isupper(ch); } +void LexInterface::Colourise(int start, int end) { + ElapsedTime et; + if (pdoc && instance && !performingStyle) { + // Protect against reentrance, which may occur, for example, when + // fold points are discovered while performing styling and the folding + // code looks for child lines which may trigger styling. + performingStyle = true; + + int lengthDoc = pdoc->Length(); + if (end == -1) + end = lengthDoc; + int len = end - start; + + PLATFORM_ASSERT(len >= 0); + PLATFORM_ASSERT(start + len <= lengthDoc); + + int styleStart = 0; + if (start > 0) + styleStart = pdoc->StyleAt(start - 1) & pdoc->stylingBitsMask; + + if (len > 0) { + instance->Lex(start, len, styleStart, pdoc); + instance->Fold(start, len, styleStart, pdoc); + } + + performingStyle = false; + } +} + Document::Document() { refCount = 0; -#ifdef unix +#ifdef __unix__ eolMode = SC_EOL_LF; #else eolMode = SC_EOL_CRLF; @@ -83,6 +120,8 @@ Document::Document() { perLineData[ldAnnotation] = new LineAnnotation(); cb.SetPerLine(this); + + pli = 0; } Document::~Document() { @@ -98,6 +137,8 @@ Document::~Document() { lenWatchers = 0; delete regex; regex = 0; + delete pli; + pli = 0; } void Document::Init() { @@ -140,13 +181,13 @@ void Document::SetSavePoint() { NotifySavePoint(true); } -int Document::GetMark(int line) { - return static_cast(perLineData[ldMarkers])->MarkValue(line); +int Document::GetMark(int line) { + return static_cast(perLineData[ldMarkers])->MarkValue(line); } int Document::AddMark(int line, int markerNum) { - if (line <= LinesTotal()) { - int prev = static_cast(perLineData[ldMarkers])-> + if (line >= 0 && line <= LinesTotal()) { + int prev = static_cast(perLineData[ldMarkers])-> AddMark(line, markerNum, LinesTotal()); DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); NotifyModified(mh); @@ -157,42 +198,49 @@ int Document::AddMark(int line, int markerNum) { } void Document::AddMarkSet(int line, int valueSet) { + if (line < 0 || line > LinesTotal()) { + return; + } unsigned int m = valueSet; for (int i = 0; m; i++, m >>= 1) if (m & 1) - static_cast(perLineData[ldMarkers])-> + static_cast(perLineData[ldMarkers])-> AddMark(line, i, LinesTotal()); DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::DeleteMark(int line, int markerNum) { - static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, false); + static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, false); DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::DeleteMarkFromHandle(int markerHandle) { - static_cast(perLineData[ldMarkers])->DeleteMarkFromHandle(markerHandle); + static_cast(perLineData[ldMarkers])->DeleteMarkFromHandle(markerHandle); DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); mh.line = -1; NotifyModified(mh); } void Document::DeleteAllMarks(int markerNum) { + bool someChanges = false; for (int line = 0; line < LinesTotal(); line++) { - static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, true); + if (static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, true)) + someChanges = true; + } + if (someChanges) { + DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); + mh.line = -1; + NotifyModified(mh); } - DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); - mh.line = -1; - NotifyModified(mh); } -int Document::LineFromHandle(int markerHandle) { - return static_cast(perLineData[ldMarkers])->LineFromHandle(markerHandle); +int Document::LineFromHandle(int markerHandle) { + return static_cast(perLineData[ldMarkers])->LineFromHandle(markerHandle); } -int Document::LineStart(int line) const { +int SCI_METHOD Document::LineStart(int line) const { return cb.LineStart(line); } @@ -209,7 +257,14 @@ int Document::LineEnd(int line) const { } } -int Document::LineFromPosition(int pos) const { +void SCI_METHOD Document::SetErrorStatus(int status) { + // Tell the watchers the lexer has changed. + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyErrorOccurred(this, watchers[i].userData, status); + } +} + +int SCI_METHOD Document::LineFromPosition(int pos) const { return cb.LineFromPosition(pos); } @@ -226,7 +281,7 @@ int Document::VCHomePosition(int position) const { int startPosition = LineStart(line); int endLine = LineEnd(line); int startText = startPosition; - while (startText < endLine && (cb.CharAt(startText) == ' ' || cb.CharAt(startText) == '\t' ) ) + while (startText < endLine && (cb.CharAt(startText) == ' ' || cb.CharAt(startText) == '\t')) startText++; if (position == startText) return startPosition; @@ -234,8 +289,8 @@ int Document::VCHomePosition(int position) const { return startText; } -int Document::SetLevel(int line, int level) { - int prev = static_cast(perLineData[ldLevels])->SetLevel(line, level, LinesTotal()); +int SCI_METHOD Document::SetLevel(int line, int level) { + int prev = static_cast(perLineData[ldLevels])->SetLevel(line, level, LinesTotal()); if (prev != level) { DocModification mh(SC_MOD_CHANGEFOLD | SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); @@ -246,12 +301,12 @@ int Document::SetLevel(int line, int level) { return prev; } -int Document::GetLevel(int line) { - return static_cast(perLineData[ldLevels])->GetLevel(line); +int SCI_METHOD Document::GetLevel(int line) const { + return static_cast(perLineData[ldLevels])->GetLevel(line); } -void Document::ClearLevels() { - static_cast(perLineData[ldLevels])->ClearLevels(); +void Document::ClearLevels() { + static_cast(perLineData[ldLevels])->ClearLevels(); } static bool IsSubordinate(int levelStart, int levelTry) { @@ -300,6 +355,110 @@ int Document::GetFoldParent(int line) { } } +void Document::GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, int line, int topLine, int bottomLine) { + int noNeedToParseBefore = Platform::Minimum(line, topLine) - 1; + int noNeedToParseAfter = Platform::Maximum(line, bottomLine) + 1; + int endLine = LineFromPosition(Length()); + int beginFoldBlock = noNeedToParseBefore; + int endFoldBlock = -1; + int beginMarginCorrectlyDrawnZone = noNeedToParseBefore; + int endMarginCorrectlyDrawnZone = noNeedToParseAfter; + int endOfTailOfWhiteFlag = -1; //endOfTailOfWhiteFlag points the last SC_FOLDLEVELWHITEFLAG if follow a fold block. Otherwise endOfTailOfWhiteFlag points end of fold block. + int level = GetLevel(line); + int levelNumber = -1; + int lineLookLevel = 0; + int lineLookLevelNumber = -1; + int lineLook = line; + bool beginFoldBlockFound = false; + bool endFoldBlockFound = false; + bool beginMarginCorrectlyDrawnZoneFound = false; + bool endMarginCorrectlyDrawnZoneFound = false; + + /*******************************************************************************/ + /* search backward (beginFoldBlock & beginMarginCorrectlyDrawnZone) */ + /*******************************************************************************/ + for (endOfTailOfWhiteFlag = line; (lineLook > noNeedToParseBefore || (lineLookLevel & SC_FOLDLEVELWHITEFLAG)) && (!beginFoldBlockFound || !beginMarginCorrectlyDrawnZoneFound); --lineLook) { + lineLookLevel = GetLevel(lineLook); + if (levelNumber != -1) { + lineLookLevelNumber = lineLookLevel & SC_FOLDLEVELNUMBERMASK; + if (!beginMarginCorrectlyDrawnZoneFound && (lineLookLevelNumber > levelNumber)) { + beginMarginCorrectlyDrawnZoneFound = true; + beginMarginCorrectlyDrawnZone = endOfTailOfWhiteFlag; + } + //find the last space line (SC_FOLDLEVELWHITEFLAG). + if (!beginMarginCorrectlyDrawnZoneFound && !(lineLookLevel & SC_FOLDLEVELWHITEFLAG)) { + endOfTailOfWhiteFlag = lineLook - 1; + } + if (!beginFoldBlockFound && (lineLookLevelNumber < levelNumber)) { + beginFoldBlockFound = true; + beginFoldBlock = lineLook; + if (!beginMarginCorrectlyDrawnZoneFound) { + beginMarginCorrectlyDrawnZoneFound = true; + beginMarginCorrectlyDrawnZone = lineLook - 1; + } + } else if (!beginFoldBlockFound && lineLookLevelNumber == SC_FOLDLEVELBASE) { + beginFoldBlockFound = true; + beginFoldBlock = -1; + } + } else if (!(lineLookLevel & SC_FOLDLEVELWHITEFLAG)) { + endOfTailOfWhiteFlag = lineLook - 1; + levelNumber = lineLookLevel & SC_FOLDLEVELNUMBERMASK; + if (lineLookLevel & SC_FOLDLEVELHEADERFLAG && + //Managed the folding block when a fold header does not have any subordinate lines to fold away. + (levelNumber < (GetLevel(lineLook + 1) & SC_FOLDLEVELNUMBERMASK))) { + beginFoldBlockFound = true; + beginFoldBlock = lineLook; + beginMarginCorrectlyDrawnZoneFound = true; + beginMarginCorrectlyDrawnZone = endOfTailOfWhiteFlag; + levelNumber = GetLevel(lineLook + 1) & SC_FOLDLEVELNUMBERMASK;; + } + } + } + + /****************************************************************************/ + /* search forward (endStartBlock & endMarginCorrectlyDrawnZone) */ + /****************************************************************************/ + if (level & SC_FOLDLEVELHEADERFLAG) { + //ignore this line because this line is on first one of block. + lineLook = line + 1; + } else { + lineLook = line; + } + for (; lineLook < noNeedToParseAfter && (!endFoldBlockFound || !endMarginCorrectlyDrawnZoneFound); ++lineLook) { + lineLookLevel = GetLevel(lineLook); + lineLookLevelNumber = lineLookLevel & SC_FOLDLEVELNUMBERMASK; + if (!endFoldBlockFound && !(lineLookLevel & SC_FOLDLEVELWHITEFLAG) && lineLookLevelNumber < levelNumber) { + endFoldBlockFound = true; + endFoldBlock = lineLook - 1; + if (!endMarginCorrectlyDrawnZoneFound) { + endMarginCorrectlyDrawnZoneFound = true; + endMarginCorrectlyDrawnZone = lineLook; + } + } else if (!endFoldBlockFound && lineLookLevel == SC_FOLDLEVELBASE) { + endFoldBlockFound = true; + endFoldBlock = -1; + } + if (!endMarginCorrectlyDrawnZoneFound && (lineLookLevel & SC_FOLDLEVELHEADERFLAG) && + //Managed the folding block when a fold header does not have any subordinate lines to fold away. + (levelNumber < (GetLevel(lineLook + 1) & SC_FOLDLEVELNUMBERMASK))) { + endMarginCorrectlyDrawnZoneFound = true; + endMarginCorrectlyDrawnZone = lineLook; + } + } + if (!endFoldBlockFound && ((lineLook > endLine && lineLookLevelNumber < levelNumber) || + (levelNumber > SC_FOLDLEVELBASE))) { + //manage when endfold is incorrect or on last line. + endFoldBlock = lineLook - 1; + //useless to set endMarginCorrectlyDrawnZone. + //if endMarginCorrectlyDrawnZoneFound equals false then endMarginCorrectlyDrawnZone already equals to endLine + 1. + } + + highlightDelimiter.beginFoldBlock = beginFoldBlock; + highlightDelimiter.endFoldBlock = endFoldBlock; + highlightDelimiter.beginMarginCorrectlyDrawnZone = beginMarginCorrectlyDrawnZone; + highlightDelimiter.endMarginCorrectlyDrawnZone = endMarginCorrectlyDrawnZone; +} + int Document::ClampPositionIntoDocument(int pos) { return Platform::Clamp(pos, 0, Length()); } @@ -312,8 +471,6 @@ bool Document::IsCrLf(int pos) { return (cb.CharAt(pos) == '\r') && (cb.CharAt(pos + 1) == '\n'); } -static const int maxBytesInDBCSCharacter=5; - int Document::LenChar(int pos) { if (pos < 0) { return 1; @@ -334,13 +491,7 @@ int Document::LenChar(int pos) { else return len; } else if (dbcsCodePage) { - char mbstr[maxBytesInDBCSCharacter+1]; - int i; - for (i=0; i0) && (pos-lead < 4) && IsTrailByte(static_cast(cb.CharAt(lead-1)))) lead--; @@ -416,8 +567,6 @@ int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { return pos - 1; } - // Not between CR and LF - if (dbcsCodePage) { if (SC_CP_UTF8 == dbcsCodePage) { unsigned char ch = static_cast(cb.CharAt(pos)); @@ -433,16 +582,18 @@ int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. - int posCheck = LineStart(LineFromPosition(pos)); - while (posCheck < pos) { - char mbstr[maxBytesInDBCSCharacter+1]; - int i; - for(i=0;i posStartLine) && IsDBCSLeadByte(cb.CharAt(posCheck-1))) + posCheck--; - int mbsize = Platform::DBCSCharLength(dbcsCodePage, mbstr); + // Check from known start of character. + while (posCheck < pos) { + int mbsize = IsDBCSLeadByte(cb.CharAt(posCheck)) ? 2 : 1; if (posCheck + mbsize == pos) { return pos; } else if (posCheck + mbsize > pos) { @@ -460,6 +611,157 @@ int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { return pos; } +// NextPosition moves between valid positions - it can not handle a position in the middle of a +// multi-byte character. It is used to iterate through text more efficiently than MovePositionOutsideChar. +// A \r\n pair is treated as two characters. +int Document::NextPosition(int pos, int moveDir) const { + // If out of range, just return minimum/maximum value. + int increment = (moveDir > 0) ? 1 : -1; + if (pos + increment <= 0) + return 0; + if (pos + increment >= Length()) + return Length(); + + if (dbcsCodePage) { + if (SC_CP_UTF8 == dbcsCodePage) { + pos += increment; + unsigned char ch = static_cast(cb.CharAt(pos)); + int startUTF = pos; + int endUTF = pos; + if (IsTrailByte(ch) && InGoodUTF8(pos, startUTF, endUTF)) { + // ch is a trail byte within a UTF-8 character + if (moveDir > 0) + pos = endUTF; + else + pos = startUTF; + } + } else { + if (moveDir > 0) { + int mbsize = IsDBCSLeadByte(cb.CharAt(pos)) ? 2 : 1; + pos += mbsize; + if (pos > Length()) + pos = Length(); + } else { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int posStartLine = LineStart(LineFromPosition(pos)); + // See http://msdn.microsoft.com/en-us/library/cc194792%28v=MSDN.10%29.aspx + // http://msdn.microsoft.com/en-us/library/cc194790.aspx + if ((pos - 1) <= posStartLine) { + return pos - 1; + } else if (IsDBCSLeadByte(cb.CharAt(pos - 1))) { + // Must actually be trail byte + return pos - 2; + } else { + // Otherwise, step back until a non-lead-byte is found. + int posTemp = pos - 1; + while (posStartLine <= --posTemp && IsDBCSLeadByte(cb.CharAt(posTemp))) + ; + // Now posTemp+1 must point to the beginning of a character, + // so figure out whether we went back an even or an odd + // number of bytes and go back 1 or 2 bytes, respectively. + return (pos - 1 - ((pos - posTemp) & 1)); + } + } + } + } else { + pos += increment; + } + + return pos; +} + +bool Document::NextCharacter(int &pos, int moveDir) { + // Returns true if pos changed + int posNext = NextPosition(pos, moveDir); + if (posNext == pos) { + return false; + } else { + pos = posNext; + return true; + } +} + +int SCI_METHOD Document::CodePage() const { + return dbcsCodePage; +} + +bool SCI_METHOD Document::IsDBCSLeadByte(char ch) const { + // Byte ranges found in Wikipedia articles with relevant search strings in each case + unsigned char uch = static_cast(ch); + switch (dbcsCodePage) { + case 932: + // Shift_jis + return ((uch >= 0x81) && (uch <= 0x9F)) || + ((uch >= 0xE0) && (uch <= 0xEF)); + case 936: + // GBK + return (uch >= 0x81) && (uch <= 0xFE); + case 949: + // Korean Wansung KS C-5601-1987 + return (uch >= 0x81) && (uch <= 0xFE); + case 950: + // Big5 + return (uch >= 0x81) && (uch <= 0xFE); + case 1361: + // Korean Johab KS C-5601-1992 + return + ((uch >= 0x84) && (uch <= 0xD3)) || + ((uch >= 0xD8) && (uch <= 0xDE)) || + ((uch >= 0xE0) && (uch <= 0xF9)); + } + return false; +} + +inline bool IsSpaceOrTab(int ch) { + return ch == ' ' || ch == '\t'; +} + +// Need to break text into segments near lengthSegment but taking into +// account the encoding to not break inside a UTF-8 or DBCS character +// and also trying to avoid breaking inside a pair of combining characters. +// The segment length must always be long enough (more than 4 bytes) +// so that there will be at least one whole character to make a segment. +// For UTF-8, text must consist only of valid whole characters. +// In preference order from best to worst: +// 1) Break after space +// 2) Break before punctuation +// 3) Break after whole character + +int Document::SafeSegment(const char *text, int length, int lengthSegment) { + if (length <= lengthSegment) + return length; + int lastSpaceBreak = -1; + int lastPunctuationBreak = -1; + int lastEncodingAllowedBreak = -1; + for (int j=0; j < lengthSegment;) { + unsigned char ch = static_cast(text[j]); + if (j > 0) { + if (IsSpaceOrTab(text[j - 1]) && !IsSpaceOrTab(text[j])) { + lastSpaceBreak = j; + } + if (ch < 'A') { + lastPunctuationBreak = j; + } + } + lastEncodingAllowedBreak = j; + + if (dbcsCodePage == SC_CP_UTF8) { + j += (ch < 0x80) ? 1 : BytesFromLead(ch); + } else if (dbcsCodePage) { + j += IsDBCSLeadByte(ch) ? 2 : 1; + } else { + j++; + } + } + if (lastSpaceBreak >= 0) { + return lastSpaceBreak; + } else if (lastPunctuationBreak >= 0) { + return lastPunctuationBreak; + } + return lastEncodingAllowedBreak; +} + void Document::ModifiedAt(int pos) { if (endStyled > pos) endStyled = pos; @@ -702,7 +1004,7 @@ void Document::DelCharBack(int pos) { } else if (IsCrLf(pos - 2)) { DeleteChars(pos - 2, 2); } else if (dbcsCodePage) { - int startChar = MovePositionOutsideChar(pos - 1, -1, false); + int startChar = NextPosition(pos, -1); DeleteChars(startChar, pos - startChar); } else { DeleteChars(pos - 1, 1); @@ -734,12 +1036,12 @@ static void CreateIndentation(char *linebuf, int length, int indent, int tabSize *linebuf = '\0'; } -int Document::GetLineIndentation(int line) { +int SCI_METHOD Document::GetLineIndentation(int line) { int indent = 0; if ((line >= 0) && (line < LinesTotal())) { int lineStart = LineStart(line); int length = Length(); - for (int i = lineStart;i < length;i++) { + for (int i = lineStart; i < length; i++) { char ch = cb.CharAt(i); if (ch == ' ') indent++; @@ -782,7 +1084,7 @@ int Document::GetColumn(int pos) { int column = 0; int line = LineFromPosition(pos); if ((line >= 0) && (line < LinesTotal())) { - for (int i = LineStart(line);i < pos;) { + for (int i = LineStart(line); i < pos;) { char ch = cb.CharAt(i); if (ch == '\t') { column = NextTab(column, tabInChars); @@ -795,7 +1097,7 @@ int Document::GetColumn(int pos) { return column; } else { column++; - i = MovePositionOutsideChar(i + 1, 1, false); + i = NextPosition(i, 1); } } } @@ -817,7 +1119,7 @@ int Document::FindColumn(int line, int column) { return position; } else { columnCurrent++; - position = MovePositionOutsideChar(position + 1, 1, false); + position = NextPosition(position, 1); } } } @@ -969,7 +1271,7 @@ int Document::ExtendWordSelect(int pos, int delta, bool onlyWordCharacters) { while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart)) pos++; } - return MovePositionOutsideChar(pos, delta); + return MovePositionOutsideChar(pos, delta, true); } /** @@ -1074,79 +1376,199 @@ static inline char MakeLowerCase(char ch) { return static_cast(ch - 'A' + 'a'); } +static bool GoodTrailByte(int v) { + return (v >= 0x80) && (v < 0xc0); +} + +size_t Document::ExtractChar(int pos, char *bytes) { + unsigned char ch = static_cast(cb.CharAt(pos)); + size_t widthChar = UTF8CharLength(ch); + bytes[0] = ch; + for (size_t i=1; i(bytes[i]))) { // Bad byte + widthChar = 1; + } + } + return widthChar; +} + +CaseFolderTable::CaseFolderTable() { + for (size_t iChar=0; iChar(iChar); + } +} + +CaseFolderTable::~CaseFolderTable() { +} + +size_t CaseFolderTable::Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { + if (lenMixed > sizeFolded) { + return 0; + } else { + for (size_t i=0; i(mixed[i])]; + } + return lenMixed; + } +} + +void CaseFolderTable::SetTranslation(char ch, char chTranslation) { + mapping[static_cast(ch)] = chTranslation; +} + +void CaseFolderTable::StandardASCII() { + for (size_t iChar=0; iChar= 'A' && iChar <= 'Z') { + mapping[iChar] = static_cast(iChar - 'A' + 'a'); + } else { + mapping[iChar] = static_cast(iChar); + } + } +} + +bool Document::MatchesWordOptions(bool word, bool wordStart, int pos, int length) { + return (!word && !wordStart) || + (word && IsWordAt(pos, pos + length)) || + (wordStart && IsWordStartAt(pos)); +} + /** * Find text in document, supporting both forward and backward * searches (just pass minPos > maxPos to do a backward search) * Has not been tested with backwards DBCS searches yet. */ -long Document::FindText(int minPos, int maxPos, const char *s, +long Document::FindText(int minPos, int maxPos, const char *search, bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, - int *length) { + int *length, CaseFolder *pcf) { + if (*length <= 0) + return minPos; if (regExp) { if (!regex) regex = CreateRegexSearch(&charClass); - return regex->FindText(this, minPos, maxPos, s, caseSensitive, word, wordStart, flags, length); + return regex->FindText(this, minPos, maxPos, search, caseSensitive, word, wordStart, flags, length); } else { - bool forward = minPos <= maxPos; - int increment = forward ? 1 : -1; + const bool forward = minPos <= maxPos; + const int increment = forward ? 1 : -1; // Range endpoints should not be inside DBCS characters, but just in case, move them. - int startPos = MovePositionOutsideChar(minPos, increment, false); - int endPos = MovePositionOutsideChar(maxPos, increment, false); + const int startPos = MovePositionOutsideChar(minPos, increment, false); + const int endPos = MovePositionOutsideChar(maxPos, increment, false); // Compute actual search ranges needed - int lengthFind = *length; - if (lengthFind == -1) - lengthFind = static_cast(strlen(s)); - int endSearch = endPos; - if (startPos <= endPos) { - endSearch = endPos - lengthFind + 1; - } + const int lengthFind = (*length == -1) ? static_cast(strlen(search)) : *length; + const int endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos; + //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); - char firstChar = s[0]; - if (!caseSensitive) - firstChar = static_cast(MakeUpperCase(firstChar)); - int pos = forward ? startPos : (startPos - 1); - while (forward ? (pos < endSearch) : (pos >= endSearch)) { - char ch = CharAt(pos); - if (caseSensitive) { - if (ch == firstChar) { - bool found = true; - if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false; - for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { - ch = CharAt(pos + posMatch); - if (ch != s[posMatch]) - found = false; - } - if (found) { - if ((!word && !wordStart) || - (word && IsWordAt(pos, pos + lengthFind)) || - (wordStart && IsWordStartAt(pos))) - return pos; - } + const int limitPos = Platform::Maximum(startPos, endPos); + int pos = startPos; + if (!forward) { + // Back all of a character + pos = NextPosition(pos, increment); + } + if (caseSensitive) { + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + bool found = (pos + lengthFind) <= limitPos; + for (int indexSearch = 0; (indexSearch < lengthFind) && found; indexSearch++) { + found = CharAt(pos + indexSearch) == search[indexSearch]; } - } else { - if (MakeUpperCase(ch) == firstChar) { - bool found = true; - if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false; - for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { - ch = CharAt(pos + posMatch); - if (MakeUpperCase(ch) != MakeUpperCase(s[posMatch])) - found = false; + if (found && MatchesWordOptions(word, wordStart, pos, lengthFind)) { + return pos; + } + if (!NextCharacter(pos, increment)) + break; + } + } else if (SC_CP_UTF8 == dbcsCodePage) { + const size_t maxBytesCharacter = 4; + const size_t maxFoldingExpansion = 4; + std::vector searchThing(lengthFind * maxBytesCharacter * maxFoldingExpansion + 1); + const int lenSearch = pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + int widthFirstCharacter = 0; + int indexDocument = 0; + int indexSearch = 0; + bool characterMatches = true; + while (characterMatches && + ((pos + indexDocument) < limitPos) && + (indexSearch < lenSearch)) { + char bytes[maxBytesCharacter + 1]; + bytes[maxBytesCharacter] = 0; + const int widthChar = ExtractChar(pos + indexDocument, bytes); + if (!widthFirstCharacter) + widthFirstCharacter = widthChar; + char folded[maxBytesCharacter * maxFoldingExpansion + 1]; + const int lenFlat = pcf->Fold(folded, sizeof(folded), bytes, widthChar); + folded[lenFlat] = 0; + // Does folded match the buffer + characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat); + indexDocument += widthChar; + indexSearch += lenFlat; + } + if (characterMatches && (indexSearch == static_cast(lenSearch))) { + if (MatchesWordOptions(word, wordStart, pos, indexDocument)) { + *length = indexDocument; + return pos; } - if (found) { - if ((!word && !wordStart) || - (word && IsWordAt(pos, pos + lengthFind)) || - (wordStart && IsWordStartAt(pos))) - return pos; + } + if (forward) { + pos += widthFirstCharacter; + } else { + if (!NextCharacter(pos, increment)) + break; + } + } + } else if (dbcsCodePage) { + const size_t maxBytesCharacter = 2; + const size_t maxFoldingExpansion = 4; + std::vector searchThing(lengthFind * maxBytesCharacter * maxFoldingExpansion + 1); + const int lenSearch = pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + int indexDocument = 0; + int indexSearch = 0; + bool characterMatches = true; + while (characterMatches && + ((pos + indexDocument) < limitPos) && + (indexSearch < lenSearch)) { + char bytes[maxBytesCharacter + 1]; + bytes[0] = cb.CharAt(pos + indexDocument); + const int widthChar = IsDBCSLeadByte(bytes[0]) ? 2 : 1; + if (widthChar == 2) + bytes[1] = cb.CharAt(pos + indexDocument + 1); + char folded[maxBytesCharacter * maxFoldingExpansion + 1]; + const int lenFlat = pcf->Fold(folded, sizeof(folded), bytes, widthChar); + folded[lenFlat] = 0; + // Does folded match the buffer + characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat); + indexDocument += widthChar; + indexSearch += lenFlat; + } + if (characterMatches && (indexSearch == static_cast(lenSearch))) { + if (MatchesWordOptions(word, wordStart, pos, indexDocument)) { + *length = indexDocument; + return pos; } } + if (!NextCharacter(pos, increment)) + break; } - pos += increment; - if (dbcsCodePage && (pos >= 0)) { - // Ensure trying to match from start of character - pos = MovePositionOutsideChar(pos, increment, false); + } else { + CaseFolderTable caseFolder; + std::vector searchThing(lengthFind + 1); + pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + bool found = (pos + lengthFind) <= limitPos; + for (int indexSearch = 0; (indexSearch < lengthFind) && found; indexSearch++) { + char ch = CharAt(pos + indexSearch); + char folded[2]; + pcf->Fold(folded, sizeof(folded), &ch, 1); + found = folded[0] == searchThing[indexSearch]; + } + if (found && MatchesWordOptions(word, wordStart, pos, lengthFind)) { + return pos; + } + if (!NextCharacter(pos, increment)) + break; } } } @@ -1155,7 +1577,10 @@ long Document::FindText(int minPos, int maxPos, const char *s, } const char *Document::SubstituteByPosition(const char *text, int *length) { - return regex->SubstituteByPosition(this, text, length); + if (regex) + return regex->SubstituteByPosition(this, text, length); + else + return 0; } int Document::LinesTotal() const { @@ -1194,12 +1619,12 @@ void Document::SetStylingBits(int bits) { stylingBitsMask = (1 << stylingBits) - 1; } -void Document::StartStyling(int position, char mask) { +void SCI_METHOD Document::StartStyling(int position, char mask) { stylingMask = mask; endStyled = position; } -bool Document::SetStyleFor(int length, char style) { +bool SCI_METHOD Document::SetStyleFor(int length, char style) { if (enteredStyling != 0) { return false; } else { @@ -1217,7 +1642,7 @@ bool Document::SetStyleFor(int length, char style) { } } -bool Document::SetStyles(int length, const char *styles) { +bool SCI_METHOD Document::SetStyles(int length, const char *styles) { if (enteredStyling != 0) { return false; } else { @@ -1248,75 +1673,93 @@ bool Document::SetStyles(int length, const char *styles) { void Document::EnsureStyledTo(int pos) { if ((enteredStyling == 0) && (pos > GetEndStyled())) { IncrementStyleClock(); - // Ask the watchers to style, and stop as soon as one responds. - for (int i = 0; pos > GetEndStyled() && i < lenWatchers; i++) { - watchers[i].watcher->NotifyStyleNeeded(this, watchers[i].userData, pos); + if (pli && !pli->UseContainerLexing()) { + int lineEndStyled = LineFromPosition(GetEndStyled()); + int endStyledTo = LineStart(lineEndStyled); + pli->Colourise(endStyledTo, pos); + } else { + // Ask the watchers to style, and stop as soon as one responds. + for (int i = 0; pos > GetEndStyled() && i < lenWatchers; i++) { + watchers[i].watcher->NotifyStyleNeeded(this, watchers[i].userData, pos); + } } } } -int Document::SetLineState(int line, int state) { - int statePrevious = static_cast(perLineData[ldState])->SetLineState(line, state); +void Document::LexerChanged() { + // Tell the watchers the lexer has changed. + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyLexerChanged(this, watchers[i].userData); + } +} + +int SCI_METHOD Document::SetLineState(int line, int state) { + int statePrevious = static_cast(perLineData[ldState])->SetLineState(line, state); if (state != statePrevious) { - DocModification mh(SC_MOD_CHANGELINESTATE, 0, 0, 0, 0, line); + DocModification mh(SC_MOD_CHANGELINESTATE, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } return statePrevious; } -int Document::GetLineState(int line) { - return static_cast(perLineData[ldState])->GetLineState(line); +int SCI_METHOD Document::GetLineState(int line) const { + return static_cast(perLineData[ldState])->GetLineState(line); } -int Document::GetMaxLineState() { - return static_cast(perLineData[ldState])->GetMaxLineState(); +int Document::GetMaxLineState() { + return static_cast(perLineData[ldState])->GetMaxLineState(); +} + +void SCI_METHOD Document::ChangeLexerState(int start, int end) { + DocModification mh(SC_MOD_LEXERSTATE, start, end-start, 0, 0, 0); + NotifyModified(mh); } StyledText Document::MarginStyledText(int line) { - LineAnnotation *pla = static_cast(perLineData[ldMargin]); - return StyledText(pla->Length(line), pla->Text(line), + LineAnnotation *pla = static_cast(perLineData[ldMargin]); + return StyledText(pla->Length(line), pla->Text(line), pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); } void Document::MarginSetText(int line, const char *text) { - static_cast(perLineData[ldMargin])->SetText(line, text); + static_cast(perLineData[ldMargin])->SetText(line, text); DocModification mh(SC_MOD_CHANGEMARGIN, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::MarginSetStyle(int line, int style) { - static_cast(perLineData[ldMargin])->SetStyle(line, style); + static_cast(perLineData[ldMargin])->SetStyle(line, style); } void Document::MarginSetStyles(int line, const unsigned char *styles) { - static_cast(perLineData[ldMargin])->SetStyles(line, styles); + static_cast(perLineData[ldMargin])->SetStyles(line, styles); } int Document::MarginLength(int line) const { - return static_cast(perLineData[ldMargin])->Length(line); + return static_cast(perLineData[ldMargin])->Length(line); } void Document::MarginClearAll() { int maxEditorLine = LinesTotal(); - for (int l=0;l(perLineData[ldMargin])->ClearAll(); + static_cast(perLineData[ldMargin])->ClearAll(); } bool Document::AnnotationAny() const { - return static_cast(perLineData[ldAnnotation])->AnySet(); + return static_cast(perLineData[ldAnnotation])->AnySet(); } StyledText Document::AnnotationStyledText(int line) { - LineAnnotation *pla = static_cast(perLineData[ldAnnotation]); - return StyledText(pla->Length(line), pla->Text(line), + LineAnnotation *pla = static_cast(perLineData[ldAnnotation]); + return StyledText(pla->Length(line), pla->Text(line), pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); } void Document::AnnotationSetText(int line, const char *text) { const int linesBefore = AnnotationLines(line); - static_cast(perLineData[ldAnnotation])->SetText(line, text); + static_cast(perLineData[ldAnnotation])->SetText(line, text); const int linesAfter = AnnotationLines(line); DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); mh.annotationLinesAdded = linesAfter - linesBefore; @@ -1324,34 +1767,36 @@ void Document::AnnotationSetText(int line, const char *text) { } void Document::AnnotationSetStyle(int line, int style) { - static_cast(perLineData[ldAnnotation])->SetStyle(line, style); + static_cast(perLineData[ldAnnotation])->SetStyle(line, style); + DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); + NotifyModified(mh); } void Document::AnnotationSetStyles(int line, const unsigned char *styles) { - static_cast(perLineData[ldAnnotation])->SetStyles(line, styles); + static_cast(perLineData[ldAnnotation])->SetStyles(line, styles); } int Document::AnnotationLength(int line) const { - return static_cast(perLineData[ldAnnotation])->Length(line); + return static_cast(perLineData[ldAnnotation])->Length(line); } int Document::AnnotationLines(int line) const { - return static_cast(perLineData[ldAnnotation])->Lines(line); + return static_cast(perLineData[ldAnnotation])->Lines(line); } void Document::AnnotationClearAll() { int maxEditorLine = LinesTotal(); - for (int l=0;l(perLineData[ldAnnotation])->ClearAll(); + static_cast(perLineData[ldAnnotation])->ClearAll(); } void Document::IncrementStyleClock() { styleClock = (styleClock + 1) % 0x100000; } -void Document::DecorationFillRange(int position, int value, int fillLength) { +void SCI_METHOD Document::DecorationFillRange(int position, int value, int fillLength) { if (decorations.FillRange(position, value, fillLength)) { DocModification mh(SC_MOD_CHANGEINDICATOR | SC_PERFORMED_USER, position, fillLength); @@ -1523,11 +1968,11 @@ bool IsLineEndChar(char c) { int Document::ExtendStyleRange(int pos, int delta, bool singleLine) { int sStart = cb.StyleAt(pos); if (delta < 0) { - while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos))) ) + while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) pos--; pos++; } else { - while (pos < (Length()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos))) ) + while (pos < (Length()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) pos++; } return pos; @@ -1567,9 +2012,8 @@ int Document::BraceMatch(int position, int /*maxReStyle*/) { if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') direction = 1; int depth = 1; - position = position + direction; + position = NextPosition(position, direction); while ((position >= 0) && (position < Length())) { - position = MovePositionOutsideChar(position, direction); char chAtPos = CharAt(position); char styAtPos = static_cast(StyleAt(position) & stylingBitsMask); if ((position > GetEndStyled()) || (styAtPos == styBrace)) { @@ -1580,7 +2024,10 @@ int Document::BraceMatch(int position, int /*maxReStyle*/) { if (depth == 0) return position; } - position = position + direction; + int positionBeforeMove = position; + position = NextPosition(position, direction); + if (position == positionBeforeMove) + break; } return - 1; } @@ -1600,7 +2047,7 @@ public: bool caseSensitive, bool word, bool wordStart, int flags, int *length); - virtual const char *SubstituteByPosition(Document* doc, const char *text, int *length); + virtual const char *SubstituteByPosition(Document *doc, const char *text, int *length); private: RESearch search; @@ -1656,6 +2103,12 @@ long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s // the start position is at end of line or between line end characters. lineRangeStart++; startPos = doc->LineStart(lineRangeStart); + } else if ((increment == -1) && + (startPos <= doc->LineStart(lineRangeStart)) && + (lineRangeStart > lineRangeEnd)) { + // the start position is at beginning of line. + lineRangeStart--; + startPos = doc->LineEnd(lineRangeStart); } int pos = -1; int lenRet = 0; @@ -1693,7 +2146,8 @@ long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s if (success) { pos = search.bopat[0]; lenRet = search.eopat[0] - search.bopat[0]; - if (increment == -1) { + // There can be only one start of a line, so no need to look for last match in line + if ((increment == -1) && (s[0] != '^')) { // Check for the last match on this line. int repetitions = 1000; // Break out of infinite loop while (success && (search.eopat[0] <= endOfLine) && (repetitions--)) { @@ -1715,7 +2169,7 @@ long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s return pos; } -const char *BuiltinRegex::SubstituteByPosition(Document* doc, const char *text, int *length) { +const char *BuiltinRegex::SubstituteByPosition(Document *doc, const char *text, int *length) { delete []substituted; substituted = 0; DocumentIndexer di(doc, doc->Length()); @@ -1737,6 +2191,7 @@ const char *BuiltinRegex::SubstituteByPosition(Document* doc, const char *text, case 'r': case 't': case 'v': + case '\\': i++; } lenResult++; @@ -1780,6 +2235,9 @@ const char *BuiltinRegex::SubstituteByPosition(Document* doc, const char *text, case 'v': *o++ = '\v'; break; + case '\\': + *o++ = '\\'; + break; default: *o++ = '\\'; j--; diff --git a/plugins/scintilla/scintilla/Document.h b/plugins/scintilla/scintilla/Document.h index 240d59e..7858db7 100644 --- a/plugins/scintilla/scintilla/Document.h +++ b/plugins/scintilla/scintilla/Document.h @@ -2,7 +2,7 @@ /** @file Document.h ** Text document that handles notifications, DBCS, styling, words and end of line. **/ -// Copyright 1998-2003 by Neil Hodgson +// Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DOCUMENT_H @@ -32,10 +32,10 @@ public: Range(Position pos=0) : start(pos), end(pos) { - }; + } Range(Position start_, Position end_) : start(start_), end(end_) { - }; + } bool Valid() const { return (start != invalidPosition) && (end != invalidPosition); @@ -81,17 +81,17 @@ class Document; */ class RegexSearchBase { public: - virtual ~RegexSearchBase(){} + virtual ~RegexSearchBase() {} - virtual long FindText(Document* doc, int minPos, int maxPos, const char *s, + virtual long FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, int *length) = 0; ///@return String with the substitutions, must remain valid until the next call or destruction - virtual const char *SubstituteByPosition(Document* doc, const char *text, int *length) = 0; + virtual const char *SubstituteByPosition(Document *doc, const char *text, int *length) = 0; }; /// Factory function for RegexSearchBase -extern RegexSearchBase* CreateRegexSearch(CharClassify *charClassTable); +extern RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable); struct StyledText { size_t length; @@ -99,7 +99,7 @@ struct StyledText { bool multipleStyles; size_t style; const unsigned char *styles; - StyledText( size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) : + StyledText(size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) : length(length_), text(text_), multipleStyles(multipleStyles_), style(style_), styles(styles_) { } // Return number of bytes from start to before '\n' or end of text. @@ -115,9 +115,86 @@ struct StyledText { } }; +class HighlightDelimiter { +public: + HighlightDelimiter() { + beginFoldBlock = -1; + endFoldBlock = -1; + beginMarginCorrectlyDrawnZone = -1; + endMarginCorrectlyDrawnZone = -1; + isEnabled = false; + } + + bool NeedsDrawing(int line) { + return isEnabled && (line <= beginMarginCorrectlyDrawnZone || endMarginCorrectlyDrawnZone <= line); + } + + bool isCurrentBlockHighlight(int line) { + return isEnabled && beginFoldBlock != -1 && beginFoldBlock <= line && line <= endFoldBlock; + } + + bool isHeadBlockFold(int line) { + return beginFoldBlock == line && line < endFoldBlock; + } + + bool isBodyBlockFold(int line) { + return beginFoldBlock != -1 && beginFoldBlock < line && line < endFoldBlock; + } + + bool isTailBlockFold(int line) { + return beginFoldBlock != -1 && beginFoldBlock < line && line == endFoldBlock; + } + + // beginFoldBlock : Begin of current fold block. + // endStartBlock : End of current fold block. + // beginMarginCorrectlyDrawnZone : Begin of zone where margin is correctly drawn. + // endMarginCorrectlyDrawnZone : End of zone where margin is correctly drawn. + int beginFoldBlock; + int endFoldBlock; + int beginMarginCorrectlyDrawnZone; + int endMarginCorrectlyDrawnZone; + bool isEnabled; +}; + +class CaseFolder { +public: + virtual ~CaseFolder() { + } + virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) = 0; +}; + +class CaseFolderTable : public CaseFolder { +protected: + char mapping[256]; +public: + CaseFolderTable(); + virtual ~CaseFolderTable(); + virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed); + void SetTranslation(char ch, char chTranslation); + void StandardASCII(); +}; + +class Document; + +class LexInterface { +protected: + Document *pdoc; + ILexer *instance; + bool performingStyle; ///< Prevent reentrance +public: + LexInterface(Document *pdoc_) : pdoc(pdoc_), instance(0), performingStyle(false) { + } + virtual ~LexInterface() { + } + void Colourise(int start, int end); + bool UseContainerLexing() const { + return instance == 0; + } +}; + /** */ -class Document : PerLine { +class Document : PerLine, public IDocument { public: /** Used to pair watcher pointer with user data. */ @@ -147,13 +224,16 @@ private: int lenWatchers; // ldSize is not real data - it is for dimensions and loops - enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; + enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; PerLine *perLineData[ldSize]; bool matchesValid; - RegexSearchBase* regex; + RegexSearchBase *regex; public: + + LexInterface *pli; + int stylingBits; int stylingBitsMask; @@ -179,12 +259,23 @@ public: virtual void InsertLine(int line); virtual void RemoveLine(int line); - int LineFromPosition(int pos) const; + int SCI_METHOD Version() const { + return dvOriginal; + } + + void SCI_METHOD SetErrorStatus(int status); + + int SCI_METHOD LineFromPosition(int pos) const; int ClampPositionIntoDocument(int pos); bool IsCrLf(int pos); int LenChar(int pos); - bool InGoodUTF8(int pos, int &start, int &end); + bool InGoodUTF8(int pos, int &start, int &end) const; int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); + int NextPosition(int pos, int moveDir) const; + bool NextCharacter(int &pos, int moveDir); // Returns true if pos changed + int SCI_METHOD CodePage() const; + bool SCI_METHOD IsDBCSLeadByte(char ch) const; + int SafeSegment(const char *text, int length, int lengthSegment); // Gateways to modifying document void ModifiedAt(int pos); @@ -205,9 +296,9 @@ public: void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } void SetSavePoint(); bool IsSavePoint() { return cb.IsSavePoint(); } - const char *BufferPointer() { return cb.BufferPointer(); } + const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); } - int GetLineIndentation(int line); + int SCI_METHOD GetLineIndentation(int line); void SetLineIndentation(int line, int indent); int GetLineIndentPosition(int line) const; int GetColumn(int position); @@ -225,10 +316,13 @@ public: void DelCharBack(int pos); char CharAt(int position) { return cb.CharAt(position); } - void GetCharRange(char *buffer, int position, int lengthRetrieve) { + void SCI_METHOD GetCharRange(char *buffer, int position, int lengthRetrieve) const { cb.GetCharRange(buffer, position, lengthRetrieve); } - char StyleAt(int position) { return cb.StyleAt(position); } + char SCI_METHOD StyleAt(int position) const { return cb.StyleAt(position); } + void GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const { + cb.GetStyleRange(buffer, position, lengthRetrieve); + } int GetMark(int line); int AddMark(int line, int markerNum); void AddMarkSet(int line, int valueSet); @@ -236,27 +330,29 @@ public: void DeleteMarkFromHandle(int markerHandle); void DeleteAllMarks(int markerNum); int LineFromHandle(int markerHandle); - int LineStart(int line) const; + int SCI_METHOD LineStart(int line) const; int LineEnd(int line) const; int LineEndPosition(int position) const; bool IsLineEndPosition(int position) const; int VCHomePosition(int position) const; - int SetLevel(int line, int level); - int GetLevel(int line); + int SCI_METHOD SetLevel(int line, int level); + int SCI_METHOD GetLevel(int line) const; void ClearLevels(); int GetLastChild(int lineParent, int level=-1); int GetFoldParent(int line); + void GetHighlightDelimiters(HighlightDelimiter &hDelimiter, int line, int topLine, int bottomLine); void Indent(bool forwards); int ExtendWordSelect(int pos, int delta, bool onlyWordCharacters=false); int NextWordStart(int pos, int delta); int NextWordEnd(int pos, int delta); - int Length() const { return cb.Length(); } + int SCI_METHOD Length() const { return cb.Length(); } void Allocate(int newSize) { cb.Allocate(newSize); } - long FindText(int minPos, int maxPos, const char *s, - bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, int *length); - long FindText(int iMessage, unsigned long wParam, long lParam); + size_t ExtractChar(int pos, char *bytes); + bool MatchesWordOptions(bool word, bool wordStart, int pos, int length); + long FindText(int minPos, int maxPos, const char *search, bool caseSensitive, bool word, + bool wordStart, bool regExp, int flags, int *length, CaseFolder *pcf); const char *SubstituteByPosition(const char *text, int *length); int LinesTotal() const; @@ -265,18 +361,23 @@ public: void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); void SetStylingBits(int bits); - void StartStyling(int position, char mask); - bool SetStyleFor(int length, char style); - bool SetStyles(int length, const char *styles); + void SCI_METHOD StartStyling(int position, char mask); + bool SCI_METHOD SetStyleFor(int length, char style); + bool SCI_METHOD SetStyles(int length, const char *styles); int GetEndStyled() { return endStyled; } void EnsureStyledTo(int pos); + void LexerChanged(); int GetStyleClock() { return styleClock; } void IncrementStyleClock(); - void DecorationFillRange(int position, int value, int fillLength); + void SCI_METHOD DecorationSetCurrentIndicator(int indicator) { + decorations.SetCurrentIndicator(indicator); + } + void SCI_METHOD DecorationFillRange(int position, int value, int fillLength); - int SetLineState(int line, int state); - int GetLineState(int line); + int SCI_METHOD SetLineState(int line, int state); + int SCI_METHOD GetLineState(int line) const; int GetMaxLineState(); + void SCI_METHOD ChangeLexerState(int start, int end); StyledText MarginStyledText(int line); void MarginSetStyle(int line, int style); @@ -299,6 +400,7 @@ public: const WatcherWithUserData *GetWatchers() const { return watchers; } int GetLenWatchers() const { return lenWatchers; } + CharClassify::cc WordCharClass(unsigned char ch); bool IsWordPartSeparator(char ch); int WordPartLeft(int pos); int WordPartRight(int pos); @@ -310,7 +412,6 @@ public: int BraceMatch(int position, int maxReStyle); private: - CharClassify::cc WordCharClass(unsigned char ch); bool IsWordStartAt(int pos); bool IsWordEndAt(int pos); bool IsWordAt(int start, int end); @@ -324,7 +425,7 @@ class UndoGroup { Document *pdoc; bool groupNeeded; public: - UndoGroup(Document *pdoc_, bool groupNeeded_=true) : + UndoGroup(Document *pdoc_, bool groupNeeded_=true) : pdoc(pdoc_), groupNeeded(groupNeeded_) { if (groupNeeded) { pdoc->BeginUndoAction(); @@ -398,6 +499,8 @@ public: virtual void NotifyModified(Document *doc, DocModification mh, void *userData) = 0; virtual void NotifyDeleted(Document *doc, void *userData) = 0; virtual void NotifyStyleNeeded(Document *doc, void *userData, int endPos) = 0; + virtual void NotifyLexerChanged(Document *doc, void *userData) = 0; + virtual void NotifyErrorOccurred(Document *doc, void *userData, int status) = 0; }; #ifdef SCI_NAMESPACE diff --git a/plugins/scintilla/scintilla/DocumentAccessor.cxx b/plugins/scintilla/scintilla/DocumentAccessor.cxx deleted file mode 100644 index a25979d..0000000 --- a/plugins/scintilla/scintilla/DocumentAccessor.cxx +++ /dev/null @@ -1,199 +0,0 @@ -// Scintilla source code edit control -/** @file DocumentAccessor.cxx - ** Rapid easy access to contents of a Scintilla. - **/ -// 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 "Platform.h" - -#include "PropSet.h" -#include "Accessor.h" -#include "DocumentAccessor.h" -#include "SplitVector.h" -#include "Partitioning.h" -#include "RunStyles.h" -#include "CellBuffer.h" -#include "Scintilla.h" -#include "CharClassify.h" -#include "Decoration.h" -#include "Document.h" - -#ifdef SCI_NAMESPACE -using namespace Scintilla; -#endif - -DocumentAccessor::~DocumentAccessor() { -} - -bool DocumentAccessor::InternalIsLeadByte(char ch) { - if (SC_CP_UTF8 == codePage) - // For lexing, all characters >= 0x80 are treated the - // same so none is considered a lead byte. - return false; - else - return Platform::IsDBCSLeadByte(codePage, ch); -} - -void DocumentAccessor::Fill(int position) { - if (lenDoc == -1) - lenDoc = pdoc->Length(); - startPos = position - slopSize; - if (startPos + bufferSize > lenDoc) - startPos = lenDoc - bufferSize; - if (startPos < 0) - startPos = 0; - endPos = startPos + bufferSize; - if (endPos > lenDoc) - endPos = lenDoc; - - pdoc->GetCharRange(buf, startPos, endPos-startPos); - buf[endPos-startPos] = '\0'; -} - -bool DocumentAccessor::Match(int pos, const char *s) { - for (int i=0; *s; i++) { - if (*s != SafeGetCharAt(pos+i)) - return false; - s++; - } - return true; -} - -char DocumentAccessor::StyleAt(int position) { - // Mask off all bits which aren't in the 'mask'. - return static_cast(pdoc->StyleAt(position) & mask); -} - -int DocumentAccessor::GetLine(int position) { - return pdoc->LineFromPosition(position); -} - -int DocumentAccessor::LineStart(int line) { - return pdoc->LineStart(line); -} - -int DocumentAccessor::LevelAt(int line) { - return pdoc->GetLevel(line); -} - -int DocumentAccessor::Length() { - if (lenDoc == -1) - lenDoc = pdoc->Length(); - return lenDoc; -} - -int DocumentAccessor::GetLineState(int line) { - return pdoc->GetLineState(line); -} - -int DocumentAccessor::SetLineState(int line, int state) { - return pdoc->SetLineState(line, state); -} - -void DocumentAccessor::StartAt(unsigned int start, char chMask) { - // Store the mask specified for use with StyleAt. - mask = chMask; - pdoc->StartStyling(start, chMask); - startPosStyling = start; -} - -void DocumentAccessor::StartSegment(unsigned int pos) { - startSeg = pos; -} - -void DocumentAccessor::ColourTo(unsigned int pos, int chAttr) { - // Only perform styling if non empty range - if (pos != startSeg - 1) { - PLATFORM_ASSERT(pos >= startSeg); - if (pos < startSeg) { - return; - } - - if (validLen + (pos - startSeg + 1) >= bufferSize) - Flush(); - if (validLen + (pos - startSeg + 1) >= bufferSize) { - // Too big for buffer so send directly - pdoc->SetStyleFor(pos - startSeg + 1, static_cast(chAttr)); - } else { - if (chAttr != chWhile) - chFlags = 0; - chAttr |= chFlags; - for (unsigned int i = startSeg; i <= pos; i++) { - PLATFORM_ASSERT((startPosStyling + validLen) < Length()); - styleBuf[validLen++] = static_cast(chAttr); - } - } - } - startSeg = pos+1; -} - -void DocumentAccessor::SetLevel(int line, int level) { - pdoc->SetLevel(line, level); -} - -void DocumentAccessor::Flush() { - startPos = extremePosition; - lenDoc = -1; - if (validLen > 0) { - pdoc->SetStyles(validLen, styleBuf); - startPosStyling += validLen; - validLen = 0; - } -} - -int DocumentAccessor::IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader) { - int end = Length(); - int spaceFlags = 0; - - // Determines the indentation level of the current line and also checks for consistent - // indentation compared to the previous line. - // Indentation is judged consistent when the indentation whitespace of each line lines - // the same or the indentation of one line is a prefix of the other. - - int pos = LineStart(line); - char ch = (*this)[pos]; - int indent = 0; - bool inPrevPrefix = line > 0; - int posPrev = inPrevPrefix ? LineStart(line-1) : 0; - while ((ch == ' ' || ch == '\t') && (pos < end)) { - if (inPrevPrefix) { - char chPrev = (*this)[posPrev++]; - if (chPrev == ' ' || chPrev == '\t') { - if (chPrev != ch) - spaceFlags |= wsInconsistent; - } else { - inPrevPrefix = false; - } - } - if (ch == ' ') { - spaceFlags |= wsSpace; - indent++; - } else { // Tab - spaceFlags |= wsTab; - if (spaceFlags & wsSpace) - spaceFlags |= wsSpaceTab; - indent = (indent / 8 + 1) * 8; - } - ch = (*this)[++pos]; - } - - *flags = spaceFlags; - indent += SC_FOLDLEVELBASE; - // if completely empty line or the start of a comment... - if ((ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') || - (pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos)) ) - return indent | SC_FOLDLEVELWHITEFLAG; - else - return indent; -} - -void DocumentAccessor::IndicatorFill(int start, int end, int indicator, int value) { - pdoc->decorations.SetCurrentIndicator(indicator); - pdoc->DecorationFillRange(start, value, end - start); -} diff --git a/plugins/scintilla/scintilla/DocumentAccessor.h b/plugins/scintilla/scintilla/DocumentAccessor.h deleted file mode 100644 index 899865f..0000000 --- a/plugins/scintilla/scintilla/DocumentAccessor.h +++ /dev/null @@ -1,77 +0,0 @@ -// Scintilla source code edit control -/** @file DocumentAccessor.h - ** Implementation of BufferAccess and StylingAccess on a Scintilla - ** rapid easy access to contents of a Scintilla. - **/ -// Copyright 1998-2001 by Neil Hodgson -// The License.txt file describes the conditions under which this software may be distributed. - -#ifdef SCI_NAMESPACE -namespace Scintilla { -#endif - -class Document; - -/** - */ - -class DocumentAccessor : public Accessor { - // Private so DocumentAccessor objects can not be copied - DocumentAccessor(const DocumentAccessor &source); - DocumentAccessor &operator=(const DocumentAccessor &); - -protected: - Document *pdoc; - PropertyGet &props; - WindowID id; - int lenDoc; - - char styleBuf[bufferSize]; - int validLen; - char chFlags; - char chWhile; - unsigned int startSeg; - int startPosStyling; - int mask; - - bool InternalIsLeadByte(char ch); - void Fill(int position); - -public: - DocumentAccessor(Document *pdoc_, PropertyGet &props_, WindowID id_=0) : - Accessor(), pdoc(pdoc_), props(props_), id(id_), - lenDoc(-1), validLen(0), chFlags(0), chWhile(0), - startSeg(0), startPosStyling(0), - mask(127) { // Initialize the mask to be big enough for any lexer. - } - ~DocumentAccessor(); - bool Match(int pos, const char *s); - char StyleAt(int position); - int GetLine(int position); - int LineStart(int line); - int LevelAt(int line); - int Length(); - void Flush(); - int GetLineState(int line); - int SetLineState(int line, int state); - int GetPropertyInt(const char *key, int defaultValue=0) { - return props.GetInt(key, defaultValue); - } - char *GetProperties() { - return props.ToString(); - } - WindowID GetWindow() { return id; } - - void StartAt(unsigned int start, char chMask=31); - void SetFlags(char chFlags_, char chWhile_) {chFlags = chFlags_; chWhile = chWhile_; }; - unsigned int GetStartSegment() { return startSeg; } - void StartSegment(unsigned int pos); - void ColourTo(unsigned int pos, int chAttr); - void SetLevel(int line, int level); - int IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); - void IndicatorFill(int start, int end, int indicator, int value); -}; - -#ifdef SCI_NAMESPACE -} -#endif diff --git a/plugins/scintilla/scintilla/Editor.cxx b/plugins/scintilla/scintilla/Editor.cxx index 9ec5994..d1d0e7f 100644 --- a/plugins/scintilla/scintilla/Editor.cxx +++ b/plugins/scintilla/scintilla/Editor.cxx @@ -2,28 +2,23 @@ /** @file Editor.cxx ** Main code for the edit control. **/ -// Copyright 1998-2004 by Neil Hodgson +// Copyright 1998-2011 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 - -// With Borland C++ 5.5, including includes Windows.h leading to defining -// FindText to FindTextA which makes calls here to Document::FindText fail. -#ifdef __BORLANDC__ -#ifdef FindText -#undef FindText -#endif -#endif +#include #include "Platform.h" +#include "ILexer.h" #include "Scintilla.h" #include "SplitVector.h" @@ -52,7 +47,7 @@ using namespace Scintilla; return whether this modification represents an operation that may reasonably be deferred (not done now OR [possibly] at all) */ -static bool CanDeferToLastStep(const DocModification& mh) { +static bool CanDeferToLastStep(const DocModification &mh) { if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) return true; // CAN skip if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO))) @@ -62,7 +57,7 @@ static bool CanDeferToLastStep(const DocModification& mh) { return false; // PRESUMABLY must do } -static bool CanEliminate(const DocModification& mh) { +static bool CanEliminate(const DocModification &mh) { return (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0; } @@ -71,7 +66,7 @@ static bool CanEliminate(const DocModification& mh) { return whether this modification represents the FINAL step in a [possibly lengthy] multi-step Undo/Redo sequence */ -static bool IsLastStep(const DocModification& mh) { +static bool IsLastStep(const DocModification &mh) { return (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0 && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0 @@ -93,6 +88,15 @@ static inline bool IsControlCharacter(int ch) { return ch >= 0 && ch < ' '; } +static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) { + for (unsigned int i = 0; i < len; i++) { + // This is safe because IsSpaceOrTab() will return false for null terminators + if (!IsSpaceOrTab(s[i])) + return false; + } + return true; +} + Editor::Editor() { ctrlID = 0; @@ -123,11 +127,15 @@ Editor::Editor() { dropWentOutside = false; posDrag = SelectionPosition(invalidPosition); posDrop = SelectionPosition(invalidPosition); + hotSpotClickPos = INVALID_POSITION; selectionType = selChar; lastXChosen = 0; lineAnchor = 0; originalAnchorPos = 0; + wordSelectAnchorStartPos = 0; + wordSelectAnchorEndPos = 0; + wordSelectInitialCaretPos = -1; primarySelection = true; @@ -147,9 +155,10 @@ Editor::Editor() { lineWidthMaxSeen = 0; verticalScrollBarVisible = true; endAtLastLine = true; - caretSticky = false; + caretSticky = SC_CARETSTICKY_OFF; multipleSelection = false; additionalSelectionTyping = false; + multiPasteMode = SC_MULTIPASTE_ONCE; additionalCaretsBlink = true; additionalCaretsVisible = true; virtualSpaceOptions = SCVS_NONE; @@ -169,7 +178,8 @@ Editor::Editor() { lengthForEncode = -1; - needUpdateUI = true; + needUpdateUI = 0; + ContainerNeedsUpdate(SC_UPDATE_CONTENT); braces[0] = invalidPosition; braces[1] = invalidPosition; bracesMatchStyle = STYLE_BRACEBAD; @@ -428,7 +438,10 @@ int Editor::LineFromLocation(Point pt) { } void Editor::SetTopLine(int topLineNew) { - topLine = topLineNew; + if (topLine != topLineNew) { + topLine = topLineNew; + ContainerNeedsUpdate(SC_UPDATE_V_SCROLL); + } posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine)); } @@ -621,7 +634,7 @@ void Editor::Redraw() { //wMain.InvalidateAll(); } -void Editor::RedrawSelMargin(int line) { +void Editor::RedrawSelMargin(int line, bool allAfter) { if (!AbandonPaint()) { if (vs.maskInLine) { Redraw(); @@ -632,7 +645,8 @@ void Editor::RedrawSelMargin(int line) { int position = pdoc->LineStart(line); PRectangle rcLine = RectangleFromRange(position, position); rcSelMargin.top = rcLine.top; - rcSelMargin.bottom = rcLine.bottom; + if (!allAfter) + rcSelMargin.bottom = rcLine.bottom; } wMain.InvalidateRectangle(rcSelMargin); } @@ -691,17 +705,17 @@ void Editor::SetRectangularRange() { if (sel.selType == Selection::selThin) { xCaret = xAnchor; } - int lineAnchor = pdoc->LineFromPosition(sel.Rectangular().anchor.Position()); + int lineAnchorRect = pdoc->LineFromPosition(sel.Rectangular().anchor.Position()); int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position()); - int increment = (lineCaret > lineAnchor) ? 1 : -1; - for (int line=lineAnchor; line != lineCaret+increment; line += increment) { + int increment = (lineCaret > lineAnchorRect) ? 1 : -1; + for (int line=lineAnchorRect; line != lineCaret+increment; line += increment) { SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor)); if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0) range.ClearVirtualSpace(); - if (line == lineAnchor) + if (line == lineAnchorRect) sel.SetSelection(range); else - sel.AddSelection(range); + sel.AddSelectionWithoutTrim(range); } } } @@ -734,19 +748,36 @@ void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSel lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position()); } } - needUpdateUI = true; + ContainerNeedsUpdate(SC_UPDATE_SELECTION); InvalidateRange(firstAffected, lastAffected); } void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) { - SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_), - ClampPositionIntoDocument(anchor_)); + currentPos_ = ClampPositionIntoDocument(currentPos_); + anchor_ = ClampPositionIntoDocument(anchor_); + int currentLine = pdoc->LineFromPosition(currentPos_.Position()); + /* For Line selection - ensure the anchor and caret are always + at the beginning and end of the region lines. */ + if (sel.selType == Selection::selLines) { + if (currentPos_ > anchor_) { + anchor_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position()))); + currentPos_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position()))); + } else { + currentPos_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position()))); + anchor_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position()))); + } + } + SelectionRange rangeNew(currentPos_, anchor_); if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); } sel.RangeMain() = rangeNew; SetRectangularRange(); ClaimSelection(); + + if (highlightDelimiter.NeedsDrawing(currentLine)) { + RedrawSelMargin(); + } } void Editor::SetSelection(int currentPos_, int anchor_) { @@ -756,6 +787,7 @@ void Editor::SetSelection(int currentPos_, int anchor_) { // Just move the caret on the main selection void Editor::SetSelection(SelectionPosition currentPos_) { currentPos_ = ClampPositionIntoDocument(currentPos_); + int currentLine = pdoc->LineFromPosition(currentPos_.Position()); if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) { InvalidateSelection(SelectionRange(currentPos_)); } @@ -768,6 +800,10 @@ void Editor::SetSelection(SelectionPosition currentPos_) { SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor); } ClaimSelection(); + + if (highlightDelimiter.NeedsDrawing(currentLine)) { + RedrawSelMargin(); + } } void Editor::SetSelection(int currentPos_) { @@ -775,6 +811,7 @@ void Editor::SetSelection(int currentPos_) { } void Editor::SetEmptySelection(SelectionPosition currentPos_) { + int currentLine = pdoc->LineFromPosition(currentPos_.Position()); SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_)); if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); @@ -784,6 +821,9 @@ void Editor::SetEmptySelection(SelectionPosition currentPos_) { SetRectangularRange(); ClaimSelection(); + if (highlightDelimiter.NeedsDrawing(currentLine)) { + RedrawSelMargin(); + } } void Editor::SetEmptySelection(int currentPos_) { @@ -847,9 +887,18 @@ SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int mov } int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) { + bool simpleCaret = (sel.Count() == 1) && sel.Empty(); + SelectionPosition spCaret = sel.Last(); + int delta = newPos.Position() - sel.MainCaret(); newPos = ClampPositionIntoDocument(newPos); newPos = MovePositionOutsideChar(newPos, delta); + if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) { + // Can't turn into multiple selection so clear additional selections + InvalidateSelection(SelectionRange(newPos), true); + SelectionRange rangeMain = sel.RangeMain(); + sel.SetSelection(rangeMain); + } if (!sel.IsRectangular() && (selt == Selection::selRectangle)) { // Switching to rectangular SelectionRange rangeMain = sel.RangeMain(); @@ -866,7 +915,20 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b } ShowCaretAtCurrentPosition(); if (ensureVisible) { - EnsureCaretVisible(); + XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true); + if (simpleCaret && (newXY.xOffset == xOffset)) { + // simple vertical scroll then invalidate + ScrollTo(newXY.topLine); + InvalidateSelection(SelectionRange(spCaret), true); + } else { + SetXYScroll(newXY); + } + } + + int currentLine = pdoc->LineFromPosition(newPos.Position()); + + if (highlightDelimiter.NeedsDrawing(currentLine)) { + RedrawSelMargin(); } return 0; } @@ -908,18 +970,22 @@ Point Editor::PointMainCaret() { */ void Editor::SetLastXChosen() { Point pt = PointMainCaret(); - lastXChosen = pt.x; + lastXChosen = pt.x + xOffset; } void Editor::ScrollTo(int line, bool moveThumb) { int topLineNew = Platform::Clamp(line, 0, MaxScrollPos()); if (topLineNew != topLine) { // Try to optimise small scrolls +#ifndef UNDER_CE int linesToMove = topLine - topLineNew; +#endif SetTopLine(topLineNew); - ShowCaretAtCurrentPosition(); - // Perform redraw rather than scroll if many lines would be redrawn anyway. + // Optimize by styling the view as this will invalidate any needed area + // which could abort the initial paint if discovered later. + StyleToPositionInView(PositionAfterArea(GetClientRectangle())); #ifndef UNDER_CE + // Perform redraw rather than scroll if many lines would be redrawn anyway. if ((abs(linesToMove) <= 10) && (paintState == notPainting)) { ScrollText(linesToMove); } else { @@ -945,22 +1011,86 @@ void Editor::HorizontalScrollTo(int xPos) { xPos = 0; if ((wrapState == eWrapNone) && (xOffset != xPos)) { xOffset = xPos; + ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); SetHorizontalScrollPos(); RedrawRect(GetClientRectangle()); } } +void Editor::VerticalCentreCaret() { + int lineDoc = pdoc->LineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret()); + int lineDisplay = cs.DisplayFromDoc(lineDoc); + int newTop = lineDisplay - (LinesOnScreen() / 2); + if (topLine != newTop) { + SetTopLine(newTop > 0 ? newTop : 0); + RedrawRect(GetClientRectangle()); + } +} + +void Editor::MoveSelectedLines(int lineDelta) { + + // if selection doesn't start at the beginning of the line, set the new start + int selectionStart = SelectionStart().Position(); + int startLine = pdoc->LineFromPosition(selectionStart); + int beginningOfStartLine = pdoc->LineStart(startLine); + selectionStart = beginningOfStartLine; + + // if selection doesn't end at the beginning of a line greater than that of the start, + // then set it at the beginning of the next one + int selectionEnd = SelectionEnd().Position(); + int endLine = pdoc->LineFromPosition(selectionEnd); + int beginningOfEndLine = pdoc->LineStart(endLine); + if (selectionEnd > beginningOfEndLine + || selectionStart == selectionEnd) { + selectionEnd = pdoc->LineStart(endLine + 1); + } + + // if there's nowhere for the selection to move + // (i.e. at the beginning going up or at the end going down), + // stop it right there! + if ((selectionStart == 0 && lineDelta < 0) + || (selectionEnd == pdoc->Length() && lineDelta > 0) + || selectionStart == selectionEnd) { + return; + } + + UndoGroup ug(pdoc); + + SetSelection(selectionStart, selectionEnd); + + SelectionText selectedText; + CopySelectionRange(&selectedText); + + int selectionLength = SelectionRange(selectionStart, selectionEnd).Length(); + ClearSelection(); + + Point currentLocation = LocationFromPosition(CurrentPosition()); + int currentLine = LineFromLocation(currentLocation); + GoToLine(currentLine + lineDelta); + + pdoc->InsertCString(CurrentPosition(), selectedText.s); + SetSelection(CurrentPosition(), CurrentPosition() + selectionLength); +} + +void Editor::MoveSelectedLinesUp() { + MoveSelectedLines(-1); +} + +void Editor::MoveSelectedLinesDown() { + MoveSelectedLines(1); +} + void Editor::MoveCaretInsideView(bool ensureVisible) { PRectangle rcClient = GetTextRectangle(); Point pt = PointMainCaret(); if (pt.y < rcClient.top) { MovePositionTo(SPositionFromLocation( - Point(lastXChosen, rcClient.top)), + Point(lastXChosen - xOffset, rcClient.top)), Selection::noSel, ensureVisible); } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) { int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight; MovePositionTo(SPositionFromLocation( - Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)), + Point(lastXChosen - xOffset, rcClient.top + yOfLastLineFullyDisplayed)), Selection::noSel, ensureVisible); } } @@ -1029,29 +1159,24 @@ slop | strict | jumps | even | Caret can go to the margin | When 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin */ -void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { - //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " "); + +Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) { PRectangle rcClient = GetTextRectangle(); - //int rcClientFullWidth = rcClient.Width(); - SelectionPosition posCaret = sel.RangeMain().caret; - if (posDrag.IsValid()) { - posCaret = posDrag; - } - Point pt = LocationFromPosition(posCaret); - Point ptBottomCaret = pt; - ptBottomCaret.y += vs.lineHeight - 1; - int lineCaret = DisplayFromPosition(posCaret.Position()); - bool bSlop, bStrict, bJump, bEven; + const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret; + const Point pt = LocationFromPosition(posCaret); + const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1); + const int lineCaret = DisplayFromPosition(posCaret.Position()); + + XYScrollPosition newXY(xOffset, topLine); // Vertical positioning - if (vert && (pt.y < rcClient.top || ptBottomCaret.y > rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { - int linesOnScreen = LinesOnScreen(); - int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2; - int newTopLine = topLine; - bSlop = (caretYPolicy & CARET_SLOP) != 0; - bStrict = (caretYPolicy & CARET_STRICT) != 0; - bJump = (caretYPolicy & CARET_JUMPS) != 0; - bEven = (caretYPolicy & CARET_EVEN) != 0; + if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { + const int linesOnScreen = LinesOnScreen(); + const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2; + const bool bSlop = (caretYPolicy & CARET_SLOP) != 0; + const bool bStrict = (caretYPolicy & CARET_STRICT) != 0; + const bool bJump = (caretYPolicy & CARET_JUMPS) != 0; + const bool bEven = (caretYPolicy & CARET_EVEN) != 0; // It should be possible to scroll the window to show the caret, // but this fails to remove the caret on GTK+ @@ -1084,10 +1209,10 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { } if (lineCaret < topLine + yMarginT) { // Caret goes too high - newTopLine = lineCaret - yMoveT; + newXY.topLine = lineCaret - yMoveT; } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) { // Caret goes too low - newTopLine = lineCaret - linesOnScreen + 1 + yMoveB; + newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; } } else { // Not strict yMoveT = bJump ? caretYSlop * 3 : caretYSlop; @@ -1099,10 +1224,10 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { } if (lineCaret < topLine) { // Caret goes too high - newTopLine = lineCaret - yMoveT; + newXY.topLine = lineCaret - yMoveT; } else if (lineCaret > topLine + linesOnScreen - 1) { // Caret goes too low - newTopLine = lineCaret - linesOnScreen + 1 + yMoveB; + newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; } } } else { // No slop @@ -1110,41 +1235,35 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { // Minimal move if (lineCaret < topLine) { // Caret goes too high - newTopLine = lineCaret; + newXY.topLine = lineCaret; } else if (lineCaret > topLine + linesOnScreen - 1) { // Caret goes too low if (bEven) { - newTopLine = lineCaret - linesOnScreen + 1; + newXY.topLine = lineCaret - linesOnScreen + 1; } else { - newTopLine = lineCaret; + newXY.topLine = lineCaret; } } } else { // Strict or going out of display if (bEven) { // Always center caret - newTopLine = lineCaret - halfScreen; + newXY.topLine = lineCaret - halfScreen; } else { // Always put caret on top of display - newTopLine = lineCaret; + newXY.topLine = lineCaret; } } } - newTopLine = Platform::Clamp(newTopLine, 0, MaxScrollPos()); - if (newTopLine != topLine) { - Redraw(); - SetTopLine(newTopLine); - SetVerticalScrollPos(); - } + newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos()); } // Horizontal positioning if (horiz && (wrapState == eWrapNone)) { - int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2; - int xOffsetNew = xOffset; - bSlop = (caretXPolicy & CARET_SLOP) != 0; - bStrict = (caretXPolicy & CARET_STRICT) != 0; - bJump = (caretXPolicy & CARET_JUMPS) != 0; - bEven = (caretXPolicy & CARET_EVEN) != 0; + const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2; + const bool bSlop = (caretXPolicy & CARET_SLOP) != 0; + const bool bStrict = (caretXPolicy & CARET_STRICT) != 0; + const bool bJump = (caretXPolicy & CARET_JUMPS) != 0; + const bool bEven = (caretXPolicy & CARET_EVEN) != 0; if (bSlop) { // A margin is defined int xMoveL, xMoveR; @@ -1173,18 +1292,18 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { if (pt.x < rcClient.left + xMarginL) { // Caret is on the left of the display if (bJump && bEven) { - xOffsetNew -= xMoveL; + newXY.xOffset -= xMoveL; } else { // Move just enough to allow to display the caret - xOffsetNew -= (rcClient.left + xMarginL) - pt.x; + newXY.xOffset -= (rcClient.left + xMarginL) - pt.x; } } else if (pt.x >= rcClient.right - xMarginR) { // Caret is on the right of the display if (bJump && bEven) { - xOffsetNew += xMoveR; + newXY.xOffset += xMoveR; } else { // Move just enough to allow to display the caret - xOffsetNew += pt.x - (rcClient.right - xMarginR) + 1; + newXY.xOffset += pt.x - (rcClient.right - xMarginR) + 1; } } } else { // Not strict @@ -1197,10 +1316,10 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { } if (pt.x < rcClient.left) { // Caret is on the left of the display - xOffsetNew -= xMoveL; + newXY.xOffset -= xMoveL; } else if (pt.x >= rcClient.right) { // Caret is on the right of the display - xOffsetNew += xMoveR; + newXY.xOffset += xMoveR; } } } else { // No slop @@ -1209,54 +1328,70 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { // Strict or going out of display if (bEven) { // Center caret - xOffsetNew += pt.x - rcClient.left - halfScreen; + newXY.xOffset += pt.x - rcClient.left - halfScreen; } else { // Put caret on right - xOffsetNew += pt.x - rcClient.right + 1; + newXY.xOffset += pt.x - rcClient.right + 1; } } else { // Move just enough to allow to display the caret if (pt.x < rcClient.left) { // Caret is on the left of the display if (bEven) { - xOffsetNew -= rcClient.left - pt.x; + newXY.xOffset -= rcClient.left - pt.x; } else { - xOffsetNew += pt.x - rcClient.right + 1; + newXY.xOffset += pt.x - rcClient.right + 1; } } else if (pt.x >= rcClient.right) { // Caret is on the right of the display - xOffsetNew += pt.x - rcClient.right + 1; + newXY.xOffset += pt.x - rcClient.right + 1; } } } // In case of a jump (find result) largely out of display, adjust the offset to display the caret - if (pt.x + xOffset < rcClient.left + xOffsetNew) { - xOffsetNew = pt.x + xOffset - rcClient.left; - } else if (pt.x + xOffset >= rcClient.right + xOffsetNew) { - xOffsetNew = pt.x + xOffset - rcClient.right + 1; + if (pt.x + xOffset < rcClient.left + newXY.xOffset) { + newXY.xOffset = pt.x + xOffset - rcClient.left; + } else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) { + newXY.xOffset = pt.x + xOffset - rcClient.right + 1; if (vs.caretStyle == CARETSTYLE_BLOCK) { // Ensure we can see a good portion of the block caret - xOffsetNew += vs.aveCharWidth; + newXY.xOffset += vs.aveCharWidth; } } - if (xOffsetNew < 0) { - xOffsetNew = 0; + if (newXY.xOffset < 0) { + newXY.xOffset = 0; + } + } + + return newXY; +} + +void Editor::SetXYScroll(XYScrollPosition newXY) { + if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) { + if (newXY.topLine != topLine) { + SetTopLine(newXY.topLine); + SetVerticalScrollPos(); } - if (xOffset != xOffsetNew) { - xOffset = xOffsetNew; - if (xOffsetNew > 0) { + if (newXY.xOffset != xOffset) { + xOffset = newXY.xOffset; + ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); + if (newXY.xOffset > 0) { PRectangle rcText = GetTextRectangle(); if (horizontalScrollBarVisible && - rcText.Width() + xOffset > scrollWidth) { + rcText.Width() + xOffset > scrollWidth) { scrollWidth = xOffset + rcText.Width(); SetScrollBars(); } } SetHorizontalScrollPos(); - Redraw(); } + Redraw(); + UpdateSystemCaret(); } - UpdateSystemCaret(); +} + +void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { + SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz)); } void Editor::ShowCaretAtCurrentPosition() { @@ -1369,8 +1504,6 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { rcTextArea.left = vs.fixedColumnWidth; rcTextArea.right -= vs.rightMarginWidth; wrapWidth = rcTextArea.Width(); - // Ensure all of the document is styled. - pdoc->EnsureStyledTo(pdoc->Length()); RefreshStyleData(); AutoSurface surface(this); if (surface) { @@ -1391,6 +1524,9 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { lastLineToWrap = wrapEnd; } // else do a fullWrap. + // Ensure all lines being wrapped are styled. + pdoc->EnsureStyledTo(pdoc->LineEnd(lastLineToWrap)); + // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap); // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd); while (lineToWrap < lastLineToWrap) { @@ -1495,7 +1631,7 @@ static int istrlen(const char *s) { bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) { if (st.multipleStyles) { - for (size_t iStyle=0;iStyleGetHighlightDelimiters(highlightDelimiter, pdoc->LineFromPosition(CurrentPosition()), lineBack, lineFront); + } // Old code does not know about new markers needed to distinguish all cases int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, @@ -1657,10 +1797,10 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) { PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed()); - int lineDoc = cs.DocFromDisplay(visibleLine); PLATFORM_ASSERT(cs.GetVisible(lineDoc)); bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc); + bool lastSubLine = visibleLine == (cs.DisplayFromDoc(lineDoc + 1) - 1); // Decide which fold indicator should be displayed level = pdoc->GetLevel(lineDoc); @@ -1672,19 +1812,31 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK; if (level & SC_FOLDLEVELHEADERFLAG) { if (firstSubLine) { - if (cs.GetExpanded(lineDoc)) { - if (levelNum == SC_FOLDLEVELBASE) - marks |= 1 << SC_MARKNUM_FOLDEROPEN; - else - marks |= 1 << folderOpenMid; - } else { - if (levelNum == SC_FOLDLEVELBASE) - marks |= 1 << SC_MARKNUM_FOLDER; - else - marks |= 1 << folderEnd; - } + if (levelNum < levelNextNum) { + if (cs.GetExpanded(lineDoc)) { + if (levelNum == SC_FOLDLEVELBASE) + marks |= 1 << SC_MARKNUM_FOLDEROPEN; + else + marks |= 1 << folderOpenMid; + } else { + if (levelNum == SC_FOLDLEVELBASE) + marks |= 1 << SC_MARKNUM_FOLDER; + else + marks |= 1 << folderEnd; + } + } else if (levelNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } } else { - marks |= 1 << SC_MARKNUM_FOLDERSUB; + if (levelNum < levelNextNum) { + if (cs.GetExpanded(lineDoc)) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } else if (levelNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + } else if (levelNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } } needWhiteClosure = false; } else if (level & SC_FOLDLEVELWHITEFLAG) { @@ -1715,16 +1867,19 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (levelNext & SC_FOLDLEVELWHITEFLAG) { marks |= 1 << SC_MARKNUM_FOLDERSUB; needWhiteClosure = true; - } else if (levelNextNum > SC_FOLDLEVELBASE) { - marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + } else if (lastSubLine) { + if (levelNextNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + } } else { - marks |= 1 << SC_MARKNUM_FOLDERTAIL; + marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } - marks &= vs.ms[margin].mask; PRectangle rcMarker = rcSelMargin; rcMarker.top = yposScreen; @@ -1771,7 +1926,20 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (marks) { for (int markBit = 0; (markBit < 32) && marks; markBit++) { if (marks & 1) { - vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font); + LineMarker::typeOfFold tFold; + if (!highlightDelimiter.isCurrentBlockHighlight(lineDoc)) { + tFold = LineMarker::undefined; + } else if (highlightDelimiter.isBodyBlockFold(lineDoc)) { + tFold = LineMarker::body; + } else if (highlightDelimiter.isHeadBlockFold(lineDoc)) { + tFold = LineMarker::head; + } else if (highlightDelimiter.isTailBlockFold(lineDoc)) { + tFold = LineMarker::tail; + } else { + //Normally, this branch is never used. But I prefer to manage it anyway. + tFold = LineMarker::undefined; + } + vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font, tFold); } marks >>= 1; } @@ -1824,6 +1992,7 @@ static bool GoodTrailByte(int v) { } bool BadUTF(const char *s, int len, int &trailBytes) { + // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 if (trailBytes) { trailBytes--; return false; @@ -1840,6 +2009,23 @@ bool BadUTF(const char *s, int len, int &trailBytes) { if (len < 4) return true; if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) { + if (*us == 0xf4) { + // Check if encoding a value beyond the last Unicode character 10FFFF + if (us[1] > 0x8f) { + return true; + } else if (us[1] == 0x8f) { + if (us[2] > 0xbf) { + return true; + } else if (us[2] == 0xbf) { + if (us[3] > 0xbf) { + return true; + } + } + } + } else if ((*us == 0xf0) && ((us[1] & 0xf0) == 0x80)) { + // Overlong + return true; + } trailBytes = 3; return false; } else { @@ -1850,6 +2036,22 @@ bool BadUTF(const char *s, int len, int &trailBytes) { if (len < 3) return true; if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) { + if ((*us == 0xe0) && ((us[1] & 0xe0) == 0x80)) { + // Overlong + return true; + } + if ((*us == 0xed) && ((us[1] & 0xe0) == 0xa0)) { + // Surrogate + return true; + } + if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbe)) { + // U+FFFE + return true; + } + if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbf)) { + // U+FFFF + return true; + } trailBytes = 2; return false; } else { @@ -1939,8 +2141,6 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou if (ll->validity == LineLayout::llInvalid) { ll->widthLine = LineLayout::wrapWidthInfinite; ll->lines = 1; - int numCharsInLine = 0; - int numCharsBeforeEOL = 0; if (vstyle.edgeState == EDGE_BACKGROUND) { ll->edgeColumn = pdoc->FindColumn(line, theEdge); if (ll->edgeColumn >= posLineStart) { @@ -1950,25 +2150,32 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou ll->edgeColumn = -1; } - char styleByte = 0; - int styleMask = pdoc->stylingBitsMask; + char styleByte; + const int styleMask = pdoc->stylingBitsMask; ll->styleBitsSet = 0; // Fill base line layout - for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) { - char chDoc = pdoc->CharAt(charInDoc); - styleByte = pdoc->StyleAt(charInDoc); + const int lineLength = posLineEnd - posLineStart; + pdoc->GetCharRange(ll->chars, posLineStart, lineLength); + pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); + int numCharsBeforeEOL = lineLength; + while ((numCharsBeforeEOL > 0) && IsEOLChar(ll->chars[numCharsBeforeEOL-1])) { + numCharsBeforeEOL--; + } + const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; + for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { + styleByte = ll->styles[styleInLine]; ll->styleBitsSet |= styleByte; - if (vstyle.viewEOL || (!IsEOLChar(chDoc))) { - ll->chars[numCharsInLine] = chDoc; - ll->styles[numCharsInLine] = static_cast(styleByte & styleMask); - ll->indicators[numCharsInLine] = static_cast(styleByte & ~styleMask); - if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper) - ll->chars[numCharsInLine] = static_cast(toupper(chDoc)); - else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) - ll->chars[numCharsInLine] = static_cast(tolower(chDoc)); - numCharsInLine++; - if (!IsEOLChar(chDoc)) - numCharsBeforeEOL++; + ll->styles[styleInLine] = static_cast(styleByte & styleMask); + ll->indicators[styleInLine] = static_cast(styleByte & ~styleMask); + } + styleByte = static_cast(((lineLength > 0) ? ll->styles[lineLength-1] : 0) & styleMask); + if (vstyle.someStylesForceCase) { + for (int charInLine = 0; charInLinechars[charInLine]; + if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper) + ll->chars[charInLine] = static_cast(toupper(chDoc)); + else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower) + ll->chars[charInLine] = static_cast(tolower(chDoc)); } } ll->xHighlightGuide = 0; @@ -2018,8 +2225,8 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou } lastSegItalics = false; } else if (isBadUTF) { - char hexits[3]; - sprintf(hexits, "%2X", ll->chars[charInLine] & 0xff); + char hexits[4]; + sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff); ll->positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3; } else { // Regular character @@ -2031,7 +2238,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou } else { lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic; posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg, - lenSeg, ll->positions + startseg + 1); + lenSeg, ll->positions + startseg + 1, pdoc); } } } else { // invisible @@ -2342,6 +2549,8 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin // Fill the remainder of the line rcSegment.left = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth; + if (rcSegment.left < rcLine.left) + rcSegment.left = rcLine.left; rcSegment.right = rcLine.right; if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { @@ -2374,12 +2583,22 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin } } +void Editor::DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, ViewStyle &vsDraw, + int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { + const int subLineStart = ll->positions[ll->LineStart(subLine)]; + PRectangle rcIndic( + ll->positions[startPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent, + ll->positions[endPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine); +} + void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) { // Draw decorators const int posLineStart = pdoc->LineStart(line); const int lineStart = ll->LineStart(subLine); - const int subLineStart = ll->positions[lineStart]; const int posLineEnd = posLineStart + lineEnd; if (!under) { @@ -2404,12 +2623,7 @@ void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int x // IN indicator run, looking for END if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) { // AT end of indicator run, DRAW it! - PRectangle rcIndic( - ll->positions[startPos] + xStart - subLineStart, - rcLine.top + vsDraw.maxAscent, - ll->positions[indicPos] + xStart - subLineStart, - rcLine.top + vsDraw.maxAscent + 3); - vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine); + DrawIndicator(indicnum, startPos, indicPos, surface, vsDraw, xStart, rcLine, ll, subLine); // RESET control var startPos = -1; } @@ -2429,16 +2643,33 @@ void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int x int endPos = deco->rs.EndRun(startPos); if (endPos > posLineEnd) endPos = posLineEnd; - PRectangle rcIndic( - ll->positions[startPos - posLineStart] + xStart - subLineStart, - rcLine.top + vsDraw.maxAscent, - ll->positions[endPos - posLineStart] + xStart - subLineStart, - rcLine.top + vsDraw.maxAscent + 3); - vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine); + DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, + surface, vsDraw, xStart, rcLine, ll, subLine); startPos = deco->rs.EndRun(endPos); } } } + + // Use indicators to highlight matching braces + if ((vs.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || + (vs.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { + int braceIndicator = (bracesMatchStyle == STYLE_BRACELIGHT) ? vs.braceHighlightIndicator : vs.braceBadLightIndicator; + if (under == vsDraw.indicators[braceIndicator].under) { + Range rangeLine(posLineStart + lineStart, posLineEnd); + if (rangeLine.ContainsCharacter(braces[0])) { + int braceOffset = braces[0] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, xStart, rcLine, ll, subLine); + } + } + if (rangeLine.ContainsCharacter(braces[1])) { + int braceOffset = braces[1] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, xStart, rcLine, ll, subLine); + } + } + } + } } void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, @@ -2481,7 +2712,7 @@ void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int x surface->LineTo(rcSegment.left, rcSegment.bottom); surface->MoveTo(rcSegment.right, rcSegment.top); surface->LineTo(rcSegment.right, rcSegment.bottom); - if (subLine == ll->lines){ + if (subLine == ll->lines) { surface->MoveTo(rcSegment.left, rcSegment.top); surface->LineTo(rcSegment.right, rcSegment.top); } @@ -2623,7 +2854,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis ll->psel = &sel; - BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, selBackDrawn); + BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, xStartVisible, selBackDrawn, pdoc); int next = bfBack.First(); // Background drawing loop @@ -2713,8 +2944,8 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis inIndentation = subLine == 0; // Do not handle indentation except on first subline. // Foreground drawing loop - BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, - ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset)); + BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, xStartVisible, + ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset), pdoc); next = bfFore.First(); while (next < lineEnd) { @@ -2787,8 +3018,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis cc, 1, textBack, textFore); } } else if ((i == startseg) && (static_cast(ll->chars[i]) >= 0x80) && IsUnicodeMode()) { - char hexits[3]; - sprintf(hexits, "%2X", ll->chars[i] & 0xff); + // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value + char hexits[4]; + sprintf(hexits, "x%2X", ll->chars[i] & 0xff); DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw); } else { // Normal text display @@ -2840,7 +3072,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis } } } - if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) { + if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd) { PRectangle rcUL = rcSegment; rcUL.top = rcUL.top + vsDraw.maxAscent + 1; rcUL.bottom = rcUL.top + 1; @@ -2893,7 +3125,8 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis lineNextWithText++; } if (lineNextWithText > line) { - // This line is empty, so use indentation of last line with text + xStartText = 100000; // Don't limit to visible indentation on empty line + // This line is empty, so use indentation of first next line with text indentSpace = Platform::Maximum(indentSpace, pdoc->GetLineIndentation(lineNextWithText)); } @@ -2941,7 +3174,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis } // Draw any translucent whole line states - rcSegment.left = xStart; + rcSegment.left = 0; rcSegment.right = rcLine.right - 1; if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) { SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha); @@ -3063,11 +3296,11 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { } pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); - pixmapSelPattern->PenColour(colourFMStripes); - for (int stripe = 0; stripe < patternSize; stripe++) { - // Alternating 1 pixel stripes is same as checkerboard. - pixmapSelPattern->MoveTo(0, stripe * 2); - pixmapSelPattern->LineTo(patternSize, stripe * 2 - patternSize); + for (int y = 0; y < patternSize; y++) { + for (int x = y % 2; x < patternSize; x+=2) { + PRectangle rcPixel(x, y, x+1, y+1); + pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); + } } } @@ -3081,10 +3314,9 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated); pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated); for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) { - pixmapIndentGuide->MoveTo(0, stripe); - pixmapIndentGuide->LineTo(2, stripe); - pixmapIndentGuideHighlight->MoveTo(0, stripe); - pixmapIndentGuideHighlight->LineTo(2, stripe); + PRectangle rcPixel(0, stripe, 1, stripe+1); + pixmapIndentGuide->FillRectangle(rcPixel, vs.styles[STYLE_INDENTGUIDE].fore.allocated); + pixmapIndentGuideHighlight->FillRectangle(rcPixel, vs.styles[STYLE_BRACELIGHT].fore.allocated); } } @@ -3186,6 +3418,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + StyleToPositionInView(PositionAfterArea(rcArea)); + pixmapLine->Release(); RefreshStyleData(); RefreshPixMaps(surfaceWindow); @@ -3198,13 +3432,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { pixmapLine->SetPalette(&palette, !hasFocus); int screenLinePaintFirst = rcArea.top / vs.lineHeight; - // The area to be painted plus one extra line is styled. - // The extra line is to determine when a style change, such as starting a comment flows on to other lines. - int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1; - //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast); - int endPosPaint = pdoc->Length(); - if (lineStyleLast < cs.LinesDisplayed()) - endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast) + 1); int xStart = vs.fixedColumnWidth - xOffset; int ypos = 0; @@ -3212,8 +3439,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { ypos += screenLinePaintFirst * vs.lineHeight; int yposScreen = screenLinePaintFirst * vs.lineHeight; - // Ensure we are styled as far as we are painting. - pdoc->EnsureStyledTo(endPosPaint); bool paintAbandonedByStyling = paintState == paintAbandoned; if (needUpdateUI) { // Deselect palette by selecting a temporary palette @@ -3221,7 +3446,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { surfaceWindow->SetPalette(&palTemp, true); NotifyUpdateUI(); - needUpdateUI = false; + needUpdateUI = 0; RefreshStyleData(); RefreshPixMaps(surfaceWindow); @@ -3245,12 +3470,14 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { } PLATFORM_ASSERT(pixmapSelPattern->Initialised()); - PaintSelMargin(surfaceWindow, rcArea); + if (paintState != paintAbandoned) { + PaintSelMargin(surfaceWindow, rcArea); - PRectangle rcRightMargin = rcClient; - rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; - if (rcArea.Intersects(rcRightMargin)) { - surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated); + PRectangle rcRightMargin = rcClient; + rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; + if (rcArea.Intersects(rcRightMargin)) { + surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated); + } } if (paintState == paintAbandoned) { @@ -3331,34 +3558,40 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { rcLine.top = ypos; rcLine.bottom = ypos + vs.lineHeight; + bool bracesIgnoreStyle = false; + if ((vs.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || + (vs.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { + bracesIgnoreStyle = true; + } Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1)); // Highlight the current braces if any ll->SetBracesHighlight(rangeLine, braces, static_cast(bracesMatchStyle), - highlightGuideColumn * vs.spaceWidth); + highlightGuideColumn * vs.spaceWidth, bracesIgnoreStyle); // Draw the line DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine); //durPaint += et.Duration(true); // Restore the previous styles for the brace highlights in case layout is in cache. - ll->RestoreBracesHighlight(rangeLine, braces); + ll->RestoreBracesHighlight(rangeLine, braces, bracesIgnoreStyle); bool expanded = cs.GetExpanded(lineDoc); - // Paint the line above the fold - if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) - || - (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { - if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + const int level = pdoc->GetLevel(lineDoc); + const int levelNext = pdoc->GetLevel(lineDoc + 1); + if ((level & SC_FOLDLEVELHEADERFLAG) && + ((level & SC_FOLDLEVELNUMBERMASK) < (levelNext & SC_FOLDLEVELNUMBERMASK))) { + // Paint the line above the fold + if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.bottom = rcFoldLine.top + 1; surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); } - } - // Paint the line below the fold - if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) - || - (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { - if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + // Paint the line below the fold + if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.top = rcFoldLine.bottom - 1; surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); @@ -3472,9 +3705,12 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { vsPrint.whitespaceBackgroundSet = false; vsPrint.whitespaceForegroundSet = false; vsPrint.showCaretLineBackground = false; + // Don't highlight matching braces using indicators + vsPrint.braceHighlightIndicatorSet = false; + vsPrint.braceBadLightIndicatorSet = false; // Set colours for printing according to users settings - for (size_t sty = 0;sty < vsPrint.stylesSize;sty++) { + for (size_t sty = 0; sty < vsPrint.stylesSize; sty++) { if (printColourMode == SC_PRINT_INVERTLIGHT) { vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired); vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired); @@ -3529,7 +3765,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { int nPrintPos = pfr->chrg.cpMin; int visibleLine = 0; - int widthPrint = pfr->rc.Width() - vsPrint.fixedColumnWidth; + int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth; if (printWrapState == eWrapNone) widthPrint = LineLayout::wrapWidthInfinite; @@ -3727,7 +3963,11 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { if (wrapState != eWrapNone) { AutoSurface surface(this); if (surface) { - WrapOneLine(surface, pdoc->LineFromPosition(positionInsert)); + if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) { + SetScrollBars(); + SetVerticalScrollPos(); + Redraw(); + } } } } @@ -3741,7 +3981,8 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { EnsureCaretVisible(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); - if (!caretSticky) { + if ((caretSticky == SC_CARETSTICKY_OFF) || + ((caretSticky == SC_CARETSTICKY_WHITESPACE) && !IsAllSpacesOrTabs(s, len))) { SetLastXChosen(); } @@ -3787,8 +4028,40 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { } } -void Editor::ClearSelection() { - if (!sel.IsRectangular()) +void Editor::InsertPaste(SelectionPosition selStart, const char *text, int len) { + if (multiPasteMode == SC_MULTIPASTE_ONCE) { + selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace())); + if (pdoc->InsertString(selStart.Position(), text, len)) { + SetEmptySelection(selStart.Position() + len); + } + } else { + // SC_MULTIPASTE_EACH + for (size_t r=0; rDeleteChars(positionInsert, sel.Range(r).Length()); + sel.Range(r).ClearVirtualSpace(); + } else { + // Range is all virtual so collapse to start of virtual space + sel.Range(r).MinimizeVirtualSpace(); + } + } + positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace()); + if (pdoc->InsertString(positionInsert, text, len)) { + sel.Range(r).caret.SetPosition(positionInsert + len); + sel.Range(r).anchor.SetPosition(positionInsert + len); + } + sel.Range(r).ClearVirtualSpace(); + } + } + } +} + +void Editor::ClearSelection(bool retainMultipleSelections) { + if (!sel.IsRectangular() && !retainMultipleSelections) FilterSelections(); UndoGroup ug(pdoc); for (size_t r=0; r 1); for (size_t r=0; rIncrementStyleClock(); @@ -4231,7 +4529,16 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { // Some lines are hidden so may need shown. // TODO: check if the modified area is hidden. if (mh.modificationType & SC_MOD_BEFOREINSERT) { - NotifyNeedShown(mh.position, 0); + int lineOfPos = pdoc->LineFromPosition(mh.position); + bool insertingNewLine = false; + for (int i=0; i < mh.length; i++) { + if ((mh.text[i] == '\n') || (mh.text[i] == '\r')) + insertingNewLine = true; + } + if (insertingNewLine && (mh.position != pdoc->LineStart(lineOfPos))) + NotifyNeedShown(mh.position, pdoc->LineStart(lineOfPos+1) - mh.position); + else + NotifyNeedShown(mh.position, 0); } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { NotifyNeedShown(mh.position, mh.length); } @@ -4250,6 +4557,7 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { int lineDoc = pdoc->LineFromPosition(mh.position); if (vs.annotationVisible) { cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded); + Redraw(); } } CheckModificationForWrap(mh); @@ -4267,12 +4575,14 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { // TODO: could invalidate from mh.startModification to end of screen //InvalidateRange(mh.position, mh.position + mh.length); if (paintState == notPainting && !CanDeferToLastStep(mh)) { + QueueStyling(pdoc->Length()); Redraw(); } } else { //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, // mh.position, mh.position + mh.length); if (paintState == notPainting && mh.length && !CanEliminate(mh)) { + QueueStyling(mh.position + mh.length); InvalidateRange(mh.position, mh.position + mh.length); } } @@ -4286,7 +4596,7 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { if ((paintState == notPainting) || !PaintContainsMargin()) { if (mh.modificationType & SC_MOD_CHANGEFOLD) { // Fold changes can affect the drawing of following lines so redraw whole margin - RedrawSelMargin(); + RedrawSelMargin(mh.line-1, true); } else { RedrawSelMargin(mh.line); } @@ -4430,6 +4740,9 @@ void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lPar case SCI_PAGEDOWNRECTEXTEND: case SCI_SELECTIONDUPLICATE: case SCI_COPYALLOWLINE: + case SCI_VERTICALCENTRECARET: + case SCI_MOVESELECTEDLINESUP: + case SCI_MOVESELECTEDLINESDOWN: break; // Filter out all others like display changes. Also, newlines are redundant @@ -4449,6 +4762,11 @@ void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lPar NotifyParent(scn); } +// Something has changed that the container should know about +void Editor::ContainerNeedsUpdate(int flags) { + needUpdateUI |= flags; +} + /** * Force scroll and keep position relative to top of window. * @@ -4456,51 +4774,76 @@ void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lPar * If stuttered = true and already at first/last row, scroll as normal. */ void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) { - int topLineNew, newPos; + int topLineNew; + SelectionPosition newPos; - // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem? int currentLine = pdoc->LineFromPosition(sel.MainCaret()); int topStutterLine = topLine + caretYSlop; int bottomStutterLine = pdoc->LineFromPosition(PositionFromLocation( - Point(lastXChosen, direction * vs.lineHeight * LinesToScroll()))) + Point(lastXChosen - xOffset, direction * vs.lineHeight * LinesToScroll()))) - caretYSlop - 1; if (stuttered && (direction < 0 && currentLine > topStutterLine)) { topLineNew = topLine; - newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * caretYSlop)); + newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * caretYSlop), + false, false, UserVirtualSpace()); } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) { topLineNew = topLine; - newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop))); + newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * (LinesToScroll() - caretYSlop)), + false, false, UserVirtualSpace()); } else { Point pt = LocationFromPosition(sel.MainCaret()); topLineNew = Platform::Clamp( topLine + direction * LinesToScroll(), 0, MaxScrollPos()); - newPos = PositionFromLocation( - Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll()))); + newPos = SPositionFromLocation( + Point(lastXChosen - xOffset, pt.y + direction * (vs.lineHeight * LinesToScroll())), + false, false, UserVirtualSpace()); } if (topLineNew != topLine) { SetTopLine(topLineNew); - MovePositionTo(SelectionPosition(newPos), selt); + MovePositionTo(newPos, selt); Redraw(); SetVerticalScrollPos(); } else { - MovePositionTo(SelectionPosition(newPos), selt); + MovePositionTo(newPos, selt); } } -void Editor::ChangeCaseOfSelection(bool makeUpperCase) { +void Editor::ChangeCaseOfSelection(int caseMapping) { UndoGroup ug(pdoc); for (size_t r=0; rChangeCase(Range(current.Start().Position(), current.End().Position()), - makeUpperCase); - // Automatic movement cuts off last character so reset to exactly the same as it was. - sel.Range(r) = current; + SelectionRange currentNoVS = current; + currentNoVS.ClearVirtualSpace(); + char *text = CopyRange(currentNoVS.Start().Position(), currentNoVS.End().Position()); + size_t rangeBytes = currentNoVS.Length(); + if (rangeBytes > 0) { + std::string sText(text, rangeBytes); + + std::string sMapped = CaseMapString(sText, caseMapping); + + if (sMapped != sText) { + size_t firstDifference = 0; + while (sMapped[firstDifference] == sText[firstDifference]) + firstDifference++; + size_t lastDifference = sMapped.size() - 1; + while (sMapped[lastDifference] == sText[lastDifference]) + lastDifference--; + size_t endSame = sMapped.size() - 1 - lastDifference; + pdoc->DeleteChars(currentNoVS.Start().Position() + firstDifference, + rangeBytes - firstDifference - endSame); + pdoc->InsertString(currentNoVS.Start().Position() + firstDifference, + sMapped.c_str() + firstDifference, lastDifference - firstDifference + 1); + // Automatic movement changes selection so reset to exactly the same as it was. + sel.Range(r) = current; + } + } + delete []text; } } @@ -4531,7 +4874,6 @@ void Editor::Duplicate(bool forLine) { forLine = true; } UndoGroup ug(pdoc, sel.Count() > 1); - SelectionPosition last; const char *eol = ""; int eolLen = 0; if (forLine) { @@ -4613,10 +4955,10 @@ void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { int subLine = (pt.y - ptStartLine.y) / vs.lineHeight; int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0; SelectionPosition posNew = SPositionFromLocation( - Point(lastXChosen, pt.y + direction * vs.lineHeight), false, false, UserVirtualSpace()); + Point(lastXChosen - xOffset, pt.y + direction * vs.lineHeight), false, false, UserVirtualSpace()); if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) { posNew = SPositionFromLocation( - Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight), false, false, UserVirtualSpace()); + Point(lastXChosen - xOffset, pt.y + (commentLines + 1) * vs.lineHeight), false, false, UserVirtualSpace()); } if (direction < 0) { // Line wrapping may lead to a location on the same line, so @@ -4935,6 +5277,7 @@ int Editor::KeyCommand(unsigned int iMessage) { inOverstrike = !inOverstrike; DropCaret(); ShowCaretAtCurrentPosition(); + ContainerNeedsUpdate(SC_UPDATE_CONTENT); NotifyUpdateUI(); break; case SCI_CANCEL: // Cancel any modes - handled in subclass @@ -4943,21 +5286,21 @@ int Editor::KeyCommand(unsigned int iMessage) { break; case SCI_DELETEBACK: DelCharBack(true); - if (!caretSticky) { + if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_DELETEBACKNOTLINE: DelCharBack(false); - if (!caretSticky) { + if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_TAB: Indent(true); - if (!caretSticky) { + if (caretSticky == SC_CARETSTICKY_OFF) { SetLastXChosen(); } EnsureCaretVisible(); @@ -4965,7 +5308,7 @@ int Editor::KeyCommand(unsigned int iMessage) { break; case SCI_BACKTAB: Indent(false); - if (!caretSticky) { + if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); @@ -5034,6 +5377,7 @@ int Editor::KeyCommand(unsigned int iMessage) { UndoGroup ug(pdoc); sel.RangeMain().caret = SelectionPosition( InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); + sel.RangeMain().anchor = sel.RangeMain().caret; int endWord = pdoc->NextWordStart(sel.MainCaret(), 1); pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); } @@ -5094,10 +5438,10 @@ int Editor::KeyCommand(unsigned int iMessage) { Duplicate(false); break; case SCI_LOWERCASE: - ChangeCaseOfSelection(false); + ChangeCaseOfSelection(cmLower); break; case SCI_UPPERCASE: - ChangeCaseOfSelection(true); + ChangeCaseOfSelection(cmUpper); break; case SCI_WORDPARTLEFT: MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1)); @@ -5205,7 +5549,7 @@ void Editor::Indent(bool forwards) { int indentation = pdoc->GetLineIndentation(lineCurrentPos); int indentationStep = pdoc->IndentSize(); pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); - SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos)); + sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos)); } else { int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) * pdoc->tabInChars; @@ -5244,6 +5588,31 @@ void Editor::Indent(bool forwards) { } } +class CaseFolderASCII : public CaseFolderTable { +public: + CaseFolderASCII() { + StandardASCII(); + } + ~CaseFolderASCII() { + } + virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { + if (lenMixed > sizeFolded) { + return 0; + } else { + for (size_t i=0; i(mixed[i])]; + } + return lenMixed; + } + } +}; + + +CaseFolder *Editor::CaseFolderForEncoding() { + // Simple default that only maps ASCII upper case to lower case. + return new CaseFolderASCII(); +} + /** * Search of a text in the document, in the given range. * @return The position of the found text, -1 if not found. @@ -5255,13 +5624,15 @@ long Editor::FindText( Sci_TextToFind *ft = reinterpret_cast(lParam); int lengthFound = istrlen(ft->lpstrText); + std::auto_ptr pcf(CaseFolderForEncoding()); int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, (wParam & SCFIND_MATCHCASE) != 0, (wParam & SCFIND_WHOLEWORD) != 0, (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, - &lengthFound); + &lengthFound, + pcf.get()); if (pos != -1) { ft->chrgText.cpMin = pos; ft->chrgText.cpMax = pos + lengthFound; @@ -5298,6 +5669,7 @@ long Editor::SearchText( const char *txt = reinterpret_cast(lParam); int pos; int lengthFound = istrlen(txt); + std::auto_ptr pcf(CaseFolderForEncoding()); if (iMessage == SCI_SEARCHNEXT) { pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, (wParam & SCFIND_MATCHCASE) != 0, @@ -5305,7 +5677,8 @@ long Editor::SearchText( (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, - &lengthFound); + &lengthFound, + pcf.get()); } else { pos = pdoc->FindText(searchAnchor, 0, txt, (wParam & SCFIND_MATCHCASE) != 0, @@ -5313,9 +5686,9 @@ long Editor::SearchText( (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, - &lengthFound); + &lengthFound, + pcf.get()); } - if (pos != -1) { SetSelection(pos, pos + lengthFound); } @@ -5323,19 +5696,39 @@ long Editor::SearchText( return pos; } +std::string Editor::CaseMapString(const std::string &s, int caseMapping) { + std::string ret(s); + for (size_t i=0; i= 'a' && ret[i] <= 'z') + ret[i] = static_cast(ret[i] - 'a' + 'A'); + break; + case cmLower: + if (ret[i] >= 'A' && ret[i] <= 'Z') + ret[i] = static_cast(ret[i] - 'A' + 'a'); + break; + } + } + return ret; +} + /** * Search for text in the target range of the document. * @return The position of the found text, -1 if not found. */ long Editor::SearchInTarget(const char *text, int length) { int lengthFound = length; + + std::auto_ptr pcf(CaseFolderForEncoding()); int pos = pdoc->FindText(targetStart, targetEnd, text, (searchFlags & SCFIND_MATCHCASE) != 0, (searchFlags & SCFIND_WHOLEWORD) != 0, (searchFlags & SCFIND_WORDSTART) != 0, (searchFlags & SCFIND_REGEXP) != 0, searchFlags, - &lengthFound); + &lengthFound, + pcf.get()); if (pos != -1) { targetStart = pos; targetEnd = pos + lengthFound; @@ -5591,6 +5984,16 @@ bool Editor::PointInSelMargin(Point pt) { } } +Window::Cursor Editor::GetMarginCursor(Point pt) { + int x = 0; + for (int margin = 0; margin < ViewStyle::margins; margin++) { + if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width)) + return static_cast(vs.ms[margin].cursor); + x += vs.ms[margin].width; + } + return Window::cursorReverseArrow; +} + void Editor::LineSelection(int lineCurrent_, int lineAnchor_) { if (lineAnchor_ < lineCurrent_) { SetSelection(pdoc->LineStart(lineCurrent_ + 1), @@ -5604,6 +6007,30 @@ void Editor::LineSelection(int lineCurrent_, int lineAnchor_) { } } +void Editor::WordSelection(int pos) { + if (pos < wordSelectAnchorStartPos) { + // Extend backward to the word containing pos. + // Skip ExtendWordSelect if the line is empty or if pos is after the last character. + // This ensures that a series of empty lines isn't counted as a single "word". + if (!pdoc->IsLineEndPosition(pos)) + pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos + 1, 1), -1); + SetSelection(pos, wordSelectAnchorEndPos); + } else if (pos > wordSelectAnchorEndPos) { + // Extend forward to the word containing the character to the left of pos. + // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line. + // This ensures that a series of empty lines isn't counted as a single "word". + if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos))) + pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1); + SetSelection(pos, wordSelectAnchorStartPos); + } else { + // Select only the anchored word + if (pos >= originalAnchorPos) + SetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos); + else + SetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos); + } +} + void Editor::DwellEnd(bool mouseMoved) { if (mouseMoved) ticksToDwell = dwellDelay; @@ -5615,7 +6042,15 @@ void Editor::DwellEnd(bool mouseMoved) { } } -static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) { +void Editor::MouseLeave() { + SetHotSpotRange(NULL); + if (!HaveMouseCapture()) { + ptMouseLast = Point(-1,-1); + DwellEnd(true); + } +} + +static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) { return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0) || (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0)); } @@ -5657,13 +6092,33 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b } if (selectionType == selWord) { - if (sel.MainCaret() >= originalAnchorPos) { // Moved forward - SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), 1), - pdoc->ExtendWordSelect(originalAnchorPos, -1)); - } else { // Moved backward - SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), -1), - pdoc->ExtendWordSelect(originalAnchorPos, 1)); + int charPos = originalAnchorPos; + if (sel.MainCaret() == originalAnchorPos) { + charPos = PositionFromLocation(pt, false, true); + charPos = MovePositionOutsideChar(charPos, -1); + } + + int startWord, endWord; + if ((sel.MainCaret() >= originalAnchorPos) && !pdoc->IsLineEndPosition(charPos)) { + startWord = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(charPos + 1, 1), -1); + endWord = pdoc->ExtendWordSelect(charPos, 1); + } else { + // Selecting backwards, or anchor beyond last character on line. In these cases, + // we select the word containing the character to the *left* of the anchor. + if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) { + startWord = pdoc->ExtendWordSelect(charPos, -1); + endWord = pdoc->ExtendWordSelect(startWord, 1); + } else { + // Anchor at start of line; select nothing to begin with. + startWord = charPos; + endWord = charPos; + } } + + wordSelectAnchorStartPos = startWord; + wordSelectAnchorEndPos = endWord; + wordSelectInitialCaretPos = sel.MainCaret(); + WordSelection(wordSelectInitialCaretPos); } else if (selectionType == selLine) { lineAnchor = LineFromLocation(pt); SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor)); @@ -5708,6 +6163,7 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b } else { if (PointIsHotspot(pt)) { NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt); + hotSpotClickPos = PositionFromLocation(pt,true,false); } if (!shift) { if (PointInSelection(pt) && !SelectionEmpty()) @@ -5727,7 +6183,8 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b InvalidateSelection(SelectionRange(newPos), true); if (sel.Count() > 1) Redraw(); - sel.Clear(); + if ((sel.Count() > 1) || (sel.selType != Selection::selStream)) + sel.Clear(); sel.selType = alt ? Selection::selRectangle : Selection::selStream; SetSelection(newPos, newPos); } @@ -5745,7 +6202,7 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b } } lastClickTime = curTime; - lastXChosen = pt.x; + lastXChosen = pt.x + xOffset; ShowCaretAtCurrentPosition(); } @@ -5793,7 +6250,7 @@ void Editor::SetHotSpotRange(Point *pt) { } } -void Editor::GetHotSpotRange(int& hsStart_, int& hsEnd_) { +void Editor::GetHotSpotRange(int &hsStart_, int &hsEnd_) { hsStart_ = hsStart; hsEnd_ = hsEnd; } @@ -5844,7 +6301,7 @@ void Editor::ButtonMove(Point pt) { } } else if (selectionType == selWord) { // Continue selecting by word - if (movePos.Position() == originalAnchorPos) { // Didn't move + if (movePos.Position() == wordSelectInitialCaretPos) { // Didn't move // No need to do anything. Previously this case was lumped // in with "Moved forward", but that can be harmful in this // case: a handler for the NotifyDoubleClick re-adjusts @@ -5854,12 +6311,9 @@ void Editor::ButtonMove(Point pt) { // the ButtonMove() called via Tick() for auto-scrolling // could result in the fancier word selection adjustment // being unmade. - } else if (movePos.Position() > originalAnchorPos) { // Moved forward - SetSelection(pdoc->ExtendWordSelect(movePos.Position(), 1), - pdoc->ExtendWordSelect(originalAnchorPos, -1)); - } else { // Moved backward - SetSelection(pdoc->ExtendWordSelect(movePos.Position(), -1), - pdoc->ExtendWordSelect(originalAnchorPos, 1)); + } else { + wordSelectInitialCaretPos = -1; + WordSelection(movePos.Position()); } } else { // Continue selecting by line @@ -5887,10 +6341,18 @@ void Editor::ButtonMove(Point pt) { if (hsStart != -1 && !PositionIsHotspot(movePos.Position())) SetHotSpotRange(NULL); + if (hotSpotClickPos != INVALID_POSITION && PositionFromLocation(pt,true,false) != hotSpotClickPos) { + if (inDragDrop == ddNone) { + DisplayCursor(Window::cursorText); + } + hotSpotClickPos = INVALID_POSITION; + } + } else { if (vs.fixedColumnWidth > 0) { // There is a margin if (PointInSelMargin(pt)) { - DisplayCursor(Window::cursorReverseArrow); + DisplayCursor(GetMarginCursor(pt)); + SetHotSpotRange(NULL); return; // No need to test for selection } } @@ -5915,10 +6377,16 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { if (inDragDrop == ddInitial) { inDragDrop = ddNone; SetEmptySelection(newPos.Position()); + selectionType = selChar; + originalAnchorPos = sel.MainCaret(); + } + if (hotSpotClickPos != INVALID_POSITION && PointIsHotspot(pt)) { + hotSpotClickPos = INVALID_POSITION; + NotifyHotSpotReleaseClick(newPos.Position(), false, ctrl, false); } if (HaveMouseCapture()) { if (PointInSelMargin(pt)) { - DisplayCursor(Window::cursorReverseArrow); + DisplayCursor(GetMarginCursor(pt)); } else { DisplayCursor(Window::cursorText); SetHotSpotRange(NULL); @@ -5968,7 +6436,7 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { SetRectangularRange(); lastClickTime = curTime; lastClick = pt; - lastXChosen = pt.x; + lastXChosen = pt.x + xOffset; if (sel.selType == Selection::selStream) { SetLastXChosen(); } @@ -6000,7 +6468,8 @@ void Editor::Tick() { } if ((dwellDelay < SC_TIME_FOREVER) && (ticksToDwell > 0) && - (!HaveMouseCapture())) { + (!HaveMouseCapture()) && + (ptMouseLast.y >= 0)) { ticksToDwell -= timer.tickSize; if (ticksToDwell <= 0) { dwelling = true; @@ -6044,6 +6513,48 @@ void Editor::SetFocusState(bool focusState) { } } +int Editor::PositionAfterArea(PRectangle rcArea) { + // The start of the document line after the display line after the area + // This often means that the line after a modification is restyled which helps + // detect multiline comment additions and heals single line comments + int lineAfter = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1; + if (lineAfter < cs.LinesDisplayed()) + return pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1); + else + return pdoc->Length(); +} + +// Style to a position within the view. If this causes a change at end of last line then +// affects later lines so style all the viewed text. +void Editor::StyleToPositionInView(Position pos) { + int endWindow = PositionAfterArea(GetClientRectangle()); + if (pos > endWindow) + pos = endWindow; + int styleAtEnd = pdoc->StyleAt(pos-1); + pdoc->EnsureStyledTo(pos); + if ((endWindow > pos) && (styleAtEnd != pdoc->StyleAt(pos-1))) { + // Style at end of line changed so is multi-line change like starting a comment + // so require rest of window to be styled. + pdoc->EnsureStyledTo(endWindow); + } +} + +void Editor::IdleStyling() { + // Style the line after the modification as this allows modifications that change just the + // line of the modification to heal instead of propagating to the rest of the window. + StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2)); + + if (needUpdateUI) { + NotifyUpdateUI(); + needUpdateUI = 0; + } + styleNeeded.Reset(); +} + +void Editor::QueueStyling(int upTo) { + styleNeeded.NeedUpTo(upTo); +} + bool Editor::PaintContains(PRectangle rc) { if (rc.Empty()) { return true; @@ -6150,6 +6661,7 @@ void Editor::SetAnnotationVisible(int visible) { } } } + Redraw(); } } @@ -6185,8 +6697,8 @@ void Editor::ToggleContraction(int line) { if (cs.GetExpanded(line)) { int lineMaxSubord = pdoc->GetLastChild(line); - cs.SetExpanded(line, 0); if (lineMaxSubord > line) { + cs.SetExpanded(line, 0); cs.SetVisible(line + 1, lineMaxSubord, false); int lineCurrent = pdoc->LineFromPosition(sel.MainCaret()); @@ -6212,6 +6724,18 @@ void Editor::ToggleContraction(int line) { } } +int Editor::ContractedFoldNext(int lineStart) { + for (int line = lineStart; lineLinesTotal();) { + if (!cs.GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG)) + return line; + line = cs.ContractedNext(line+1); + if (line < 0) + return -1; + } + + return -1; +} + /** * Recurse up from this line to find any folds that prevent this line from being visible * and unfold them all. @@ -6257,6 +6781,24 @@ void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { } } +int Editor::GetTag(char *tagValue, int tagNumber) { + char name[3] = "\\?"; + const char *text = 0; + int length = 0; + if ((tagNumber >= 1) && (tagNumber <= 9)) { + name[1] = static_cast(tagNumber + '0'); + length = 2; + text = pdoc->SubstituteByPosition(name, &length); + } + if (tagValue) { + if (text) + memcpy(tagValue, text, length + 1); + else + *tagValue = '\0'; + } + return length; +} + int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) { UndoGroup ug(pdoc); if (length == -1) @@ -6303,11 +6845,11 @@ void Editor::AddStyledText(char *buffer, int appendLength) { size_t textLength = appendLength / 2; char *text = new char[textLength]; size_t i; - for (i = 0;i < textLength;i++) { + for (i = 0; i < textLength; i++) { text[i] = buffer[i*2]; } pdoc->InsertString(CurrentPosition(), text, textLength); - for (i = 0;i < textLength;i++) { + for (i = 0; i < textLength; i++) { text[i] = buffer[i*2+1]; } pdoc->StartStyling(CurrentPosition(), static_cast(0xff)); @@ -6466,6 +7008,18 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { CopyAllowLine(); break; + case SCI_VERTICALCENTRECARET: + VerticalCentreCaret(); + break; + + case SCI_MOVESELECTEDLINESUP: + MoveSelectedLinesUp(); + break; + + case SCI_MOVESELECTEDLINESDOWN: + MoveSelectedLinesDown(); + break; + case SCI_COPYRANGE: CopyRangeToClipboard(wParam, lParam); break; @@ -6476,7 +7030,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_PASTE: Paste(); - if (!caretSticky) { + if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); @@ -6641,6 +7195,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETSEARCHFLAGS: return searchFlags; + case SCI_GETTAG: + return GetTag(CharPtrFromSPtr(lParam), wParam); + case SCI_POSITIONBEFORE: return pdoc->MovePositionOutsideChar(wParam - 1, -1, true); @@ -6654,6 +7211,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_SETXOFFSET: xOffset = wParam; + ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); SetHorizontalScrollPos(); Redraw(); break; @@ -6861,14 +7419,14 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_GETSELECTIONSTART: - return Platform::Minimum(sel.MainAnchor(), sel.MainCaret()); + return sel.LimitsForRectangularElseMain().start.Position(); case SCI_SETSELECTIONEND: SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam)); break; case SCI_GETSELECTIONEND: - return Platform::Maximum(sel.MainAnchor(), sel.MainCaret()); + return sel.LimitsForRectangularElseMain().end.Position(); case SCI_SETPRINTMAGNIFICATION: printMagnification = wParam; @@ -6968,7 +7526,6 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GOTOPOS: SetEmptySelection(wParam); EnsureCaretVisible(); - Redraw(); break; case SCI_GETCURLINE: { @@ -7119,6 +7676,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; } xOffset = 0; + ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); InvalidateStyleRedraw(); ReconfigureScrollBars(); break; @@ -7127,9 +7685,11 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return wrapState; case SCI_SETWRAPVISUALFLAGS: - wrapVisualFlags = wParam; - InvalidateStyleRedraw(); - ReconfigureScrollBars(); + if (wrapVisualFlags != static_cast(wParam)) { + wrapVisualFlags = wParam; + InvalidateStyleRedraw(); + ReconfigureScrollBars(); + } break; case SCI_GETWRAPVISUALFLAGS: @@ -7144,18 +7704,22 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return wrapVisualFlagsLocation; case SCI_SETWRAPSTARTINDENT: - wrapVisualStartIndent = wParam; - InvalidateStyleRedraw(); - ReconfigureScrollBars(); + if (wrapVisualStartIndent != static_cast(wParam)) { + wrapVisualStartIndent = wParam; + InvalidateStyleRedraw(); + ReconfigureScrollBars(); + } break; case SCI_GETWRAPSTARTINDENT: return wrapVisualStartIndent; case SCI_SETWRAPINDENTMODE: - wrapIndentMode = wParam; - InvalidateStyleRedraw(); - ReconfigureScrollBars(); + if (wrapIndentMode != static_cast(wParam)) { + wrapIndentMode = wParam; + InvalidateStyleRedraw(); + ReconfigureScrollBars(); + } break; case SCI_GETWRAPINDENTMODE: @@ -7222,9 +7786,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return endAtLastLine; case SCI_SETCARETSTICKY: - PLATFORM_ASSERT((wParam == 0) || (wParam == 1)); - if (caretSticky != (wParam != 0)) { - caretSticky = wParam != 0; + PLATFORM_ASSERT((wParam >= SC_CARETSTICKY_OFF) && (wParam <= SC_CARETSTICKY_WHITESPACE)); + if ((wParam >= SC_CARETSTICKY_OFF) && (wParam <= SC_CARETSTICKY_WHITESPACE)) { + caretSticky = wParam; } break; @@ -7322,6 +7886,15 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { InvalidateStyleData(); RedrawSelMargin(); break; + case SCI_MARKERSETBACKSELECTED: + if (wParam <= MARKER_MAX) + vs.markers[wParam].backSelected.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + case SCI_MARKERENABLEHIGHLIGHT: + highlightDelimiter.isEnabled = wParam == 1; + InvalidateStyleRedraw(); + break; case SCI_MARKERSETBACK: if (wParam <= MARKER_MAX) vs.markers[wParam].back.desired = ColourDesired(lParam); @@ -7433,6 +8006,17 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { else return 0; + case SCI_SETMARGINCURSORN: + if (ValidMargin(wParam)) + vs.ms[wParam].cursor = lParam; + break; + + case SCI_GETMARGINCURSORN: + if (ValidMargin(wParam)) + return vs.ms[wParam].cursor; + else + return 0; + case SCI_STYLECLEARALL: vs.ClearStyles(); InvalidateStyleRedraw(); @@ -7570,6 +8154,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { ToggleContraction(wParam); break; + case SCI_CONTRACTEDFOLDNEXT: + return ContractedFoldNext(wParam); + case SCI_ENSUREVISIBLE: EnsureLineVisible(wParam, false); break; @@ -7725,7 +8312,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0; case SCI_INDICSETALPHA: - if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 100) { + if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { vs.indicators[wParam].fillAlpha = lParam; InvalidateStyleRedraw(); } @@ -7734,6 +8321,16 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_INDICGETALPHA: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0; + case SCI_INDICSETOUTLINEALPHA: + if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { + vs.indicators[wParam].outlineAlpha = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETOUTLINEALPHA: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].outlineAlpha : 0; + case SCI_SETINDICATORCURRENT: pdoc->decorations.SetCurrentIndicator(wParam); break; @@ -7859,10 +8456,24 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { SetBraceHighlight(static_cast(wParam), lParam, STYLE_BRACELIGHT); break; + case SCI_BRACEHIGHLIGHTINDICATOR: + if (lParam >= 0 && lParam <= INDIC_MAX) { + vs.braceHighlightIndicatorSet = wParam != 0; + vs.braceHighlightIndicator = lParam; + } + break; + case SCI_BRACEBADLIGHT: SetBraceHighlight(static_cast(wParam), -1, STYLE_BRACEBAD); break; + case SCI_BRACEBADLIGHTINDICATOR: + if (lParam >= 0 && lParam <= INDIC_MAX) { + vs.braceBadLightIndicatorSet = wParam != 0; + vs.braceBadLightIndicator = lParam; + } + break; + case SCI_BRACEMATCH: // wParam is position of char to find brace for, // lParam is maximum amount of text to restyle to find it @@ -8261,6 +8872,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETADDITIONALSELECTIONTYPING: return additionalSelectionTyping; + case SCI_SETMULTIPASTE: + multiPasteMode = wParam; + break; + + case SCI_GETMULTIPASTE: + return multiPasteMode; + case SCI_SETADDITIONALCARETSBLINK: additionalCaretsBlink = wParam != 0; InvalidateCaret(); @@ -8441,6 +9059,10 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret); break; + case SCI_CHANGELEXERSTATE: + pdoc->ChangeLexerState(wParam, lParam); + break; + default: return DefWndProc(iMessage, wParam, lParam); } diff --git a/plugins/scintilla/scintilla/Editor.h b/plugins/scintilla/scintilla/Editor.h index 92dcfb1..5c01ee8 100644 --- a/plugins/scintilla/scintilla/Editor.h +++ b/plugins/scintilla/scintilla/Editor.h @@ -2,7 +2,7 @@ /** @file Editor.h ** Defines the main editor class. **/ -// Copyright 1998-2003 by Neil Hodgson +// Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef EDITOR_H @@ -46,6 +46,26 @@ public: }; /** + * When platform has a way to generate an event before painting, + * accumulate needed styling range in StyleNeeded to avoid unnecessary work. + */ +class StyleNeeded { +public: + bool active; + Position upTo; + + StyleNeeded() : active(false), upTo(0) {} + void Reset() { + active = false; + upTo = 0; + } + void NeedUpTo(Position pos) { + if (upTo < pos) + upTo = pos; + } +}; + +/** * Hold a piece of text selected for copying or dragging. * The text is expected to hold a terminating '\0' and this is counted in len. */ @@ -119,6 +139,9 @@ protected: // ScintillaBase subclass needs access to much of Editor int cursorMode; int controlCharSymbol; + // Highlight current folding block + HighlightDelimiter highlightDelimiter; + bool hasFocus; bool hideSelection; bool inOverstrike; @@ -139,9 +162,10 @@ protected: // ScintillaBase subclass needs access to much of Editor int lineWidthMaxSeen; bool verticalScrollBarVisible; bool endAtLastLine; - bool caretSticky; + int caretSticky; bool multipleSelection; bool additionalSelectionTyping; + int multiPasteMode; bool additionalCaretsBlink; bool additionalCaretsVisible; @@ -176,9 +200,13 @@ protected: // ScintillaBase subclass needs access to much of Editor bool dropWentOutside; SelectionPosition posDrag; SelectionPosition posDrop; + int hotSpotClickPos; int lastXChosen; int lineAnchor; int originalAnchorPos; + int wordSelectAnchorStartPos; + int wordSelectAnchorEndPos; + int wordSelectInitialCaretPos; int targetStart; int targetEnd; int searchFlags; @@ -186,7 +214,7 @@ protected: // ScintillaBase subclass needs access to much of Editor int posTopLine; int lengthForEncode; - bool needUpdateUI; + int needUpdateUI; Position braces[2]; int bracesMatchStyle; int highlightGuideColumn; @@ -196,6 +224,7 @@ protected: // ScintillaBase subclass needs access to much of Editor enum { notPainting, painting, paintAbandoned } paintState; PRectangle rcPaint; bool paintingAllText; + StyleNeeded styleNeeded; int modEventMask; @@ -271,7 +300,7 @@ protected: // ScintillaBase subclass needs access to much of Editor bool AbandonPaint(); void RedrawRect(PRectangle rc); void Redraw(); - void RedrawSelMargin(int line=-1); + void RedrawSelMargin(int line=-1, bool allAfter=false); PRectangle RectangleFromRange(int start, int end); void InvalidateRange(int start, int end); @@ -305,8 +334,20 @@ protected: // ScintillaBase subclass needs access to much of Editor void ScrollTo(int line, bool moveThumb=true); virtual void ScrollText(int linesToMove); void HorizontalScrollTo(int xPos); + void VerticalCentreCaret(); + void MoveSelectedLines(int lineDelta); + void MoveSelectedLinesUp(); + void MoveSelectedLinesDown(); void MoveCaretInsideView(bool ensureVisible=true); int DisplayFromPosition(int pos); + + struct XYScrollPosition { + int xOffset; + int topLine; + XYScrollPosition(int xOffset_, int topLine_) : xOffset(xOffset_), topLine(topLine_) {} + }; + XYScrollPosition XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz); + void SetXYScroll(XYScrollPosition newXY); void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true); void ShowCaretAtCurrentPosition(); void DropCaret(); @@ -332,13 +373,15 @@ protected: // ScintillaBase subclass needs access to much of Editor int line, int lineEnd, int xStart, int subLine, int subLineStart, bool overrideBackground, ColourAllocated background, bool drawWrapMark, ColourAllocated wrapColour); + void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, ViewStyle &vsDraw, + int xStart, PRectangle rcLine, LineLayout *ll, int subLine); void DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under); void DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); - void DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, + void DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourAllocated caretColour); void DrawCarets(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); @@ -358,7 +401,8 @@ protected: // ScintillaBase subclass needs access to much of Editor int InsertSpace(int position, unsigned int spaces); void AddChar(char ch); virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); - void ClearSelection(); + void InsertPaste(SelectionPosition selStart, const char *text, int len); + void ClearSelection(bool retainMultipleSelections=false); void ClearAll(); void ClearDocumentStyle(); void Cut(); @@ -386,6 +430,7 @@ protected: // ScintillaBase subclass needs access to much of Editor virtual void NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt); void NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt); void NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt); + void NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt); void NotifyUpdateUI(); void NotifyPainted(); void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt); @@ -400,10 +445,15 @@ protected: // ScintillaBase subclass needs access to much of Editor void NotifyModified(Document *document, DocModification mh, void *userData); void NotifyDeleted(Document *document, void *userData); void NotifyStyleNeeded(Document *doc, void *userData, int endPos); + void NotifyLexerChanged(Document *doc, void *userData); + void NotifyErrorOccurred(Document *doc, void *userData, int status); void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + void ContainerNeedsUpdate(int flags); void PageMove(int direction, Selection::selTypes sel=Selection::noSel, bool stuttered = false); - void ChangeCaseOfSelection(bool makeUpperCase); + enum { cmSame, cmUpper, cmLower } caseMap; + virtual std::string CaseMapString(const std::string &s, int caseMapping); + void ChangeCaseOfSelection(int caseMapping); void LineTranspose(); void Duplicate(bool forLine); virtual void CancelModes(); @@ -420,6 +470,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void Indent(bool forwards); + virtual CaseFolder *CaseFolderForEncoding(); long FindText(uptr_t wParam, sptr_t lParam); void SearchAnchor(); long SearchText(unsigned int iMessage, uptr_t wParam, sptr_t lParam); @@ -440,8 +491,11 @@ protected: // ScintillaBase subclass needs access to much of Editor bool PositionInSelection(int pos); bool PointInSelection(Point pt); bool PointInSelMargin(Point pt); + Window::Cursor GetMarginCursor(Point pt); void LineSelection(int lineCurrent_, int lineAnchor_); + void WordSelection(int pos); void DwellEnd(bool mouseMoved); + void MouseLeave(); virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); void ButtonMove(Point pt); void ButtonUp(Point pt, unsigned int curTime, bool ctrl); @@ -454,6 +508,11 @@ protected: // ScintillaBase subclass needs access to much of Editor virtual bool HaveMouseCapture() = 0; void SetFocusState(bool focusState); + int PositionAfterArea(PRectangle rcArea); + void StyleToPositionInView(Position pos); + void IdleStyling(); + virtual void QueueStyling(int upTo); + virtual bool PaintContains(PRectangle rc); bool PaintContainsMargin(); void CheckForChangeOutsidePaint(Range r); @@ -461,18 +520,20 @@ protected: // ScintillaBase subclass needs access to much of Editor void SetAnnotationHeights(int start, int end); void SetDocPointer(Document *document); - + void SetAnnotationVisible(int visible); void Expand(int &line, bool doExpand); void ToggleContraction(int line); + int ContractedFoldNext(int lineStart); void EnsureLineVisible(int lineDoc, bool enforcePolicy); + int GetTag(char *tagValue, int tagNumber); int ReplaceTarget(bool replacePatterns, const char *text, int length=-1); bool PositionIsHotspot(int position); bool PointIsHotspot(Point pt); void SetHotSpotRange(Point *pt); - void GetHotSpotRange(int& hsStart, int& hsEnd); + void GetHotSpotRange(int &hsStart, int &hsEnd); int CodePage() const; virtual bool ValidCodePage(int /* codePage */) const { return true; } diff --git a/plugins/scintilla/scintilla/ExternalLexer.cxx b/plugins/scintilla/scintilla/ExternalLexer.cxx index 098df4d..bb48464 100644 --- a/plugins/scintilla/scintilla/ExternalLexer.cxx +++ b/plugins/scintilla/scintilla/ExternalLexer.cxx @@ -9,18 +9,18 @@ #include #include #include +#include #include #include "Platform.h" +#include "ILexer.h" #include "Scintilla.h" - #include "SciLexer.h" -#include "PropSet.h" -#include "Accessor.h" -#include "DocumentAccessor.h" -#include "KeyWords.h" + +#include "LexerModule.h" +#include "Catalogue.h" #include "ExternalLexer.h" #ifdef SCI_NAMESPACE @@ -35,77 +35,9 @@ LexerManager *LexerManager::theInstance = NULL; // //------------------------------------------ -char **WordListsToStrings(WordList *val[]) { - int dim = 0; - while (val[dim]) - dim++; - char **wls = new char * [dim + 1]; - for (int i = 0;i < dim;i++) { - std::string words; - words = ""; - for (int n = 0; n < val[i]->len; n++) { - words += val[i]->words[n]; - if (n != val[i]->len - 1) - words += " "; - } - wls[i] = new char[words.length() + 1]; - strcpy(wls[i], words.c_str()); - } - wls[dim] = 0; - return wls; -} - -void DeleteWLStrings(char *strs[]) { - int dim = 0; - while (strs[dim]) { - delete strs[dim]; - dim++; - } - delete [] strs; -} - -void ExternalLexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, - WordList *keywordlists[], Accessor &styler) const { - if (!fneLexer) - return ; - - char **kwds = WordListsToStrings(keywordlists); - char *ps = styler.GetProperties(); - - // The accessor passed in is always a DocumentAccessor so this cast and the subsequent - // access will work. Can not use the stricter dynamic_cast as that requires RTTI. - DocumentAccessor &da = static_cast(styler); - WindowID wID = da.GetWindow(); - - fneLexer(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps); - - delete ps; - DeleteWLStrings(kwds); -} - -void ExternalLexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, - WordList *keywordlists[], Accessor &styler) const { - if (!fneFolder) - return ; - - char **kwds = WordListsToStrings(keywordlists); - char *ps = styler.GetProperties(); - - // The accessor passed in is always a DocumentAccessor so this cast and the subsequent - // access will work. Can not use the stricter dynamic_cast as that requires RTTI. - DocumentAccessor &da = static_cast(styler); - WindowID wID = da.GetWindow(); - - fneFolder(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps); - - delete ps; - DeleteWLStrings(kwds); -} - -void ExternalLexerModule::SetExternal(ExtLexerFunction fLexer, ExtFoldFunction fFolder, int index) { - fneLexer = fLexer; - fneFolder = fFolder; - externalLanguage = index; +void ExternalLexerModule::SetExternal(GetLexerFactoryFunction fFactory, int index) { + fneFactory = fFactory; + fnFactory = fFactory(index); } //------------------------------------------ @@ -114,7 +46,7 @@ void ExternalLexerModule::SetExternal(ExtLexerFunction fLexer, ExtFoldFunction f // //------------------------------------------ -LexerLibrary::LexerLibrary(const char* ModuleName) { +LexerLibrary::LexerLibrary(const char *ModuleName) { // Initialise some members... first = NULL; last = NULL; @@ -132,8 +64,7 @@ LexerLibrary::LexerLibrary(const char* ModuleName) { // Find functions in the DLL GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName"); - ExtLexerFunction Lexer = (ExtLexerFunction)(sptr_t)lib->FindFunction("Lex"); - ExtFoldFunction Folder = (ExtFoldFunction)(sptr_t)lib->FindFunction("Fold"); + GetLexerFactoryFunction fnFactory = (GetLexerFactoryFunction)(sptr_t)lib->FindFunction("GetLexerFactory"); // Assign a buffer for the lexer name. char lexname[100]; @@ -144,6 +75,7 @@ LexerLibrary::LexerLibrary(const char* ModuleName) { for (int i = 0; i < nl; i++) { GetLexerName(i, lexname, 100); lex = new ExternalLexerModule(SCLEX_AUTOMATIC, NULL, lexname, NULL); + Catalogue::AddLexerModule(lex); // Create a LexerMinder so we don't leak the ExternalLexerModule... lm = new LexerMinder; @@ -158,8 +90,8 @@ LexerLibrary::LexerLibrary(const char* ModuleName) { } // The external lexer needs to know how to call into its DLL to - // do its lexing and folding, we tell it here. Folder may be null. - lex->SetExternal(Lexer, Folder, i); + // do its lexing and folding, we tell it here. + lex->SetExternal(fnFactory, i); } } } @@ -172,7 +104,6 @@ LexerLibrary::~LexerLibrary() { } void LexerLibrary::Release() { - //TODO maintain a list of lexers created, and delete them! LexerMinder *lm; LexerMinder *lmNext; lm = first; @@ -195,18 +126,15 @@ void LexerLibrary::Release() { /// Return the single LexerManager instance... LexerManager *LexerManager::GetInstance() { - if(!theInstance) + if (!theInstance) theInstance = new LexerManager; return theInstance; } /// Delete any LexerManager instance... -void LexerManager::DeleteInstance() -{ - if(theInstance) { - delete theInstance; - theInstance = NULL; - } +void LexerManager::DeleteInstance() { + delete theInstance; + theInstance = NULL; } /// protected constructor - this is a singleton... @@ -219,13 +147,15 @@ LexerManager::~LexerManager() { Clear(); } -void LexerManager::Load(const char* path) -{ +void LexerManager::Load(const char *path) { LoadLexerLibrary(path); } -void LexerManager::LoadLexerLibrary(const char* module) -{ +void LexerManager::LoadLexerLibrary(const char *module) { + for (LexerLibrary *ll = first; ll; ll= ll->next) { + if (strcmp(ll->m_sModuleName.c_str(), module) == 0) + return; + } LexerLibrary *lib = new LexerLibrary(module); if (NULL != first) { last->next = lib; @@ -236,8 +166,7 @@ void LexerManager::LoadLexerLibrary(const char* module) } } -void LexerManager::Clear() -{ +void LexerManager::Clear() { if (NULL != first) { LexerLibrary *cur = first; LexerLibrary *next; @@ -257,8 +186,7 @@ void LexerManager::Clear() // //------------------------------------------ -LMMinder::~LMMinder() -{ +LMMinder::~LMMinder() { LexerManager::DeleteInstance(); } diff --git a/plugins/scintilla/scintilla/ExternalLexer.h b/plugins/scintilla/scintilla/ExternalLexer.h index 29f42cc..bf175a6 100644 --- a/plugins/scintilla/scintilla/ExternalLexer.h +++ b/plugins/scintilla/scintilla/ExternalLexer.h @@ -18,36 +18,26 @@ namespace Scintilla { #endif -// External Lexer function definitions... -typedef void (EXT_LEXER_DECL *ExtLexerFunction)(unsigned int lexer, unsigned int startPos, int length, int initStyle, - char *words[], WindowID window, char *props); -typedef void (EXT_LEXER_DECL *ExtFoldFunction)(unsigned int lexer, unsigned int startPos, int length, int initStyle, - char *words[], WindowID window, char *props); -typedef void* (EXT_LEXER_DECL *GetLexerFunction)(unsigned int Index); +typedef void*(EXT_LEXER_DECL *GetLexerFunction)(unsigned int Index); typedef int (EXT_LEXER_DECL *GetLexerCountFn)(); typedef void (EXT_LEXER_DECL *GetLexerNameFn)(unsigned int Index, char *name, int buflength); - -//class DynamicLibrary; +typedef LexerFactoryFunction(EXT_LEXER_DECL *GetLexerFactoryFunction)(unsigned int Index); /// Sub-class of LexerModule to use an external lexer. -class ExternalLexerModule : protected LexerModule { +class ExternalLexerModule : public LexerModule { protected: - ExtLexerFunction fneLexer; - ExtFoldFunction fneFolder; - int externalLanguage; + GetLexerFactoryFunction fneFactory; char name[100]; public: - ExternalLexerModule(int language_, LexerFunction fnLexer_, - const char *languageName_=0, LexerFunction fnFolder_=0) : LexerModule(language_, fnLexer_, 0, fnFolder_){ + ExternalLexerModule(int language_, LexerFunction fnLexer_, + const char *languageName_=0, LexerFunction fnFolder_=0) : + LexerModule(language_, fnLexer_, 0, fnFolder_), + fneFactory(0) { strncpy(name, languageName_, sizeof(name)); name[sizeof(name)-1] = '\0'; languageName = name; - }; - virtual void Lex(unsigned int startPos, int lengthDoc, int initStyle, - WordList *keywordlists[], Accessor &styler) const; - virtual void Fold(unsigned int startPos, int lengthDoc, int initStyle, - WordList *keywordlists[], Accessor &styler) const; - virtual void SetExternal(ExtLexerFunction fLexer, ExtFoldFunction fFolder, int index); + } + virtual void SetExternal(GetLexerFactoryFunction fFactory, int index); }; /// LexerMinder points to an ExternalLexerModule - so we don't leak them. @@ -64,10 +54,10 @@ class LexerLibrary { LexerMinder *last; public: - LexerLibrary(const char* ModuleName); + LexerLibrary(const char *ModuleName); ~LexerLibrary(); void Release(); - + LexerLibrary *next; std::string m_sModuleName; }; @@ -76,18 +66,18 @@ public: class LexerManager { public: ~LexerManager(); - + static LexerManager *GetInstance(); static void DeleteInstance(); - - void Load(const char* path); + + void Load(const char *path); void Clear(); private: LexerManager(); static LexerManager *theInstance; - void LoadLexerLibrary(const char* module); + void LoadLexerLibrary(const char *module); LexerLibrary *first; LexerLibrary *last; }; diff --git a/plugins/scintilla/scintilla/Indicator.cxx b/plugins/scintilla/scintilla/Indicator.cxx index da95312..5c352bf 100644 --- a/plugins/scintilla/scintilla/Indicator.cxx +++ b/plugins/scintilla/scintilla/Indicator.cxx @@ -67,12 +67,12 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r surface->LineTo(rc.right, rcLine.top+1); surface->LineTo(rc.left, rcLine.top+1); surface->LineTo(rc.left, ymid+1); - } else if (style == INDIC_ROUNDBOX) { + } else if (style == INDIC_ROUNDBOX || style == INDIC_STRAIGHTBOX) { PRectangle rcBox = rcLine; rcBox.top = rcLine.top + 1; rcBox.left = rc.left; rcBox.right = rc.right; - surface->AlphaRectangle(rcBox, 1, fore.allocated, fillAlpha, fore.allocated, 50, 0); + surface->AlphaRectangle(rcBox, (style == INDIC_ROUNDBOX) ? 1 : 0, fore.allocated, fillAlpha, fore.allocated, outlineAlpha, 0); } else { // Either INDIC_PLAIN or unknown surface->MoveTo(rc.left, ymid); surface->LineTo(rc.right, ymid); diff --git a/plugins/scintilla/scintilla/Indicator.h b/plugins/scintilla/scintilla/Indicator.h index 42b56f0..e787b59 100644 --- a/plugins/scintilla/scintilla/Indicator.h +++ b/plugins/scintilla/scintilla/Indicator.h @@ -20,7 +20,8 @@ public: bool under; ColourPair fore; int fillAlpha; - Indicator() : style(INDIC_PLAIN), under(false), fore(ColourDesired(0,0,0)), fillAlpha(30) { + int outlineAlpha; + Indicator() : style(INDIC_PLAIN), under(false), fore(ColourDesired(0,0,0)), fillAlpha(30), outlineAlpha(50) { } void Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine); }; diff --git a/plugins/scintilla/scintilla/KeyWords.cxx b/plugins/scintilla/scintilla/KeyWords.cxx deleted file mode 100644 index 5e4de66..0000000 --- a/plugins/scintilla/scintilla/KeyWords.cxx +++ /dev/null @@ -1,429 +0,0 @@ -// Scintilla source code edit control -/** @file KeyWords.cxx - ** Colourise for particular languages. - **/ -// 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 "Platform.h" - -#include "PropSet.h" -#include "Accessor.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" - -#ifdef SCI_NAMESPACE -using namespace Scintilla; -#endif - -/** - * Creates an array that points into each word in the string and puts \0 terminators - * after each word. - */ -static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) { - int prev = '\n'; - int words = 0; - // For rapid determination of whether a character is a separator, build - // a look up table. - bool wordSeparator[256]; - for (int i=0;i<256; i++) { - wordSeparator[i] = false; - } - wordSeparator['\r'] = true; - wordSeparator['\n'] = true; - if (!onlyLineEnds) { - wordSeparator[' '] = true; - wordSeparator['\t'] = true; - } - for (int j = 0; wordlist[j]; j++) { - int curr = static_cast(wordlist[j]); - if (!wordSeparator[curr] && wordSeparator[prev]) - words++; - prev = curr; - } - char **keywords = new char *[words + 1]; - if (keywords) { - words = 0; - prev = '\0'; - size_t slen = strlen(wordlist); - for (size_t k = 0; k < slen; k++) { - if (!wordSeparator[static_cast(wordlist[k])]) { - if (!prev) { - keywords[words] = &wordlist[k]; - words++; - } - } else { - wordlist[k] = '\0'; - } - prev = wordlist[k]; - } - keywords[words] = &wordlist[slen]; - *len = words; - } else { - *len = 0; - } - return keywords; -} - -void WordList::Clear() { - if (words) { - delete []list; - delete []words; - } - words = 0; - list = 0; - len = 0; - sorted = false; -} - -void WordList::Set(const char *s) { - list = new char[strlen(s) + 1]; - strcpy(list, s); - sorted = false; - words = ArrayFromWordList(list, &len, onlyLineEnds); -} - -extern "C" int cmpString(const void *a1, const void *a2) { - // Can't work out the correct incantation to use modern casts here - return strcmp(*(char**)(a1), *(char**)(a2)); -} - -static void SortWordList(char **words, unsigned int len) { - qsort(reinterpret_cast(words), len, sizeof(*words), - cmpString); -} - -bool WordList::InList(const char *s) { - if (0 == words) - return false; - if (!sorted) { - sorted = true; - SortWordList(words, len); - for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) - starts[k] = -1; - for (int l = len - 1; l >= 0; l--) { - unsigned char indexChar = words[l][0]; - starts[indexChar] = l; - } - } - unsigned char firstChar = s[0]; - int j = starts[firstChar]; - if (j >= 0) { - while ((unsigned char)words[j][0] == firstChar) { - if (s[1] == words[j][1]) { - const char *a = words[j] + 1; - const char *b = s + 1; - while (*a && *a == *b) { - a++; - b++; - } - if (!*a && !*b) - return true; - } - j++; - } - } - j = starts['^']; - if (j >= 0) { - while (words[j][0] == '^') { - const char *a = words[j] + 1; - const char *b = s; - while (*a && *a == *b) { - a++; - b++; - } - if (!*a) - return true; - j++; - } - } - return false; -} - -/** similar to InList, but word s can be a substring of keyword. - * eg. the keyword define is defined as def~ine. This means the word must start - * with def to be a keyword, but also defi, defin and define are valid. - * The marker is ~ in this case. - */ -bool WordList::InListAbbreviated(const char *s, const char marker) { - if (0 == words) - return false; - if (!sorted) { - sorted = true; - SortWordList(words, len); - for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) - starts[k] = -1; - for (int l = len - 1; l >= 0; l--) { - unsigned char indexChar = words[l][0]; - starts[indexChar] = l; - } - } - unsigned char firstChar = s[0]; - int j = starts[firstChar]; - if (j >= 0) { - while (words[j][0] == firstChar) { - bool isSubword = false; - int start = 1; - if (words[j][1] == marker) { - isSubword = true; - start++; - } - if (s[1] == words[j][start]) { - const char *a = words[j] + start; - const char *b = s + 1; - while (*a && *a == *b) { - a++; - if (*a == marker) { - isSubword = true; - a++; - } - b++; - } - if ((!*a || isSubword) && !*b) - return true; - } - j++; - } - } - j = starts['^']; - if (j >= 0) { - while (words[j][0] == '^') { - const char *a = words[j] + 1; - const char *b = s; - while (*a && *a == *b) { - a++; - b++; - } - if (!*a) - return true; - j++; - } - } - return false; -} - -const LexerModule *LexerModule::base = 0; -int LexerModule::nextLanguage = SCLEX_AUTOMATIC+1; - -LexerModule::LexerModule(int language_, - LexerFunction fnLexer_, - const char *languageName_, - LexerFunction fnFolder_, - const char * const wordListDescriptions_[], - int styleBits_) : - language(language_), - fnLexer(fnLexer_), - fnFolder(fnFolder_), - wordListDescriptions(wordListDescriptions_), - styleBits(styleBits_), - languageName(languageName_) { - next = base; - base = this; - if (language == SCLEX_AUTOMATIC) { - language = nextLanguage; - nextLanguage++; - } -} - -int LexerModule::GetNumWordLists() const { - if (wordListDescriptions == NULL) { - return -1; - } else { - int numWordLists = 0; - - while (wordListDescriptions[numWordLists]) { - ++numWordLists; - } - - return numWordLists; - } -} - -const char *LexerModule::GetWordListDescription(int index) const { - static const char *emptyStr = ""; - - PLATFORM_ASSERT(index < GetNumWordLists()); - if (index >= GetNumWordLists()) { - return emptyStr; - } else { - return wordListDescriptions[index]; - } -} - -int LexerModule::GetStyleBitsNeeded() const { - return styleBits; -} - -const LexerModule *LexerModule::Find(int language) { - const LexerModule *lm = base; - while (lm) { - if (lm->language == language) { - return lm; - } - lm = lm->next; - } - return 0; -} - -const LexerModule *LexerModule::Find(const char *languageName) { - if (languageName) { - const LexerModule *lm = base; - while (lm) { - if (lm->languageName && 0 == strcmp(lm->languageName, languageName)) { - return lm; - } - lm = lm->next; - } - } - return 0; -} - -void LexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, - WordList *keywordlists[], Accessor &styler) const { - if (fnLexer) - fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler); -} - -void LexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, - WordList *keywordlists[], Accessor &styler) const { - if (fnFolder) { - int lineCurrent = styler.GetLine(startPos); - // Move back one line in case deletion wrecked current line fold state - if (lineCurrent > 0) { - lineCurrent--; - int newStartPos = styler.LineStart(lineCurrent); - lengthDoc += startPos - newStartPos; - startPos = newStartPos; - initStyle = 0; - if (startPos > 0) { - initStyle = styler.StyleAt(startPos - 1); - } - } - fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler); - } -} - -// Alternative historical name for Scintilla_LinkLexers -int wxForceScintillaLexers(void) { - return Scintilla_LinkLexers(); -} - -// To add or remove a lexer, add or remove its file and run LexGen.py. - -// Force a reference to all of the Scintilla lexers so that the linker will -// not remove the code of the lexers. -int Scintilla_LinkLexers() { - static int forcer = 0; - -// Shorten the code that declares a lexer and ensures it is linked in by calling a method. -#define LINK_LEXER(lexer) extern LexerModule lexer; forcer += lexer.GetLanguage(); - -//++Autogenerated -- run src/LexGen.py to regenerate -//**\(\tLINK_LEXER(\*);\n\) - LINK_LEXER(lmAbaqus); - LINK_LEXER(lmAda); - LINK_LEXER(lmAns1); - LINK_LEXER(lmAPDL); - LINK_LEXER(lmAsm); - LINK_LEXER(lmASY); - LINK_LEXER(lmAU3); - LINK_LEXER(lmAVE); - LINK_LEXER(lmBaan); - LINK_LEXER(lmBash); - LINK_LEXER(lmBatch); - LINK_LEXER(lmBlitzBasic); - LINK_LEXER(lmBullant); - LINK_LEXER(lmCaml); - LINK_LEXER(lmClw); - LINK_LEXER(lmClwNoCase); - LINK_LEXER(lmCmake); - LINK_LEXER(lmCOBOL); - LINK_LEXER(lmConf); - LINK_LEXER(lmCPP); - LINK_LEXER(lmCPPNoCase); - LINK_LEXER(lmCsound); - LINK_LEXER(lmCss); - LINK_LEXER(lmD); - LINK_LEXER(lmDiff); - LINK_LEXER(lmEiffel); - LINK_LEXER(lmEiffelkw); - LINK_LEXER(lmErlang); - LINK_LEXER(lmErrorList); - LINK_LEXER(lmESCRIPT); - LINK_LEXER(lmF77); - LINK_LEXER(lmFlagShip); - LINK_LEXER(lmForth); - LINK_LEXER(lmFortran); - LINK_LEXER(lmFreeBasic); - LINK_LEXER(lmGAP); - LINK_LEXER(lmGui4Cli); - LINK_LEXER(lmHaskell); - LINK_LEXER(lmHTML); - LINK_LEXER(lmInno); - LINK_LEXER(lmKix); - LINK_LEXER(lmLatex); - LINK_LEXER(lmLISP); - LINK_LEXER(lmLot); - LINK_LEXER(lmLout); - LINK_LEXER(lmLua); - LINK_LEXER(lmMagikSF); - LINK_LEXER(lmMake); - LINK_LEXER(lmMarkdown); - LINK_LEXER(lmMatlab); - LINK_LEXER(lmMETAPOST); - LINK_LEXER(lmMMIXAL); - LINK_LEXER(lmMSSQL); - LINK_LEXER(lmMySQL); - LINK_LEXER(lmNimrod); - LINK_LEXER(lmNncrontab); - LINK_LEXER(lmNsis); - LINK_LEXER(lmNull); - LINK_LEXER(lmOctave); - LINK_LEXER(lmOpal); - LINK_LEXER(lmPascal); - LINK_LEXER(lmPB); - LINK_LEXER(lmPerl); - LINK_LEXER(lmPHPSCRIPT); - LINK_LEXER(lmPLM); - LINK_LEXER(lmPo); - LINK_LEXER(lmPOV); - LINK_LEXER(lmPowerPro); - LINK_LEXER(lmPowerShell); - LINK_LEXER(lmProgress); - LINK_LEXER(lmProps); - LINK_LEXER(lmPS); - LINK_LEXER(lmPureBasic); - LINK_LEXER(lmPython); - LINK_LEXER(lmR); - LINK_LEXER(lmREBOL); - LINK_LEXER(lmRuby); - LINK_LEXER(lmScriptol); - LINK_LEXER(lmSmalltalk); - LINK_LEXER(lmSML); - LINK_LEXER(lmSorc); - LINK_LEXER(lmSpecman); - LINK_LEXER(lmSpice); - LINK_LEXER(lmSQL); - LINK_LEXER(lmTACL); - LINK_LEXER(lmTADS3); - LINK_LEXER(lmTAL); - LINK_LEXER(lmTCL); - LINK_LEXER(lmTeX); - LINK_LEXER(lmVB); - LINK_LEXER(lmVBScript); - LINK_LEXER(lmVerilog); - LINK_LEXER(lmVHDL); - LINK_LEXER(lmXML); - LINK_LEXER(lmYAML); - -//--Autogenerated -- end of automatically generated section - - return 1; -} diff --git a/plugins/scintilla/scintilla/LexA68k.cxx b/plugins/scintilla/scintilla/LexA68k.cxx new file mode 100644 index 0000000..970e429 --- /dev/null +++ b/plugins/scintilla/scintilla/LexA68k.cxx @@ -0,0 +1,318 @@ +// Scintilla source code edit control +/** @file LexA68k.cxx + ** Lexer for Assembler, just for the MASM syntax + ** Written by Martial Demolins AKA Folco + **/ +// Copyright 2010 Martial Demolins +// 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" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + + +// Return values for GetOperatorType +#define NO_OPERATOR 0 +#define OPERATOR_1CHAR 1 +#define OPERATOR_2CHAR 2 + + +/** + * IsIdentifierStart + * + * Return true if the given char is a valid identifier first char + */ + +static inline bool IsIdentifierStart (const int ch) +{ + return (isalpha(ch) || (ch == '_') || (ch == '\\')); +} + + +/** + * IsIdentifierChar + * + * Return true if the given char is a valid identifier char + */ + +static inline bool IsIdentifierChar (const int ch) +{ + return (isalnum(ch) || (ch == '_') || (ch == '@') || (ch == ':') || (ch == '.')); +} + + +/** + * GetOperatorType + * + * Return: + * NO_OPERATOR if char is not an operator + * OPERATOR_1CHAR if the operator is one char long + * OPERATOR_2CHAR if the operator is two chars long + */ + +static inline int GetOperatorType (const int ch1, const int ch2) +{ + int OpType = NO_OPERATOR; + + if ((ch1 == '+') || (ch1 == '-') || (ch1 == '*') || (ch1 == '/') || (ch1 == '#') || + (ch1 == '(') || (ch1 == ')') || (ch1 == '~') || (ch1 == '&') || (ch1 == '|') || (ch1 == ',')) + OpType = OPERATOR_1CHAR; + + else if ((ch1 == ch2) && (ch1 == '<' || ch1 == '>')) + OpType = OPERATOR_2CHAR; + + return OpType; +} + + +/** + * IsBin + * + * Return true if the given char is 0 or 1 + */ + +static inline bool IsBin (const int ch) +{ + return (ch == '0') || (ch == '1'); +} + + +/** + * IsDoxygenChar + * + * Return true if the char may be part of a Doxygen keyword + */ + +static inline bool IsDoxygenChar (const int ch) +{ + return isalpha(ch) || (ch == '$') || (ch == '[') || (ch == ']') || (ch == '{') || (ch == '}'); +} + + +/** + * ColouriseA68kDoc + * + * Main function, which colourises a 68k source + */ + +static void ColouriseA68kDoc (unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) +{ + + // Get references to keywords lists + WordList &cpuInstruction = *keywordlists[0]; + WordList ®isters = *keywordlists[1]; + WordList &directive = *keywordlists[2]; + WordList &extInstruction = *keywordlists[3]; + WordList &commentSpecial = *keywordlists[4]; + WordList &doxygenKeyword = *keywordlists[5]; + + + // Instanciate a context for our source + StyleContext sc(startPos, length, initStyle, styler); + + + /************************************************************ + * + * Parse the text + * + ************************************************************/ + + for ( ; sc.More(); sc.Forward()) + { + char Buffer[100]; + int OpType; + + // Reset style at beginning of line + if (sc.atLineStart) + sc.SetState(SCE_A68K_DEFAULT); + + + /************************************************************ + * + * Handle current state if we are not in the "default style" + * + ************************************************************/ + + if (sc.state != SCE_A68K_DEFAULT) + { + // Check if current style continue. + // If this case, we loop because there is nothing else to do + if (((sc.state == SCE_A68K_NUMBER_DEC) && isdigit(sc.ch)) // Decimal number + || ((sc.state == SCE_A68K_NUMBER_BIN) && IsBin(sc.ch)) // Binary number + || ((sc.state == SCE_A68K_NUMBER_HEX) && isxdigit(sc.ch)) // Hexa number + || ((sc.state == SCE_A68K_MACRO_ARG) && isdigit(sc.ch)) // Arg of macro + || ((sc.state == SCE_A68K_STRING1) && (sc.ch != '\'')) // String single-quoted + || ((sc.state == SCE_A68K_STRING2) && (sc.ch != '\"')) // String double-quoted + || ((sc.state == SCE_A68K_MACRO_ARG) && isdigit(sc.ch)) // Macro argument + // Label. ' ' and '\t' are needed to handle macro declarations + || ((sc.state == SCE_A68K_LABEL) && (sc.ch != ':') && (sc.ch != ' ') && (sc.ch != '\t')) + || ((sc.state == SCE_A68K_IDENTIFIER) && (sc.ch < 0x80) && IsIdentifierChar(sc.ch)) // Identifier + || ((sc.state == SCE_A68K_COMMENT_DOXYGEN) && (sc.ch < 0x80) && IsDoxygenChar(sc.ch)) // Doxygen keyword + || ((sc.state == SCE_A68K_COMMENT_WORD) && (sc.ch < 0x80) && isalpha(sc.ch))) // Comment current word + { + continue; + } + + // Check if some states terminate at the current char: + // we must include this char in the current style context + else if (((sc.state == SCE_A68K_STRING1) && (sc.ch < 0x80) && (sc.ch == '\'')) // String single-quoted + || ((sc.state == SCE_A68K_STRING2) && (sc.ch < 0x80) && (sc.ch == '\"')) // String double-quoted + || ((sc.state == SCE_A68K_LABEL) && (sc.ch < 0x80) && (sc.ch == ':'))) // Label + { + sc.ForwardSetState(SCE_A68K_DEFAULT); + } + + // Check for special words or Doxygen keywords in comments + else if (sc.state == SCE_A68K_COMMENT) + { + if (sc.ch == '\\') { + sc.SetState(SCE_A68K_COMMENT_DOXYGEN); + } + else if ((sc.ch < 0x80) && isalpha(sc.ch)) { + sc.SetState(SCE_A68K_COMMENT_WORD); + } + continue; + } + + // Check for special words in comment + else if ((sc.state == SCE_A68K_COMMENT_WORD) && (sc.ch < 0x80) && !isalpha(sc.ch)) + { + sc.GetCurrent(Buffer, sizeof(Buffer)); + if (commentSpecial.InList(Buffer)) { + sc.ChangeState(SCE_A68K_COMMENT_SPECIAL); + } + else { + sc.ChangeState(SCE_A68K_COMMENT); + } + sc.SetState(SCE_A68K_COMMENT); + continue; + } + + // Check for Doxygen keywords + else if ((sc.state == SCE_A68K_COMMENT_DOXYGEN) && (sc.ch < 0x80) && !IsDoxygenChar(sc.ch)) + { + sc.GetCurrentLowered(Buffer, sizeof(Buffer)); // Buffer the string of the current context + if (!doxygenKeyword.InList(Buffer)) { + sc.ChangeState(SCE_A68K_COMMENT); + } + sc.SetState(SCE_A68K_COMMENT); + continue; + } + + // Check if we are in the case of a label which terminates without ':' + // It should be a macro declaration, not a label + else if ((sc.state == SCE_A68K_LABEL) && (sc.ch < 0x80) && ((sc.ch == ' ') || (sc.ch == '\t'))) + { + sc.ChangeState(SCE_A68K_MACRO_DECLARATION); + } + + // Check if we are at the end of an identifier + // In this case, colourise it if was a keyword. + else if ((sc.state == SCE_A68K_IDENTIFIER) && !IsIdentifierChar(sc.ch)) + { + sc.GetCurrentLowered(Buffer, sizeof(Buffer)); // Buffer the string of the current context + if (cpuInstruction.InList(Buffer)) { // And check if it belongs to a keyword list + sc.ChangeState(SCE_A68K_CPUINSTRUCTION); + } + else if (extInstruction.InList(Buffer)) { + sc.ChangeState(SCE_A68K_EXTINSTRUCTION); + } + else if (registers.InList(Buffer)) { + sc.ChangeState(SCE_A68K_REGISTER); + } + else if (directive.InList(Buffer)) { + sc.ChangeState(SCE_A68K_DIRECTIVE); + } + } + + // All special contexts are now handled.Come back to default style + sc.SetState(SCE_A68K_DEFAULT); + } + + + /************************************************************ + * + * Check if we must enter a new state + * + ************************************************************/ + + // Label and macro identifiers start at the beginning of a line + // We set both as a label, but if it wasn't one (no ':' at the end), + // it will be changed as a macro identifier. + if (sc.atLineStart && (sc.ch < 0x80) && IsIdentifierStart(sc.ch)) { + sc.SetState(SCE_A68K_LABEL); + } + else if ((sc.ch < 0x80) && (sc.ch == ';')) { // Comment + sc.SetState(SCE_A68K_COMMENT); + } + else if ((sc.ch < 0x80) && isdigit(sc.ch)) { // Decimal numbers haven't prefix + sc.SetState(SCE_A68K_NUMBER_DEC); + } + else if ((sc.ch < 0x80) && (sc.ch == '%')) { // Binary numbers are prefixed with '%' + sc.SetState(SCE_A68K_NUMBER_BIN); + } + else if ((sc.ch < 0x80) && (sc.ch == '$')) { // Hexadecimal numbers are prefixed with '$' + sc.SetState(SCE_A68K_NUMBER_HEX); + } + else if ((sc.ch < 0x80) && (sc.ch == '\'')) { // String (single-quoted) + sc.SetState(SCE_A68K_STRING1); + } + else if ((sc.ch < 0x80) && (sc.ch == '\"')) { // String (double-quoted) + sc.SetState(SCE_A68K_STRING2); + } + else if ((sc.ch < 0x80) && (sc.ch == '\\') && (isdigit(sc.chNext))) { // Replacement symbols in macro + sc.SetState(SCE_A68K_MACRO_ARG); + } + else if ((sc.ch < 0x80) && IsIdentifierStart(sc.ch)) { // An identifier: constant, label, etc... + sc.SetState(SCE_A68K_IDENTIFIER); + } + else { + if (sc.ch < 0x80) { + OpType = GetOperatorType(sc.ch, sc.chNext); // Check if current char is an operator + if (OpType != NO_OPERATOR) { + sc.SetState(SCE_A68K_OPERATOR); + if (OpType == OPERATOR_2CHAR) { // Check if the operator is 2 bytes long + sc.ForwardSetState(SCE_A68K_OPERATOR); // (>> or <<) + } + } + } + } + } // End of for() + sc.Complete(); +} + + +// Names of the keyword lists + +static const char * const a68kWordListDesc[] = +{ + "CPU instructions", + "Registers", + "Directives", + "Extended instructions", + "Comment special words", + "Doxygen keywords", + 0 +}; + +LexerModule lmA68k(SCLEX_A68K, ColouriseA68kDoc, "a68k", 0, a68kWordListDesc); diff --git a/plugins/scintilla/scintilla/LexAPDL.cxx b/plugins/scintilla/scintilla/LexAPDL.cxx index 7bf597b..7d65a56 100644 --- a/plugins/scintilla/scintilla/LexAPDL.cxx +++ b/plugins/scintilla/scintilla/LexAPDL.cxx @@ -8,18 +8,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; diff --git a/plugins/scintilla/scintilla/LexASY.cxx b/plugins/scintilla/scintilla/LexASY.cxx index 5bf979f..9e3470c 100644 --- a/plugins/scintilla/scintilla/LexASY.cxx +++ b/plugins/scintilla/scintilla/LexASY.cxx @@ -4,25 +4,26 @@ #include #include -#include #include #include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" #include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif -static void ColouriseAsyDoc(unsigned int startPos, int length, int initStyle, +static void ColouriseAsyDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; @@ -118,7 +119,7 @@ static void ColouriseAsyDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_ASY_IDENTIFIER); } else if (sc.Match('/', '*')) { sc.SetState(SCE_ASY_COMMENT); - sc.Forward(); // + sc.Forward(); // } else if (sc.Match('/', '/')) { sc.SetState(SCE_ASY_COMMENTLINE); } else if (sc.ch == '\"') { @@ -162,14 +163,14 @@ static int ParseASYWord(unsigned int pos, Accessor &styler, char *word) length++; ch=styler.SafeGetCharAt(pos+length); } - word[length]=0; + word[length]=0; return length; } static bool IsASYDrawingLine(int line, Accessor &styler) { int pos = styler.LineStart(line); int eol_pos = styler.LineStart(line + 1) - 1; - + int startpos = pos; char buffer[100]=""; @@ -181,11 +182,11 @@ static bool IsASYDrawingLine(int line, Accessor &styler) { if (!drawcommands && ch!=' ') return false; else if (drawcommands) return true; startpos++; - } + } return false; } -static void FoldAsyDoc(unsigned int startPos, int length, int initStyle, +static void FoldAsyDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; @@ -236,7 +237,7 @@ static void FoldAsyDoc(unsigned int startPos, int length, int initStyle, else if (lineCurrent!=0 && IsASYDrawingLine(lineCurrent - 1, styler) && !IsASYDrawingLine(lineCurrent+1, styler)) levelNext--; - } + } if (atEOL) { int levelUse = levelCurrent; diff --git a/plugins/scintilla/scintilla/LexAU3.cxx b/plugins/scintilla/scintilla/LexAU3.cxx index cfff927..72c918f 100644 --- a/plugins/scintilla/scintilla/LexAU3.cxx +++ b/plugins/scintilla/scintilla/LexAU3.cxx @@ -1,15 +1,15 @@ // Scintilla source code edit control // @file LexAU3.cxx // Lexer for AutoIt3 http://www.hiddensoft.com/autoit3 -// by Jos van der Zande, jvdzande@yahoo.com +// by Jos van der Zande, jvdzande@yahoo.com // // Changes: // March 28, 2004 - Added the standard Folding code // April 21, 2004 - Added Preprosessor Table + Syntax Highlighting // Fixed Number highlighting // Changed default isoperator to IsAOperator to have a better match to AutoIt3 -// Fixed "#comments_start" -> "#comments-start" -// Fixed "#comments_end" -> "#comments-end" +// Fixed "#comments_start" -> "#comments-start" +// Fixed "#comments_end" -> "#comments-end" // Fixed Sendkeys in Strings when not terminated with } // Added support for Sendkey strings that have second parameter e.g. {UP 5} or {a down} // April 26, 2004 - Fixed # pre-processor statement inside of comment block would invalidly change the color. @@ -25,9 +25,9 @@ // Added fold.compact support set with fold.compact=1 // Changed folding inside of #cs-#ce. Default is no keyword folding inside comment blocks when fold.comment=1 // it will now only happen when fold.comment=2. -// Sep 5, 2004 - Added logic to handle colourizing words on the last line. +// Sep 5, 2004 - Added logic to handle colourizing words on the last line. // Typed Characters now show as "default" till they match any table. -// Oct 10, 2004 - Added logic to show Comments in "Special" directives. +// Oct 10, 2004 - Added logic to show Comments in "Special" directives. // Nov 1, 2004 - Added better testing for Numbers supporting x and e notation. // Nov 28, 2004 - Added logic to handle continuation lines for syntax highlighting. // Jan 10, 2005 - Added Abbreviations Keyword used for expansion @@ -52,18 +52,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -127,7 +130,7 @@ static int GetSendKey(const char *szLine, char *szKey) } else if (cTemp == ' ') { - // skip other spaces + // skip other spaces } else if (nFlag == 0) { @@ -139,7 +142,7 @@ static int GetSendKey(const char *szLine, char *szKey) // Save second portion into var... szSpecial[nSpecPos++] = cTemp; // check if Second portion is all numbers for repeat fuction - if (isdigit(cTemp) == false) {nSpecNum = 0;} + if (isdigit(cTemp) == false) {nSpecNum = 0;} } } nPos++; // skip to next char @@ -151,7 +154,7 @@ static int GetSendKey(const char *szLine, char *szKey) szKey[nKeyPos] = '\0'; szSpecial[nSpecPos] = '\0'; if (strcmp(szSpecial,"down")== 0 || strcmp(szSpecial,"up")== 0 || - strcmp(szSpecial,"on")== 0 || strcmp(szSpecial,"off")== 0 || + strcmp(szSpecial,"on")== 0 || strcmp(szSpecial,"off")== 0 || strcmp(szSpecial,"toggle")== 0 || nSpecNum == 1 ) { nFlag = 0; @@ -160,13 +163,13 @@ static int GetSendKey(const char *szLine, char *szKey) { nFlag = 1; } - return nFlag; // 1 is bad, 0 is good + return nFlag; // 1 is bad, 0 is good -} // GetSendKey() +} // GetSendKey() // // Routine to check the last "none comment" character on a line to see if its a continuation -// +// static bool IsContinuationLine(unsigned int szLine, Accessor &styler) { int nsPos = styler.LineStart(szLine); @@ -192,7 +195,7 @@ static bool IsContinuationLine(unsigned int szLine, Accessor &styler) // // syntax highlighting logic -static void ColouriseAU3Doc(unsigned int startPos, +static void ColouriseAU3Doc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { @@ -214,19 +217,19 @@ static void ColouriseAU3Doc(unsigned int startPos, (lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) { lineCurrent--; startPos = styler.LineStart(lineCurrent); // get start position - initStyle = 0; // reset the start style to 0 + initStyle = 0; // reset the start style to 0 } } // Set the new length to include it from the start and set the start position length = length + s_startPos - startPos; // correct the total length to process styler.StartAt(startPos); - + StyleContext sc(startPos, length, initStyle, styler); char si; // string indicator "=1 '=2 char ni; // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 Enot=3 - char ci; // comment indicator 0=not linecomment(;) + char ci; // comment indicator 0=not linecomment(;) char s_save[100]; - si=0; + si=0; ni=0; ci=0; //$$$ @@ -234,8 +237,8 @@ static void ColouriseAU3Doc(unsigned int startPos, char s[100]; sc.GetCurrentLowered(s, sizeof(s)); // ********************************************** - // save the total current word for eof processing - if (IsAWordChar(sc.ch) || sc.ch == '}') + // save the total current word for eof processing + if (IsAWordChar(sc.ch) || sc.ch == '}') { strcpy(s_save,s); int tp = strlen(s_save); @@ -254,9 +257,9 @@ static void ColouriseAU3Doc(unsigned int startPos, if (sc.atLineEnd) { ci=0; if (strcmp(s, "#ce")== 0 || strcmp(s, "#comments-end")== 0) { - if (sc.atLineEnd) + if (sc.atLineEnd) sc.SetState(SCE_AU3_DEFAULT); - else + else sc.SetState(SCE_AU3_COMMENTBLOCK); } break; @@ -267,9 +270,9 @@ static void ColouriseAU3Doc(unsigned int startPos, sc.SetState(SCE_AU3_COMMENTBLOCK); } // skip rest of the line - if (ci==2) + if (ci==2) break; - // check when first character is detected on the line + // check when first character is detected on the line if (ci==0) { if (IsAWordStart(static_cast(sc.ch)) || IsAOperator(static_cast(sc.ch))) { ci=1; @@ -292,10 +295,10 @@ static void ColouriseAU3Doc(unsigned int startPos, } case SCE_AU3_OPERATOR: { - // check if its a COMobject + // check if its a COMobject if (sc.chPrev == '.' && IsAWordChar(sc.ch)) { sc.SetState(SCE_AU3_COMOBJ); - } + } else { sc.SetState(SCE_AU3_DEFAULT); } @@ -360,7 +363,7 @@ static void ColouriseAU3Doc(unsigned int startPos, sc.SetState(SCE_AU3_DEFAULT); } } - } + } if (sc.atLineEnd) { sc.SetState(SCE_AU3_DEFAULT);} break; @@ -433,7 +436,7 @@ static void ColouriseAU3Doc(unsigned int startPos, case SCE_AU3_STRING: { // check for " to end a double qouted string or - // check for ' to end a single qouted string + // check for ' to end a single qouted string if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\'') || (si == 3 && sc.ch == '>')) { sc.ForwardSetState(SCE_AU3_DEFAULT); @@ -445,7 +448,7 @@ static void ColouriseAU3Doc(unsigned int startPos, si=0; // at line end and not found a continuation char then reset to default int lineCurrent = styler.GetLine(sc.currentPos); - if (!IsContinuationLine(lineCurrent,styler)) + if (!IsContinuationLine(lineCurrent,styler)) { sc.SetState(SCE_AU3_DEFAULT); break; @@ -456,27 +459,27 @@ static void ColouriseAU3Doc(unsigned int startPos, sc.SetState(SCE_AU3_SENT);} break; } - + case SCE_AU3_SENT: { - // Send key string ended - if (sc.chPrev == '}' && sc.ch != '}') + // Send key string ended + if (sc.chPrev == '}' && sc.ch != '}') { // set color to SENDKEY when valid sendkey .. else set back to regular string char sk[100]; // split {111 222} and return {111} and check if 222 is valid. // if return code = 1 then invalid 222 so must be string - if (GetSendKey(s,sk)) + if (GetSendKey(s,sk)) { sc.ChangeState(SCE_AU3_STRING); } // if single char between {?} then its ok as sendkey for a single character - else if (strlen(sk) == 3) + else if (strlen(sk) == 3) { sc.ChangeState(SCE_AU3_SENT); } // if sendkey {111} is in table then ok as sendkey - else if (keywords4.InList(sk)) + else if (keywords4.InList(sk)) { sc.ChangeState(SCE_AU3_SENT); } @@ -492,9 +495,9 @@ static void ColouriseAU3Doc(unsigned int startPos, int nPos = 0; int nState = 1; char cTemp; - while (!(nState == 2) && ((cTemp = s[nPos]) != '\0')) + while (!(nState == 2) && ((cTemp = s[nPos]) != '\0')) { - if (cTemp == '{' && nState == 1) + if (cTemp == '{' && nState == 1) { nState = 2; } @@ -509,14 +512,14 @@ static void ColouriseAU3Doc(unsigned int startPos, sc.ChangeState(SCE_AU3_STRING); sc.SetState(SCE_AU3_STRING); } - // If invalid character found then assume its a regular string + // If invalid character found then assume its a regular string if (nState == 0) { sc.ChangeState(SCE_AU3_STRING); sc.SetState(SCE_AU3_STRING); } } // check if next portion is again a sendkey - if (sc.atLineEnd) + if (sc.atLineEnd) { sc.ChangeState(SCE_AU3_STRING); sc.SetState(SCE_AU3_DEFAULT); @@ -547,14 +550,14 @@ static void ColouriseAU3Doc(unsigned int startPos, else if (sc.ch == '.' && !IsADigit(sc.chNext)) {sc.SetState(SCE_AU3_OPERATOR);} else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);} //else if (sc.ch == '_') {sc.SetState(SCE_AU3_KEYWORD);} - else if (sc.ch == '<' && si==3) {sc.SetState(SCE_AU3_STRING);} // string after #include + else if (sc.ch == '<' && si==3) {sc.SetState(SCE_AU3_STRING);} // string after #include else if (sc.ch == '\"') { sc.SetState(SCE_AU3_STRING); si = 1; } else if (sc.ch == '\'') { sc.SetState(SCE_AU3_STRING); si = 2; } - else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) + else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_AU3_NUMBER); ni = 0; @@ -566,7 +569,7 @@ static void ColouriseAU3Doc(unsigned int startPos, } //for (; sc.More(); sc.Forward()) //************************************* - // Colourize the last word correctly + // Colourize the last word correctly //************************************* if (sc.state == SCE_AU3_KEYWORD) { @@ -610,24 +613,24 @@ static void ColouriseAU3Doc(unsigned int startPos, } if (sc.state == SCE_AU3_SENT) { - // Send key string ended - if (sc.chPrev == '}' && sc.ch != '}') + // Send key string ended + if (sc.chPrev == '}' && sc.ch != '}') { // set color to SENDKEY when valid sendkey .. else set back to regular string char sk[100]; // split {111 222} and return {111} and check if 222 is valid. // if return code = 1 then invalid 222 so must be string - if (GetSendKey(s_save,sk)) + if (GetSendKey(s_save,sk)) { sc.ChangeState(SCE_AU3_STRING); } // if single char between {?} then its ok as sendkey for a single character - else if (strlen(sk) == 3) + else if (strlen(sk) == 3) { sc.ChangeState(SCE_AU3_SENT); } // if sendkey {111} is in table then ok as sendkey - else if (keywords4.InList(sk)) + else if (keywords4.InList(sk)) { sc.ChangeState(SCE_AU3_SENT); } @@ -638,7 +641,7 @@ static void ColouriseAU3Doc(unsigned int startPos, sc.SetState(SCE_AU3_STRING); } // check if next portion is again a sendkey - if (sc.atLineEnd) + if (sc.atLineEnd) { sc.ChangeState(SCE_AU3_STRING); sc.SetState(SCE_AU3_DEFAULT); @@ -655,7 +658,7 @@ static bool IsStreamCommentStyle(int style) { // // Routine to find first none space on the current line and return its Style -// needed for comment lines not starting on pos 1 +// needed for comment lines not starting on pos 1 static int GetStyleFirstWord(unsigned int szLine, Accessor &styler) { int nsPos = styler.LineStart(szLine); @@ -687,7 +690,7 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc startPos = styler.LineStart(lineCurrent); } } - // vars for style of previous/current/next lines + // vars for style of previous/current/next lines int style = GetStyleFirstWord(lineCurrent,styler); int stylePrev = 0; // find the first previous line without continuation character at the end @@ -712,7 +715,7 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelNext = levelCurrent; - // + // int visibleChars = 0; char chNext = styler.SafeGetCharAt(startPos); char chPrev = ' '; @@ -737,7 +740,7 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc } } } - // start the capture of the first word + // start the capture of the first word if (!(FirstWordStart)) { if (IsAWordChar(ch) || IsAWordStart(ch) || ch == ';') { FirstWordStart = true; @@ -749,7 +752,7 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc if (ThenFoundLast) { if (IsAWordChar(ch)) { ThenFoundLast = false; - } + } } // find out if the word "then" is the last on a "if" line if (FirstWordEnd && strcmp(szKeyword,"if") == 0) { @@ -770,21 +773,21 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc } } } - // End of Line found so process the information + // End of Line found so process the information if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) { // ************************** // Folding logic for Keywords // ************************** // if a keyword is found on the current line and the line doesn't end with _ (continuation) // and we are not inside a commentblock. - if (szKeywordlen > 0 && (!(chPrev == '_')) && + if (szKeywordlen > 0 && (!(chPrev == '_')) && ((!(IsStreamCommentStyle(style)) || foldInComment)) ) { szKeyword[szKeywordlen] = '\0'; // only fold "if" last keyword is "then" (else its a one line if) if (strcmp(szKeyword,"if") == 0 && ThenFoundLast) { levelNext++; } - // create new fold for these words + // create new fold for these words if (strcmp(szKeyword,"do") == 0 || strcmp(szKeyword,"for") == 0 || strcmp(szKeyword,"func") == 0 || strcmp(szKeyword,"while") == 0|| strcmp(szKeyword,"with") == 0 || strcmp(szKeyword,"#region") == 0 ) { @@ -797,12 +800,12 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc } // end the fold for these words before the current line if (strcmp(szKeyword,"endfunc") == 0 || strcmp(szKeyword,"endif") == 0 || - strcmp(szKeyword,"next") == 0 || strcmp(szKeyword,"until") == 0 || + strcmp(szKeyword,"next") == 0 || strcmp(szKeyword,"until") == 0 || strcmp(szKeyword,"endwith") == 0 ||strcmp(szKeyword,"wend") == 0){ levelNext--; levelCurrent--; } - // end the fold for these words before the current line and Start new fold + // end the fold for these words before the current line and Start new fold if (strcmp(szKeyword,"case") == 0 || strcmp(szKeyword,"else") == 0 || strcmp(szKeyword,"elseif") == 0 ) { levelCurrent--; @@ -841,16 +844,16 @@ static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Acc // Start of a comment block if (!(stylePrev==style) && IsStreamCommentStyle(styleNext) && styleNext==style) { levelNext++; - } + } // fold till the last line for normal comment lines - else if (IsStreamCommentStyle(stylePrev) + else if (IsStreamCommentStyle(stylePrev) && !(styleNext == SCE_AU3_COMMENT) - && stylePrev == SCE_AU3_COMMENT + && stylePrev == SCE_AU3_COMMENT && style == SCE_AU3_COMMENT) { levelNext--; } // fold till the one but last line for Blockcomment lines - else if (IsStreamCommentStyle(stylePrev) + else if (IsStreamCommentStyle(stylePrev) && !(styleNext == SCE_AU3_COMMENTBLOCK) && style == SCE_AU3_COMMENTBLOCK) { levelNext--; diff --git a/plugins/scintilla/scintilla/LexAVE.cxx b/plugins/scintilla/scintilla/LexAVE.cxx index 2b7029b..373173c 100644 --- a/plugins/scintilla/scintilla/LexAVE.cxx +++ b/plugins/scintilla/scintilla/LexAVE.cxx @@ -9,18 +9,21 @@ #include #include -#include -#include #include +#include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -42,7 +45,7 @@ inline bool IsAWordStart(const int ch) { } inline bool isAveOperator(char ch) { - if (isalnum(ch)) + if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || diff --git a/plugins/scintilla/scintilla/LexAbaqus.cxx b/plugins/scintilla/scintilla/LexAbaqus.cxx index 10e8b76..1341700 100644 --- a/plugins/scintilla/scintilla/LexAbaqus.cxx +++ b/plugins/scintilla/scintilla/LexAbaqus.cxx @@ -10,18 +10,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; diff --git a/plugins/scintilla/scintilla/LexAccessor.h b/plugins/scintilla/scintilla/LexAccessor.h new file mode 100644 index 0000000..dccf31e --- /dev/null +++ b/plugins/scintilla/scintilla/LexAccessor.h @@ -0,0 +1,175 @@ +// Scintilla source code edit control +/** @file LexAccessor.h + ** Interfaces between Scintilla and lexers. + **/ +// Copyright 1998-2010 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef LEXACCESSOR_H +#define LEXACCESSOR_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class LexAccessor { +private: + IDocument *pAccess; + enum {extremePosition=0x7FFFFFFF}; + /** @a bufferSize is a trade off between time taken to copy the characters + * and retrieval overhead. + * @a slopSize positions the buffer before the desired position + * in case there is some backtracking. */ + enum {bufferSize=4000, slopSize=bufferSize/8}; + char buf[bufferSize+1]; + int startPos; + int endPos; + int codePage; + int lenDoc; + int mask; + char styleBuf[bufferSize]; + int validLen; + char chFlags; + char chWhile; + unsigned int startSeg; + int startPosStyling; + + void Fill(int position) { + startPos = position - slopSize; + if (startPos + bufferSize > lenDoc) + startPos = lenDoc - bufferSize; + if (startPos < 0) + startPos = 0; + endPos = startPos + bufferSize; + if (endPos > lenDoc) + endPos = lenDoc; + + pAccess->GetCharRange(buf, startPos, endPos-startPos); + buf[endPos-startPos] = '\0'; + } + +public: + LexAccessor(IDocument *pAccess_) : + pAccess(pAccess_), startPos(extremePosition), endPos(0), + codePage(pAccess->CodePage()), lenDoc(pAccess->Length()), + mask(127), validLen(0), chFlags(0), chWhile(0), + startSeg(0), startPosStyling(0) { + } + char operator[](int position) { + if (position < startPos || position >= endPos) { + Fill(position); + } + return buf[position - startPos]; + } + /** Safe version of operator[], returning a defined value for invalid position. */ + char SafeGetCharAt(int position, char chDefault=' ') { + if (position < startPos || position >= endPos) { + Fill(position); + if (position < startPos || position >= endPos) { + // Position is outside range of document + return chDefault; + } + } + return buf[position - startPos]; + } + bool IsLeadByte(char ch) { + return pAccess->IsDBCSLeadByte(ch); + } + + bool Match(int pos, const char *s) { + for (int i=0; *s; i++) { + if (*s != SafeGetCharAt(pos+i)) + return false; + s++; + } + return true; + } + char StyleAt(int position) { + return static_cast(pAccess->StyleAt(position) & mask); + } + int GetLine(int position) { + return pAccess->LineFromPosition(position); + } + int LineStart(int line) { + return pAccess->LineStart(line); + } + int LevelAt(int line) { + return pAccess->GetLevel(line); + } + int Length() const { + return lenDoc; + } + void Flush() { + startPos = extremePosition; + if (validLen > 0) { + pAccess->SetStyles(validLen, styleBuf); + startPosStyling += validLen; + validLen = 0; + } + } + int GetLineState(int line) { + return pAccess->GetLineState(line); + } + int SetLineState(int line, int state) { + return pAccess->SetLineState(line, state); + } + // Style setting + void StartAt(unsigned int start, char chMask=31) { + // Store the mask specified for use with StyleAt. + mask = chMask; + pAccess->StartStyling(start, chMask); + startPosStyling = start; + } + void SetFlags(char chFlags_, char chWhile_) { + chFlags = chFlags_; + chWhile = chWhile_; + } + unsigned int GetStartSegment() const { + return startSeg; + } + void StartSegment(unsigned int pos) { + startSeg = pos; + } + void ColourTo(unsigned int pos, int chAttr) { + // Only perform styling if non empty range + if (pos != startSeg - 1) { + assert(pos >= startSeg); + if (pos < startSeg) { + return; + } + + if (validLen + (pos - startSeg + 1) >= bufferSize) + Flush(); + if (validLen + (pos - startSeg + 1) >= bufferSize) { + // Too big for buffer so send directly + pAccess->SetStyleFor(pos - startSeg + 1, static_cast(chAttr)); + } else { + if (chAttr != chWhile) + chFlags = 0; + chAttr |= chFlags; + for (unsigned int i = startSeg; i <= pos; i++) { + assert((startPosStyling + validLen) < Length()); + styleBuf[validLen++] = static_cast(chAttr); + } + } + } + startSeg = pos+1; + } + void SetLevel(int line, int level) { + pAccess->SetLevel(line, level); + } + void IndicatorFill(int start, int end, int indicator, int value) { + pAccess->DecorationSetCurrentIndicator(indicator); + pAccess->DecorationFillRange(start, value, end - start); + } + + void ChangeLexerState(int start, int end) { + pAccess->ChangeLexerState(start, end); + } +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/plugins/scintilla/scintilla/LexAda.cxx b/plugins/scintilla/scintilla/LexAda.cxx old mode 100755 new mode 100644 index 654bfbe..e109514 --- a/plugins/scintilla/scintilla/LexAda.cxx +++ b/plugins/scintilla/scintilla/LexAda.cxx @@ -6,19 +6,23 @@ // The License.txt file describes the conditions under which this software may be distributed. #include -#include #include #include +#include +#include #include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "PropSet.h" -#include "KeyWords.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; diff --git a/plugins/scintilla/scintilla/LexAsm.cxx b/plugins/scintilla/scintilla/LexAsm.cxx index 17c9384..946d47a 100644 --- a/plugins/scintilla/scintilla/LexAsm.cxx +++ b/plugins/scintilla/scintilla/LexAsm.cxx @@ -4,25 +4,37 @@ ** Written by The Black Horus ** Enhancements and NASM stuff by Kein-Hong Man, 2003-10 ** SCE_ASM_COMMENTBLOCK and SCE_ASM_CHARACTER are for future GNU as colouring + ** Converted to lexer object and added further folding features/properties by "Udo Lechner" **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include -#include #include #include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif -#include "Platform.h" +#include +#include +#include -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" +#include "OptionSet.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -50,15 +62,184 @@ static inline bool IsAsmOperator(const int ch) { return false; } -static void ColouriseAsmDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler) { +static bool IsStreamCommentStyle(int style) { + return style == SCE_ASM_COMMENTDIRECTIVE || style == SCE_ASM_COMMENTBLOCK; +} + +static inline int LowerCase(int c) { + if (c >= 'A' && c <= 'Z') + return 'a' + c - 'A'; + return c; +} + +// An individual named option for use in an OptionSet - WordList &cpuInstruction = *keywordlists[0]; - WordList &mathInstruction = *keywordlists[1]; - WordList ®isters = *keywordlists[2]; - WordList &directive = *keywordlists[3]; - WordList &directiveOperand = *keywordlists[4]; - WordList &extInstruction = *keywordlists[5]; +// Options used for LexerAsm +struct OptionsAsm { + std::string delimiter; + bool fold; + bool foldSyntaxBased; + bool foldCommentMultiline; + bool foldCommentExplicit; + std::string foldExplicitStart; + std::string foldExplicitEnd; + bool foldExplicitAnywhere; + bool foldCompact; + OptionsAsm() { + delimiter = ""; + fold = false; + foldSyntaxBased = true; + foldCommentMultiline = false; + foldCommentExplicit = false; + foldExplicitStart = ""; + foldExplicitEnd = ""; + foldExplicitAnywhere = false; + foldCompact = true; + } +}; + +static const char * const asmWordListDesc[] = { + "CPU instructions", + "FPU instructions", + "Registers", + "Directives", + "Directive operands", + "Extended instructions", + "Directives4Foldstart", + "Directives4Foldend", + 0 +}; + +struct OptionSetAsm : public OptionSet { + OptionSetAsm() { + DefineProperty("lexer.asm.comment.delimiter", &OptionsAsm::delimiter, + "Character used for COMMENT directive's delimiter, replacing the standard \"~\"."); + + DefineProperty("fold", &OptionsAsm::fold); + + DefineProperty("fold.asm.syntax.based", &OptionsAsm::foldSyntaxBased, + "Set this property to 0 to disable syntax based folding."); + + DefineProperty("fold.asm.comment.multiline", &OptionsAsm::foldCommentMultiline, + "Set this property to 1 to enable folding multi-line comments."); + + DefineProperty("fold.asm.comment.explicit", &OptionsAsm::foldCommentExplicit, + "This option enables folding explicit fold points when using the Asm lexer. " + "Explicit fold points allows adding extra folding by placing a ;{ comment at the start and a ;} " + "at the end of a section that should fold."); + + DefineProperty("fold.asm.explicit.start", &OptionsAsm::foldExplicitStart, + "The string to use for explicit fold start points, replacing the standard ;{."); + + DefineProperty("fold.asm.explicit.end", &OptionsAsm::foldExplicitEnd, + "The string to use for explicit fold end points, replacing the standard ;}."); + + DefineProperty("fold.asm.explicit.anywhere", &OptionsAsm::foldExplicitAnywhere, + "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); + + DefineProperty("fold.compact", &OptionsAsm::foldCompact); + + DefineWordListSets(asmWordListDesc); + } +}; + +class LexerAsm : public ILexer { + WordList cpuInstruction; + WordList mathInstruction; + WordList registers; + WordList directive; + WordList directiveOperand; + WordList extInstruction; + WordList directives4foldstart; + WordList directives4foldend; + OptionsAsm options; + OptionSetAsm osAsm; +public: + LexerAsm() { + } + ~LexerAsm() { + } + void SCI_METHOD Release() { + delete this; + } + int SCI_METHOD Version() const { + return lvOriginal; + } + const char * SCI_METHOD PropertyNames() { + return osAsm.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) { + return osAsm.PropertyType(name); + } + const char * SCI_METHOD DescribeProperty(const char *name) { + return osAsm.DescribeProperty(name); + } + int SCI_METHOD PropertySet(const char *key, const char *val); + const char * SCI_METHOD DescribeWordListSets() { + return osAsm.DescribeWordListSets(); + } + int SCI_METHOD WordListSet(int n, const char *wl); + void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + + void * SCI_METHOD PrivateCall(int, void *) { + return 0; + } + + static ILexer *LexerFactoryAsm() { + return new LexerAsm(); + } +}; + +int SCI_METHOD LexerAsm::PropertySet(const char *key, const char *val) { + if (osAsm.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +int SCI_METHOD LexerAsm::WordListSet(int n, const char *wl) { + WordList *wordListN = 0; + switch (n) { + case 0: + wordListN = &cpuInstruction; + break; + case 1: + wordListN = &mathInstruction; + break; + case 2: + wordListN = ®isters; + break; + case 3: + wordListN = &directive; + break; + case 4: + wordListN = &directiveOperand; + break; + case 5: + wordListN = &extInstruction; + break; + case 6: + wordListN = &directives4foldstart; + break; + case 7: + wordListN = &directives4foldend; + break; + } + int firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +void SCI_METHOD LexerAsm::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + LexAccessor styler(pAccess); // Do not leak onto next line if (initStyle == SCE_ASM_STRINGEOL) @@ -92,7 +273,7 @@ static void ColouriseAsmDoc(unsigned int startPos, int length, int initStyle, Wo if (!IsAsmOperator(sc.ch)) { sc.SetState(SCE_ASM_DEFAULT); } - }else if (sc.state == SCE_ASM_NUMBER) { + } else if (sc.state == SCE_ASM_NUMBER) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_ASM_DEFAULT); } @@ -100,6 +281,7 @@ static void ColouriseAsmDoc(unsigned int startPos, int length, int initStyle, Wo if (!IsAWordChar(sc.ch) ) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); + bool IsDirective = false; if (cpuInstruction.InList(s)) { sc.ChangeState(SCE_ASM_CPUINSTRUCTION); @@ -109,15 +291,32 @@ static void ColouriseAsmDoc(unsigned int startPos, int length, int initStyle, Wo sc.ChangeState(SCE_ASM_REGISTER); } else if (directive.InList(s)) { sc.ChangeState(SCE_ASM_DIRECTIVE); + IsDirective = true; } else if (directiveOperand.InList(s)) { sc.ChangeState(SCE_ASM_DIRECTIVEOPERAND); } else if (extInstruction.InList(s)) { sc.ChangeState(SCE_ASM_EXTINSTRUCTION); } sc.SetState(SCE_ASM_DEFAULT); + if (IsDirective && !strcmp(s, "comment")) { + char delimiter = options.delimiter.empty() ? '~' : options.delimiter.c_str()[0]; + while (IsASpaceOrTab(sc.ch) && !sc.atLineEnd) { + sc.ForwardSetState(SCE_ASM_DEFAULT); + } + if (sc.ch == delimiter) { + sc.SetState(SCE_ASM_COMMENTDIRECTIVE); + } + } } - } - else if (sc.state == SCE_ASM_COMMENT ) { + } else if (sc.state == SCE_ASM_COMMENTDIRECTIVE) { + char delimiter = options.delimiter.empty() ? '~' : options.delimiter.c_str()[0]; + if (sc.ch == delimiter) { + while (!sc.atLineEnd) { + sc.Forward(); + } + sc.SetState(SCE_ASM_DEFAULT); + } + } else if (sc.state == SCE_ASM_COMMENT ) { if (sc.atLineEnd) { sc.SetState(SCE_ASM_DEFAULT); } @@ -166,15 +365,100 @@ static void ColouriseAsmDoc(unsigned int startPos, int length, int initStyle, Wo sc.Complete(); } -static const char * const asmWordListDesc[] = { - "CPU instructions", - "FPU instructions", - "Registers", - "Directives", - "Directive operands", - "Extended instructions", - 0 -}; +// Store both the current line's fold level and the next lines in the +// level store to make it easy to pick up with each increment +// and to make it possible to fiddle the current level for "else". + +void SCI_METHOD LexerAsm::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + + if (!options.fold) + return; + + LexAccessor styler(pAccess); + + unsigned int endPos = startPos + length; + int visibleChars = 0; + int lineCurrent = styler.GetLine(startPos); + int levelCurrent = SC_FOLDLEVELBASE; + if (lineCurrent > 0) + levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; + int levelNext = levelCurrent; + char chNext = styler[startPos]; + int styleNext = styler.StyleAt(startPos); + int style = initStyle; + char word[100]; + int wordlen = 0; + const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); + for (unsigned int i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + int stylePrev = style; + style = styleNext; + styleNext = styler.StyleAt(i + 1); + bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + if (options.foldCommentMultiline && IsStreamCommentStyle(style)) { + if (!IsStreamCommentStyle(stylePrev)) { + levelNext++; + } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { + // Comments don't end at end of line and the next character may be unstyled. + levelNext--; + } + } + if (options.foldCommentExplicit && ((style == SCE_ASM_COMMENT) || options.foldExplicitAnywhere)) { + if (userDefinedFoldMarkers) { + if (styler.Match(i, options.foldExplicitStart.c_str())) { + levelNext++; + } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { + levelNext--; + } + } else { + if (ch == ';') { + if (chNext == '{') { + levelNext++; + } else if (chNext == '}') { + levelNext--; + } + } + } + } + if (options.foldSyntaxBased && (style == SCE_ASM_DIRECTIVE)) { + word[wordlen++] = static_cast(LowerCase(ch)); + if (wordlen == 100) { // prevent overflow + word[0] = '\0'; + wordlen = 1; + } + if (styleNext != SCE_ASM_DIRECTIVE) { // reading directive ready + word[wordlen] = '\0'; + wordlen = 0; + if (directives4foldstart.InList(word)) { + levelNext++; + } else if (directives4foldend.InList(word)){ + levelNext--; + } + } + } + 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++; + 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 lmAsm(SCLEX_ASM, ColouriseAsmDoc, "asm", 0, asmWordListDesc); +LexerModule lmAsm(SCLEX_ASM, LexerAsm::LexerFactoryAsm, "asm", asmWordListDesc); diff --git a/plugins/scintilla/scintilla/LexAsn1.cxx b/plugins/scintilla/scintilla/LexAsn1.cxx index 36f1d5d..3545b3f 100644 --- a/plugins/scintilla/scintilla/LexAsn1.cxx +++ b/plugins/scintilla/scintilla/LexAsn1.cxx @@ -5,20 +5,23 @@ // Copyright 2004 by Herr Pfarrer rpfarrer yahoo de // Last Updated: 20/07/2004 // The License.txt file describes the conditions under which this software may be distributed. + #include #include -#include #include #include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; diff --git a/plugins/scintilla/scintilla/LexBaan.cxx b/plugins/scintilla/scintilla/LexBaan.cxx index a6847db..3784f3c 100644 --- a/plugins/scintilla/scintilla/LexBaan.cxx +++ b/plugins/scintilla/scintilla/LexBaan.cxx @@ -8,18 +8,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; diff --git a/plugins/scintilla/scintilla/LexBash.cxx b/plugins/scintilla/scintilla/LexBash.cxx index 5801278..165e104 100644 --- a/plugins/scintilla/scintilla/LexBash.cxx +++ b/plugins/scintilla/scintilla/LexBash.cxx @@ -2,44 +2,53 @@ /** @file LexBash.cxx ** Lexer for Bash. **/ -// Copyright 2004-2008 by Neil Hodgson +// Copyright 2004-2010 by Neil Hodgson // Adapted from LexPerl by Kein-Hong Man 2004 // The License.txt file describes the conditions under which this software may be distributed. #include #include -#include #include #include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" #include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif -#define HERE_DELIM_MAX 256 +#define HERE_DELIM_MAX 256 // define this if you want 'invalid octals' to be marked as errors // usually, this is not a good idea, permissive lexing is better #undef PEDANTIC_OCTAL -#define BASH_BASE_ERROR 65 -#define BASH_BASE_DECIMAL 66 -#define BASH_BASE_HEX 67 +#define BASH_BASE_ERROR 65 +#define BASH_BASE_DECIMAL 66 +#define BASH_BASE_HEX 67 #ifdef PEDANTIC_OCTAL -#define BASH_BASE_OCTAL 68 -#define BASH_BASE_OCTAL_ERROR 69 +#define BASH_BASE_OCTAL 68 +#define BASH_BASE_OCTAL_ERROR 69 #endif +// state constants for parts of a bash command segment +#define BASH_CMD_BODY 0 +#define BASH_CMD_START 1 +#define BASH_CMD_WORD 2 +#define BASH_CMD_TEST 3 +#define BASH_CMD_ARITH 4 +#define BASH_CMD_DELIM 5 + static inline int translateBashDigit(int ch) { if (ch >= '0' && ch <= '9') { return ch - '0'; @@ -80,11 +89,15 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; + WordList cmdDelimiter, bashStruct, bashStruct_in; + cmdDelimiter.Set("| || |& & && ; ;; ( ) { }"); + bashStruct.Set("if elif fi while until else then do done esac eval"); + bashStruct_in.Set("for case select"); CharacterSet setWordStart(CharacterSet::setAlpha, "_"); // note that [+-] are often parts of identifiers in shell scripts CharacterSet setWord(CharacterSet::setAlphaNum, "._+-"); - CharacterSet setBashOperator(CharacterSet::setNone, "^&\\%()-+=|{}[]:;>,*/,*/ 1) && (styler.StyleAt(startPos) != SCE_SH_HERE_DELIM)) { - startPos--; - } - startPos = styler.LineStart(styler.GetLine(startPos)); - initStyle = styler.StyleAt(startPos - 1); - } - // Bash strings can be multi-line with embedded newlines, so backtrack. - // Bash numbers have additional state during lexing, so backtrack too. - if (initStyle == SCE_SH_STRING - || initStyle == SCE_SH_BACKTICKS - || initStyle == SCE_SH_CHARACTER - || initStyle == SCE_SH_NUMBER - || initStyle == SCE_SH_IDENTIFIER - || initStyle == SCE_SH_COMMENTLINE) { - while ((startPos > 1) && (styler.StyleAt(startPos - 1) == initStyle)) { - startPos--; - } - initStyle = SCE_SH_DEFAULT; + // Always backtracks to the start of a line that is not a continuation + // of the previous line (i.e. start of a bash command segment) + int ln = styler.GetLine(startPos); + for (;;) { + startPos = styler.LineStart(ln); + if (ln == 0 || styler.GetLineState(ln) == BASH_CMD_START) + break; + ln--; } + initStyle = SCE_SH_DEFAULT; StyleContext sc(startPos, endPos - startPos, initStyle, styler); for (; sc.More(); sc.Forward()) { + // handle line continuation, updates per-line stored state + if (sc.atLineStart) { + ln = styler.GetLine(sc.currentPos); + if (sc.state == SCE_SH_STRING + || sc.state == SCE_SH_BACKTICKS + || sc.state == SCE_SH_CHARACTER + || sc.state == SCE_SH_HERE_Q + || sc.state == SCE_SH_COMMENTLINE + || sc.state == SCE_SH_PARAM) { + // force backtrack while retaining cmdState + styler.SetLineState(ln, BASH_CMD_BODY); + } else { + if (ln > 0) { + if ((sc.GetRelative(-3) == '\\' && sc.GetRelative(-2) == '\r' && sc.chPrev == '\n') + || sc.GetRelative(-2) == '\\') { // handle '\' line continuation + // retain last line's state + } else + cmdState = BASH_CMD_START; + } + styler.SetLineState(ln, cmdState); + } + } + + // controls change of cmdState at the end of a non-whitespace element + // states BODY|TEST|ARITH persist until the end of a command segment + // state WORD persist, but ends with 'in' or 'do' construct keywords + int cmdStateNew = BASH_CMD_BODY; + if (cmdState == BASH_CMD_TEST || cmdState == BASH_CMD_ARITH || cmdState == BASH_CMD_WORD) + cmdStateNew = cmdState; + int stylePrev = sc.state; + // Determine if the current state should terminate. switch (sc.state) { case SCE_SH_OPERATOR: sc.SetState(SCE_SH_DEFAULT); + if (cmdState == BASH_CMD_DELIM) // if command delimiter, start new command + cmdStateNew = BASH_CMD_START; + else if (sc.chPrev == '\\') // propagate command state if line continued + cmdStateNew = cmdState; break; case SCE_SH_WORD: // "." never used in Bash variable names but used in file names if (!setWord.Contains(sc.ch)) { - char s[1000]; + char s[500]; + char s2[10]; sc.GetCurrent(s, sizeof(s)); - if (s[0] != '-' && // for file operators - !keywords.InList(s)) { + // allow keywords ending in a whitespace or command delimiter + s2[0] = static_cast(sc.ch); + s2[1] = '\0'; + bool keywordEnds = IsASpace(sc.ch) || cmdDelimiter.InList(s2); + // 'in' or 'do' may be construct keywords + if (cmdState == BASH_CMD_WORD) { + if (strcmp(s, "in") == 0 && keywordEnds) + cmdStateNew = BASH_CMD_BODY; + else if (strcmp(s, "do") == 0 && keywordEnds) + cmdStateNew = BASH_CMD_START; + else + sc.ChangeState(SCE_SH_IDENTIFIER); + sc.SetState(SCE_SH_DEFAULT); + break; + } + // a 'test' keyword starts a test expression + if (strcmp(s, "test") == 0) { + if (cmdState == BASH_CMD_START && keywordEnds) { + cmdStateNew = BASH_CMD_TEST; + testExprType = 0; + } else + sc.ChangeState(SCE_SH_IDENTIFIER); + } + // detect bash construct keywords + else if (bashStruct.InList(s)) { + if (cmdState == BASH_CMD_START && keywordEnds) + cmdStateNew = BASH_CMD_START; + else + sc.ChangeState(SCE_SH_IDENTIFIER); + } + // 'for'|'case'|'select' needs 'in'|'do' to be highlighted later + else if (bashStruct_in.InList(s)) { + if (cmdState == BASH_CMD_START && keywordEnds) + cmdStateNew = BASH_CMD_WORD; + else + sc.ChangeState(SCE_SH_IDENTIFIER); + } + // disambiguate option items and file test operators + else if (s[0] == '-') { + if (cmdState != BASH_CMD_TEST) + sc.ChangeState(SCE_SH_IDENTIFIER); + } + // disambiguate keywords and identifiers + else if (cmdState != BASH_CMD_START + || !(keywords.InList(s) && keywordEnds)) { sc.ChangeState(SCE_SH_IDENTIFIER); } sc.SetState(SCE_SH_DEFAULT); @@ -248,14 +330,8 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_SH_DEFAULT); break; case SCE_SH_COMMENTLINE: - if (sc.ch == '\\' && (sc.chNext == '\r' || sc.chNext == '\n')) { - // comment continuation - sc.Forward(); - if (sc.ch == '\r' && sc.chNext == '\n') { - sc.Forward(); - } - } else if (sc.atLineEnd) { - sc.ForwardSetState(SCE_SH_DEFAULT); + if (sc.atLineEnd && sc.chPrev != '\\') { + sc.SetState(SCE_SH_DEFAULT); } break; case SCE_SH_HERE_DELIM: @@ -294,23 +370,14 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, HereDoc.State = 1; } } else if (HereDoc.State == 1) { // collect the delimiter - if (HereDoc.Quoted) { // a quoted here-doc delimiter - if (sc.ch == HereDoc.Quote) { // closing quote => end of delimiter - sc.ForwardSetState(SCE_SH_DEFAULT); - } else { - if (sc.ch == '\\' && sc.chNext == HereDoc.Quote) { // escaped quote - sc.Forward(); - } - HereDoc.Append(sc.ch); - } - } else { // an unquoted here-doc delimiter - if (setHereDoc2.Contains(sc.ch)) { - HereDoc.Append(sc.ch); - } else if (sc.ch == '\\') { - // skip escape prefix - } else { - sc.SetState(SCE_SH_DEFAULT); - } + if (setHereDoc2.Contains(sc.ch) || sc.chPrev == '\\') { + HereDoc.Append(sc.ch); + } else if (HereDoc.Quoted && sc.ch == HereDoc.Quote) { // closing quote => end of delimiter + sc.ForwardSetState(SCE_SH_DEFAULT); + } else if (sc.ch == '\\') { + // skip escape prefix + } else { + sc.SetState(SCE_SH_DEFAULT); } if (HereDoc.DelimiterLength >= HERE_DELIM_MAX - 1) { // force blowup sc.SetState(SCE_SH_ERROR); @@ -339,8 +406,8 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, if (s[strlen(s) - 1] == '\r') s[strlen(s) - 1] = '\0'; if (strcmp(HereDoc.Delimiter, s) == 0) { - if ((prefixws > 0 && HereDoc.Indent) || // indentation rule - (prefixws == 0 && !HereDoc.Indent)) { + if ((prefixws == 0) || // indentation rule + (prefixws > 0 && HereDoc.Indent)) { sc.SetState(SCE_SH_DEFAULT); break; } @@ -391,10 +458,17 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_SH_HERE_Q); } + // update cmdState about the current command segment + if (stylePrev != SCE_SH_DEFAULT && sc.state == SCE_SH_DEFAULT) { + cmdState = cmdStateNew; + } // Determine if a new state should be entered. if (sc.state == SCE_SH_DEFAULT) { - if (sc.ch == '\\') { // escaped character + if (sc.ch == '\\') { + // Bash can escape any non-newline as a literal sc.SetState(SCE_SH_IDENTIFIER); + if (sc.chNext == '\r' || sc.chNext == '\n') + sc.SetState(SCE_SH_OPERATOR); } else if (IsADigit(sc.ch)) { sc.SetState(SCE_SH_NUMBER); numBase = BASH_BASE_DECIMAL; @@ -424,6 +498,10 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_SH_BACKTICKS); Quote.Start(sc.ch); } else if (sc.ch == '$') { + if (sc.Match("$((")) { + sc.SetState(SCE_SH_OPERATOR); // handle '((' later + continue; + } sc.SetState(SCE_SH_SCALAR); sc.Forward(); if (sc.ch == '{') { @@ -434,9 +512,6 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.ChangeState(SCE_SH_STRING); } else if (sc.ch == '(' || sc.ch == '`') { sc.ChangeState(SCE_SH_BACKTICKS); - if (sc.chNext == '(') { // $(( is lexed as operator - sc.ChangeState(SCE_SH_OPERATOR); - } } else { continue; // scalar has no delimiter pair } @@ -453,9 +528,66 @@ static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_SH_WORD); sc.Forward(); } else if (setBashOperator.Contains(sc.ch)) { + char s[10]; + bool isCmdDelim = false; sc.SetState(SCE_SH_OPERATOR); + // handle opening delimiters for test/arithmetic expressions - ((,[[,[ + if (cmdState == BASH_CMD_START + || cmdState == BASH_CMD_BODY) { + if (sc.Match('(', '(')) { + cmdState = BASH_CMD_ARITH; + sc.Forward(); + } else if (sc.Match('[', '[') && IsASpace(sc.GetRelative(2))) { + cmdState = BASH_CMD_TEST; + testExprType = 1; + sc.Forward(); + } else if (sc.ch == '[' && IsASpace(sc.chNext)) { + cmdState = BASH_CMD_TEST; + testExprType = 2; + } + } + // special state -- for ((x;y;z)) in ... looping + if (cmdState == BASH_CMD_WORD && sc.Match('(', '(')) { + cmdState = BASH_CMD_ARITH; + sc.Forward(); + continue; + } + // handle command delimiters in command START|BODY|WORD state, also TEST if 'test' + if (cmdState == BASH_CMD_START + || cmdState == BASH_CMD_BODY + || cmdState == BASH_CMD_WORD + || (cmdState == BASH_CMD_TEST && testExprType == 0)) { + s[0] = static_cast(sc.ch); + if (setBashOperator.Contains(sc.chNext)) { + s[1] = static_cast(sc.chNext); + s[2] = '\0'; + isCmdDelim = cmdDelimiter.InList(s); + if (isCmdDelim) + sc.Forward(); + } + if (!isCmdDelim) { + s[1] = '\0'; + isCmdDelim = cmdDelimiter.InList(s); + } + if (isCmdDelim) { + cmdState = BASH_CMD_DELIM; + continue; + } + } + // handle closing delimiters for test/arithmetic expressions - )),]],] + if (cmdState == BASH_CMD_ARITH && sc.Match(')', ')')) { + cmdState = BASH_CMD_BODY; + sc.Forward(); + } else if (cmdState == BASH_CMD_TEST && IsASpace(sc.chPrev)) { + if (sc.Match(']', ']') && testExprType == 1) { + sc.Forward(); + cmdState = BASH_CMD_BODY; + } else if (sc.ch == ']' && testExprType == 2) { + cmdState = BASH_CMD_BODY; + } + } } - } + }// sc.state } sc.Complete(); } @@ -507,6 +639,14 @@ static void FoldBashDoc(unsigned int startPos, int length, int, WordList *[], levelCurrent--; } } + // Here Document folding + if (style == SCE_SH_HERE_DELIM) { + if (ch == '<' && chNext == '<') { + levelCurrent++; + } + } else if (style == SCE_SH_HERE_Q && styler.StyleAt(i+1) == SCE_PL_DEFAULT) { + levelCurrent--; + } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) diff --git a/plugins/scintilla/scintilla/LexBasic.cxx b/plugins/scintilla/scintilla/LexBasic.cxx index 1c5d7b4..55641ed 100644 --- a/plugins/scintilla/scintilla/LexBasic.cxx +++ b/plugins/scintilla/scintilla/LexBasic.cxx @@ -1,6 +1,7 @@ // Scintilla source code edit control /** @file LexBasic.cxx ** Lexer for BlitzBasic and PureBasic. + ** Converted to lexer object and added further folding features/properties by "Udo Lechner" **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. @@ -19,18 +20,28 @@ #include #include #include -#include #include +#include +#include -#include "Platform.h" +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#include +#include + +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" +#include "OptionSet.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -86,8 +97,213 @@ static int LowerCase(int c) return c; } -static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler, char comment_char) { +static int CheckBlitzFoldPoint(char const *token, int &level) { + if (!strcmp(token, "function") || + !strcmp(token, "type")) { + level |= SC_FOLDLEVELHEADERFLAG; + return 1; + } + if (!strcmp(token, "end function") || + !strcmp(token, "end type")) { + return -1; + } + return 0; +} + +static int CheckPureFoldPoint(char const *token, int &level) { + if (!strcmp(token, "procedure") || + !strcmp(token, "enumeration") || + !strcmp(token, "interface") || + !strcmp(token, "structure")) { + level |= SC_FOLDLEVELHEADERFLAG; + return 1; + } + if (!strcmp(token, "endprocedure") || + !strcmp(token, "endenumeration") || + !strcmp(token, "endinterface") || + !strcmp(token, "endstructure")) { + return -1; + } + return 0; +} + +static int CheckFreeFoldPoint(char const *token, int &level) { + if (!strcmp(token, "function") || + !strcmp(token, "sub") || + !strcmp(token, "type")) { + level |= SC_FOLDLEVELHEADERFLAG; + return 1; + } + if (!strcmp(token, "end function") || + !strcmp(token, "end sub") || + !strcmp(token, "end type")) { + return -1; + } + return 0; +} + +// An individual named option for use in an OptionSet + +// Options used for LexerBasic +struct OptionsBasic { + bool fold; + bool foldSyntaxBased; + bool foldCommentExplicit; + std::string foldExplicitStart; + std::string foldExplicitEnd; + bool foldExplicitAnywhere; + bool foldCompact; + OptionsBasic() { + fold = false; + foldSyntaxBased = true; + foldCommentExplicit = false; + foldExplicitStart = ""; + foldExplicitEnd = ""; + foldExplicitAnywhere = false; + foldCompact = true; + } +}; + +static const char * const blitzbasicWordListDesc[] = { + "BlitzBasic Keywords", + "user1", + "user2", + "user3", + 0 +}; + +static const char * const purebasicWordListDesc[] = { + "PureBasic Keywords", + "PureBasic PreProcessor Keywords", + "user defined 1", + "user defined 2", + 0 +}; + +static const char * const freebasicWordListDesc[] = { + "FreeBasic Keywords", + "FreeBasic PreProcessor Keywords", + "user defined 1", + "user defined 2", + 0 +}; + +struct OptionSetBasic : public OptionSet { + OptionSetBasic(const char * const wordListDescriptions[]) { + DefineProperty("fold", &OptionsBasic::fold); + + DefineProperty("fold.basic.syntax.based", &OptionsBasic::foldSyntaxBased, + "Set this property to 0 to disable syntax based folding."); + + DefineProperty("fold.basic.comment.explicit", &OptionsBasic::foldCommentExplicit, + "This option enables folding explicit fold points when using the Basic lexer. " + "Explicit fold points allows adding extra folding by placing a ;{ (BB/PB) or '{ (FB) comment at the start " + "and a ;} (BB/PB) or '} (FB) at the end of a section that should be folded."); + + DefineProperty("fold.basic.explicit.start", &OptionsBasic::foldExplicitStart, + "The string to use for explicit fold start points, replacing the standard ;{ (BB/PB) or '{ (FB)."); + + DefineProperty("fold.basic.explicit.end", &OptionsBasic::foldExplicitEnd, + "The string to use for explicit fold end points, replacing the standard ;} (BB/PB) or '} (FB)."); + + DefineProperty("fold.basic.explicit.anywhere", &OptionsBasic::foldExplicitAnywhere, + "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); + + DefineProperty("fold.compact", &OptionsBasic::foldCompact); + + DefineWordListSets(wordListDescriptions); + } +}; + +class LexerBasic : public ILexer { + char comment_char; + int (*CheckFoldPoint)(char const *, int &); + WordList keywordlists[4]; + OptionsBasic options; + OptionSetBasic osBasic; +public: + LexerBasic(char comment_char_, int (*CheckFoldPoint_)(char const *, int &), const char * const wordListDescriptions[]) : + comment_char(comment_char_), + CheckFoldPoint(CheckFoldPoint_), + osBasic(wordListDescriptions) { + } + ~LexerBasic() { + } + void SCI_METHOD Release() { + delete this; + } + int SCI_METHOD Version() const { + return lvOriginal; + } + const char * SCI_METHOD PropertyNames() { + return osBasic.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) { + return osBasic.PropertyType(name); + } + const char * SCI_METHOD DescribeProperty(const char *name) { + return osBasic.DescribeProperty(name); + } + int SCI_METHOD PropertySet(const char *key, const char *val); + const char * SCI_METHOD DescribeWordListSets() { + return osBasic.DescribeWordListSets(); + } + int SCI_METHOD WordListSet(int n, const char *wl); + void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + + void * SCI_METHOD PrivateCall(int, void *) { + return 0; + } + static ILexer *LexerFactoryBlitzBasic() { + return new LexerBasic(';', CheckBlitzFoldPoint, blitzbasicWordListDesc); + } + static ILexer *LexerFactoryPureBasic() { + return new LexerBasic(';', CheckPureFoldPoint, purebasicWordListDesc); + } + static ILexer *LexerFactoryFreeBasic() { + return new LexerBasic('\'', CheckFreeFoldPoint, freebasicWordListDesc ); + } +}; + +int SCI_METHOD LexerBasic::PropertySet(const char *key, const char *val) { + if (osBasic.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +int SCI_METHOD LexerBasic::WordListSet(int n, const char *wl) { + WordList *wordListN = 0; + switch (n) { + case 0: + wordListN = &keywordlists[0]; + break; + case 1: + wordListN = &keywordlists[1]; + break; + case 2: + wordListN = &keywordlists[2]; + break; + case 3: + wordListN = &keywordlists[3]; + break; + } + int firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +void SCI_METHOD LexerBasic::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + LexAccessor styler(pAccess); + bool wasfirst = true, isfirst = true; // true if first token in a line styler.StartAt(startPos); @@ -111,7 +327,7 @@ static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle, }; sc.GetCurrentLowered(s, sizeof(s)); for (int i = 0; i < 4; i++) { - if (keywordlists[i]->InList(s)) { + if (keywordlists[i].InList(s)) { sc.ChangeState(kstates[i]); } } @@ -202,66 +418,30 @@ static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle, sc.Complete(); } -static int CheckBlitzFoldPoint(char const *token, int &level) { - if (!strcmp(token, "function") || - !strcmp(token, "type")) { - level |= SC_FOLDLEVELHEADERFLAG; - return 1; - } - if (!strcmp(token, "end function") || - !strcmp(token, "end type")) { - return -1; - } - return 0; -} -static int CheckPureFoldPoint(char const *token, int &level) { - if (!strcmp(token, "procedure") || - !strcmp(token, "enumeration") || - !strcmp(token, "interface") || - !strcmp(token, "structure")) { - level |= SC_FOLDLEVELHEADERFLAG; - return 1; - } - if (!strcmp(token, "endprocedure") || - !strcmp(token, "endenumeration") || - !strcmp(token, "endinterface") || - !strcmp(token, "endstructure")) { - return -1; - } - return 0; -} +void SCI_METHOD LexerBasic::Fold(unsigned int startPos, int length, int /* initStyle */, IDocument *pAccess) { -static int CheckFreeFoldPoint(char const *token, int &level) { - if (!strcmp(token, "function") || - !strcmp(token, "sub") || - !strcmp(token, "type")) { - level |= SC_FOLDLEVELHEADERFLAG; - return 1; - } - if (!strcmp(token, "end function") || - !strcmp(token, "end sub") || - !strcmp(token, "end type")) { - return -1; - } - return 0; -} + if (!options.fold) + return; + + LexAccessor styler(pAccess); -static void FoldBasicDoc(unsigned int startPos, int length, - Accessor &styler, int (*CheckFoldPoint)(char const *, int &)) { int line = styler.GetLine(startPos); int level = styler.LevelAt(line); int go = 0, done = 0; int endPos = startPos + length; char word[256]; int wordlen = 0; - int i; - bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); + int cNext = styler[startPos]; + // Scan for tokens at the start of the line (they may include // whitespace, for tokens like "End Function" - for (i = startPos; i < endPos; i++) { - int c = styler.SafeGetCharAt(i); - if (!done && !go) { + for (int i = startPos; i < endPos; i++) { + int c = cNext; + cNext = styler.SafeGetCharAt(i + 1); + bool atEOL = (c == '\r' && cNext != '\n') || (c == '\n'); + if (options.foldSyntaxBased && !done && !go) { if (wordlen) { // are we scanning a token already? word[wordlen] = static_cast(LowerCase(c)); if (!IsIdentifier(c)) { // done with token @@ -291,8 +471,27 @@ static void FoldBasicDoc(unsigned int startPos, int length, } } } - if (c == '\n') { // line end - if (!done && wordlen == 0 && foldCompact) // line was only space + if (options.foldCommentExplicit && ((styler.StyleAt(i) == SCE_B_COMMENT) || options.foldExplicitAnywhere)) { + if (userDefinedFoldMarkers) { + if (styler.Match(i, options.foldExplicitStart.c_str())) { + level |= SC_FOLDLEVELHEADERFLAG; + go = 1; + } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { + go = -1; + } + } else { + if (c == comment_char) { + if (cNext == '{') { + level |= SC_FOLDLEVELHEADERFLAG; + go = 1; + } else if (cNext == '}') { + go = -1; + } + } + } + } + if (atEOL) { // line end + if (!done && wordlen == 0 && options.foldCompact) // line was only space level |= SC_FOLDLEVELWHITEFLAG; if (level != styler.LevelAt(line)) styler.SetLevel(line, level); @@ -308,66 +507,8 @@ static void FoldBasicDoc(unsigned int startPos, int length, } } -static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler) { - ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';'); -} - -static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler) { - ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';'); -} - -static void ColouriseFreeBasicDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler) { - ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, '\''); -} - -static void FoldBlitzBasicDoc(unsigned int startPos, int length, int, - WordList *[], Accessor &styler) { - FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint); -} - -static void FoldPureBasicDoc(unsigned int startPos, int length, int, - WordList *[], Accessor &styler) { - FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint); -} - -static void FoldFreeBasicDoc(unsigned int startPos, int length, int, - WordList *[], Accessor &styler) { - FoldBasicDoc(startPos, length, styler, CheckFreeFoldPoint); -} - -static const char * const blitzbasicWordListDesc[] = { - "BlitzBasic Keywords", - "user1", - "user2", - "user3", - 0 -}; - -static const char * const purebasicWordListDesc[] = { - "PureBasic Keywords", - "PureBasic PreProcessor Keywords", - "user defined 1", - "user defined 2", - 0 -}; - -static const char * const freebasicWordListDesc[] = { - "FreeBasic Keywords", - "FreeBasic PreProcessor Keywords", - "user defined 1", - "user defined 2", - 0 -}; - -LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic", - FoldBlitzBasicDoc, blitzbasicWordListDesc); - -LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic", - FoldPureBasicDoc, purebasicWordListDesc); +LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, LexerBasic::LexerFactoryBlitzBasic, "blitzbasic", blitzbasicWordListDesc); -LexerModule lmFreeBasic(SCLEX_FREEBASIC, ColouriseFreeBasicDoc, "freebasic", - FoldFreeBasicDoc, freebasicWordListDesc); +LexerModule lmPureBasic(SCLEX_PUREBASIC, LexerBasic::LexerFactoryPureBasic, "purebasic", purebasicWordListDesc); +LexerModule lmFreeBasic(SCLEX_FREEBASIC, LexerBasic::LexerFactoryFreeBasic, "freebasic", freebasicWordListDesc); diff --git a/plugins/scintilla/scintilla/LexBullant.cxx b/plugins/scintilla/scintilla/LexBullant.cxx index cc60cd2..bb5c9c4 100644 --- a/plugins/scintilla/scintilla/LexBullant.cxx +++ b/plugins/scintilla/scintilla/LexBullant.cxx @@ -3,24 +3,29 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" - -#include "PropSet.h" -#include "Accessor.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static int classifyWordBullant(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { char s[100]; + s[0] = '\0'; for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { s[i] = static_cast(tolower(styler[start + i])); s[i + 1] = '\0'; @@ -111,7 +116,7 @@ static void ColouriseBullantDoc(unsigned int startPos, int length, int initStyle } blockChange=0; */ } - if (!isspace(ch)) + if (!(isascii(ch) && isspace(ch))) visibleChars++; if (styler.IsLeadByte(ch)) { diff --git a/plugins/scintilla/scintilla/LexCLW.cxx b/plugins/scintilla/scintilla/LexCLW.cxx index 624ef0f..c1dea60 100644 --- a/plugins/scintilla/scintilla/LexCLW.cxx +++ b/plugins/scintilla/scintilla/LexCLW.cxx @@ -10,16 +10,19 @@ #include #include #include +#include #include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -60,10 +63,10 @@ inline bool IsALabelStart(const int iChar) { // Is a label character inline bool IsALabelCharacter(const int iChar) { - return(isalnum(iChar) || iChar == '_' || iChar == ':'); + return(isalnum(iChar) || iChar == '_' || iChar == ':'); } -// Is the character is a ! and the the next character is not a ! +// Is the character is a ! and the the next character is not a ! inline bool IsACommentStart(const int iChar) { return(iChar == '!'); @@ -126,7 +129,7 @@ inline bool SetNumericConstantState(StyleContext &scDoc) { break; default : break; - } + } } // If points found (can be more than one for improper formatted number if (iPoints > 0) { @@ -186,12 +189,12 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS WordList &wlLabelReservedWords = *wlKeywords[7]; // Clarion Reserved Keywords (Labels) WordList &wlProcLabelReservedWords = *wlKeywords[8]; // Clarion Reserved Keywords (Procedure Labels) - const char wlProcReservedKeywordList[] = + const char wlProcReservedKeywordList[] = "PROCEDURE FUNCTION"; WordList wlProcReservedKeywords; wlProcReservedKeywords.Set(wlProcReservedKeywordList); - const char wlCompilerKeywordList[] = + const char wlCompilerKeywordList[] = "COMPILE OMIT"; WordList wlCompilerKeywords; wlCompilerKeywords.Set(wlCompilerKeywordList); @@ -243,7 +246,7 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS // change the label to error state scDoc.ChangeState(SCE_CLW_ERROR); } - // Else if UPPERCASE label string is + // Else if UPPERCASE label string is else if (wlProcLabelReservedWords.InList(cLabel) && iColumn1Label) { char cWord[512]; // Word buffer // Get the next word from the current position @@ -368,13 +371,13 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS // Increment the parenthese level iParenthesesLevel++; } - // Else if the character is a ) (close parenthese) + // Else if the character is a ) (close parenthese) else if (scDoc.ch == ')') { // If the parenthese level is set to zero // parentheses matched if (!iParenthesesLevel) { scDoc.SetState(SCE_CLW_DEFAULT); - } + } // Else parenthese level is greater than zero // still looking for matching parentheses else { @@ -399,7 +402,7 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS || IsAHexCharacter(scDoc.ch, bCaseSensitive) || scDoc.ch == '.' || IsANumericBaseCharacter(scDoc.ch, bCaseSensitive))) { - // If the number was a real + // If the number was a real if (SetNumericConstantState(scDoc)) { // Colour the matched string to the real constant state scDoc.ChangeState(SCE_CLW_REAL_CONSTANT); @@ -461,7 +464,7 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS } // Default Handling else { - // If in default state + // If in default state if (scDoc.state == SCE_CLW_DEFAULT) { // If is a letter could be a possible statement if (isalpha(scDoc.ch)) { @@ -477,10 +480,10 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS else if (IsACommentStart(scDoc.ch) || scDoc.ch == '|') { // then set the state to comment. scDoc.SetState(SCE_CLW_COMMENT); - } + } // else if the character is a ' (single quote) else if (scDoc.ch == '\'') { - // If the character is also a ' (single quote) + // If the character is also a ' (single quote) // Embedded Apostrophe if (scDoc.chNext == '\'') { // Move forward colouring it as default state @@ -490,7 +493,7 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS // move to the next character and then set the state to comment. scDoc.ForwardSetState(SCE_CLW_STRING); } - } + } // else the character is an @ (ampersand) else if (scDoc.ch == '@') { // Case insensitive. @@ -509,7 +512,7 @@ static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitS scDoc.SetState(SCE_CLW_PICTURE_STRING); } } - } + } } } } @@ -616,7 +619,7 @@ static void FoldClarionDoc(unsigned int uiStartPos, int iLength, int iInitStyle, iStyle = iStyleNext; iStyleNext = accStyler.StyleAt(uiPos + 1); bool bEOL = (chChar == '\r' && chNext != '\n') || (chChar == '\n'); - + if (iStylePrev == SCE_CLW_DEFAULT) { if (iStyle == SCE_CLW_KEYWORD || iStyle == SCE_CLW_STRUCTURE_DATA_TYPE) { // Store last word start point. @@ -647,7 +650,7 @@ static void FoldClarionDoc(unsigned int uiStartPos, int iLength, int iInitStyle, iLevelPrev = iLevelCurrent; iVisibleChars = 0; } - + if (!isspacechar(chChar)) iVisibleChars++; } diff --git a/plugins/scintilla/scintilla/LexCOBOL.cxx b/plugins/scintilla/scintilla/LexCOBOL.cxx index d061d5c..a9a8f55 100644 --- a/plugins/scintilla/scintilla/LexCOBOL.cxx +++ b/plugins/scintilla/scintilla/LexCOBOL.cxx @@ -10,18 +10,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" - -#include "PropSet.h" -#include "Accessor.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" + +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" #include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -90,11 +93,11 @@ static int classifyWordCOBOL(unsigned int start, unsigned int end, /*WordList &k getRange(start, end, styler, s, sizeof(s)); char chAttr = SCE_C_IDENTIFIER; - if (isdigit(s[0]) || (s[0] == '.')) { + if (isdigit(s[0]) || (s[0] == '.') || (s[0] == 'v')) { chAttr = SCE_C_NUMBER; char *p = s + 1; while (*p) { - if (!isdigit(*p) && isCOBOLwordchar(*p)) { + if ((!isdigit(*p) && (*p) != 'v') && isCOBOLwordchar(*p)) { chAttr = SCE_C_IDENTIFIER; break; } @@ -202,7 +205,7 @@ static void ColouriseCOBOLDoc(unsigned int startPos, int length, int initStyle, } if (state == SCE_C_DEFAULT) { - if (isCOBOLwordstart(ch) || (ch == '$' && isalpha(chNext))) { + if (isCOBOLwordstart(ch) || (ch == '$' && isascii(chNext) && isalpha(chNext))) { ColourTo(styler, i-1, state); state = SCE_C_IDENTIFIER; } else if (column == 0 && ch == '*' && chNext != '*') { diff --git a/plugins/scintilla/scintilla/LexCPP.cxx b/plugins/scintilla/scintilla/LexCPP.cxx index 9577afb..22477c3 100644 --- a/plugins/scintilla/scintilla/LexCPP.cxx +++ b/plugins/scintilla/scintilla/LexCPP.cxx @@ -1,6 +1,7 @@ // Scintilla source code edit control /** @file LexCPP.cxx ** Lexer for C++, C, Java, and JavaScript. + ** Further folding features and configuration properties added by "Udo Lechner" **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. @@ -10,16 +11,29 @@ #include #include #include +#include -#include "Platform.h" +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#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" +#include "OptionSet.h" +#include "SparseState.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -39,7 +53,7 @@ static bool IsSpaceEquiv(int state) { // a = b+++/ptn/... // Putting a space between the '++' post-inc operator and the '+' binary op // fixes this, and is highly recommended for readability anyway. -static bool FollowsPostfixOperator(StyleContext &sc, Accessor &styler) { +static bool FollowsPostfixOperator(StyleContext &sc, LexAccessor &styler) { int pos = (int) sc.currentPos; while (--pos > 0) { char ch = styler[pos]; @@ -50,18 +64,384 @@ static bool FollowsPostfixOperator(StyleContext &sc, Accessor &styler) { return false; } -static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler, bool caseSensitive) { +static bool followsReturnKeyword(StyleContext &sc, LexAccessor &styler) { + // Don't look at styles, so no need to flush. + int pos = (int) sc.currentPos; + int currentLine = styler.GetLine(pos); + int lineStartPos = styler.LineStart(currentLine); + char ch; + while (--pos > lineStartPos) { + ch = styler.SafeGetCharAt(pos); + if (ch != ' ' && ch != '\t') { + break; + } + } + const char *retBack = "nruter"; + const char *s = retBack; + while (*s + && pos >= lineStartPos + && styler.SafeGetCharAt(pos) == *s) { + s++; + pos--; + } + return !*s; +} + +static std::string GetRestOfLine(LexAccessor &styler, int start, bool allowSpace) { + std::string restOfLine; + int i =0; + char ch = styler.SafeGetCharAt(start + i, '\n'); + while ((ch != '\r') && (ch != '\n')) { + if (allowSpace || (ch != ' ')) + restOfLine += ch; + i++; + ch = styler.SafeGetCharAt(start + i, '\n'); + } + return restOfLine; +} + +static bool IsStreamCommentStyle(int style) { + return style == SCE_C_COMMENT || + style == SCE_C_COMMENTDOC || + style == SCE_C_COMMENTDOCKEYWORD || + style == SCE_C_COMMENTDOCKEYWORDERROR; +} + +static std::vector Tokenize(const std::string &s) { + // Break into space separated tokens + std::string word; + std::vector tokens; + for (const char *cp = s.c_str(); *cp; cp++) { + if ((*cp == ' ') || (*cp == '\t')) { + if (!word.empty()) { + tokens.push_back(word); + word = ""; + } + } else { + word += *cp; + } + } + if (!word.empty()) { + tokens.push_back(word); + } + return tokens; +} + +struct PPDefinition { + int line; + std::string key; + std::string value; + PPDefinition(int line_, const std::string &key_, const std::string &value_) : + line(line_), key(key_), value(value_) { + } +}; - WordList &keywords = *keywordlists[0]; - WordList &keywords2 = *keywordlists[1]; - WordList &keywords3 = *keywordlists[2]; - WordList &keywords4 = *keywordlists[3]; +class LinePPState { + int state; + int ifTaken; + int level; + bool ValidLevel() const { + return level >= 0 && level < 32; + } + int maskLevel() const { + return 1 << level; + } +public: + LinePPState() : state(0), ifTaken(0), level(-1) { + } + bool IsInactive() const { + return state != 0; + } + bool CurrentIfTaken() { + return (ifTaken & maskLevel()) != 0; + } + void StartSection(bool on) { + level++; + if (ValidLevel()) { + if (on) { + state &= ~maskLevel(); + ifTaken |= maskLevel(); + } else { + state |= maskLevel(); + ifTaken &= ~maskLevel(); + } + } + } + void EndSection() { + if (ValidLevel()) { + state &= ~maskLevel(); + ifTaken &= ~maskLevel(); + } + level--; + } + void InvertCurrentLevel() { + if (ValidLevel()) { + state ^= maskLevel(); + ifTaken |= maskLevel(); + } + } +}; + +// Hold the preprocessor state for each line seen. +// Currently one entry per line but could become sparse with just one entry per preprocessor line. +class PPStates { + std::vector vlls; +public: + LinePPState ForLine(int line) { + if ((line > 0) && (vlls.size() > static_cast(line))) { + return vlls[line]; + } else { + return LinePPState(); + } + } + void Add(int line, LinePPState lls) { + vlls.resize(line+1); + vlls[line] = lls; + } +}; - // property styling.within.preprocessor - // For C++ code, determines whether all preprocessor code is styled in the preprocessor style (0, the default) - // or only from the initial # to the end of the command word(1). - bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0; +// An individual named option for use in an OptionSet + +// Options used for LexerCPP +struct OptionsCPP { + bool stylingWithinPreprocessor; + bool identifiersAllowDollars; + bool trackPreprocessor; + bool updatePreprocessor; + bool triplequotedStrings; + bool fold; + bool foldSyntaxBased; + bool foldComment; + bool foldCommentMultiline; + bool foldCommentExplicit; + std::string foldExplicitStart; + std::string foldExplicitEnd; + bool foldExplicitAnywhere; + bool foldPreprocessor; + bool foldCompact; + bool foldAtElse; + OptionsCPP() { + stylingWithinPreprocessor = false; + identifiersAllowDollars = true; + trackPreprocessor = true; + updatePreprocessor = true; + triplequotedStrings = false; + fold = false; + foldSyntaxBased = true; + foldComment = false; + foldCommentMultiline = true; + foldCommentExplicit = true; + foldExplicitStart = ""; + foldExplicitEnd = ""; + foldExplicitAnywhere = false; + foldPreprocessor = false; + foldCompact = false; + foldAtElse = false; + } +}; + +static const char *const cppWordLists[] = { + "Primary keywords and identifiers", + "Secondary keywords and identifiers", + "Documentation comment keywords", + "Global classes and typedefs", + "Preprocessor definitions", + 0, +}; + +struct OptionSetCPP : public OptionSet { + OptionSetCPP() { + DefineProperty("styling.within.preprocessor", &OptionsCPP::stylingWithinPreprocessor, + "For C++ code, determines whether all preprocessor code is styled in the " + "preprocessor style (0, the default) or only from the initial # to the end " + "of the command word(1)."); + + DefineProperty("lexer.cpp.allow.dollars", &OptionsCPP::identifiersAllowDollars, + "Set to 0 to disallow the '$' character in identifiers with the cpp lexer."); + + DefineProperty("lexer.cpp.track.preprocessor", &OptionsCPP::trackPreprocessor, + "Set to 1 to interpret #if/#else/#endif to grey out code that is not active."); + + DefineProperty("lexer.cpp.update.preprocessor", &OptionsCPP::updatePreprocessor, + "Set to 1 to update preprocessor definitions when #define found."); + + DefineProperty("lexer.cpp.triplequoted.strings", &OptionsCPP::triplequotedStrings, + "Set to 1 to enable highlighting of triple-quoted strings."); + + DefineProperty("fold", &OptionsCPP::fold); + + DefineProperty("fold.cpp.syntax.based", &OptionsCPP::foldSyntaxBased, + "Set this property to 0 to disable syntax based folding."); + + DefineProperty("fold.comment", &OptionsCPP::foldComment, + "This option enables folding multi-line comments and explicit fold points when using the C++ lexer. " + "Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //} " + "at the end of a section that should fold."); + + DefineProperty("fold.cpp.comment.multiline", &OptionsCPP::foldCommentMultiline, + "Set this property to 0 to disable folding multi-line comments when fold.comment=1."); + + DefineProperty("fold.cpp.comment.explicit", &OptionsCPP::foldCommentExplicit, + "Set this property to 0 to disable folding explicit fold points when fold.comment=1."); + + DefineProperty("fold.cpp.explicit.start", &OptionsCPP::foldExplicitStart, + "The string to use for explicit fold start points, replacing the standard //{."); + + DefineProperty("fold.cpp.explicit.end", &OptionsCPP::foldExplicitEnd, + "The string to use for explicit fold end points, replacing the standard //}."); + + DefineProperty("fold.cpp.explicit.anywhere", &OptionsCPP::foldExplicitAnywhere, + "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); + + DefineProperty("fold.preprocessor", &OptionsCPP::foldPreprocessor, + "This option enables folding preprocessor directives when using the C++ lexer. " + "Includes C#'s explicit #region and #endregion folding directives."); + + DefineProperty("fold.compact", &OptionsCPP::foldCompact); + + DefineProperty("fold.at.else", &OptionsCPP::foldAtElse, + "This option enables C++ folding on a \"} else {\" line of an if statement."); + + DefineWordListSets(cppWordLists); + } +}; + +class LexerCPP : public ILexer { + bool caseSensitive; + CharacterSet setWord; + CharacterSet setNegationOp; + CharacterSet setArithmethicOp; + CharacterSet setRelOp; + CharacterSet setLogicalOp; + PPStates vlls; + std::vector ppDefineHistory; + WordList keywords; + WordList keywords2; + WordList keywords3; + WordList keywords4; + WordList ppDefinitions; + std::map preprocessorDefinitionsStart; + OptionsCPP options; + OptionSetCPP osCPP; + SparseState rawStringTerminators; + enum { activeFlag = 0x40 }; +public: + LexerCPP(bool caseSensitive_) : + caseSensitive(caseSensitive_), + setWord(CharacterSet::setAlphaNum, "._", 0x80, true), + setNegationOp(CharacterSet::setNone, "!"), + setArithmethicOp(CharacterSet::setNone, "+-/*%"), + setRelOp(CharacterSet::setNone, "=!<>"), + setLogicalOp(CharacterSet::setNone, "|&") { + } + ~LexerCPP() { + } + void SCI_METHOD Release() { + delete this; + } + int SCI_METHOD Version() const { + return lvOriginal; + } + const char * SCI_METHOD PropertyNames() { + return osCPP.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) { + return osCPP.PropertyType(name); + } + const char * SCI_METHOD DescribeProperty(const char *name) { + return osCPP.DescribeProperty(name); + } + int SCI_METHOD PropertySet(const char *key, const char *val); + const char * SCI_METHOD DescribeWordListSets() { + return osCPP.DescribeWordListSets(); + } + int SCI_METHOD WordListSet(int n, const char *wl); + void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + + void * SCI_METHOD PrivateCall(int, void *) { + return 0; + } + + static ILexer *LexerFactoryCPP() { + return new LexerCPP(true); + } + static ILexer *LexerFactoryCPPInsensitive() { + return new LexerCPP(false); + } + static int MaskActive(int style) { + return style & ~activeFlag; + } + void EvaluateTokens(std::vector &tokens); + bool EvaluateExpression(const std::string &expr, const std::map &preprocessorDefinitions); +}; + +int SCI_METHOD LexerCPP::PropertySet(const char *key, const char *val) { + if (osCPP.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +int SCI_METHOD LexerCPP::WordListSet(int n, const char *wl) { + WordList *wordListN = 0; + switch (n) { + case 0: + wordListN = &keywords; + break; + case 1: + wordListN = &keywords2; + break; + case 2: + wordListN = &keywords3; + break; + case 3: + wordListN = &keywords4; + break; + case 4: + wordListN = &ppDefinitions; + break; + } + int firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + if (n == 4) { + // Rebuild preprocessorDefinitions + preprocessorDefinitionsStart.clear(); + for (int nDefinition = 0; nDefinition < ppDefinitions.len; nDefinition++) { + char *cpDefinition = ppDefinitions.words[nDefinition]; + char *cpEquals = strchr(cpDefinition, '='); + if (cpEquals) { + std::string name(cpDefinition, cpEquals - cpDefinition); + std::string val(cpEquals+1); + preprocessorDefinitionsStart[name] = val; + } else { + std::string name(cpDefinition); + std::string val("1"); + preprocessorDefinitionsStart[name] = val; + } + } + } + } + } + return firstModification; +} + +// Functor used to truncate history +struct After { + int line; + After(int line_) : line(line_) {} + bool operator()(PPDefinition &p) const { + return p.line > line; + } +}; + +void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + LexAccessor styler(pAccess); CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-"); CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-"); @@ -69,11 +449,8 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true); - CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true); - // property lexer.cpp.allow.dollars - // Set to 0 to disallow the '$' character in identifiers with the cpp lexer. - if (styler.GetPropertyInt("lexer.cpp.allow.dollars", 1) != 0) { + if (options.identifiersAllowDollars) { setWordStart.Add('$'); setWord.Add('$'); } @@ -85,9 +462,11 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo bool continuationLine = false; bool isIncludePreprocessor = false; - if (initStyle == SCE_C_PREPROCESSOR) { + int lineCurrent = styler.GetLine(startPos); + if ((initStyle == SCE_C_PREPROCESSOR) || + (initStyle == SCE_C_COMMENTLINE) || + (initStyle == SCE_C_COMMENTLINEDOC)) { // Set continuationLine if last character of previous line is '\' - int lineCurrent = styler.GetLine(startPos); if (lineCurrent > 0) { int chBack = styler.SafeGetCharAt(startPos-1, 0); int chBack2 = styler.SafeGetCharAt(startPos-2, 0); @@ -111,21 +490,64 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo } } - StyleContext sc(startPos, length, initStyle, styler); + StyleContext sc(startPos, length, initStyle, styler, 0x7f); + LinePPState preproc = vlls.ForLine(lineCurrent); + + bool definitionsChanged = false; + + // Truncate ppDefineHistory before current line + + if (!options.updatePreprocessor) + ppDefineHistory.clear(); + + std::vector::iterator itInvalid = std::find_if(ppDefineHistory.begin(), ppDefineHistory.end(), After(lineCurrent-1)); + if (itInvalid != ppDefineHistory.end()) { + ppDefineHistory.erase(itInvalid, ppDefineHistory.end()); + definitionsChanged = true; + } + + std::map preprocessorDefinitions = preprocessorDefinitionsStart; + for (std::vector::iterator itDef = ppDefineHistory.begin(); itDef != ppDefineHistory.end(); ++itDef) { + preprocessorDefinitions[itDef->key] = itDef->value; + } + + std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1); + SparseState rawSTNew(lineCurrent); + + int activitySet = preproc.IsInactive() ? activeFlag : 0; for (; sc.More(); sc.Forward()) { if (sc.atLineStart) { - if (sc.state == SCE_C_STRING) { + if ((sc.state == SCE_C_STRING) || (sc.state == SCE_C_CHARACTER)) { // Prevent SCE_C_STRINGEOL from leaking back to previous line which // ends with a line continuation by locking in the state upto this position. - sc.SetState(SCE_C_STRING); + sc.SetState(sc.state); } // Reset states to begining of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; lastWordWasUUID = false; isIncludePreprocessor = false; + if (preproc.IsInactive()) { + activitySet = activeFlag; + sc.SetState(sc.state | activitySet); + } + if (activitySet) { + if (sc.ch == '#') { + if (sc.Match("#else") || sc.Match("#end") || sc.Match("#if")) { + //activitySet = 0; + } + } + } + } + + if (sc.atLineEnd) { + lineCurrent++; + vlls.Add(lineCurrent, preproc); + if (rawStringTerminator != "") { + rawSTNew.Set(lineCurrent-1, rawStringTerminator); + } } // Handle line continuation generically. @@ -140,15 +562,17 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo } } + const bool atLineEndBeforeSwitch = sc.atLineEnd; + // Determine if the current state should terminate. - switch (sc.state) { + switch (MaskActive(sc.state)) { case SCE_C_OPERATOR: - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); break; case SCE_C_NUMBER: // We accept almost anything because of hex. and number suffixes - if (!setWord.Contains(sc.ch)) { - sc.SetState(SCE_C_DEFAULT); + if (!(setWord.Contains(sc.ch) || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) { + sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_IDENTIFIER: @@ -161,59 +585,76 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo } if (keywords.InList(s)) { lastWordWasUUID = strcmp(s, "uuid") == 0; - sc.ChangeState(SCE_C_WORD); + sc.ChangeState(SCE_C_WORD|activitySet); } else if (keywords2.InList(s)) { - sc.ChangeState(SCE_C_WORD2); + sc.ChangeState(SCE_C_WORD2|activitySet); } else if (keywords4.InList(s)) { - sc.ChangeState(SCE_C_GLOBALCLASS); + sc.ChangeState(SCE_C_GLOBALCLASS|activitySet); + } + const bool literalString = sc.ch == '\"'; + if (literalString || sc.ch == '\'') { + size_t lenS = strlen(s); + const bool raw = literalString && sc.chPrev == 'R'; + if (raw) + s[lenS--] = '\0'; + bool valid = + (lenS == 0) || + ((lenS == 1) && ((s[0] == 'L') || (s[0] == 'u') || (s[0] == 'U'))) || + ((lenS == 2) && literalString && (s[0] == 'u') && (s[1] == '8')); + if (valid) { + if (literalString) + sc.ChangeState((raw ? SCE_C_STRINGRAW : SCE_C_STRING)|activitySet); + else + sc.ChangeState(SCE_C_CHARACTER|activitySet); + } } - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_PREPROCESSOR: if (sc.atLineStart && !continuationLine) { - sc.SetState(SCE_C_DEFAULT); - } else if (stylingWithinPreprocessor) { + sc.SetState(SCE_C_DEFAULT|activitySet); + } else if (options.stylingWithinPreprocessor) { if (IsASpace(sc.ch)) { - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } } else { if (sc.Match('/', '*') || sc.Match('/', '/')) { - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } } break; case SCE_C_COMMENT: if (sc.Match('*', '/')) { sc.Forward(); - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_COMMENTDOC: if (sc.Match('*', '/')) { sc.Forward(); - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_C_COMMENTDOC; - sc.SetState(SCE_C_COMMENTDOCKEYWORD); + sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet); } } break; case SCE_C_COMMENTLINE: - if (sc.atLineStart) { - sc.SetState(SCE_C_DEFAULT); + if (sc.atLineStart && !continuationLine) { + sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_COMMENTLINEDOC: - if (sc.atLineStart) { - sc.SetState(SCE_C_DEFAULT); + if (sc.atLineStart && !continuationLine) { + sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_C_COMMENTLINEDOC; - sc.SetState(SCE_C_COMMENTDOCKEYWORD); + sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet); } } break; @@ -221,7 +662,7 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo if ((styleBeforeDCKeyword == SCE_C_COMMENTDOC) && sc.Match('*', '/')) { sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR); sc.Forward(); - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } else if (!setDoxygen.Contains(sc.ch)) { char s[100]; if (caseSensitive) { @@ -230,17 +671,17 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo sc.GetCurrentLowered(s, sizeof(s)); } if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) { - sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR); + sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet); } sc.SetState(styleBeforeDCKeyword); } break; case SCE_C_STRING: if (sc.atLineEnd) { - sc.ChangeState(SCE_C_STRINGEOL); + sc.ChangeState(SCE_C_STRINGEOL|activitySet); } else if (isIncludePreprocessor) { if (sc.ch == '>') { - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); isIncludePreprocessor = false; } } else if (sc.ch == '\\') { @@ -248,28 +689,36 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo sc.Forward(); } } else if (sc.ch == '\"') { - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); + } + break; + case SCE_C_STRINGRAW: + if (sc.Match(rawStringTerminator.c_str())) { + for (size_t termPos=rawStringTerminator.size(); termPos; termPos--) + sc.Forward(); + sc.SetState(SCE_C_DEFAULT|activitySet); + rawStringTerminator = ""; } break; case SCE_C_CHARACTER: if (sc.atLineEnd) { - sc.ChangeState(SCE_C_STRINGEOL); + sc.ChangeState(SCE_C_STRINGEOL|activitySet); } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_REGEX: if (sc.atLineStart) { - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '/') { sc.Forward(); while ((sc.ch < 0x80) && islower(sc.ch)) sc.Forward(); // gobble regex flags - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '\\') { // Gobble up the quoted character if (sc.chNext == '\\' || sc.chNext == '/') { @@ -279,7 +728,7 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo break; case SCE_C_STRINGEOL: if (sc.atLineStart) { - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_VERBATIM: @@ -287,72 +736,170 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo if (sc.chNext == '\"') { sc.Forward(); } else { - sc.ForwardSetState(SCE_C_DEFAULT); + sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } } break; + case SCE_C_TRIPLEVERBATIM: + if (sc.Match("\"\"\"")) { + while (sc.Match('"')) { + sc.Forward(); + } + sc.SetState(SCE_C_DEFAULT|activitySet); + } + break; case SCE_C_UUID: if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') { - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } } + if (sc.atLineEnd && !atLineEndBeforeSwitch) { + // State exit processing consumed characters up to end of line. + lineCurrent++; + vlls.Add(lineCurrent, preproc); + } + // Determine if a new state should be entered. - if (sc.state == SCE_C_DEFAULT) { + if (MaskActive(sc.state) == SCE_C_DEFAULT) { if (sc.Match('@', '\"')) { - sc.SetState(SCE_C_VERBATIM); + sc.SetState(SCE_C_VERBATIM|activitySet); sc.Forward(); + } else if (options.triplequotedStrings && sc.Match("\"\"\"")) { + sc.SetState(SCE_C_TRIPLEVERBATIM|activitySet); + sc.Forward(2); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { if (lastWordWasUUID) { - sc.SetState(SCE_C_UUID); + sc.SetState(SCE_C_UUID|activitySet); lastWordWasUUID = false; } else { - sc.SetState(SCE_C_NUMBER); + sc.SetState(SCE_C_NUMBER|activitySet); } } else if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) { if (lastWordWasUUID) { - sc.SetState(SCE_C_UUID); + sc.SetState(SCE_C_UUID|activitySet); lastWordWasUUID = false; } else { - sc.SetState(SCE_C_IDENTIFIER); + sc.SetState(SCE_C_IDENTIFIER|activitySet); } } else if (sc.Match('/', '*')) { if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style - sc.SetState(SCE_C_COMMENTDOC); + sc.SetState(SCE_C_COMMENTDOC|activitySet); } else { - sc.SetState(SCE_C_COMMENT); + sc.SetState(SCE_C_COMMENT|activitySet); } sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!")) // Support of Qt/Doxygen doc. style - sc.SetState(SCE_C_COMMENTLINEDOC); + sc.SetState(SCE_C_COMMENTLINEDOC|activitySet); else - sc.SetState(SCE_C_COMMENTLINE); - } else if (sc.ch == '/' && setOKBeforeRE.Contains(chPrevNonWhite) && - (!setCouldBePostOp.Contains(chPrevNonWhite) || !FollowsPostfixOperator(sc, styler))) { - sc.SetState(SCE_C_REGEX); // JavaScript's RegEx + sc.SetState(SCE_C_COMMENTLINE|activitySet); + } else if (sc.ch == '/' + && (setOKBeforeRE.Contains(chPrevNonWhite) + || followsReturnKeyword(sc, styler)) + && (!setCouldBePostOp.Contains(chPrevNonWhite) + || !FollowsPostfixOperator(sc, styler))) { + sc.SetState(SCE_C_REGEX|activitySet); // JavaScript's RegEx } else if (sc.ch == '\"') { - sc.SetState(SCE_C_STRING); + if (sc.chPrev == 'R') { + sc.SetState(SCE_C_STRINGRAW|activitySet); + rawStringTerminator = ")"; + for (int termPos = sc.currentPos + 1;; termPos++) { + char chTerminator = styler.SafeGetCharAt(termPos, '('); + if (chTerminator == '(') + break; + rawStringTerminator += chTerminator; + } + rawStringTerminator += '\"'; + } else { + sc.SetState(SCE_C_STRING|activitySet); + } isIncludePreprocessor = false; // ensure that '>' won't end the string } else if (isIncludePreprocessor && sc.ch == '<') { - sc.SetState(SCE_C_STRING); + sc.SetState(SCE_C_STRING|activitySet); } else if (sc.ch == '\'') { - sc.SetState(SCE_C_CHARACTER); + sc.SetState(SCE_C_CHARACTER|activitySet); } else if (sc.ch == '#' && visibleChars == 0) { // Preprocessor commands are alone on their line - sc.SetState(SCE_C_PREPROCESSOR); + sc.SetState(SCE_C_PREPROCESSOR|activitySet); // Skip whitespace between # and preprocessor word do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); if (sc.atLineEnd) { - sc.SetState(SCE_C_DEFAULT); + sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.Match("include")) { isIncludePreprocessor = true; + } else { + if (options.trackPreprocessor) { + if (sc.Match("ifdef") || sc.Match("ifndef")) { + bool isIfDef = sc.Match("ifdef"); + int i = isIfDef ? 5 : 6; + std::string restOfLine = GetRestOfLine(styler, sc.currentPos + i + 1, false); + bool foundDef = preprocessorDefinitions.find(restOfLine) != preprocessorDefinitions.end(); + preproc.StartSection(isIfDef == foundDef); + } else if (sc.Match("if")) { + std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true); + bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions); + preproc.StartSection(ifGood); + } else if (sc.Match("else")) { + if (!preproc.CurrentIfTaken()) { + preproc.InvertCurrentLevel(); + activitySet = preproc.IsInactive() ? activeFlag : 0; + if (!activitySet) + sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + } else if (!preproc.IsInactive()) { + preproc.InvertCurrentLevel(); + activitySet = preproc.IsInactive() ? activeFlag : 0; + if (!activitySet) + sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + } + } else if (sc.Match("elif")) { + // Ensure only one chosen out of #if .. #elif .. #elif .. #else .. #endif + if (!preproc.CurrentIfTaken()) { + // Similar to #if + std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true); + bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions); + if (ifGood) { + preproc.InvertCurrentLevel(); + activitySet = preproc.IsInactive() ? activeFlag : 0; + if (!activitySet) + sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + } + } else if (!preproc.IsInactive()) { + preproc.InvertCurrentLevel(); + activitySet = preproc.IsInactive() ? activeFlag : 0; + if (!activitySet) + sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + } + } else if (sc.Match("endif")) { + preproc.EndSection(); + activitySet = preproc.IsInactive() ? activeFlag : 0; + sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + } else if (sc.Match("define")) { + if (options.updatePreprocessor && !preproc.IsInactive()) { + std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true); + if (restOfLine.find(")") == std::string::npos) { // Don't handle macros with arguments + std::vector tokens = Tokenize(restOfLine); + std::string key; + std::string value("1"); + if (tokens.size() >= 1) { + key = tokens[0]; + if (tokens.size() >= 2) { + value = tokens[1]; + } + preprocessorDefinitions[key] = value; + ppDefineHistory.push_back(PPDefinition(lineCurrent, key, value)); + definitionsChanged = true; + } + } + } + } + } } } else if (isoperator(static_cast(sc.ch))) { - sc.SetState(SCE_C_OPERATOR); + sc.SetState(SCE_C_OPERATOR|activitySet); } } @@ -362,38 +909,22 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo } continuationLine = false; } + const bool rawStringsChanged = rawStringTerminators.Merge(rawSTNew, lineCurrent); + if (definitionsChanged || rawStringsChanged) + styler.ChangeLexerState(startPos, startPos + length); sc.Complete(); } -static bool IsStreamCommentStyle(int style) { - return style == SCE_C_COMMENT || - style == SCE_C_COMMENTDOC || - style == SCE_C_COMMENTDOCKEYWORD || - style == SCE_C_COMMENTDOCKEYWORDERROR; -} - // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". -static void FoldCppDoc(unsigned int startPos, int length, int initStyle, - WordList *[], Accessor &styler) { - // property fold.comment - // This option enables folding multi-line comments and explicit fold points when using the C++ lexer. - // Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //} - // at the end of a section that should fold. - bool foldComment = styler.GetPropertyInt("fold.comment") != 0; +void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { - // property fold.preprocessor - // This option enables folding preprocessor directives when using the C++ lexer. - // Includes C#'s explicit #region and #endregion folding directives. - bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; + if (!options.fold) + return; - bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; - - // property fold.at.else - // This option enables C++ folding on a "} else {" line of an if statement. - bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; + LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; @@ -404,16 +935,17 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; - int styleNext = styler.StyleAt(startPos); - int style = initStyle; + int styleNext = MaskActive(styler.StyleAt(startPos)); + int style = MaskActive(initStyle); + const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; - styleNext = styler.StyleAt(i + 1); + styleNext = MaskActive(styler.StyleAt(i + 1)); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); - if (foldComment && IsStreamCommentStyle(style)) { + if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev) && (stylePrev != SCE_C_COMMENTLINEDOC)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_C_COMMENTLINEDOC) && !atEOL) { @@ -421,17 +953,25 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, levelNext--; } } - if (foldComment && (style == SCE_C_COMMENTLINE)) { - if ((ch == '/') && (chNext == '/')) { - char chNext2 = styler.SafeGetCharAt(i + 2); - if (chNext2 == '{') { + if (options.foldComment && options.foldCommentExplicit && ((style == SCE_C_COMMENTLINE) || options.foldExplicitAnywhere)) { + if (userDefinedFoldMarkers) { + if (styler.Match(i, options.foldExplicitStart.c_str())) { levelNext++; - } else if (chNext2 == '}') { + } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { levelNext--; } + } else { + if ((ch == '/') && (chNext == '/')) { + char chNext2 = styler.SafeGetCharAt(i + 2); + if (chNext2 == '{') { + levelNext++; + } else if (chNext2 == '}') { + levelNext--; + } + } } } - if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { + if (options.foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { if (ch == '#') { unsigned int j = i + 1; while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { @@ -444,7 +984,7 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, } } } - if (style == SCE_C_OPERATOR) { + if (options.foldSyntaxBased && (style == SCE_C_OPERATOR)) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" @@ -460,11 +1000,11 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, visibleChars++; if (atEOL || (i == endPos-1)) { int levelUse = levelCurrent; - if (foldAtElse) { + if (options.foldSyntaxBased && options.foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; - if (visibleChars == 0 && foldCompact) + if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; @@ -483,24 +1023,154 @@ static void FoldCppDoc(unsigned int startPos, int length, int initStyle, } } -static const char * const cppWordLists[] = { - "Primary keywords and identifiers", - "Secondary keywords and identifiers", - "Documentation comment keywords", - "Unused", - "Global classes and typedefs", - 0, - }; +void LexerCPP::EvaluateTokens(std::vector &tokens) { -static void ColouriseCppDocSensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler) { - ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, true); + // Evaluate defined() statements to either 0 or 1 + for (size_t i=0; (i+2)) + tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 4); + val = "1"; + } + tokens[i] = val; + } else { + i++; + } + } + + // Find bracketed subexpressions and recurse on them + std::vector::iterator itBracket = std::find(tokens.begin(), tokens.end(), "("); + std::vector::iterator itEndBracket = std::find(tokens.begin(), tokens.end(), ")"); + while ((itBracket != tokens.end()) && (itEndBracket != tokens.end()) && (itEndBracket > itBracket)) { + std::vector inBracket(itBracket + 1, itEndBracket); + EvaluateTokens(inBracket); + + // The insertion is done before the removal because there were failures with the opposite approach + tokens.insert(itBracket, inBracket.begin(), inBracket.end()); + itBracket = std::find(tokens.begin(), tokens.end(), "("); + itEndBracket = std::find(tokens.begin(), tokens.end(), ")"); + tokens.erase(itBracket, itEndBracket + 1); + + itBracket = std::find(tokens.begin(), tokens.end(), "("); + itEndBracket = std::find(tokens.begin(), tokens.end(), ")"); + } + + // Evaluate logical negations + for (size_t j=0; (j+1)::iterator itInsert = + tokens.erase(tokens.begin() + j, tokens.begin() + j + 2); + tokens.insert(itInsert, isTrue ? "1" : "0"); + } else { + j++; + } + } + + // Evaluate expressions in precedence order + enum precedence { precArithmetic, precRelative, precLogical }; + for (int prec=precArithmetic; prec <= precLogical; prec++) { + // Looking at 3 tokens at a time so end at 2 before end + for (size_t k=0; (k+2)") + result = valA > valB; + else if (tokens[k+1] == ">=") + result = valA >= valB; + else if (tokens[k+1] == "==") + result = valA == valB; + else if (tokens[k+1] == "!=") + result = valA != valB; + else if (tokens[k+1] == "||") + result = valA || valB; + else if (tokens[k+1] == "&&") + result = valA && valB; + char sResult[30]; + sprintf(sResult, "%d", result); + std::vector::iterator itInsert = + tokens.erase(tokens.begin() + k, tokens.begin() + k + 3); + tokens.insert(itInsert, sResult); + } else { + k++; + } + } + } } -static void ColouriseCppDocInsensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler) { - ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, false); +bool LexerCPP::EvaluateExpression(const std::string &expr, const std::map &preprocessorDefinitions) { + // Break into tokens, replacing with definitions + std::string word; + std::vector tokens; + const char *cp = expr.c_str(); + for (;;) { + if (setWord.Contains(*cp)) { + word += *cp; + } else { + std::map::const_iterator it = preprocessorDefinitions.find(word); + if (it != preprocessorDefinitions.end()) { + tokens.push_back(it->second); + } else if (!word.empty() && ((word[0] >= '0' && word[0] <= '9') || (word == "defined"))) { + tokens.push_back(word); + } + word = ""; + if (!*cp) { + break; + } + if ((*cp != ' ') && (*cp != '\t')) { + std::string op(cp, 1); + if (setRelOp.Contains(*cp)) { + if (setRelOp.Contains(cp[1])) { + op += cp[1]; + cp++; + } + } else if (setLogicalOp.Contains(*cp)) { + if (setLogicalOp.Contains(cp[1])) { + op += cp[1]; + cp++; + } + } + tokens.push_back(op); + } + } + cp++; + } + + EvaluateTokens(tokens); + + // "0" or "" -> false else true + bool isFalse = tokens.empty() || + ((tokens.size() == 1) && ((tokens[0] == "") || tokens[0] == "0")); + return !isFalse; } -LexerModule lmCPP(SCLEX_CPP, ColouriseCppDocSensitive, "cpp", FoldCppDoc, cppWordLists); -LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, ColouriseCppDocInsensitive, "cppnocase", FoldCppDoc, cppWordLists); +LexerModule lmCPP(SCLEX_CPP, LexerCPP::LexerFactoryCPP, "cpp", cppWordLists); +LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, LexerCPP::LexerFactoryCPPInsensitive, "cppnocase", cppWordLists); diff --git a/plugins/scintilla/scintilla/LexCSS.cxx b/plugins/scintilla/scintilla/LexCSS.cxx index 3b139cd..8fbca38 100644 --- a/plugins/scintilla/scintilla/LexCSS.cxx +++ b/plugins/scintilla/scintilla/LexCSS.cxx @@ -9,18 +9,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -62,6 +65,7 @@ static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, Wo int lastState = -1; // before operator int lastStateC = -1; // before comment + int lastStateS = -1; // before single-quoted/double-quoted string int op = ' '; // last operator int opPrev = ' '; // last operator @@ -105,7 +109,7 @@ static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, Wo i--; if ((sc.currentPos - i) % 2 == 1) continue; - sc.ForwardSetState(SCE_CSS_VALUE); + sc.ForwardSetState(lastStateS); } if (sc.state == SCE_CSS_OPERATOR) { @@ -140,9 +144,9 @@ static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, Wo sc.SetState(SCE_CSS_TAG); break; case '{': - if (lastState == SCE_CSS_DIRECTIVE) + if (lastState == SCE_CSS_MEDIA) sc.SetState(SCE_CSS_DEFAULT); - else if (lastState == SCE_CSS_TAG) + else if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DIRECTIVE) sc.SetState(SCE_CSS_IDENTIFIER); break; case '}': @@ -219,7 +223,8 @@ static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, Wo sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_PSEUDOELEMENT || sc.state == SCE_CSS_EXTENDED_PSEUDOCLASS || sc.state == SCE_CSS_EXTENDED_PSEUDOELEMENT || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || - sc.state == SCE_CSS_IMPORTANT + sc.state == SCE_CSS_IMPORTANT || + sc.state == SCE_CSS_DIRECTIVE )) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); @@ -263,6 +268,10 @@ static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, Wo if (strcmp(s2, "important") != 0) sc.ChangeState(SCE_CSS_VALUE); break; + case SCE_CSS_DIRECTIVE: + if (op == '@' && strcmp(s2, "media") == 0) + sc.ChangeState(SCE_CSS_MEDIA); + break; } } @@ -280,12 +289,14 @@ static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, Wo lastStateC = sc.state; sc.SetState(SCE_CSS_COMMENT); sc.Forward(); - } else if (sc.state == SCE_CSS_VALUE && (sc.ch == '\"' || sc.ch == '\'')) { + } else if ((sc.state == SCE_CSS_VALUE || sc.state == SCE_CSS_ATTRIBUTE) + && (sc.ch == '\"' || sc.ch == '\'')) { + lastStateS = sc.state; sc.SetState((sc.ch == '\"' ? SCE_CSS_DOUBLESTRING : SCE_CSS_SINGLESTRING)); } else if (IsCssOperator(sc.ch) && (sc.state != SCE_CSS_ATTRIBUTE || sc.ch == ']') && (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!') - && (sc.state != SCE_CSS_DIRECTIVE || sc.ch == ';' || sc.ch == '{') + && ((sc.state != SCE_CSS_DIRECTIVE && sc.state != SCE_CSS_MEDIA) || sc.ch == ';' || sc.ch == '{') ) { if (sc.state != SCE_CSS_OPERATOR) lastState = sc.state; diff --git a/plugins/scintilla/scintilla/LexCaml.cxx b/plugins/scintilla/scintilla/LexCaml.cxx index 0d11622..f576e3e 100644 --- a/plugins/scintilla/scintilla/LexCaml.cxx +++ b/plugins/scintilla/scintilla/LexCaml.cxx @@ -20,19 +20,22 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" #include "PropSetSimple.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" // Since the Microsoft __iscsym[f] funcs are not ANSI... inline int iscaml(int c) {return isalnum(c) || c == '_';} @@ -51,9 +54,13 @@ using namespace Scintilla; /* (actually seems to work!) */ +#include #include "WindowAccessor.h" #include "ExternalLexer.h" +#undef EXT_LEXER_DECL +#define EXT_LEXER_DECL __declspec( dllexport ) __stdcall + #if PLAT_WIN #include #endif @@ -430,13 +437,11 @@ void ColouriseCamlDoc( static #endif /* BUILD_AS_EXTERNAL_LEXER */ void FoldCamlDoc( - unsigned int startPos, int length, - int initStyle, - WordList *keywordlists[], - Accessor &styler) + unsigned int, int, + int, + WordList *[], + Accessor &) { - // below useless evaluation(s) to supress "not used" warnings - startPos || length || initStyle || keywordlists[0] || styler.Length(); } static const char * const camlWordListDesc[] = { diff --git a/plugins/scintilla/scintilla/LexCmake.cxx b/plugins/scintilla/scintilla/LexCmake.cxx index 1f51f47..70e9dee 100644 --- a/plugins/scintilla/scintilla/LexCmake.cxx +++ b/plugins/scintilla/scintilla/LexCmake.cxx @@ -5,21 +5,25 @@ // Copyright 2007 by Cristian Adam // based on the NSIS lexer // The License.txt file describes the conditions under which this software may be distributed. + #include #include -#include #include #include +#include +#include -#include "Platform.h" - -#include "CharClassify.h" -#include "PropSet.h" -#include "Accessor.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif diff --git a/plugins/scintilla/scintilla/LexConf.cxx b/plugins/scintilla/scintilla/LexConf.cxx index 969275f..5e1bd19 100644 --- a/plugins/scintilla/scintilla/LexConf.cxx +++ b/plugins/scintilla/scintilla/LexConf.cxx @@ -11,18 +11,22 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" - -#include "PropSet.h" -#include "Accessor.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -70,17 +74,17 @@ static void ColouriseConfDoc(unsigned int startPos, int length, int, WordList *k } else if( ch == '"') { state = SCE_CONF_STRING; styler.ColourTo(i,SCE_CONF_STRING); - } else if( ispunct(ch) ) { + } else if( isascii(ch) && ispunct(ch) ) { // signals an operator... // no state jump necessary for this // simple case... styler.ColourTo(i,SCE_CONF_OPERATOR); - } else if( isalpha(ch) ) { + } else if( isascii(ch) && isalpha(ch) ) { // signals the start of an identifier bufferCount = 0; buffer[bufferCount++] = static_cast(tolower(ch)); state = SCE_CONF_IDENTIFIER; - } else if( isdigit(ch) ) { + } else if( isascii(ch) && isdigit(ch) ) { // signals the start of a number bufferCount = 0; buffer[bufferCount++] = ch; @@ -107,7 +111,7 @@ static void ColouriseConfDoc(unsigned int startPos, int length, int, WordList *k // if we find a non-alphanumeric char, // we simply go to default state // else we're still dealing with an extension... - if( isalnum(ch) || (ch == '_') || + if( (isascii(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '$') || (ch == '/') || (ch == '.') || (ch == '*') ) { @@ -129,7 +133,7 @@ static void ColouriseConfDoc(unsigned int startPos, int length, int, WordList *k case SCE_CONF_IDENTIFIER: // stay in CONF_IDENTIFIER state until we find a non-alphanumeric - if( isalnum(ch) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '*')) { + if( (isascii(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '*')) { buffer[bufferCount++] = static_cast(tolower(ch)); } else { state = SCE_CONF_DEFAULT; @@ -154,7 +158,7 @@ static void ColouriseConfDoc(unsigned int startPos, int length, int, WordList *k case SCE_CONF_NUMBER: // stay in CONF_NUMBER state until we find a non-numeric - if( isdigit(ch) || ch == '.') { + if( (isascii(ch) && isdigit(ch)) || ch == '.') { buffer[bufferCount++] = ch; } else { state = SCE_CONF_DEFAULT; diff --git a/plugins/scintilla/scintilla/LexCrontab.cxx b/plugins/scintilla/scintilla/LexCrontab.cxx old mode 100755 new mode 100644 index 62044c3..08abc71 --- a/plugins/scintilla/scintilla/LexCrontab.cxx +++ b/plugins/scintilla/scintilla/LexCrontab.cxx @@ -9,18 +9,22 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" - -#include "PropSet.h" -#include "Accessor.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -94,12 +98,12 @@ static void ColouriseNncrontabDoc(unsigned int startPos, int length, int, WordLi // signals an asterisk // no state jump necessary for this simple case... styler.ColourTo(i,SCE_NNCRONTAB_ASTERISK); - } else if( isalpha(ch) || ch == '<' ) { + } else if( (isascii(ch) && isalpha(ch)) || ch == '<' ) { // signals the start of an identifier bufferCount = 0; buffer[bufferCount++] = ch; state = SCE_NNCRONTAB_IDENTIFIER; - } else if( isdigit(ch) ) { + } else if( isascii(ch) && isdigit(ch) ) { // signals the start of a number bufferCount = 0; buffer[bufferCount++] = ch; @@ -167,7 +171,7 @@ static void ColouriseNncrontabDoc(unsigned int startPos, int length, int, WordLi case SCE_NNCRONTAB_IDENTIFIER: // stay in CONF_IDENTIFIER state until we find a non-alphanumeric - if( isalnum(ch) || (ch == '_') || (ch == '-') || (ch == '/') || + if( (isascii(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '<') || (ch == '>') || (ch == '@') ) { buffer[bufferCount++] = ch; @@ -196,7 +200,7 @@ static void ColouriseNncrontabDoc(unsigned int startPos, int length, int, WordLi case SCE_NNCRONTAB_NUMBER: // stay in CONF_NUMBER state until we find a non-numeric - if( isdigit(ch) /* || ch == '.' */ ) { + if( isascii(ch) && isdigit(ch) /* || ch == '.' */ ) { buffer[bufferCount++] = ch; } else { state = SCE_NNCRONTAB_DEFAULT; diff --git a/plugins/scintilla/scintilla/LexCsound.cxx b/plugins/scintilla/scintilla/LexCsound.cxx index 4162c9b..8e5880c 100644 --- a/plugins/scintilla/scintilla/LexCsound.cxx +++ b/plugins/scintilla/scintilla/LexCsound.cxx @@ -8,18 +8,22 @@ #include #include -#include #include #include -#include "Platform.h" +#include +#include -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -35,7 +39,7 @@ static inline bool IsAWordStart(const int ch) { } static inline bool IsCsoundOperator(char ch) { - if (isalnum(ch)) + if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || @@ -72,7 +76,7 @@ static void ColouriseCsoundDoc(unsigned int startPos, int length, int initStyle, continue; } } - + // Determine if the current state should terminate. if (sc.state == SCE_CSOUND_OPERATOR) { if (!IsCsoundOperator(static_cast(sc.ch))) { @@ -119,7 +123,7 @@ static void ColouriseCsoundDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_CSOUND_DEFAULT); } } - + // Determine if a new state should be entered. if (sc.state == SCE_CSOUND_DEFAULT) { if (sc.ch == ';'){ @@ -146,7 +150,7 @@ static void ColouriseCsoundDoc(unsigned int startPos, int length, int initStyle, sc.Complete(); } -static void FoldCsoundInstruments(unsigned int startPos, int length, int /* initStyle */, WordList *[], +static void FoldCsoundInstruments(unsigned int startPos, int length, int /* initStyle */, WordList *[], Accessor &styler) { unsigned int lengthDoc = startPos + length; int visibleChars = 0; diff --git a/plugins/scintilla/scintilla/LexD.cxx b/plugins/scintilla/scintilla/LexD.cxx index 4c4bcb3..5b8f9e7 100644 --- a/plugins/scintilla/scintilla/LexD.cxx +++ b/plugins/scintilla/scintilla/LexD.cxx @@ -2,25 +2,36 @@ ** Lexer for D. ** ** Copyright (c) 2006 by Waldemar Augustyn + ** Converted to lexer object and added further folding features/properties by "Udo Lechner" **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include -#include #include #include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif -#include "Platform.h" +#include +#include -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" +#include "OptionSet.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -55,17 +66,187 @@ static bool IsStringSuffix(int ch) { return ch == 'c' || ch == 'w' || ch == 'd'; } +static bool IsStreamCommentStyle(int style) { + return style == SCE_D_COMMENT || + style == SCE_D_COMMENTDOC || + style == SCE_D_COMMENTDOCKEYWORD || + style == SCE_D_COMMENTDOCKEYWORDERROR; +} -static void ColouriseDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler, bool caseSensitive) { +// An individual named option for use in an OptionSet - WordList &keywords = *keywordlists[0]; - WordList &keywords2 = *keywordlists[1]; - WordList &keywords3 = *keywordlists[2]; //doxygen - WordList &keywords4 = *keywordlists[3]; - WordList &keywords5 = *keywordlists[4]; - WordList &keywords6 = *keywordlists[5]; - WordList &keywords7 = *keywordlists[6]; +// Options used for LexerD +struct OptionsD { + bool fold; + bool foldSyntaxBased; + bool foldComment; + bool foldCommentMultiline; + bool foldCommentExplicit; + std::string foldExplicitStart; + std::string foldExplicitEnd; + bool foldExplicitAnywhere; + bool foldCompact; + int foldAtElseInt; + bool foldAtElse; + OptionsD() { + fold = false; + foldSyntaxBased = true; + foldComment = false; + foldCommentMultiline = true; + foldCommentExplicit = true; + foldExplicitStart = ""; + foldExplicitEnd = ""; + foldExplicitAnywhere = false; + foldCompact = true; + foldAtElseInt = -1; + foldAtElse = false; + } +}; + +static const char * const dWordLists[] = { + "Primary keywords and identifiers", + "Secondary keywords and identifiers", + "Documentation comment keywords", + "Type definitions and aliases", + "Keywords 5", + "Keywords 6", + "Keywords 7", + 0, + }; + +struct OptionSetD : public OptionSet { + OptionSetD() { + DefineProperty("fold", &OptionsD::fold); + + DefineProperty("fold.d.syntax.based", &OptionsD::foldSyntaxBased, + "Set this property to 0 to disable syntax based folding."); + + DefineProperty("fold.comment", &OptionsD::foldComment); + + DefineProperty("fold.d.comment.multiline", &OptionsD::foldCommentMultiline, + "Set this property to 0 to disable folding multi-line comments when fold.comment=1."); + + DefineProperty("fold.d.comment.explicit", &OptionsD::foldCommentExplicit, + "Set this property to 0 to disable folding explicit fold points when fold.comment=1."); + + DefineProperty("fold.d.explicit.start", &OptionsD::foldExplicitStart, + "The string to use for explicit fold start points, replacing the standard //{."); + + DefineProperty("fold.d.explicit.end", &OptionsD::foldExplicitEnd, + "The string to use for explicit fold end points, replacing the standard //}."); + + DefineProperty("fold.d.explicit.anywhere", &OptionsD::foldExplicitAnywhere, + "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); + + DefineProperty("fold.compact", &OptionsD::foldCompact); + + DefineProperty("lexer.d.fold.at.else", &OptionsD::foldAtElseInt, + "This option enables D folding on a \"} else {\" line of an if statement."); + + DefineProperty("fold.at.else", &OptionsD::foldAtElse); + + DefineWordListSets(dWordLists); + } +}; + +class LexerD : public ILexer { + bool caseSensitive; + WordList keywords; + WordList keywords2; + WordList keywords3; + WordList keywords4; + WordList keywords5; + WordList keywords6; + WordList keywords7; + OptionsD options; + OptionSetD osD; +public: + LexerD(bool caseSensitive_) : + caseSensitive(caseSensitive_) { + } + ~LexerD() { + } + void SCI_METHOD Release() { + delete this; + } + int SCI_METHOD Version() const { + return lvOriginal; + } + const char * SCI_METHOD PropertyNames() { + return osD.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) { + return osD.PropertyType(name); + } + const char * SCI_METHOD DescribeProperty(const char *name) { + return osD.DescribeProperty(name); + } + int SCI_METHOD PropertySet(const char *key, const char *val); + const char * SCI_METHOD DescribeWordListSets() { + return osD.DescribeWordListSets(); + } + int SCI_METHOD WordListSet(int n, const char *wl); + void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); + + void * SCI_METHOD PrivateCall(int, void *) { + return 0; + } + + static ILexer *LexerFactoryD() { + return new LexerD(true); + } + static ILexer *LexerFactoryDInsensitive() { + return new LexerD(false); + } +}; + +int SCI_METHOD LexerD::PropertySet(const char *key, const char *val) { + if (osD.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +int SCI_METHOD LexerD::WordListSet(int n, const char *wl) { + WordList *wordListN = 0; + switch (n) { + case 0: + wordListN = &keywords; + break; + case 1: + wordListN = &keywords2; + break; + case 2: + wordListN = &keywords3; + break; + case 3: + wordListN = &keywords4; + break; + case 4: + wordListN = &keywords5; + break; + case 5: + wordListN = &keywords6; + break; + case 6: + wordListN = &keywords7; + break; + } + int firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +void SCI_METHOD LexerD::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + LexAccessor styler(pAccess); int styleBeforeDCKeyword = SCE_D_DEFAULT; @@ -290,24 +471,17 @@ static void ColouriseDoc(unsigned int startPos, int length, int initStyle, sc.Complete(); } -static bool IsStreamCommentStyle(int style) { - return style == SCE_D_COMMENT || - style == SCE_D_COMMENTDOC || - style == SCE_D_COMMENTDOCKEYWORD || - style == SCE_D_COMMENTDOCKEYWORDERROR; -} - // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". -static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor &styler) { - bool foldComment = styler.GetPropertyInt("fold.comment") != 0; - bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; - - // property lexer.d.fold.at.else - // This option enables D folding on a "} else {" line of an if statement. - bool foldAtElse = styler.GetPropertyInt("lexer.d.fold.at.else", - styler.GetPropertyInt("fold.at.else", 0)) != 0; + +void SCI_METHOD LexerD::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + + if (!options.fold) + return; + + LexAccessor styler(pAccess); + unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); @@ -319,6 +493,8 @@ static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor & char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; + bool foldAtElse = options.foldAtElseInt >= 0 ? options.foldAtElseInt != 0 : options.foldAtElse; + const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); @@ -326,7 +502,7 @@ static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor & style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); - if (foldComment && IsStreamCommentStyle(style)) { + if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { @@ -334,7 +510,25 @@ static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor & levelNext--; } } - if (style == SCE_D_OPERATOR) { + if (options.foldComment && options.foldCommentExplicit && ((style == SCE_D_COMMENTLINE) || options.foldExplicitAnywhere)) { + if (userDefinedFoldMarkers) { + if (styler.Match(i, options.foldExplicitStart.c_str())) { + levelNext++; + } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { + levelNext--; + } + } else { + if ((ch == '/') && (chNext == '/')) { + char chNext2 = styler.SafeGetCharAt(i + 2); + if (chNext2 == '{') { + levelNext++; + } else if (chNext2 == '}') { + levelNext--; + } + } + } + } + if (options.foldSyntaxBased && (style == SCE_D_OPERATOR)) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" @@ -346,19 +540,19 @@ static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor & levelNext--; } } - if (atEOL) { - if (foldComment) { // Handle nested comments + if (atEOL || (i == endPos-1)) { + if (options.foldComment && options.foldCommentMultiline) { // Handle nested comments int nc; nc = styler.GetLineState(lineCurrent); nc -= lineCurrent>0? styler.GetLineState(lineCurrent-1): 0; levelNext += nc; } int levelUse = levelCurrent; - if (foldAtElse) { + if (options.foldSyntaxBased && foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; - if (visibleChars == 0 && foldCompact) + if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; @@ -375,25 +569,4 @@ static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor & } } -static void FoldDDoc(unsigned int startPos, int length, int initStyle, - WordList *[], Accessor &styler) { - FoldDoc(startPos, length, initStyle, styler); -} - -static const char * const dWordLists[] = { - "Primary keywords and identifiers", - "Secondary keywords and identifiers", - "Documentation comment keywords", - "Type definitions and aliases", - "Keywords 5", - "Keywords 6", - "Keywords 7", - 0, - }; - -static void ColouriseDDoc(unsigned int startPos, int length, - int initStyle, WordList *keywordlists[], Accessor &styler) { - ColouriseDoc(startPos, length, initStyle, keywordlists, styler, true); -} - -LexerModule lmD(SCLEX_D, ColouriseDDoc, "d", FoldDDoc, dWordLists); +LexerModule lmD(SCLEX_D, LexerD::LexerFactoryD, "d", dWordLists); diff --git a/plugins/scintilla/scintilla/LexEScript.cxx b/plugins/scintilla/scintilla/LexEScript.cxx index 295aaec..9a7560e 100644 --- a/plugins/scintilla/scintilla/LexEScript.cxx +++ b/plugins/scintilla/scintilla/LexEScript.cxx @@ -9,15 +9,18 @@ #include #include #include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -198,7 +201,7 @@ static void FoldESCRIPTDoc(unsigned int startPos, int length, int initStyle, Wor styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); - + if (foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelCurrent++; diff --git a/plugins/scintilla/scintilla/LexEiffel.cxx b/plugins/scintilla/scintilla/LexEiffel.cxx old mode 100755 new mode 100644 index 03dea5e..067801c --- a/plugins/scintilla/scintilla/LexEiffel.cxx +++ b/plugins/scintilla/scintilla/LexEiffel.cxx @@ -7,18 +7,21 @@ #include #include -#include -#include #include +#include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; diff --git a/plugins/scintilla/scintilla/LexErlang.cxx b/plugins/scintilla/scintilla/LexErlang.cxx index 45577bd..5f52258 100644 --- a/plugins/scintilla/scintilla/LexErlang.cxx +++ b/plugins/scintilla/scintilla/LexErlang.cxx @@ -4,24 +4,28 @@ /** @file LexErlang.cxx ** Lexer for Erlang. ** Enhanced by Etienne 'Lenain' Girondel (lenaing@gmail.com) - ** Originally wrote by Peter-Henry Mander, + ** Originally wrote by Peter-Henry Mander, ** based on Matlab lexer by José Fonseca. **/ #include #include -#include #include #include +#include +#include -#include "Platform.h" -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -152,7 +156,7 @@ static void ColouriseErlangDoc(unsigned int startPos, int length, int initStyle, // Try to match documentation comment sc.GetCurrent(cur, sizeof(cur)); - if (parse_state == COMMENT_DOC_MACRO + if (parse_state == COMMENT_DOC_MACRO && erlangDocMacro.InList(cur)) { sc.ChangeState(SCE_ERLANG_COMMENT_DOC_MACRO); while (sc.ch != '}' && !sc.atLineEnd) @@ -340,7 +344,7 @@ static void ColouriseErlangDoc(unsigned int startPos, int length, int initStyle, case NUMERAL_BASE_VALUE : { if (!is_radix(radix_digits,sc.ch)) { radix_digits = 0; - + if (!isalnum(sc.ch)) sc.ChangeState(SCE_ERLANG_NUMBER); @@ -380,7 +384,7 @@ static void ColouriseErlangDoc(unsigned int startPos, int length, int initStyle, /* Preprocessor --------------------------------------------------*/ case PREPROCESSOR : { if (!IsAWordChar(sc.ch)) { - + sc.GetCurrent(cur, sizeof(cur)); if (erlangPreproc.InList(cur)) { style = SCE_ERLANG_PREPROC; @@ -421,7 +425,7 @@ static void ColouriseErlangDoc(unsigned int startPos, int length, int initStyle, } break; case SCE_ERLANG_OPERATOR : { if (sc.chPrev == '.') { - if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' + if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') { sc.ForwardSetState(SCE_ERLANG_DEFAULT); } else if (sc.ch == '\'') { diff --git a/plugins/scintilla/scintilla/LexFlagship.cxx b/plugins/scintilla/scintilla/LexFlagship.cxx index baf2941..b8568b0 100644 --- a/plugins/scintilla/scintilla/LexFlagship.cxx +++ b/plugins/scintilla/scintilla/LexFlagship.cxx @@ -1,169 +1,299 @@ // Scintilla source code edit control /** @file LexFlagShip.cxx - ** Lexer for FlagShip - ** (Syntactically compatible to other XBase dialects, like dBase, Clipper, Fox etc.) + ** Lexer for Harbour and FlagShip. + ** (Syntactically compatible to other xBase dialects, like Clipper, dBase, Clip, FoxPro etc.) **/ // Copyright 2005 by Randy Butler +// Copyright 2010 by Xavi (Harbour) // Copyright 1998-2003 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 "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif -static bool IsFlagShipComment(Accessor &styler, int pos, int len) { - return len>0 && styler[pos]=='\''; -} - -static inline bool IsTypeCharacter(int ch) { - return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$'; -} - // Extended to accept accented characters -static inline bool IsAWordChar(int ch) { +static inline bool IsAWordChar(int ch) +{ return ch >= 0x80 || - (isalnum(ch) || ch == '.' || ch == '_'); -} - -static inline bool IsAWordStart(int ch) { - return ch >= 0x80 || - (isalnum(ch) || ch == '_'); -} - -static inline bool IsADateCharacter(const int ch) { - return (ch < 0x80) && - (isalnum(ch) || ch == '|' || ch == '-' || ch == '/' || ch == ':' || ch == ' ' || ch == '\t'); + (isalnum(ch) || ch == '_'); } - static void ColouriseFlagShipDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler) { + WordList *keywordlists[], Accessor &styler) +{ - //bool FSScriptSyntax = true; WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; + WordList &keywords5 = *keywordlists[4]; + + // property lexer.flagship.styling.within.preprocessor + // For Harbour code, determines whether all preprocessor code is styled in the preprocessor style (0) or only from the + // initial # to the end of the command word(1, the default). It also determines how to present text, dump, and disabled code. + bool stylingWithinPreprocessor = styler.GetPropertyInt("lexer.flagship.styling.within.preprocessor", 1) != 0; - styler.StartAt(startPos); + CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); int visibleChars = 0; + int closeStringChar = 0; + int styleBeforeDCKeyword = SCE_FS_DEFAULT; + bool bEnableCode = initStyle < SCE_FS_DISABLEDCODE; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { - if (sc.state == SCE_FS_OPERATOR) { - sc.SetState(SCE_FS_DEFAULT); - } else if (sc.state == SCE_FS_IDENTIFIER) { - if (!IsAWordChar(sc.ch)) { - char s[100]; - sc.GetCurrentLowered(s, sizeof(s)); - if (keywords.InList(s)) { - sc.ChangeState(SCE_FS_KEYWORD); - } else if (keywords2.InList(s)) { - sc.ChangeState(SCE_FS_KEYWORD2); - } else if (keywords3.InList(s)) { - sc.ChangeState(SCE_FS_KEYWORD3); - } else if (keywords4.InList(s)) { - sc.ChangeState(SCE_FS_KEYWORD4); - }// Else, it is really an identifier... - sc.SetState(SCE_FS_DEFAULT); - } - } else if (sc.state == SCE_FS_NUMBER) { - if (!IsAWordChar(sc.ch)) { - sc.SetState(SCE_FS_DEFAULT); - } - } else if (sc.state == SCE_FS_STRING) { - // VB doubles quotes to preserve them, so just end this string - // state now as a following quote will start again - if (sc.ch == '\"') { - if (tolower(sc.chNext) == 'c') { + // Determine if the current state should terminate. + switch (sc.state) { + case SCE_FS_OPERATOR: + case SCE_FS_OPERATOR_C: + case SCE_FS_WORDOPERATOR: + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + break; + case SCE_FS_IDENTIFIER: + case SCE_FS_IDENTIFIER_C: + if (!IsAWordChar(sc.ch)) { + char s[64]; + sc.GetCurrentLowered(s, sizeof(s)); + if (keywords.InList(s)) { + sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD : SCE_FS_KEYWORD_C); + } else if (keywords2.InList(s)) { + sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD2 : SCE_FS_KEYWORD2_C); + } else if (bEnableCode && keywords3.InList(s)) { + sc.ChangeState(SCE_FS_KEYWORD3); + } else if (bEnableCode && keywords4.InList(s)) { + sc.ChangeState(SCE_FS_KEYWORD4); + }// Else, it is really an identifier... + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_NUMBER: + if (!IsAWordChar(sc.ch) && !(sc.ch == '.' && IsADigit(sc.chNext))) { + sc.SetState(SCE_FS_DEFAULT); + } + break; + case SCE_FS_NUMBER_C: + if (!IsAWordChar(sc.ch) && sc.ch != '.') { + sc.SetState(SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_CONSTANT: + if (!IsAWordChar(sc.ch)) { + sc.SetState(SCE_FS_DEFAULT); + } + break; + case SCE_FS_STRING: + case SCE_FS_STRING_C: + if (sc.ch == closeStringChar) { + sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.atLineEnd) { + sc.ChangeState(bEnableCode ? SCE_FS_STRINGEOL : SCE_FS_STRINGEOL_C); + } + break; + case SCE_FS_STRINGEOL: + case SCE_FS_STRINGEOL_C: + if (sc.atLineStart) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_COMMENTDOC: + case SCE_FS_COMMENTDOC_C: + if (sc.Match('*', '/')) { sc.Forward(); + sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support + // Verify that we have the conditions to mark a comment-doc-keyword + if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { + styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C; + sc.SetState(SCE_FS_COMMENTDOCKEYWORD); + } + } + break; + case SCE_FS_COMMENT: + case SCE_FS_COMMENTLINE: + if (sc.atLineStart) { + sc.SetState(SCE_FS_DEFAULT); + } + break; + case SCE_FS_COMMENTLINEDOC: + case SCE_FS_COMMENTLINEDOC_C: + if (sc.atLineStart) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support + // Verify that we have the conditions to mark a comment-doc-keyword + if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { + styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C; + sc.SetState(SCE_FS_COMMENTDOCKEYWORD); + } + } + break; + case SCE_FS_COMMENTDOCKEYWORD: + if ((styleBeforeDCKeyword == SCE_FS_COMMENTDOC || styleBeforeDCKeyword == SCE_FS_COMMENTDOC_C) && + sc.Match('*', '/')) { + sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR); + sc.Forward(); + sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (!setDoxygen.Contains(sc.ch)) { + char s[64]; + sc.GetCurrentLowered(s, sizeof(s)); + if (!IsASpace(sc.ch) || !keywords5.InList(s + 1)) { + sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR); + } + sc.SetState(styleBeforeDCKeyword); + } + break; + case SCE_FS_PREPROCESSOR: + case SCE_FS_PREPROCESSOR_C: + if (sc.atLineEnd) { + if (!(sc.chPrev == ';' || sc.GetRelative(-2) == ';')) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + } else if (stylingWithinPreprocessor) { + if (IsASpaceOrTab(sc.ch)) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + } else if (sc.Match('/', '*') || sc.Match('/', '/') || sc.Match('&', '&')) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_DISABLEDCODE: + if (sc.ch == '#' && visibleChars == 0) { + sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C); + do { // Skip whitespace between # and preprocessor word + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.MatchIgnoreCase("pragma")) { + sc.Forward(6); + do { // Skip more whitespace until keyword + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) { + bEnableCode = true; + sc.SetState(SCE_FS_DISABLEDCODE); + sc.Forward(sc.ch == '_' ? 8 : 6); + sc.ForwardSetState(SCE_FS_DEFAULT); + } else { + sc.ChangeState(SCE_FS_DISABLEDCODE); + } + } else { + sc.ChangeState(SCE_FS_DISABLEDCODE); + } + } + break; + case SCE_FS_DATE: + if (sc.ch == '}') { + sc.ForwardSetState(SCE_FS_DEFAULT); + } else if (sc.atLineEnd) { + sc.ChangeState(SCE_FS_STRINGEOL); } - sc.ForwardSetState(SCE_FS_DEFAULT); - } else if (sc.atLineEnd) { - sc.ChangeState(SCE_FS_STRINGEOL); - sc.ForwardSetState(SCE_FS_DEFAULT); - } - } else if (sc.state == SCE_FS_COMMENT) { - if (sc.Match('*', '/')) { // new code - sc.Forward(); - sc.ForwardSetState(SCE_FS_DEFAULT); - //if (sc.atLineEnd) { // old code - // sc.SetState(SCE_FS_DEFAULT); - } - } else if (sc.state == SCE_FS_COMMENTLINE) { //new code - if (sc.ch == '\r' || sc.ch == '\n') { - sc.SetState(SCE_FS_DEFAULT); - visibleChars = 0; - } - } else if (sc.state == SCE_FS_PREPROCESSOR) { - if (sc.atLineEnd) { - sc.SetState(SCE_FS_DEFAULT); - } - } else if (sc.state == SCE_FS_DATE) { - if (sc.ch == '#' || !IsADateCharacter(sc.chNext)) { - sc.ForwardSetState(SCE_FS_DEFAULT); - } } // Determine if a new state should be entered. - if (sc.state == SCE_FS_DEFAULT) { - if (sc.Match('/', '*')) { // New code - sc.SetState(SCE_FS_COMMENT); - sc.Forward(); // Eat the * so it isn't used for the end of the comment - //if (sc.ch == '\'') { // Old code - // sc.SetState(SCE_FS_COMMENT); // old code - } else if (sc.Match('/', '/')) { // New code + if (sc.state == SCE_FS_DEFAULT || sc.state == SCE_FS_DEFAULT_C) { + if (bEnableCode && + (sc.MatchIgnoreCase(".and.") || sc.MatchIgnoreCase(".not."))) { + sc.SetState(SCE_FS_WORDOPERATOR); + sc.Forward(4); + } else if (bEnableCode && sc.MatchIgnoreCase(".or.")) { + sc.SetState(SCE_FS_WORDOPERATOR); + sc.Forward(3); + } else if (bEnableCode && + (sc.MatchIgnoreCase(".t.") || sc.MatchIgnoreCase(".f.") || + (!IsAWordChar(sc.GetRelative(3)) && sc.MatchIgnoreCase("nil")))) { + sc.SetState(SCE_FS_CONSTANT); + sc.Forward(2); + } else if (sc.Match('/', '*')) { + sc.SetState(bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C); + sc.Forward(); + } else if (bEnableCode && sc.Match('&', '&')) { sc.SetState(SCE_FS_COMMENTLINE); - } else if (sc.ch == '\"') { - sc.SetState(SCE_FS_STRING); + sc.Forward(); + } else if (sc.Match('/', '/')) { + sc.SetState(bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C); + sc.Forward(); + } else if (bEnableCode && sc.ch == '*' && visibleChars == 0) { + sc.SetState(SCE_FS_COMMENT); + } else if (sc.ch == '\"' || sc.ch == '\'') { + sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C); + closeStringChar = sc.ch; + } else if (closeStringChar == '>' && sc.ch == '<') { + sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C); } else if (sc.ch == '#' && visibleChars == 0) { - // Preprocessor commands are alone on their line - sc.SetState(SCE_FS_PREPROCESSOR); - } else if (sc.ch == '#') { - int n = 1; - int chSeek = ' '; - while ((n < 100) && (chSeek == ' ' || chSeek == '\t')) { - chSeek = sc.GetRelative(n); - n++; - } - if (IsADigit(chSeek)) { + sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C); + do { // Skip whitespace between # and preprocessor word + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.atLineEnd) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.MatchIgnoreCase("include")) { + if (stylingWithinPreprocessor) { + closeStringChar = '>'; + } + } else if (sc.MatchIgnoreCase("pragma")) { + sc.Forward(6); + do { // Skip more whitespace until keyword + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.MatchIgnoreCase("begindump") || sc.MatchIgnoreCase("__cstream")) { + bEnableCode = false; + if (stylingWithinPreprocessor) { + sc.SetState(SCE_FS_DISABLEDCODE); + sc.Forward(8); + sc.ForwardSetState(SCE_FS_DEFAULT_C); + } else { + sc.SetState(SCE_FS_DISABLEDCODE); + } + } else if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) { + bEnableCode = true; + sc.SetState(SCE_FS_DISABLEDCODE); + sc.Forward(sc.ch == '_' ? 8 : 6); + sc.ForwardSetState(SCE_FS_DEFAULT); + } + } + } else if (bEnableCode && sc.ch == '{') { + int p = 0; + int chSeek; + unsigned int endPos(startPos + length); + do { // Skip whitespace + chSeek = sc.GetRelative(++p); + } while (IsASpaceOrTab(chSeek) && (sc.currentPos + p < endPos)); + if (chSeek == '^') { sc.SetState(SCE_FS_DATE); } else { sc.SetState(SCE_FS_OPERATOR); } - } else if (sc.ch == '&' && tolower(sc.chNext) == 'h') { - sc.SetState(SCE_FS_NUMBER); - } else if (sc.ch == '&' && tolower(sc.chNext) == 'o') { - sc.SetState(SCE_FS_NUMBER); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { - sc.SetState(SCE_FS_NUMBER); - } else if (IsAWordStart(sc.ch) || (sc.ch == '[')) { - sc.SetState(SCE_FS_IDENTIFIER); - } else if (isoperator(static_cast(sc.ch)) || (sc.ch == '\\')) { - sc.SetState(SCE_FS_OPERATOR); + sc.SetState(bEnableCode ? SCE_FS_NUMBER : SCE_FS_NUMBER_C); + } else if (IsAWordChar(sc.ch)) { + sc.SetState(bEnableCode ? SCE_FS_IDENTIFIER : SCE_FS_IDENTIFIER_C); + } else if (isoperator(static_cast(sc.ch)) || (bEnableCode && sc.ch == '@')) { + sc.SetState(bEnableCode ? SCE_FS_OPERATOR : SCE_FS_OPERATOR_C); } } if (sc.atLineEnd) { visibleChars = 0; + closeStringChar = 0; } if (!IsASpace(sc.ch)) { visibleChars++; @@ -173,36 +303,33 @@ static void ColouriseFlagShipDoc(unsigned int startPos, int length, int initStyl } static void FoldFlagShipDoc(unsigned int startPos, int length, int, - WordList *[], Accessor &styler) { + WordList *[], Accessor &styler) +{ int endPos = startPos + length; // Backtrack to previous line in case need to fix its fold status int lineCurrent = styler.GetLine(startPos); - if (startPos > 0) { - if (lineCurrent > 0) { + if (startPos > 0 && lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); - } } int spaceFlags = 0; - int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsFlagShipComment); + int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags); char chNext = styler[startPos]; for (int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); - if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) { + if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos-1)) { int lev = indentCurrent; - int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsFlagShipComment); + int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags); if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { - // Only non whitespace lines can be headers if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { - // Line after is blank so check the next - maybe should continue further? int spaceFlags2 = 0; - int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsFlagShipComment); + int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2); if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } @@ -215,16 +342,13 @@ static void FoldFlagShipDoc(unsigned int startPos, int length, int, } } - static const char * const FSWordListDesc[] = { - "Keywords", - "functions", - "user2", - "user3", + "Keywords Commands", + "Std Library Functions", + "Procedure, return, exit", + "Class (oop)", + "Doxygen keywords", 0 }; LexerModule lmFlagShip(SCLEX_FLAGSHIP, ColouriseFlagShipDoc, "flagship", FoldFlagShipDoc, FSWordListDesc); - - - diff --git a/plugins/scintilla/scintilla/LexForth.cxx b/plugins/scintilla/scintilla/LexForth.cxx index e52543f..0e9875c 100644 --- a/plugins/scintilla/scintilla/LexForth.cxx +++ b/plugins/scintilla/scintilla/LexForth.cxx @@ -7,18 +7,21 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -130,7 +133,7 @@ static void ColouriseForthDoc(unsigned int startPos, int length, int initStyle, sc.SetState(SCE_FORTH_NUMBER); while(sc.More() && isascii(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1')) sc.Forward(); - } else if ( isascii(sc.ch) && + } else if ( isascii(sc.ch) && (isxdigit(sc.ch) || ((sc.ch == '.' || sc.ch == '-') && isascii(sc.chNext) && isxdigit(sc.chNext)) ) ){ sc.SetState(SCE_FORTH_NUMBER); @@ -173,4 +176,4 @@ static const char * const forthWordLists[] = { LexerModule lmForth(SCLEX_FORTH, ColouriseForthDoc, "forth", FoldForthDoc, forthWordLists); - + diff --git a/plugins/scintilla/scintilla/LexFortran.cxx b/plugins/scintilla/scintilla/LexFortran.cxx index 0b3f277..6c61c54 100644 --- a/plugins/scintilla/scintilla/LexFortran.cxx +++ b/plugins/scintilla/scintilla/LexFortran.cxx @@ -8,18 +8,23 @@ /***************************************/ #include #include -#include #include #include +#include +#include /***************************************/ -#include "Platform.h" -#include "PropSet.h" -#include "Accessor.h" -#include "StyleContext.h" -#include "KeyWords.h" +#include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" +/***************************************/ + #ifdef SCI_NAMESPACE using namespace Scintilla; #endif @@ -261,7 +266,7 @@ static int classifyFoldPointFortran(const char* s, const char* prevWord, const c || strcmp(s, "endmodule") == 0 || strcmp(s, "endprogram") == 0 || strcmp(s, "endsubroutine") == 0 || strcmp(s, "endtype") == 0 || strcmp(s, "endwhere") == 0 - || strcmp(s, "procedure") == 0 ) { // Take care of the module procedure statement + || (strcmp(s, "procedure") == 0 && strcmp(prevWord,"module")==0) ) { // Take care of the module procedure statement lev = -1; } else if (strcmp(prevWord, "end") == 0 && strcmp(s, "if") == 0){ // end if lev = 0; diff --git a/plugins/scintilla/scintilla/LexGAP.cxx b/plugins/scintilla/scintilla/LexGAP.cxx index 25bd33b..fb30660 100644 --- a/plugins/scintilla/scintilla/LexGAP.cxx +++ b/plugins/scintilla/scintilla/LexGAP.cxx @@ -8,25 +8,28 @@ #include #include -#include #include #include +#include +#include -#include "Platform.h" +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" -#include "PropSet.h" +#include "WordList.h" +#include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" -#include "KeyWords.h" -#include "Scintilla.h" -#include "SciLexer.h" +#include "CharacterSet.h" +#include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsGAPOperator(char ch) { - if (isalnum(ch)) return false; + if (isascii(ch) && isalnum(ch)) return false; if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == ',' || ch == '!' || ch == '.' || ch == '=' || ch == '<' || ch == '>' || ch == '(' || diff --git a/plugins/scintilla/scintilla/LexGen.py b/plugins/scintilla/scintilla/LexGen.py new file mode 100755 index 0000000..22cdaae --- /dev/null +++ b/plugins/scintilla/scintilla/LexGen.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python +# LexGen.py - implemented 2002 by Neil Hodgson neilh@scintilla.org +# Released to the public domain. + +# Regenerate the Scintilla and SciTE source files that list +# all the lexers and all the properties files. +# Should be run whenever a new lexer is added or removed. +# Requires Python 2.4 or later +# Most files are regenerated in place with templates stored in comments. +# The VS .NET project file is generated into a different file as the +# VS .NET environment will not retain comments when modifying the file. +# The files are copied to a string apart from sections between a +# ++Autogenerated comment and a --Autogenerated comment which is +# generated by the CopyWithInsertion function. After the whole +# string is instantiated, it is compared with the target file and +# if different the file is rewritten. +# Does not regenerate the Visual C++ 6 project files but does the VS .NET +# project file. + +import string +import sys +import os +import glob + +# EOL constants +CR = "\r" +LF = "\n" +CRLF = "\r\n" +if sys.platform == "win32": + NATIVE = CRLF +else: + # Yes, LF is the native EOL even on Mac OS X. CR is just for + # Mac OS <=9 (a.k.a. "Mac Classic") + NATIVE = LF + +# Automatically generated sections contain start and end comments, +# a definition line and the results. +# The results are replaced by regenerating based on the definition line. +# The definition line is a comment prefix followed by "**". +# If there is a digit after the ** then this indicates which list to use +# and the digit and next character are not part of the definition +# Backslash is used as an escape within the definition line. +# The part between \( and \) is repeated for each item in the list. +# \* is replaced by each list item. \t, and \n are tab and newline. +def CopyWithInsertion(input, commentPrefix, retainDefs, eolType, *lists): + copying = 1 + listid = 0 + output = [] + for line in input.splitlines(0): + isStartGenerated = line.startswith(commentPrefix + "++Autogenerated") + if copying and not isStartGenerated: + output.append(line) + if isStartGenerated: + if retainDefs: + output.append(line) + copying = 0 + definition = "" + elif not copying and line.startswith(commentPrefix + "**"): + if retainDefs: + output.append(line) + definition = line[len(commentPrefix + "**"):] + if (commentPrefix == "" in definition): + definition = definition.replace(" -->", "") + listid = 0 + if definition[0] in string.digits: + listid = int(definition[:1]) + definition = definition[2:] + # Hide double slashes as a control character + definition = definition.replace("\\\\", "\001") + # Do some normal C style transforms + definition = definition.replace("\\n", "\n") + definition = definition.replace("\\t", "\t") + # Get the doubled backslashes back as single backslashes + definition = definition.replace("\001", "\\") + startRepeat = definition.find("\\(") + endRepeat = definition.find("\\)") + intro = definition[:startRepeat] + out = "" + if intro.endswith("\n"): + pos = 0 + else: + pos = len(intro) + out += intro + middle = definition[startRepeat+2:endRepeat] + for i in lists[listid]: + item = middle.replace("\\*", i) + if pos and (pos + len(item) >= 80): + out += "\\\n" + pos = 0 + out += item + pos += len(item) + if item.endswith("\n"): + pos = 0 + outro = definition[endRepeat+2:] + out += outro + out = out.replace("\n", eolType) # correct EOLs in generated content + output.append(out) + elif line.startswith(commentPrefix + "--Autogenerated"): + copying = 1 + if retainDefs: + output.append(line) + output = [line.rstrip(" \t") for line in output] # trim trailing whitespace + return eolType.join(output) + eolType + +def UpdateFile(filename, updated): + """ If the file is different to updated then copy updated + into the file else leave alone so CVS and make don't treat + it as modified. """ + try: + infile = open(filename, "rb") + except IOError: # File is not there yet + out = open(filename, "wb") + out.write(updated.encode('utf-8')) + out.close() + print("New %s" % filename) + return + original = infile.read() + infile.close() + original = original.decode('utf-8') + if updated != original: + os.unlink(filename) + out = open(filename, "wb") + out.write(updated.encode('utf-8')) + out.close() + print("Changed %s " % filename) + #~ else: + #~ print "Unchanged", filename + +def Generate(inpath, outpath, commentPrefix, eolType, *lists): + """Generate 'outpath' from 'inpath'. + + "eolType" indicates the type of EOLs to use in the generated + file. It should be one of following constants: LF, CRLF, + CR, or NATIVE. + """ + #print "generate '%s' -> '%s' (comment prefix: %r, eols: %r)"\ + # % (inpath, outpath, commentPrefix, eolType) + try: + infile = open(inpath, "rb") + except IOError: + print("Can not open %s" % inpath) + return + original = infile.read() + infile.close() + original = original.decode('utf-8') + updated = CopyWithInsertion(original, commentPrefix, + inpath == outpath, eolType, *lists) + UpdateFile(outpath, updated) + +def Regenerate(filename, commentPrefix, eolType, *lists): + """Regenerate the given file. + + "eolType" indicates the type of EOLs to use in the generated + file. It should be one of following constants: LF, CRLF, + CR, or NATIVE. + """ + Generate(filename, filename, commentPrefix, eolType, *lists) + +def FindModules(lexFile): + modules = [] + f = open(lexFile) + for l in f.readlines(): + if l.startswith("LexerModule"): + l = l.replace("(", " ") + modules.append(l.split()[1]) + return modules + +# Properties that start with lexer. or fold. are automatically found but there are some +# older properties that don't follow this pattern so must be explicitly listed. +knownIrregularProperties = [ + "fold", + "styling.within.preprocessor", + "tab.timmy.whinge.level", + "asp.default.language", + "html.tags.case.sensitive", + "ps.level", + "ps.tokenize", + "sql.backslash.escapes", + "nsis.uservars", + "nsis.ignorecase" +] + +def FindProperties(lexFile): + properties = {} + f = open(lexFile) + for l in f.readlines(): + if ("GetProperty" in l or "DefineProperty" in l) and "\"" in l: + l = l.strip() + if not l.startswith("//"): # Drop comments + propertyName = l.split("\"")[1] + if propertyName.lower() == propertyName: + # Only allow lower case property names + if propertyName in knownIrregularProperties or \ + propertyName.startswith("fold.") or \ + propertyName.startswith("lexer."): + properties[propertyName] = 1 + return properties + +def FindPropertyDocumentation(lexFile): + documents = {} + f = open(lexFile) + name = "" + for l in f.readlines(): + l = l.strip() + if "// property " in l: + propertyName = l.split()[2] + if propertyName.lower() == propertyName: + # Only allow lower case property names + name = propertyName + documents[name] = "" + elif "DefineProperty" in l and "\"" in l: + propertyName = l.split("\"")[1] + if propertyName.lower() == propertyName: + # Only allow lower case property names + name = propertyName + documents[name] = "" + elif name: + if l.startswith("//"): + if documents[name]: + documents[name] += " " + documents[name] += l[2:].strip() + elif l.startswith("\""): + l = l[1:].strip() + if l.endswith(";"): + l = l[:-1].strip() + if l.endswith(")"): + l = l[:-1].strip() + if l.endswith("\""): + l = l[:-1] + # Fix escaped double quotes + l = l.replace("\\\"", "\"") + documents[name] += l + else: + name = "" + for name in list(documents.keys()): + if documents[name] == "": + del documents[name] + return documents + +def ciCompare(a,b): + return cmp(a.lower(), b.lower()) + +def ciKey(a): + return a.lower() + +def sortListInsensitive(l): + try: # Try key function + l.sort(key=ciKey) + except TypeError: # Earlier version of Python, so use comparison function + l.sort(ciCompare) + +def RegenerateAll(): + root="../../" + + # Find all the lexer source code files + lexFilePaths = glob.glob(root + "scintilla/lexers/Lex*.cxx") + sortListInsensitive(lexFilePaths) + lexFiles = [os.path.basename(f)[:-4] for f in lexFilePaths] + print(lexFiles) + lexerModules = [] + lexerProperties = {} + propertyDocuments = {} + for lexFile in lexFilePaths: + lexerModules.extend(FindModules(lexFile)) + for k in FindProperties(lexFile).keys(): + lexerProperties[k] = 1 + documents = FindPropertyDocumentation(lexFile) + for k in documents.keys(): + propertyDocuments[k] = documents[k] + sortListInsensitive(lexerModules) + del lexerProperties["fold.comment.python"] + lexerProperties = list(lexerProperties.keys()) + sortListInsensitive(lexerProperties) + + # Generate HTML to document each property + # This is done because tags can not be safely put inside comments in HTML + documentProperties = list(propertyDocuments.keys()) + sortListInsensitive(documentProperties) + propertiesHTML = [] + for k in documentProperties: + propertiesHTML.append("\t\n\t%s\n\t%s\n\t" % + (k, propertyDocuments[k])) + + # Find all the SciTE properties files + otherProps = ["abbrev.properties", "Embedded.properties", "SciTEGlobal.properties", "SciTE.properties"] + if os.path.exists(root + "scite"): + propFilePaths = glob.glob(root + "scite/src/*.properties") + sortListInsensitive(propFilePaths) + propFiles = [os.path.basename(f) for f in propFilePaths if os.path.basename(f) not in otherProps] + sortListInsensitive(propFiles) + print(propFiles) + + Regenerate(root + "scintilla/src/Catalogue.cxx", "//", NATIVE, lexerModules) + Regenerate(root + "scintilla/win32/scintilla.mak", "#", NATIVE, lexFiles) + Regenerate(root + "scintilla/win32/scintilla_vc6.mak", "#", NATIVE, lexFiles) + if os.path.exists(root + "scite"): + Regenerate(root + "scite/win32/makefile", "#", NATIVE, propFiles) + Regenerate(root + "scite/win32/scite.mak", "#", NATIVE, propFiles) + Regenerate(root + "scite/src/SciTEProps.cxx", "//", NATIVE, lexerProperties) + Regenerate(root + "scite/doc/SciTEDoc.html", "