diff --git a/Makefile.in b/Makefile.in index f456892a36..0322d80ad1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -236,6 +236,7 @@ WXSCINTILLA_OBJECTS = \ wxscintilla_LexBaan.o \ wxscintilla_LexBash.o \ wxscintilla_LexBasic.o \ + wxscintilla_LexBibTeX.o \ wxscintilla_LexBullant.o \ wxscintilla_LexCaml.o \ wxscintilla_LexCLW.o \ @@ -295,6 +296,7 @@ WXSCINTILLA_OBJECTS = \ wxscintilla_LexPython.o \ wxscintilla_LexR.o \ wxscintilla_LexRebol.o \ + wxscintilla_LexRegistry.o \ wxscintilla_LexRuby.o \ wxscintilla_LexRust.o \ wxscintilla_LexScriptol.o \ @@ -337,11 +339,14 @@ WXSCINTILLA_OBJECTS = \ wxscintilla_ContractionState.o \ wxscintilla_Decoration.o \ wxscintilla_Document.o \ + wxscintilla_EditModel.o \ + wxscintilla_EditView.o \ wxscintilla_Editor.o \ wxscintilla_ExternalLexer.o \ wxscintilla_Indicator.o \ wxscintilla_KeyMap.o \ wxscintilla_LineMarker.o \ + wxscintilla_MarginView.o \ wxscintilla_PerLine.o \ wxscintilla_PositionCache.o \ wxscintilla_RESearch.o \ @@ -17060,6 +17065,9 @@ wxscintilla_LexBash.o: $(srcdir)/src/stc/scintilla/lexers/LexBash.cxx wxscintilla_LexBasic.o: $(srcdir)/src/stc/scintilla/lexers/LexBasic.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/lexers/LexBasic.cxx +wxscintilla_LexBibTeX.o: $(srcdir)/src/stc/scintilla/lexers/LexBibTeX.cxx + $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/lexers/LexBibTeX.cxx + wxscintilla_LexBullant.o: $(srcdir)/src/stc/scintilla/lexers/LexBullant.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/lexers/LexBullant.cxx @@ -17237,6 +17245,9 @@ wxscintilla_LexR.o: $(srcdir)/src/stc/scintilla/lexers/LexR.cxx wxscintilla_LexRebol.o: $(srcdir)/src/stc/scintilla/lexers/LexRebol.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/lexers/LexRebol.cxx +wxscintilla_LexRegistry.o: $(srcdir)/src/stc/scintilla/lexers/LexRegistry.cxx + $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/lexers/LexRegistry.cxx + wxscintilla_LexRuby.o: $(srcdir)/src/stc/scintilla/lexers/LexRuby.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/lexers/LexRuby.cxx @@ -17363,6 +17374,12 @@ wxscintilla_Decoration.o: $(srcdir)/src/stc/scintilla/src/Decoration.cxx wxscintilla_Document.o: $(srcdir)/src/stc/scintilla/src/Document.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/Document.cxx +wxscintilla_EditModel.o: $(srcdir)/src/stc/scintilla/src/EditModel.cxx + $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/EditModel.cxx + +wxscintilla_EditView.o: $(srcdir)/src/stc/scintilla/src/EditView.cxx + $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/EditView.cxx + wxscintilla_Editor.o: $(srcdir)/src/stc/scintilla/src/Editor.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/Editor.cxx @@ -17378,6 +17395,9 @@ wxscintilla_KeyMap.o: $(srcdir)/src/stc/scintilla/src/KeyMap.cxx wxscintilla_LineMarker.o: $(srcdir)/src/stc/scintilla/src/LineMarker.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/LineMarker.cxx +wxscintilla_MarginView.o: $(srcdir)/src/stc/scintilla/src/MarginView.cxx + $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/MarginView.cxx + wxscintilla_PerLine.o: $(srcdir)/src/stc/scintilla/src/PerLine.cxx $(CXXC) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(srcdir)/src/stc/scintilla/src/PerLine.cxx diff --git a/build/bakefiles/scintilla.bkl b/build/bakefiles/scintilla.bkl index 4b3e95423b..37065e76f6 100644 --- a/build/bakefiles/scintilla.bkl +++ b/build/bakefiles/scintilla.bkl @@ -69,6 +69,7 @@ src/stc/scintilla/lexers/LexBaan.cxx src/stc/scintilla/lexers/LexBash.cxx src/stc/scintilla/lexers/LexBasic.cxx + src/stc/scintilla/lexers/LexBibTeX.cxx src/stc/scintilla/lexers/LexBullant.cxx src/stc/scintilla/lexers/LexCaml.cxx src/stc/scintilla/lexers/LexCLW.cxx @@ -128,6 +129,7 @@ src/stc/scintilla/lexers/LexPython.cxx src/stc/scintilla/lexers/LexR.cxx src/stc/scintilla/lexers/LexRebol.cxx + src/stc/scintilla/lexers/LexRegistry.cxx src/stc/scintilla/lexers/LexRuby.cxx src/stc/scintilla/lexers/LexRust.cxx src/stc/scintilla/lexers/LexScriptol.cxx @@ -170,11 +172,14 @@ src/stc/scintilla/src/ContractionState.cxx src/stc/scintilla/src/Decoration.cxx src/stc/scintilla/src/Document.cxx + src/stc/scintilla/src/EditModel.cxx + src/stc/scintilla/src/EditView.cxx src/stc/scintilla/src/Editor.cxx src/stc/scintilla/src/ExternalLexer.cxx src/stc/scintilla/src/Indicator.cxx src/stc/scintilla/src/KeyMap.cxx src/stc/scintilla/src/LineMarker.cxx + src/stc/scintilla/src/MarginView.cxx src/stc/scintilla/src/PerLine.cxx src/stc/scintilla/src/PositionCache.cxx src/stc/scintilla/src/RESearch.cxx diff --git a/build/msw/makefile.bcc b/build/msw/makefile.bcc index fdf357418f..7ac4fe1644 100644 --- a/build/msw/makefile.bcc +++ b/build/msw/makefile.bcc @@ -217,6 +217,7 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_LexBaan.obj \ $(OBJS)\wxscintilla_LexBash.obj \ $(OBJS)\wxscintilla_LexBasic.obj \ + $(OBJS)\wxscintilla_LexBibTeX.obj \ $(OBJS)\wxscintilla_LexBullant.obj \ $(OBJS)\wxscintilla_LexCaml.obj \ $(OBJS)\wxscintilla_LexCLW.obj \ @@ -276,6 +277,7 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_LexPython.obj \ $(OBJS)\wxscintilla_LexR.obj \ $(OBJS)\wxscintilla_LexRebol.obj \ + $(OBJS)\wxscintilla_LexRegistry.obj \ $(OBJS)\wxscintilla_LexRuby.obj \ $(OBJS)\wxscintilla_LexRust.obj \ $(OBJS)\wxscintilla_LexScriptol.obj \ @@ -318,11 +320,14 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_ContractionState.obj \ $(OBJS)\wxscintilla_Decoration.obj \ $(OBJS)\wxscintilla_Document.obj \ + $(OBJS)\wxscintilla_EditModel.obj \ + $(OBJS)\wxscintilla_EditView.obj \ $(OBJS)\wxscintilla_Editor.obj \ $(OBJS)\wxscintilla_ExternalLexer.obj \ $(OBJS)\wxscintilla_Indicator.obj \ $(OBJS)\wxscintilla_KeyMap.obj \ $(OBJS)\wxscintilla_LineMarker.obj \ + $(OBJS)\wxscintilla_MarginView.obj \ $(OBJS)\wxscintilla_PerLine.obj \ $(OBJS)\wxscintilla_PositionCache.obj \ $(OBJS)\wxscintilla_RESearch.obj \ @@ -5942,6 +5947,9 @@ $(OBJS)\wxscintilla_LexBash.obj: ..\..\src\stc\scintilla\lexers\LexBash.cxx $(OBJS)\wxscintilla_LexBasic.obj: ..\..\src\stc\scintilla\lexers\LexBasic.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexBasic.cxx +$(OBJS)\wxscintilla_LexBibTeX.obj: ..\..\src\stc\scintilla\lexers\LexBibTeX.cxx + $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexBibTeX.cxx + $(OBJS)\wxscintilla_LexBullant.obj: ..\..\src\stc\scintilla\lexers\LexBullant.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexBullant.cxx @@ -6119,6 +6127,9 @@ $(OBJS)\wxscintilla_LexR.obj: ..\..\src\stc\scintilla\lexers\LexR.cxx $(OBJS)\wxscintilla_LexRebol.obj: ..\..\src\stc\scintilla\lexers\LexRebol.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexRebol.cxx +$(OBJS)\wxscintilla_LexRegistry.obj: ..\..\src\stc\scintilla\lexers\LexRegistry.cxx + $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexRegistry.cxx + $(OBJS)\wxscintilla_LexRuby.obj: ..\..\src\stc\scintilla\lexers\LexRuby.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexRuby.cxx @@ -6245,6 +6256,12 @@ $(OBJS)\wxscintilla_Decoration.obj: ..\..\src\stc\scintilla\src\Decoration.cxx $(OBJS)\wxscintilla_Document.obj: ..\..\src\stc\scintilla\src\Document.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\Document.cxx +$(OBJS)\wxscintilla_EditModel.obj: ..\..\src\stc\scintilla\src\EditModel.cxx + $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\EditModel.cxx + +$(OBJS)\wxscintilla_EditView.obj: ..\..\src\stc\scintilla\src\EditView.cxx + $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\EditView.cxx + $(OBJS)\wxscintilla_Editor.obj: ..\..\src\stc\scintilla\src\Editor.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\Editor.cxx @@ -6260,6 +6277,9 @@ $(OBJS)\wxscintilla_KeyMap.obj: ..\..\src\stc\scintilla\src\KeyMap.cxx $(OBJS)\wxscintilla_LineMarker.obj: ..\..\src\stc\scintilla\src\LineMarker.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\LineMarker.cxx +$(OBJS)\wxscintilla_MarginView.obj: ..\..\src\stc\scintilla\src\MarginView.cxx + $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\MarginView.cxx + $(OBJS)\wxscintilla_PerLine.obj: ..\..\src\stc\scintilla\src\PerLine.cxx $(CXX) -q -c -P -o$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\PerLine.cxx diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc index 58de4691d8..d0d1a013c8 100644 --- a/build/msw/makefile.gcc +++ b/build/msw/makefile.gcc @@ -205,6 +205,7 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_LexBaan.o \ $(OBJS)\wxscintilla_LexBash.o \ $(OBJS)\wxscintilla_LexBasic.o \ + $(OBJS)\wxscintilla_LexBibTeX.o \ $(OBJS)\wxscintilla_LexBullant.o \ $(OBJS)\wxscintilla_LexCaml.o \ $(OBJS)\wxscintilla_LexCLW.o \ @@ -264,6 +265,7 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_LexPython.o \ $(OBJS)\wxscintilla_LexR.o \ $(OBJS)\wxscintilla_LexRebol.o \ + $(OBJS)\wxscintilla_LexRegistry.o \ $(OBJS)\wxscintilla_LexRuby.o \ $(OBJS)\wxscintilla_LexRust.o \ $(OBJS)\wxscintilla_LexScriptol.o \ @@ -306,11 +308,14 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_ContractionState.o \ $(OBJS)\wxscintilla_Decoration.o \ $(OBJS)\wxscintilla_Document.o \ + $(OBJS)\wxscintilla_EditModel.o \ + $(OBJS)\wxscintilla_EditView.o \ $(OBJS)\wxscintilla_Editor.o \ $(OBJS)\wxscintilla_ExternalLexer.o \ $(OBJS)\wxscintilla_Indicator.o \ $(OBJS)\wxscintilla_KeyMap.o \ $(OBJS)\wxscintilla_LineMarker.o \ + $(OBJS)\wxscintilla_MarginView.o \ $(OBJS)\wxscintilla_PerLine.o \ $(OBJS)\wxscintilla_PositionCache.o \ $(OBJS)\wxscintilla_RESearch.o \ @@ -6117,6 +6122,9 @@ $(OBJS)\wxscintilla_LexBash.o: ../../src/stc/scintilla/lexers/LexBash.cxx $(OBJS)\wxscintilla_LexBasic.o: ../../src/stc/scintilla/lexers/LexBasic.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\wxscintilla_LexBibTeX.o: ../../src/stc/scintilla/lexers/LexBibTeX.cxx + $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\wxscintilla_LexBullant.o: ../../src/stc/scintilla/lexers/LexBullant.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< @@ -6294,6 +6302,9 @@ $(OBJS)\wxscintilla_LexR.o: ../../src/stc/scintilla/lexers/LexR.cxx $(OBJS)\wxscintilla_LexRebol.o: ../../src/stc/scintilla/lexers/LexRebol.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\wxscintilla_LexRegistry.o: ../../src/stc/scintilla/lexers/LexRegistry.cxx + $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\wxscintilla_LexRuby.o: ../../src/stc/scintilla/lexers/LexRuby.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< @@ -6420,6 +6431,12 @@ $(OBJS)\wxscintilla_Decoration.o: ../../src/stc/scintilla/src/Decoration.cxx $(OBJS)\wxscintilla_Document.o: ../../src/stc/scintilla/src/Document.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\wxscintilla_EditModel.o: ../../src/stc/scintilla/src/EditModel.cxx + $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< + +$(OBJS)\wxscintilla_EditView.o: ../../src/stc/scintilla/src/EditView.cxx + $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\wxscintilla_Editor.o: ../../src/stc/scintilla/src/Editor.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< @@ -6435,6 +6452,9 @@ $(OBJS)\wxscintilla_KeyMap.o: ../../src/stc/scintilla/src/KeyMap.cxx $(OBJS)\wxscintilla_LineMarker.o: ../../src/stc/scintilla/src/LineMarker.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\wxscintilla_MarginView.o: ../../src/stc/scintilla/src/MarginView.cxx + $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\wxscintilla_PerLine.o: ../../src/stc/scintilla/src/PerLine.cxx $(CXX) -c -o $@ $(WXSCINTILLA_CXXFLAGS) $(CPPDEPS) $< diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc index c5dcd0812f..fe5f95662b 100644 --- a/build/msw/makefile.vc +++ b/build/msw/makefile.vc @@ -228,6 +228,7 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_LexBaan.obj \ $(OBJS)\wxscintilla_LexBash.obj \ $(OBJS)\wxscintilla_LexBasic.obj \ + $(OBJS)\wxscintilla_LexBibTeX.obj \ $(OBJS)\wxscintilla_LexBullant.obj \ $(OBJS)\wxscintilla_LexCaml.obj \ $(OBJS)\wxscintilla_LexCLW.obj \ @@ -287,6 +288,7 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_LexPython.obj \ $(OBJS)\wxscintilla_LexR.obj \ $(OBJS)\wxscintilla_LexRebol.obj \ + $(OBJS)\wxscintilla_LexRegistry.obj \ $(OBJS)\wxscintilla_LexRuby.obj \ $(OBJS)\wxscintilla_LexRust.obj \ $(OBJS)\wxscintilla_LexScriptol.obj \ @@ -329,11 +331,14 @@ WXSCINTILLA_OBJECTS = \ $(OBJS)\wxscintilla_ContractionState.obj \ $(OBJS)\wxscintilla_Decoration.obj \ $(OBJS)\wxscintilla_Document.obj \ + $(OBJS)\wxscintilla_EditModel.obj \ + $(OBJS)\wxscintilla_EditView.obj \ $(OBJS)\wxscintilla_Editor.obj \ $(OBJS)\wxscintilla_ExternalLexer.obj \ $(OBJS)\wxscintilla_Indicator.obj \ $(OBJS)\wxscintilla_KeyMap.obj \ $(OBJS)\wxscintilla_LineMarker.obj \ + $(OBJS)\wxscintilla_MarginView.obj \ $(OBJS)\wxscintilla_PerLine.obj \ $(OBJS)\wxscintilla_PositionCache.obj \ $(OBJS)\wxscintilla_RESearch.obj \ @@ -6634,6 +6639,9 @@ $(OBJS)\wxscintilla_LexBash.obj: ..\..\src\stc\scintilla\lexers\LexBash.cxx $(OBJS)\wxscintilla_LexBasic.obj: ..\..\src\stc\scintilla\lexers\LexBasic.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexBasic.cxx +$(OBJS)\wxscintilla_LexBibTeX.obj: ..\..\src\stc\scintilla\lexers\LexBibTeX.cxx + $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexBibTeX.cxx + $(OBJS)\wxscintilla_LexBullant.obj: ..\..\src\stc\scintilla\lexers\LexBullant.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexBullant.cxx @@ -6811,6 +6819,9 @@ $(OBJS)\wxscintilla_LexR.obj: ..\..\src\stc\scintilla\lexers\LexR.cxx $(OBJS)\wxscintilla_LexRebol.obj: ..\..\src\stc\scintilla\lexers\LexRebol.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexRebol.cxx +$(OBJS)\wxscintilla_LexRegistry.obj: ..\..\src\stc\scintilla\lexers\LexRegistry.cxx + $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexRegistry.cxx + $(OBJS)\wxscintilla_LexRuby.obj: ..\..\src\stc\scintilla\lexers\LexRuby.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\lexers\LexRuby.cxx @@ -6937,6 +6948,12 @@ $(OBJS)\wxscintilla_Decoration.obj: ..\..\src\stc\scintilla\src\Decoration.cxx $(OBJS)\wxscintilla_Document.obj: ..\..\src\stc\scintilla\src\Document.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\Document.cxx +$(OBJS)\wxscintilla_EditModel.obj: ..\..\src\stc\scintilla\src\EditModel.cxx + $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\EditModel.cxx + +$(OBJS)\wxscintilla_EditView.obj: ..\..\src\stc\scintilla\src\EditView.cxx + $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\EditView.cxx + $(OBJS)\wxscintilla_Editor.obj: ..\..\src\stc\scintilla\src\Editor.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\Editor.cxx @@ -6952,6 +6969,9 @@ $(OBJS)\wxscintilla_KeyMap.obj: ..\..\src\stc\scintilla\src\KeyMap.cxx $(OBJS)\wxscintilla_LineMarker.obj: ..\..\src\stc\scintilla\src\LineMarker.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\LineMarker.cxx +$(OBJS)\wxscintilla_MarginView.obj: ..\..\src\stc\scintilla\src\MarginView.cxx + $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\MarginView.cxx + $(OBJS)\wxscintilla_PerLine.obj: ..\..\src\stc\scintilla\src\PerLine.cxx $(CXX) /c /nologo /TP /Fo$@ $(WXSCINTILLA_CXXFLAGS) ..\..\src\stc\scintilla\src\PerLine.cxx diff --git a/build/msw/wx_vc7_wxscintilla.vcproj b/build/msw/wx_vc7_wxscintilla.vcproj index 76fefd019b..90af102689 100644 --- a/build/msw/wx_vc7_wxscintilla.vcproj +++ b/build/msw/wx_vc7_wxscintilla.vcproj @@ -286,6 +286,12 @@ + + + + @@ -337,6 +343,9 @@ + + @@ -514,6 +523,9 @@ + + @@ -595,6 +607,9 @@ + + diff --git a/build/msw/wx_vc8_wxscintilla.vcproj b/build/msw/wx_vc8_wxscintilla.vcproj index a0226156d7..418e0fe9c9 100644 --- a/build/msw/wx_vc8_wxscintilla.vcproj +++ b/build/msw/wx_vc8_wxscintilla.vcproj @@ -730,6 +730,14 @@ RelativePath="..\..\src\stc\scintilla\src\Document.cxx" > + + + + @@ -798,6 +806,10 @@ RelativePath="..\..\src\stc\scintilla\lexers\LexBasic.cxx" > + + @@ -1034,6 +1046,10 @@ RelativePath="..\..\src\stc\scintilla\lexers\LexRebol.cxx" > + + @@ -1142,6 +1158,10 @@ RelativePath="..\..\src\stc\scintilla\src\LineMarker.cxx" > + + diff --git a/build/msw/wx_vc9_wxscintilla.vcproj b/build/msw/wx_vc9_wxscintilla.vcproj index 9d36c7afba..479161d738 100644 --- a/build/msw/wx_vc9_wxscintilla.vcproj +++ b/build/msw/wx_vc9_wxscintilla.vcproj @@ -726,6 +726,14 @@ RelativePath="..\..\src\stc\scintilla\src\Document.cxx" > + + + + @@ -794,6 +802,10 @@ RelativePath="..\..\src\stc\scintilla\lexers\LexBasic.cxx" > + + @@ -1030,6 +1042,10 @@ RelativePath="..\..\src\stc\scintilla\lexers\LexRebol.cxx" > + + @@ -1138,6 +1154,10 @@ RelativePath="..\..\src\stc\scintilla\src\LineMarker.cxx" > + + diff --git a/include/wx/stc/stc.h b/include/wx/stc/stc.h index a06899cb71..381596251d 100644 --- a/include/wx/stc/stc.h +++ b/include/wx/stc/stc.h @@ -75,6 +75,8 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; /// The SC_CP_UTF8 value can be used to enter Unicode mode. /// This is the same value as CP_UTF8 in Windows #define wxSTC_CP_UTF8 65001 +#define wxSTC_IME_WINDOWED 0 +#define wxSTC_IME_INLINE 1 #define wxSTC_MARKER_MAX 31 #define wxSTC_MARK_CIRCLE 0 #define wxSTC_MARK_ROUNDRECT 1 @@ -190,7 +192,9 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_INDIC_DOTBOX 12 #define wxSTC_INDIC_SQUIGGLEPIXMAP 13 #define wxSTC_INDIC_COMPOSITIONTHICK 14 -#define wxSTC_INDIC_MAX 31 +#define wxSTC_INDIC_IME 32 +#define wxSTC_INDIC_IME_MAX 35 +#define wxSTC_INDIC_MAX 35 #define wxSTC_INDIC_CONTAINER 8 #define wxSTC_INDIC0_MASK 0x20 #define wxSTC_INDIC1_MASK 0x40 @@ -220,6 +224,7 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_FIND_WORDSTART 0x00100000 #define wxSTC_FIND_REGEXP 0x00200000 #define wxSTC_FIND_POSIX 0x00400000 +#define wxSTC_FIND_CXX11REGEX 0x00800000 #define wxSTC_FOLDLEVELBASE 0x400 #define wxSTC_FOLDLEVELWHITEFLAG 0x1000 #define wxSTC_FOLDLEVELHEADERFLAG 0x2000 @@ -255,6 +260,9 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_CACHE_CARET 1 #define wxSTC_CACHE_PAGE 2 #define wxSTC_CACHE_DOCUMENT 3 +#define wxSTC_PHASES_ONE 0 +#define wxSTC_PHASES_TWO 1 +#define wxSTC_PHASES_MULTIPLE 2 /// Control font anti-aliasing. #define wxSTC_EFF_QUALITY_MASK 0xF @@ -270,6 +278,8 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_STATUS_OK 0 #define wxSTC_STATUS_FAILURE 1 #define wxSTC_STATUS_BADALLOC 2 +#define wxSTC_STATUS_WARN_START 1000 +#define wxSTC_STATUS_WARN_REGEX 1001 #define wxSTC_CURSORNORMAL -1 #define wxSTC_CURSORARROW 2 #define wxSTC_CURSORWAIT 4 @@ -329,12 +339,15 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_ANNOTATION_HIDDEN 0 #define wxSTC_ANNOTATION_STANDARD 1 #define wxSTC_ANNOTATION_BOXED 2 +#define wxSTC_ANNOTATION_INDENTED 3 #define wxSTC_UNDO_MAY_COALESCE 1 #define wxSTC_SCVS_NONE 0 #define wxSTC_SCVS_RECTANGULARSELECTION 1 #define wxSTC_SCVS_USERACCESSIBLE 2 #define wxSTC_TECHNOLOGY_DEFAULT 0 #define wxSTC_TECHNOLOGY_DIRECTWRITE 1 +#define wxSTC_TECHNOLOGY_DIRECTWRITERETAIN 2 +#define wxSTC_TECHNOLOGY_DIRECTWRITEDC 3 /// Line end types which may be used in addition to LF, CR, and CRLF /// SC_LINE_END_TYPE_UNICODE includes U+2028 Line Separator, @@ -373,7 +386,8 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_MOD_CONTAINER 0x40000 #define wxSTC_MOD_LEXERSTATE 0x80000 #define wxSTC_MOD_INSERTCHECK 0x100000 -#define wxSTC_MODEVENTMASKALL 0x1FFFFF +#define wxSTC_MOD_CHANGETABSTOPS 0x200000 +#define wxSTC_MODEVENTMASKALL 0x3FFFFF #define wxSTC_UPDATE_CONTENT 0x1 #define wxSTC_UPDATE_SELECTION 0x2 #define wxSTC_UPDATE_V_SCROLL 0x4 @@ -523,6 +537,8 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_LEX_DMAP 112 #define wxSTC_LEX_AS 113 #define wxSTC_LEX_DMIS 114 +#define wxSTC_LEX_REGISTRY 115 +#define wxSTC_LEX_BIBTEX 116 /// When a lexer specifies its language as SCLEX_AUTOMATIC it receives a /// value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -1418,6 +1434,7 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_KIX_KEYWORD 7 #define wxSTC_KIX_FUNCTIONS 8 #define wxSTC_KIX_OPERATOR 9 +#define wxSTC_KIX_COMMENTSTREAM 10 #define wxSTC_KIX_IDENTIFIER 31 /// Lexical states for SCLEX_GUI4CLI @@ -1528,6 +1545,7 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_VHDL_STDPACKAGE 12 #define wxSTC_VHDL_STDTYPE 13 #define wxSTC_VHDL_USERWORD 14 +#define wxSTC_VHDL_BLOCK_COMMENT 15 /// Lexical states for SCLEX_CAML #define wxSTC_CAML_DEFAULT 0 @@ -1649,6 +1667,7 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_SQL_USER3 21 #define wxSTC_SQL_USER4 22 #define wxSTC_SQL_QUOTEDIDENTIFIER 23 +#define wxSTC_SQL_QOPERATOR 24 /// Lexical states for SCLEX_SMALLTALK #define wxSTC_ST_DEFAULT 0 @@ -2294,6 +2313,9 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_RUST_LIFETIME 18 #define wxSTC_RUST_MACRO 19 #define wxSTC_RUST_LEXERROR 20 +#define wxSTC_RUST_BYTESTRING 21 +#define wxSTC_RUST_BYTESTRINGR 22 +#define wxSTC_RUST_BYTECHARACTER 23 /// Lexical states for SCLEX_DMAP #define wxSTC_DMAP_DEFAULT 0 @@ -2320,6 +2342,30 @@ class WXDLLIMPEXP_FWD_CORE wxScrollBar; #define wxSTC_DMIS_UNSUPPORTED_MINOR 8 #define wxSTC_DMIS_LABEL 9 +/// Lexical states for SCLEX_REGISTRY +#define wxSTC_REG_DEFAULT 0 +#define wxSTC_REG_COMMENT 1 +#define wxSTC_REG_VALUENAME 2 +#define wxSTC_REG_STRING 3 +#define wxSTC_REG_HEXDIGIT 4 +#define wxSTC_REG_VALUETYPE 5 +#define wxSTC_REG_ADDEDKEY 6 +#define wxSTC_REG_DELETEDKEY 7 +#define wxSTC_REG_ESCAPED 8 +#define wxSTC_REG_KEYPATH_GUID 9 +#define wxSTC_REG_STRING_GUID 10 +#define wxSTC_REG_PARAMETER 11 +#define wxSTC_REG_OPERATOR 12 + +/// Lexical state for SCLEX_BIBTEX +#define wxSTC_BIBTEX_DEFAULT 0 +#define wxSTC_BIBTEX_ENTRY 1 +#define wxSTC_BIBTEX_UNKNOWN_ENTRY 2 +#define wxSTC_BIBTEX_KEY 3 +#define wxSTC_BIBTEX_PARAMETER 4 +#define wxSTC_BIBTEX_VALUE 5 +#define wxSTC_BIBTEX_COMMENT 6 + //}}} //---------------------------------------------------------------------- @@ -2806,9 +2852,24 @@ public: // Retrieve the visible size of a tab. int GetTabWidth() const; + // Clear explicit tabstops on a line. + void ClearTabStops(int line); + + // Add an explicit tab stop for a line. + void AddTabStop(int line, int x); + + // Find the next explicit tab stop position on a line after a position. + int GetNextTabStop(int line, int x); + // Set the code page used to interpret the bytes of the document as characters. void SetCodePage(int codePage); + // Is the IME displayed in a winow or inline? + int GetIMEInteraction() const; + + // Choose to display the the IME in a winow or inline. + void SetIMEInteraction(int imeInteraction); + // Set the symbol used for a particular marker number, // and optionally the fore and background colours. void MarkerDefine(int markerNumber, int markerSymbol, @@ -3632,13 +3693,22 @@ public: // Append a string to the end of the document without changing the selection. void AppendText(const wxString& text); - // Is drawing done in two phases with backgrounds drawn before faoregrounds? + // Is drawing done in two phases with backgrounds drawn before foregrounds? bool GetTwoPhaseDraw() const; // In twoPhaseDraw mode, drawing is performed in two phases, first the background // and then the foreground. This avoids chopping off characters that overlap the next run. void SetTwoPhaseDraw(bool twoPhase); + // How many phases is drawing done in? + int GetPhasesDraw() const; + + // In one phase draw, text is drawn in a series of rectangular blocks with no overlap. + // In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. + // In multiple phase draw, each element is drawn over the whole drawing area, allowing text + // to overlap from one line to the next. + void SetPhasesDraw(int phases); + // Scroll so that a display line is at the top of the display. void SetFirstVisibleLine(int lineDisplay); diff --git a/interface/wx/stc/stc.h b/interface/wx/stc/stc.h index 31dda9f42d..80f4a21676 100644 --- a/interface/wx/stc/stc.h +++ b/interface/wx/stc/stc.h @@ -31,6 +31,8 @@ /// The SC_CP_UTF8 value can be used to enter Unicode mode. /// This is the same value as CP_UTF8 in Windows #define wxSTC_CP_UTF8 65001 +#define wxSTC_IME_WINDOWED 0 +#define wxSTC_IME_INLINE 1 #define wxSTC_MARKER_MAX 31 #define wxSTC_MARK_CIRCLE 0 #define wxSTC_MARK_ROUNDRECT 1 @@ -146,7 +148,9 @@ #define wxSTC_INDIC_DOTBOX 12 #define wxSTC_INDIC_SQUIGGLEPIXMAP 13 #define wxSTC_INDIC_COMPOSITIONTHICK 14 -#define wxSTC_INDIC_MAX 31 +#define wxSTC_INDIC_IME 32 +#define wxSTC_INDIC_IME_MAX 35 +#define wxSTC_INDIC_MAX 35 #define wxSTC_INDIC_CONTAINER 8 #define wxSTC_INDIC0_MASK 0x20 #define wxSTC_INDIC1_MASK 0x40 @@ -176,6 +180,7 @@ #define wxSTC_FIND_WORDSTART 0x00100000 #define wxSTC_FIND_REGEXP 0x00200000 #define wxSTC_FIND_POSIX 0x00400000 +#define wxSTC_FIND_CXX11REGEX 0x00800000 #define wxSTC_FOLDLEVELBASE 0x400 #define wxSTC_FOLDLEVELWHITEFLAG 0x1000 #define wxSTC_FOLDLEVELHEADERFLAG 0x2000 @@ -211,6 +216,9 @@ #define wxSTC_CACHE_CARET 1 #define wxSTC_CACHE_PAGE 2 #define wxSTC_CACHE_DOCUMENT 3 +#define wxSTC_PHASES_ONE 0 +#define wxSTC_PHASES_TWO 1 +#define wxSTC_PHASES_MULTIPLE 2 /// Control font anti-aliasing. #define wxSTC_EFF_QUALITY_MASK 0xF @@ -226,6 +234,8 @@ #define wxSTC_STATUS_OK 0 #define wxSTC_STATUS_FAILURE 1 #define wxSTC_STATUS_BADALLOC 2 +#define wxSTC_STATUS_WARN_START 1000 +#define wxSTC_STATUS_WARN_REGEX 1001 #define wxSTC_CURSORNORMAL -1 #define wxSTC_CURSORARROW 2 #define wxSTC_CURSORWAIT 4 @@ -285,12 +295,15 @@ #define wxSTC_ANNOTATION_HIDDEN 0 #define wxSTC_ANNOTATION_STANDARD 1 #define wxSTC_ANNOTATION_BOXED 2 +#define wxSTC_ANNOTATION_INDENTED 3 #define wxSTC_UNDO_MAY_COALESCE 1 #define wxSTC_SCVS_NONE 0 #define wxSTC_SCVS_RECTANGULARSELECTION 1 #define wxSTC_SCVS_USERACCESSIBLE 2 #define wxSTC_TECHNOLOGY_DEFAULT 0 #define wxSTC_TECHNOLOGY_DIRECTWRITE 1 +#define wxSTC_TECHNOLOGY_DIRECTWRITERETAIN 2 +#define wxSTC_TECHNOLOGY_DIRECTWRITEDC 3 /// Line end types which may be used in addition to LF, CR, and CRLF /// SC_LINE_END_TYPE_UNICODE includes U+2028 Line Separator, @@ -329,7 +342,8 @@ #define wxSTC_MOD_CONTAINER 0x40000 #define wxSTC_MOD_LEXERSTATE 0x80000 #define wxSTC_MOD_INSERTCHECK 0x100000 -#define wxSTC_MODEVENTMASKALL 0x1FFFFF +#define wxSTC_MOD_CHANGETABSTOPS 0x200000 +#define wxSTC_MODEVENTMASKALL 0x3FFFFF #define wxSTC_UPDATE_CONTENT 0x1 #define wxSTC_UPDATE_SELECTION 0x2 #define wxSTC_UPDATE_V_SCROLL 0x4 @@ -479,6 +493,8 @@ #define wxSTC_LEX_DMAP 112 #define wxSTC_LEX_AS 113 #define wxSTC_LEX_DMIS 114 +#define wxSTC_LEX_REGISTRY 115 +#define wxSTC_LEX_BIBTEX 116 /// When a lexer specifies its language as SCLEX_AUTOMATIC it receives a /// value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -1374,6 +1390,7 @@ #define wxSTC_KIX_KEYWORD 7 #define wxSTC_KIX_FUNCTIONS 8 #define wxSTC_KIX_OPERATOR 9 +#define wxSTC_KIX_COMMENTSTREAM 10 #define wxSTC_KIX_IDENTIFIER 31 /// Lexical states for SCLEX_GUI4CLI @@ -1484,6 +1501,7 @@ #define wxSTC_VHDL_STDPACKAGE 12 #define wxSTC_VHDL_STDTYPE 13 #define wxSTC_VHDL_USERWORD 14 +#define wxSTC_VHDL_BLOCK_COMMENT 15 /// Lexical states for SCLEX_CAML #define wxSTC_CAML_DEFAULT 0 @@ -1605,6 +1623,7 @@ #define wxSTC_SQL_USER3 21 #define wxSTC_SQL_USER4 22 #define wxSTC_SQL_QUOTEDIDENTIFIER 23 +#define wxSTC_SQL_QOPERATOR 24 /// Lexical states for SCLEX_SMALLTALK #define wxSTC_ST_DEFAULT 0 @@ -2250,6 +2269,9 @@ #define wxSTC_RUST_LIFETIME 18 #define wxSTC_RUST_MACRO 19 #define wxSTC_RUST_LEXERROR 20 +#define wxSTC_RUST_BYTESTRING 21 +#define wxSTC_RUST_BYTESTRINGR 22 +#define wxSTC_RUST_BYTECHARACTER 23 /// Lexical states for SCLEX_DMAP #define wxSTC_DMAP_DEFAULT 0 @@ -2276,6 +2298,30 @@ #define wxSTC_DMIS_UNSUPPORTED_MINOR 8 #define wxSTC_DMIS_LABEL 9 +/// Lexical states for SCLEX_REGISTRY +#define wxSTC_REG_DEFAULT 0 +#define wxSTC_REG_COMMENT 1 +#define wxSTC_REG_VALUENAME 2 +#define wxSTC_REG_STRING 3 +#define wxSTC_REG_HEXDIGIT 4 +#define wxSTC_REG_VALUETYPE 5 +#define wxSTC_REG_ADDEDKEY 6 +#define wxSTC_REG_DELETEDKEY 7 +#define wxSTC_REG_ESCAPED 8 +#define wxSTC_REG_KEYPATH_GUID 9 +#define wxSTC_REG_STRING_GUID 10 +#define wxSTC_REG_PARAMETER 11 +#define wxSTC_REG_OPERATOR 12 + +/// Lexical state for SCLEX_BIBTEX +#define wxSTC_BIBTEX_DEFAULT 0 +#define wxSTC_BIBTEX_ENTRY 1 +#define wxSTC_BIBTEX_UNKNOWN_ENTRY 2 +#define wxSTC_BIBTEX_KEY 3 +#define wxSTC_BIBTEX_PARAMETER 4 +#define wxSTC_BIBTEX_VALUE 5 +#define wxSTC_BIBTEX_COMMENT 6 + //}}} // Commands that can be bound to keystrokes {{{ @@ -2916,11 +2962,36 @@ public: */ int GetTabWidth() const; + /** + Clear explicit tabstops on a line. + */ + void ClearTabStops(int line); + + /** + Add an explicit tab stop for a line. + */ + void AddTabStop(int line, int x); + + /** + Find the next explicit tab stop position on a line after a position. + */ + int GetNextTabStop(int line, int x); + /** Set the code page used to interpret the bytes of the document as characters. */ void SetCodePage(int codePage); + /** + Is the IME displayed in a winow or inline? + */ + int GetIMEInteraction() const; + + /** + Choose to display the the IME in a winow or inline. + */ + void SetIMEInteraction(int imeInteraction); + /** Set the symbol used for a particular marker number, and optionally the fore and background colours. @@ -4261,7 +4332,7 @@ public: void AppendText(const wxString& text); /** - Is drawing done in two phases with backgrounds drawn before faoregrounds? + Is drawing done in two phases with backgrounds drawn before foregrounds? */ bool GetTwoPhaseDraw() const; @@ -4271,6 +4342,19 @@ public: */ void SetTwoPhaseDraw(bool twoPhase); + /** + How many phases is drawing done in? + */ + int GetPhasesDraw() const; + + /** + In one phase draw, text is drawn in a series of rectangular blocks with no overlap. + In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. + In multiple phase draw, each element is drawn over the whole drawing area, allowing text + to overlap from one line to the next. + */ + void SetPhasesDraw(int phases); + /** Scroll so that a display line is at the top of the display. */ diff --git a/src/stc/scintilla/README.txt b/src/stc/scintilla/README.txt index fe78ff9e85..94198e0a47 100644 --- a/src/stc/scintilla/README.txt +++ b/src/stc/scintilla/README.txt @@ -3,7 +3,7 @@ directories from the Scintilla source distribution. All other code needed to implement Scintilla on top of wxWidgets is located in the directory above this one. -The current version of the Scintilla code is 3.4.4 +The current version of the Scintilla code is 3.5.2 These are the basic steps needed to update the version of Scintilla used by wxSTC. diff --git a/src/stc/scintilla/include/SciLexer.h b/src/stc/scintilla/include/SciLexer.h index 54cc8ba7ef..dc75a98b6a 100644 --- a/src/stc/scintilla/include/SciLexer.h +++ b/src/stc/scintilla/include/SciLexer.h @@ -127,6 +127,8 @@ #define SCLEX_DMAP 112 #define SCLEX_AS 113 #define SCLEX_DMIS 114 +#define SCLEX_REGISTRY 115 +#define SCLEX_BIBTEX 116 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -906,6 +908,7 @@ #define SCE_KIX_KEYWORD 7 #define SCE_KIX_FUNCTIONS 8 #define SCE_KIX_OPERATOR 9 +#define SCE_KIX_COMMENTSTREAM 10 #define SCE_KIX_IDENTIFIER 31 #define SCE_GC_DEFAULT 0 #define SCE_GC_COMMENTLINE 1 @@ -1002,6 +1005,7 @@ #define SCE_VHDL_STDPACKAGE 12 #define SCE_VHDL_STDTYPE 13 #define SCE_VHDL_USERWORD 14 +#define SCE_VHDL_BLOCK_COMMENT 15 #define SCE_CAML_DEFAULT 0 #define SCE_CAML_IDENTIFIER 1 #define SCE_CAML_TAGNAME 2 @@ -1113,6 +1117,7 @@ #define SCE_SQL_USER3 21 #define SCE_SQL_USER4 22 #define SCE_SQL_QUOTEDIDENTIFIER 23 +#define SCE_SQL_QOPERATOR 24 #define SCE_ST_DEFAULT 0 #define SCE_ST_STRING 1 #define SCE_ST_NUMBER 2 @@ -1692,6 +1697,9 @@ #define SCE_RUST_LIFETIME 18 #define SCE_RUST_MACRO 19 #define SCE_RUST_LEXERROR 20 +#define SCE_RUST_BYTESTRING 21 +#define SCE_RUST_BYTESTRINGR 22 +#define SCE_RUST_BYTECHARACTER 23 #define SCE_DMAP_DEFAULT 0 #define SCE_DMAP_COMMENT 1 #define SCE_DMAP_NUMBER 2 @@ -1713,6 +1721,26 @@ #define SCE_DMIS_UNSUPPORTED_MAJOR 7 #define SCE_DMIS_UNSUPPORTED_MINOR 8 #define SCE_DMIS_LABEL 9 +#define SCE_REG_DEFAULT 0 +#define SCE_REG_COMMENT 1 +#define SCE_REG_VALUENAME 2 +#define SCE_REG_STRING 3 +#define SCE_REG_HEXDIGIT 4 +#define SCE_REG_VALUETYPE 5 +#define SCE_REG_ADDEDKEY 6 +#define SCE_REG_DELETEDKEY 7 +#define SCE_REG_ESCAPED 8 +#define SCE_REG_KEYPATH_GUID 9 +#define SCE_REG_STRING_GUID 10 +#define SCE_REG_PARAMETER 11 +#define SCE_REG_OPERATOR 12 +#define SCE_BIBTEX_DEFAULT 0 +#define SCE_BIBTEX_ENTRY 1 +#define SCE_BIBTEX_UNKNOWN_ENTRY 2 +#define SCE_BIBTEX_KEY 3 +#define SCE_BIBTEX_PARAMETER 4 +#define SCE_BIBTEX_VALUE 5 +#define SCE_BIBTEX_COMMENT 6 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif diff --git a/src/stc/scintilla/include/Scintilla.h b/src/stc/scintilla/include/Scintilla.h index a769398d8a..6fc75c3696 100644 --- a/src/stc/scintilla/include/Scintilla.h +++ b/src/stc/scintilla/include/Scintilla.h @@ -18,9 +18,9 @@ extern "C" { #if defined(_WIN32) /* Return false on failure: */ int Scintilla_RegisterClasses(void *hInstance); -int Scintilla_ReleaseResources(); +int Scintilla_ReleaseResources(void); #endif -int Scintilla_LinkLexers(); +int Scintilla_LinkLexers(void); #ifdef __cplusplus } @@ -103,8 +103,15 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define SCI_SETBUFFEREDDRAW 2035 #define SCI_SETTABWIDTH 2036 #define SCI_GETTABWIDTH 2121 +#define SCI_CLEARTABSTOPS 2675 +#define SCI_ADDTABSTOP 2676 +#define SCI_GETNEXTTABSTOP 2677 #define SC_CP_UTF8 65001 #define SCI_SETCODEPAGE 2037 +#define SC_IME_WINDOWED 0 +#define SC_IME_INLINE 1 +#define SCI_GETIMEINTERACTION 2678 +#define SCI_SETIMEINTERACTION 2679 #define MARKER_MAX 31 #define SC_MARK_CIRCLE 0 #define SC_MARK_ROUNDRECT 1 @@ -278,7 +285,9 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define INDIC_DOTBOX 12 #define INDIC_SQUIGGLEPIXMAP 13 #define INDIC_COMPOSITIONTHICK 14 -#define INDIC_MAX 31 +#define INDIC_IME 32 +#define INDIC_IME_MAX 35 +#define INDIC_MAX 35 #define INDIC_CONTAINER 8 #define INDIC0_MASK 0x20 #define INDIC1_MASK 0x40 @@ -376,6 +385,7 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define SCFIND_WORDSTART 0x00100000 #define SCFIND_REGEXP 0x00200000 #define SCFIND_POSIX 0x00400000 +#define SCFIND_CXX11REGEX 0x00800000 #define SCI_FINDTEXT 2150 #define SCI_FORMATRANGE 2151 #define SCI_GETFIRSTVISIBLELINE 2152 @@ -528,6 +538,11 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define SCI_APPENDTEXT 2282 #define SCI_GETTWOPHASEDRAW 2283 #define SCI_SETTWOPHASEDRAW 2284 +#define SC_PHASES_ONE 0 +#define SC_PHASES_TWO 1 +#define SC_PHASES_MULTIPLE 2 +#define SCI_GETPHASESDRAW 2673 +#define SCI_SETPHASESDRAW 2674 #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 @@ -642,6 +657,8 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define SC_STATUS_OK 0 #define SC_STATUS_FAILURE 1 #define SC_STATUS_BADALLOC 2 +#define SC_STATUS_WARN_START 1000 +#define SC_STATUS_WARN_REGEX 1001 #define SCI_SETSTATUS 2382 #define SCI_GETSTATUS 2383 #define SCI_SETMOUSEDOWNCAPTURES 2384 @@ -812,6 +829,7 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define ANNOTATION_HIDDEN 0 #define ANNOTATION_STANDARD 1 #define ANNOTATION_BOXED 2 +#define ANNOTATION_INDENTED 3 #define SCI_ANNOTATIONSETVISIBLE 2548 #define SCI_ANNOTATIONGETVISIBLE 2549 #define SCI_ANNOTATIONSETSTYLEOFFSET 2550 @@ -891,6 +909,8 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define SCI_SCROLLTOEND 2629 #define SC_TECHNOLOGY_DEFAULT 0 #define SC_TECHNOLOGY_DIRECTWRITE 1 +#define SC_TECHNOLOGY_DIRECTWRITERETAIN 2 +#define SC_TECHNOLOGY_DIRECTWRITEDC 3 #define SCI_SETTECHNOLOGY 2630 #define SCI_GETTECHNOLOGY 2631 #define SCI_CREATELOADER 2632 @@ -963,7 +983,8 @@ inline int isascii(int c) { return !(c & ~0x7F); } #define SC_MOD_CONTAINER 0x40000 #define SC_MOD_LEXERSTATE 0x80000 #define SC_MOD_INSERTCHECK 0x100000 -#define SC_MODEVENTMASKALL 0x1FFFFF +#define SC_MOD_CHANGETABSTOPS 0x200000 +#define SC_MODEVENTMASKALL 0x3FFFFF #define SC_UPDATE_CONTENT 0x1 #define SC_UPDATE_SELECTION 0x2 #define SC_UPDATE_V_SCROLL 0x4 diff --git a/src/stc/scintilla/include/Scintilla.iface b/src/stc/scintilla/include/Scintilla.iface index 3e5f51b9cf..ca54c65ee8 100644 --- a/src/stc/scintilla/include/Scintilla.iface +++ b/src/stc/scintilla/include/Scintilla.iface @@ -226,6 +226,15 @@ set void SetTabWidth=2036(int tabWidth,) # Retrieve the visible size of a tab. get int GetTabWidth=2121(,) +# Clear explicit tabstops on a line. +fun void ClearTabStops=2675(int line,) + +# Add an explicit tab stop for a line. +fun void AddTabStop=2676(int line, int x) + +# Find the next explicit tab stop position on a line after a position. +fun int GetNextTabStop=2677(int line, int x) + # The SC_CP_UTF8 value can be used to enter Unicode mode. # This is the same value as CP_UTF8 in Windows val SC_CP_UTF8=65001 @@ -234,6 +243,16 @@ val SC_CP_UTF8=65001 # The SC_CP_UTF8 value can be used to enter Unicode mode. set void SetCodePage=2037(int codePage,) +enu IMEInteraction=SC_IME_ +val SC_IME_WINDOWED=0 +val SC_IME_INLINE=1 + +# Is the IME displayed in a winow or inline? +get int GetIMEInteraction=2678(,) + +# Choose to display the the IME in a winow or inline. +set void SetIMEInteraction=2679(int imeInteraction,) + enu MarkerSymbol=SC_MARK_ val MARKER_MAX=31 val SC_MARK_CIRCLE=0 @@ -586,7 +605,9 @@ val INDIC_SQUIGGLELOW=11 val INDIC_DOTBOX=12 val INDIC_SQUIGGLEPIXMAP=13 val INDIC_COMPOSITIONTHICK=14 -val INDIC_MAX=31 +val INDIC_IME=32 +val INDIC_IME_MAX=35 +val INDIC_MAX=35 val INDIC_CONTAINER=8 val INDIC0_MASK=0x20 val INDIC1_MASK=0x40 @@ -865,6 +886,7 @@ val SCFIND_MATCHCASE=0x4 val SCFIND_WORDSTART=0x00100000 val SCFIND_REGEXP=0x00200000 val SCFIND_POSIX=0x00400000 +val SCFIND_CXX11REGEX=0x00800000 # Find some text in the document. fun position FindText=2150(int flags, findtext ft) @@ -1291,13 +1313,27 @@ get bool GetVScrollBar=2281(,) # Append a string to the end of the document without changing the selection. fun void AppendText=2282(int length, string text) -# Is drawing done in two phases with backgrounds drawn before faoregrounds? +# Is drawing done in two phases with backgrounds drawn before foregrounds? get bool GetTwoPhaseDraw=2283(,) # In twoPhaseDraw mode, drawing is performed in two phases, first the background # and then the foreground. This avoids chopping off characters that overlap the next run. set void SetTwoPhaseDraw=2284(bool twoPhase,) +enu FontQuality=SC_PHASES_ +val SC_PHASES_ONE=0 +val SC_PHASES_TWO=1 +val SC_PHASES_MULTIPLE=2 + +# How many phases is drawing done in? +get int GetPhasesDraw=2673(,) + +# In one phase draw, text is drawn in a series of rectangular blocks with no overlap. +# In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. +# In multiple phase draw, each element is drawn over the whole drawing area, allowing text +# to overlap from one line to the next. +set void SetPhasesDraw=2674(int phases,) + # Control font anti-aliasing. enu FontQuality=SC_EFF_ @@ -1628,6 +1664,8 @@ enu Status=SC_STATUS_ val SC_STATUS_OK=0 val SC_STATUS_FAILURE=1 val SC_STATUS_BADALLOC=2 +val SC_STATUS_WARN_START=1000 +val SC_STATUS_WARN_REGEX=1001 # Change error status - 0 = OK. set void SetStatus=2382(int statusCode,) @@ -2119,6 +2157,7 @@ enu AnnotationVisible=ANNOTATION_ val ANNOTATION_HIDDEN=0 val ANNOTATION_STANDARD=1 val ANNOTATION_BOXED=2 +val ANNOTATION_INDENTED=3 # Set the visibility for the annotations for a view set void AnnotationSetVisible=2548(int visible,) @@ -2326,6 +2365,8 @@ fun void ScrollToEnd=2629(,) val SC_TECHNOLOGY_DEFAULT=0 val SC_TECHNOLOGY_DIRECTWRITE=1 +val SC_TECHNOLOGY_DIRECTWRITERETAIN=2 +val SC_TECHNOLOGY_DIRECTWRITEDC=3 # Set the technology used. set void SetTechnology=2630(int technology,) @@ -2509,7 +2550,8 @@ val SC_MOD_CHANGEANNOTATION=0x20000 val SC_MOD_CONTAINER=0x40000 val SC_MOD_LEXERSTATE=0x80000 val SC_MOD_INSERTCHECK=0x100000 -val SC_MODEVENTMASKALL=0x1FFFFF +val SC_MOD_CHANGETABSTOPS=0x200000 +val SC_MODEVENTMASKALL=0x3FFFFF enu Update=SC_UPDATE_ val SC_UPDATE_CONTENT=0x1 @@ -2675,6 +2717,8 @@ val SCLEX_RUST=111 val SCLEX_DMAP=112 val SCLEX_AS=113 val SCLEX_DMIS=114 +val SCLEX_REGISTRY=115 +val SCLEX_BIBTEX=116 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -3567,6 +3611,7 @@ val SCE_KIX_MACRO=6 val SCE_KIX_KEYWORD=7 val SCE_KIX_FUNCTIONS=8 val SCE_KIX_OPERATOR=9 +val SCE_KIX_COMMENTSTREAM=10 val SCE_KIX_IDENTIFIER=31 # Lexical states for SCLEX_GUI4CLI lex Gui4Cli=SCLEX_GUI4CLI SCE_GC_ @@ -3677,6 +3722,7 @@ val SCE_VHDL_STDFUNCTION=11 val SCE_VHDL_STDPACKAGE=12 val SCE_VHDL_STDTYPE=13 val SCE_VHDL_USERWORD=14 +val SCE_VHDL_BLOCK_COMMENT=15 # Lexical states for SCLEX_CAML lex Caml=SCLEX_CAML SCE_CAML_ val SCE_CAML_DEFAULT=0 @@ -3798,6 +3844,7 @@ val SCE_SQL_USER2=20 val SCE_SQL_USER3=21 val SCE_SQL_USER4=22 val SCE_SQL_QUOTEDIDENTIFIER=23 +val SCE_SQL_QOPERATOR=24 # Lexical states for SCLEX_SMALLTALK lex Smalltalk=SCLEX_SMALLTALK SCE_ST_ val SCE_ST_DEFAULT=0 @@ -4443,6 +4490,9 @@ val SCE_RUST_IDENTIFIER=17 val SCE_RUST_LIFETIME=18 val SCE_RUST_MACRO=19 val SCE_RUST_LEXERROR=20 +val SCE_RUST_BYTESTRING=21 +val SCE_RUST_BYTESTRINGR=22 +val SCE_RUST_BYTECHARACTER=23 # Lexical states for SCLEX_DMAP lex DMAP=SCLEX_DMAP SCE_DMAP_ val SCE_DMAP_DEFAULT=0 @@ -4468,6 +4518,30 @@ val SCE_DMIS_MINORWORD=6 val SCE_DMIS_UNSUPPORTED_MAJOR=7 val SCE_DMIS_UNSUPPORTED_MINOR=8 val SCE_DMIS_LABEL=9 +# Lexical states for SCLEX_REGISTRY +lex REG=SCLEX_REGISTRY SCE_REG_ +val SCE_REG_DEFAULT=0 +val SCE_REG_COMMENT=1 +val SCE_REG_VALUENAME=2 +val SCE_REG_STRING=3 +val SCE_REG_HEXDIGIT=4 +val SCE_REG_VALUETYPE=5 +val SCE_REG_ADDEDKEY=6 +val SCE_REG_DELETEDKEY=7 +val SCE_REG_ESCAPED=8 +val SCE_REG_KEYPATH_GUID=9 +val SCE_REG_STRING_GUID=10 +val SCE_REG_PARAMETER=11 +val SCE_REG_OPERATOR=12 +# Lexical state for SCLEX_BIBTEX +lex BibTeX=SCLEX_BIBTEX SCE_BIBTEX_ +val SCE_BIBTEX_DEFAULT=0 +val SCE_BIBTEX_ENTRY=1 +val SCE_BIBTEX_UNKNOWN_ENTRY=2 +val SCE_BIBTEX_KEY=3 +val SCE_BIBTEX_PARAMETER=4 +val SCE_BIBTEX_VALUE=5 +val SCE_BIBTEX_COMMENT=6 # Events diff --git a/src/stc/scintilla/lexers/LexBibTeX.cxx b/src/stc/scintilla/lexers/LexBibTeX.cxx new file mode 100644 index 0000000000..cdbce8d493 --- /dev/null +++ b/src/stc/scintilla/lexers/LexBibTeX.cxx @@ -0,0 +1,310 @@ +// Copyright 2008-2010 Sergiu Dotenco. The License.txt file describes the +// conditions under which this software may be distributed. + +/** + * @file LexBibTeX.cxx + * @brief General BibTeX coloring scheme. + * @author Sergiu Dotenco + * @date April 18, 2009 + */ + +#include +#include + +#include +#include + +#include +#include +#include + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "PropSetSimple.h" +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +namespace { + bool IsAlphabetic(unsigned int ch) + { + return IsASCII(ch) && std::isalpha(ch) != 0; + } + bool IsAlphaNumeric(char ch) + { + return IsASCII(ch) && std::isalnum(ch); + } + + bool EqualCaseInsensitive(const char* a, const char* b) + { + return CompareCaseInsensitive(a, b) == 0; + } + + bool EntryWithoutKey(const char* name) + { + return EqualCaseInsensitive(name,"string"); + } + + char GetClosingBrace(char openbrace) + { + char result = openbrace; + + switch (openbrace) { + case '(': result = ')'; break; + case '{': result = '}'; break; + } + + return result; + } + + bool IsEntryStart(char prev, char ch) + { + return prev != '\\' && ch == '@'; + } + + bool IsEntryStart(const StyleContext& sc) + { + return IsEntryStart(sc.chPrev, sc.ch); + } + + void ColorizeBibTeX(unsigned start_pos, int length, int /*init_style*/, WordList* keywordlists[], Accessor& styler) + { + WordList &EntryNames = *keywordlists[0]; + bool fold_compact = styler.GetPropertyInt("fold.compact", 1) != 0; + + std::string buffer; + buffer.reserve(25); + + // We always colorize a section from the beginning, so let's + // search for the @ character which isn't escaped, i.e. \@ + while (start_pos > 0 && !IsEntryStart(styler.SafeGetCharAt(start_pos - 1), + styler.SafeGetCharAt(start_pos))) { + --start_pos; ++length; + } + + styler.StartAt(start_pos); + styler.StartSegment(start_pos); + + int current_line = styler.GetLine(start_pos); + int prev_level = styler.LevelAt(current_line) & SC_FOLDLEVELNUMBERMASK; + int current_level = prev_level; + int visible_chars = 0; + + bool in_comment = false ; + StyleContext sc(start_pos, length, SCE_BIBTEX_DEFAULT, styler); + + bool going = sc.More(); // needed because of a fuzzy end of file state + char closing_brace = 0; + bool collect_entry_name = false; + + for (; going; sc.Forward()) { + if (!sc.More()) + going = false; // we need to go one behind the end of text + + if (in_comment) { + if (sc.atLineEnd) { + sc.SetState(SCE_BIBTEX_DEFAULT); + in_comment = false; + } + } + else { + // Found @entry + if (IsEntryStart(sc)) { + sc.SetState(SCE_BIBTEX_UNKNOWN_ENTRY); + sc.Forward(); + ++current_level; + + buffer.clear(); + collect_entry_name = true; + } + else if ((sc.state == SCE_BIBTEX_ENTRY || sc.state == SCE_BIBTEX_UNKNOWN_ENTRY) + && (sc.ch == '{' || sc.ch == '(')) { + // Entry name colorization done + // Found either a { or a ( after entry's name, e.g. @entry(...) @entry{...} + // Closing counterpart needs to be stored. + closing_brace = GetClosingBrace(sc.ch); + + sc.SetState(SCE_BIBTEX_DEFAULT); // Don't colorize { ( + + // @string doesn't have any key + if (EntryWithoutKey(buffer.c_str())) + sc.ForwardSetState(SCE_BIBTEX_PARAMETER); + else + sc.ForwardSetState(SCE_BIBTEX_KEY); // Key/label colorization + } + + // Need to handle the case where entry's key is empty + // e.g. @book{,...} + if (sc.state == SCE_BIBTEX_KEY && sc.ch == ',') { + // Key/label colorization done + sc.SetState(SCE_BIBTEX_DEFAULT); // Don't colorize the , + sc.ForwardSetState(SCE_BIBTEX_PARAMETER); // Parameter colorization + } + else if (sc.state == SCE_BIBTEX_PARAMETER && sc.ch == '=') { + sc.SetState(SCE_BIBTEX_DEFAULT); // Don't colorize the = + sc.ForwardSetState(SCE_BIBTEX_VALUE); // Parameter value colorization + + int start = sc.currentPos; + + // We need to handle multiple situations: + // 1. name"one two {three}" + // 2. name={one {one two {two}} three} + // 3. year=2005 + + // Skip ", { until we encounter the first alphanumerical character + while (sc.More() && !(IsAlphaNumeric(sc.ch) || sc.ch == '"' || sc.ch == '{')) + sc.Forward(); + + if (sc.More()) { + // Store " or { + char ch = sc.ch; + + // Not interested in alphanumerical characters + if (IsAlphaNumeric(ch)) + ch = 0; + + int skipped = 0; + + if (ch) { + // Skip preceding " or { such as in name={{test}}. + // Remember how many characters have been skipped + // Make sure that empty values, i.e. "" are also handled correctly + while (sc.More() && (sc.ch == ch && (ch != '"' || skipped < 1))) { + sc.Forward(); + ++skipped; + } + } + + // Closing counterpart for " is the same character + if (ch == '{') + ch = '}'; + + // We have reached the parameter value + // In case the open character was a alnum char, skip until , is found + // otherwise until skipped == 0 + while (sc.More() && (skipped > 0 || (!ch && !(sc.ch == ',' || sc.ch == closing_brace)))) { + // Make sure the character isn't escaped + if (sc.chPrev != '\\') { + // Parameter value contains a { which is the 2nd case described above + if (sc.ch == '{') + ++skipped; // Remember it + else if (sc.ch == '}') + --skipped; + else if (skipped == 1 && sc.ch == ch && ch == '"') // Don't ignore cases like {"o} + skipped = 0; + } + + sc.Forward(); + } + } + + // Don't colorize the , + sc.SetState(SCE_BIBTEX_DEFAULT); + + // Skip until the , or entry's closing closing_brace is found + // since this parameter might be the last one + while (sc.More() && !(sc.ch == ',' || sc.ch == closing_brace)) + sc.Forward(); + + int state = SCE_BIBTEX_PARAMETER; // The might be more parameters + + // We've reached the closing closing_brace for the bib entry + // in case no " or {} has been used to enclose the value, + // as in 3rd case described above + if (sc.ch == closing_brace) { + --current_level; + // Make sure the text between entries is not colored + // using parameter's style + state = SCE_BIBTEX_DEFAULT; + } + + int end = sc.currentPos; + current_line = styler.GetLine(end); + + // We have possibly skipped some lines, so the folding levels + // have to be adjusted separately + for (int i = styler.GetLine(start); i <= styler.GetLine(end); ++i) + styler.SetLevel(i, prev_level); + + sc.ForwardSetState(state); + } + + if (sc.state == SCE_BIBTEX_PARAMETER && sc.ch == closing_brace) { + sc.SetState(SCE_BIBTEX_DEFAULT); + --current_level; + } + + // Non escaped % found which represents a comment until the end of the line + if (sc.chPrev != '\\' && sc.ch == '%') { + in_comment = true; + sc.SetState(SCE_BIBTEX_COMMENT); + } + } + + if (sc.state == SCE_BIBTEX_UNKNOWN_ENTRY || sc.state == SCE_BIBTEX_ENTRY) { + if (!IsAlphabetic(sc.ch) && collect_entry_name) + collect_entry_name = false; + + if (collect_entry_name) { + buffer += static_cast(tolower(sc.ch)); + if (EntryNames.InList(buffer.c_str())) + sc.ChangeState(SCE_BIBTEX_ENTRY); + else + sc.ChangeState(SCE_BIBTEX_UNKNOWN_ENTRY); + } + } + + if (sc.atLineEnd) { + int level = prev_level; + + if (visible_chars == 0 && fold_compact) + level |= SC_FOLDLEVELWHITEFLAG; + + if ((current_level > prev_level)) + level |= SC_FOLDLEVELHEADERFLAG; + // else if (current_level < prev_level) + // level |= SC_FOLDLEVELBOXFOOTERFLAG; // Deprecated + + if (level != styler.LevelAt(current_line)) { + styler.SetLevel(current_line, level); + } + + ++current_line; + prev_level = current_level; + visible_chars = 0; + } + + if (!isspacechar(sc.ch)) + ++visible_chars; + } + + sc.Complete(); + + // Fill in the real level of the next line, keeping the current flags as they will be filled in later + int flagsNext = styler.LevelAt(current_line) & ~SC_FOLDLEVELNUMBERMASK; + styler.SetLevel(current_line, prev_level | flagsNext); + } +} +static const char * const BibTeXWordLists[] = { + "Entry Names", + 0, +}; + + +LexerModule lmBibTeX(SCLEX_BIBTEX, ColorizeBibTeX, "bib", 0, BibTeXWordLists); + +// Entry Names +// article, book, booklet, conference, inbook, +// incollection, inproceedings, manual, mastersthesis, +// misc, phdthesis, proceedings, techreport, unpublished, +// string, url + diff --git a/src/stc/scintilla/lexers/LexCoffeeScript.cxx b/src/stc/scintilla/lexers/LexCoffeeScript.cxx index c52a5a42bf..1667683218 100644 --- a/src/stc/scintilla/lexers/LexCoffeeScript.cxx +++ b/src/stc/scintilla/lexers/LexCoffeeScript.cxx @@ -31,11 +31,8 @@ using namespace Scintilla; #endif static bool IsSpaceEquiv(int state) { - return (state <= SCE_COFFEESCRIPT_COMMENTDOC - // including SCE_COFFEESCRIPT_DEFAULT, SCE_COFFEESCRIPT_COMMENT, SCE_COFFEESCRIPT_COMMENTLINE - || state == SCE_COFFEESCRIPT_COMMENTLINEDOC - || state == SCE_COFFEESCRIPT_COMMENTDOCKEYWORD - || state == SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR + return (state == SCE_COFFEESCRIPT_DEFAULT + || state == SCE_COFFEESCRIPT_COMMENTLINE || state == SCE_COFFEESCRIPT_COMMENTBLOCK || state == SCE_COFFEESCRIPT_VERBOSE_REGEX || state == SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT @@ -88,51 +85,16 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; - WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; - // 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; - CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-"); CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-"); - 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) { - setWordStart.Add('$'); - setWord.Add('$'); - } + CharacterSet setWordStart(CharacterSet::setAlpha, "_$@", 0x80, true); + CharacterSet setWord(CharacterSet::setAlphaNum, "._$", 0x80, true); int chPrevNonWhite = ' '; int visibleChars = 0; - bool lastWordWasUUID = false; - int styleBeforeDCKeyword = SCE_COFFEESCRIPT_DEFAULT; - bool continuationLine = false; - bool isIncludePreprocessor = false; - - if (initStyle == SCE_COFFEESCRIPT_PREPROCESSOR) { - // 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); - int lineEndChar = '!'; - if (chBack2 == '\r' && chBack == '\n') { - lineEndChar = styler.SafeGetCharAt(startPos-3, 0); - } else if (chBack == '\n' || chBack == '\r') { - lineEndChar = chBack2; - } - continuationLine = lineEndChar == '\\'; - } - } // look back to set chPrevNonWhite properly for better regex colouring int endPos = startPos + length; @@ -161,20 +123,6 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init // Reset states to beginning of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; - lastWordWasUUID = false; - isIncludePreprocessor = false; - } - - // Handle line continuation generically. - if (sc.ch == '\\') { - if (sc.chNext == '\n' || sc.chNext == '\r') { - sc.Forward(); - if (sc.ch == '\r' && sc.chNext == '\n') { - sc.Forward(); - } - continuationLine = true; - continue; - } } // Determine if the current state should terminate. @@ -193,7 +141,6 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init char s[1000]; sc.GetCurrent(s, sizeof(s)); if (keywords.InList(s)) { - lastWordWasUUID = strcmp(s, "uuid") == 0; sc.ChangeState(SCE_COFFEESCRIPT_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_COFFEESCRIPT_WORD2); @@ -210,74 +157,13 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init sc.SetState(SCE_COFFEESCRIPT_DEFAULT); } break; - case SCE_COFFEESCRIPT_PREPROCESSOR: - if (sc.atLineStart && !continuationLine) { - sc.SetState(SCE_COFFEESCRIPT_DEFAULT); - } else if (stylingWithinPreprocessor) { - if (IsASpace(sc.ch)) { - sc.SetState(SCE_COFFEESCRIPT_DEFAULT); - } - } else { - if (sc.Match('/', '*') || sc.Match('/', '/')) { - sc.SetState(SCE_COFFEESCRIPT_DEFAULT); - } - } - break; - case SCE_COFFEESCRIPT_COMMENT: - if (sc.Match('*', '/')) { - sc.Forward(); - sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT); - } - break; - case SCE_COFFEESCRIPT_COMMENTDOC: - if (sc.Match('*', '/')) { - sc.Forward(); - sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT); - } 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_COFFEESCRIPT_COMMENTDOC; - sc.SetState(SCE_COFFEESCRIPT_COMMENTDOCKEYWORD); - } - } - break; case SCE_COFFEESCRIPT_COMMENTLINE: if (sc.atLineStart) { sc.SetState(SCE_COFFEESCRIPT_DEFAULT); } break; - case SCE_COFFEESCRIPT_COMMENTLINEDOC: - if (sc.atLineStart) { - sc.SetState(SCE_COFFEESCRIPT_DEFAULT); - } 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_COFFEESCRIPT_COMMENTLINEDOC; - sc.SetState(SCE_COFFEESCRIPT_COMMENTDOCKEYWORD); - } - } - break; - case SCE_COFFEESCRIPT_COMMENTDOCKEYWORD: - if ((styleBeforeDCKeyword == SCE_COFFEESCRIPT_COMMENTDOC) && sc.Match('*', '/')) { - sc.ChangeState(SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR); - sc.Forward(); - sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT); - } else if (!setDoxygen.Contains(sc.ch)) { - char s[100]; - sc.GetCurrent(s, sizeof(s)); - if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) { - sc.ChangeState(SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR); - } - sc.SetState(styleBeforeDCKeyword); - } - break; case SCE_COFFEESCRIPT_STRING: - if (isIncludePreprocessor) { - if (sc.ch == '>') { - sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT); - isIncludePreprocessor = false; - } - } else if (sc.ch == '\\') { + if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } @@ -314,20 +200,6 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init sc.SetState(SCE_COFFEESCRIPT_DEFAULT); } break; - case SCE_COFFEESCRIPT_VERBATIM: - if (sc.ch == '\"') { - if (sc.chNext == '\"') { - sc.Forward(); - } else { - sc.ForwardSetState(SCE_COFFEESCRIPT_DEFAULT); - } - } - break; - case SCE_COFFEESCRIPT_UUID: - if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') { - sc.SetState(SCE_COFFEESCRIPT_DEFAULT); - } - break; case SCE_COFFEESCRIPT_COMMENTBLOCK: if (sc.Match("###")) { sc.Forward(); @@ -357,30 +229,10 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init // Determine if a new state should be entered. if (sc.state == SCE_COFFEESCRIPT_DEFAULT) { - if (sc.Match('@', '\"')) { - sc.SetState(SCE_COFFEESCRIPT_VERBATIM); - sc.Forward(); - } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { - if (lastWordWasUUID) { - sc.SetState(SCE_COFFEESCRIPT_UUID); - lastWordWasUUID = false; - } else { - sc.SetState(SCE_COFFEESCRIPT_NUMBER); - } - } else if (setWordStart.Contains(sc.ch) || (sc.ch == '@') || (sc.ch == '$')) { - if (lastWordWasUUID) { - sc.SetState(SCE_COFFEESCRIPT_UUID); - lastWordWasUUID = false; - } else { - sc.SetState(SCE_COFFEESCRIPT_IDENTIFIER); - } - } else if (sc.Match('/', '*')) { - if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style - sc.SetState(SCE_COFFEESCRIPT_COMMENTDOC); - } else { - sc.SetState(SCE_COFFEESCRIPT_COMMENT); - } - sc.Forward(); // Eat the * so it isn't used for the end of the comment + if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + sc.SetState(SCE_COFFEESCRIPT_NUMBER); + } else if (setWordStart.Contains(sc.ch)) { + sc.SetState(SCE_COFFEESCRIPT_IDENTIFIER); } else if (sc.Match("///")) { sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX); sc.Forward(); @@ -393,9 +245,6 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init sc.SetState(SCE_COFFEESCRIPT_REGEX); // JavaScript's RegEx } else if (sc.ch == '\"') { sc.SetState(SCE_COFFEESCRIPT_STRING); - isIncludePreprocessor = false; // ensure that '>' won't end the string - } else if (isIncludePreprocessor && sc.ch == '<') { - sc.SetState(SCE_COFFEESCRIPT_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_COFFEESCRIPT_CHARACTER); } else if (sc.ch == '#') { @@ -403,7 +252,6 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init sc.SetState(SCE_COFFEESCRIPT_COMMENTBLOCK); sc.Forward(); sc.Forward(); - } else { sc.SetState(SCE_COFFEESCRIPT_COMMENTLINE); } @@ -416,7 +264,6 @@ static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int init chPrevNonWhite = sc.ch; visibleChars++; } - continuationLine = false; } sc.Complete(); } @@ -428,10 +275,6 @@ static bool IsCommentLine(int line, Accessor &styler) { char ch = styler[i]; if (ch == '#') return true; - else if (ch == '/' - && i < eol_pos - 1 - && styler[i + 1] == '*') - return true; else if (ch != ' ' && ch != '\t') return false; } @@ -563,6 +406,9 @@ static void FoldCoffeeScriptDoc(unsigned int startPos, int length, int, static const char *const csWordLists[] = { "Keywords", + "Secondary keywords", + "Unused", + "Global classes", 0, }; diff --git a/src/stc/scintilla/lexers/LexHTML.cxx b/src/stc/scintilla/lexers/LexHTML.cxx index d6b0b31bcb..02047930ce 100644 --- a/src/stc/scintilla/lexers/LexHTML.cxx +++ b/src/stc/scintilla/lexers/LexHTML.cxx @@ -822,19 +822,27 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty // handle start of Mako comment line if (isMako && ch == '#' && chNext == '#') { makoComment = 1; + state = SCE_HP_COMMENTLINE; } // handle end of Mako comment line else if (isMako && makoComment && (ch == '\r' || ch == '\n')) { makoComment = 0; - styler.ColourTo(i, SCE_HP_COMMENTLINE); - state = SCE_HP_DEFAULT; + styler.ColourTo(i, StateToPrint); + if (scriptLanguage == eScriptPython) { + state = SCE_HP_DEFAULT; + } else { + state = SCE_H_DEFAULT; + } } // Allow falling through to mako handling code if newline is going to end a block if (((ch == '\r' && chNext != '\n') || (ch == '\n')) && (!isMako || (0 != strcmp(makoBlockType, "%")))) { } + // Ignore everything in mako comment until the line ends + else if (isMako && makoComment) { + } // generic end of script processing else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) { diff --git a/src/stc/scintilla/lexers/LexKix.cxx b/src/stc/scintilla/lexers/LexKix.cxx index 32af263fdf..dc509e4caa 100644 --- a/src/stc/scintilla/lexers/LexKix.cxx +++ b/src/stc/scintilla/lexers/LexKix.cxx @@ -4,6 +4,7 @@ **/ // Copyright 2004 by Manfred Becker // The License.txt file describes the conditions under which this software may be distributed. +// Edited by Lee Wilmott (24-Jun-2014) added support for block comments #include #include @@ -54,6 +55,10 @@ static void ColouriseKixDoc(unsigned int startPos, int length, int initStyle, if (sc.atLineEnd) { sc.SetState(SCE_KIX_DEFAULT); } + } else if (sc.state == SCE_KIX_COMMENTSTREAM) { + if (sc.ch == '/' && sc.chPrev == '*') { + sc.ForwardSetState(SCE_KIX_DEFAULT); + } } else if (sc.state == SCE_KIX_STRING1) { // This is a doubles quotes string if (sc.ch == '\"') { @@ -104,6 +109,8 @@ static void ColouriseKixDoc(unsigned int startPos, int length, int initStyle, if (sc.state == SCE_KIX_DEFAULT) { if (sc.ch == ';') { sc.SetState(SCE_KIX_COMMENT); + } else if (sc.ch == '/' && sc.chNext == '*') { + sc.SetState(SCE_KIX_COMMENTSTREAM); } else if (sc.ch == '\"') { sc.SetState(SCE_KIX_STRING1); } else if (sc.ch == '\'') { diff --git a/src/stc/scintilla/lexers/LexMatlab.cxx b/src/stc/scintilla/lexers/LexMatlab.cxx index a8ac03cc7f..4dfd512c83 100644 --- a/src/stc/scintilla/lexers/LexMatlab.cxx +++ b/src/stc/scintilla/lexers/LexMatlab.cxx @@ -12,6 +12,9 @@ ** - added ... displayed as a comment ** - removed unused IsAWord functions ** - added some comments + ** + ** Changes by John Donoghue 2014/08/01 + ** - fix allowed transpose ' after {} operator **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. @@ -218,7 +221,7 @@ static void ColouriseMatlabOctaveDoc( } else if (isalpha(sc.ch)) { sc.SetState(SCE_MATLAB_KEYWORD); } else if (isoperator(static_cast(sc.ch)) || sc.ch == '@' || sc.ch == '\\') { - if (sc.ch == ')' || sc.ch == ']') { + if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') { transpose = true; } else { transpose = false; diff --git a/src/stc/scintilla/lexers/LexRegistry.cxx b/src/stc/scintilla/lexers/LexRegistry.cxx new file mode 100644 index 0000000000..0f401fa4b5 --- /dev/null +++ b/src/stc/scintilla/lexers/LexRegistry.cxx @@ -0,0 +1,416 @@ +// Scintilla source code edit control +/** + * @file LexRegistry.cxx + * @date July 26 2014 + * @brief Lexer for Windows registration files(.reg) + * @author nkmathew + * + * 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 "WordList.h" +#include "LexAccessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" +#include "OptionSet.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static const char *const RegistryWordListDesc[] = { + 0 +}; + +struct OptionsRegistry { + bool foldCompact; + bool fold; + OptionsRegistry() { + foldCompact = false; + fold = false; + } +}; + +struct OptionSetRegistry : public OptionSet { + OptionSetRegistry() { + DefineProperty("fold.compact", &OptionsRegistry::foldCompact); + DefineProperty("fold", &OptionsRegistry::fold); + DefineWordListSets(RegistryWordListDesc); + } +}; + +class LexerRegistry : public ILexer { + OptionsRegistry options; + OptionSetRegistry optSetRegistry; + + static bool IsStringState(int state) { + return (state == SCE_REG_VALUENAME || state == SCE_REG_STRING); + } + + static bool IsKeyPathState(int state) { + return (state == SCE_REG_ADDEDKEY || state == SCE_REG_DELETEDKEY); + } + + static bool AtValueType(LexAccessor &styler, int start) { + int i = 0; + while (i < 10) { + i++; + char curr = styler.SafeGetCharAt(start+i, '\0'); + if (curr == ':') { + return true; + } else if (!curr) { + return false; + } + } + return false; + } + + static bool IsNextNonWhitespace(LexAccessor &styler, int start, char ch) { + int i = 0; + while (i < 100) { + i++; + char curr = styler.SafeGetCharAt(start+i, '\0'); + char next = styler.SafeGetCharAt(start+i+1, '\0'); + bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n'); + if (curr == ch) { + return true; + } else if (!isspacechar(curr) || atEOL) { + return false; + } + } + return false; + } + + // Looks for the equal sign at the end of the string + static bool AtValueName(LexAccessor &styler, int start) { + bool atEOL = false; + int i = 0; + bool escaped = false; + while (!atEOL) { + i++; + char curr = styler.SafeGetCharAt(start+i, '\0'); + char next = styler.SafeGetCharAt(start+i+1, '\0'); + atEOL = (curr == '\r' && next != '\n') || (curr == '\n'); + if (escaped) { + escaped = false; + continue; + } + escaped = curr == '\\'; + if (curr == '"') { + return IsNextNonWhitespace(styler, start+i, '='); + } else if (!curr) { + return false; + } + } + return false; + } + + static bool AtKeyPathEnd(LexAccessor &styler, int start) { + bool atEOL = false; + int i = 0; + while (!atEOL) { + i++; + char curr = styler.SafeGetCharAt(start+i, '\0'); + char next = styler.SafeGetCharAt(start+i+1, '\0'); + atEOL = (curr == '\r' && next != '\n') || (curr == '\n'); + if (curr == ']' || !curr) { + // There's still at least one or more square brackets ahead + return false; + } + } + return true; + } + + static bool AtGUID(LexAccessor &styler, int start) { + int count = 8; + int portion = 0; + int offset = 1; + char digit = '\0'; + while (portion < 5) { + int i = 0; + while (i < count) { + digit = styler.SafeGetCharAt(start+offset); + if (!(isxdigit(digit) || digit == '-')) { + return false; + } + offset++; + i++; + } + portion++; + count = (portion == 4) ? 13 : 5; + } + digit = styler.SafeGetCharAt(start+offset); + if (digit == '}') { + return true; + } else { + return false; + } + } + +public: + LexerRegistry() {} + virtual ~LexerRegistry() {} + virtual int SCI_METHOD Version() const { + return lvOriginal; + } + virtual void SCI_METHOD Release() { + delete this; + } + virtual const char *SCI_METHOD PropertyNames() { + return optSetRegistry.PropertyNames(); + } + virtual int SCI_METHOD PropertyType(const char *name) { + return optSetRegistry.PropertyType(name); + } + virtual const char *SCI_METHOD DescribeProperty(const char *name) { + return optSetRegistry.DescribeProperty(name); + } + virtual int SCI_METHOD PropertySet(const char *key, const char *val) { + if (optSetRegistry.PropertySet(&options, key, val)) { + return 0; + } + return -1; + } + virtual int SCI_METHOD WordListSet(int, const char *) { + return -1; + } + virtual void *SCI_METHOD PrivateCall(int, void *) { + return 0; + } + static ILexer *LexerFactoryRegistry() { + return new LexerRegistry; + } + virtual const char *SCI_METHOD DescribeWordListSets() { + return optSetRegistry.DescribeWordListSets(); + } + virtual void SCI_METHOD Lex(unsigned startPos, + int length, + int initStyle, + IDocument *pAccess); + virtual void SCI_METHOD Fold(unsigned startPos, + int length, + int initStyle, + IDocument *pAccess); +}; + +void SCI_METHOD LexerRegistry::Lex(unsigned startPos, + int length, + int initStyle, + IDocument *pAccess) { + int beforeGUID = SCE_REG_DEFAULT; + int beforeEscape = SCE_REG_DEFAULT; + CharacterSet setOperators = CharacterSet(CharacterSet::setNone, "-,.=:\\@()"); + LexAccessor styler(pAccess); + StyleContext context(startPos, length, initStyle, styler); + bool highlight = true; + bool afterEqualSign = false; + while (context.More()) { + if (context.atLineStart) { + int currPos = static_cast(context.currentPos); + bool continued = styler[currPos-3] == '\\'; + highlight = continued ? true : false; + } + switch (context.state) { + case SCE_REG_COMMENT: + if (context.atLineEnd) { + context.SetState(SCE_REG_DEFAULT); + } + break; + case SCE_REG_VALUENAME: + case SCE_REG_STRING: { + int currPos = static_cast(context.currentPos); + if (context.ch == '"') { + context.ForwardSetState(SCE_REG_DEFAULT); + } else if (context.ch == '\\') { + beforeEscape = context.state; + context.SetState(SCE_REG_ESCAPED); + context.Forward(); + } else if (context.ch == '{') { + if (AtGUID(styler, currPos)) { + beforeGUID = context.state; + context.SetState(SCE_REG_STRING_GUID); + } + } + if (context.state == SCE_REG_STRING && + context.ch == '%' && + (isdigit(context.chNext) || context.chNext == '*')) { + context.SetState(SCE_REG_PARAMETER); + } + } + break; + case SCE_REG_PARAMETER: + context.ForwardSetState(SCE_REG_STRING); + if (context.ch == '"') { + context.ForwardSetState(SCE_REG_DEFAULT); + } + break; + case SCE_REG_VALUETYPE: + if (context.ch == ':') { + context.SetState(SCE_REG_DEFAULT); + afterEqualSign = false; + } + break; + case SCE_REG_HEXDIGIT: + case SCE_REG_OPERATOR: + context.SetState(SCE_REG_DEFAULT); + break; + case SCE_REG_DELETEDKEY: + case SCE_REG_ADDEDKEY: { + int currPos = static_cast(context.currentPos); + if (context.ch == ']' && AtKeyPathEnd(styler, currPos)) { + context.ForwardSetState(SCE_REG_DEFAULT); + } else if (context.ch == '{') { + if (AtGUID(styler, currPos)) { + beforeGUID = context.state; + context.SetState(SCE_REG_KEYPATH_GUID); + } + } + } + break; + case SCE_REG_ESCAPED: + if (context.ch == '"') { + context.SetState(beforeEscape); + context.ForwardSetState(SCE_REG_DEFAULT); + } else if (context.ch == '\\') { + context.Forward(); + } else { + context.SetState(beforeEscape); + beforeEscape = SCE_REG_DEFAULT; + } + break; + case SCE_REG_STRING_GUID: + case SCE_REG_KEYPATH_GUID: { + if (context.ch == '}') { + context.ForwardSetState(beforeGUID); + beforeGUID = SCE_REG_DEFAULT; + } + int currPos = static_cast(context.currentPos); + if (context.ch == '"' && IsStringState(context.state)) { + context.ForwardSetState(SCE_REG_DEFAULT); + } else if (context.ch == ']' && + AtKeyPathEnd(styler, currPos) && + IsKeyPathState(context.state)) { + context.ForwardSetState(SCE_REG_DEFAULT); + } else if (context.ch == '\\' && IsStringState(context.state)) { + beforeEscape = context.state; + context.SetState(SCE_REG_ESCAPED); + context.Forward(); + } + } + break; + } + // Determine if a new state should be entered. + if (context.state == SCE_REG_DEFAULT) { + int currPos = static_cast(context.currentPos); + if (context.ch == ';') { + context.SetState(SCE_REG_COMMENT); + } else if (context.ch == '"') { + if (AtValueName(styler, currPos)) { + context.SetState(SCE_REG_VALUENAME); + } else { + context.SetState(SCE_REG_STRING); + } + } else if (context.ch == '[') { + if (IsNextNonWhitespace(styler, currPos, '-')) { + context.SetState(SCE_REG_DELETEDKEY); + } else { + context.SetState(SCE_REG_ADDEDKEY); + } + } else if (context.ch == '=') { + afterEqualSign = true; + highlight = true; + } else if (afterEqualSign) { + bool wordStart = isalpha(context.ch) && !isalpha(context.chPrev); + if (wordStart && AtValueType(styler, currPos)) { + context.SetState(SCE_REG_VALUETYPE); + } + } else if (isxdigit(context.ch) && highlight) { + context.SetState(SCE_REG_HEXDIGIT); + } + highlight = (context.ch == '@') ? true : highlight; + if (setOperators.Contains(context.ch) && highlight) { + context.SetState(SCE_REG_OPERATOR); + } + } + context.Forward(); + } + context.Complete(); +} + +// Folding similar to that of FoldPropsDoc in LexOthers +void SCI_METHOD LexerRegistry::Fold(unsigned startPos, + int length, + int, + IDocument *pAccess) { + if (!options.fold) { + return; + } + LexAccessor styler(pAccess); + int currLine = styler.GetLine(startPos); + int visibleChars = 0; + unsigned endPos = startPos + length; + bool atKeyPath = false; + for (unsigned i = startPos; i < endPos; i++) { + atKeyPath = IsKeyPathState(styler.StyleAt(i)) ? true : atKeyPath; + char curr = styler.SafeGetCharAt(i); + char next = styler.SafeGetCharAt(i+1); + bool atEOL = (curr == '\r' && next != '\n') || (curr == '\n'); + if (atEOL || i == (endPos-1)) { + int level = SC_FOLDLEVELBASE; + if (currLine > 0) { + int prevLevel = styler.LevelAt(currLine-1); + if (prevLevel & SC_FOLDLEVELHEADERFLAG) { + level += 1; + } else { + level = prevLevel; + } + } + if (!visibleChars && options.foldCompact) { + level |= SC_FOLDLEVELWHITEFLAG; + } else if (atKeyPath) { + level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; + } + if (level != styler.LevelAt(currLine)) { + styler.SetLevel(currLine, level); + } + currLine++; + visibleChars = 0; + atKeyPath = false; + } + if (!isspacechar(curr)) { + visibleChars++; + } + } + + // Make the folding reach the last line in the file + int level = SC_FOLDLEVELBASE; + if (currLine > 0) { + int prevLevel = styler.LevelAt(currLine-1); + if (prevLevel & SC_FOLDLEVELHEADERFLAG) { + level += 1; + } else { + level = prevLevel; + } + } + styler.SetLevel(currLine, level); +} + +LexerModule lmRegistry(SCLEX_REGISTRY, + LexerRegistry::LexerFactoryRegistry, + "registry", + RegistryWordListDesc); + diff --git a/src/stc/scintilla/lexers/LexRuby.cxx b/src/stc/scintilla/lexers/LexRuby.cxx index f818d3d473..d4c3fad25d 100644 --- a/src/stc/scintilla/lexers/LexRuby.cxx +++ b/src/stc/scintilla/lexers/LexRuby.cxx @@ -882,6 +882,31 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, preferRE = false; } else if (isSafeWordcharOrHigh(chNext)) { state = SCE_RB_SYMBOL; + } else if ((chNext == '@' || chNext == '$') && + isSafeWordcharOrHigh(chNext2)) { + // instance and global variable followed by an identifier + advance_char(i, ch, chNext, chNext2); + state = SCE_RB_SYMBOL; + } else if (((chNext == '@' && chNext2 == '@') || + (chNext == '$' && chNext2 == '-')) && + isSafeWordcharOrHigh(styler.SafeGetCharAt(i+3))) { + // class variables and special global variable "$-IDENTCHAR" + state = SCE_RB_SYMBOL; + // $-IDENTCHAR doesn't continue past the IDENTCHAR + if (chNext == '$') { + styler.ColourTo(i+3, SCE_RB_SYMBOL); + state = SCE_RB_DEFAULT; + } + i += 3; + ch = styler.SafeGetCharAt(i); + chNext = styler.SafeGetCharAt(i+1); + } else if (chNext == '$' && strchr("_~*$?!@/\\;,.=:<>\"&`'+", chNext2)) { + // single-character special global variables + i += 2; + ch = chNext2; + chNext = styler.SafeGetCharAt(i+1); + styler.ColourTo(i, SCE_RB_SYMBOL); + state = SCE_RB_DEFAULT; } else if (strchr("[*!~+-*/%=<>&^|", chNext)) { // Do the operator analysis in-line, looking ahead // Based on the table in pickaxe 2nd ed., page 339 @@ -1260,7 +1285,16 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, } else if (state == SCE_RB_CLASS_VAR || state == SCE_RB_INSTANCE_VAR || state == SCE_RB_SYMBOL) { - if (!isSafeWordcharOrHigh(ch)) { + if (state == SCE_RB_SYMBOL && + // FIDs suffices '?' and '!' + (((ch == '!' || ch == '?') && chNext != '=') || + // identifier suffix '=' + (ch == '=' && (chNext != '~' && chNext != '>' && + (chNext != '=' || chNext2 == '>'))))) { + styler.ColourTo(i, state); + state = SCE_RB_DEFAULT; + preferRE = false; + } else if (!isSafeWordcharOrHigh(ch)) { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; diff --git a/src/stc/scintilla/lexers/LexRust.cxx b/src/stc/scintilla/lexers/LexRust.cxx index 8a30205327..3b1201c7f3 100644 --- a/src/stc/scintilla/lexers/LexRust.cxx +++ b/src/stc/scintilla/lexers/LexRust.cxx @@ -230,7 +230,9 @@ static void ScanIdentifier(Accessor& styler, int& pos, WordList *keywords) { } } -static void ScanDigits(Accessor& styler, int& pos, int base) { +/* Scans a sequence of digits, returning true if it found any. */ +static bool ScanDigits(Accessor& styler, int& pos, int base) { + int old_pos = pos; for (;;) { int c = styler.SafeGetCharAt(pos, '\0'); if (IsADigit(c, base) || c == '_') @@ -238,13 +240,17 @@ static void ScanDigits(Accessor& styler, int& pos, int base) { else break; } + return old_pos != pos; } +/* Scans an integer and floating point literals. */ static void ScanNumber(Accessor& styler, int& pos) { int base = 10; int c = styler.SafeGetCharAt(pos, '\0'); int n = styler.SafeGetCharAt(pos + 1, '\0'); bool error = false; + /* Scan the prefix, thus determining the base. + * 10 is default if there's no prefix. */ if (c == '0' && n == 'x') { pos += 2; base = 16; @@ -255,8 +261,11 @@ static void ScanNumber(Accessor& styler, int& pos) { pos += 2; base = 8; } - int old_pos = pos; - ScanDigits(styler, pos, base); + + /* Scan initial digits. The literal is malformed if there are none. */ + error |= !ScanDigits(styler, pos, base); + /* See if there's an integer suffix. We mimic the Rust's lexer + * and munch it even if there was an error above. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'u' || c == 'i') { pos++; @@ -271,14 +280,22 @@ static void ScanNumber(Accessor& styler, int& pos) { } else if (c == '6' && n == '4') { pos += 2; } - } else { + /* See if it's a floating point literal. These literals have to be base 10. + */ + } else if (!error) { + /* If there's a period, it's a floating point literal unless it's + * followed by an identifier (meaning this is a method call, e.g. + * `1.foo()`) or another period, in which case it's a range (e.g. 1..2) + */ n = styler.SafeGetCharAt(pos + 1, '\0'); if (c == '.' && !(IsIdentifierStart(n) || n == '.')) { error |= base != 10; pos++; + /* It's ok to have no digits after the period. */ ScanDigits(styler, pos, 10); } + /* Look for the exponentiation. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'e' || c == 'E') { error |= base != 10; @@ -286,13 +303,11 @@ static void ScanNumber(Accessor& styler, int& pos) { c = styler.SafeGetCharAt(pos, '\0'); if (c == '-' || c == '+') pos++; - int old_pos = pos; - ScanDigits(styler, pos, 10); - if (old_pos == pos) { - error = true; - } + /* It is invalid to have no digits in the exponent. */ + error |= !ScanDigits(styler, pos, 10); } + /* Scan the floating point suffix. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'f') { error |= base != 10; @@ -308,9 +323,7 @@ static void ScanNumber(Accessor& styler, int& pos) { } } } - if (old_pos == pos) { - error = true; - } + if (error) styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); else @@ -351,7 +364,7 @@ static bool IsValidCharacterEscape(int c) { } static bool IsValidStringEscape(int c) { - return IsValidCharacterEscape(c) || c == '\n'; + return IsValidCharacterEscape(c) || c == '\n' || c == '\r'; } static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool stop_asap) { @@ -373,12 +386,12 @@ static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool s /* This is overly permissive for character literals in order to accept UTF-8 encoded * character literals. */ -static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { +static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos, bool ascii_only) { pos++; int c = styler.SafeGetCharAt(pos, '\0'); int n = styler.SafeGetCharAt(pos + 1, '\0'); bool done = false; - bool valid_lifetime = IsIdentifierStart(c); + bool valid_lifetime = !ascii_only && IsIdentifierStart(c); bool valid_char = true; bool first = true; while (!done) { @@ -390,10 +403,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { } else if (n == 'x') { pos += 2; valid_char = ScanNumericEscape(styler, pos, 2, false); - } else if (n == 'u') { + } else if (n == 'u' && !ascii_only) { pos += 2; valid_char = ScanNumericEscape(styler, pos, 4, false); - } else if (n == 'U') { + } else if (n == 'U' && !ascii_only) { pos += 2; valid_char = ScanNumericEscape(styler, pos, 8, false); } else { @@ -412,7 +425,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { done = true; break; default: - if (!IsIdentifierContinue(c) && !first) { + if (ascii_only && !IsASCII((char)c)) { + done = true; + valid_char = false; + } else if (!IsIdentifierContinue(c) && !first) { done = true; } else { pos++; @@ -433,7 +449,7 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { styler.ColourTo(pos - 1, SCE_RUST_LIFETIME); } else if (valid_char) { pos++; - styler.ColourTo(pos - 1, SCE_RUST_CHARACTER); + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTECHARACTER : SCE_RUST_CHARACTER); } else { styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); } @@ -542,7 +558,7 @@ static void ScanComments(Accessor &styler, int& pos, int max) { ResumeBlockComment(styler, pos, max, UnknownComment, 1); } -static void ResumeString(Accessor &styler, int& pos, int max) { +static void ResumeString(Accessor &styler, int& pos, int max, bool ascii_only) { int c = styler.SafeGetCharAt(pos, '\0'); bool error = false; while (c != '"' && !error) { @@ -559,10 +575,10 @@ static void ResumeString(Accessor &styler, int& pos, int max) { } else if (n == 'x') { pos += 2; error = !ScanNumericEscape(styler, pos, 2, true); - } else if (n == 'u') { + } else if (n == 'u' && !ascii_only) { pos += 2; error = !ScanNumericEscape(styler, pos, 4, true); - } else if (n == 'U') { + } else if (n == 'U' && !ascii_only) { pos += 2; error = !ScanNumericEscape(styler, pos, 8, true); } else { @@ -570,16 +586,19 @@ static void ResumeString(Accessor &styler, int& pos, int max) { error = true; } } else { - pos++; + if (ascii_only && !IsASCII((char)c)) + error = true; + else + pos++; } c = styler.SafeGetCharAt(pos, '\0'); } if (!error) pos++; - styler.ColourTo(pos - 1, SCE_RUST_STRING); + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRING : SCE_RUST_STRING); } -static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) { +static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes, bool ascii_only) { for (;;) { if (pos == styler.LineEnd(styler.GetLine(pos))) styler.SetLineState(styler.GetLine(pos), num_hashes); @@ -594,19 +613,20 @@ static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) } if (trailing_num_hashes == num_hashes) { styler.SetLineState(styler.GetLine(pos), 0); - styler.ColourTo(pos - 1, SCE_RUST_STRINGR); break; } } else if (pos >= max) { - styler.ColourTo(pos - 1, SCE_RUST_STRINGR); break; - } else { + } else { + if (ascii_only && !IsASCII((char)c)) + break; pos++; } } + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRINGR : SCE_RUST_STRINGR); } -static void ScanRawString(Accessor &styler, int& pos, int max) { +static void ScanRawString(Accessor &styler, int& pos, int max, bool ascii_only) { pos++; int num_hashes = 0; while (styler.SafeGetCharAt(pos, '\0') == '#') { @@ -617,7 +637,7 @@ static void ScanRawString(Accessor &styler, int& pos, int max) { styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); } else { pos++; - ResumeRawString(styler, pos, max, num_hashes); + ResumeRawString(styler, pos, max, num_hashes, ascii_only); } } @@ -635,9 +655,13 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, } else if (initStyle == SCE_RUST_COMMENTLINE || initStyle == SCE_RUST_COMMENTLINEDOC) { ResumeLineComment(styler, pos, max, initStyle == SCE_RUST_COMMENTLINEDOC ? DocComment : NotDocComment); } else if (initStyle == SCE_RUST_STRING) { - ResumeString(styler, pos, max); + ResumeString(styler, pos, max, false); + } else if (initStyle == SCE_RUST_BYTESTRING) { + ResumeString(styler, pos, max, true); } else if (initStyle == SCE_RUST_STRINGR) { - ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1)); + ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), false); + } else if (initStyle == SCE_RUST_BYTESTRINGR) { + ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), true); } while (pos < max) { @@ -645,7 +669,7 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, int n = styler.SafeGetCharAt(pos + 1, '\0'); int n2 = styler.SafeGetCharAt(pos + 2, '\0'); - if (pos == 0 && c == '#' && n == '!') { + if (pos == 0 && c == '#' && n == '!' && n2 != '[') { pos += 2; ResumeLineComment(styler, pos, max, NotDocComment); } else if (IsWhitespace(c)) { @@ -653,7 +677,16 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, } else if (c == '/' && (n == '/' || n == '*')) { ScanComments(styler, pos, max); } else if (c == 'r' && (n == '#' || n == '"')) { - ScanRawString(styler, pos, max); + ScanRawString(styler, pos, max, false); + } else if (c == 'b' && n == 'r' && (n2 == '#' || n2 == '"')) { + pos++; + ScanRawString(styler, pos, max, true); + } else if (c == 'b' && n == '"') { + pos += 2; + ResumeString(styler, pos, max, true); + } else if (c == 'b' && n == '\'') { + pos++; + ScanCharacterLiteralOrLifetime(styler, pos, true); } else if (IsIdentifierStart(c)) { ScanIdentifier(styler, pos, keywords); } else if (IsADigit(c)) { @@ -668,10 +701,10 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, pos++; styler.ColourTo(pos - 1, SCE_RUST_OPERATOR); } else if (c == '\'') { - ScanCharacterLiteralOrLifetime(styler, pos); + ScanCharacterLiteralOrLifetime(styler, pos, false); } else if (c == '"') { pos++; - ResumeString(styler, pos, max); + ResumeString(styler, pos, max, false); } else { pos++; styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); diff --git a/src/stc/scintilla/lexers/LexSQL.cxx b/src/stc/scintilla/lexers/LexSQL.cxx index fa22f8e633..b9f15ea1a6 100644 --- a/src/stc/scintilla/lexers/LexSQL.cxx +++ b/src/stc/scintilla/lexers/LexSQL.cxx @@ -444,6 +444,8 @@ void SCI_METHOD LexerSQL::Lex(unsigned int startPos, int length, int initStyle, StyleContext sc(startPos, length, initStyle, styler); int styleBeforeDCKeyword = SCE_SQL_DEFAULT; int offset = 0; + char qOperator = 0x00; + for (; sc.More(); sc.Forward(), offset++) { // Determine if the current state should terminate. switch (sc.state) { @@ -556,11 +558,39 @@ void SCI_METHOD LexerSQL::Lex(unsigned int startPos, int length, int initStyle, } } break; + case SCE_SQL_QOPERATOR: + if (qOperator == 0x00) { + qOperator = sc.ch; + } else { + char qComplement = 0x00; + + if (qOperator == '<') { + qComplement = '>'; + } else if (qOperator == '(') { + qComplement = ')'; + } else if (qOperator == '{') { + qComplement = '}'; + } else if (qOperator == '[') { + qComplement = ']'; + } else { + qComplement = qOperator; + } + + if (sc.Match(qComplement, '\'')) { + sc.Forward(); + sc.ForwardSetState(SCE_SQL_DEFAULT); + qOperator = 0x00; + } + } + break; } // Determine if a new state should be entered. if (sc.state == SCE_SQL_DEFAULT) { - if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + if (sc.Match('q', '\'') || sc.Match('Q', '\'')) { + sc.SetState(SCE_SQL_QOPERATOR); + sc.Forward(); + } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_SQL_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_SQL_IDENTIFIER); diff --git a/src/stc/scintilla/lexers/LexVHDL.cxx b/src/stc/scintilla/lexers/LexVHDL.cxx index 189416425d..fe1b33317a 100644 --- a/src/stc/scintilla/lexers/LexVHDL.cxx +++ b/src/stc/scintilla/lexers/LexVHDL.cxx @@ -119,6 +119,11 @@ static void ColouriseVHDLDoc( sc.ChangeState(SCE_VHDL_STRINGEOL); sc.ForwardSetState(SCE_VHDL_DEFAULT); } + } else if (sc.state == SCE_VHDL_BLOCK_COMMENT){ + if(sc.ch == '*' && sc.chNext == '/'){ + sc.Forward(); + sc.ForwardSetState(SCE_VHDL_DEFAULT); + } } // Determine if a new state should be entered. @@ -132,6 +137,8 @@ static void ColouriseVHDLDoc( sc.SetState(SCE_VHDL_COMMENTLINEBANG); else sc.SetState(SCE_VHDL_COMMENT); + } else if (sc.Match('/', '*')){ + sc.SetState(SCE_VHDL_BLOCK_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_VHDL_STRING); } else if (isoperator(static_cast(sc.ch))) { @@ -155,6 +162,39 @@ static bool IsCommentLine(int line, Accessor &styler) { } return false; } +static bool IsCommentBlockStart(int line, Accessor &styler) +{ + int pos = styler.LineStart(line); + int eol_pos = styler.LineStart(line + 1) - 1; + for (int i = pos; i < eol_pos; i++) { + char ch = styler[i]; + char chNext = styler[i+1]; + char style = styler.StyleAt(i); + if ((style == SCE_VHDL_BLOCK_COMMENT) && (ch == '/') && (chNext == '*')) + return true; + } + return false; +} + +static bool IsCommentBlockEnd(int line, Accessor &styler) +{ + int pos = styler.LineStart(line); + int eol_pos = styler.LineStart(line + 1) - 1; + + for (int i = pos; i < eol_pos; i++) { + char ch = styler[i]; + char chNext = styler[i+1]; + char style = styler.StyleAt(i); + if ((style == SCE_VHDL_BLOCK_COMMENT) && (ch == '*') && (chNext == '/')) + return true; + } + return false; +} + +static bool IsCommentStyle(char style) +{ + return style == SCE_VHDL_BLOCK_COMMENT || style == SCE_VHDL_COMMENT || style == SCE_VHDL_COMMENTLINEBANG; +} //============================================================================= // Folding the code @@ -167,7 +207,7 @@ static void FoldNoBoxVHDLDoc( // Decided it would be smarter to have the lexer have all keywords included. Therefore I // don't check if the style for the keywords that I use to adjust the levels. char words[] = - "architecture begin case component else elsif end entity generate loop package process record then " + "architecture begin block case component else elsif end entity generate loop package process record then " "procedure function when"; WordList keywords; keywords.Set(words); @@ -207,14 +247,14 @@ static void FoldNoBoxVHDLDoc( char chPrev = styler.SafeGetCharAt(j-1); int style = styler.StyleAt(j); int stylePrev = styler.StyleAt(j-1); - if ((stylePrev != SCE_VHDL_COMMENT) && (stylePrev != SCE_VHDL_STRING)) + if ((!IsCommentStyle(style)) && (stylePrev != SCE_VHDL_STRING)) { if(IsAWordChar(chPrev) && !IsAWordChar(ch)) { end = j-1; } } - if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING)) + if ((!IsCommentStyle(style)) && (style != SCE_VHDL_STRING)) { if(!IsAWordChar(chPrev) && IsAWordStart(ch) && (end != 0)) { @@ -236,7 +276,7 @@ static void FoldNoBoxVHDLDoc( { char ch = styler.SafeGetCharAt(j); int style = styler.StyleAt(j); - if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING)) + if ((!IsCommentStyle(style)) && (style != SCE_VHDL_STRING)) { if((ch == ';') && (strcmp(prevWord, "end") == 0)) { @@ -268,15 +308,29 @@ static void FoldNoBoxVHDLDoc( styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); - if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) + if (foldComment && atEOL) { - if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler)) + if(IsCommentLine(lineCurrent, styler)) { - levelNext++; + if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler)) + { + levelNext++; + } + else if(IsCommentLine(lineCurrent-1, styler) && !IsCommentLine(lineCurrent+1, styler)) + { + levelNext--; + } } - else if(IsCommentLine(lineCurrent-1, styler) && !IsCommentLine(lineCurrent+1, styler)) + else { - levelNext--; + if (IsCommentBlockStart(lineCurrent, styler) && !IsCommentBlockEnd(lineCurrent, styler)) + { + levelNext++; + } + else if (IsCommentBlockEnd(lineCurrent, styler) && !IsCommentBlockStart(lineCurrent, styler)) + { + levelNext--; + } } } @@ -289,7 +343,7 @@ static void FoldNoBoxVHDLDoc( } } - if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING)) + if ((!IsCommentStyle(style)) && (style != SCE_VHDL_STRING)) { if((ch == ';') && (strcmp(prevWord, "end") == 0)) { @@ -301,7 +355,7 @@ static void FoldNoBoxVHDLDoc( lastStart = i; } - if(iswordchar(ch) && !iswordchar(chNext)) { + if(IsAWordChar(ch) && !IsAWordChar(chNext)) { char s[32]; unsigned int k; for(k=0; (k<31 ) && (k0 && + (chAtPos == ' ' || chAtPos == '\t' || + chAtPos == '\n' || chAtPos == '\r' || + IsCommentStyle(styleAtPos))); + + // check for a colon (':') before the instantiated units "entity", "component" or "configuration". Don't fold thereafter. + if (chAtPos != ':') + { + if (levelMinCurrentElse > levelNext) { + levelMinCurrentElse = levelNext; + } + levelNext++; + } + } } else if ( strcmp(s, "procedure") == 0 || strcmp(s, "function") == 0) @@ -338,19 +417,19 @@ static void FoldNoBoxVHDLDoc( { // This code checks to see if the procedure / function is a definition within a "package" // rather than the actual code in the body. int BracketLevel = 0; - for(int j=i+1; j levelNext) { levelMinCurrentElse = levelNext; @@ -358,7 +437,7 @@ static void FoldNoBoxVHDLDoc( levelNext++; break; } - if((BracketLevel == 0) && (LocalCh == ';')) + if((BracketLevel == 0) && (chAtPos == ';')) { break; } diff --git a/src/stc/scintilla/lexlib/LexerModule.h b/src/stc/scintilla/lexlib/LexerModule.h index ee092e68fd..5993c0fe97 100644 --- a/src/stc/scintilla/lexlib/LexerModule.h +++ b/src/stc/scintilla/lexlib/LexerModule.h @@ -67,7 +67,12 @@ inline int Maximum(int a, int b) { // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER -#pragma warning(disable: 4244 4309) +#pragma warning(disable: 4244 4309 4456 4457) +#endif + +// Turn off shadow warnings for lexers as may be maintained by others +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wshadow" #endif #ifdef SCI_NAMESPACE diff --git a/src/stc/scintilla/src/Catalogue.cxx b/src/stc/scintilla/src/Catalogue.cxx index ac1fc3818b..3fd006f7ac 100644 --- a/src/stc/scintilla/src/Catalogue.cxx +++ b/src/stc/scintilla/src/Catalogue.cxx @@ -90,6 +90,7 @@ int Scintilla_LinkLexers() { LINK_LEXER(lmBaan); LINK_LEXER(lmBash); LINK_LEXER(lmBatch); + LINK_LEXER(lmBibTeX); LINK_LEXER(lmBlitzBasic); LINK_LEXER(lmBullant); LINK_LEXER(lmCaml); @@ -163,6 +164,7 @@ int Scintilla_LinkLexers() { LINK_LEXER(lmPython); LINK_LEXER(lmR); LINK_LEXER(lmREBOL); + LINK_LEXER(lmRegistry); LINK_LEXER(lmRuby); LINK_LEXER(lmRust); LINK_LEXER(lmScriptol); diff --git a/src/stc/scintilla/src/CellBuffer.cxx b/src/stc/scintilla/src/CellBuffer.cxx index 0c56c9e927..a770dc3351 100644 --- a/src/stc/scintilla/src/CellBuffer.cxx +++ b/src/stc/scintilla/src/CellBuffer.cxx @@ -144,6 +144,7 @@ UndoHistory::UndoHistory() { currentAction = 0; undoSequenceDepth = 0; savePoint = 0; + tentativePoint = -1; actions[currentAction].Create(startAction); } @@ -194,7 +195,7 @@ const char *UndoHistory::AppendAction(actionType at, int position, const char *d // Visual Studio 2013 Code Analysis wrongly believes actions can be NULL at its next reference __analysis_assume(actions); #endif - if (currentAction == savePoint) { + if ((currentAction == savePoint) || (currentAction == tentativePoint)) { currentAction++; } else if (!actions[currentAction].mayCoalesce) { // Not allowed to coalesce if this set @@ -282,6 +283,7 @@ void UndoHistory::DeleteUndoHistory() { currentAction = 0; actions[currentAction].Create(startAction); savePoint = 0; + tentativePoint = -1; } void UndoHistory::SetSavePoint() { @@ -292,6 +294,26 @@ bool UndoHistory::IsSavePoint() const { return savePoint == currentAction; } +void UndoHistory::TentativeStart() { + tentativePoint = currentAction; +} + +void UndoHistory::TentativeCommit() { + tentativePoint = -1; + // Truncate undo history + maxAction = currentAction; +} + +int UndoHistory::TentativeSteps() { + // Drop any trailing startAction + if (actions[currentAction].at == startAction && currentAction > 0) + currentAction--; + if (tentativePoint >= 0) + return currentAction - tentativePoint; + else + return -1; +} + bool UndoHistory::CanUndo() const { return (currentAction > 0) && (maxAction > 0); } @@ -356,7 +378,7 @@ char CellBuffer::CharAt(int position) const { } void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) const { - if (lengthRetrieve < 0) + if (lengthRetrieve <= 0) return; if (position < 0) return; @@ -505,6 +527,22 @@ bool CellBuffer::IsSavePoint() const { return uh.IsSavePoint(); } +void CellBuffer::TentativeStart() { + uh.TentativeStart(); +} + +void CellBuffer::TentativeCommit() { + uh.TentativeCommit(); +} + +int CellBuffer::TentativeSteps() { + return uh.TentativeSteps(); +} + +bool CellBuffer::TentativeActive() const { + return uh.TentativeActive(); +} + // Without undo void CellBuffer::InsertLine(int line, int position, bool lineStart) { diff --git a/src/stc/scintilla/src/CellBuffer.h b/src/stc/scintilla/src/CellBuffer.h index f07b459832..5e4fc7c8ca 100644 --- a/src/stc/scintilla/src/CellBuffer.h +++ b/src/stc/scintilla/src/CellBuffer.h @@ -95,6 +95,7 @@ class UndoHistory { int currentAction; int undoSequenceDepth; int savePoint; + int tentativePoint; void EnsureUndoRoom(); @@ -117,6 +118,12 @@ public: void SetSavePoint(); bool IsSavePoint() const; + // Tentative actions are used for input composition so that it can be undone cleanly + void TentativeStart(); + void TentativeCommit(); + bool TentativeActive() const { return tentativePoint >= 0; } + int TentativeSteps(); + /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo() const; @@ -193,6 +200,11 @@ public: void SetSavePoint(); bool IsSavePoint() const; + void TentativeStart(); + void TentativeCommit(); + bool TentativeActive() const; + int TentativeSteps(); + bool SetUndoCollection(bool collectUndo); bool IsCollectingUndo() const; void BeginUndoAction(); diff --git a/src/stc/scintilla/src/ContractionState.cxx b/src/stc/scintilla/src/ContractionState.cxx index a5ecfe1130..7b76554209 100644 --- a/src/stc/scintilla/src/ContractionState.cxx +++ b/src/stc/scintilla/src/ContractionState.cxx @@ -150,8 +150,8 @@ bool ContractionState::GetVisible(int lineDoc) const { } } -bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) { - if (OneToOne() && visible_) { +bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool isVisible) { + if (OneToOne() && isVisible) { return false; } else { EnsureData(); @@ -159,9 +159,9 @@ bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible Check(); if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) { for (int line = lineDocStart; line <= lineDocEnd; line++) { - if (GetVisible(line) != visible_) { - int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line); - visible->SetValueAt(line, visible_ ? 1 : 0); + if (GetVisible(line) != isVisible) { + int difference = isVisible ? heights->ValueAt(line) : -heights->ValueAt(line); + visible->SetValueAt(line, isVisible ? 1 : 0); displayLines->InsertText(line, difference); delta += difference; } @@ -191,13 +191,13 @@ bool ContractionState::GetExpanded(int lineDoc) const { } } -bool ContractionState::SetExpanded(int lineDoc, bool expanded_) { - if (OneToOne() && expanded_) { +bool ContractionState::SetExpanded(int lineDoc, bool isExpanded) { + if (OneToOne() && isExpanded) { return false; } else { EnsureData(); - if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) { - expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0); + if (isExpanded != (expanded->ValueAt(lineDoc) == 1)) { + expanded->SetValueAt(lineDoc, isExpanded ? 1 : 0); Check(); return true; } else { diff --git a/src/stc/scintilla/src/ContractionState.h b/src/stc/scintilla/src/ContractionState.h index 1c9109c69e..96cbf07638 100644 --- a/src/stc/scintilla/src/ContractionState.h +++ b/src/stc/scintilla/src/ContractionState.h @@ -48,11 +48,11 @@ public: void DeleteLines(int lineDoc, int lineCount); bool GetVisible(int lineDoc) const; - bool SetVisible(int lineDocStart, int lineDocEnd, bool visible); + bool SetVisible(int lineDocStart, int lineDocEnd, bool isVisible); bool HiddenLines() const; bool GetExpanded(int lineDoc) const; - bool SetExpanded(int lineDoc, bool expanded); + bool SetExpanded(int lineDoc, bool isExpanded); int ContractedNext(int lineDocStart) const; int GetHeight(int lineDoc) const; diff --git a/src/stc/scintilla/src/Decoration.cxx b/src/stc/scintilla/src/Decoration.cxx index 72c7a331ff..e7610e0b6b 100644 --- a/src/stc/scintilla/src/Decoration.cxx +++ b/src/stc/scintilla/src/Decoration.cxx @@ -163,7 +163,9 @@ int DecorationList::AllOnFor(int position) const { int mask = 0; for (Decoration *deco=root; deco; deco = deco->next) { if (deco->rs.ValueAt(position)) { - mask |= 1 << deco->indicator; + if (deco->indicator < INDIC_IME) { + mask |= 1 << deco->indicator; + } } } return mask; diff --git a/src/stc/scintilla/src/Document.cxx b/src/stc/scintilla/src/Document.cxx index 32d5f18960..d0909b808f 100644 --- a/src/stc/scintilla/src/Document.cxx +++ b/src/stc/scintilla/src/Document.cxx @@ -11,10 +11,15 @@ #include #include +#include #include #include #include +#ifdef CXX11_REGEX +#include +#endif + #include "Platform.h" #include "ILexer.h" @@ -209,6 +214,65 @@ void Document::SetSavePoint() { NotifySavePoint(true); } +void Document::TentativeUndo() { + CheckReadOnly(); + if (enteredModification == 0) { + enteredModification++; + if (!cb.IsReadOnly()) { + bool startSavePoint = cb.IsSavePoint(); + bool multiLine = false; + int steps = cb.TentativeSteps(); + //Platform::DebugPrintf("Steps=%d\n", steps); + for (int step = 0; step < steps; step++) { + const int prevLinesTotal = LinesTotal(); + const Action &action = cb.GetUndoStep(); + if (action.at == removeAction) { + NotifyModified(DocModification( + SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); + } else if (action.at == containerAction) { + DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); + dm.token = action.position; + NotifyModified(dm); + } else { + NotifyModified(DocModification( + SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); + } + cb.PerformUndoStep(); + if (action.at != containerAction) { + ModifiedAt(action.position); + } + + int modFlags = SC_PERFORMED_UNDO; + // With undo, an insertion action becomes a deletion notification + if (action.at == removeAction) { + modFlags |= SC_MOD_INSERTTEXT; + } else if (action.at == insertAction) { + modFlags |= SC_MOD_DELETETEXT; + } + if (steps > 1) + modFlags |= SC_MULTISTEPUNDOREDO; + const int linesAdded = LinesTotal() - prevLinesTotal; + if (linesAdded != 0) + multiLine = true; + if (step == steps - 1) { + modFlags |= SC_LASTSTEPINUNDOREDO; + if (multiLine) + modFlags |= SC_MULTILINEUNDOREDO; + } + NotifyModified(DocModification(modFlags, action.position, action.lenData, + linesAdded, action.data)); + } + + bool endSavePoint = cb.IsSavePoint(); + if (startSavePoint != endSavePoint) + NotifySavePoint(endSavePoint); + + cb.TentativeCommit(); + } + enteredModification--; + } +} + int Document::GetMark(int line) { return static_cast(perLineData[ldMarkers])->MarkValue(line); } @@ -276,6 +340,10 @@ int SCI_METHOD Document::LineStart(int line) const { return cb.LineStart(line); } +bool Document::IsLineStartPosition(int position) const { + return LineStart(LineFromPosition(position)) == position; +} + int SCI_METHOD Document::LineEnd(int line) const { if (line >= LinesTotal() - 1) { return LineStart(line + 1); @@ -542,7 +610,7 @@ bool Document::InGoodUTF8(int pos, int &start, int &end) const { // When lines are terminated with \r\n pairs which should be treated as one character. // When displaying DBCS text such as Japanese. // If moving, move the position in the indicated direction. -int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { +int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const { //Platform::DebugPrintf("NoCRLF %d %d\n", pos, moveDir); // If out of range, just return minimum/maximum value. if (pos <= 0) @@ -878,6 +946,8 @@ void Document::CheckReadOnly() { // SetStyleAt does not change the persistent state of a document bool Document::DeleteChars(int pos, int len) { + if (pos < 0) + return false; if (len <= 0) return false; if ((pos + len) > Length()) @@ -1236,7 +1306,7 @@ int Document::GetColumn(int pos) { return column; } -int Document::CountCharacters(int startPos, int endPos) { +int Document::CountCharacters(int startPos, int endPos) const { startPos = MovePositionOutsideChar(startPos, 1, false); endPos = MovePositionOutsideChar(endPos, -1, false); int count = 0; @@ -1525,6 +1595,25 @@ void Document::SetCaseFolder(CaseFolder *pcf_) { pcf = pcf_; } +Document::CharacterExtracted Document::ExtractCharacter(int position) const { + const unsigned char leadByte = static_cast(cb.CharAt(position)); + if (UTF8IsAscii(leadByte)) { + // Common case: ASCII character + return CharacterExtracted(leadByte, 1); + } + const int widthCharBytes = UTF8BytesOfLead[leadByte]; + unsigned char charBytes[UTF8MaxBytes] = { leadByte, 0, 0, 0 }; + for (int b=1; b(cb.CharAt(position + b)); + int utf8status = UTF8Classify(charBytes, widthCharBytes); + if (utf8status & UTF8MaskInvalid) { + // Treat as invalid and use up just one byte + return CharacterExtracted(unicodeReplacementChar, 1); + } else { + return CharacterExtracted(UnicodeFromBytes(charBytes), utf8status & UTF8MaskWidth); + } +} + /** * Find text in document, supporting both forward and backward * searches (just pass minPos > maxPos to do a backward search) @@ -2116,6 +2205,61 @@ private: std::string substituted; }; +namespace { + +/** +* RESearchRange keeps track of search range. +*/ +class RESearchRange { +public: + const Document *doc; + int increment; + int startPos; + int endPos; + int lineRangeStart; + int lineRangeEnd; + int lineRangeBreak; + RESearchRange(const Document *doc_, int minPos, int maxPos) : doc(doc_) { + increment = (minPos <= maxPos) ? 1 : -1; + + // Range endpoints should not be inside DBCS characters, but just in case, move them. + startPos = doc->MovePositionOutsideChar(minPos, 1, false); + endPos = doc->MovePositionOutsideChar(maxPos, 1, false); + + lineRangeStart = doc->LineFromPosition(startPos); + lineRangeEnd = doc->LineFromPosition(endPos); + if ((increment == 1) && + (startPos >= doc->LineEnd(lineRangeStart)) && + (lineRangeStart < lineRangeEnd)) { + // 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); + } + lineRangeBreak = lineRangeEnd + increment; + } + Range LineRange(int line) const { + Range range(doc->LineStart(line), doc->LineEnd(line)); + if (increment == 1) { + if (line == lineRangeStart) + range.start = startPos; + if (line == lineRangeEnd) + range.end = endPos; + } else { + if (line == lineRangeEnd) + range.start = endPos; + if (line == lineRangeStart) + range.end = startPos; + } + return range; + } +}; + // Define a way for the Regular Expression code to access the document class DocumentIndexer : public CharacterIndexer { Document *pdoc; @@ -2136,18 +2280,375 @@ public: } }; +#ifdef CXX11_REGEX + +class ByteIterator : public std::iterator { +public: + const Document *doc; + Position position; + ByteIterator(const Document *doc_ = 0, Position position_ = 0) : doc(doc_), position(position_) { + } + ByteIterator(const ByteIterator &other) { + doc = other.doc; + position = other.position; + } + ByteIterator &operator=(const ByteIterator &other) { + if (this != &other) { + doc = other.doc; + position = other.position; + } + return *this; + } + char operator*() const { + return doc->CharAt(position); + } + ByteIterator &operator++() { + position++; + return *this; + } + ByteIterator operator++(int) { + ByteIterator retVal(*this); + position++; + return retVal; + } + ByteIterator &operator--() { + position--; + return *this; + } + bool operator==(const ByteIterator &other) const { + return doc == other.doc && position == other.position; + } + bool operator!=(const ByteIterator &other) const { + return doc != other.doc || position != other.position; + } + int Pos() const { + return position; + } + int PosRoundUp() const { + return position; + } +}; + +// On Windows, wchar_t is 16 bits wide and on Unix it is 32 bits wide. +// Would be better to use sizeof(wchar_t) or similar to differentiate +// but easier for now to hard-code platforms. +// C++11 has char16_t and char32_t but neither Clang nor Visual C++ +// appear to allow specializing basic_regex over these. + +#ifdef _WIN32 +#define WCHAR_T_IS_16 1 +#else +#define WCHAR_T_IS_16 0 +#endif + +#if WCHAR_T_IS_16 + +// On Windows, report non-BMP characters as 2 separate surrogates as that +// matches wregex since it is based on wchar_t. +class UTF8Iterator : public std::iterator { + // These 3 fields determine the iterator position and are used for comparisons + const Document *doc; + Position position; + size_t characterIndex; + // Remaining fields are derived from the determining fields so are excluded in comparisons + unsigned int lenBytes; + size_t lenCharacters; + wchar_t buffered[2]; +public: + UTF8Iterator(const Document *doc_ = 0, Position position_ = 0) : + doc(doc_), position(position_), characterIndex(0), lenBytes(0), lenCharacters(0) { + buffered[0] = 0; + buffered[1] = 0; + } + UTF8Iterator(const UTF8Iterator &other) { + doc = other.doc; + position = other.position; + characterIndex = other.characterIndex; + lenBytes = other.lenBytes; + lenCharacters = other.lenCharacters; + buffered[0] = other.buffered[0]; + buffered[1] = other.buffered[1]; + } + UTF8Iterator &operator=(const UTF8Iterator &other) { + if (this != &other) { + doc = other.doc; + position = other.position; + characterIndex = other.characterIndex; + lenBytes = other.lenBytes; + lenCharacters = other.lenCharacters; + buffered[0] = other.buffered[0]; + buffered[1] = other.buffered[1]; + } + return *this; + } + wchar_t operator*() { + if (lenCharacters == 0) { + ReadCharacter(); + } + return buffered[characterIndex]; + } + UTF8Iterator &operator++() { + if ((characterIndex + 1) < (lenCharacters)) { + characterIndex++; + } else { + position += lenBytes; + ReadCharacter(); + characterIndex = 0; + } + return *this; + } + UTF8Iterator operator++(int) { + UTF8Iterator retVal(*this); + if ((characterIndex + 1) < (lenCharacters)) { + characterIndex++; + } else { + position += lenBytes; + ReadCharacter(); + characterIndex = 0; + } + return retVal; + } + UTF8Iterator &operator--() { + if (characterIndex) { + characterIndex--; + } else { + position = doc->NextPosition(position, -1); + ReadCharacter(); + characterIndex = lenCharacters - 1; + } + return *this; + } + bool operator==(const UTF8Iterator &other) const { + // Only test the determining fields, not the character widths and values derived from this + return doc == other.doc && + position == other.position && + characterIndex == other.characterIndex; + } + bool operator!=(const UTF8Iterator &other) const { + // Only test the determining fields, not the character widths and values derived from this + return doc != other.doc || + position != other.position || + characterIndex != other.characterIndex; + } + int Pos() const { + return position; + } + int PosRoundUp() const { + if (characterIndex) + return position + lenBytes; // Force to end of character + else + return position; + } +private: + void ReadCharacter() { + Document::CharacterExtracted charExtracted = doc->ExtractCharacter(position); + lenBytes = charExtracted.widthBytes; + if (charExtracted.character == unicodeReplacementChar) { + lenCharacters = 1; + buffered[0] = static_cast(charExtracted.character); + } else { + lenCharacters = UTF16FromUTF32Character(charExtracted.character, buffered); + } + } +}; + +#else + +// On Unix, report non-BMP characters as single characters + +class UTF8Iterator : public std::iterator { + const Document *doc; + Position position; +public: + UTF8Iterator(const Document *doc_=0, Position position_=0) : doc(doc_), position(position_) { + } + UTF8Iterator(const UTF8Iterator &other) { + doc = other.doc; + position = other.position; + } + UTF8Iterator &operator=(const UTF8Iterator &other) { + if (this != &other) { + doc = other.doc; + position = other.position; + } + return *this; + } + wchar_t operator*() const { + Document::CharacterExtracted charExtracted = doc->ExtractCharacter(position); + return charExtracted.character; + } + UTF8Iterator &operator++() { + position = doc->NextPosition(position, 1); + return *this; + } + UTF8Iterator operator++(int) { + UTF8Iterator retVal(*this); + position = doc->NextPosition(position, 1); + return retVal; + } + UTF8Iterator &operator--() { + position = doc->NextPosition(position, -1); + return *this; + } + bool operator==(const UTF8Iterator &other) const { + return doc == other.doc && position == other.position; + } + bool operator!=(const UTF8Iterator &other) const { + return doc != other.doc || position != other.position; + } + int Pos() const { + return position; + } + int PosRoundUp() const { + return position; + } +}; + +#endif + +std::regex_constants::match_flag_type MatchFlags(const Document *doc, int startPos, int endPos) { + std::regex_constants::match_flag_type flagsMatch = std::regex_constants::match_default; + if (!doc->IsLineStartPosition(startPos)) + flagsMatch |= std::regex_constants::match_not_bol; + if (!doc->IsLineEndPosition(endPos)) + flagsMatch |= std::regex_constants::match_not_eol; + return flagsMatch; +} + +template +bool MatchOnLines(const Document *doc, const Regex ®exp, const RESearchRange &resr, RESearch &search) { + bool matched = false; + std::match_results match; + + // MSVC and libc++ have problems with ^ and $ matching line ends inside a range + // If they didn't then the line by line iteration could be removed for the forwards + // case and replaced with the following 4 lines: + // Iterator uiStart(doc, startPos); + // Iterator uiEnd(doc, endPos); + // flagsMatch = MatchFlags(doc, startPos, endPos); + // matched = std::regex_search(uiStart, uiEnd, match, regexp, flagsMatch); + + // Line by line. + for (int line = resr.lineRangeStart; line != resr.lineRangeBreak; line += resr.increment) { + const Range lineRange = resr.LineRange(line); + Iterator itStart(doc, lineRange.start); + Iterator itEnd(doc, lineRange.end); + std::regex_constants::match_flag_type flagsMatch = MatchFlags(doc, lineRange.start, lineRange.end); + matched = std::regex_search(itStart, itEnd, match, regexp, flagsMatch); + // Check for the last match on this line. + if (matched) { + if (resr.increment == -1) { + while (matched) { + Iterator itNext(doc, match[0].second.PosRoundUp()); + flagsMatch = MatchFlags(doc, itNext.Pos(), lineRange.end); + std::match_results matchNext; + matched = std::regex_search(itNext, itEnd, matchNext, regexp, flagsMatch); + if (matched) { + if (match[0].first == match[0].second) { + // Empty match means failure so exit + return false; + } + match = matchNext; + } + } + matched = true; + } + break; + } + } + if (matched) { + for (size_t co = 0; co < match.size(); co++) { + search.bopat[co] = match[co].first.Pos(); + search.eopat[co] = match[co].second.PosRoundUp(); + size_t lenMatch = search.eopat[co] - search.bopat[co]; + search.pat[co].resize(lenMatch); + for (size_t iPos = 0; iPos < lenMatch; iPos++) { + search.pat[co][iPos] = doc->CharAt(iPos + search.bopat[co]); + } + } + } + return matched; +} + +long Cxx11RegexFindText(Document *doc, int minPos, int maxPos, const char *s, + bool caseSensitive, int *length, RESearch &search) { + const RESearchRange resr(doc, minPos, maxPos); + try { + //ElapsedTime et; + std::regex::flag_type flagsRe = std::regex::ECMAScript; + // Flags that apper to have no effect: + // | std::regex::collate | std::regex::extended; + if (!caseSensitive) + flagsRe = flagsRe | std::regex::icase; + + // Clear the RESearch so can fill in matches + search.Clear(); + + bool matched = false; + if (SC_CP_UTF8 == doc->dbcsCodePage) { + unsigned int lenS = static_cast(strlen(s)); + std::vector ws(lenS + 1); +#if WCHAR_T_IS_16 + size_t outLen = UTF16FromUTF8(s, lenS, &ws[0], lenS); +#else + size_t outLen = UTF32FromUTF8(s, lenS, reinterpret_cast(&ws[0]), lenS); +#endif + ws[outLen] = 0; + std::wregex regexp; +#if defined(__APPLE__) + // Using a UTF-8 locale doesn't change to Unicode over a byte buffer so '.' + // is one byte not one character. + // However, on OS X this makes wregex act as Unicode + std::locale localeU("en_US.UTF-8"); + regexp.imbue(localeU); +#endif + regexp.assign(&ws[0], flagsRe); + matched = MatchOnLines(doc, regexp, resr, search); + + } else { + std::regex regexp; + regexp.assign(s, flagsRe); + matched = MatchOnLines(doc, regexp, resr, search); + } + + int posMatch = -1; + if (matched) { + posMatch = search.bopat[0]; + *length = search.eopat[0] - search.bopat[0]; + } + // Example - search in doc/ScintillaHistory.html for + // [[:upper:]]eta[[:space:]] + // On MacBook, normally around 1 second but with locale imbued -> 14 seconds. + //double durSearch = et.Duration(true); + //Platform::DebugPrintf("Search:%9.6g \n", durSearch); + return posMatch; + } catch (std::regex_error &) { + // Failed to create regular expression + throw RegexError(); + } catch (...) { + // Failed in some other way + return -1; + } +} + +#endif + +} + long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool, bool, int flags, int *length) { - bool posix = (flags & SCFIND_POSIX) != 0; - int increment = (minPos <= maxPos) ? 1 : -1; - int startPos = minPos; - int endPos = maxPos; +#ifdef CXX11_REGEX + if (flags & SCFIND_CXX11REGEX) { + return Cxx11RegexFindText(doc, minPos, maxPos, s, + caseSensitive, length, search); + } +#endif - // Range endpoints should not be inside DBCS characters, but just in case, move them. - startPos = doc->MovePositionOutsideChar(startPos, 1, false); - endPos = doc->MovePositionOutsideChar(endPos, 1, false); + const RESearchRange resr(doc, minPos, maxPos); + + const bool posix = (flags & SCFIND_POSIX) != 0; const char *errmsg = search.Compile(s, *length, caseSensitive, posix); if (errmsg) { @@ -2157,50 +2658,34 @@ long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s // Replace first '.' with '-' in each property file variable reference: // Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\)) // Replace: $(\1-\2) - int lineRangeStart = doc->LineFromPosition(startPos); - int lineRangeEnd = doc->LineFromPosition(endPos); - if ((increment == 1) && - (startPos >= doc->LineEnd(lineRangeStart)) && - (lineRangeStart < lineRangeEnd)) { - // 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; - char searchEnd = s[*length - 1]; - char searchEndPrev = (*length > 1) ? s[*length - 2] : '\0'; - int lineRangeBreak = lineRangeEnd + increment; - for (int line = lineRangeStart; line != lineRangeBreak; line += increment) { + const char searchEnd = s[*length - 1]; + const char searchEndPrev = (*length > 1) ? s[*length - 2] : '\0'; + for (int line = resr.lineRangeStart; line != resr.lineRangeBreak; line += resr.increment) { int startOfLine = doc->LineStart(line); int endOfLine = doc->LineEnd(line); - if (increment == 1) { - if (line == lineRangeStart) { - if ((startPos != startOfLine) && (s[0] == '^')) + if (resr.increment == 1) { + if (line == resr.lineRangeStart) { + if ((resr.startPos != startOfLine) && (s[0] == '^')) continue; // Can't match start of line if start position after start of line - startOfLine = startPos; + startOfLine = resr.startPos; } - if (line == lineRangeEnd) { - if ((endPos != endOfLine) && (searchEnd == '$') && (searchEndPrev != '\\')) + if (line == resr.lineRangeEnd) { + if ((resr.endPos != endOfLine) && (searchEnd == '$') && (searchEndPrev != '\\')) continue; // Can't match end of line if end position before end of line - endOfLine = endPos; + endOfLine = resr.endPos; } } else { - if (line == lineRangeEnd) { - if ((endPos != startOfLine) && (s[0] == '^')) + if (line == resr.lineRangeEnd) { + if ((resr.endPos != startOfLine) && (s[0] == '^')) continue; // Can't match start of line if end position after start of line - startOfLine = endPos; + startOfLine = resr.endPos; } - if (line == lineRangeStart) { - if ((startPos != endOfLine) && (searchEnd == '$') && (searchEndPrev != '\\')) + if (line == resr.lineRangeStart) { + if ((resr.startPos != endOfLine) && (searchEnd == '$') && (searchEndPrev != '\\')) continue; // Can't match end of line if start position before end of line - endOfLine = startPos; + endOfLine = resr.startPos; } } @@ -2212,7 +2697,7 @@ long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s search.eopat[0] = doc->MovePositionOutsideChar(search.eopat[0], 1, false); lenRet = search.eopat[0] - search.bopat[0]; // There can be only one start of a line, so no need to look for last match in line - if ((increment == -1) && (s[0] != '^')) { + if ((resr.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--)) { diff --git a/src/stc/scintilla/src/Document.h b/src/stc/scintilla/src/Document.h index a59f192a96..e808bb37f4 100644 --- a/src/stc/scintilla/src/Document.h +++ b/src/stc/scintilla/src/Document.h @@ -188,6 +188,10 @@ public: } }; +struct RegexError : public std::runtime_error { + RegexError() : std::runtime_error("regex failure") {} +}; + /** */ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { @@ -271,7 +275,7 @@ public: bool IsCrLf(int pos) const; int LenChar(int pos); bool InGoodUTF8(int pos, int &start, int &end) const; - int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); + int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const; int NextPosition(int pos, int moveDir) const; bool NextCharacter(int &pos, int moveDir) const; // Returns true if pos changed int SCI_METHOD GetRelativePosition(int positionStart, int characterOffset) const; @@ -303,6 +307,12 @@ public: void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } void SetSavePoint(); bool IsSavePoint() const { return cb.IsSavePoint(); } + + void TentativeStart() { cb.TentativeStart(); } + void TentativeCommit() { cb.TentativeCommit(); } + void TentativeUndo(); + bool TentativeActive() const { return cb.TentativeActive(); } + const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); } const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); } int GapPosition() const { return cb.GapPosition(); } @@ -311,7 +321,7 @@ public: int SetLineIndentation(int line, int indent); int GetLineIndentPosition(int line) const; int GetColumn(int position); - int CountCharacters(int startPos, int endPos); + int CountCharacters(int startPos, int endPos) const; int FindColumn(int line, int column); void Indent(bool forwards, int lineBottom, int lineTop); static std::string TransformLineEnds(const char *s, size_t len, int eolModeWanted); @@ -339,6 +349,7 @@ public: void DeleteAllMarks(int markerNum); int LineFromHandle(int markerHandle); int SCI_METHOD LineStart(int line) const; + bool IsLineStartPosition(int position) const; int SCI_METHOD LineEnd(int line) const; int LineEndPosition(int position) const; bool IsLineEndPosition(int position) const; @@ -358,6 +369,16 @@ public: int NextWordEnd(int pos, int delta); int SCI_METHOD Length() const { return cb.Length(); } void Allocate(int newSize) { cb.Allocate(newSize); } + + struct CharacterExtracted { + unsigned int character; + unsigned int widthBytes; + CharacterExtracted(unsigned int character_, unsigned int widthBytes_) : + character(character_), widthBytes(widthBytes_) { + } + }; + CharacterExtracted ExtractCharacter(int position) const; + bool MatchesWordOptions(bool word, bool wordStart, int pos, int length) const; bool HasCaseFolder(void) const; void SetCaseFolder(CaseFolder *pcf_); @@ -368,7 +389,7 @@ public: void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); - int GetCharsOfClass(CharClassify::cc charClass, unsigned char *buffer); + int GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer); 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); diff --git a/src/stc/scintilla/src/EditModel.cxx b/src/stc/scintilla/src/EditModel.cxx new file mode 100644 index 0000000000..fe65a8bf8d --- /dev/null +++ b/src/stc/scintilla/src/EditModel.cxx @@ -0,0 +1,76 @@ +// Scintilla source code edit control +/** @file EditModel.cxx + ** Defines the editor state that must be visible to EditorView. + **/ +// Copyright 1998-2014 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +Caret::Caret() : + active(false), on(false), period(500) {} + +EditModel::EditModel() { + inOverstrike = false; + xOffset = 0; + trackLineWidth = false; + posDrag = SelectionPosition(invalidPosition); + braces[0] = invalidPosition; + braces[1] = invalidPosition; + bracesMatchStyle = STYLE_BRACEBAD; + highlightGuideColumn = 0; + primarySelection = true; + imeInteraction = imeWindowed; + foldFlags = 0; + hotspot = Range(invalidPosition); + wrapWidth = LineLayout::wrapWidthInfinite; + pdoc = new Document(); + pdoc->AddRef(); +} + +EditModel::~EditModel() { + pdoc->Release(); + pdoc = 0; +} diff --git a/src/stc/scintilla/src/EditModel.h b/src/stc/scintilla/src/EditModel.h new file mode 100644 index 0000000000..d8def32942 --- /dev/null +++ b/src/stc/scintilla/src/EditModel.h @@ -0,0 +1,69 @@ +// Scintilla source code edit control +/** @file EditModel.h + ** Defines the editor state that must be visible to EditorView. + **/ +// Copyright 1998-2014 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITMODEL_H +#define EDITMODEL_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** +*/ +class Caret { +public: + bool active; + bool on; + int period; + + Caret(); +}; + +class EditModel { + // Private so EditModel objects can not be copied + EditModel(const EditModel &); + EditModel &operator=(const EditModel &); + +public: + bool inOverstrike; + int xOffset; ///< Horizontal scrolled amount in pixels + bool trackLineWidth; + + SpecialRepresentations reprs; + Caret caret; + SelectionPosition posDrag; + Position braces[2]; + int bracesMatchStyle; + int highlightGuideColumn; + Selection sel; + bool primarySelection; + + enum IMEInteraction { imeWindowed, imeInline } imeInteraction; + + int foldFlags; + ContractionState cs; + // Hotspot support + Range hotspot; + + // Wrapping support + int wrapWidth; + + Document *pdoc; + + EditModel(); + virtual ~EditModel(); + virtual int TopLineOfMain() const = 0; + virtual Point GetVisibleOriginInMain() const = 0; + virtual int LinesOnScreen() const = 0; + virtual Range GetHotSpotRange() const = 0; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/src/stc/scintilla/src/EditView.cxx b/src/stc/scintilla/src/EditView.cxx new file mode 100644 index 0000000000..4976d3614b --- /dev/null +++ b/src/stc/scintilla/src/EditView.cxx @@ -0,0 +1,2088 @@ +// Scintilla source code edit control +/** @file Editor.cxx + ** Defines the appearance of the main text area of the editor window. + **/ +// Copyright 1998-2014 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "PerLine.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static inline bool IsControlCharacter(int ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +PrintParameters::PrintParameters() { + magnification = 0; + colourMode = SC_PRINT_NORMAL; + wrapState = eWrapWord; +} + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { + if (st.multipleStyles) { + for (size_t iStyle = 0; iStyle(styles[endSegment + 1]) == style)) + endSegment++; + FontAlias fontText = vs.styles[style + styleOffset].font; + width += static_cast(surface->WidthText(fontText, text + start, + static_cast(endSegment - start + 1))); + start = endSegment + 1; + } + return width; +} + +int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { + int widthMax = 0; + size_t start = 0; + while (start < st.length) { + size_t lenLine = st.LineLength(start); + int widthSubLine; + if (st.multipleStyles) { + widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); + } else { + FontAlias fontText = vs.styles[styleOffset + st.style].font; + widthSubLine = static_cast(surface->WidthText(fontText, + st.text + start, static_cast(lenLine))); + } + if (widthSubLine > widthMax) + widthMax = widthSubLine; + start += lenLine + 1; + } + return widthMax; +} + +void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, + const char *s, int len, DrawPhase phase) { + FontAlias fontText = style.font; + if (phase & drawBack) { + if (phase & drawText) { + // Drawing both + surface->DrawTextNoClip(rc, fontText, ybase, s, len, + style.fore, style.back); + } else { + surface->FillRectangle(rc, style.back); + } + } else if (phase & drawText) { + surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore); + } +} + +void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, + const StyledText &st, size_t start, size_t length, DrawPhase phase) { + + if (st.multipleStyles) { + int x = static_cast(rcText.left); + size_t i = 0; + while (i < length) { + size_t end = i; + size_t style = st.styles[i + start]; + while (end < length - 1 && st.styles[start + end + 1] == style) + end++; + style += styleOffset; + FontAlias fontText = vs.styles[style].font; + const int width = static_cast(surface->WidthText(fontText, + st.text + start + i, static_cast(end - i + 1))); + PRectangle rcSegment = rcText; + rcSegment.left = static_cast(x); + rcSegment.right = static_cast(x + width + 1); + DrawTextNoClipPhase(surface, rcSegment, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start + i, + static_cast(end - i + 1), phase); + x += width; + i = end + 1; + } + } else { + const size_t style = st.style + styleOffset; + DrawTextNoClipPhase(surface, rcText, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start, + static_cast(length), phase); + } +} + +#ifdef SCI_NAMESPACE +} +#endif + +const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues + +EditView::EditView() { + ldTabstops = NULL; + hideSelection = false; + drawOverstrikeCaret = true; + bufferedDraw = true; + phasesDraw = phasesTwo; + lineWidthMaxSeen = 0; + additionalCaretsBlink = true; + additionalCaretsVisible = true; + imeCaretBlockOverride = false; + pixmapLine = 0; + pixmapIndentGuide = 0; + pixmapIndentGuideHighlight = 0; + llc.SetLevel(LineLayoutCache::llcCaret); + posCache.SetSize(0x400); + tabArrowHeight = 4; + customDrawTabArrow = NULL; + customDrawWrapMarker = NULL; +} + +EditView::~EditView() { + delete ldTabstops; + ldTabstops = NULL; +} + +bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) { + const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne; + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::SetPhasesDraw(int phases) { + const PhasesDraw phasesDrawNew = static_cast(phases); + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::LinesOverlap() const { + return phasesDraw == phasesMultiple; +} + +void EditView::ClearAllTabstops() { + delete ldTabstops; + ldTabstops = 0; +} + +XYPOSITION EditView::NextTabstopPos(int line, XYPOSITION x, XYPOSITION tabWidth) const { + int next = GetNextTabstop(line, static_cast(x + 2)); + if (next > 0) + return static_cast(next); + return (static_cast((x + 2) / tabWidth) + 1) * tabWidth; +} + +bool EditView::ClearTabstops(int line) { + LineTabstops *lt = static_cast(ldTabstops); + return lt && lt->ClearTabstops(line); +} + +bool EditView::AddTabstop(int line, int x) { + if (!ldTabstops) { + ldTabstops = new LineTabstops(); + } + LineTabstops *lt = static_cast(ldTabstops); + return lt && lt->AddTabstop(line, x); +} + +int EditView::GetNextTabstop(int line, int x) const { + LineTabstops *lt = static_cast(ldTabstops); + if (lt) { + return lt->GetNextTabstop(line, x); + } else { + return 0; + } +} + +void EditView::LinesAddedOrRemoved(int lineOfPos, int linesAdded) { + if (ldTabstops) { + if (linesAdded > 0) { + for (int line = lineOfPos; line < lineOfPos + linesAdded; line++) { + ldTabstops->InsertLine(line); + } + } else { + for (int line = (lineOfPos + -linesAdded) - 1; line >= lineOfPos; line--) { + ldTabstops->RemoveLine(line); + } + } + } +} + +void EditView::DropGraphics(bool freeObjects) { + if (freeObjects) { + delete pixmapLine; + pixmapLine = 0; + delete pixmapIndentGuide; + pixmapIndentGuide = 0; + delete pixmapIndentGuideHighlight; + pixmapIndentGuideHighlight = 0; + } else { + if (pixmapLine) + pixmapLine->Release(); + if (pixmapIndentGuide) + pixmapIndentGuide->Release(); + if (pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight->Release(); + } +} + +void EditView::AllocateGraphics(const ViewStyle &vsDraw) { + if (!pixmapLine) + pixmapLine = Surface::Allocate(vsDraw.technology); + if (!pixmapIndentGuide) + pixmapIndentGuide = Surface::Allocate(vsDraw.technology); + if (!pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight = Surface::Allocate(vsDraw.technology); +} + +const char *ControlCharacterString(unsigned char ch) { + const char *reps[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" + }; + if (ch < ELEMENTS(reps)) { + return reps[ch]; + } else { + return "BAD"; + } +} + +void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { + int ydiff = static_cast(rcTab.bottom - rcTab.top) / 2; + int xhead = static_cast(rcTab.right) - 1 - ydiff; + if (xhead <= rcTab.left) { + ydiff -= static_cast(rcTab.left) - xhead - 1; + xhead = static_cast(rcTab.left) - 1; + } + if ((rcTab.left + 2) < (rcTab.right - 1)) + surface->MoveTo(static_cast(rcTab.left) + 2, ymid); + else + surface->MoveTo(static_cast(rcTab.right) - 1, ymid); + surface->LineTo(static_cast(rcTab.right) - 1, ymid); + surface->LineTo(xhead, ymid - ydiff); + surface->MoveTo(static_cast(rcTab.right) - 1, ymid); + surface->LineTo(xhead, ymid + ydiff); +} + +void EditView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { + if (!pixmapIndentGuide->Initialised()) { + // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line + pixmapIndentGuide->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); + pixmapIndentGuideHighlight->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); + PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vsDraw.lineHeight); + pixmapIndentGuide->FillRectangle(rcIG, vsDraw.styles[STYLE_INDENTGUIDE].back); + pixmapIndentGuide->PenColour(vsDraw.styles[STYLE_INDENTGUIDE].fore); + pixmapIndentGuideHighlight->FillRectangle(rcIG, vsDraw.styles[STYLE_BRACELIGHT].back); + pixmapIndentGuideHighlight->PenColour(vsDraw.styles[STYLE_BRACELIGHT].fore); + for (int stripe = 1; stripe < vsDraw.lineHeight + 1; stripe += 2) { + PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1); + pixmapIndentGuide->FillRectangle(rcPixel, vsDraw.styles[STYLE_INDENTGUIDE].fore); + pixmapIndentGuideHighlight->FillRectangle(rcPixel, vsDraw.styles[STYLE_BRACELIGHT].fore); + } + } +} + +LineLayout *EditView::RetrieveLineLayout(int lineNumber, const EditModel &model) { + int posLineStart = model.pdoc->LineStart(lineNumber); + int posLineEnd = model.pdoc->LineStart(lineNumber + 1); + PLATFORM_ASSERT(posLineEnd >= posLineStart); + int lineCaret = model.pdoc->LineFromPosition(model.sel.MainCaret()); + return llc.Retrieve(lineNumber, lineCaret, + posLineEnd - posLineStart, model.pdoc->GetStyleClock(), + model.LinesOnScreen() + 1, model.pdoc->LinesTotal()); +} + +/** +* Fill in the LineLayout data for the given line. +* Copy the given @a line and its styles from the document into local arrays. +* Also determine the x position at which each character starts. +*/ +void EditView::LayoutLine(const EditModel &model, int line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) { + if (!ll) + return; + + PLATFORM_ASSERT(line < model.pdoc->LinesTotal()); + PLATFORM_ASSERT(ll->chars != NULL); + int posLineStart = model.pdoc->LineStart(line); + int posLineEnd = model.pdoc->LineStart(line + 1); + // If the line is very long, limit the treatment to a length that should fit in the viewport + if (posLineEnd >(posLineStart + ll->maxLineLength)) { + posLineEnd = posLineStart + ll->maxLineLength; + } + if (ll->validity == LineLayout::llCheckTextAndStyle) { + int lineLength = posLineEnd - posLineStart; + if (!vstyle.viewEOL) { + lineLength = model.pdoc->LineEnd(line) - posLineStart; + } + if (lineLength == ll->numCharsInLine) { + // See if chars, styles, indicators, are all the same + bool allSame = true; + // Check base line layout + char styleByte = 0; + int numCharsInLine = 0; + while (numCharsInLine < lineLength) { + int charInDoc = numCharsInLine + posLineStart; + char chDoc = model.pdoc->CharAt(charInDoc); + styleByte = model.pdoc->StyleAt(charInDoc); + allSame = allSame && + (ll->styles[numCharsInLine] == static_cast(styleByte)); + if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) + allSame = allSame && + (ll->chars[numCharsInLine] == chDoc); + else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast(tolower(chDoc))); + else // Style::caseUpper + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast(toupper(chDoc))); + numCharsInLine++; + } + allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled + if (allSame) { + ll->validity = LineLayout::llPositions; + } else { + ll->validity = LineLayout::llInvalid; + } + } else { + ll->validity = LineLayout::llInvalid; + } + } + if (ll->validity == LineLayout::llInvalid) { + ll->widthLine = LineLayout::wrapWidthInfinite; + ll->lines = 1; + if (vstyle.edgeState == EDGE_BACKGROUND) { + ll->edgeColumn = model.pdoc->FindColumn(line, vstyle.theEdge); + if (ll->edgeColumn >= posLineStart) { + ll->edgeColumn -= posLineStart; + } + } else { + ll->edgeColumn = -1; + } + + // Fill base line layout + const int lineLength = posLineEnd - posLineStart; + model.pdoc->GetCharRange(ll->chars, posLineStart, lineLength); + model.pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); + int numCharsBeforeEOL = model.pdoc->LineEnd(line) - posLineStart; + const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; + for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { + const unsigned char styleByte = ll->styles[styleInLine]; + ll->styles[styleInLine] = styleByte; + } + const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength - 1] : 0; + 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; + // Extra element at the end of the line to hold end x position and act as + ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character + ll->styles[numCharsInLine] = styleByteLast; // For eolFilled + + // Layout the line, determining the position of each character, + // with an extra element at the end for the end of the line. + ll->positions[0] = 0; + bool lastSegItalics = false; + + BreakFinder bfLayout(ll, NULL, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs); + while (bfLayout.More()) { + + const TextSegment ts = bfLayout.Next(); + + std::fill(&ll->positions[ts.start + 1], &ll->positions[ts.end() + 1], 0.0f); + if (vstyle.styles[ll->styles[ts.start]].visible) { + if (ts.representation) { + XYPOSITION representationWidth = vstyle.controlCharWidth; + if (ll->chars[ts.start] == '\t') { + // Tab is a special case of representation, taking a variable amount of space + const XYPOSITION x = ll->positions[ts.start]; + representationWidth = NextTabstopPos(line, x, vstyle.tabWidth) - ll->positions[ts.start]; + } else { + if (representationWidth <= 0.0) { + XYPOSITION positionsRepr[256]; // Should expand when needed + posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, ts.representation->stringRep.c_str(), + static_cast(ts.representation->stringRep.length()), positionsRepr, model.pdoc); + representationWidth = positionsRepr[ts.representation->stringRep.length() - 1] + vstyle.ctrlCharPadding; + } + } + for (int ii = 0; ii < ts.length; ii++) + ll->positions[ts.start + 1 + ii] = representationWidth; + } else { + if ((ts.length == 1) && (' ' == ll->chars[ts.start])) { + // Over half the segments are single characters and of these about half are space characters. + ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth; + } else { + posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], ll->chars + ts.start, + ts.length, ll->positions + ts.start + 1, model.pdoc); + } + } + lastSegItalics = (!ts.representation) && ((ll->chars[ts.end() - 1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic); + } + + for (int posToIncrease = ts.start + 1; posToIncrease <= ts.end(); posToIncrease++) { + ll->positions[posToIncrease] += ll->positions[ts.start]; + } + } + + // Small hack to make lines that end with italics not cut off the edge of the last character + if (lastSegItalics) { + ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset; + } + ll->numCharsInLine = numCharsInLine; + ll->numCharsBeforeEOL = numCharsBeforeEOL; + ll->validity = LineLayout::llPositions; + } + // Hard to cope when too narrow, so just assume there is space + if (width < 20) { + width = 20; + } + if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { + ll->widthLine = width; + if (width == LineLayout::wrapWidthInfinite) { + ll->lines = 1; + } else if (width > ll->positions[ll->numCharsInLine]) { + // Simple common case where line does not need wrapping. + ll->lines = 1; + } else { + if (vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + width -= static_cast(vstyle.aveCharWidth); // take into account the space for end wrap mark + } + XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line + if (vstyle.wrapIndentMode == SC_WRAPINDENT_INDENT) { + wrapAddIndent = model.pdoc->IndentSize() * vstyle.spaceWidth; + } else if (vstyle.wrapIndentMode == SC_WRAPINDENT_FIXED) { + wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth; + } + ll->wrapIndent = wrapAddIndent; + if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED) + for (int i = 0; i < ll->numCharsInLine; i++) { + if (!IsSpaceOrTab(ll->chars[i])) { + ll->wrapIndent += ll->positions[i]; // Add line indent + break; + } + } + // Check for text width minimum + if (ll->wrapIndent > width - static_cast(vstyle.aveCharWidth) * 15) + ll->wrapIndent = wrapAddIndent; + // Check for wrapIndent minimum + if ((vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) + ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual + ll->lines = 0; + // Calculate line start positions based upon width. + int lastGoodBreak = 0; + int lastLineStart = 0; + XYACCUMULATOR startOffset = 0; + int p = 0; + while (p < ll->numCharsInLine) { + if ((ll->positions[p + 1] - startOffset) >= width) { + if (lastGoodBreak == lastLineStart) { + // Try moving to start of last character + if (p > 0) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + } + if (lastGoodBreak == lastLineStart) { + // Ensure at least one character on line. + lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) + - posLineStart; + } + } + lastLineStart = lastGoodBreak; + ll->lines++; + ll->SetLineStart(ll->lines, lastGoodBreak); + startOffset = ll->positions[lastGoodBreak]; + // take into account the space for start wrap mark and indent + startOffset -= ll->wrapIndent; + p = lastGoodBreak + 1; + continue; + } + if (p > 0) { + if (vstyle.wrapState == eWrapChar) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; + continue; + } else if ((vstyle.wrapState == eWrapWord) && (ll->styles[p] != ll->styles[p - 1])) { + lastGoodBreak = p; + } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { + lastGoodBreak = p; + } + } + p++; + } + ll->lines++; + } + ll->validity = LineLayout::llLines; + } +} + +Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, int topLine, const ViewStyle &vs) { + Point pt; + if (pos.Position() == INVALID_POSITION) + return pt; + const int line = model.pdoc->LineFromPosition(pos.Position()); + const int lineVisible = model.cs.DisplayFromDoc(line); + //Platform::DebugPrintf("line=%d\n", line); + AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); + if (surface && ll) { + const int posLineStart = model.pdoc->LineStart(line); + LayoutLine(model, line, surface, vs, ll, model.wrapWidth); + const int posInLine = pos.Position() - posLineStart; + pt = ll->PointFromPosition(posInLine, vs.lineHeight); + pt.y += (lineVisible - topLine) * vs.lineHeight; + pt.x += vs.textStart - model.xOffset; + } + pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; + return pt; +} + +SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) { + pt.x = pt.x - vs.textStart; + int visibleLine = static_cast(floor(pt.y / vs.lineHeight)); + if (!canReturnInvalid && (visibleLine < 0)) + visibleLine = 0; + const int lineDoc = model.cs.DocFromDisplay(visibleLine); + if (canReturnInvalid && (lineDoc < 0)) + return SelectionPosition(INVALID_POSITION); + if (lineDoc >= model.pdoc->LinesTotal()) + return SelectionPosition(canReturnInvalid ? INVALID_POSITION : model.pdoc->Length()); + const int posLineStart = model.pdoc->LineStart(lineDoc); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + const int lineStartSet = model.cs.DisplayFromDoc(lineDoc); + const int subLine = visibleLine - lineStartSet; + if (subLine < ll->lines) { + const Range rangeSubLine = ll->SubLineRange(subLine); + const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; + if (subLine > 0) // Wrapped + pt.x -= ll->wrapIndent; + const int positionInLine = ll->FindPositionFromX(pt.x + subLineStart, rangeSubLine, charPosition); + if (positionInLine < rangeSubLine.end) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); + } + if (virtualSpace) { + const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; + const int spaceOffset = static_cast( + (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); + return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); + } else if (canReturnInvalid) { + if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1)); + } + } else { + return SelectionPosition(rangeSubLine.end + posLineStart); + } + } + if (!canReturnInvalid) + return SelectionPosition(ll->numCharsInLine + posLineStart); + } + return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart); +} + +/** +* Find the document position corresponding to an x coordinate on a particular document line. +* Ensure is between whole characters when document is in multi-byte or UTF-8 mode. +* This method is used for rectangular selections and does not work on wrapped lines. +*/ +SelectionPosition EditView::SPositionFromLineX(Surface *surface, const EditModel &model, int lineDoc, int x, const ViewStyle &vs) { + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + const int posLineStart = model.pdoc->LineStart(lineDoc); + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + const Range rangeSubLine = ll->SubLineRange(0); + const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; + const int positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false); + if (positionInLine < rangeSubLine.end) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); + } + const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; + const int spaceOffset = static_cast( + (x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); + return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); + } + return SelectionPosition(0); +} + +int EditView::DisplayFromPosition(Surface *surface, const EditModel &model, int pos, const ViewStyle &vs) { + int lineDoc = model.pdoc->LineFromPosition(pos); + int lineDisplay = model.cs.DisplayFromDoc(lineDoc); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + unsigned int posLineStart = model.pdoc->LineStart(lineDoc); + int posInLine = pos - posLineStart; + lineDisplay--; // To make up for first increment ahead. + for (int subLine = 0; subLine < ll->lines; subLine++) { + if (posInLine >= ll->LineStart(subLine)) { + lineDisplay++; + } + } + } + return lineDisplay; +} + +int EditView::StartEndDisplayLine(Surface *surface, const EditModel &model, int pos, bool start, const ViewStyle &vs) { + int line = model.pdoc->LineFromPosition(pos); + AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); + int posRet = INVALID_POSITION; + if (surface && ll) { + unsigned int posLineStart = model.pdoc->LineStart(line); + LayoutLine(model, line, surface, vs, ll, model.wrapWidth); + int posInLine = pos - posLineStart; + if (posInLine <= ll->maxLineLength) { + for (int subLine = 0; subLine < ll->lines; subLine++) { + if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { + if (start) { + posRet = ll->LineStart(subLine) + posLineStart; + } else { + if (subLine == ll->lines - 1) + posRet = ll->LineStart(subLine + 1) + posLineStart; + else + posRet = ll->LineStart(subLine + 1) + posLineStart - 1; + } + } + } + } + } + return posRet; +} + +static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) { + return main ? + (primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) : + vsDraw.selAdditionalBackground; +} + +static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + ColourOptional background, int inSelection, bool inHotspot, int styleMain, int i) { + if (inSelection == 1) { + if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, true, model.primarySelection); + } + } else if (inSelection == 2) { + if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, false, model.primarySelection); + } + } else { + if ((vsDraw.edgeState == EDGE_BACKGROUND) && + (i >= ll->edgeColumn) && + (i < ll->numCharsBeforeEOL)) + return vsDraw.edgecolour; + if (inHotspot && vsDraw.hotspotColours.back.isSet) + return vsDraw.hotspotColours.back; + } + if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { + return background; + } else { + return vsDraw.styles[styleMain].back; + } +} + +void EditView::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { + Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); + PRectangle rcCopyArea = PRectangle::FromInts(start + 1, static_cast(rcSegment.top), start + 2, static_cast(rcSegment.bottom)); + surface->Copy(rcCopyArea, from, + highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); +} + +static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { + if (alpha != SC_ALPHA_NOALPHA) { + surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); + } +} + +static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, + const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) { + if (fillBackground) { + surface->FillRectangle(rcSegment, textBack); + } + FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; + int normalCharHeight = static_cast(surface->Ascent(ctrlCharsFont) - + surface->InternalLeading(ctrlCharsFont)); + PRectangle rcCChar = rcSegment; + rcCChar.left = rcCChar.left + 1; + rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; + rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; + PRectangle rcCentral = rcCChar; + rcCentral.top++; + rcCentral.bottom--; + surface->FillRectangle(rcCentral, textFore); + PRectangle rcChar = rcCChar; + rcChar.left++; + rcChar.right--; + surface->DrawTextClipped(rcChar, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, s, static_cast(s ? strlen(s) : 0), + textBack, textFore); +} + +void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + PRectangle rcLine, int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, + ColourOptional background) { + + const int posLineStart = model.pdoc->LineStart(line); + PRectangle rcSegment = rcLine; + + const bool lastSubLine = subLine == (ll->lines - 1); + XYPOSITION virtualSpace = 0; + if (lastSubLine) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth; + } + XYPOSITION xEol = static_cast(ll->positions[lineEnd] - subLineStart); + + // Fill the virtual space and show selections within it + if (virtualSpace) { + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + xStart + virtualSpace; + surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { + SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)))); + for (size_t r = 0; rEndLineStyle()].spaceWidth; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast(subLineStart)+portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast(subLineStart)+portion.end.VirtualSpace() * spaceWidth; + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection)); + } + } + } + } + } + + int eolInSelection = 0; + int alpha = SC_ALPHA_NOALPHA; + if (!hideSelection) { + int posAfterLineEnd = model.pdoc->LineStart(line + 1); + eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0; + alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + } + + // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on + XYPOSITION blobsWidth = 0; + if (lastSubLine) { + for (int eolPos = ll->numCharsBeforeEOL; eolPosnumCharsInLine; eolPos++) { + rcSegment.left = xStart + ll->positions[eolPos] - static_cast(subLineStart)+virtualSpace; + rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast(subLineStart)+virtualSpace; + blobsWidth += rcSegment.Width(); + char hexits[4]; + const char *ctrlChar; + unsigned char chEOL = ll->chars[eolPos]; + int styleMain = ll->styles[eolPos]; + ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos); + if (UTF8IsAscii(chEOL)) { + ctrlChar = ControlCharacterString(chEOL); + } else { + const Representation *repr = model.reprs.RepresentationFromCharacter(ll->chars + eolPos, ll->numCharsInLine - eolPos); + if (repr) { + ctrlChar = repr->stringRep.c_str(); + eolPos = ll->numCharsInLine; + } else { + sprintf(hexits, "x%2X", chEOL); + ctrlChar = hexits; + } + } + ColourDesired textFore = vsDraw.styles[styleMain].fore; + if (eolInSelection && vsDraw.selColours.fore.isSet) { + textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; + } + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1)) { + if (alpha == SC_ALPHA_NOALPHA) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + surface->FillRectangle(rcSegment, textBack); + } + } else { + surface->FillRectangle(rcSegment, textBack); + } + DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne); + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + } + + // Draw the eol-is-selected rectangle + rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; + rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; + + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + if (background.isSet) { + surface->FillRectangle(rcSegment, background); + } else if (line < model.pdoc->LinesTotal() - 1) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); + } + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + + // Fill the remainder of the line + rcSegment.left = rcSegment.right; + if (rcSegment.left < rcLine.left) + rcSegment.left = rcLine.left; + rcSegment.right = rcLine.right; + + if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + if (background.isSet) { + surface->FillRectangle(rcSegment, background); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); + } + if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + + bool drawWrapMarkEnd = false; + + if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + if (subLine + 1 < ll->lines) { + drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; + } + } + + if (drawWrapMarkEnd) { + PRectangle rcPlace = rcSegment; + + if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { + rcPlace.left = xEol + xStart + virtualSpace; + rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; + } else { + // rcLine is clipped to text area + rcPlace.right = rcLine.right; + rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; + } + if (customDrawWrapMarker == NULL) { + DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); + } else { + customDrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); + } + } +} + +static void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, const ViewStyle &vsDraw, + const LineLayout *ll, int xStart, PRectangle rcLine, int subLine) { + const XYPOSITION 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); +} + +static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, int lineEnd, bool under) { + // Draw decorators + const int posLineStart = model.pdoc->LineStart(line); + const int lineStart = ll->LineStart(subLine); + const int posLineEnd = posLineStart + lineEnd; + + for (Decoration *deco = model.pdoc->decorations.root; deco; deco = deco->next) { + if (under == vsDraw.indicators[deco->indicator].under) { + int startPos = posLineStart + lineStart; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { + int endPos = deco->rs.EndRun(startPos); + if (endPos > posLineEnd) + endPos = posLineEnd; + DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, + surface, vsDraw, ll, xStart, rcLine, subLine); + startPos = endPos; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + } + } + } + + // Use indicators to highlight matching braces + if ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) || + (vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))) { + int braceIndicator = (model.bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.braceBadLightIndicator; + if (under == vsDraw.indicators[braceIndicator].under) { + Range rangeLine(posLineStart + lineStart, posLineEnd); + if (rangeLine.ContainsCharacter(model.braces[0])) { + int braceOffset = model.braces[0] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine); + } + } + if (rangeLine.ContainsCharacter(model.braces[1])) { + int braceOffset = model.braces[1] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine); + } + } + } + } +} + +static bool AnnotationBoxedOrIndented(int annotationVisible) { + return annotationVisible == ANNOTATION_BOXED || annotationVisible == ANNOTATION_INDENTED; +} + +void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { + int indent = static_cast(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); + PRectangle rcSegment = rcLine; + int annotationLine = subLine - ll->lines; + const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line); + if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { + if (phase & drawBack) { + surface->FillRectangle(rcSegment, vsDraw.styles[0].back); + } + rcSegment.left = static_cast(xStart); + if (model.trackLineWidth || AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { + // Only care about calculating width if tracking or need to draw indented box + int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); + if (AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { + widthAnnotation += static_cast(vsDraw.spaceWidth * 2); // Margins + rcSegment.left = static_cast(xStart + indent); + rcSegment.right = rcSegment.left + widthAnnotation; + } + if (widthAnnotation > lineWidthMaxSeen) + lineWidthMaxSeen = widthAnnotation; + } + const int annotationLines = model.pdoc->AnnotationLines(line); + size_t start = 0; + size_t lengthAnnotation = stAnnotation.LineLength(start); + int lineInAnnotation = 0; + while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { + start += lengthAnnotation + 1; + lengthAnnotation = stAnnotation.LineLength(start); + lineInAnnotation++; + } + PRectangle rcText = rcSegment; + if ((phase & drawBack) && AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { + surface->FillRectangle(rcText, + vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); + rcText.left += vsDraw.spaceWidth; + } + DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, + stAnnotation, start, lengthAnnotation, phase); + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); + surface->MoveTo(static_cast(rcSegment.left), static_cast(rcSegment.top)); + surface->LineTo(static_cast(rcSegment.left), static_cast(rcSegment.bottom)); + surface->MoveTo(static_cast(rcSegment.right), static_cast(rcSegment.top)); + surface->LineTo(static_cast(rcSegment.right), static_cast(rcSegment.bottom)); + if (subLine == ll->lines) { + surface->MoveTo(static_cast(rcSegment.left), static_cast(rcSegment.top)); + surface->LineTo(static_cast(rcSegment.right), static_cast(rcSegment.top)); + } + if (subLine == ll->lines + annotationLines - 1) { + surface->MoveTo(static_cast(rcSegment.left), static_cast(rcSegment.bottom - 1)); + surface->LineTo(static_cast(rcSegment.right), static_cast(rcSegment.bottom - 1)); + } + } + } +} + +static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) { + + int lineStart = ll->LineStart(subLine); + int posBefore = posCaret; + int posAfter = model.pdoc->MovePositionOutsideChar(posCaret + 1, 1); + int numCharsToDraw = posAfter - posCaret; + + // Work out where the starting and ending offsets are. We need to + // see if the previous character shares horizontal space, such as a + // glyph / combining character. If so we'll need to draw that too. + int offsetFirstChar = offset; + int offsetLastChar = offset + (posAfter - posCaret); + while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) { + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + // Update posBefore to point to the prev char + posBefore = model.pdoc->MovePositionOutsideChar(posBefore - 1, -1); + numCharsToDraw = posAfter - posBefore; + offsetFirstChar = offset - (posCaret - posBefore); + } + + // See if the next character shares horizontal space, if so we'll + // need to draw that too. + if (offsetFirstChar < 0) + offsetFirstChar = 0; + numCharsToDraw = offsetLastChar - offsetFirstChar; + while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { + // Update posAfter to point to the 2nd next char, this is where + // the next character ends, and 2nd next begins. We'll need + // to compare these two + posBefore = posAfter; + posAfter = model.pdoc->MovePositionOutsideChar(posAfter + 1, 1); + offsetLastChar = offset + (posAfter - posCaret); + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + numCharsToDraw = offsetLastChar - offsetFirstChar; + } + + // We now know what to draw, update the caret drawing rectangle + rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; + rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart; + + // Adjust caret position to take into account any word wrapping symbols. + if ((ll->wrapIndent != 0) && (lineStart != 0)) { + XYPOSITION wordWrapCharWidth = ll->wrapIndent; + rcCaret.left += wordWrapCharWidth; + rcCaret.right += wordWrapCharWidth; + } + + // This character is where the caret block is, we override the colours + // (inversed) for drawing the caret here. + int styleMain = ll->styles[offsetFirstChar]; + FontAlias fontText = vsDraw.styles[styleMain].font; + surface->DrawTextClipped(rcCaret, fontText, + rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, + numCharsToDraw, vsDraw.styles[styleMain].back, + caretColour); +} + +void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int lineDoc, int xStart, PRectangle rcLine, int subLine) const { + // When drag is active it is the only caret drawn + bool drawDrag = model.posDrag.IsValid(); + if (hideSelection && !drawDrag) + return; + const int posLineStart = model.pdoc->LineStart(lineDoc); + // For each selection draw + for (size_t r = 0; (rEndLineStyle()].spaceWidth; + const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth; + if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { + XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; + if (ll->wrapIndent != 0) { + int lineStart = ll->LineStart(subLine); + if (lineStart != 0) // Wrapped + xposCaret += ll->wrapIndent; + } + bool caretBlinkState = (model.caret.active && model.caret.on) || (!additionalCaretsBlink && !mainCaret); + bool caretVisibleState = additionalCaretsVisible || mainCaret; + if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && + ((model.posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) { + bool caretAtEOF = false; + bool caretAtEOL = false; + bool drawBlockCaret = false; + XYPOSITION widthOverstrikeCaret; + XYPOSITION caretWidthOffset = 0; + PRectangle rcCaret = rcLine; + + if (posCaret.Position() == model.pdoc->Length()) { // At end of document + caretAtEOF = true; + widthOverstrikeCaret = vsDraw.aveCharWidth; + } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line + caretAtEOL = true; + widthOverstrikeCaret = vsDraw.aveCharWidth; + } else { + const int widthChar = model.pdoc->LenChar(posCaret.Position()); + widthOverstrikeCaret = ll->positions[offset + widthChar] - ll->positions[offset]; + } + if (widthOverstrikeCaret < 3) // Make sure its visible + widthOverstrikeCaret = 3; + + if (xposCaret > 0) + caretWidthOffset = 0.51f; // Move back so overlaps both character cells. + xposCaret += xStart; + if (model.posDrag.IsValid()) { + /* Dragging text, use a line caret */ + rcCaret.left = static_cast(RoundXYPosition(xposCaret - caretWidthOffset)); + rcCaret.right = rcCaret.left + vsDraw.caretWidth; + } else if (model.inOverstrike && drawOverstrikeCaret) { + /* Overstrike (insert mode), use a modified bar caret */ + rcCaret.top = rcCaret.bottom - 2; + rcCaret.left = xposCaret + 1; + rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; + } else if ((vsDraw.caretStyle == CARETSTYLE_BLOCK) || imeCaretBlockOverride) { + /* Block caret */ + rcCaret.left = xposCaret; + if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { + drawBlockCaret = true; + rcCaret.right = xposCaret + widthOverstrikeCaret; + } else { + rcCaret.right = xposCaret + vsDraw.aveCharWidth; + } + } else { + /* Line caret */ + rcCaret.left = static_cast(RoundXYPosition(xposCaret - caretWidthOffset)); + rcCaret.right = rcCaret.left + vsDraw.caretWidth; + } + ColourDesired caretColour = mainCaret ? vsDraw.caretcolour : vsDraw.additionalCaretColour; + if (drawBlockCaret) { + DrawBlockCaret(surface, model, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); + } else { + surface->FillRectangle(rcCaret, caretColour); + } + } + } + if (drawDrag) + break; + } +} + +static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, + int xStart, PRectangle rcLine, ColourOptional background, DrawWrapMarkerFn customDrawWrapMarker) { + // default bgnd here.. + surface->FillRectangle(rcLine, background.isSet ? background : + vsDraw.styles[STYLE_DEFAULT].back); + + if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_START) { + + // draw continuation rect + PRectangle rcPlace = rcLine; + + rcPlace.left = static_cast(xStart); + rcPlace.right = rcPlace.left + ll->wrapIndent; + + if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT) + rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; + else + rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; + + if (customDrawWrapMarker == NULL) { + DrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour()); + } else { + customDrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour()); + } + } +} + +void EditView::DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + PRectangle rcLine, Range lineRange, int posLineStart, int xStart, + int subLine, ColourOptional background) const { + + const bool selBackDrawn = vsDraw.SelectionBackgroundDrawn(); + bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. + const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; + // Does not take margin into account but not significant + const int xStartVisible = static_cast(subLineStart)-xStart; + + BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, selBackDrawn, model.pdoc, &model.reprs); + + const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background.isSet; + + // Background drawing loop + while (bfBack.More()) { + + const TextSegment ts = bfBack.Next(); + const int i = ts.end() - 1; + const int iDoc = i + posLineStart; + + PRectangle rcSegment = rcLine; + rcSegment.left = ll->positions[ts.start] + xStart - static_cast(subLineStart); + rcSegment.right = ll->positions[ts.end()] + xStart - static_cast(subLineStart); + // Only try to draw if really visible - enhances performance by not calling environment to + // draw strings that are completely past the right side of the window. + if (rcSegment.Intersects(rcLine)) { + // Clip to line rectangle, since may have a huge position which will not work with some platforms + if (rcSegment.left < rcLine.left) + rcSegment.left = rcLine.left; + if (rcSegment.right > rcLine.right) + rcSegment.right = rcLine.right; + + const int inSelection = hideSelection ? 0 : model.sel.CharacterInSelection(iDoc); + const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); + ColourDesired textBack = TextBackground(model, vsDraw, ll, background, inSelection, + inHotspot, ll->styles[i], i); + if (ts.representation) { + if (ll->chars[i] == '\t') { + // Tab display + if (drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) + textBack = vsDraw.whitespaceColours.back; + } else { + // Blob display + inIndentation = false; + } + surface->FillRectangle(rcSegment, textBack); + } else { + // Normal text display + surface->FillRectangle(rcSegment, textBack); + if (vsDraw.viewWhitespace != wsInvisible || + (inIndentation && vsDraw.viewIndentationGuides == ivReal)) { + for (int cpos = 0; cpos <= i - ts.start; cpos++) { + if (ll->chars[cpos + ts.start] == ' ') { + if (drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { + PRectangle rcSpace( + ll->positions[cpos + ts.start] + xStart - static_cast(subLineStart), + rcSegment.top, + ll->positions[cpos + ts.start + 1] + xStart - static_cast(subLineStart), + rcSegment.bottom); + surface->FillRectangle(rcSpace, vsDraw.whitespaceColours.back); + } + } else { + inIndentation = false; + } + } + } + } + } else if (rcSegment.left > rcLine.right) { + break; + } + } +} + +static void DrawEdgeLine(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, + Range lineRange, int xStart) { + if (vsDraw.edgeState == EDGE_LINE) { + PRectangle rcSegment = rcLine; + int edgeX = static_cast(vsDraw.theEdge * vsDraw.spaceWidth); + rcSegment.left = static_cast(edgeX + xStart); + if ((ll->wrapIndent != 0) && (lineRange.start != 0)) + rcSegment.left -= ll->wrapIndent; + rcSegment.right = rcSegment.left + 1; + surface->FillRectangle(rcSegment, vsDraw.edgecolour); + } +} + +// Draw underline mark as part of background if not transparent +static void DrawMarkUnderline(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, + int line, PRectangle rcLine) { + int marks = model.pdoc->GetMark(line); + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) && + (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { + PRectangle rcUnderline = rcLine; + rcUnderline.top = rcUnderline.bottom - 2; + surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back); + } + marks >>= 1; + } +} +static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, PRectangle rcLine, int subLine, Range lineRange, int xStart) { + if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA)) { + const int posLineStart = model.pdoc->LineStart(line); + const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; + // For each selection draw + int virtualSpaces = 0; + if (subLine == (ll->lines - 1)) { + virtualSpaces = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)); + } + SelectionPosition posStart(posLineStart + lineRange.start); + SelectionPosition posEnd(posLineStart + lineRange.end, virtualSpaces); + SelectionSegment virtualSpaceRange(posStart, posEnd); + for (size_t r = 0; r < model.sel.Count(); r++) { + int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + if (alpha != SC_ALPHA_NOALPHA) { + SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + PRectangle rcSegment = rcLine; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast(subLineStart)+portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast(subLineStart)+portion.end.VirtualSpace() * spaceWidth; + if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { + if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) + rcSegment.left -= static_cast(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here + } + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + if (rcSegment.right > rcLine.left) + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha); + } + } + } + } +} + +// Draw any translucent whole line states +static void DrawTranslucentLineState(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, PRectangle rcLine) { + if ((model.caret.active || vsDraw.alwaysShowCaretLineBackground) && vsDraw.showCaretLineBackground && ll->containsCaret) { + SimpleAlphaRectangle(surface, rcLine, vsDraw.caretLineBackground, vsDraw.caretLineAlpha); + } + int marks = model.pdoc->GetMark(line); + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) { + SimpleAlphaRectangle(surface, rcLine, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); + } else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) { + PRectangle rcUnderline = rcLine; + rcUnderline.top = rcUnderline.bottom - 2; + SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); + } + marks >>= 1; + } + if (vsDraw.maskInLine) { + int marksMasked = model.pdoc->GetMark(line) & vsDraw.maskInLine; + if (marksMasked) { + for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) { + if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) { + SimpleAlphaRectangle(surface, rcLine, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); + } + marksMasked >>= 1; + } + } + } +} + +void EditView::DrawForeground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int lineVisible, PRectangle rcLine, Range lineRange, int posLineStart, int xStart, + int subLine, ColourOptional background) { + + const bool selBackDrawn = vsDraw.SelectionBackgroundDrawn(); + const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background.isSet; + bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. + + const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; + const XYPOSITION indentWidth = model.pdoc->IndentSize() * vsDraw.spaceWidth; + + // Does not take margin into account but not significant + const int xStartVisible = static_cast(subLineStart)-xStart; + + // Foreground drawing loop + BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, + (((phasesDraw == phasesOne) && selBackDrawn) || vsDraw.selColours.fore.isSet), model.pdoc, &model.reprs); + + while (bfFore.More()) { + + const TextSegment ts = bfFore.Next(); + const int i = ts.end() - 1; + const int iDoc = i + posLineStart; + + PRectangle rcSegment = rcLine; + rcSegment.left = ll->positions[ts.start] + xStart - static_cast(subLineStart); + rcSegment.right = ll->positions[ts.end()] + xStart - static_cast(subLineStart); + // Only try to draw if really visible - enhances performance by not calling environment to + // draw strings that are completely past the right side of the window. + if (rcSegment.Intersects(rcLine)) { + int styleMain = ll->styles[i]; + ColourDesired textFore = vsDraw.styles[styleMain].fore; + FontAlias textFont = vsDraw.styles[styleMain].font; + //hotspot foreground + const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); + if (inHotspot) { + if (vsDraw.hotspotColours.fore.isSet) + textFore = vsDraw.hotspotColours.fore; + } + const int inSelection = hideSelection ? 0 : model.sel.CharacterInSelection(iDoc); + if (inSelection && (vsDraw.selColours.fore.isSet)) { + textFore = (inSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; + } + ColourDesired textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, styleMain, i); + if (ts.representation) { + if (ll->chars[i] == '\t') { + // Tab display + if (phasesDraw == phasesOne) { + if (drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) + textBack = vsDraw.whitespaceColours.back; + surface->FillRectangle(rcSegment, textBack); + } + if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { + for (int indentCount = static_cast((ll->positions[i] + epsilon) / indentWidth); + indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth; + indentCount++) { + if (indentCount > 0) { + int xIndent = static_cast(indentCount * indentWidth); + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, + (ll->xHighlightGuide == xIndent)); + } + } + } + if (vsDraw.viewWhitespace != wsInvisible) { + if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { + if (vsDraw.whitespaceColours.fore.isSet) + textFore = vsDraw.whitespaceColours.fore; + surface->PenColour(textFore); + PRectangle rcTab(rcSegment.left + 1, rcSegment.top + tabArrowHeight, + rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); + if (customDrawTabArrow == NULL) + DrawTabArrow(surface, rcTab, static_cast(rcSegment.top + vsDraw.lineHeight / 2)); + else + customDrawTabArrow(surface, rcTab, static_cast(rcSegment.top + vsDraw.lineHeight / 2)); + } + } + } else { + inIndentation = false; + if (vsDraw.controlCharSymbol >= 32) { + // Using one font for all control characters so it can be controlled independently to ensure + // the box goes around the characters tightly. Seems to be no way to work out what height + // is taken by an individual character - internal leading gives varying results. + FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; + char cc[2] = { static_cast(vsDraw.controlCharSymbol), '\0' }; + surface->DrawTextNoClip(rcSegment, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, + cc, 1, textBack, textFore); + } else { + DrawTextBlob(surface, vsDraw, rcSegment, ts.representation->stringRep.c_str(), + textBack, textFore, phasesDraw == phasesOne); + } + } + } else { + // Normal text display + if (vsDraw.styles[styleMain].visible) { + if (phasesDraw != phasesOne) { + surface->DrawTextTransparent(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll->chars + ts.start, + i - ts.start + 1, textFore); + } else { + surface->DrawTextNoClip(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll->chars + ts.start, + i - ts.start + 1, textFore, textBack); + } + } + if (vsDraw.viewWhitespace != wsInvisible || + (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { + for (int cpos = 0; cpos <= i - ts.start; cpos++) { + if (ll->chars[cpos + ts.start] == ' ') { + if (vsDraw.viewWhitespace != wsInvisible) { + if (vsDraw.whitespaceColours.fore.isSet) + textFore = vsDraw.whitespaceColours.fore; + if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { + XYPOSITION xmid = (ll->positions[cpos + ts.start] + ll->positions[cpos + ts.start + 1]) / 2; + if ((phasesDraw == phasesOne) && drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { + textBack = vsDraw.whitespaceColours.back; + PRectangle rcSpace( + ll->positions[cpos + ts.start] + xStart - static_cast(subLineStart), + rcSegment.top, + ll->positions[cpos + ts.start + 1] + xStart - static_cast(subLineStart), + rcSegment.bottom); + surface->FillRectangle(rcSpace, textBack); + } + PRectangle rcDot(xmid + xStart - static_cast(subLineStart), + rcSegment.top + vsDraw.lineHeight / 2, 0.0f, 0.0f); + rcDot.right = rcDot.left + vsDraw.whitespaceSize; + rcDot.bottom = rcDot.top + vsDraw.whitespaceSize; + surface->FillRectangle(rcDot, textFore); + } + } + if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { + for (int indentCount = static_cast((ll->positions[cpos + ts.start] + epsilon) / indentWidth); + indentCount <= (ll->positions[cpos + ts.start + 1] - epsilon) / indentWidth; + indentCount++) { + if (indentCount > 0) { + int xIndent = static_cast(indentCount * indentWidth); + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, + (ll->xHighlightGuide == xIndent)); + } + } + } + } else { + inIndentation = false; + } + } + } + } + if (ll->hotspot.Valid() && vsDraw.hotspotUnderline && ll->hotspot.ContainsCharacter(iDoc)) { + PRectangle rcUL = rcSegment; + rcUL.top = rcUL.top + vsDraw.maxAscent + 1; + rcUL.bottom = rcUL.top + 1; + if (vsDraw.hotspotColours.fore.isSet) + surface->FillRectangle(rcUL, vsDraw.hotspotColours.fore); + else + surface->FillRectangle(rcUL, textFore); + } else if (vsDraw.styles[styleMain].underline) { + PRectangle rcUL = rcSegment; + rcUL.top = rcUL.top + vsDraw.maxAscent + 1; + rcUL.bottom = rcUL.top + 1; + surface->FillRectangle(rcUL, textFore); + } + } else if (rcSegment.left > rcLine.right) { + break; + } + } +} + +void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int lineVisible, PRectangle rcLine, int xStart, int subLine) { + if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) + && (subLine == 0)) { + const int posLineStart = model.pdoc->LineStart(line); + int indentSpace = model.pdoc->GetLineIndentation(line); + int xStartText = static_cast(ll->positions[model.pdoc->GetLineIndentPosition(line) - posLineStart]); + + // Find the most recent line with some text + + int lineLastWithText = line; + while (lineLastWithText > Platform::Maximum(line - 20, 0) && model.pdoc->IsWhiteLine(lineLastWithText)) { + lineLastWithText--; + } + if (lineLastWithText < line) { + xStartText = 100000; // Don't limit to visible indentation on empty line + // This line is empty, so use indentation of last line with text + int indentLastWithText = model.pdoc->GetLineIndentation(lineLastWithText); + int isFoldHeader = model.pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; + if (isFoldHeader) { + // Level is one more level than parent + indentLastWithText += model.pdoc->IndentSize(); + } + if (vsDraw.viewIndentationGuides == ivLookForward) { + // In viLookForward mode, previous line only used if it is a fold header + if (isFoldHeader) { + indentSpace = Platform::Maximum(indentSpace, indentLastWithText); + } + } else { // viLookBoth + indentSpace = Platform::Maximum(indentSpace, indentLastWithText); + } + } + + int lineNextWithText = line; + while (lineNextWithText < Platform::Minimum(line + 20, model.pdoc->LinesTotal()) && model.pdoc->IsWhiteLine(lineNextWithText)) { + lineNextWithText++; + } + if (lineNextWithText > line) { + 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, + model.pdoc->GetLineIndentation(lineNextWithText)); + } + + for (int indentPos = model.pdoc->IndentSize(); indentPos < indentSpace; indentPos += model.pdoc->IndentSize()) { + int xIndent = static_cast(indentPos * vsDraw.spaceWidth); + if (xIndent < xStartText) { + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcLine, + (ll->xHighlightGuide == xIndent)); + } + } + } +} + +void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { + + if (subLine >= ll->lines) { + DrawAnnotation(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, phase); + return; // No further drawing + } + + // See if something overrides the line background color. + const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); + + const int posLineStart = model.pdoc->LineStart(line); + + const Range lineRange = ll->SubLineRange(subLine); + const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; + + if ((ll->wrapIndent != 0) && (subLine > 0)) { + if (phase & drawBack) { + DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background, customDrawWrapMarker); + } + xStart += static_cast(ll->wrapIndent); + } + + if ((phasesDraw != phasesOne) && (phase & drawBack)) { + DrawBackground(surface, model, vsDraw, ll, rcLine, lineRange, posLineStart, xStart, + subLine, background); + DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end, + xStart, subLine, subLineStart, background); + } + + if (phase & drawIndicatorsBack) { + DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRange.end, true); + DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart); + DrawMarkUnderline(surface, model, vsDraw, line, rcLine); + } + + if (phase & drawText) { + DrawForeground(surface, model, vsDraw, ll, lineVisible, rcLine, lineRange, posLineStart, xStart, + subLine, background); + } + + if (phase & drawIndentationGuides) { + DrawIndentGuidesOverEmpty(surface, model, vsDraw, ll, line, lineVisible, rcLine, xStart, subLine); + } + + if (phase & drawIndicatorsFore) { + DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRange.end, false); + } + + // End of the drawing of the current line + if (phasesDraw == phasesOne) { + DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end, + xStart, subLine, subLineStart, background); + } + + if (!hideSelection && (phase & drawSelectionTranslucent)) { + DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart); + } + + if (phase & drawLineTranslucent) { + DrawTranslucentLineState(surface, model, vsDraw, ll, line, rcLine); + } +} + +static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, int line, PRectangle rcLine) { + bool expanded = model.cs.GetExpanded(line); + const int level = model.pdoc->GetLevel(line); + const int levelNext = model.pdoc->GetLevel(line + 1); + if ((level & SC_FOLDLEVELHEADERFLAG) && + ((level & SC_FOLDLEVELNUMBERMASK) < (levelNext & SC_FOLDLEVELNUMBERMASK))) { + // Paint the line above the fold + if ((expanded && (model.foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) + || + (!expanded && (model.foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.bottom = rcFoldLine.top + 1; + surface->FillRectangle(rcFoldLine, vsDraw.styles[STYLE_DEFAULT].fore); + } + // Paint the line below the fold + if ((expanded && (model.foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) + || + (!expanded && (model.foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.top = rcFoldLine.bottom - 1; + surface->FillRectangle(rcFoldLine, vsDraw.styles[STYLE_DEFAULT].fore); + } + } +} + +void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea, + PRectangle rcClient, const ViewStyle &vsDraw) { + // Allow text at start of line to overlap 1 pixel into the margin as this displays + // serifs and italic stems for aliased text. + const int leftTextOverlap = ((model.xOffset == 0) && (vsDraw.leftMarginWidth > 0)) ? 1 : 0; + + // Do the painting + if (rcArea.right > vsDraw.textStart - leftTextOverlap) { + + Surface *surface = surfaceWindow; + if (bufferedDraw) { + surface = pixmapLine; + PLATFORM_ASSERT(pixmapLine->Initialised()); + } + surface->SetUnicodeMode(SC_CP_UTF8 == model.pdoc->dbcsCodePage); + surface->SetDBCSMode(model.pdoc->dbcsCodePage); + + const Point ptOrigin = model.GetVisibleOriginInMain(); + + const int screenLinePaintFirst = static_cast(rcArea.top) / vsDraw.lineHeight; + const int xStart = vsDraw.textStart - model.xOffset + static_cast(ptOrigin.x); + + SelectionPosition posCaret = model.sel.RangeMain().caret; + if (model.posDrag.IsValid()) + posCaret = model.posDrag; + const int lineCaret = model.pdoc->LineFromPosition(posCaret.Position()); + + PRectangle rcTextArea = rcClient; + if (vsDraw.marginInside) { + rcTextArea.left += vsDraw.textStart; + rcTextArea.right -= vsDraw.rightMarginWidth; + } else { + rcTextArea = rcArea; + } + + // Remove selection margin from drawing area so text will not be drawn + // on it in unbuffered mode. + if (!bufferedDraw && vsDraw.marginInside) { + PRectangle rcClipText = rcTextArea; + rcClipText.left -= leftTextOverlap; + surfaceWindow->SetClip(rcClipText); + } + + // Loop on visible lines + //double durLayout = 0.0; + //double durPaint = 0.0; + //double durCopy = 0.0; + //ElapsedTime etWhole; + + const bool bracesIgnoreStyle = ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) || + (vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))); + + int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times + AutoLineLayout ll(llc, 0); + std::vector phases; + if ((phasesDraw == phasesMultiple) && !bufferedDraw) { + for (DrawPhase phase = drawBack; phase <= drawCarets; phase = static_cast(phase * 2)) { + phases.push_back(phase); + } + } else { + phases.push_back(drawAll); + } + for (std::vector::iterator it = phases.begin(); it != phases.end(); ++it) { + int ypos = 0; + if (!bufferedDraw) + ypos += screenLinePaintFirst * vsDraw.lineHeight; + int yposScreen = screenLinePaintFirst * vsDraw.lineHeight; + int visibleLine = model.TopLineOfMain() + screenLinePaintFirst; + while (visibleLine < model.cs.LinesDisplayed() && yposScreen < rcArea.bottom) { + + const int lineDoc = model.cs.DocFromDisplay(visibleLine); + // Only visible lines should be handled by the code within the loop + PLATFORM_ASSERT(model.cs.GetVisible(lineDoc)); + const int lineStartSet = model.cs.DisplayFromDoc(lineDoc); + const int subLine = visibleLine - lineStartSet; + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + //ElapsedTime et; + if (lineDoc != lineDocPrevious) { + ll.Set(0); + ll.Set(RetrieveLineLayout(lineDoc, model)); + LayoutLine(model, lineDoc, surface, vsDraw, ll, model.wrapWidth); + lineDocPrevious = lineDoc; + } + //durLayout += et.Duration(true); + + if (ll) { + ll->containsCaret = !hideSelection && (lineDoc == lineCaret); + ll->hotspot = model.GetHotSpotRange(); + + PRectangle rcLine = rcTextArea; + rcLine.top = static_cast(ypos); + rcLine.bottom = static_cast(ypos + vsDraw.lineHeight); + + Range rangeLine(model.pdoc->LineStart(lineDoc), model.pdoc->LineStart(lineDoc + 1)); + + // Highlight the current braces if any + ll->SetBracesHighlight(rangeLine, model.braces, static_cast(model.bracesMatchStyle), + static_cast(model.highlightGuideColumn * vsDraw.spaceWidth), bracesIgnoreStyle); + + if (leftTextOverlap && bufferedDraw) { + PRectangle rcSpacer = rcLine; + rcSpacer.right = rcSpacer.left; + rcSpacer.left -= 1; + surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back); + } + + DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine, *it); + //durPaint += et.Duration(true); + + // Restore the previous styles for the brace highlights in case layout is in cache. + ll->RestoreBracesHighlight(rangeLine, model.braces, bracesIgnoreStyle); + + if (*it & drawFoldLines) { + DrawFoldLines(surface, model, vsDraw, lineDoc, rcLine); + } + + if (*it & drawCarets) { + DrawCarets(surface, model, vsDraw, ll, lineDoc, xStart, rcLine, subLine); + } + + if (bufferedDraw) { + Point from = Point::FromInts(vsDraw.textStart - leftTextOverlap, 0); + PRectangle rcCopyArea = PRectangle::FromInts(vsDraw.textStart - leftTextOverlap, yposScreen, + static_cast(rcClient.right - vsDraw.rightMarginWidth), + yposScreen + vsDraw.lineHeight); + surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); + } + + lineWidthMaxSeen = Platform::Maximum( + lineWidthMaxSeen, static_cast(ll->positions[ll->numCharsInLine])); + //durCopy += et.Duration(true); + } + + if (!bufferedDraw) { + ypos += vsDraw.lineHeight; + } + + yposScreen += vsDraw.lineHeight; + visibleLine++; + } + } + ll.Set(0); + //if (durPaint < 0.00000001) + // durPaint = 0.00000001; + + // Right column limit indicator + PRectangle rcBeyondEOF = (vsDraw.marginInside) ? rcClient : rcArea; + rcBeyondEOF.left = static_cast(vsDraw.textStart); + rcBeyondEOF.right = rcBeyondEOF.right - ((vsDraw.marginInside) ? vsDraw.rightMarginWidth : 0); + rcBeyondEOF.top = static_cast((model.cs.LinesDisplayed() - model.TopLineOfMain()) * vsDraw.lineHeight); + if (rcBeyondEOF.top < rcBeyondEOF.bottom) { + surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.styles[STYLE_DEFAULT].back); + if (vsDraw.edgeState == EDGE_LINE) { + int edgeX = static_cast(vsDraw.theEdge * vsDraw.spaceWidth); + rcBeyondEOF.left = static_cast(edgeX + xStart); + rcBeyondEOF.right = rcBeyondEOF.left + 1; + surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.edgecolour); + } + } + //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); + + //Platform::DebugPrintf( + //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n", + //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration()); + } +} + +// Space (3 space characters) between line numbers and text when printing. +#define lineNumberPrintSpace " " + +ColourDesired InvertedLight(ColourDesired orig) { + unsigned int r = orig.GetRed(); + unsigned int g = orig.GetGreen(); + unsigned int b = orig.GetBlue(); + unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye + unsigned int il = 0xff - l; + if (l == 0) + return ColourDesired(0xff, 0xff, 0xff); + r = r * il / l; + g = g * il / l; + b = b * il / l; + return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff)); +} + +long EditView::FormatRange(bool draw, Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure, + const EditModel &model, const ViewStyle &vs) { + // Can't use measurements cached for screen + posCache.Clear(); + + ViewStyle vsPrint(vs); + vsPrint.technology = SC_TECHNOLOGY_DEFAULT; + + // Modify the view style for printing as do not normally want any of the transient features to be printed + // Printing supports only the line number margin. + int lineNumberIndex = -1; + for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) { + if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) { + lineNumberIndex = margin; + } else { + vsPrint.ms[margin].width = 0; + } + } + vsPrint.fixedColumnWidth = 0; + vsPrint.zoomLevel = printParameters.magnification; + // Don't show indentation guides + // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT + vsPrint.viewIndentationGuides = ivNone; + // Don't show the selection when printing + vsPrint.selColours.back.isSet = false; + vsPrint.selColours.fore.isSet = false; + vsPrint.selAlpha = SC_ALPHA_NOALPHA; + vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA; + vsPrint.whitespaceColours.back.isSet = false; + vsPrint.whitespaceColours.fore.isSet = false; + vsPrint.showCaretLineBackground = false; + vsPrint.alwaysShowCaretLineBackground = 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.styles.size(); sty++) { + if (printParameters.colourMode == SC_PRINT_INVERTLIGHT) { + vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore); + vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back); + } else if (printParameters.colourMode == SC_PRINT_BLACKONWHITE) { + vsPrint.styles[sty].fore = ColourDesired(0, 0, 0); + vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); + } else if (printParameters.colourMode == SC_PRINT_COLOURONWHITE) { + vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); + } else if (printParameters.colourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) { + if (sty <= STYLE_DEFAULT) { + vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); + } + } + } + // White background for the line numbers + vsPrint.styles[STYLE_LINENUMBER].back = ColourDesired(0xff, 0xff, 0xff); + + // Printing uses different margins, so reset screen margins + vsPrint.leftMarginWidth = 0; + vsPrint.rightMarginWidth = 0; + + vsPrint.Refresh(*surfaceMeasure, model.pdoc->tabInChars); + // Determining width must happen after fonts have been realised in Refresh + int lineNumberWidth = 0; + if (lineNumberIndex >= 0) { + lineNumberWidth = static_cast(surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, + "99999" lineNumberPrintSpace, 5 + static_cast(strlen(lineNumberPrintSpace)))); + vsPrint.ms[lineNumberIndex].width = lineNumberWidth; + vsPrint.Refresh(*surfaceMeasure, model.pdoc->tabInChars); // Recalculate fixedColumnWidth + } + + int linePrintStart = model.pdoc->LineFromPosition(pfr->chrg.cpMin); + int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; + if (linePrintLast < linePrintStart) + linePrintLast = linePrintStart; + int linePrintMax = model.pdoc->LineFromPosition(pfr->chrg.cpMax); + if (linePrintLast > linePrintMax) + linePrintLast = linePrintMax; + //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", + // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, + // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); + int endPosPrint = model.pdoc->Length(); + if (linePrintLast < model.pdoc->LinesTotal()) + endPosPrint = model.pdoc->LineStart(linePrintLast + 1); + + // Ensure we are styled to where we are formatting. + model.pdoc->EnsureStyledTo(endPosPrint); + + int xStart = vsPrint.fixedColumnWidth + pfr->rc.left; + int ypos = pfr->rc.top; + + int lineDoc = linePrintStart; + + int nPrintPos = pfr->chrg.cpMin; + int visibleLine = 0; + int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth; + if (printParameters.wrapState == eWrapNone) + widthPrint = LineLayout::wrapWidthInfinite; + + while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) { + + // When printing, the hdc and hdcTarget may be the same, so + // changing the state of surfaceMeasure may change the underlying + // state of surface. Therefore, any cached state is discarded before + // using each surface. + surfaceMeasure->FlushCachedState(); + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + LineLayout ll(model.pdoc->LineStart(lineDoc + 1) - model.pdoc->LineStart(lineDoc) + 1); + LayoutLine(model, lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); + + ll.containsCaret = false; + + PRectangle rcLine = PRectangle::FromInts( + pfr->rc.left, + ypos, + pfr->rc.right - 1, + ypos + vsPrint.lineHeight); + + // When document line is wrapped over multiple display lines, find where + // to start printing from to ensure a particular position is on the first + // line of the page. + if (visibleLine == 0) { + int startWithinLine = nPrintPos - model.pdoc->LineStart(lineDoc); + for (int iwl = 0; iwl < ll.lines - 1; iwl++) { + if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) { + visibleLine = -iwl; + } + } + + if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) { + visibleLine = -(ll.lines - 1); + } + } + + if (draw && lineNumberWidth && + (ypos + vsPrint.lineHeight <= pfr->rc.bottom) && + (visibleLine >= 0)) { + char number[100]; + sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1); + PRectangle rcNumber = rcLine; + rcNumber.right = rcNumber.left + lineNumberWidth; + // Right justify + rcNumber.left = rcNumber.right - surfaceMeasure->WidthText( + vsPrint.styles[STYLE_LINENUMBER].font, number, static_cast(strlen(number))); + surface->FlushCachedState(); + surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, + static_cast(ypos + vsPrint.maxAscent), number, static_cast(strlen(number)), + vsPrint.styles[STYLE_LINENUMBER].fore, + vsPrint.styles[STYLE_LINENUMBER].back); + } + + // Draw the line + surface->FlushCachedState(); + + for (int iwl = 0; iwl < ll.lines; iwl++) { + if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) { + if (visibleLine >= 0) { + if (draw) { + rcLine.top = static_cast(ypos); + rcLine.bottom = static_cast(ypos + vsPrint.lineHeight); + DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xStart, rcLine, iwl, drawAll); + } + ypos += vsPrint.lineHeight; + } + visibleLine++; + if (iwl == ll.lines - 1) + nPrintPos = model.pdoc->LineStart(lineDoc + 1); + else + nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl); + } + } + + ++lineDoc; + } + + // Clear cache so measurements are not used for screen + posCache.Clear(); + + return nPrintPos; +} diff --git a/src/stc/scintilla/src/EditView.h b/src/stc/scintilla/src/EditView.h new file mode 100644 index 0000000000..70af6b2bf0 --- /dev/null +++ b/src/stc/scintilla/src/EditView.h @@ -0,0 +1,173 @@ +// Scintilla source code edit control +/** @file EditView.h + ** Defines the appearance of the main text area of the editor window. + **/ +// Copyright 1998-2014 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITVIEW_H +#define EDITVIEW_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +struct PrintParameters { + int magnification; + int colourMode; + WrapMode wrapState; + PrintParameters(); +}; + +/** +* The view may be drawn in separate phases. +*/ +enum DrawPhase { + drawBack = 0x1, + drawIndicatorsBack = 0x2, + drawText = 0x4, + drawIndentationGuides = 0x8, + drawIndicatorsFore = 0x10, + drawSelectionTranslucent = 0x20, + drawLineTranslucent = 0x40, + drawFoldLines = 0x80, + drawCarets = 0x100, + drawAll = 0x1FF +}; + +bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st); +int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st); +void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, + const char *s, int len, DrawPhase phase); +void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, + const StyledText &st, size_t start, size_t length, DrawPhase phase); + +typedef void (*DrawTabArrowFn)(Surface *surface, PRectangle rcTab, int ymid); + +/** +* EditView draws the main text area. +*/ +class EditView { +public: + PrintParameters printParameters; + PerLine *ldTabstops; + + bool hideSelection; + bool drawOverstrikeCaret; + + /** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to + * the screen. This avoids flashing but is about 30% slower. */ + bool bufferedDraw; + /** In phasesTwo mode, drawing is performed in two phases, first the background + * and then the foreground. This avoids chopping off characters that overlap the next run. + * In multiPhaseDraw mode, drawing is performed in multiple phases with each phase drawing + * one feature over the whole drawing area, instead of within one line. This allows text to + * overlap from one line to the next. */ + enum PhasesDraw { phasesOne, phasesTwo, phasesMultiple }; + PhasesDraw phasesDraw; + + int lineWidthMaxSeen; + + bool additionalCaretsBlink; + bool additionalCaretsVisible; + + bool imeCaretBlockOverride; + + Surface *pixmapLine; + Surface *pixmapIndentGuide; + Surface *pixmapIndentGuideHighlight; + + LineLayoutCache llc; + PositionCache posCache; + + int tabArrowHeight; // draw arrow heads this many pixels above/below line midpoint + /** Some platforms, notably PLAT_CURSES, do not support Scintilla's native + * DrawTabArrow function for drawing tab characters. Allow those platforms to + * override it instead of creating a new method in the Surface class that + * existing platforms must implement as empty. */ + DrawTabArrowFn customDrawTabArrow; + DrawWrapMarkerFn customDrawWrapMarker; + + EditView(); + virtual ~EditView(); + + bool SetTwoPhaseDraw(bool twoPhaseDraw); + bool SetPhasesDraw(int phases); + bool LinesOverlap() const; + + void ClearAllTabstops(); + XYPOSITION NextTabstopPos(int line, XYPOSITION x, XYPOSITION tabWidth) const; + bool ClearTabstops(int line); + bool AddTabstop(int line, int x); + int GetNextTabstop(int line, int x) const; + void LinesAddedOrRemoved(int lineOfPos, int linesAdded); + + void DropGraphics(bool freeObjects); + void AllocateGraphics(const ViewStyle &vsDraw); + void RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw); + + LineLayout *RetrieveLineLayout(int lineNumber, const EditModel &model); + void LayoutLine(const EditModel &model, int line, Surface *surface, const ViewStyle &vstyle, + LineLayout *ll, int width = LineLayout::wrapWidthInfinite); + + Point LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, int topLine, const ViewStyle &vs); + SelectionPosition SPositionFromLocation(Surface *surface, const EditModel &model, Point pt, bool canReturnInvalid, + bool charPosition, bool virtualSpace, const ViewStyle &vs); + SelectionPosition SPositionFromLineX(Surface *surface, const EditModel &model, int lineDoc, int x, const ViewStyle &vs); + int DisplayFromPosition(Surface *surface, const EditModel &model, int pos, const ViewStyle &vs); + int StartEndDisplayLine(Surface *surface, const EditModel &model, int pos, bool start, const ViewStyle &vs); + + void DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight); + void DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, + int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, + ColourOptional background); + void DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase); + void DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int line, + int xStart, PRectangle rcLine, int subLine) const; + void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, + Range lineRange, int posLineStart, int xStart, + int subLine, ColourOptional background) const; + void DrawForeground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int lineVisible, + PRectangle rcLine, Range lineRange, int posLineStart, int xStart, + int subLine, ColourOptional background); + void DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int lineVisible, PRectangle rcLine, int xStart, int subLine); + void DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int line, + int lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase); + void PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea, PRectangle rcClient, + const ViewStyle &vsDraw); + long FormatRange(bool draw, Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure, + const EditModel &model, const ViewStyle &vs); +}; + +/** +* Convenience class to ensure LineLayout objects are always disposed. +*/ +class AutoLineLayout { + LineLayoutCache &llc; + LineLayout *ll; + AutoLineLayout &operator=(const AutoLineLayout &); +public: + AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {} + ~AutoLineLayout() { + llc.Dispose(ll); + ll = 0; + } + LineLayout *operator->() const { + return ll; + } + operator LineLayout *() const { + return ll; + } + void Set(LineLayout *ll_) { + llc.Dispose(ll); + ll = ll_; + } +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/src/stc/scintilla/src/Editor.cxx b/src/stc/scintilla/src/Editor.cxx index db0aecf43b..64017c58da 100644 --- a/src/stc/scintilla/src/Editor.cxx +++ b/src/stc/scintilla/src/Editor.cxx @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" +#include "PerLine.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" @@ -42,6 +44,9 @@ #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" #include "Editor.h" #ifdef SCI_NAMESPACE @@ -79,21 +84,13 @@ static bool IsLastStep(const DocModification &mh) { && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0; } -Caret::Caret() : - active(false), on(false), period(500) {} - Timer::Timer() : ticking(false), ticksToWait(0), tickerID(0) {} Idler::Idler() : state(false), idlerID(0) {} -static inline bool IsControlCharacter(int ch) { - // iscntrl returns true for lots of chars > 127 which are displayable - return ch >= 0 && ch < ' '; -} - -static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) { +static inline bool IsAllSpacesOrTabs(const 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])) @@ -102,12 +99,6 @@ static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) { return true; } -PrintParameters::PrintParameters() { - magnification = 0; - colourMode = SC_PRINT_NORMAL; - wrapState = eWrapWord; -} - Editor::Editor() { ctrlID = 0; @@ -118,16 +109,11 @@ Editor::Editor() { cursorMode = SC_CURSORNORMAL; hasFocus = false; - hideSelection = false; - inOverstrike = false; - drawOverstrikeCaret = true; errorStatus = 0; mouseDownCaptures = true; - bufferedDraw = true; - twoPhaseDraw = true; - lastClickTime = 0; + doubleClickCloseThreshold = Point(3, 3); dwellDelay = SC_TIME_FOREVER; ticksToDwell = SC_TIME_FOREVER; dwelling = false; @@ -135,7 +121,6 @@ Editor::Editor() { ptMouseLast.y = 0; inDragDrop = ddNone; dropWentOutside = false; - posDrag = SelectionPosition(invalidPosition); posDrop = SelectionPosition(invalidPosition); hotSpotClickPos = INVALID_POSITION; selectionType = selChar; @@ -147,8 +132,6 @@ Editor::Editor() { wordSelectAnchorEndPos = 0; wordSelectInitialCaretPos = -1; - primarySelection = true; - caretXPolicy = CARET_SLOP | CARET_EVEN; caretXSlop = 50; @@ -160,12 +143,9 @@ Editor::Editor() { searchAnchor = 0; - xOffset = 0; xCaretMargin = 50; horizontalScrollBarVisible = true; scrollWidth = 2000; - trackLineWidth = false; - lineWidthMaxSeen = 0; verticalScrollBarVisible = true; endAtLastLine = true; caretSticky = SC_CARETSTICKY_OFF; @@ -174,17 +154,8 @@ Editor::Editor() { multipleSelection = false; additionalSelectionTyping = false; multiPasteMode = SC_MULTIPASTE_ONCE; - additionalCaretsBlink = true; - additionalCaretsVisible = true; virtualSpaceOptions = SCVS_NONE; - pixmapLine = 0; - pixmapSelMargin = 0; - pixmapSelPattern = 0; - pixmapSelPatternOffset1 = 0; - pixmapIndentGuide = 0; - pixmapIndentGuideHighlight = 0; - targetStart = 0; targetEnd = 0; searchFlags = 0; @@ -196,10 +167,6 @@ Editor::Editor() { needUpdateUI = 0; ContainerNeedsUpdate(SC_UPDATE_CONTENT); - braces[0] = invalidPosition; - braces[1] = invalidPosition; - bracesMatchStyle = STYLE_BRACEBAD; - highlightGuideColumn = 0; paintState = notPainting; paintAbandonedByStyling = false; @@ -208,30 +175,18 @@ Editor::Editor() { modEventMask = SC_MODEVENTMASKALL; - pdoc = new Document(); - pdoc->AddRef(); pdoc->AddWatcher(this, 0); recordingMacro = false; - foldFlags = 0; foldAutomatic = 0; - wrapWidth = LineLayout::wrapWidthInfinite; - convertPastes = true; - hotspot = Range(invalidPosition); - - llc.SetLevel(LineLayoutCache::llcCaret); - posCache.SetSize(0x400); - SetRepresentations(); } Editor::~Editor() { pdoc->RemoveWatcher(this, 0); - pdoc->Release(); - pdoc = 0; DropGraphics(true); } @@ -284,48 +239,13 @@ void Editor::SetRepresentations() { } void Editor::DropGraphics(bool freeObjects) { - if (freeObjects) { - delete pixmapLine; - pixmapLine = 0; - delete pixmapSelMargin; - pixmapSelMargin = 0; - delete pixmapSelPattern; - pixmapSelPattern = 0; - delete pixmapSelPatternOffset1; - pixmapSelPatternOffset1 = 0; - delete pixmapIndentGuide; - pixmapIndentGuide = 0; - delete pixmapIndentGuideHighlight; - pixmapIndentGuideHighlight = 0; - } else { - if (pixmapLine) - pixmapLine->Release(); - if (pixmapSelMargin) - pixmapSelMargin->Release(); - if (pixmapSelPattern) - pixmapSelPattern->Release(); - if (pixmapSelPatternOffset1) - pixmapSelPatternOffset1->Release(); - if (pixmapIndentGuide) - pixmapIndentGuide->Release(); - if (pixmapIndentGuideHighlight) - pixmapIndentGuideHighlight->Release(); - } + marginView.DropGraphics(freeObjects); + view.DropGraphics(freeObjects); } void Editor::AllocateGraphics() { - if (!pixmapLine) - pixmapLine = Surface::Allocate(technology); - if (!pixmapSelMargin) - pixmapSelMargin = Surface::Allocate(technology); - if (!pixmapSelPattern) - pixmapSelPattern = Surface::Allocate(technology); - if (!pixmapSelPatternOffset1) - pixmapSelPatternOffset1 = Surface::Allocate(technology); - if (!pixmapIndentGuide) - pixmapIndentGuide = Surface::Allocate(technology); - if (!pixmapIndentGuideHighlight) - pixmapIndentGuideHighlight = Surface::Allocate(technology); + marginView.AllocateGraphics(vs); + view.AllocateGraphics(vs); } void Editor::InvalidateStyleData() { @@ -333,8 +253,8 @@ void Editor::InvalidateStyleData() { vs.technology = technology; DropGraphics(false); AllocateGraphics(); - llc.Invalidate(LineLayout::llInvalid); - posCache.Clear(); + view.llc.Invalidate(LineLayout::llInvalid); + view.posCache.Clear(); } void Editor::InvalidateStyleRedraw() { @@ -355,11 +275,11 @@ void Editor::RefreshStyleData() { } } -Point Editor::GetVisibleOriginInMain() { +Point Editor::GetVisibleOriginInMain() const { return Point(0,0); } -Point Editor::DocumentPointFromView(Point ptView) { +Point Editor::DocumentPointFromView(Point ptView) const { Point ptDocument = ptView; if (wMargin.GetID()) { Point ptOrigin = GetVisibleOriginInMain(); @@ -379,29 +299,30 @@ int Editor::TopLineOfMain() const { return topLine; } -PRectangle Editor::GetClientRectangle() { - return wMain.GetClientPosition(); +PRectangle Editor::GetClientRectangle() const { + Window &win = const_cast(wMain); + return win.GetClientPosition(); } PRectangle Editor::GetClientDrawingRectangle() { return GetClientRectangle(); } -PRectangle Editor::GetTextRectangle() { +PRectangle Editor::GetTextRectangle() const { PRectangle rc = GetClientRectangle(); rc.left += vs.textStart; rc.right -= vs.rightMarginWidth; return rc; } -int Editor::LinesOnScreen() { +int Editor::LinesOnScreen() const { PRectangle rcClient = GetClientRectangle(); int htClient = static_cast(rcClient.bottom - rcClient.top); //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1); return htClient / vs.lineHeight; } -int Editor::LinesToScroll() { +int Editor::LinesToScroll() const { int retVal = LinesOnScreen() - 1; if (retVal < 1) return 1; @@ -409,7 +330,7 @@ int Editor::LinesToScroll() { return retVal; } -int Editor::MaxScrollPos() { +int Editor::MaxScrollPos() const { //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n", //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1); int retVal = cs.LinesDisplayed(); @@ -425,45 +346,6 @@ int Editor::MaxScrollPos() { } } -const char *ControlCharacterString(unsigned char ch) { - const char *reps[] = { - "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", - "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", - "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", - "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" - }; - if (ch < ELEMENTS(reps)) { - return reps[ch]; - } else { - return "BAD"; - } -} - -/** - * Convenience class to ensure LineLayout objects are always disposed. - */ -class AutoLineLayout { - LineLayoutCache &llc; - LineLayout *ll; - AutoLineLayout &operator=(const AutoLineLayout &); -public: - AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {} - ~AutoLineLayout() { - llc.Dispose(ll); - ll = 0; - } - LineLayout *operator->() const { - return ll; - } - operator LineLayout *() const { - return ll; - } - void Set(LineLayout *ll_) { - llc.Dispose(ll); - ll = ll_; - } -}; - SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const { if (sp.Position() < 0) { return SelectionPosition(0); @@ -478,25 +360,9 @@ SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const } Point Editor::LocationFromPosition(SelectionPosition pos) { - Point pt; RefreshStyleData(); - if (pos.Position() == INVALID_POSITION) - return pt; - const int line = pdoc->LineFromPosition(pos.Position()); - const int lineVisible = cs.DisplayFromDoc(line); - //Platform::DebugPrintf("line=%d\n", line); AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(line)); - if (surface && ll) { - const int posLineStart = pdoc->LineStart(line); - LayoutLine(line, surface, vs, ll, wrapWidth); - const int posInLine = pos.Position() - posLineStart; - pt = ll->PointFromPosition(posInLine, vs.lineHeight); - pt.y += (lineVisible - topLine) * vs.lineHeight; - pt.x += vs.textStart - xOffset; - } - pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; - return pt; + return view.LocationFromPosition(surface, *this, pos, topLine, vs); } Point Editor::LocationFromPosition(int pos) { @@ -513,20 +379,10 @@ int Editor::XFromPosition(SelectionPosition sp) { return static_cast(pt.x) - vs.textStart + xOffset; } -int Editor::LineFromLocation(Point pt) const { - return cs.DocFromDisplay(static_cast(pt.y) / vs.lineHeight + topLine); -} - -void Editor::SetTopLine(int topLineNew) { - if ((topLine != topLineNew) && (topLineNew >= 0)) { - topLine = topLineNew; - ContainerNeedsUpdate(SC_UPDATE_V_SCROLL); - } - posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine)); -} - SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) { RefreshStyleData(); + AutoSurface surface(this); + if (canReturnInvalid) { PRectangle rcClient = GetTextRectangle(); // May be in scroll view coordinates so translate back to main view @@ -540,48 +396,7 @@ SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, return SelectionPosition(INVALID_POSITION); } pt = DocumentPointFromView(pt); - pt.x = pt.x - vs.textStart; - int visibleLine = static_cast(floor(pt.y / vs.lineHeight)); - if (!canReturnInvalid && (visibleLine < 0)) - visibleLine = 0; - const int lineDoc = cs.DocFromDisplay(visibleLine); - if (canReturnInvalid && (lineDoc < 0)) - return SelectionPosition(INVALID_POSITION); - if (lineDoc >= pdoc->LinesTotal()) - return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length()); - const int posLineStart = pdoc->LineStart(lineDoc); - AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); - if (surface && ll) { - LayoutLine(lineDoc, surface, vs, ll, wrapWidth); - const int lineStartSet = cs.DisplayFromDoc(lineDoc); - const int subLine = visibleLine - lineStartSet; - if (subLine < ll->lines) { - const Range rangeSubLine = ll->SubLineRange(subLine); - const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; - if (subLine > 0) // Wrapped - pt.x -= ll->wrapIndent; - const int positionInLine = ll->FindPositionFromX(pt.x + subLineStart, rangeSubLine, charPosition); - if (positionInLine < rangeSubLine.end) { - return SelectionPosition(pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); - } - if (virtualSpace) { - const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; - const int spaceOffset = static_cast( - (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); - return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); - } else if (canReturnInvalid) { - if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) { - return SelectionPosition(pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1)); - } - } else { - return SelectionPosition(rangeSubLine.end + posLineStart); - } - } - if (!canReturnInvalid) - return SelectionPosition(ll->numCharsInLine + posLineStart); - } - return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart); + return view.SPositionFromLocation(surface, *this, pt, canReturnInvalid, charPosition, virtualSpace, vs); } int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { @@ -589,38 +404,35 @@ int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosit } /** - * Find the document position corresponding to an x coordinate on a particular document line. - * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. - * This method is used for rectangular selections and does not work on wrapped lines. - */ +* Find the document position corresponding to an x coordinate on a particular document line. +* Ensure is between whole characters when document is in multi-byte or UTF-8 mode. +* This method is used for rectangular selections and does not work on wrapped lines. +*/ SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) { RefreshStyleData(); if (lineDoc >= pdoc->LinesTotal()) return SelectionPosition(pdoc->Length()); //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); - if (surface && ll) { - const int posLineStart = pdoc->LineStart(lineDoc); - LayoutLine(lineDoc, surface, vs, ll, wrapWidth); - const Range rangeSubLine = ll->SubLineRange(0); - const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; - const int positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false); - if (positionInLine < rangeSubLine.end) { - return SelectionPosition(pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); - } - const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; - const int spaceOffset = static_cast( - (x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); - return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); - } - return SelectionPosition(0); + return view.SPositionFromLineX(surface, *this, lineDoc, x, vs); } int Editor::PositionFromLineX(int lineDoc, int x) { return SPositionFromLineX(lineDoc, x).Position(); } +int Editor::LineFromLocation(Point pt) const { + return cs.DocFromDisplay(static_cast(pt.y) / vs.lineHeight + topLine); +} + +void Editor::SetTopLine(int topLineNew) { + if ((topLine != topLineNew) && (topLineNew >= 0)) { + topLine = topLineNew; + ContainerNeedsUpdate(SC_UPDATE_V_SCROLL); + } + posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine)); +} + /** * If painting then abandon the painting because a wider redraw is needed. * @return true if calling code should stop drawing. @@ -675,7 +487,7 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = rcSelMargin.left + vs.fixedColumnWidth; if (line != -1) { - PRectangle rcLine = RectangleFromRange(Range(pdoc->LineStart(line))); + PRectangle rcLine = RectangleFromRange(Range(pdoc->LineStart(line)), 0); // Inflate line rectangle if there are image markers with height larger than line height if (vs.largestMarkerHeight > vs.lineHeight) { @@ -705,25 +517,25 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { } } -PRectangle Editor::RectangleFromRange(Range r) { +PRectangle Editor::RectangleFromRange(Range r, int overlap) { const int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(r.First())); const int maxLine = cs.DisplayLastFromDoc(pdoc->LineFromPosition(r.Last())); const PRectangle rcClientDrawing = GetClientDrawingRectangle(); PRectangle rc; const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0; rc.left = static_cast(vs.textStart - leftTextOverlap); - rc.top = static_cast((minLine - TopLineOfMain()) * vs.lineHeight); + rc.top = static_cast((minLine - TopLineOfMain()) * vs.lineHeight - overlap); if (rc.top < rcClientDrawing.top) rc.top = rcClientDrawing.top; // Extend to right of prepared area if any to prevent artifacts from caret line highlight rc.right = rcClientDrawing.right; - rc.bottom = static_cast((maxLine - TopLineOfMain() + 1) * vs.lineHeight); + rc.bottom = static_cast((maxLine - TopLineOfMain() + 1) * vs.lineHeight + overlap); return rc; } void Editor::InvalidateRange(int start, int end) { - RedrawRect(RectangleFromRange(Range(start, end))); + RedrawRect(RectangleFromRange(Range(start, end), view.LinesOverlap() ? vs.lineOverlap : 0)); } int Editor::CurrentPosition() const { @@ -819,7 +631,7 @@ void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition ancho SetRectangularRange(); ClaimSelection(); - if (highlightDelimiter.NeedsDrawing(currentLine)) { + if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } QueueIdleWork(WorkNeeded::workUpdateUI); @@ -846,7 +658,7 @@ void Editor::SetSelection(SelectionPosition currentPos_) { } ClaimSelection(); - if (highlightDelimiter.NeedsDrawing(currentLine)) { + if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } QueueIdleWork(WorkNeeded::workUpdateUI); @@ -867,7 +679,7 @@ void Editor::SetEmptySelection(SelectionPosition currentPos_) { SetRectangularRange(); ClaimSelection(); - if (highlightDelimiter.NeedsDrawing(currentLine)) { + if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } QueueIdleWork(WorkNeeded::workUpdateUI); @@ -977,7 +789,7 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b } } - if (highlightDelimiter.NeedsDrawing(currentLine)) { + if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } return 0; @@ -1174,22 +986,8 @@ void Editor::MoveCaretInsideView(bool ensureVisible) { } int Editor::DisplayFromPosition(int pos) { - int lineDoc = pdoc->LineFromPosition(pos); - int lineDisplay = cs.DisplayFromDoc(lineDoc); AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); - if (surface && ll) { - LayoutLine(lineDoc, surface, vs, ll, wrapWidth); - unsigned int posLineStart = pdoc->LineStart(lineDoc); - int posInLine = pos - posLineStart; - lineDisplay--; // To make up for first increment ahead. - for (int subLine = 0; subLine < ll->lines; subLine++) { - if (posInLine >= ll->LineStart(subLine)) { - lineDisplay++; - } - } - } - return lineDisplay; + return view.DisplayFromPosition(surface, *this, pos, vs); } /** @@ -1451,7 +1249,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const SelectionRange &ran newXY.xOffset = static_cast(pt.x + xOffset - rcClient.left) - 2; } else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) { newXY.xOffset = static_cast(pt.x + xOffset - rcClient.right) + 2; - if (vs.caretStyle == CARETSTYLE_BLOCK) { + if ((vs.caretStyle == CARETSTYLE_BLOCK) || view.imeCaretBlockOverride) { // Ensure we can see a good portion of the block caret newXY.xOffset += static_cast(vs.aveCharWidth); } @@ -1516,16 +1314,26 @@ void Editor::ShowCaretAtCurrentPosition() { if (hasFocus) { caret.active = true; caret.on = true; - SetTicking(true); + if (FineTickerAvailable()) { + FineTickerCancel(tickCaret); + if (caret.period > 0) + FineTickerStart(tickCaret, caret.period, caret.period/10); + } else { + SetTicking(true); + } } else { caret.active = false; caret.on = false; + if (FineTickerAvailable()) { + FineTickerCancel(tickCaret); + } } InvalidateCaret(); } void Editor::DropCaret() { caret.active = false; + FineTickerCancel(tickCaret); InvalidateCaret(); } @@ -1533,6 +1341,11 @@ void Editor::CaretSetPeriod(int period) { if (caret.period != period) { caret.period = period; caret.on = true; + if (FineTickerAvailable()) { + FineTickerCancel(tickCaret); + if ((caret.active) && (caret.period > 0)) + FineTickerStart(tickCaret, caret.period, caret.period/10); + } InvalidateCaret(); } } @@ -1558,7 +1371,7 @@ bool Editor::Wrapping() const { void Editor::NeedWrapping(int docLineStart, int docLineEnd) { //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd); if (wrapPending.AddRange(docLineStart, docLineEnd)) { - llc.Invalidate(LineLayout::llPositions); + view.llc.Invalidate(LineLayout::llPositions); } // Wrap lines during idle. if (Wrapping() && wrapPending.NeedsWrap()) { @@ -1567,10 +1380,10 @@ void Editor::NeedWrapping(int docLineStart, int docLineEnd) { } bool Editor::WrapOneLine(Surface *surface, int lineToWrap) { - AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap)); + AutoLineLayout ll(view.llc, view.RetrieveLineLayout(lineToWrap, *this)); int linesWrapped = 1; if (ll) { - LayoutLine(lineToWrap, surface, vs, ll, wrapWidth); + view.LayoutLine(*this, lineToWrap, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } return cs.SetHeight(lineToWrap, linesWrapped + @@ -1713,10 +1526,10 @@ void Editor::LinesSplit(int pixelWidth) { UndoGroup ug(pdoc); for (int line = lineStart; line <= lineEnd; line++) { AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(line)); + AutoLineLayout ll(view.llc, view.RetrieveLineLayout(line, *this)); if (surface && ll) { unsigned int posLineStart = pdoc->LineStart(line); - LayoutLine(line, surface, vs, ll, pixelWidth); + view.LayoutLine(*this, line, surface, vs, ll, pixelWidth); int lengthInsertedTotal = 0; for (int subLine = 1; subLine < ll->lines; subLine++) { const int lengthInserted = pdoc->InsertString( @@ -1732,98 +1545,6 @@ void Editor::LinesSplit(int pixelWidth) { } } -int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) const { - if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) - return markerDefault; - return markerCheck; -} - -bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { - if (st.multipleStyles) { - for (size_t iStyle=0; iStyle(styles[endSegment+1]) == style)) - endSegment++; - FontAlias fontText = vs.styles[style + styleOffset].font; - width += static_cast(surface->WidthText(fontText, text + start, - static_cast(endSegment - start + 1))); - start = endSegment + 1; - } - return width; -} - -static int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { - int widthMax = 0; - size_t start = 0; - while (start < st.length) { - size_t lenLine = st.LineLength(start); - int widthSubLine; - if (st.multipleStyles) { - widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); - } else { - FontAlias fontText = vs.styles[styleOffset + st.style].font; - widthSubLine = static_cast(surface->WidthText(fontText, - st.text + start, static_cast(lenLine))); - } - if (widthSubLine > widthMax) - widthMax = widthSubLine; - start += lenLine + 1; - } - return widthMax; -} - -static void DrawTextInStyle(Surface *surface, PRectangle rcText, const Style &style, XYPOSITION ybase, const char *s, size_t length) { - FontAlias fontText = style.font; - surface->DrawTextNoClip(rcText, fontText, ybase, s, static_cast(length), - style.fore, style.back); -} - -static void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, - const StyledText &st, size_t start, size_t length) { - - if (st.multipleStyles) { - int x = static_cast(rcText.left); - size_t i = 0; - while (i < length) { - size_t end = i; - size_t style = st.styles[i + start]; - while (end < length-1 && st.styles[start+end+1] == style) - end++; - style += styleOffset; - FontAlias fontText = vs.styles[style].font; - const int width = static_cast(surface->WidthText(fontText, - st.text + start + i, static_cast(end - i + 1))); - PRectangle rcSegment = rcText; - rcSegment.left = static_cast(x); - rcSegment.right = static_cast(x + width + 1); - DrawTextInStyle(surface, rcSegment, vs.styles[style], rcText.top + vs.maxAscent, - st.text + start + i, end - i + 1); - x += width; - i = end + 1; - } - } else { - const size_t style = st.style + styleOffset; - DrawTextInStyle(surface, rcText, vs.styles[style], rcText.top + vs.maxAscent, - st.text + start, length); - } -} - void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (vs.fixedColumnWidth == 0) return; @@ -1849,8 +1570,8 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { return; Surface *surface; - if (bufferedDraw) { - surface = pixmapSelMargin; + if (view.bufferedDraw) { + surface = marginView.pixmapSelMargin; } else { surface = surfWindow; } @@ -1861,1571 +1582,30 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (rcMargin.top < rc.top) rcMargin.top = rc.top; - PRectangle rcSelMargin = rcMargin; - rcSelMargin.right = rcMargin.left; - if (rcSelMargin.bottom < rc.bottom) - rcSelMargin.bottom = rc.bottom; + marginView.PaintMargin(surface, topLine, rc, rcMargin, *this, vs); - for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) { - if (vs.ms[margin].width > 0) { - - rcSelMargin.left = rcSelMargin.right; - rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; - - if (vs.ms[margin].style != SC_MARGIN_NUMBER) { - if (vs.ms[margin].mask & SC_MASK_FOLDERS) { - // Required because of special way brush is created for selection margin - // Ensure patterns line up when scrolling with separate margin view - // by choosing correctly aligned variant. - bool invertPhase = static_cast(ptOrigin.y) & 1; - surface->FillRectangle(rcSelMargin, - invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); - } else { - ColourDesired colour; - switch (vs.ms[margin].style) { - case SC_MARGIN_BACK: - colour = vs.styles[STYLE_DEFAULT].back; - break; - case SC_MARGIN_FORE: - colour = vs.styles[STYLE_DEFAULT].fore; - break; - default: - colour = vs.styles[STYLE_LINENUMBER].back; - break; - } - surface->FillRectangle(rcSelMargin, colour); - } - } else { - surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back); - } - - const int lineStartPaint = static_cast(rcMargin.top + ptOrigin.y) / vs.lineHeight; - int visibleLine = TopLineOfMain() + lineStartPaint; - int yposScreen = lineStartPaint * vs.lineHeight - static_cast(ptOrigin.y); - // Work out whether the top line is whitespace located after a - // lessening of fold level which implies a 'fold tail' but which should not - // be displayed until the last of a sequence of whitespace. - bool needWhiteClosure = false; - if (vs.ms[margin].mask & SC_MASK_FOLDERS) { - int level = pdoc->GetLevel(cs.DocFromDisplay(visibleLine)); - if (level & SC_FOLDLEVELWHITEFLAG) { - int lineBack = cs.DocFromDisplay(visibleLine); - int levelPrev = level; - while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { - lineBack--; - levelPrev = pdoc->GetLevel(lineBack); - } - if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { - if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK)) - needWhiteClosure = true; - } - } - if (highlightDelimiter.isEnabled) { - int lastLine = cs.DocFromDisplay(topLine + LinesOnScreen()) + 1; - pdoc->GetHighlightDelimiters(highlightDelimiter, pdoc->LineFromPosition(CurrentPosition()), lastLine); - } - } - - // Old code does not know about new markers needed to distinguish all cases - const int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, - SC_MARKNUM_FOLDEROPEN); - const int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND, - SC_MARKNUM_FOLDER); - - while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rc.bottom) { - - PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed()); - const int lineDoc = cs.DocFromDisplay(visibleLine); - PLATFORM_ASSERT(cs.GetVisible(lineDoc)); - const bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc); - const bool lastSubLine = visibleLine == cs.DisplayLastFromDoc(lineDoc); - - int marks = pdoc->GetMark(lineDoc); - if (!firstSubLine) - marks = 0; - - bool headWithTail = false; - - if (vs.ms[margin].mask & SC_MASK_FOLDERS) { - // Decide which fold indicator should be displayed - const int level = pdoc->GetLevel(lineDoc); - const int levelNext = pdoc->GetLevel(lineDoc + 1); - const int levelNum = level & SC_FOLDLEVELNUMBERMASK; - const int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK; - if (level & SC_FOLDLEVELHEADERFLAG) { - if (firstSubLine) { - 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 { - 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; - const int firstFollowupLine = cs.DocFromDisplay(cs.DisplayFromDoc(lineDoc + 1)); - const int firstFollowupLineLevel = pdoc->GetLevel(firstFollowupLine); - const int secondFollowupLineLevelNum = pdoc->GetLevel(firstFollowupLine + 1) & SC_FOLDLEVELNUMBERMASK; - if (!cs.GetExpanded(lineDoc)) { - if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) && - (levelNum > secondFollowupLineLevelNum)) - needWhiteClosure = true; - - if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) - headWithTail = true; - } - } else if (level & SC_FOLDLEVELWHITEFLAG) { - if (needWhiteClosure) { - if (levelNext & SC_FOLDLEVELWHITEFLAG) { - marks |= 1 << SC_MARKNUM_FOLDERSUB; - } else if (levelNextNum > SC_FOLDLEVELBASE) { - marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; - needWhiteClosure = false; - } else { - marks |= 1 << SC_MARKNUM_FOLDERTAIL; - needWhiteClosure = false; - } - } else if (levelNum > SC_FOLDLEVELBASE) { - if (levelNextNum < levelNum) { - if (levelNextNum > SC_FOLDLEVELBASE) { - marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; - } else { - marks |= 1 << SC_MARKNUM_FOLDERTAIL; - } - } else { - marks |= 1 << SC_MARKNUM_FOLDERSUB; - } - } - } else if (levelNum > SC_FOLDLEVELBASE) { - if (levelNextNum < levelNum) { - needWhiteClosure = false; - if (levelNext & SC_FOLDLEVELWHITEFLAG) { - marks |= 1 << SC_MARKNUM_FOLDERSUB; - needWhiteClosure = true; - } else if (lastSubLine) { - if (levelNextNum > SC_FOLDLEVELBASE) { - marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; - } else { - marks |= 1 << SC_MARKNUM_FOLDERTAIL; - } - } else { - marks |= 1 << SC_MARKNUM_FOLDERSUB; - } - } else { - marks |= 1 << SC_MARKNUM_FOLDERSUB; - } - } - } - - marks &= vs.ms[margin].mask; - - PRectangle rcMarker = rcSelMargin; - rcMarker.top = static_cast(yposScreen); - rcMarker.bottom = static_cast(yposScreen + vs.lineHeight); - if (vs.ms[margin].style == SC_MARGIN_NUMBER) { - if (firstSubLine) { - char number[100] = ""; - if (lineDoc >= 0) - sprintf(number, "%d", lineDoc + 1); - if (foldFlags & (SC_FOLDFLAG_LEVELNUMBERS | SC_FOLDFLAG_LINESTATE)) { - if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) { - int lev = pdoc->GetLevel(lineDoc); - sprintf(number, "%c%c %03X %03X", - (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_', - (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_', - lev & SC_FOLDLEVELNUMBERMASK, - lev >> 16 - ); - } else { - int state = pdoc->GetLineState(lineDoc); - sprintf(number, "%0X", state); - } - } - PRectangle rcNumber = rcMarker; - // Right justify - XYPOSITION width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number)); - XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; - rcNumber.left = xpos; - DrawTextInStyle(surface, rcNumber, vs.styles[STYLE_LINENUMBER], - rcNumber.top + vs.maxAscent, number, strlen(number)); - } else if (vs.wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) { - PRectangle rcWrapMarker = rcMarker; - rcWrapMarker.right -= 3; - rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth; - DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); - } - } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { - if (firstSubLine) { - const StyledText stMargin = pdoc->MarginStyledText(lineDoc); - if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { - surface->FillRectangle(rcMarker, - vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back); - if (vs.ms[margin].style == SC_MARGIN_RTEXT) { - int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); - rcMarker.left = rcMarker.right - width - 3; - } - DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, - stMargin, 0, stMargin.length); - } - } - } - - if (marks) { - for (int markBit = 0; (markBit < 32) && marks; markBit++) { - if (marks & 1) { - LineMarker::typeOfFold tFold = LineMarker::undefined; - if ((vs.ms[margin].mask & SC_MASK_FOLDERS) && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { - if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { - tFold = LineMarker::body; - } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { - if (firstSubLine) { - tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head; - } else { - if (cs.GetExpanded(lineDoc) || headWithTail) { - tFold = LineMarker::body; - } else { - tFold = LineMarker::undefined; - } - } - } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { - tFold = LineMarker::tail; - } - } - vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font, tFold, vs.ms[margin].style); - } - marks >>= 1; - } - } - - visibleLine++; - yposScreen += vs.lineHeight; - } - } + if (view.bufferedDraw) { + surfWindow->Copy(rcMargin, Point(rcMargin.left, rcMargin.top), *marginView.pixmapSelMargin); } - - PRectangle rcBlankMargin = rcMargin; - rcBlankMargin.left = rcSelMargin.right; - surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back); - - if (bufferedDraw) { - surfWindow->Copy(rcMargin, Point(rcMargin.left, rcMargin.top), *pixmapSelMargin); - } -} - -void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { - int ydiff = static_cast(rcTab.bottom - rcTab.top) / 2; - int xhead = static_cast(rcTab.right) - 1 - ydiff; - if (xhead <= rcTab.left) { - ydiff -= static_cast(rcTab.left) - xhead - 1; - xhead = static_cast(rcTab.left) - 1; - } - if ((rcTab.left + 2) < (rcTab.right - 1)) - surface->MoveTo(static_cast(rcTab.left) + 2, ymid); - else - surface->MoveTo(static_cast(rcTab.right) - 1, ymid); - surface->LineTo(static_cast(rcTab.right) - 1, ymid); - surface->LineTo(xhead, ymid - ydiff); - surface->MoveTo(static_cast(rcTab.right) - 1, ymid); - surface->LineTo(xhead, ymid + ydiff); -} - -LineLayout *Editor::RetrieveLineLayout(int lineNumber) { - int posLineStart = pdoc->LineStart(lineNumber); - int posLineEnd = pdoc->LineStart(lineNumber + 1); - PLATFORM_ASSERT(posLineEnd >= posLineStart); - int lineCaret = pdoc->LineFromPosition(sel.MainCaret()); - return llc.Retrieve(lineNumber, lineCaret, - posLineEnd - posLineStart, pdoc->GetStyleClock(), - LinesOnScreen() + 1, pdoc->LinesTotal()); -} - -/** - * Fill in the LineLayout data for the given line. - * Copy the given @a line and its styles from the document into local arrays. - * Also determine the x position at which each character starts. - */ -void Editor::LayoutLine(int line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) { - if (!ll) - return; - - PLATFORM_ASSERT(line < pdoc->LinesTotal()); - PLATFORM_ASSERT(ll->chars != NULL); - int posLineStart = pdoc->LineStart(line); - int posLineEnd = pdoc->LineStart(line + 1); - // If the line is very long, limit the treatment to a length that should fit in the viewport - if (posLineEnd > (posLineStart + ll->maxLineLength)) { - posLineEnd = posLineStart + ll->maxLineLength; - } - if (ll->validity == LineLayout::llCheckTextAndStyle) { - int lineLength = posLineEnd - posLineStart; - if (!vstyle.viewEOL) { - lineLength = pdoc->LineEnd(line) - posLineStart; - } - if (lineLength == ll->numCharsInLine) { - // See if chars, styles, indicators, are all the same - bool allSame = true; - // Check base line layout - char styleByte = 0; - int numCharsInLine = 0; - while (numCharsInLine < lineLength) { - int charInDoc = numCharsInLine + posLineStart; - char chDoc = pdoc->CharAt(charInDoc); - styleByte = pdoc->StyleAt(charInDoc); - allSame = allSame && - (ll->styles[numCharsInLine] == static_cast(styleByte)); - if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) - allSame = allSame && - (ll->chars[numCharsInLine] == chDoc); - else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) - allSame = allSame && - (ll->chars[numCharsInLine] == static_cast(tolower(chDoc))); - else // Style::caseUpper - allSame = allSame && - (ll->chars[numCharsInLine] == static_cast(toupper(chDoc))); - numCharsInLine++; - } - allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled - if (allSame) { - ll->validity = LineLayout::llPositions; - } else { - ll->validity = LineLayout::llInvalid; - } - } else { - ll->validity = LineLayout::llInvalid; - } - } - if (ll->validity == LineLayout::llInvalid) { - ll->widthLine = LineLayout::wrapWidthInfinite; - ll->lines = 1; - if (vstyle.edgeState == EDGE_BACKGROUND) { - ll->edgeColumn = pdoc->FindColumn(line, vstyle.theEdge); - if (ll->edgeColumn >= posLineStart) { - ll->edgeColumn -= posLineStart; - } - } else { - ll->edgeColumn = -1; - } - - // Fill base line layout - const int lineLength = posLineEnd - posLineStart; - pdoc->GetCharRange(ll->chars, posLineStart, lineLength); - pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); - int numCharsBeforeEOL = pdoc->LineEnd(line) - posLineStart; - const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; - for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { - const unsigned char styleByte = ll->styles[styleInLine]; - ll->styles[styleInLine] = styleByte; - } - const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength-1] : 0; - 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; - // Extra element at the end of the line to hold end x position and act as - ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character - ll->styles[numCharsInLine] = styleByteLast; // For eolFilled - - // Layout the line, determining the position of each character, - // with an extra element at the end for the end of the line. - ll->positions[0] = 0; - bool lastSegItalics = false; - - BreakFinder bfLayout(ll, NULL, 0, numCharsInLine, posLineStart, 0, false, pdoc, &reprs); - while (bfLayout.More()) { - - const TextSegment ts = bfLayout.Next(); - - std::fill(&ll->positions[ts.start+1], &ll->positions[ts.end()+1], 0.0f); - if (vstyle.styles[ll->styles[ts.start]].visible) { - if (ts.representation) { - XYPOSITION representationWidth = vstyle.controlCharWidth; - if (ll->chars[ts.start] == '\t') { - // Tab is a special case of representation, taking a variable amount of space - representationWidth = - ((static_cast((ll->positions[ts.start] + 2) / vstyle.tabWidth) + 1) * vstyle.tabWidth) - ll->positions[ts.start]; - } else { - if (representationWidth <= 0.0) { - XYPOSITION positionsRepr[256]; // Should expand when needed - posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, ts.representation->stringRep.c_str(), - static_cast(ts.representation->stringRep.length()), positionsRepr, pdoc); - representationWidth = positionsRepr[ts.representation->stringRep.length()-1] + vstyle.ctrlCharPadding; - } - } - for (int ii=0; ii < ts.length; ii++) - ll->positions[ts.start + 1 + ii] = representationWidth; - } else { - if ((ts.length == 1) && (' ' == ll->chars[ts.start])) { - // Over half the segments are single characters and of these about half are space characters. - ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth; - } else { - posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], ll->chars + ts.start, - ts.length, ll->positions + ts.start + 1, pdoc); - } - } - lastSegItalics = (!ts.representation) && ((ll->chars[ts.end()-1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic); - } - - for (int posToIncrease = ts.start+1; posToIncrease <= ts.end(); posToIncrease++) { - ll->positions[posToIncrease] += ll->positions[ts.start]; - } - } - - // Small hack to make lines that end with italics not cut off the edge of the last character - if (lastSegItalics) { - ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset; - } - ll->numCharsInLine = numCharsInLine; - ll->numCharsBeforeEOL = numCharsBeforeEOL; - ll->validity = LineLayout::llPositions; - } - // Hard to cope when too narrow, so just assume there is space - if (width < 20) { - width = 20; - } - if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { - ll->widthLine = width; - if (width == LineLayout::wrapWidthInfinite) { - ll->lines = 1; - } else if (width > ll->positions[ll->numCharsInLine]) { - // Simple common case where line does not need wrapping. - ll->lines = 1; - } else { - if (vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { - width -= static_cast(vstyle.aveCharWidth); // take into account the space for end wrap mark - } - XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line - if (vstyle.wrapIndentMode == SC_WRAPINDENT_INDENT) { - wrapAddIndent = pdoc->IndentSize() * vstyle.spaceWidth; - } else if (vstyle.wrapIndentMode == SC_WRAPINDENT_FIXED) { - wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth; - } - ll->wrapIndent = wrapAddIndent; - if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED) - for (int i = 0; i < ll->numCharsInLine; i++) { - if (!IsSpaceOrTab(ll->chars[i])) { - ll->wrapIndent += ll->positions[i]; // Add line indent - break; - } - } - // Check for text width minimum - if (ll->wrapIndent > width - static_cast(vstyle.aveCharWidth) * 15) - ll->wrapIndent = wrapAddIndent; - // Check for wrapIndent minimum - if ((vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) - ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual - ll->lines = 0; - // Calculate line start positions based upon width. - int lastGoodBreak = 0; - int lastLineStart = 0; - XYACCUMULATOR startOffset = 0; - int p = 0; - while (p < ll->numCharsInLine) { - if ((ll->positions[p + 1] - startOffset) >= width) { - if (lastGoodBreak == lastLineStart) { - // Try moving to start of last character - if (p > 0) { - lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) - - posLineStart; - } - if (lastGoodBreak == lastLineStart) { - // Ensure at least one character on line. - lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) - - posLineStart; - } - } - lastLineStart = lastGoodBreak; - ll->lines++; - ll->SetLineStart(ll->lines, lastGoodBreak); - startOffset = ll->positions[lastGoodBreak]; - // take into account the space for start wrap mark and indent - startOffset -= ll->wrapIndent; - p = lastGoodBreak + 1; - continue; - } - if (p > 0) { - if (vstyle.wrapState == eWrapChar) { - lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) - - posLineStart; - p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; - continue; - } else if ((vstyle.wrapState == eWrapWord) && (ll->styles[p] != ll->styles[p - 1])) { - lastGoodBreak = p; - } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { - lastGoodBreak = p; - } - } - p++; - } - ll->lines++; - } - ll->validity = LineLayout::llLines; - } -} - -ColourDesired Editor::SelectionBackground(const ViewStyle &vsDraw, bool main) const { - return main ? - (primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) : - vsDraw.selAdditionalBackground; -} - -ColourDesired Editor::TextBackground(const ViewStyle &vsDraw, - ColourOptional background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) const { - if (inSelection == 1) { - if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(vsDraw, true); - } - } else if (inSelection == 2) { - if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(vsDraw, false); - } - } else { - if ((vsDraw.edgeState == EDGE_BACKGROUND) && - (i >= ll->edgeColumn) && - (i < ll->numCharsBeforeEOL)) - return vsDraw.edgecolour; - if (inHotspot && vsDraw.hotspotColours.back.isSet) - return vsDraw.hotspotColours.back; - } - if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { - return background; - } else { - return vsDraw.styles[styleMain].back; - } -} - -void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { - Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); - PRectangle rcCopyArea = PRectangle::FromInts(start + 1, static_cast(rcSegment.top), start + 2, static_cast(rcSegment.bottom)); - surface->Copy(rcCopyArea, from, - highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); -} - -void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace, - bool isEndMarker, ColourDesired wrapColour) { - surface->PenColour(wrapColour); - - enum { xa = 1 }; // gap before start - int w = static_cast(rcPlace.right - rcPlace.left) - xa - 1; - - bool xStraight = isEndMarker; // x-mirrored symbol for start marker - - int x0 = static_cast(xStraight ? rcPlace.left : rcPlace.right - 1); - int y0 = static_cast(rcPlace.top); - - int dy = static_cast(rcPlace.bottom - rcPlace.top) / 5; - int y = static_cast(rcPlace.bottom - rcPlace.top) / 2 + dy; - - struct Relative { - Surface *surface; - int xBase; - int xDir; - int yBase; - int yDir; - void MoveTo(int xRelative, int yRelative) { - surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); - } - void LineTo(int xRelative, int yRelative) { - surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); - } - }; - Relative rel = {surface, x0, xStraight ? 1 : -1, y0, 1}; - - // arrow head - rel.MoveTo(xa, y); - rel.LineTo(xa + 2*w / 3, y - dy); - rel.MoveTo(xa, y); - rel.LineTo(xa + 2*w / 3, y + dy); - - // arrow body - rel.MoveTo(xa, y); - rel.LineTo(xa + w, y); - rel.LineTo(xa + w, y - 2 * dy); - rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... - y - 2 * dy); -} - -static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { - if (alpha != SC_ALPHA_NOALPHA) { - surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); - } -} - -void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, - const char *s, ColourDesired textBack, ColourDesired textFore, bool twoPhaseDraw) { - if (!twoPhaseDraw) { - surface->FillRectangle(rcSegment, textBack); - } - FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; - int normalCharHeight = static_cast(surface->Ascent(ctrlCharsFont) - - surface->InternalLeading(ctrlCharsFont)); - PRectangle rcCChar = rcSegment; - rcCChar.left = rcCChar.left + 1; - rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; - rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; - PRectangle rcCentral = rcCChar; - rcCentral.top++; - rcCentral.bottom--; - surface->FillRectangle(rcCentral, textFore); - PRectangle rcChar = rcCChar; - rcChar.left++; - rcChar.right--; - surface->DrawTextClipped(rcChar, ctrlCharsFont, - rcSegment.top + vsDraw.maxAscent, s, istrlen(s), - textBack, textFore); -} - -void Editor::DrawEOL(Surface *surface, const ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, - int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, - ColourOptional background) { - - const int posLineStart = pdoc->LineStart(line); - PRectangle rcSegment = rcLine; - - const bool lastSubLine = subLine == (ll->lines - 1); - XYPOSITION virtualSpace = 0; - if (lastSubLine) { - const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * spaceWidth; - } - XYPOSITION xEol = static_cast(ll->positions[lineEnd] - subLineStart); - - // Fill the virtual space and show selections within it - if (virtualSpace) { - rcSegment.left = xEol + xStart; - rcSegment.right = xEol + xStart + virtualSpace; - surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back); - if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { - SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line)))); - for (size_t r=0; rEndLineStyle()].spaceWidth; - rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - - static_cast(subLineStart) + portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - - static_cast(subLineStart) + portion.end.VirtualSpace() * spaceWidth; - rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; - rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; - surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main())); - } - } - } - } - } - - int eolInSelection = 0; - int alpha = SC_ALPHA_NOALPHA; - if (!hideSelection) { - int posAfterLineEnd = pdoc->LineStart(line + 1); - eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0; - alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; - } - - // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on - XYPOSITION blobsWidth = 0; - if (lastSubLine) { - for (int eolPos=ll->numCharsBeforeEOL; eolPosnumCharsInLine; eolPos++) { - rcSegment.left = xStart + ll->positions[eolPos] - static_cast(subLineStart) + virtualSpace; - rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast(subLineStart) + virtualSpace; - blobsWidth += rcSegment.Width(); - char hexits[4]; - const char *ctrlChar; - unsigned char chEOL = ll->chars[eolPos]; - int styleMain = ll->styles[eolPos]; - ColourDesired textBack = TextBackground(vsDraw, background, eolInSelection, false, styleMain, eolPos, ll); - if (UTF8IsAscii(chEOL)) { - ctrlChar = ControlCharacterString(chEOL); - } else { - const Representation *repr = reprs.RepresentationFromCharacter(ll->chars + eolPos, ll->numCharsInLine - eolPos); - if (repr) { - ctrlChar = repr->stringRep.c_str(); - eolPos = ll->numCharsInLine; - } else { - sprintf(hexits, "x%2X", chEOL); - ctrlChar = hexits; - } - } - ColourDesired textFore = vsDraw.styles[styleMain].fore; - if (eolInSelection && vsDraw.selColours.fore.isSet) { - textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; - } - if (eolInSelection && vsDraw.selColours.back.isSet && (line < pdoc->LinesTotal() - 1)) { - if (alpha == SC_ALPHA_NOALPHA) { - surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); - } else { - surface->FillRectangle(rcSegment, textBack); - } - } else { - surface->FillRectangle(rcSegment, textBack); - } - DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); - if (eolInSelection && vsDraw.selColours.back.isSet && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); - } - } - } - - // Draw the eol-is-selected rectangle - rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; - rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; - - if (eolInSelection && vsDraw.selColours.back.isSet && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); - } else { - if (background.isSet) { - surface->FillRectangle(rcSegment, background); - } else if (line < pdoc->LinesTotal() - 1) { - surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); - } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { - surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); - } else { - surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); - } - if (eolInSelection && vsDraw.selColours.back.isSet && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); - } - } - - // Fill the remainder of the line - rcSegment.left = rcSegment.right; - if (rcSegment.left < rcLine.left) - rcSegment.left = rcLine.left; - rcSegment.right = rcLine.right; - - if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); - } else { - if (background.isSet) { - surface->FillRectangle(rcSegment, background); - } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { - surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); - } else { - surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); - } - if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); - } - } - - bool drawWrapMarkEnd = false; - - if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { - if (subLine + 1 < ll->lines) { - drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; - } - } - - if (drawWrapMarkEnd) { - PRectangle rcPlace = rcSegment; - - if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { - rcPlace.left = xEol + xStart + virtualSpace; - rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; - } else { - // rcLine is clipped to text area - rcPlace.right = rcLine.right; - rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; - } - DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); - } -} - -void Editor::DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, const ViewStyle &vsDraw, - int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { - const XYPOSITION 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, const 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 posLineEnd = posLineStart + lineEnd; - - for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) { - if (under == vsDraw.indicators[deco->indicator].under) { - int startPos = posLineStart + lineStart; - if (!deco->rs.ValueAt(startPos)) { - startPos = deco->rs.EndRun(startPos); - } - while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { - int endPos = deco->rs.EndRun(startPos); - if (endPos > posLineEnd) - endPos = posLineEnd; - DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, - surface, vsDraw, xStart, rcLine, ll, subLine); - startPos = endPos; - if (!deco->rs.ValueAt(startPos)) { - startPos = deco->rs.EndRun(startPos); - } - } - } - } - - // Use indicators to highlight matching braces - if ((vsDraw.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || - (vsDraw.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { - int braceIndicator = (bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.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, const ViewStyle &vsDraw, int line, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine) { - int indent = static_cast(pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); - PRectangle rcSegment = rcLine; - int annotationLine = subLine - ll->lines; - const StyledText stAnnotation = pdoc->AnnotationStyledText(line); - if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { - surface->FillRectangle(rcSegment, vsDraw.styles[0].back); - rcSegment.left = static_cast(xStart); - if (trackLineWidth || (vsDraw.annotationVisible == ANNOTATION_BOXED)) { - // Only care about calculating width if tracking or need to draw box - int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); - if (vsDraw.annotationVisible == ANNOTATION_BOXED) { - widthAnnotation += static_cast(vsDraw.spaceWidth * 2); // Margins - } - if (widthAnnotation > lineWidthMaxSeen) - lineWidthMaxSeen = widthAnnotation; - if (vsDraw.annotationVisible == ANNOTATION_BOXED) { - rcSegment.left = static_cast(xStart + indent); - rcSegment.right = rcSegment.left + widthAnnotation; - } - } - const int annotationLines = pdoc->AnnotationLines(line); - size_t start = 0; - size_t lengthAnnotation = stAnnotation.LineLength(start); - int lineInAnnotation = 0; - while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { - start += lengthAnnotation + 1; - lengthAnnotation = stAnnotation.LineLength(start); - lineInAnnotation++; - } - PRectangle rcText = rcSegment; - if (vsDraw.annotationVisible == ANNOTATION_BOXED) { - surface->FillRectangle(rcText, - vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); - rcText.left += vsDraw.spaceWidth; - } - DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, - stAnnotation, start, lengthAnnotation); - if (vsDraw.annotationVisible == ANNOTATION_BOXED) { - surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); - surface->MoveTo(static_cast(rcSegment.left), static_cast(rcSegment.top)); - surface->LineTo(static_cast(rcSegment.left), static_cast(rcSegment.bottom)); - surface->MoveTo(static_cast(rcSegment.right), static_cast(rcSegment.top)); - surface->LineTo(static_cast(rcSegment.right), static_cast(rcSegment.bottom)); - if (subLine == ll->lines) { - surface->MoveTo(static_cast(rcSegment.left), static_cast(rcSegment.top)); - surface->LineTo(static_cast(rcSegment.right), static_cast(rcSegment.top)); - } - if (subLine == ll->lines+annotationLines-1) { - surface->MoveTo(static_cast(rcSegment.left), static_cast(rcSegment.bottom - 1)); - surface->LineTo(static_cast(rcSegment.right), static_cast(rcSegment.bottom - 1)); - } - } - } -} - -void Editor::DrawLine(Surface *surface, const ViewStyle &vsDraw, int line, int lineVisible, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine) { - - if (subLine >= ll->lines) { - DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine); - return; // No further drawing - } - - PRectangle rcSegment = rcLine; - - // Using one font for all control characters so it can be controlled independently to ensure - // the box goes around the characters tightly. Seems to be no way to work out what height - // is taken by an individual character - internal leading gives varying results. - FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; - - // See if something overrides the line background color. - const ColourOptional background = vsDraw.Background(pdoc->GetMark(line), caret.active, ll->containsCaret); - - const bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) && - (!background.isSet) && (vsDraw.whitespaceColours.back.isSet); - - bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. - const XYPOSITION indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth; - const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues - - const int posLineStart = pdoc->LineStart(line); - - const int startseg = ll->LineStart(subLine); - const XYACCUMULATOR subLineStart = ll->positions[startseg]; - int lineStart = 0; - int lineEnd = 0; - if (subLine < ll->lines) { - lineStart = ll->LineStart(subLine); - lineEnd = ll->LineStart(subLine + 1); - if (subLine == ll->lines - 1) { - lineEnd = ll->numCharsBeforeEOL; - } - } - - if (ll->wrapIndent != 0) { - - bool continuedWrapLine = false; - if (subLine < ll->lines) { - continuedWrapLine = ll->LineStart(subLine) != 0; - } - - if (continuedWrapLine) { - // draw continuation rect - PRectangle rcPlace = rcSegment; - - rcPlace.left = ll->positions[startseg] + xStart - static_cast(subLineStart); - rcPlace.right = rcPlace.left + ll->wrapIndent; - - // default bgnd here.. - surface->FillRectangle(rcSegment, background.isSet ? background : - vsDraw.styles[STYLE_DEFAULT].back); - - // main line style would be below but this would be inconsistent with end markers - // also would possibly not be the style at wrap point - //int styleMain = ll->styles[lineStart]; - //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back); - - if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_START) { - - if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT) - rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; - else - rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; - - DrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour()); - } - - xStart += static_cast(ll->wrapIndent); - } - } - - const bool selBackDrawn = vsDraw.selColours.back.isSet && - ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)); - - // Does not take margin into account but not significant - const int xStartVisible = static_cast(subLineStart) - xStart; - - if (twoPhaseDraw) { - BreakFinder bfBack(ll, &sel, lineStart, lineEnd, posLineStart, xStartVisible, selBackDrawn, pdoc, &reprs); - - // Background drawing loop - while (bfBack.More()) { - - const TextSegment ts = bfBack.Next(); - const int i = ts.end() - 1; - const int iDoc = i + posLineStart; - - rcSegment.left = ll->positions[ts.start] + xStart - static_cast(subLineStart); - rcSegment.right = ll->positions[ts.end()] + xStart - static_cast(subLineStart); - // Only try to draw if really visible - enhances performance by not calling environment to - // draw strings that are completely past the right side of the window. - if (rcSegment.Intersects(rcLine)) { - // Clip to line rectangle, since may have a huge position which will not work with some platforms - if (rcSegment.left < rcLine.left) - rcSegment.left = rcLine.left; - if (rcSegment.right > rcLine.right) - rcSegment.right = rcLine.right; - - const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); - const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); - ColourDesired textBack = TextBackground(vsDraw, background, inSelection, - inHotspot, ll->styles[i], i, ll); - if (ts.representation) { - if (ll->chars[i] == '\t') { - // Tab display - if (drawWhitespaceBackground && - (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) - textBack = vsDraw.whitespaceColours.back; - } else { - // Blob display - inIndentation = false; - } - surface->FillRectangle(rcSegment, textBack); - } else { - // Normal text display - surface->FillRectangle(rcSegment, textBack); - if (vsDraw.viewWhitespace != wsInvisible || - (inIndentation && vsDraw.viewIndentationGuides == ivReal)) { - for (int cpos = 0; cpos <= i - ts.start; cpos++) { - if (ll->chars[cpos + ts.start] == ' ') { - if (drawWhitespaceBackground && - (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { - PRectangle rcSpace( - ll->positions[cpos + ts.start] + xStart - static_cast(subLineStart), - rcSegment.top, - ll->positions[cpos + ts.start + 1] + xStart - static_cast(subLineStart), - rcSegment.bottom); - surface->FillRectangle(rcSpace, vsDraw.whitespaceColours.back); - } - } else { - inIndentation = false; - } - } - } - } - } else if (rcSegment.left > rcLine.right) { - break; - } - } - - DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, - xStart, subLine, subLineStart, background); - } - - DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true); - - if (vsDraw.edgeState == EDGE_LINE) { - int edgeX = static_cast(vsDraw.theEdge * vsDraw.spaceWidth); - rcSegment.left = static_cast(edgeX + xStart); - if ((ll->wrapIndent != 0) && (lineStart != 0)) - rcSegment.left -= ll->wrapIndent; - rcSegment.right = rcSegment.left + 1; - surface->FillRectangle(rcSegment, vsDraw.edgecolour); - } - - // Draw underline mark as part of background if not transparent - int marks = pdoc->GetMark(line); - int markBit; - for (markBit = 0; (markBit < 32) && marks; markBit++) { - if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) && - (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { - PRectangle rcUnderline = rcLine; - rcUnderline.top = rcUnderline.bottom - 2; - surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back); - } - marks >>= 1; - } - - inIndentation = subLine == 0; // Do not handle indentation except on first subline. - // Foreground drawing loop - BreakFinder bfFore(ll, &sel, lineStart, lineEnd, posLineStart, xStartVisible, - ((!twoPhaseDraw && selBackDrawn) || vsDraw.selColours.fore.isSet), pdoc, &reprs); - - while (bfFore.More()) { - - const TextSegment ts = bfFore.Next(); - const int i = ts.end() - 1; - const int iDoc = i + posLineStart; - - rcSegment.left = ll->positions[ts.start] + xStart - static_cast(subLineStart); - rcSegment.right = ll->positions[ts.end()] + xStart - static_cast(subLineStart); - // Only try to draw if really visible - enhances performance by not calling environment to - // draw strings that are completely past the right side of the window. - if (rcSegment.Intersects(rcLine)) { - int styleMain = ll->styles[i]; - ColourDesired textFore = vsDraw.styles[styleMain].fore; - FontAlias textFont = vsDraw.styles[styleMain].font; - //hotspot foreground - const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc); - if (inHotspot) { - if (vsDraw.hotspotColours.fore.isSet) - textFore = vsDraw.hotspotColours.fore; - } - const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); - if (inSelection && (vsDraw.selColours.fore.isSet)) { - textFore = (inSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; - } - ColourDesired textBack = TextBackground(vsDraw, background, inSelection, inHotspot, styleMain, i, ll); - if (ts.representation) { - if (ll->chars[i] == '\t') { - // Tab display - if (!twoPhaseDraw) { - if (drawWhitespaceBackground && - (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) - textBack = vsDraw.whitespaceColours.back; - surface->FillRectangle(rcSegment, textBack); - } - if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { - for (int indentCount = static_cast((ll->positions[i] + epsilon) / indentWidth); - indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth; - indentCount++) { - if (indentCount > 0) { - int xIndent = static_cast(indentCount * indentWidth); - DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, - (ll->xHighlightGuide == xIndent)); - } - } - } - if (vsDraw.viewWhitespace != wsInvisible) { - if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { - if (vsDraw.whitespaceColours.fore.isSet) - textFore = vsDraw.whitespaceColours.fore; - surface->PenColour(textFore); - PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, - rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); - DrawTabArrow(surface, rcTab, static_cast(rcSegment.top + vsDraw.lineHeight / 2)); - } - } - } else { - inIndentation = false; - if (vsDraw.controlCharSymbol >= 32) { - char cc[2] = { static_cast(vsDraw.controlCharSymbol), '\0' }; - surface->DrawTextNoClip(rcSegment, ctrlCharsFont, - rcSegment.top + vsDraw.maxAscent, - cc, 1, textBack, textFore); - } else { - DrawTextBlob(surface, vsDraw, rcSegment, ts.representation->stringRep.c_str(), textBack, textFore, twoPhaseDraw); - } - } - } else { - // Normal text display - if (vsDraw.styles[styleMain].visible) { - if (twoPhaseDraw) { - surface->DrawTextTransparent(rcSegment, textFont, - rcSegment.top + vsDraw.maxAscent, ll->chars + ts.start, - i - ts.start + 1, textFore); - } else { - surface->DrawTextNoClip(rcSegment, textFont, - rcSegment.top + vsDraw.maxAscent, ll->chars + ts.start, - i - ts.start + 1, textFore, textBack); - } - } - if (vsDraw.viewWhitespace != wsInvisible || - (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { - for (int cpos = 0; cpos <= i - ts.start; cpos++) { - if (ll->chars[cpos + ts.start] == ' ') { - if (vsDraw.viewWhitespace != wsInvisible) { - if (vsDraw.whitespaceColours.fore.isSet) - textFore = vsDraw.whitespaceColours.fore; - if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { - XYPOSITION xmid = (ll->positions[cpos + ts.start] + ll->positions[cpos + ts.start + 1]) / 2; - if (!twoPhaseDraw && drawWhitespaceBackground && - (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { - textBack = vsDraw.whitespaceColours.back; - PRectangle rcSpace( - ll->positions[cpos + ts.start] + xStart - static_cast(subLineStart), - rcSegment.top, - ll->positions[cpos + ts.start + 1] + xStart - static_cast(subLineStart), - rcSegment.bottom); - surface->FillRectangle(rcSpace, textBack); - } - PRectangle rcDot(xmid + xStart - static_cast(subLineStart), - rcSegment.top + vsDraw.lineHeight / 2, 0.0f, 0.0f); - rcDot.right = rcDot.left + vsDraw.whitespaceSize; - rcDot.bottom = rcDot.top + vsDraw.whitespaceSize; - surface->FillRectangle(rcDot, textFore); - } - } - if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { - for (int indentCount = static_cast((ll->positions[cpos + ts.start] + epsilon) / indentWidth); - indentCount <= (ll->positions[cpos + ts.start + 1] - epsilon) / indentWidth; - indentCount++) { - if (indentCount > 0) { - int xIndent = static_cast(indentCount * indentWidth); - DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, - (ll->xHighlightGuide == xIndent)); - } - } - } - } else { - inIndentation = false; - } - } - } - } - if (ll->hotspot.Valid() && vsDraw.hotspotUnderline && ll->hotspot.ContainsCharacter(iDoc)) { - PRectangle rcUL = rcSegment; - rcUL.top = rcUL.top + vsDraw.maxAscent + 1; - rcUL.bottom = rcUL.top + 1; - if (vsDraw.hotspotColours.fore.isSet) - surface->FillRectangle(rcUL, vsDraw.hotspotColours.fore); - else - surface->FillRectangle(rcUL, textFore); - } else if (vsDraw.styles[styleMain].underline) { - PRectangle rcUL = rcSegment; - rcUL.top = rcUL.top + vsDraw.maxAscent + 1; - rcUL.bottom = rcUL.top + 1; - surface->FillRectangle(rcUL, textFore); - } - } else if (rcSegment.left > rcLine.right) { - break; - } - } - if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) - && (subLine == 0)) { - int indentSpace = pdoc->GetLineIndentation(line); - int xStartText = static_cast(ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart]); - - // Find the most recent line with some text - - int lineLastWithText = line; - while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) { - lineLastWithText--; - } - if (lineLastWithText < line) { - xStartText = 100000; // Don't limit to visible indentation on empty line - // This line is empty, so use indentation of last line with text - int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText); - int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; - if (isFoldHeader) { - // Level is one more level than parent - indentLastWithText += pdoc->IndentSize(); - } - if (vsDraw.viewIndentationGuides == ivLookForward) { - // In viLookForward mode, previous line only used if it is a fold header - if (isFoldHeader) { - indentSpace = Platform::Maximum(indentSpace, indentLastWithText); - } - } else { // viLookBoth - indentSpace = Platform::Maximum(indentSpace, indentLastWithText); - } - } - - int lineNextWithText = line; - while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) { - lineNextWithText++; - } - if (lineNextWithText > line) { - 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)); - } - - for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) { - int xIndent = static_cast(indentPos * vsDraw.spaceWidth); - if (xIndent < xStartText) { - DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, - (ll->xHighlightGuide == xIndent)); - } - } - } - - DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false); - - // End of the drawing of the current line - if (!twoPhaseDraw) { - DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, - xStart, subLine, subLineStart, background); - } - if (!hideSelection && ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) { - // For each selection draw - int virtualSpaces = 0; - if (subLine == (ll->lines - 1)) { - virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line)); - } - SelectionPosition posStart(posLineStart + lineStart); - SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces); - SelectionSegment virtualSpaceRange(posStart, posEnd); - for (size_t r=0; rEndLineStyle()].spaceWidth; - rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - - static_cast(subLineStart) + portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - - static_cast(subLineStart) + portion.end.VirtualSpace() * spaceWidth; - if ((ll->wrapIndent != 0) && (lineStart != 0)) { - if ((portion.start.Position() - posLineStart) == lineStart && sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) - rcSegment.left -= static_cast(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here - } - rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; - rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; - if (rcSegment.right > rcLine.left) - SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == sel.Main()), alpha); - } - } - } - } - - // Draw any translucent whole line states - rcSegment = rcLine; - if ((caret.active || vsDraw.alwaysShowCaretLineBackground) && vsDraw.showCaretLineBackground && ll->containsCaret) { - SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground, vsDraw.caretLineAlpha); - } - marks = pdoc->GetMark(line); - for (markBit = 0; (markBit < 32) && marks; markBit++) { - if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) { - SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); - } else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) { - PRectangle rcUnderline = rcSegment; - rcUnderline.top = rcUnderline.bottom - 2; - SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); - } - marks >>= 1; - } - if (vsDraw.maskInLine) { - int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; - if (marksMasked) { - for (markBit = 0; (markBit < 32) && marksMasked; markBit++) { - if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) { - SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); - } - marksMasked >>= 1; - } - } - } -} - -void Editor::DrawBlockCaret(Surface *surface, const ViewStyle &vsDraw, LineLayout *ll, int subLine, - int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) const { - - int lineStart = ll->LineStart(subLine); - int posBefore = posCaret; - int posAfter = MovePositionOutsideChar(posCaret + 1, 1); - int numCharsToDraw = posAfter - posCaret; - - // Work out where the starting and ending offsets are. We need to - // see if the previous character shares horizontal space, such as a - // glyph / combining character. If so we'll need to draw that too. - int offsetFirstChar = offset; - int offsetLastChar = offset + (posAfter - posCaret); - while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) { - if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { - // The char does not share horizontal space - break; - } - // Char shares horizontal space, update the numChars to draw - // Update posBefore to point to the prev char - posBefore = MovePositionOutsideChar(posBefore - 1, -1); - numCharsToDraw = posAfter - posBefore; - offsetFirstChar = offset - (posCaret - posBefore); - } - - // See if the next character shares horizontal space, if so we'll - // need to draw that too. - if (offsetFirstChar < 0) - offsetFirstChar = 0; - numCharsToDraw = offsetLastChar - offsetFirstChar; - while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { - // Update posAfter to point to the 2nd next char, this is where - // the next character ends, and 2nd next begins. We'll need - // to compare these two - posBefore = posAfter; - posAfter = MovePositionOutsideChar(posAfter + 1, 1); - offsetLastChar = offset + (posAfter - posCaret); - if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { - // The char does not share horizontal space - break; - } - // Char shares horizontal space, update the numChars to draw - numCharsToDraw = offsetLastChar - offsetFirstChar; - } - - // We now know what to draw, update the caret drawing rectangle - rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; - rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart; - - // Adjust caret position to take into account any word wrapping symbols. - if ((ll->wrapIndent != 0) && (lineStart != 0)) { - XYPOSITION wordWrapCharWidth = ll->wrapIndent; - rcCaret.left += wordWrapCharWidth; - rcCaret.right += wordWrapCharWidth; - } - - // This character is where the caret block is, we override the colours - // (inversed) for drawing the caret here. - int styleMain = ll->styles[offsetFirstChar]; - FontAlias fontText = vsDraw.styles[styleMain].font; - surface->DrawTextClipped(rcCaret, fontText, - rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, - numCharsToDraw, vsDraw.styles[styleMain].back, - caretColour); } void Editor::RefreshPixMaps(Surface *surfaceWindow) { - if (!pixmapSelPattern->Initialised()) { - const int patternSize = 8; - pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID()); - pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID()); - // This complex procedure is to reproduce the checkerboard dithered pattern used by windows - // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half - // way between the chrome colour and the chrome highlight colour making a nice transition - // between the window chrome and the content area. And it works in low colour depths. - PRectangle rcPattern = PRectangle::FromInts(0, 0, patternSize, patternSize); + view.RefreshPixMaps(surfaceWindow, wMain.GetID(), vs); + marginView.RefreshPixMaps(surfaceWindow, wMain.GetID(), vs); + if (view.bufferedDraw) { + PRectangle rcClient = GetClientRectangle(); + if (!view.pixmapLine->Initialised()) { - // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. - ColourDesired colourFMFill = vs.selbar; - ColourDesired colourFMStripes = vs.selbarlight; - - if (!(vs.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { - // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. - // (Typically, the highlight colour is white.) - colourFMFill = vs.selbarlight; - } - - if (vs.foldmarginColour.isSet) { - // override default fold margin colour - colourFMFill = vs.foldmarginColour; - } - if (vs.foldmarginHighlightColour.isSet) { - // override default fold margin highlight colour - colourFMStripes = vs.foldmarginHighlightColour; - } - - pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); - pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes); - for (int y = 0; y < patternSize; y++) { - for (int x = y % 2; x < patternSize; x+=2) { - PRectangle rcPixel = PRectangle::FromInts(x, y, x + 1, y + 1); - pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); - pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill); - } - } - } - - if (!pixmapIndentGuide->Initialised()) { - // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line - pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); - pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); - PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vs.lineHeight); - pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back); - pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore); - pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back); - pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore); - for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) { - PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1); - pixmapIndentGuide->FillRectangle(rcPixel, vs.styles[STYLE_INDENTGUIDE].fore); - pixmapIndentGuideHighlight->FillRectangle(rcPixel, vs.styles[STYLE_BRACELIGHT].fore); - } - } - - if (bufferedDraw) { - if (!pixmapLine->Initialised()) { - PRectangle rcClient = GetClientRectangle(); - pixmapLine->InitPixMap(static_cast(rcClient.Width()), vs.lineHeight, + view.pixmapLine->InitPixMap(static_cast(rcClient.Width()), vs.lineHeight, surfaceWindow, wMain.GetID()); - pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, + } + if (!marginView.pixmapSelMargin->Initialised()) { + marginView.pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, static_cast(rcClient.Height()), surfaceWindow, wMain.GetID()); } } } -void Editor::DrawCarets(Surface *surface, const ViewStyle &vsDraw, int lineDoc, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine) { - // When drag is active it is the only caret drawn - bool drawDrag = posDrag.IsValid(); - if (hideSelection && !drawDrag) - return; - const int posLineStart = pdoc->LineStart(lineDoc); - // For each selection draw - for (size_t r=0; (rEndLineStyle()].spaceWidth; - const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth; - if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { - XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; - if (ll->wrapIndent != 0) { - int lineStart = ll->LineStart(subLine); - if (lineStart != 0) // Wrapped - xposCaret += ll->wrapIndent; - } - bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret); - bool caretVisibleState = additionalCaretsVisible || mainCaret; - if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && - ((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) { - bool caretAtEOF = false; - bool caretAtEOL = false; - bool drawBlockCaret = false; - XYPOSITION widthOverstrikeCaret; - XYPOSITION caretWidthOffset = 0; - PRectangle rcCaret = rcLine; - - if (posCaret.Position() == pdoc->Length()) { // At end of document - caretAtEOF = true; - widthOverstrikeCaret = vsDraw.aveCharWidth; - } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line - caretAtEOL = true; - widthOverstrikeCaret = vsDraw.aveCharWidth; - } else { - widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset]; - } - if (widthOverstrikeCaret < 3) // Make sure its visible - widthOverstrikeCaret = 3; - - if (xposCaret > 0) - caretWidthOffset = 0.51f; // Move back so overlaps both character cells. - xposCaret += xStart; - if (posDrag.IsValid()) { - /* Dragging text, use a line caret */ - rcCaret.left = static_cast(RoundXYPosition(xposCaret - caretWidthOffset)); - rcCaret.right = rcCaret.left + vsDraw.caretWidth; - } else if (inOverstrike && drawOverstrikeCaret) { - /* Overstrike (insert mode), use a modified bar caret */ - rcCaret.top = rcCaret.bottom - 2; - rcCaret.left = xposCaret + 1; - rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; - } else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) { - /* Block caret */ - rcCaret.left = xposCaret; - if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { - drawBlockCaret = true; - rcCaret.right = xposCaret + widthOverstrikeCaret; - } else { - rcCaret.right = xposCaret + vsDraw.aveCharWidth; - } - } else { - /* Line caret */ - rcCaret.left = static_cast(RoundXYPosition(xposCaret - caretWidthOffset)); - rcCaret.right = rcCaret.left + vsDraw.caretWidth; - } - ColourDesired caretColour = mainCaret ? vsDraw.caretcolour : vsDraw.additionalCaretColour; - if (drawBlockCaret) { - DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); - } else { - surface->FillRectangle(rcCaret, caretColour); - } - } - } - if (drawDrag) - break; - } -} - 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); @@ -3441,18 +1621,9 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { StyleToPositionInView(PositionAfterArea(rcArea)); PRectangle rcClient = GetClientRectangle(); - Point ptOrigin = GetVisibleOriginInMain(); //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); - int screenLinePaintFirst = static_cast(rcArea.top) / vs.lineHeight; - - int xStart = vs.textStart - xOffset + static_cast(ptOrigin.x); - int ypos = 0; - if (!bufferedDraw) - ypos += screenLinePaintFirst * vs.lineHeight; - int yposScreen = screenLinePaintFirst * vs.lineHeight; - if (NotifyUpdateUI()) { RefreshStyleData(); RefreshPixMaps(surfaceWindow); @@ -3467,9 +1638,9 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { } RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change } - PLATFORM_ASSERT(pixmapSelPattern->Initialised()); + PLATFORM_ASSERT(marginView.pixmapSelPattern->Initialised()); - if (!bufferedDraw) + if (!view.bufferedDraw) surfaceWindow->SetClip(rcArea); if (paintState != paintAbandoned) { @@ -3503,195 +1674,19 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { } return; } - //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); - // Allow text at start of line to overlap 1 pixel into the margin as this displays - // serifs and italic stems for aliased text. - const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0; + view.PaintText(surfaceWindow, *this, rcArea, rcClient, vs); - // Do the painting - if (rcArea.right > vs.textStart - leftTextOverlap) { - - Surface *surface = surfaceWindow; - if (bufferedDraw) { - surface = pixmapLine; - PLATFORM_ASSERT(pixmapLine->Initialised()); - } - surface->SetUnicodeMode(IsUnicodeMode()); - surface->SetDBCSMode(CodePage()); - - int visibleLine = TopLineOfMain() + screenLinePaintFirst; - - SelectionPosition posCaret = sel.RangeMain().caret; - if (posDrag.IsValid()) - posCaret = posDrag; - int lineCaret = pdoc->LineFromPosition(posCaret.Position()); - - PRectangle rcTextArea = rcClient; - if (vs.marginInside) { - rcTextArea.left += vs.textStart; - rcTextArea.right -= vs.rightMarginWidth; - } else { - rcTextArea = rcArea; - } - - // Remove selection margin from drawing area so text will not be drawn - // on it in unbuffered mode. - if (!bufferedDraw && vs.marginInside) { - PRectangle rcClipText = rcTextArea; - rcClipText.left -= leftTextOverlap; - surfaceWindow->SetClip(rcClipText); - } - - // Loop on visible lines - //double durLayout = 0.0; - //double durPaint = 0.0; - //double durCopy = 0.0; - //ElapsedTime etWhole; - int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times - AutoLineLayout ll(llc, 0); - while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) { - - int lineDoc = cs.DocFromDisplay(visibleLine); - // Only visible lines should be handled by the code within the loop - PLATFORM_ASSERT(cs.GetVisible(lineDoc)); - int lineStartSet = cs.DisplayFromDoc(lineDoc); - int subLine = visibleLine - lineStartSet; - - // Copy this line and its styles from the document into local arrays - // and determine the x position at which each character starts. - //ElapsedTime et; - if (lineDoc != lineDocPrevious) { - ll.Set(0); - ll.Set(RetrieveLineLayout(lineDoc)); - LayoutLine(lineDoc, surface, vs, ll, wrapWidth); - lineDocPrevious = lineDoc; - } - //durLayout += et.Duration(true); - - if (ll) { - ll->containsCaret = lineDoc == lineCaret; - if (hideSelection) { - ll->containsCaret = false; - } - - ll->hotspot = GetHotSpotRange(); - - PRectangle rcLine = rcTextArea; - rcLine.top = static_cast(ypos); - rcLine.bottom = static_cast(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), - static_cast(highlightGuideColumn * vs.spaceWidth), bracesIgnoreStyle); - - if (leftTextOverlap && bufferedDraw) { - PRectangle rcSpacer = rcLine; - rcSpacer.right = rcSpacer.left; - rcSpacer.left -= 1; - surface->FillRectangle(rcSpacer, vs.styles[STYLE_DEFAULT].back); - } - - // 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, bracesIgnoreStyle); - - bool expanded = cs.GetExpanded(lineDoc); - 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); - } - // 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); - } - } - - DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine); - - if (bufferedDraw) { - Point from = Point::FromInts(vs.textStart-leftTextOverlap, 0); - PRectangle rcCopyArea = PRectangle::FromInts(vs.textStart - leftTextOverlap, yposScreen, - static_cast(rcClient.right - vs.rightMarginWidth), - yposScreen + vs.lineHeight); - surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); - } - - lineWidthMaxSeen = Platform::Maximum( - lineWidthMaxSeen, static_cast(ll->positions[ll->numCharsInLine])); - //durCopy += et.Duration(true); - } - - if (!bufferedDraw) { - ypos += vs.lineHeight; - } - - yposScreen += vs.lineHeight; - visibleLine++; - - //gdk_flush(); - } - ll.Set(0); - //if (durPaint < 0.00000001) - // durPaint = 0.00000001; - - // Right column limit indicator - PRectangle rcBeyondEOF = (vs.marginInside) ? rcClient : rcArea; - rcBeyondEOF.left = static_cast(vs.textStart); - rcBeyondEOF.right = rcBeyondEOF.right - ((vs.marginInside) ? vs.rightMarginWidth : 0); - rcBeyondEOF.top = static_cast((cs.LinesDisplayed() - TopLineOfMain()) * vs.lineHeight); - if (rcBeyondEOF.top < rcBeyondEOF.bottom) { - surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back); - if (vs.edgeState == EDGE_LINE) { - int edgeX = static_cast(vs.theEdge * vs.spaceWidth); - rcBeyondEOF.left = static_cast(edgeX + xStart); - rcBeyondEOF.right = rcBeyondEOF.left + 1; - surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour); + if (horizontalScrollBarVisible && trackLineWidth && (view.lineWidthMaxSeen > scrollWidth)) { + if (FineTickerAvailable()) { + scrollWidth = view.lineWidthMaxSeen; + if (!FineTickerRunning(tickWiden)) { + FineTickerStart(tickWiden, 50, 5); } } - //Platform::DebugPrintf( - //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n", - //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration()); - NotifyPainted(); } -} -// Space (3 space characters) between line numbers and text when printing. -#define lineNumberPrintSpace " " - -ColourDesired InvertedLight(ColourDesired orig) { - unsigned int r = orig.GetRed(); - unsigned int g = orig.GetGreen(); - unsigned int b = orig.GetBlue(); - unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye - unsigned int il = 0xff - l; - if (l == 0) - return ColourDesired(0xff, 0xff, 0xff); - r = r * il / l; - g = g * il / l; - b = b * il / l; - return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff)); + NotifyPainted(); } // This is mostly copied from the Paint method but with some things omitted @@ -3708,184 +1703,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { if (!surfaceMeasure) { return 0; } - - // Can't use measurements cached for screen - posCache.Clear(); - - ViewStyle vsPrint(vs); - vsPrint.technology = SC_TECHNOLOGY_DEFAULT; - - // Modify the view style for printing as do not normally want any of the transient features to be printed - // Printing supports only the line number margin. - int lineNumberIndex = -1; - for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) { - if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) { - lineNumberIndex = margin; - } else { - vsPrint.ms[margin].width = 0; - } - } - vsPrint.fixedColumnWidth = 0; - vsPrint.zoomLevel = printParameters.magnification; - // Don't show indentation guides - // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT - vsPrint.viewIndentationGuides = ivNone; - // Don't show the selection when printing - vsPrint.selColours.back.isSet = false; - vsPrint.selColours.fore.isSet = false; - vsPrint.selAlpha = SC_ALPHA_NOALPHA; - vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA; - vsPrint.whitespaceColours.back.isSet = false; - vsPrint.whitespaceColours.fore.isSet = false; - vsPrint.showCaretLineBackground = false; - vsPrint.alwaysShowCaretLineBackground = 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.styles.size(); sty++) { - if (printParameters.colourMode == SC_PRINT_INVERTLIGHT) { - vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore); - vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back); - } else if (printParameters.colourMode == SC_PRINT_BLACKONWHITE) { - vsPrint.styles[sty].fore = ColourDesired(0, 0, 0); - vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); - } else if (printParameters.colourMode == SC_PRINT_COLOURONWHITE) { - vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); - } else if (printParameters.colourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) { - if (sty <= STYLE_DEFAULT) { - vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); - } - } - } - // White background for the line numbers - vsPrint.styles[STYLE_LINENUMBER].back = ColourDesired(0xff, 0xff, 0xff); - - // Printing uses different margins, so reset screen margins - vsPrint.leftMarginWidth = 0; - vsPrint.rightMarginWidth = 0; - - vsPrint.Refresh(*surfaceMeasure, pdoc->tabInChars); - // Determining width must happen after fonts have been realised in Refresh - int lineNumberWidth = 0; - if (lineNumberIndex >= 0) { - lineNumberWidth = static_cast(surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, - "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace))); - vsPrint.ms[lineNumberIndex].width = lineNumberWidth; - vsPrint.Refresh(*surfaceMeasure, pdoc->tabInChars); // Recalculate fixedColumnWidth - } - - int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin); - int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; - if (linePrintLast < linePrintStart) - linePrintLast = linePrintStart; - int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax); - if (linePrintLast > linePrintMax) - linePrintLast = linePrintMax; - //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", - // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, - // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); - int endPosPrint = pdoc->Length(); - if (linePrintLast < pdoc->LinesTotal()) - endPosPrint = pdoc->LineStart(linePrintLast + 1); - - // Ensure we are styled to where we are formatting. - pdoc->EnsureStyledTo(endPosPrint); - - int xStart = vsPrint.fixedColumnWidth + pfr->rc.left; - int ypos = pfr->rc.top; - - int lineDoc = linePrintStart; - - int nPrintPos = pfr->chrg.cpMin; - int visibleLine = 0; - int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth; - if (printParameters.wrapState == eWrapNone) - widthPrint = LineLayout::wrapWidthInfinite; - - while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) { - - // When printing, the hdc and hdcTarget may be the same, so - // changing the state of surfaceMeasure may change the underlying - // state of surface. Therefore, any cached state is discarded before - // using each surface. - surfaceMeasure->FlushCachedState(); - - // Copy this line and its styles from the document into local arrays - // and determine the x position at which each character starts. - LineLayout ll(pdoc->LineStart(lineDoc+1)-pdoc->LineStart(lineDoc)+1); - LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); - - ll.containsCaret = false; - - PRectangle rcLine = PRectangle::FromInts( - pfr->rc.left, - ypos, - pfr->rc.right - 1, - ypos + vsPrint.lineHeight); - - // When document line is wrapped over multiple display lines, find where - // to start printing from to ensure a particular position is on the first - // line of the page. - if (visibleLine == 0) { - int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc); - for (int iwl = 0; iwl < ll.lines - 1; iwl++) { - if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) { - visibleLine = -iwl; - } - } - - if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) { - visibleLine = -(ll.lines - 1); - } - } - - if (draw && lineNumberWidth && - (ypos + vsPrint.lineHeight <= pfr->rc.bottom) && - (visibleLine >= 0)) { - char number[100]; - sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1); - PRectangle rcNumber = rcLine; - rcNumber.right = rcNumber.left + lineNumberWidth; - // Right justify - rcNumber.left = rcNumber.right - surfaceMeasure->WidthText( - vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number)); - surface->FlushCachedState(); - surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, - static_cast(ypos + vsPrint.maxAscent), number, istrlen(number), - vsPrint.styles[STYLE_LINENUMBER].fore, - vsPrint.styles[STYLE_LINENUMBER].back); - } - - // Draw the line - surface->FlushCachedState(); - - for (int iwl = 0; iwl < ll.lines; iwl++) { - if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) { - if (visibleLine >= 0) { - if (draw) { - rcLine.top = static_cast(ypos); - rcLine.bottom = static_cast(ypos + vsPrint.lineHeight); - DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl); - } - ypos += vsPrint.lineHeight; - } - visibleLine++; - if (iwl == ll.lines - 1) - nPrintPos = pdoc->LineStart(lineDoc + 1); - else - nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl); - } - } - - ++lineDoc; - } - - // Clear cache so measurements are not used for screen - posCache.Clear(); - - return nPrintPos; + return view.FormatRange(draw, pfr, surface, surfaceMeasure, *this, vs); } int Editor::TextWidth(int style, const char *text) { @@ -3968,17 +1786,20 @@ static bool cmpSelPtrs(const SelectionRange *a, const SelectionRange *b) { } // AddCharUTF inserts an array of bytes which may or may not be in UTF-8. -void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { +void Editor::AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS) { FilterSelections(); { UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike); + // Vector elements point into selection in order to change selection. std::vector selPtrs; for (size_t r = 0; r < sel.Count(); r++) { selPtrs.push_back(&sel.Range(r)); } + // Order selections by position in document. std::sort(selPtrs.begin(), selPtrs.end(), cmpSelPtrs); + // Loop in reverse to avoid disturbing positions of selections yet to be processed. for (std::vector::reverse_iterator rit = selPtrs.rbegin(); rit != selPtrs.rend(); ++rit) { SelectionRange *currentSel = *rit; @@ -4172,6 +1993,9 @@ void Editor::ClearAll() { pdoc->MarginClearAll(); } } + + view.ClearAllTabstops(); + sel.Clear(); SetTopLine(0); SetVerticalScrollPos(); @@ -4192,6 +2016,7 @@ void Editor::ClearDocumentStyle() { pdoc->StartStyling(0, '\377'); pdoc->SetStyleFor(pdoc->Length(), 0); cs.ShowAll(); + SetAnnotationHeights(0, pdoc->LinesTotal()); pdoc->ClearLevels(); } @@ -4285,6 +2110,7 @@ void Editor::Clear() { ClearSelection(); } sel.RemoveDuplicates(); + ShowCaretAtCurrentPosition(); // Avoid blinking } void Editor::SelectAll() { @@ -4312,15 +2138,8 @@ void Editor::Redo() { } } -void Editor::DelChar() { - if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) { - pdoc->DelChar(sel.MainCaret()); - } - // Avoid blinking during rapid typing: - ShowCaretAtCurrentPosition(); -} - void Editor::DelCharBack(bool allowLineStartDeletion) { + RefreshStyleData(); if (!sel.IsRectangular()) FilterSelections(); if (sel.IsRectangular()) @@ -4591,7 +2410,7 @@ void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) { void Editor::CheckModificationForWrap(DocModification mh) { if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { - llc.Invalidate(LineLayout::llCheckTextAndStyle); + view.llc.Invalidate(LineLayout::llCheckTextAndStyle); int lineDoc = pdoc->LineFromPosition(mh.position); int lines = Platform::Maximum(0, mh.linesAdded); if (Wrapping()) { @@ -4640,6 +2459,9 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) { Redraw(); } } + if (mh.modificationType & SC_MOD_CHANGETABSTOPS) { + Redraw(); + } if (mh.modificationType & SC_MOD_LEXERSTATE) { if (paintState == painting) { CheckForChangeOutsidePaint( @@ -4661,7 +2483,7 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) { } } if (mh.modificationType & SC_MOD_CHANGESTYLE) { - llc.Invalidate(LineLayout::llCheckTextAndStyle); + view.llc.Invalidate(LineLayout::llCheckTextAndStyle); } } else { // Move selection and brace highlights @@ -4703,6 +2525,7 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) { } else { cs.DeleteLines(lineOfPos, -mh.linesAdded); } + view.LinesAddedOrRemoved(lineOfPos, mh.linesAdded); } if (mh.modificationType & SC_MOD_CHANGEANNOTATION) { int lineDoc = pdoc->LineFromPosition(mh.position); @@ -4742,7 +2565,7 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) { if ((!willRedrawAll) && ((paintState == notPainting) || !PaintContainsMargin())) { if (mh.modificationType & SC_MOD_CHANGEFOLD) { // Fold changes can affect the drawing of following lines so redraw whole margin - RedrawSelMargin(highlightDelimiter.isEnabled ? -1 : mh.line-1, true); + RedrawSelMargin(marginView.highlightDelimiter.isEnabled ? -1 : mh.line - 1, true); } else { RedrawSelMargin(mh.line); } @@ -5195,29 +3018,8 @@ void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) { int Editor::StartEndDisplayLine(int pos, bool start) { RefreshStyleData(); - int line = pdoc->LineFromPosition(pos); AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(line)); - int posRet = INVALID_POSITION; - if (surface && ll) { - unsigned int posLineStart = pdoc->LineStart(line); - LayoutLine(line, surface, vs, ll, wrapWidth); - int posInLine = pos - posLineStart; - if (posInLine <= ll->maxLineLength) { - for (int subLine = 0; subLine < ll->lines; subLine++) { - if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { - if (start) { - posRet = ll->LineStart(subLine) + posLineStart; - } else { - if (subLine == ll->lines - 1) - posRet = ll->LineStart(subLine + 1) + posLineStart; - else - posRet = ll->LineStart(subLine + 1) + posLineStart - 1; - } - } - } - } - } + int posRet = view.StartEndDisplayLine(surface, *this, pos, start, vs); if (posRet == INVALID_POSITION) { return pos; } else { @@ -5581,6 +3383,7 @@ int Editor::KeyCommand(unsigned int iMessage) { break; case SCI_DELWORDRIGHT: { UndoGroup ug(pdoc); + InvalidateSelection(sel.RangeMain(), true); sel.RangeMain().caret = SelectionPosition( InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); sel.RangeMain().anchor = sel.RangeMain().caret; @@ -5590,6 +3393,7 @@ int Editor::KeyCommand(unsigned int iMessage) { break; case SCI_DELWORDRIGHTEND: { UndoGroup ug(pdoc); + InvalidateSelection(sel.RangeMain(), true); sel.RangeMain().caret = SelectionPosition( InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1); @@ -5840,18 +3644,23 @@ long Editor::FindText( int lengthFound = istrlen(ft->lpstrText); if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); - int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, - (wParam & SCFIND_MATCHCASE) != 0, - (wParam & SCFIND_WHOLEWORD) != 0, - (wParam & SCFIND_WORDSTART) != 0, - (wParam & SCFIND_REGEXP) != 0, - static_cast(wParam), - &lengthFound); - if (pos != -1) { - ft->chrgText.cpMin = pos; - ft->chrgText.cpMax = pos + lengthFound; + try { + 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, + static_cast(wParam), + &lengthFound); + if (pos != -1) { + ft->chrgText.cpMin = pos; + ft->chrgText.cpMax = pos + lengthFound; + } + return pos; + } catch (RegexError &) { + errorStatus = SC_STATUS_WARN_REGEX; + return -1; } - return pos; } /** @@ -5885,22 +3694,27 @@ long Editor::SearchText( int lengthFound = istrlen(txt); if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); - if (iMessage == SCI_SEARCHNEXT) { - pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, - (wParam & SCFIND_MATCHCASE) != 0, - (wParam & SCFIND_WHOLEWORD) != 0, - (wParam & SCFIND_WORDSTART) != 0, - (wParam & SCFIND_REGEXP) != 0, - static_cast(wParam), - &lengthFound); - } else { - pos = pdoc->FindText(searchAnchor, 0, txt, - (wParam & SCFIND_MATCHCASE) != 0, - (wParam & SCFIND_WHOLEWORD) != 0, - (wParam & SCFIND_WORDSTART) != 0, - (wParam & SCFIND_REGEXP) != 0, - static_cast(wParam), - &lengthFound); + try { + if (iMessage == SCI_SEARCHNEXT) { + pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, + (wParam & SCFIND_MATCHCASE) != 0, + (wParam & SCFIND_WHOLEWORD) != 0, + (wParam & SCFIND_WORDSTART) != 0, + (wParam & SCFIND_REGEXP) != 0, + static_cast(wParam), + &lengthFound); + } else { + pos = pdoc->FindText(searchAnchor, 0, txt, + (wParam & SCFIND_MATCHCASE) != 0, + (wParam & SCFIND_WHOLEWORD) != 0, + (wParam & SCFIND_WORDSTART) != 0, + (wParam & SCFIND_REGEXP) != 0, + static_cast(wParam), + &lengthFound); + } + } catch (RegexError &) { + errorStatus = SC_STATUS_WARN_REGEX; + return -1; } if (pos != -1) { SetSelection(pos, pos + lengthFound); @@ -5935,18 +3749,23 @@ long Editor::SearchInTarget(const char *text, int length) { if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); - int pos = pdoc->FindText(targetStart, targetEnd, text, - (searchFlags & SCFIND_MATCHCASE) != 0, - (searchFlags & SCFIND_WHOLEWORD) != 0, - (searchFlags & SCFIND_WORDSTART) != 0, - (searchFlags & SCFIND_REGEXP) != 0, - searchFlags, - &lengthFound); - if (pos != -1) { - targetStart = pos; - targetEnd = pos + lengthFound; + try { + 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); + if (pos != -1) { + targetStart = pos; + targetEnd = pos + lengthFound; + } + return pos; + } catch (RegexError &) { + errorStatus = SC_STATUS_WARN_REGEX; + return -1; } - return pos; } void Editor::GoToLine(int lineNo) { @@ -5959,10 +3778,10 @@ void Editor::GoToLine(int lineNo) { EnsureCaretVisible(); } -static bool Close(Point pt1, Point pt2) { - if (abs(pt1.x - pt2.x) > 3) +static bool Close(Point pt1, Point pt2, Point threshold) { + if (abs(pt1.x - pt2.x) > threshold.x) return false; - if (abs(pt1.y - pt2.y) > 3) + if (abs(pt1.y - pt2.y) > threshold.y) return false; return true; } @@ -6038,7 +3857,13 @@ void Editor::SetDragPosition(SelectionPosition newPos) { } if (!(posDrag == newPos)) { caret.on = true; - SetTicking(true); + if (FineTickerAvailable()) { + FineTickerCancel(tickCaret); + if ((caret.active) && (caret.period > 0) && (newPos.Position() < 0)) + FineTickerStart(tickCaret, caret.period, caret.period/10); + } else { + SetTicking(true); + } InvalidateCaret(); posDrag = newPos; InvalidateCaret(); @@ -6169,7 +3994,7 @@ bool Editor::PointInSelection(Point pt) { return false; } -bool Editor::PointInSelMargin(Point pt) { +bool Editor::PointInSelMargin(Point pt) const { // Really means: "Point in a margin" if (vs.fixedColumnWidth > 0) { // There is a margin PRectangle rcSelMargin = GetClientRectangle(); @@ -6262,6 +4087,12 @@ void Editor::DwellEnd(bool mouseMoved) { dwelling = false; NotifyDwelling(ptMouseLast, dwelling); } + if (FineTickerAvailable()) { + FineTickerCancel(tickDwell); + if (mouseMoved && (dwellDelay < SC_TIME_FOREVER)) { + //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10); + } + } } void Editor::MouseLeave() { @@ -6306,9 +4137,12 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifie if (shift && !inSelMargin) { SetSelection(newPos); } - if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) { + if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick, doubleClickCloseThreshold)) { //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime); SetMouseCapture(true); + if (FineTickerAvailable()) { + FineTickerStart(tickScroll, 100, 10); + } if (!ctrl || !multipleSelection || (selectionType != selChar && selectionType != selWord)) SetEmptySelection(newPos.Position()); bool doubleClick = false; @@ -6405,6 +4239,9 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifie SetDragPosition(SelectionPosition(invalidPosition)); SetMouseCapture(true); + if (FineTickerAvailable()) { + FineTickerStart(tickScroll, 100, 10); + } } else { if (PointIsHotspot(pt)) { NotifyHotSpotClicked(newCharPos.Position(), modifiers); @@ -6417,6 +4254,9 @@ void Editor::ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifie inDragDrop = ddNone; } SetMouseCapture(true); + if (FineTickerAvailable()) { + FineTickerStart(tickScroll, 100, 10); + } if (inDragDrop != ddInitial) { SetDragPosition(SelectionPosition(invalidPosition)); if (!shift) { @@ -6457,7 +4297,7 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b } bool Editor::PositionIsHotspot(int position) const { - return vs.styles[pdoc->StyleAt(position)].hotspot; + return vs.styles[static_cast(pdoc->StyleAt(position))].hotspot; } bool Editor::PointIsHotspot(Point pt) { @@ -6510,6 +4350,9 @@ void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) { if (inDragDrop == ddInitial) { if (DragThreshold(ptMouseLast, pt)) { SetMouseCapture(false); + if (FineTickerAvailable()) { + FineTickerCancel(tickScroll); + } SetDragPosition(movePos); CopySelectionRange(&drag); StartDrag(); @@ -6518,6 +4361,12 @@ void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) { } ptMouseLast = pt; + PRectangle rcClient = GetClientRectangle(); + Point ptOrigin = GetVisibleOriginInMain(); + rcClient.Move(0, -ptOrigin.y); + if (FineTickerAvailable() && (dwellDelay < SC_TIME_FOREVER) && rcClient.Contains(pt)) { + FineTickerStart(tickDwell, dwellDelay, dwellDelay/10); + } //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); if (HaveMouseCapture()) { @@ -6569,9 +4418,6 @@ void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) { } // Autoscroll - PRectangle rcClient = GetClientRectangle(); - Point ptOrigin = GetVisibleOriginInMain(); - rcClient.Move(0, -ptOrigin.y); int lineMove = DisplayFromPosition(movePos.Position()); if (pt.y > rcClient.bottom) { ScrollTo(lineMove - LinesOnScreen() + 1); @@ -6643,6 +4489,9 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { } ptMouseLast = pt; SetMouseCapture(false); + if (FineTickerAvailable()) { + FineTickerCancel(tickScroll); + } NotifyIndicatorClick(false, newPos.Position(), 0); if (inDragDrop == ddDragging) { SelectionPosition selStart = SelectionStart(); @@ -6719,8 +4568,8 @@ void Editor::Tick() { } } } - if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) { - scrollWidth = lineWidthMaxSeen; + if (horizontalScrollBarVisible && trackLineWidth && (view.lineWidthMaxSeen > scrollWidth)) { + scrollWidth = view.lineWidthMaxSeen; SetScrollBars(); } if ((dwellDelay < SC_TIME_FOREVER) && @@ -6759,6 +4608,66 @@ bool Editor::Idle() { return !idleDone; } +void Editor::SetTicking(bool) { + // SetTicking is deprecated. In the past it was pure virtual and was overridden in each + // derived platform class but fine grained timers should now be implemented. + // Either way, execution should not arrive here so assert failure. + assert(false); +} + +void Editor::TickFor(TickReason reason) { + switch (reason) { + case tickCaret: + caret.on = !caret.on; + if (caret.active) { + InvalidateCaret(); + } + break; + case tickScroll: + // Auto scroll + ButtonMove(ptMouseLast); + break; + case tickWiden: + SetScrollBars(); + FineTickerCancel(tickWiden); + break; + case tickDwell: + if ((!HaveMouseCapture()) && + (ptMouseLast.y >= 0)) { + dwelling = true; + NotifyDwelling(ptMouseLast, dwelling); + } + FineTickerCancel(tickDwell); + break; + default: + // tickPlatform handled by subclass + break; + } +} + +bool Editor::FineTickerAvailable() { + return false; +} + +// FineTickerStart is be overridden by subclasses that support fine ticking so +// this method should never be called. +bool Editor::FineTickerRunning(TickReason) { + assert(false); + return false; +} + +// FineTickerStart is be overridden by subclasses that support fine ticking so +// this method should never be called. +void Editor::FineTickerStart(TickReason, int, int) { + assert(false); +} + +// FineTickerCancel is be overridden by subclasses that support fine ticking so +// this method should never be called. +void Editor::FineTickerCancel(TickReason) { + assert(false); +} + void Editor::SetFocusState(bool focusState) { hasFocus = focusState; NotifyFocus(hasFocus); @@ -6838,7 +4747,7 @@ void Editor::CheckForChangeOutsidePaint(Range r) { if (!r.Valid()) return; - PRectangle rcRange = RectangleFromRange(r); + PRectangle rcRange = RectangleFromRange(r, 0); PRectangle rcText = GetTextRectangle(); if (rcRange.top < rcText.top) { rcRange.top = rcText.top; @@ -6880,9 +4789,9 @@ void Editor::SetAnnotationHeights(int start, int end) { int linesWrapped = 1; if (Wrapping()) { AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(line)); + AutoLineLayout ll(view.llc, view.RetrieveLineLayout(line, *this)); if (surface && ll) { - LayoutLine(line, surface, vs, ll, wrapWidth); + view.LayoutLine(*this, line, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } } @@ -6922,9 +4831,11 @@ void Editor::SetDocPointer(Document *document) { cs.Clear(); cs.InsertLines(0, pdoc->LinesTotal() - 1); SetAnnotationHeights(0, pdoc->LinesTotal()); - llc.Deallocate(); + view.llc.Deallocate(); NeedWrapping(); + view.ClearAllTabstops(); + pdoc->AddWatcher(this, 0); SetScrollBars(); Redraw(); @@ -7235,10 +5146,10 @@ int Editor::CodePage() const { int Editor::WrapCount(int line) { AutoSurface surface(this); - AutoLineLayout ll(llc, RetrieveLineLayout(line)); + AutoLineLayout ll(view.llc, view.RetrieveLineLayout(line, *this)); if (surface && ll) { - LayoutLine(line, surface, vs, ll, wrapWidth); + view.LayoutLine(*this, line, surface, vs, ll, wrapWidth); return ll->lines; } else { return 1; @@ -7704,7 +5615,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { } case SCI_HIDESELECTION: - hideSelection = wParam != 0; + view.hideSelection = wParam != 0; Redraw(); break; @@ -7892,25 +5803,25 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_SETPRINTMAGNIFICATION: - printParameters.magnification = static_cast(wParam); + view.printParameters.magnification = static_cast(wParam); break; case SCI_GETPRINTMAGNIFICATION: - return printParameters.magnification; + return view.printParameters.magnification; case SCI_SETPRINTCOLOURMODE: - printParameters.colourMode = static_cast(wParam); + view.printParameters.colourMode = static_cast(wParam); break; case SCI_GETPRINTCOLOURMODE: - return printParameters.colourMode; + return view.printParameters.colourMode; case SCI_SETPRINTWRAPMODE: - printParameters.wrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone; + view.printParameters.wrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone; break; case SCI_GETPRINTWRAPMODE: - return printParameters.wrapState; + return view.printParameters.wrapState; case SCI_GETSTYLEAT: if (static_cast(wParam) >= pdoc->Length()) @@ -8052,18 +5963,26 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_SETBUFFEREDDRAW: - bufferedDraw = wParam != 0; + view.bufferedDraw = wParam != 0; break; case SCI_GETBUFFEREDDRAW: - return bufferedDraw; + return view.bufferedDraw; case SCI_GETTWOPHASEDRAW: - return twoPhaseDraw; + return view.phasesDraw == EditView::phasesTwo; case SCI_SETTWOPHASEDRAW: - twoPhaseDraw = wParam != 0; - InvalidateStyleRedraw(); + if (view.SetTwoPhaseDraw(wParam != 0)) + InvalidateStyleRedraw(); + break; + + case SCI_GETPHASESDRAW: + return view.phasesDraw; + + case SCI_SETPHASESDRAW: + if (view.SetPhasesDraw(static_cast(wParam))) + InvalidateStyleRedraw(); break; case SCI_SETFONTQUALITY: @@ -8087,6 +6006,23 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETTABWIDTH: return pdoc->tabInChars; + case SCI_CLEARTABSTOPS: + if (view.ClearTabstops(static_cast(wParam))) { + DocModification mh(SC_MOD_CHANGETABSTOPS, 0, 0, 0, 0, static_cast(wParam)); + NotifyModified(pdoc, mh, NULL); + } + break; + + case SCI_ADDTABSTOP: + if (view.AddTabstop(static_cast(wParam), static_cast(lParam))) { + DocModification mh(SC_MOD_CHANGETABSTOPS, 0, 0, 0, 0, static_cast(wParam)); + NotifyModified(pdoc, mh, NULL); + } + break; + + case SCI_GETNEXTTABSTOP: + return view.GetNextTabstop(static_cast(wParam), static_cast(lParam)); + case SCI_SETINDENT: pdoc->indentInChars = static_cast(wParam); if (pdoc->indentInChars != 0) @@ -8197,23 +6133,23 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return vs.wrapIndentMode; case SCI_SETLAYOUTCACHE: - llc.SetLevel(static_cast(wParam)); + view.llc.SetLevel(static_cast(wParam)); break; case SCI_GETLAYOUTCACHE: - return llc.GetLevel(); + return view.llc.GetLevel(); case SCI_SETPOSITIONCACHE: - posCache.SetSize(wParam); + view.posCache.SetSize(wParam); break; case SCI_GETPOSITIONCACHE: - return posCache.GetSize(); + return view.posCache.GetSize(); case SCI_SETSCROLLWIDTH: PLATFORM_ASSERT(wParam > 0); if ((wParam > 0) && (wParam != static_cast(scrollWidth))) { - lineWidthMaxSeen = 0; + view.lineWidthMaxSeen = 0; scrollWidth = static_cast(wParam); SetScrollBars(); } @@ -8336,6 +6272,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETCODEPAGE: return pdoc->dbcsCodePage; + case SCI_SETIMEINTERACTION: + imeInteraction = static_cast(wParam); + break; + + case SCI_GETIMEINTERACTION: + return imeInteraction; + #ifdef INCLUDE_DEPRECATED_FEATURES case SCI_SETUSEPALETTE: InvalidateStyleRedraw(); @@ -8374,7 +6317,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { RedrawSelMargin(); break; case SCI_MARKERENABLEHIGHLIGHT: - highlightDelimiter.isEnabled = wParam == 1; + marginView.highlightDelimiter.isEnabled = wParam == 1; RedrawSelMargin(); break; case SCI_MARKERSETBACK: @@ -9441,20 +7384,20 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return multiPasteMode; case SCI_SETADDITIONALCARETSBLINK: - additionalCaretsBlink = wParam != 0; + view.additionalCaretsBlink = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALCARETSBLINK: - return additionalCaretsBlink; + return view.additionalCaretsBlink; case SCI_SETADDITIONALCARETSVISIBLE: - additionalCaretsVisible = wParam != 0; + view.additionalCaretsVisible = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALCARETSVISIBLE: - return additionalCaretsVisible; + return view.additionalCaretsVisible; case SCI_GETSELECTIONS: return sel.Count(); diff --git a/src/stc/scintilla/src/Editor.h b/src/stc/scintilla/src/Editor.h index c7d44c16d6..27a2469aa6 100644 --- a/src/stc/scintilla/src/Editor.h +++ b/src/stc/scintilla/src/Editor.h @@ -12,17 +12,6 @@ namespace Scintilla { #endif -/** - */ -class Caret { -public: - bool active; - bool on; - int period; - - Caret(); -}; - /** */ class Timer { @@ -160,16 +149,9 @@ struct WrapPending { } }; -struct PrintParameters { - int magnification; - int colourMode; - WrapMode wrapState; - PrintParameters(); -}; - /** */ -class Editor : public DocWatcher { +class Editor : public EditModel, public DocWatcher { // Private so Editor objects can not be copied Editor(const Editor &); Editor &operator=(const Editor &); @@ -189,32 +171,17 @@ protected: // ScintillaBase subclass needs access to much of Editor Point sizeRGBAImage; float scaleRGBAImage; - PrintParameters printParameters; + MarginView marginView; + EditView view; int cursorMode; - // Highlight current folding block - HighlightDelimiter highlightDelimiter; - bool hasFocus; - bool hideSelection; - bool inOverstrike; - bool drawOverstrikeCaret; bool mouseDownCaptures; - /** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to - * the screen. This avoids flashing but is about 30% slower. */ - bool bufferedDraw; - /** In twoPhaseDraw mode, drawing is performed in two phases, first the background - * and then the foreground. This avoids chopping off characters that overlap the next run. */ - bool twoPhaseDraw; - - int xOffset; ///< Horizontal scrolled amount in pixels int xCaretMargin; ///< Ensure this many pixels visible on both sides of caret bool horizontalScrollBarVisible; int scrollWidth; - bool trackLineWidth; - int lineWidthMaxSeen; bool verticalScrollBarVisible; bool endAtLastLine; int caretSticky; @@ -223,25 +190,11 @@ protected: // ScintillaBase subclass needs access to much of Editor bool multipleSelection; bool additionalSelectionTyping; int multiPasteMode; - bool additionalCaretsBlink; - bool additionalCaretsVisible; int virtualSpaceOptions; - Surface *pixmapLine; - Surface *pixmapSelMargin; - Surface *pixmapSelPattern; - Surface *pixmapSelPatternOffset1; - Surface *pixmapIndentGuide; - Surface *pixmapIndentGuideHighlight; - - LineLayoutCache llc; - PositionCache posCache; - SpecialRepresentations reprs; - KeyMap kmap; - Caret caret; Timer timer; Timer autoScrollTimer; enum { autoScrollDelay = 200 }; @@ -250,6 +203,7 @@ protected: // ScintillaBase subclass needs access to much of Editor Point lastClick; unsigned int lastClickTime; + Point doubleClickCloseThreshold; int dwellDelay; int ticksToDwell; bool dwelling; @@ -257,7 +211,6 @@ protected: // ScintillaBase subclass needs access to much of Editor Point ptMouseLast; enum { ddNone, ddInitial, ddDragging } inDragDrop; bool dropWentOutside; - SelectionPosition posDrag; SelectionPosition posDrop; int hotSpotClickPos; int lastXChosen; @@ -274,9 +227,6 @@ protected: // ScintillaBase subclass needs access to much of Editor int lengthForEncode; int needUpdateUI; - Position braces[2]; - int bracesMatchStyle; - int highlightGuideColumn; enum { notPainting, painting, paintAbandoned } paintState; bool paintAbandonedByStyling; @@ -288,8 +238,6 @@ protected: // ScintillaBase subclass needs access to much of Editor int modEventMask; SelectionText drag; - Selection sel; - bool primarySelection; int caretXPolicy; int caretXSlop; ///< Ensure this many pixels visible on both sides of caret @@ -304,21 +252,13 @@ protected: // ScintillaBase subclass needs access to much of Editor bool recordingMacro; - int foldFlags; int foldAutomatic; - ContractionState cs; - - // Hotspot support - Range hotspot; // Wrapping support - int wrapWidth; WrapPending wrapPending; bool convertPastes; - Document *pdoc; - Editor(); virtual ~Editor(); virtual void Initialise() = 0; @@ -333,23 +273,23 @@ protected: // ScintillaBase subclass needs access to much of Editor // The top left visible point in main window coordinates. Will be 0,0 except for // scroll views where it will be equivalent to the current scroll position. - virtual Point GetVisibleOriginInMain(); - Point DocumentPointFromView(Point ptView); // Convert a point from view space to document + virtual Point GetVisibleOriginInMain() const; + Point DocumentPointFromView(Point ptView) const; // Convert a point from view space to document int TopLineOfMain() const; // Return the line at Main's y coordinate 0 - virtual PRectangle GetClientRectangle(); + virtual PRectangle GetClientRectangle() const; virtual PRectangle GetClientDrawingRectangle(); - PRectangle GetTextRectangle(); + PRectangle GetTextRectangle() const; - int LinesOnScreen(); - int LinesToScroll(); - int MaxScrollPos(); + virtual int LinesOnScreen() const; + int LinesToScroll() const; + int MaxScrollPos() const; SelectionPosition ClampPositionIntoDocument(SelectionPosition sp) const; Point LocationFromPosition(SelectionPosition pos); Point LocationFromPosition(int pos); int XFromPosition(int pos); int XFromPosition(SelectionPosition sp); SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true); - int PositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false); + int PositionFromLocation(Point pt, bool canReturnInvalid = false, bool charPosition = false); SelectionPosition SPositionFromLineX(int lineDoc, int x); int PositionFromLineX(int line, int x); int LineFromLocation(Point pt) const; @@ -360,7 +300,7 @@ protected: // ScintillaBase subclass needs access to much of Editor virtual void DiscardOverdraw(); virtual void Redraw(); void RedrawSelMargin(int line=-1, bool allAfter=false); - PRectangle RectangleFromRange(Range r); + PRectangle RectangleFromRange(Range r, int overlap); void InvalidateRange(int start, int end); bool UserVirtualSpace() const { @@ -383,8 +323,8 @@ protected: // ScintillaBase subclass needs access to much of Editor bool SelectionContainsProtected(); int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const; SelectionPosition MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd=true) const; - int MovePositionTo(SelectionPosition newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true); - int MovePositionTo(int newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true); + int MovePositionTo(SelectionPosition newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true); + int MovePositionTo(int newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true); SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir); SelectionPosition MovePositionSoVisible(int pos, int moveDir); Point PointMainCaret(); @@ -431,30 +371,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void LinesJoin(); void LinesSplit(int pixelWidth); - int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) const; void PaintSelMargin(Surface *surface, PRectangle &rc); - LineLayout *RetrieveLineLayout(int lineNumber); - void LayoutLine(int line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, - int width=LineLayout::wrapWidthInfinite); - ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main) const; - ColourDesired TextBackground(const ViewStyle &vsDraw, ColourOptional background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) const; - void DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight); - static void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); - void DrawEOL(Surface *surface, const ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, - int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, - ColourOptional background); - static void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, const ViewStyle &vsDraw, - int xStart, PRectangle rcLine, LineLayout *ll, int subLine); - void DrawIndicators(Surface *surface, const ViewStyle &vsDraw, int line, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under); - void DrawAnnotation(Surface *surface, const ViewStyle &vsDraw, int line, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine); - void DrawLine(Surface *surface, const ViewStyle &vsDraw, int line, int lineVisible, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine); - void DrawBlockCaret(Surface *surface, const ViewStyle &vsDraw, LineLayout *ll, int subLine, - int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) const; - void DrawCarets(Surface *surface, const ViewStyle &vsDraw, int line, int xStart, - PRectangle rcLine, LineLayout *ll, int subLine); void RefreshPixMaps(Surface *surfaceWindow); void Paint(Surface *surfaceWindow, PRectangle rcArea); long FormatRange(bool draw, Sci_RangeToFormat *pfr); @@ -470,7 +387,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void FilterSelections(); int InsertSpace(int position, unsigned int spaces); void AddChar(char ch); - virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); + virtual void AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS=false); void InsertPaste(const char *text, int len); enum PasteShape { pasteStream=0, pasteRectangular = 1, pasteLine = 2 }; void InsertPasteShape(const char *text, int len, PasteShape shape); @@ -487,7 +404,6 @@ protected: // ScintillaBase subclass needs access to much of Editor void SelectAll(); void Undo(); void Redo(); - void DelChar(); void DelCharBack(bool allowLineStartDeletion); virtual void ClaimSelection() = 0; @@ -530,7 +446,7 @@ protected: // ScintillaBase subclass needs access to much of Editor 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 PageMove(int direction, Selection::selTypes selt=Selection::noSel, bool stuttered = false); enum { cmSame, cmUpper, cmLower }; virtual std::string CaseMapString(const std::string &s, int caseMapping); void ChangeCaseOfSelection(int caseMapping); @@ -538,8 +454,8 @@ protected: // ScintillaBase subclass needs access to much of Editor void Duplicate(bool forLine); virtual void CancelModes(); void NewLine(); - void CursorUpOrDown(int direction, Selection::selTypes sel=Selection::noSel); - void ParaUpOrDown(int direction, Selection::selTypes sel=Selection::noSel); + void CursorUpOrDown(int direction, Selection::selTypes selt=Selection::noSel); + void ParaUpOrDown(int direction, Selection::selTypes selt=Selection::noSel); int StartEndDisplayLine(int pos, bool start); virtual int KeyCommand(unsigned int iMessage); virtual int KeyDefault(int /* key */, int /*modifiers*/); @@ -569,7 +485,7 @@ protected: // ScintillaBase subclass needs access to much of Editor /** PositionInSelection returns true if position in selection. */ bool PositionInSelection(int pos); bool PointInSelection(Point pt); - bool PointInSelMargin(Point pt); + bool PointInSelMargin(Point pt) const; Window::Cursor GetMarginCursor(Point pt) const; void TrimAndSetSelection(int currentPos_, int anchor_); void LineSelection(int lineCurrentPos_, int lineAnchorPos_, bool wholeLine); @@ -584,7 +500,13 @@ protected: // ScintillaBase subclass needs access to much of Editor void Tick(); bool Idle(); - virtual void SetTicking(bool on) = 0; + virtual void SetTicking(bool on); + enum TickReason { tickCaret, tickScroll, tickWiden, tickDwell, tickPlatform }; + virtual void TickFor(TickReason reason); + virtual bool FineTickerAvailable(); + virtual bool FineTickerRunning(TickReason reason); + virtual void FineTickerStart(TickReason reason, int millis, int tolerance); + virtual void FineTickerCancel(TickReason reason); virtual bool SetIdle(bool) { return false; } virtual void SetMouseCapture(bool on) = 0; virtual bool HaveMouseCapture() = 0; diff --git a/src/stc/scintilla/src/Indicator.h b/src/stc/scintilla/src/Indicator.h index beda8214b9..96cba3c054 100644 --- a/src/stc/scintilla/src/Indicator.h +++ b/src/stc/scintilla/src/Indicator.h @@ -17,11 +17,14 @@ namespace Scintilla { class Indicator { public: int style; - bool under; ColourDesired fore; + bool under; int fillAlpha; int outlineAlpha; - Indicator() : style(INDIC_PLAIN), under(false), fore(ColourDesired(0,0,0)), fillAlpha(30), outlineAlpha(50) { + Indicator() : style(INDIC_PLAIN), fore(ColourDesired(0,0,0)), under(false), fillAlpha(30), outlineAlpha(50) { + } + Indicator(int style_, ColourDesired fore_=ColourDesired(0,0,0), bool under_=false, int fillAlpha_=30, int outlineAlpha_=50) : + style(style_), fore(fore_), under(under_), fillAlpha(fillAlpha_), outlineAlpha(outlineAlpha_) { } void Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine) const; }; diff --git a/src/stc/scintilla/src/LineMarker.cxx b/src/stc/scintilla/src/LineMarker.cxx index 8ae815a653..98e75ca52e 100644 --- a/src/stc/scintilla/src/LineMarker.cxx +++ b/src/stc/scintilla/src/LineMarker.cxx @@ -72,23 +72,28 @@ static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, C } void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, typeOfFold tFold, int marginStyle) const { - ColourDesired head = back; - ColourDesired body = back; - ColourDesired tail = back; + if (customDraw != NULL) { + customDraw(surface, rcWhole, fontForCharacter, tFold, marginStyle, this); + return; + } + + ColourDesired colourHead = back; + ColourDesired colourBody = back; + ColourDesired colourTail = back; switch (tFold) { case LineMarker::head : case LineMarker::headWithTail : - head = backSelected; - tail = backSelected; + colourHead = backSelected; + colourTail = backSelected; break; case LineMarker::body : - head = backSelected; - body = backSelected; + colourHead = backSelected; + colourBody = backSelected; break; case LineMarker::tail : - body = backSelected; - tail = backSelected; + colourBody = backSelected; + colourTail = backSelected; break; default : // LineMarker::undefined @@ -192,69 +197,69 @@ void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharac // An invisible marker so don't draw anything } else if (markType == SC_MARK_VLINE) { - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, static_cast(rcWhole.bottom)); } else if (markType == SC_MARK_LCORNER) { - surface->PenColour(tail); + surface->PenColour(colourTail); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY); surface->LineTo(static_cast(rc.right) - 1, centreY); } else if (markType == SC_MARK_TCORNER) { - surface->PenColour(tail); + surface->PenColour(colourTail); surface->MoveTo(centreX, centreY); surface->LineTo(static_cast(rc.right) - 1, centreY); - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY + 1); - surface->PenColour(head); + surface->PenColour(colourHead); surface->LineTo(centreX, static_cast(rcWhole.bottom)); } else if (markType == SC_MARK_LCORNERCURVE) { - surface->PenColour(tail); + surface->PenColour(colourTail); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY-3); surface->LineTo(centreX+3, centreY); surface->LineTo(static_cast(rc.right) - 1, centreY); } else if (markType == SC_MARK_TCORNERCURVE) { - surface->PenColour(tail); + surface->PenColour(colourTail); surface->MoveTo(centreX, centreY-3); surface->LineTo(centreX+3, centreY); surface->LineTo(static_cast(rc.right) - 1, centreY); - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY-2); - surface->PenColour(head); + surface->PenColour(colourHead); surface->LineTo(centreX, static_cast(rcWhole.bottom)); } else if (markType == SC_MARK_BOXPLUS) { - DrawBox(surface, centreX, centreY, blobSize, fore, head); - DrawPlus(surface, centreX, centreY, blobSize, tail); + DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); + DrawPlus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_BOXPLUSCONNECTED) { if (tFold == LineMarker::headWithTail) - surface->PenColour(tail); + surface->PenColour(colourTail); else - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, static_cast(rcWhole.bottom)); - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY - blobSize); - DrawBox(surface, centreX, centreY, blobSize, fore, head); - DrawPlus(surface, centreX, centreY, blobSize, tail); + DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); + DrawPlus(surface, centreX, centreY, blobSize, colourTail); if (tFold == LineMarker::body) { - surface->PenColour(tail); + surface->PenColour(colourTail); surface->MoveTo(centreX + 1, centreY + blobSize); surface->LineTo(centreX + blobSize + 1, centreY + blobSize); @@ -265,27 +270,27 @@ void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharac surface->LineTo(centreX + blobSize + 1, centreY - blobSize); } } else if (markType == SC_MARK_BOXMINUS) { - DrawBox(surface, centreX, centreY, blobSize, fore, head); - DrawMinus(surface, centreX, centreY, blobSize, tail); + DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); + DrawMinus(surface, centreX, centreY, blobSize, colourTail); - surface->PenColour(head); + surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, static_cast(rcWhole.bottom)); } else if (markType == SC_MARK_BOXMINUSCONNECTED) { - DrawBox(surface, centreX, centreY, blobSize, fore, head); - DrawMinus(surface, centreX, centreY, blobSize, tail); + DrawBox(surface, centreX, centreY, blobSize, fore, colourHead); + DrawMinus(surface, centreX, centreY, blobSize, colourTail); - surface->PenColour(head); + surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, static_cast(rcWhole.bottom)); - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY - blobSize); if (tFold == LineMarker::body) { - surface->PenColour(tail); + surface->PenColour(colourTail); surface->MoveTo(centreX + 1, centreY + blobSize); surface->LineTo(centreX + blobSize + 1, centreY + blobSize); @@ -296,43 +301,43 @@ void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharac surface->LineTo(centreX + blobSize + 1, centreY - blobSize); } } else if (markType == SC_MARK_CIRCLEPLUS) { - DrawCircle(surface, centreX, centreY, blobSize, fore, head); - DrawPlus(surface, centreX, centreY, blobSize, tail); + DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); + DrawPlus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) { if (tFold == LineMarker::headWithTail) - surface->PenColour(tail); + surface->PenColour(colourTail); else - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, static_cast(rcWhole.bottom)); - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY - blobSize); - DrawCircle(surface, centreX, centreY, blobSize, fore, head); - DrawPlus(surface, centreX, centreY, blobSize, tail); + DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); + DrawPlus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_CIRCLEMINUS) { - surface->PenColour(head); + surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, static_cast(rcWhole.bottom)); - DrawCircle(surface, centreX, centreY, blobSize, fore, head); - DrawMinus(surface, centreX, centreY, blobSize, tail); + DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); + DrawMinus(surface, centreX, centreY, blobSize, colourTail); } else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) { - surface->PenColour(head); + surface->PenColour(colourHead); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, static_cast(rcWhole.bottom)); - surface->PenColour(body); + surface->PenColour(colourBody); surface->MoveTo(centreX, static_cast(rcWhole.top)); surface->LineTo(centreX, centreY - blobSize); - DrawCircle(surface, centreX, centreY, blobSize, fore, head); - DrawMinus(surface, centreX, centreY, blobSize, tail); + DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead); + DrawMinus(surface, centreX, centreY, blobSize, colourTail); } else if (markType >= SC_MARK_CHARACTER) { char character[1]; diff --git a/src/stc/scintilla/src/LineMarker.h b/src/stc/scintilla/src/LineMarker.h index 4004a8a427..6a5fe74924 100644 --- a/src/stc/scintilla/src/LineMarker.h +++ b/src/stc/scintilla/src/LineMarker.h @@ -12,6 +12,8 @@ namespace Scintilla { #endif +typedef void (*DrawLineMarkerFn)(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, int tFold, int marginStyle, const void *lineMarker); + /** */ class LineMarker { @@ -25,6 +27,11 @@ public: int alpha; XPM *pxpm; RGBAImage *image; + /** Some platforms, notably PLAT_CURSES, do not support Scintilla's native + * Draw function for drawing line markers. Allow those platforms to override + * it instead of creating a new method(s) in the Surface class that existing + * platforms must implement as empty. */ + DrawLineMarkerFn customDraw; LineMarker() { markType = SC_MARK_CIRCLE; fore = ColourDesired(0,0,0); @@ -33,6 +40,7 @@ public: alpha = SC_ALPHA_NOALPHA; pxpm = NULL; image = NULL; + customDraw = NULL; } LineMarker(const LineMarker &) { // Defined to avoid pxpm being blindly copied, not as a complete copy constructor @@ -43,6 +51,7 @@ public: alpha = SC_ALPHA_NOALPHA; pxpm = NULL; image = NULL; + customDraw = NULL; } ~LineMarker() { delete pxpm; @@ -60,6 +69,7 @@ public: pxpm = NULL; delete image; image = NULL; + customDraw = NULL; } return *this; } diff --git a/src/stc/scintilla/src/MarginView.cxx b/src/stc/scintilla/src/MarginView.cxx new file mode 100644 index 0000000000..b7ef485138 --- /dev/null +++ b/src/stc/scintilla/src/MarginView.cxx @@ -0,0 +1,462 @@ +// Scintilla source code edit control +/** @file MarginView.cxx + ** Defines the appearance of the editor margin. + **/ +// Copyright 1998-2014 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +void DrawWrapMarker(Surface *surface, PRectangle rcPlace, + bool isEndMarker, ColourDesired wrapColour) { + surface->PenColour(wrapColour); + + enum { xa = 1 }; // gap before start + int w = static_cast(rcPlace.right - rcPlace.left) - xa - 1; + + bool xStraight = isEndMarker; // x-mirrored symbol for start marker + + int x0 = static_cast(xStraight ? rcPlace.left : rcPlace.right - 1); + int y0 = static_cast(rcPlace.top); + + int dy = static_cast(rcPlace.bottom - rcPlace.top) / 5; + int y = static_cast(rcPlace.bottom - rcPlace.top) / 2 + dy; + + struct Relative { + Surface *surface; + int xBase; + int xDir; + int yBase; + int yDir; + void MoveTo(int xRelative, int yRelative) { + surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); + } + void LineTo(int xRelative, int yRelative) { + surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); + } + }; + Relative rel = { surface, x0, xStraight ? 1 : -1, y0, 1 }; + + // arrow head + rel.MoveTo(xa, y); + rel.LineTo(xa + 2 * w / 3, y - dy); + rel.MoveTo(xa, y); + rel.LineTo(xa + 2 * w / 3, y + dy); + + // arrow body + rel.MoveTo(xa, y); + rel.LineTo(xa + w, y); + rel.LineTo(xa + w, y - 2 * dy); + rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... + y - 2 * dy); +} + +MarginView::MarginView() { + pixmapSelMargin = 0; + pixmapSelPattern = 0; + pixmapSelPatternOffset1 = 0; + wrapMarkerPaddingRight = 3; + customDrawWrapMarker = NULL; +} + +void MarginView::DropGraphics(bool freeObjects) { + if (freeObjects) { + delete pixmapSelMargin; + pixmapSelMargin = 0; + delete pixmapSelPattern; + pixmapSelPattern = 0; + delete pixmapSelPatternOffset1; + pixmapSelPatternOffset1 = 0; + } else { + if (pixmapSelMargin) + pixmapSelMargin->Release(); + if (pixmapSelPattern) + pixmapSelPattern->Release(); + if (pixmapSelPatternOffset1) + pixmapSelPatternOffset1->Release(); + } +} + +void MarginView::AllocateGraphics(const ViewStyle &vsDraw) { + if (!pixmapSelMargin) + pixmapSelMargin = Surface::Allocate(vsDraw.technology); + if (!pixmapSelPattern) + pixmapSelPattern = Surface::Allocate(vsDraw.technology); + if (!pixmapSelPatternOffset1) + pixmapSelPatternOffset1 = Surface::Allocate(vsDraw.technology); +} + +void MarginView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { + if (!pixmapSelPattern->Initialised()) { + const int patternSize = 8; + pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wid); + pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wid); + // This complex procedure is to reproduce the checkerboard dithered pattern used by windows + // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half + // way between the chrome colour and the chrome highlight colour making a nice transition + // between the window chrome and the content area. And it works in low colour depths. + PRectangle rcPattern = PRectangle::FromInts(0, 0, patternSize, patternSize); + + // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. + ColourDesired colourFMFill = vsDraw.selbar; + ColourDesired colourFMStripes = vsDraw.selbarlight; + + if (!(vsDraw.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { + // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. + // (Typically, the highlight colour is white.) + colourFMFill = vsDraw.selbarlight; + } + + if (vsDraw.foldmarginColour.isSet) { + // override default fold margin colour + colourFMFill = vsDraw.foldmarginColour; + } + if (vsDraw.foldmarginHighlightColour.isSet) { + // override default fold margin highlight colour + colourFMStripes = vsDraw.foldmarginHighlightColour; + } + + pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); + pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes); + for (int y = 0; y < patternSize; y++) { + for (int x = y % 2; x < patternSize; x += 2) { + PRectangle rcPixel = PRectangle::FromInts(x, y, x + 1, y + 1); + pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); + pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill); + } + } + } +} + +static int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault, const ViewStyle &vs) { + if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) + return markerDefault; + return markerCheck; +} + +void MarginView::PaintMargin(Surface *surface, int topLine, PRectangle rc, PRectangle rcMargin, + const EditModel &model, const ViewStyle &vs) { + + PRectangle rcSelMargin = rcMargin; + rcSelMargin.right = rcMargin.left; + if (rcSelMargin.bottom < rc.bottom) + rcSelMargin.bottom = rc.bottom; + + Point ptOrigin = model.GetVisibleOriginInMain(); + FontAlias fontLineNumber = vs.styles[STYLE_LINENUMBER].font; + for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) { + if (vs.ms[margin].width > 0) { + + rcSelMargin.left = rcSelMargin.right; + rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; + + if (vs.ms[margin].style != SC_MARGIN_NUMBER) { + if (vs.ms[margin].mask & SC_MASK_FOLDERS) { + // Required because of special way brush is created for selection margin + // Ensure patterns line up when scrolling with separate margin view + // by choosing correctly aligned variant. + bool invertPhase = static_cast(ptOrigin.y) & 1; + surface->FillRectangle(rcSelMargin, + invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); + } else { + ColourDesired colour; + switch (vs.ms[margin].style) { + case SC_MARGIN_BACK: + colour = vs.styles[STYLE_DEFAULT].back; + break; + case SC_MARGIN_FORE: + colour = vs.styles[STYLE_DEFAULT].fore; + break; + default: + colour = vs.styles[STYLE_LINENUMBER].back; + break; + } + surface->FillRectangle(rcSelMargin, colour); + } + } else { + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back); + } + + const int lineStartPaint = static_cast(rcMargin.top + ptOrigin.y) / vs.lineHeight; + int visibleLine = model.TopLineOfMain() + lineStartPaint; + int yposScreen = lineStartPaint * vs.lineHeight - static_cast(ptOrigin.y); + // Work out whether the top line is whitespace located after a + // lessening of fold level which implies a 'fold tail' but which should not + // be displayed until the last of a sequence of whitespace. + bool needWhiteClosure = false; + if (vs.ms[margin].mask & SC_MASK_FOLDERS) { + int level = model.pdoc->GetLevel(model.cs.DocFromDisplay(visibleLine)); + if (level & SC_FOLDLEVELWHITEFLAG) { + int lineBack = model.cs.DocFromDisplay(visibleLine); + int levelPrev = level; + while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { + lineBack--; + levelPrev = model.pdoc->GetLevel(lineBack); + } + if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { + if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK)) + needWhiteClosure = true; + } + } + if (highlightDelimiter.isEnabled) { + int lastLine = model.cs.DocFromDisplay(topLine + model.LinesOnScreen()) + 1; + model.pdoc->GetHighlightDelimiters(highlightDelimiter, model.pdoc->LineFromPosition(model.sel.MainCaret()), lastLine); + } + } + + // Old code does not know about new markers needed to distinguish all cases + const int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, + SC_MARKNUM_FOLDEROPEN, vs); + const int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND, + SC_MARKNUM_FOLDER, vs); + + while ((visibleLine < model.cs.LinesDisplayed()) && yposScreen < rc.bottom) { + + PLATFORM_ASSERT(visibleLine < model.cs.LinesDisplayed()); + const int lineDoc = model.cs.DocFromDisplay(visibleLine); + PLATFORM_ASSERT(model.cs.GetVisible(lineDoc)); + const bool firstSubLine = visibleLine == model.cs.DisplayFromDoc(lineDoc); + const bool lastSubLine = visibleLine == model.cs.DisplayLastFromDoc(lineDoc); + + int marks = model.pdoc->GetMark(lineDoc); + if (!firstSubLine) + marks = 0; + + bool headWithTail = false; + + if (vs.ms[margin].mask & SC_MASK_FOLDERS) { + // Decide which fold indicator should be displayed + const int level = model.pdoc->GetLevel(lineDoc); + const int levelNext = model.pdoc->GetLevel(lineDoc + 1); + const int levelNum = level & SC_FOLDLEVELNUMBERMASK; + const int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK; + if (level & SC_FOLDLEVELHEADERFLAG) { + if (firstSubLine) { + if (levelNum < levelNextNum) { + if (model.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 { + if (levelNum < levelNextNum) { + if (model.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; + const int firstFollowupLine = model.cs.DocFromDisplay(model.cs.DisplayFromDoc(lineDoc + 1)); + const int firstFollowupLineLevel = model.pdoc->GetLevel(firstFollowupLine); + const int secondFollowupLineLevelNum = model.pdoc->GetLevel(firstFollowupLine + 1) & SC_FOLDLEVELNUMBERMASK; + if (!model.cs.GetExpanded(lineDoc)) { + if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) && + (levelNum > secondFollowupLineLevelNum)) + needWhiteClosure = true; + + if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) + headWithTail = true; + } + } else if (level & SC_FOLDLEVELWHITEFLAG) { + if (needWhiteClosure) { + if (levelNext & SC_FOLDLEVELWHITEFLAG) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } else if (levelNextNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + needWhiteClosure = false; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + needWhiteClosure = false; + } + } else if (levelNum > SC_FOLDLEVELBASE) { + if (levelNextNum < levelNum) { + if (levelNextNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + } + } else { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + } + } else if (levelNum > SC_FOLDLEVELBASE) { + if (levelNextNum < levelNum) { + needWhiteClosure = false; + if (levelNext & SC_FOLDLEVELWHITEFLAG) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + needWhiteClosure = true; + } else if (lastSubLine) { + if (levelNextNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + } + } else { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + } else { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + } + } + + marks &= vs.ms[margin].mask; + + PRectangle rcMarker = rcSelMargin; + rcMarker.top = static_cast(yposScreen); + rcMarker.bottom = static_cast(yposScreen + vs.lineHeight); + if (vs.ms[margin].style == SC_MARGIN_NUMBER) { + if (firstSubLine) { + char number[100] = ""; + if (lineDoc >= 0) + sprintf(number, "%d", lineDoc + 1); + if (model.foldFlags & (SC_FOLDFLAG_LEVELNUMBERS | SC_FOLDFLAG_LINESTATE)) { + if (model.foldFlags & SC_FOLDFLAG_LEVELNUMBERS) { + int lev = model.pdoc->GetLevel(lineDoc); + sprintf(number, "%c%c %03X %03X", + (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_', + (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_', + lev & SC_FOLDLEVELNUMBERMASK, + lev >> 16 + ); + } else { + int state = model.pdoc->GetLineState(lineDoc); + sprintf(number, "%0X", state); + } + } + PRectangle rcNumber = rcMarker; + // Right justify + XYPOSITION width = surface->WidthText(fontLineNumber, number, static_cast(strlen(number))); + XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; + rcNumber.left = xpos; + DrawTextNoClipPhase(surface, rcNumber, vs.styles[STYLE_LINENUMBER], + rcNumber.top + vs.maxAscent, number, static_cast(strlen(number)), drawAll); + } else if (vs.wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) { + PRectangle rcWrapMarker = rcMarker; + rcWrapMarker.right -= wrapMarkerPaddingRight; + rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth; + if (customDrawWrapMarker == NULL) { + DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); + } else { + customDrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); + } + } + } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { + if (firstSubLine) { + const StyledText stMargin = model.pdoc->MarginStyledText(lineDoc); + if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { + surface->FillRectangle(rcMarker, + vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); + if (vs.ms[margin].style == SC_MARGIN_RTEXT) { + int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); + rcMarker.left = rcMarker.right - width - 3; + } + DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, + stMargin, 0, stMargin.length, drawAll); + } + } + } + + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + LineMarker::typeOfFold tFold = LineMarker::undefined; + if ((vs.ms[margin].mask & SC_MASK_FOLDERS) && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { + if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { + tFold = LineMarker::body; + } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { + if (firstSubLine) { + tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head; + } else { + if (model.cs.GetExpanded(lineDoc) || headWithTail) { + tFold = LineMarker::body; + } else { + tFold = LineMarker::undefined; + } + } + } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { + tFold = LineMarker::tail; + } + } + vs.markers[markBit].Draw(surface, rcMarker, fontLineNumber, tFold, vs.ms[margin].style); + } + marks >>= 1; + } + } + + visibleLine++; + yposScreen += vs.lineHeight; + } + } + } + + PRectangle rcBlankMargin = rcMargin; + rcBlankMargin.left = rcSelMargin.right; + surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back); +} + +#ifdef SCI_NAMESPACE +} +#endif + diff --git a/src/stc/scintilla/src/MarginView.h b/src/stc/scintilla/src/MarginView.h new file mode 100644 index 0000000000..ff55646767 --- /dev/null +++ b/src/stc/scintilla/src/MarginView.h @@ -0,0 +1,50 @@ +// Scintilla source code edit control +/** @file MarginView.h + ** Defines the appearance of the editor margin. + **/ +// Copyright 1998-2014 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef MARGINVIEW_H +#define MARGINVIEW_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); + +typedef void (*DrawWrapMarkerFn)(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); + +/** +* MarginView draws the margins. +*/ +class MarginView { +public: + Surface *pixmapSelMargin; + Surface *pixmapSelPattern; + Surface *pixmapSelPatternOffset1; + // Highlight current folding block + HighlightDelimiter highlightDelimiter; + + int wrapMarkerPaddingRight; // right-most pixel padding of wrap markers + /** Some platforms, notably PLAT_CURSES, do not support Scintilla's native + * DrawWrapMarker function for drawing wrap markers. Allow those platforms to + * override it instead of creating a new method in the Surface class that + * existing platforms must implement as empty. */ + DrawWrapMarkerFn customDrawWrapMarker; + + MarginView(); + + void DropGraphics(bool freeObjects); + void AllocateGraphics(const ViewStyle &vsDraw); + void RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw); + void PaintMargin(Surface *surface, int topLine, PRectangle rc, PRectangle rcMargin, + const EditModel &model, const ViewStyle &vs); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/src/stc/scintilla/src/PerLine.cxx b/src/stc/scintilla/src/PerLine.cxx index 8b0dbc44b7..8fd96cbedf 100644 --- a/src/stc/scintilla/src/PerLine.cxx +++ b/src/stc/scintilla/src/PerLine.cxx @@ -7,6 +7,7 @@ #include +#include #include #include "Platform.h" @@ -484,3 +485,72 @@ int LineAnnotation::Lines(int line) const { else return 0; } + +LineTabstops::~LineTabstops() { + Init(); +} + +void LineTabstops::Init() { + for (int line = 0; line < tabstops.Length(); line++) { + delete tabstops[line]; + } + tabstops.DeleteAll(); +} + +void LineTabstops::InsertLine(int line) { + if (tabstops.Length()) { + tabstops.EnsureLength(line); + tabstops.Insert(line, 0); + } +} + +void LineTabstops::RemoveLine(int line) { + if (tabstops.Length() > line) { + delete tabstops[line]; + tabstops.Delete(line); + } +} + +bool LineTabstops::ClearTabstops(int line) { + if (line < tabstops.Length()) { + TabstopList *tl = tabstops[line]; + if (tl) { + tl->clear(); + return true; + } + } + return false; +} + +bool LineTabstops::AddTabstop(int line, int x) { + tabstops.EnsureLength(line + 1); + if (!tabstops[line]) { + tabstops[line] = new TabstopList(); + } + + TabstopList *tl = tabstops[line]; + if (tl) { + // tabstop positions are kept in order - insert in the right place + std::vector::iterator it = std::lower_bound(tl->begin(), tl->end(), x); + // don't insert duplicates + if (it == tl->end() || *it != x) { + tl->insert(it, x); + return true; + } + } + return false; +} + +int LineTabstops::GetNextTabstop(int line, int x) const { + if (line < tabstops.Length()) { + TabstopList *tl = tabstops[line]; + if (tl) { + for (size_t i = 0; i < tl->size(); i++) { + if ((*tl)[i] > x) { + return (*tl)[i]; + } + } + } + } + return 0; +} diff --git a/src/stc/scintilla/src/PerLine.h b/src/stc/scintilla/src/PerLine.h index 70d0023e40..4bf1c88fdd 100644 --- a/src/stc/scintilla/src/PerLine.h +++ b/src/stc/scintilla/src/PerLine.h @@ -112,6 +112,23 @@ public: int Lines(int line) const; }; +typedef std::vector TabstopList; + +class LineTabstops : public PerLine { + SplitVector tabstops; +public: + LineTabstops() { + } + virtual ~LineTabstops(); + virtual void Init(); + virtual void InsertLine(int line); + virtual void RemoveLine(int line); + + bool ClearTabstops(int line); + bool AddTabstop(int line, int x); + int GetNextTabstop(int line, int x) const; +}; + #ifdef SCI_NAMESPACE } #endif diff --git a/src/stc/scintilla/src/PositionCache.cxx b/src/stc/scintilla/src/PositionCache.cxx index 9e55c1a82f..6663995036 100644 --- a/src/stc/scintilla/src/PositionCache.cxx +++ b/src/stc/scintilla/src/PositionCache.cxx @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -438,13 +439,12 @@ void BreakFinder::Insert(int val) { } } -BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, int lineStart_, int lineEnd_, int posLineStart_, +BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, Range lineRange_, int posLineStart_, int xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_) : ll(ll_), - lineStart(lineStart_), - lineEnd(lineEnd_), + lineRange(lineRange_), posLineStart(posLineStart_), - nextBreak(lineStart_), + nextBreak(lineRange_.start), saeCurrentPos(0), saeNext(0), subBreak(-1), @@ -455,15 +455,15 @@ BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, int lineS // Search for first visible break // First find the first visible character if (xStart > 0.0f) - nextBreak = ll->FindBefore(static_cast(xStart), lineStart, lineEnd); + nextBreak = ll->FindBefore(static_cast(xStart), lineRange.start, lineRange.end); // Now back to a style break - while ((nextBreak > lineStart) && (ll->styles[nextBreak] == ll->styles[nextBreak - 1])) { + while ((nextBreak > lineRange.start) && (ll->styles[nextBreak] == ll->styles[nextBreak - 1])) { nextBreak--; } if (breakForSelection) { SelectionPosition posStart(posLineStart); - SelectionPosition posEnd(posLineStart + lineEnd); + SelectionPosition posEnd(posLineStart + lineRange.end); SelectionSegment segmentLine(posStart, posEnd); for (size_t r=0; rCount(); r++) { SelectionSegment portion = psel->Range(r).Intersect(segmentLine); @@ -477,7 +477,7 @@ BreakFinder::BreakFinder(const LineLayout *ll_, const Selection *psel, int lineS } Insert(ll->edgeColumn); - Insert(lineEnd); + Insert(lineRange.end); saeNext = (!selAndEdge.empty()) ? selAndEdge[0] : -1; } @@ -487,19 +487,19 @@ BreakFinder::~BreakFinder() { TextSegment BreakFinder::Next() { if (subBreak == -1) { int prev = nextBreak; - while (nextBreak < lineEnd) { + while (nextBreak < lineRange.end) { int charWidth = 1; if (encodingFamily == efUnicode) - charWidth = UTF8DrawBytes(reinterpret_cast(ll->chars) + nextBreak, lineEnd - nextBreak); + charWidth = UTF8DrawBytes(reinterpret_cast(ll->chars) + nextBreak, lineRange.end - nextBreak); else if (encodingFamily == efDBCS) charWidth = pdoc->IsDBCSLeadByte(ll->chars[nextBreak]) ? 2 : 1; const Representation *repr = preprs->RepresentationFromCharacter(ll->chars + nextBreak, charWidth); if (((nextBreak > 0) && (ll->styles[nextBreak] != ll->styles[nextBreak - 1])) || repr || (nextBreak == saeNext)) { - while ((nextBreak >= saeNext) && (saeNext < lineEnd)) { + while ((nextBreak >= saeNext) && (saeNext < lineRange.end)) { saeCurrentPos++; - saeNext = (saeCurrentPos < selAndEdge.size()) ? selAndEdge[saeCurrentPos] : lineEnd; + saeNext = (saeCurrentPos < selAndEdge.size()) ? selAndEdge[saeCurrentPos] : lineRange.end; } if ((nextBreak > prev) || repr) { // Have a segment to report @@ -540,7 +540,7 @@ TextSegment BreakFinder::Next() { } bool BreakFinder::More() const { - return (subBreak >= 0) || (nextBreak < lineEnd); + return (subBreak >= 0) || (nextBreak < lineRange.end); } PositionCacheEntry::PositionCacheEntry() : diff --git a/src/stc/scintilla/src/PositionCache.h b/src/stc/scintilla/src/PositionCache.h index 05005e9ac6..9d9821f8fa 100644 --- a/src/stc/scintilla/src/PositionCache.h +++ b/src/stc/scintilla/src/PositionCache.h @@ -104,7 +104,7 @@ class PositionCacheEntry { public: PositionCacheEntry(); ~PositionCacheEntry(); - void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock); + void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock_); void Clear(); bool Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_) const; static unsigned int Hash(unsigned int styleNumber_, const char *s, unsigned int len); @@ -148,8 +148,7 @@ struct TextSegment { // Class to break a line of text into shorter runs at sensible places. class BreakFinder { const LineLayout *ll; - int lineStart; - int lineEnd; + Range lineRange; int posLineStart; int nextBreak; std::vector selAndEdge; @@ -168,7 +167,7 @@ public: enum { lengthStartSubdivision = 300 }; // Try to make each subdivided run lengthEachSubdivision or shorter. enum { lengthEachSubdivision = 100 }; - BreakFinder(const LineLayout *ll_, const Selection *psel, int lineStart_, int lineEnd_, int posLineStart_, + BreakFinder(const LineLayout *ll_, const Selection *psel, Range rangeLine_, int posLineStart_, int xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_); ~BreakFinder(); TextSegment Next(); diff --git a/src/stc/scintilla/src/RESearch.cxx b/src/stc/scintilla/src/RESearch.cxx index 74db013559..dbf1423e78 100644 --- a/src/stc/scintilla/src/RESearch.cxx +++ b/src/stc/scintilla/src/RESearch.cxx @@ -203,6 +203,7 @@ #include #include +#include #include "CharClassify.h" #include "RESearch.h" @@ -251,22 +252,18 @@ const char bitarr[] = { 1, 2, 4, 8, 16, 32, 64, '\200' }; RESearch::RESearch(CharClassify *charClassTable) { failure = 0; charClass = charClassTable; - Init(); + sta = NOP; /* status of lastpat */ + bol = 0; + std::fill(bittab, bittab + BITBLK, 0); + std::fill(tagstk, tagstk + MAXTAG, 0); + std::fill(nfa, nfa + MAXNFA, 0); + Clear(); } RESearch::~RESearch() { Clear(); } -void RESearch::Init() { - sta = NOP; /* status of lastpat */ - bol = 0; - for (int i = 0; i < MAXTAG; i++) - pat[i].clear(); - for (int j = 0; j < BITBLK; j++) - bittab[j] = 0; -} - void RESearch::Clear() { for (int i = 0; i < MAXTAG; i++) { pat[i].clear(); @@ -279,10 +276,9 @@ void RESearch::GrabMatches(CharacterIndexer &ci) { for (unsigned int i = 0; i < MAXTAG; i++) { if ((bopat[i] != NOTFOUND) && (eopat[i] != NOTFOUND)) { unsigned int len = eopat[i] - bopat[i]; - pat[i] = std::string(len+1, '\0'); + pat[i].resize(len); for (unsigned int j = 0; j < len; j++) pat[i][j] = ci.CharAt(bopat[i] + j); - pat[i][len] = '\0'; } } } diff --git a/src/stc/scintilla/src/RESearch.h b/src/stc/scintilla/src/RESearch.h index 48533a41c1..3a7f0e4d61 100644 --- a/src/stc/scintilla/src/RESearch.h +++ b/src/stc/scintilla/src/RESearch.h @@ -33,6 +33,7 @@ class RESearch { public: explicit RESearch(CharClassify *charClassTable); ~RESearch(); + void Clear(); void GrabMatches(CharacterIndexer &ci); const char *Compile(const char *pattern, int length, bool caseSensitive, bool posix); int Execute(CharacterIndexer &ci, int lp, int endp); @@ -46,8 +47,6 @@ public: std::string pat[MAXTAG]; private: - void Init(); - void Clear(); void ChSet(unsigned char c); void ChSetWithCase(unsigned char c, bool caseSensitive); int GetBackslashExpression(const char *pattern, int &incr); diff --git a/src/stc/scintilla/src/ScintillaBase.cxx b/src/stc/scintilla/src/ScintillaBase.cxx index d42dfc7ff6..f9d70ce537 100644 --- a/src/stc/scintilla/src/ScintillaBase.cxx +++ b/src/stc/scintilla/src/ScintillaBase.cxx @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,9 @@ #include "Document.h" #include "Selection.h" #include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" #include "Editor.h" #include "AutoComplete.h" #include "ScintillaBase.h" @@ -73,7 +77,7 @@ void ScintillaBase::Finalise() { popup.Destroy(); } -void ScintillaBase::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { +void ScintillaBase::AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS) { bool isFillUp = ac.Active() && ac.IsFillUpChar(*s); if (!isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); diff --git a/src/stc/scintilla/src/ScintillaBase.h b/src/stc/scintilla/src/ScintillaBase.h index 8440ebecc9..668abed3cd 100644 --- a/src/stc/scintilla/src/ScintillaBase.h +++ b/src/stc/scintilla/src/ScintillaBase.h @@ -38,6 +38,8 @@ protected: idcmdSelectAll=16 }; + enum { maxLenInputIME = 200 }; + bool displayPopupMenu; Menu popup; AutoComplete ac; @@ -60,7 +62,7 @@ protected: virtual void Initialise() = 0; virtual void Finalise(); - virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); + virtual void AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS=false); void Command(int cmdId); virtual void CancelModes(); virtual int KeyCommand(unsigned int iMessage); diff --git a/src/stc/scintilla/src/Selection.cxx b/src/stc/scintilla/src/Selection.cxx index b46dca890d..52ed5774eb 100644 --- a/src/stc/scintilla/src/Selection.cxx +++ b/src/stc/scintilla/src/Selection.cxx @@ -81,6 +81,11 @@ int SelectionRange::Length() const { } } +void SelectionRange::MoveForInsertDelete(bool insertion, int startChange, int length) { + caret.MoveForInsertDelete(insertion, startChange, length); + anchor.MoveForInsertDelete(insertion, startChange, length); +} + bool SelectionRange::Contains(int pos) const { if (anchor > caret) return (pos >= caret.Position()) && (pos <= anchor.Position()); @@ -283,9 +288,11 @@ int Selection::Length() const { void Selection::MovePositions(bool insertion, int startChange, int length) { for (size_t i=0; i(s); + unsigned int i=0; + while ((i= 1) && (ch < 0x80 + 0x40 + 0x20)) { + value = (ch & 0x1F) << 6; + ch = us[i++]; + value += ch & 0x7F; + } else if (((len-i) >= 2) && (ch < 0x80 + 0x40 + 0x20 + 0x10)) { + value = (ch & 0xF) << 12; + ch = us[i++]; + value += (ch & 0x7F) << 6; + ch = us[i++]; + value += ch & 0x7F; + } else if ((len-i) >= 3) { + value = (ch & 0x7) << 18; + ch = us[i++]; + value += (ch & 0x3F) << 12; + ch = us[i++]; + value += (ch & 0x3F) << 6; + ch = us[i++]; + value += ch & 0x3F; + } + tbuf[ui] = value; + ui++; + } + return ui; +} + +unsigned int UTF16FromUTF32Character(unsigned int val, wchar_t *tbuf) { + if (val < SUPPLEMENTAL_PLANE_FIRST) { + tbuf[0] = static_cast(val); + return 1; + } else { + tbuf[0] = static_cast(((val - SUPPLEMENTAL_PLANE_FIRST) >> 10) + SURROGATE_LEAD_FIRST); + tbuf[1] = static_cast((val & 0x3ff) + SURROGATE_TRAIL_FIRST); + return 2; + } +} + int UTF8BytesOfLead[256]; static bool initialisedBytesOfLead = false; diff --git a/src/stc/scintilla/src/UniConversion.h b/src/stc/scintilla/src/UniConversion.h index 753490bab5..760f504760 100644 --- a/src/stc/scintilla/src/UniConversion.h +++ b/src/stc/scintilla/src/UniConversion.h @@ -14,11 +14,15 @@ namespace Scintilla { const int UTF8MaxBytes = 4; +const int unicodeReplacementChar = 0xFFFD; + unsigned int UTF8Length(const wchar_t *uptr, unsigned int tlen); void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len); unsigned int UTF8CharLength(unsigned char ch); unsigned int UTF16Length(const char *s, unsigned int len); unsigned int UTF16FromUTF8(const char *s, unsigned int len, wchar_t *tbuf, unsigned int tlen); +unsigned int UTF32FromUTF8(const char *s, unsigned int len, unsigned int *tbuf, unsigned int tlen); +unsigned int UTF16FromUTF32Character(unsigned int val, wchar_t *tbuf); extern int UTF8BytesOfLead[256]; void UTF8BytesOfLeadInitialise(); diff --git a/src/stc/scintilla/src/ViewStyle.cxx b/src/stc/scintilla/src/ViewStyle.cxx index 2983bb0c0f..b60905caff 100644 --- a/src/stc/scintilla/src/ViewStyle.cxx +++ b/src/stc/scintilla/src/ViewStyle.cxx @@ -192,18 +192,13 @@ void ViewStyle::Init(size_t stylesSize_) { // There are no image markers by default, so no need for calling CalcLargestMarkerHeight() largestMarkerHeight = 0; - indicators[0].style = INDIC_SQUIGGLE; - indicators[0].under = false; - indicators[0].fore = ColourDesired(0, 0x7f, 0); - indicators[1].style = INDIC_TT; - indicators[1].under = false; - indicators[1].fore = ColourDesired(0, 0, 0xff); - indicators[2].style = INDIC_PLAIN; - indicators[2].under = false; - indicators[2].fore = ColourDesired(0xff, 0, 0); + indicators[0] = Indicator(INDIC_SQUIGGLE, ColourDesired(0, 0x7f, 0)); + indicators[1] = Indicator(INDIC_TT, ColourDesired(0, 0, 0xff)); + indicators[2] = Indicator(INDIC_PLAIN, ColourDesired(0xff, 0, 0)); technology = SC_TECHNOLOGY_DEFAULT; lineHeight = 1; + lineOverlap = 0; maxAscent = 1; maxDescent = 1; aveCharWidth = 8; @@ -329,6 +324,11 @@ void ViewStyle::Refresh(Surface &surface, int tabInChars) { maxAscent += extraAscent; maxDescent += extraDescent; lineHeight = maxAscent + maxDescent; + lineOverlap = lineHeight / 10; + if (lineOverlap < 2) + lineOverlap = 2; + if (lineOverlap > lineHeight) + lineOverlap = lineHeight; someStylesProtected = false; someStylesForceCase = false; @@ -470,6 +470,14 @@ ColourOptional ViewStyle::Background(int marksOfLine, bool caretActive, bool lin return background; } +bool ViewStyle::SelectionBackgroundDrawn() const { + return selColours.back.isSet && + ((selAlpha == SC_ALPHA_NOALPHA) || (selAdditionalAlpha == SC_ALPHA_NOALPHA)); +} + +bool ViewStyle::WhitespaceBackgroundDrawn() const { + return (viewWhitespace != wsInvisible) && (whitespaceColours.back.isSet); +} ColourDesired ViewStyle::WrapColour() const { if (whitespaceColours.fore.isSet) diff --git a/src/stc/scintilla/src/ViewStyle.h b/src/stc/scintilla/src/ViewStyle.h index 60bd9688ee..4a4ffcdf0e 100644 --- a/src/stc/scintilla/src/ViewStyle.h +++ b/src/stc/scintilla/src/ViewStyle.h @@ -85,6 +85,7 @@ public: Indicator indicators[INDIC_MAX + 1]; int technology; int lineHeight; + int lineOverlap; unsigned int maxAscent; unsigned int maxDescent; XYPOSITION aveCharWidth; @@ -170,7 +171,10 @@ public: bool ValidStyle(size_t styleIndex) const; void CalcLargestMarkerHeight(); ColourOptional Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const; + bool SelectionBackgroundDrawn() const; + bool WhitespaceBackgroundDrawn() const; ColourDesired WrapColour() const; + bool SetWrapState(int wrapState_); bool SetWrapVisualFlags(int wrapVisualFlags_); bool SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_); diff --git a/src/stc/stc.cpp b/src/stc/stc.cpp index 1fb5018248..5acbaa2476 100644 --- a/src/stc/stc.cpp +++ b/src/stc/stc.cpp @@ -529,6 +529,24 @@ int wxStyledTextCtrl::GetTabWidth() const return SendMsg(SCI_GETTABWIDTH, 0, 0); } +// Clear explicit tabstops on a line. +void wxStyledTextCtrl::ClearTabStops(int line) +{ + SendMsg(SCI_CLEARTABSTOPS, line, 0); +} + +// Add an explicit tab stop for a line. +void wxStyledTextCtrl::AddTabStop(int line, int x) +{ + SendMsg(SCI_ADDTABSTOP, line, x); +} + +// Find the next explicit tab stop position on a line after a position. +int wxStyledTextCtrl::GetNextTabStop(int line, int x) +{ + return SendMsg(SCI_GETNEXTTABSTOP, line, x); +} + // Set the code page used to interpret the bytes of the document as characters. void wxStyledTextCtrl::SetCodePage(int codePage) { #if wxUSE_UNICODE @@ -541,6 +559,18 @@ void wxStyledTextCtrl::SetCodePage(int codePage) { SendMsg(SCI_SETCODEPAGE, codePage); } +// Is the IME displayed in a winow or inline? +int wxStyledTextCtrl::GetIMEInteraction() const +{ + return SendMsg(SCI_GETIMEINTERACTION, 0, 0); +} + +// Choose to display the the IME in a winow or inline. +void wxStyledTextCtrl::SetIMEInteraction(int imeInteraction) +{ + SendMsg(SCI_SETIMEINTERACTION, imeInteraction, 0); +} + // Set the symbol used for a particular marker number, // and optionally the fore and background colours. void wxStyledTextCtrl::MarkerDefine(int markerNumber, int markerSymbol, @@ -2243,7 +2273,7 @@ void wxStyledTextCtrl::AppendText(const wxString& text) { SendMsg(SCI_APPENDTEXT, wx2stclen(text, buf), (sptr_t)(const char*)buf); } -// Is drawing done in two phases with backgrounds drawn before faoregrounds? +// Is drawing done in two phases with backgrounds drawn before foregrounds? bool wxStyledTextCtrl::GetTwoPhaseDraw() const { return SendMsg(SCI_GETTWOPHASEDRAW, 0, 0) != 0; @@ -2256,6 +2286,21 @@ void wxStyledTextCtrl::SetTwoPhaseDraw(bool twoPhase) SendMsg(SCI_SETTWOPHASEDRAW, twoPhase, 0); } +// How many phases is drawing done in? +int wxStyledTextCtrl::GetPhasesDraw() const +{ + return SendMsg(SCI_GETPHASESDRAW, 0, 0); +} + +// In one phase draw, text is drawn in a series of rectangular blocks with no overlap. +// In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. +// In multiple phase draw, each element is drawn over the whole drawing area, allowing text +// to overlap from one line to the next. +void wxStyledTextCtrl::SetPhasesDraw(int phases) +{ + SendMsg(SCI_SETPHASESDRAW, phases, 0); +} + // Scroll so that a display line is at the top of the display. void wxStyledTextCtrl::SetFirstVisibleLine(int lineDisplay) { @@ -5335,7 +5380,7 @@ wxStyledTextEvent::wxStyledTextEvent(const wxStyledTextEvent& event): /*static*/ wxVersionInfo wxStyledTextCtrl::GetLibraryVersionInfo() { - return wxVersionInfo("Scintilla", 3, 4, 4, "Scintilla 3.4.4"); + return wxVersionInfo("Scintilla", 3, 5, 2, "Scintilla 3.5.2"); } #endif // wxUSE_STC diff --git a/src/stc/stc.cpp.in b/src/stc/stc.cpp.in index f273c20501..d40b68b2f7 100644 --- a/src/stc/stc.cpp.in +++ b/src/stc/stc.cpp.in @@ -1205,7 +1205,7 @@ wxStyledTextEvent::wxStyledTextEvent(const wxStyledTextEvent& event): /*static*/ wxVersionInfo wxStyledTextCtrl::GetLibraryVersionInfo() { - return wxVersionInfo("Scintilla", 3, 4, 4, "Scintilla 3.4.4"); + return wxVersionInfo("Scintilla", 3, 5, 2, "Scintilla 3.5.2"); } #endif // wxUSE_STC