aboutsummaryrefslogtreecommitdiffhomepage
path: root/lexilla/test/TestDocument.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'lexilla/test/TestDocument.cxx')
-rw-r--r--lexilla/test/TestDocument.cxx222
1 files changed, 222 insertions, 0 deletions
diff --git a/lexilla/test/TestDocument.cxx b/lexilla/test/TestDocument.cxx
new file mode 100644
index 000000000..780265305
--- /dev/null
+++ b/lexilla/test/TestDocument.cxx
@@ -0,0 +1,222 @@
+// Scintilla source code edit control
+/** @file TestDocument.cxx
+ ** Lexer testing.
+ **/
+ // Copyright 2019 by Neil Hodgson <neilh@scintilla.org>
+ // The License.txt file describes the conditions under which this software may be distributed.
+
+#include <cassert>
+
+#include <string>
+#include <string_view>
+#include <vector>
+#include <algorithm>
+
+#include <iostream>
+
+#include "ILexer.h"
+
+#include "TestDocument.h"
+
+namespace {
+
+ const unsigned char UTF8BytesOfLead[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00 - 0F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 - 1F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20 - 2F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30 - 3F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 - 4F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50 - 5F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 - 6F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70 - 7F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 - 8F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90 - 9F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0 - AF
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0 - BF
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0 - CF
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D0 - DF
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E0 - EF
+ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // F0 - FF
+ };
+
+ int UnicodeFromUTF8(const unsigned char *us) noexcept {
+ switch (UTF8BytesOfLead[us[0]]) {
+ case 1:
+ return us[0];
+ case 2:
+ return ((us[0] & 0x1F) << 6) + (us[1] & 0x3F);
+ case 3:
+ return ((us[0] & 0xF) << 12) + ((us[1] & 0x3F) << 6) + (us[2] & 0x3F);
+ default:
+ return ((us[0] & 0x7) << 18) + ((us[1] & 0x3F) << 12) + ((us[2] & 0x3F) << 6) + (us[3] & 0x3F);
+ }
+ }
+
+}
+
+void TestDocument::Set(std::string_view sv) {
+ text = sv;
+ textStyles.resize(text.size());
+ lineStarts.clear();
+ endStyled = 0;
+ lineStarts.push_back(0);
+ for (size_t pos = 0; pos < text.length(); pos++) {
+ if (text[pos] == '\n') {
+ lineStarts.push_back(pos + 1);
+ }
+ }
+ lineStarts.push_back(text.length());
+ lineStates.resize(lineStarts.size());
+}
+
+int SCI_METHOD TestDocument::Version() const {
+ return Scintilla::dvRelease4;
+}
+
+void SCI_METHOD TestDocument::SetErrorStatus(int) {
+}
+
+Sci_Position SCI_METHOD TestDocument::Length() const {
+ return text.length();
+}
+
+void SCI_METHOD TestDocument::GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const {
+ text.copy(buffer, lengthRetrieve, position);
+}
+
+char SCI_METHOD TestDocument::StyleAt(Sci_Position position) const {
+ return textStyles.at(position);
+}
+
+Sci_Position SCI_METHOD TestDocument::LineFromPosition(Sci_Position position) const {
+ if (position >= static_cast<Sci_Position>(text.length())) {
+ return lineStarts.size() - 1 - 1;
+ }
+
+ std::vector<Sci_Position>::const_iterator it = std::lower_bound(lineStarts.begin(), lineStarts.end(), position);
+ Sci_Position line = it - lineStarts.begin();
+ if (*it > position)
+ line--;
+ return line;
+}
+
+Sci_Position SCI_METHOD TestDocument::LineStart(Sci_Position line) const {
+ if (line >= static_cast<Sci_Position>(lineStarts.size())) {
+ return text.length();
+ }
+ return lineStarts.at(line);
+}
+
+int SCI_METHOD TestDocument::GetLevel(Sci_Position) const {
+ // Only for folding so not implemented yet
+ return 0;
+}
+
+int SCI_METHOD TestDocument::SetLevel(Sci_Position, int) {
+ // Only for folding so not implemented yet
+ return 0;
+}
+
+int SCI_METHOD TestDocument::GetLineState(Sci_Position line) const {
+ return lineStates.at(line);
+}
+
+int SCI_METHOD TestDocument::SetLineState(Sci_Position line, int state) {
+ return lineStates.at(line) = state;
+}
+
+void SCI_METHOD TestDocument::StartStyling(Sci_Position position) {
+ endStyled = position;
+}
+
+bool SCI_METHOD TestDocument::SetStyleFor(Sci_Position length, char style) {
+ for (Sci_Position i = 0; i < length; i++) {
+ textStyles[endStyled] = style;
+ endStyled++;
+ }
+ return true;
+}
+
+bool SCI_METHOD TestDocument::SetStyles(Sci_Position length, const char *styles) {
+ for (Sci_Position i = 0; i < length; i++) {
+ textStyles[endStyled] = styles[i];
+ endStyled++;
+ }
+ return true;
+}
+
+void SCI_METHOD TestDocument::DecorationSetCurrentIndicator(int) {
+ // Not implemented as no way to read decorations
+}
+
+void SCI_METHOD TestDocument::DecorationFillRange(Sci_Position, int, Sci_Position) {
+ // Not implemented as no way to read decorations
+}
+
+void SCI_METHOD TestDocument::ChangeLexerState(Sci_Position, Sci_Position) {
+ // Not implemented as no watcher to trigger
+}
+
+int SCI_METHOD TestDocument::CodePage() const {
+ // Always UTF-8 for now
+ return 65001;
+}
+
+bool SCI_METHOD TestDocument::IsDBCSLeadByte(char) const {
+ // Always UTF-8 for now
+ return false;
+}
+
+const char *SCI_METHOD TestDocument::BufferPointer() {
+ return text.c_str();
+}
+
+int SCI_METHOD TestDocument::GetLineIndentation(Sci_Position) {
+ // Never actually called - lexers use Accessor::IndentAmount
+ return 0;
+}
+
+Sci_Position SCI_METHOD TestDocument::LineEnd(Sci_Position line) const {
+ Sci_Position position = LineStart(line + 1);
+ position--; // Back over CR or LF
+ // When line terminator is CR+LF, may need to go back one more
+ if ((position > LineStart(line)) && (text.at(position - 1) == '\r')) {
+ position--;
+ }
+ return position;
+}
+
+Sci_Position SCI_METHOD TestDocument::GetRelativePosition(Sci_Position positionStart, Sci_Position characterOffset) const {
+ // TODO: negative characterOffset
+ assert(characterOffset >= 0);
+ // TODO: invalid UTF-8
+ Sci_Position pos = positionStart;
+ while (characterOffset > 0) {
+ Sci_Position width = 0;
+ GetCharacterAndWidth(pos, &width);
+ pos += width;
+ characterOffset--;
+ }
+ return pos;
+}
+
+int SCI_METHOD TestDocument::GetCharacterAndWidth(Sci_Position position, Sci_Position *pWidth) const {
+ // TODO: invalid UTF-8
+ if (position >= static_cast<Sci_Position>(text.length())) {
+ // Return NULs after document end
+ if (pWidth) {
+ *pWidth = 1;
+ }
+ return '\0';
+ }
+ const unsigned char leadByte = text.at(position);
+ const int widthCharBytes = UTF8BytesOfLead[leadByte];
+ unsigned char charBytes[] = { leadByte,0,0,0 };
+ for (int b = 1; b < widthCharBytes; b++)
+ charBytes[b] = text[position + b];
+
+ if (pWidth) {
+ *pWidth = widthCharBytes;
+ }
+ return UnicodeFromUTF8(charBytes);
+}