Update Scintilla to version 3.5.2
This commit is contained in:
parent
6909627641
commit
0a58f5012b
@ -708,7 +708,7 @@ void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back) {
|
||||
|
||||
void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
|
||||
SurfaceImpl &surfi = static_cast<SurfaceImpl &>(surfacePattern);
|
||||
bool canDraw = surfi.psurf;
|
||||
bool canDraw = surfi.psurf != NULL;
|
||||
if (canDraw) {
|
||||
PLATFORM_ASSERT(context);
|
||||
// Tile pattern over rectangle
|
||||
@ -842,7 +842,7 @@ void SurfaceImpl::Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back)
|
||||
|
||||
void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
|
||||
SurfaceImpl &surfi = static_cast<SurfaceImpl &>(surfaceSource);
|
||||
bool canDraw = surfi.psurf;
|
||||
bool canDraw = surfi.psurf != NULL;
|
||||
if (canDraw) {
|
||||
PLATFORM_ASSERT(context);
|
||||
cairo_set_source_surface(context, surfi.psurf,
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -424,6 +425,7 @@ ScintillaGTK::~ScintillaGTK() {
|
||||
gdk_event_free(reinterpret_cast<GdkEvent *>(evbtn));
|
||||
evbtn = 0;
|
||||
}
|
||||
wPreedit.Destroy();
|
||||
}
|
||||
|
||||
static void UnRefCursor(GdkCursor *cursor) {
|
||||
@ -482,20 +484,8 @@ void ScintillaGTK::RealizeThis(GtkWidget *widget) {
|
||||
gdk_window_show(widget->window);
|
||||
UnRefCursor(cursor);
|
||||
#endif
|
||||
wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
|
||||
wPreeditDraw = gtk_drawing_area_new();
|
||||
GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
|
||||
#if GTK_CHECK_VERSION(3,0,0)
|
||||
g_signal_connect(G_OBJECT(predrw), "draw",
|
||||
G_CALLBACK(DrawPreedit), this);
|
||||
#else
|
||||
g_signal_connect(G_OBJECT(predrw), "expose_event",
|
||||
G_CALLBACK(ExposePreedit), this);
|
||||
#endif
|
||||
gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
|
||||
gtk_widget_realize(PWidget(wPreedit));
|
||||
gtk_widget_realize(predrw);
|
||||
gtk_widget_show(predrw);
|
||||
gtk_widget_realize(PWidget(wPreeditDraw));
|
||||
|
||||
im_context = gtk_im_multicontext_new();
|
||||
g_signal_connect(G_OBJECT(im_context), "commit",
|
||||
@ -843,6 +833,20 @@ void ScintillaGTK::Initialise() {
|
||||
GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets,
|
||||
static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE));
|
||||
|
||||
/* create pre-edit window */
|
||||
wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
|
||||
wPreeditDraw = gtk_drawing_area_new();
|
||||
GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
|
||||
#if GTK_CHECK_VERSION(3,0,0)
|
||||
g_signal_connect(G_OBJECT(predrw), "draw",
|
||||
G_CALLBACK(DrawPreedit), this);
|
||||
#else
|
||||
g_signal_connect(G_OBJECT(predrw), "expose_event",
|
||||
G_CALLBACK(ExposePreedit), this);
|
||||
#endif
|
||||
gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
|
||||
gtk_widget_show(predrw);
|
||||
|
||||
// Set caret period based on GTK settings
|
||||
gboolean blinkOn = false;
|
||||
if (g_object_class_find_property(G_OBJECT_GET_CLASS(
|
||||
@ -1563,6 +1567,13 @@ void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, Selectio
|
||||
len--; // Forget the extra '\0'
|
||||
#endif
|
||||
|
||||
#if PLAT_GTK_WIN32
|
||||
// Win32 includes an ending '\0' byte in 'len' for clipboard text from
|
||||
// external applications; ignore it.
|
||||
if ((len > 0) && (data[len - 1] == '\0'))
|
||||
len--;
|
||||
#endif
|
||||
|
||||
std::string dest(data, len);
|
||||
if (selectionTypeData == GDK_TARGET_STRING) {
|
||||
if (IsUnicodeMode()) {
|
||||
|
@ -274,7 +274,9 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
|
||||
#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
|
||||
@ -372,6 +374,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
|
||||
#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
|
||||
@ -643,6 +646,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
|
||||
#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
|
||||
@ -813,6 +818,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
|
||||
#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
|
||||
@ -893,6 +899,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
|
||||
#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
|
||||
|
@ -605,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
|
||||
@ -884,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)
|
||||
@ -1661,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,)
|
||||
@ -2152,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,)
|
||||
@ -2360,6 +2366,7 @@ 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,)
|
||||
|
@ -407,7 +407,7 @@ static void FoldCoffeeScriptDoc(unsigned int startPos, int length, int,
|
||||
static const char *const csWordLists[] = {
|
||||
"Keywords",
|
||||
"Secondary keywords",
|
||||
"Unused"
|
||||
"Unused",
|
||||
"Global classes",
|
||||
0,
|
||||
};
|
||||
|
@ -207,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);
|
||||
@ -369,6 +369,7 @@ static void FoldNoBoxVHDLDoc(
|
||||
strcmp(s, "architecture") == 0 ||
|
||||
strcmp(s, "case") == 0 ||
|
||||
strcmp(s, "generate") == 0 ||
|
||||
strcmp(s, "block") == 0 ||
|
||||
strcmp(s, "loop") == 0 ||
|
||||
strcmp(s, "package") ==0 ||
|
||||
strcmp(s, "process") == 0 ||
|
||||
|
@ -84,8 +84,8 @@ int Scintilla_LinkLexers() {
|
||||
LINK_LEXER(lmCaml);
|
||||
LINK_LEXER(lmCmake);
|
||||
LINK_LEXER(lmCOBOL);
|
||||
LINK_LEXER(lmCPP);
|
||||
LINK_LEXER(lmCoffeeScript);
|
||||
LINK_LEXER(lmCPP);
|
||||
LINK_LEXER(lmCss);
|
||||
LINK_LEXER(lmD);
|
||||
LINK_LEXER(lmDiff);
|
||||
|
@ -378,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;
|
||||
|
@ -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;
|
||||
|
@ -11,10 +11,15 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef CXX11_REGEX
|
||||
#include <regex>
|
||||
#endif
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#include "ILexer.h"
|
||||
@ -335,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);
|
||||
@ -601,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)
|
||||
@ -1297,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;
|
||||
@ -1586,6 +1595,25 @@ void Document::SetCaseFolder(CaseFolder *pcf_) {
|
||||
pcf = pcf_;
|
||||
}
|
||||
|
||||
Document::CharacterExtracted Document::ExtractCharacter(int position) const {
|
||||
const unsigned char leadByte = static_cast<unsigned char>(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<widthCharBytes; b++)
|
||||
charBytes[b] = static_cast<unsigned char>(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)
|
||||
@ -2177,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;
|
||||
@ -2197,18 +2280,375 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CXX11_REGEX
|
||||
|
||||
class ByteIterator : public std::iterator<std::bidirectional_iterator_tag, char> {
|
||||
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<std::bidirectional_iterator_tag, wchar_t> {
|
||||
// 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<wchar_t>(charExtracted.character);
|
||||
} else {
|
||||
lenCharacters = UTF16FromUTF32Character(charExtracted.character, buffered);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// On Unix, report non-BMP characters as single characters
|
||||
|
||||
class UTF8Iterator : public std::iterator<std::bidirectional_iterator_tag, wchar_t> {
|
||||
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<typename Iterator, typename Regex>
|
||||
bool MatchOnLines(const Document *doc, const Regex ®exp, const RESearchRange &resr, RESearch &search) {
|
||||
bool matched = false;
|
||||
std::match_results<Iterator> 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<Iterator> 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<unsigned int>(strlen(s));
|
||||
std::vector<wchar_t> 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<unsigned int *>(&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<UTF8Iterator>(doc, regexp, resr, search);
|
||||
|
||||
} else {
|
||||
std::regex regexp;
|
||||
regexp.assign(s, flagsRe);
|
||||
matched = MatchOnLines<ByteIterator>(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) {
|
||||
|
||||
#ifdef CXX11_REGEX
|
||||
if (flags & SCFIND_CXX11REGEX) {
|
||||
return Cxx11RegexFindText(doc, minPos, maxPos, s,
|
||||
caseSensitive, length, search);
|
||||
}
|
||||
#endif
|
||||
|
||||
const RESearchRange resr(doc, minPos, maxPos);
|
||||
|
||||
const bool posix = (flags & SCFIND_POSIX) != 0;
|
||||
const int increment = (minPos <= maxPos) ? 1 : -1;
|
||||
|
||||
int startPos = minPos;
|
||||
int endPos = maxPos;
|
||||
|
||||
// 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 char *errmsg = search.Compile(s, *length, caseSensitive, posix);
|
||||
if (errmsg) {
|
||||
@ -2218,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);
|
||||
const 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;
|
||||
const char searchEnd = s[*length - 1];
|
||||
const char searchEndPrev = (*length > 1) ? s[*length - 2] : '\0';
|
||||
const int lineRangeBreak = lineRangeEnd + increment;
|
||||
for (int line = lineRangeStart; line != lineRangeBreak; line += increment) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2273,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--)) {
|
||||
|
@ -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;
|
||||
@ -317,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);
|
||||
@ -345,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;
|
||||
@ -364,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_);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@ -185,6 +186,9 @@ EditView::EditView() {
|
||||
pixmapIndentGuideHighlight = 0;
|
||||
llc.SetLevel(LineLayoutCache::llcCaret);
|
||||
posCache.SetSize(0x400);
|
||||
tabArrowHeight = 4;
|
||||
customDrawTabArrow = NULL;
|
||||
customDrawWrapMarker = NULL;
|
||||
}
|
||||
|
||||
EditView::~EditView() {
|
||||
@ -927,7 +931,11 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle
|
||||
rcPlace.right = rcLine.right;
|
||||
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
|
||||
}
|
||||
DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour());
|
||||
if (customDrawWrapMarker == NULL) {
|
||||
DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour());
|
||||
} else {
|
||||
customDrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -991,6 +999,10 @@ static void DrawIndicators(Surface *surface, const EditModel &model, const ViewS
|
||||
}
|
||||
}
|
||||
|
||||
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<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth);
|
||||
@ -1002,18 +1014,16 @@ void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const Vi
|
||||
surface->FillRectangle(rcSegment, vsDraw.styles[0].back);
|
||||
}
|
||||
rcSegment.left = static_cast<XYPOSITION>(xStart);
|
||||
if (model.trackLineWidth || (vsDraw.annotationVisible == ANNOTATION_BOXED)) {
|
||||
// Only care about calculating width if tracking or need to draw box
|
||||
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 (vsDraw.annotationVisible == ANNOTATION_BOXED) {
|
||||
if (AnnotationBoxedOrIndented(vsDraw.annotationVisible)) {
|
||||
widthAnnotation += static_cast<int>(vsDraw.spaceWidth * 2); // Margins
|
||||
}
|
||||
if (widthAnnotation > lineWidthMaxSeen)
|
||||
lineWidthMaxSeen = widthAnnotation;
|
||||
if (vsDraw.annotationVisible == ANNOTATION_BOXED) {
|
||||
rcSegment.left = static_cast<XYPOSITION>(xStart + indent);
|
||||
rcSegment.right = rcSegment.left + widthAnnotation;
|
||||
}
|
||||
if (widthAnnotation > lineWidthMaxSeen)
|
||||
lineWidthMaxSeen = widthAnnotation;
|
||||
}
|
||||
const int annotationLines = model.pdoc->AnnotationLines(line);
|
||||
size_t start = 0;
|
||||
@ -1025,7 +1035,7 @@ void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const Vi
|
||||
lineInAnnotation++;
|
||||
}
|
||||
PRectangle rcText = rcSegment;
|
||||
if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) {
|
||||
if ((phase & drawBack) && AnnotationBoxedOrIndented(vsDraw.annotationVisible)) {
|
||||
surface->FillRectangle(rcText,
|
||||
vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back);
|
||||
rcText.left += vsDraw.spaceWidth;
|
||||
@ -1201,7 +1211,7 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt
|
||||
}
|
||||
|
||||
static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll,
|
||||
int xStart, PRectangle rcLine, ColourOptional background) {
|
||||
int xStart, PRectangle rcLine, ColourOptional background, DrawWrapMarkerFn customDrawWrapMarker) {
|
||||
// default bgnd here..
|
||||
surface->FillRectangle(rcLine, background.isSet ? background :
|
||||
vsDraw.styles[STYLE_DEFAULT].back);
|
||||
@ -1219,7 +1229,11 @@ static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, c
|
||||
else
|
||||
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
|
||||
|
||||
DrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour());
|
||||
if (customDrawWrapMarker == NULL) {
|
||||
DrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour());
|
||||
} else {
|
||||
customDrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1463,9 +1477,12 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
|
||||
if (vsDraw.whitespaceColours.fore.isSet)
|
||||
textFore = vsDraw.whitespaceColours.fore;
|
||||
surface->PenColour(textFore);
|
||||
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
|
||||
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + tabArrowHeight,
|
||||
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
|
||||
DrawTabArrow(surface, rcTab, static_cast<int>(rcSegment.top + vsDraw.lineHeight / 2));
|
||||
if (customDrawTabArrow == NULL)
|
||||
DrawTabArrow(surface, rcTab, static_cast<int>(rcSegment.top + vsDraw.lineHeight / 2));
|
||||
else
|
||||
customDrawTabArrow(surface, rcTab, static_cast<int>(rcSegment.top + vsDraw.lineHeight / 2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1632,7 +1649,7 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl
|
||||
|
||||
if ((ll->wrapIndent != 0) && (subLine > 0)) {
|
||||
if (phase & drawBack) {
|
||||
DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background);
|
||||
DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background, customDrawWrapMarker);
|
||||
}
|
||||
xStart += static_cast<int>(ll->wrapIndent);
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XY
|
||||
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.
|
||||
*/
|
||||
@ -78,6 +80,14 @@ public:
|
||||
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();
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@ -112,6 +113,7 @@ Editor::Editor() {
|
||||
mouseDownCaptures = true;
|
||||
|
||||
lastClickTime = 0;
|
||||
doubleClickCloseThreshold = Point(3, 3);
|
||||
dwellDelay = SC_TIME_FOREVER;
|
||||
ticksToDwell = SC_TIME_FOREVER;
|
||||
dwelling = false;
|
||||
@ -1789,12 +1791,15 @@ void Editor::AddCharUTF(const char *s, unsigned int len, bool treatAsDBCS) {
|
||||
{
|
||||
UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike);
|
||||
|
||||
// Vector elements point into selection in order to change selection.
|
||||
std::vector<SelectionRange *> 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<SelectionRange *>::reverse_iterator rit = selPtrs.rbegin();
|
||||
rit != selPtrs.rend(); ++rit) {
|
||||
SelectionRange *currentSel = *rit;
|
||||
@ -2105,6 +2110,7 @@ void Editor::Clear() {
|
||||
ClearSelection();
|
||||
}
|
||||
sel.RemoveDuplicates();
|
||||
ShowCaretAtCurrentPosition(); // Avoid blinking
|
||||
}
|
||||
|
||||
void Editor::SelectAll() {
|
||||
@ -3638,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<int>(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<int>(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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3683,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<int>(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<int>(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<int>(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<int>(wParam),
|
||||
&lengthFound);
|
||||
}
|
||||
} catch (RegexError &) {
|
||||
errorStatus = SC_STATUS_WARN_REGEX;
|
||||
return -1;
|
||||
}
|
||||
if (pos != -1) {
|
||||
SetSelection(pos, pos + lengthFound);
|
||||
@ -3733,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) {
|
||||
@ -3757,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;
|
||||
}
|
||||
@ -4116,7 +4137,7 @@ 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()) {
|
||||
|
@ -203,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;
|
||||
|
@ -72,6 +72,11 @@ 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 {
|
||||
if (customDraw != NULL) {
|
||||
customDraw(surface, rcWhole, fontForCharacter, tFold, marginStyle, this);
|
||||
return;
|
||||
}
|
||||
|
||||
ColourDesired colourHead = back;
|
||||
ColourDesired colourBody = back;
|
||||
ColourDesired colourTail = back;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@ -102,6 +103,8 @@ MarginView::MarginView() {
|
||||
pixmapSelMargin = 0;
|
||||
pixmapSelPattern = 0;
|
||||
pixmapSelPatternOffset1 = 0;
|
||||
wrapMarkerPaddingRight = 3;
|
||||
customDrawWrapMarker = NULL;
|
||||
}
|
||||
|
||||
void MarginView::DropGraphics(bool freeObjects) {
|
||||
@ -391,9 +394,13 @@ void MarginView::PaintMargin(Surface *surface, int topLine, PRectangle rc, PRect
|
||||
rcNumber.top + vs.maxAscent, number, static_cast<int>(strlen(number)), drawAll);
|
||||
} else if (vs.wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) {
|
||||
PRectangle rcWrapMarker = rcMarker;
|
||||
rcWrapMarker.right -= 3;
|
||||
rcWrapMarker.right -= wrapMarkerPaddingRight;
|
||||
rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth;
|
||||
DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore);
|
||||
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) {
|
||||
|
@ -14,6 +14,8 @@ namespace Scintilla {
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -25,6 +27,13 @@ public:
|
||||
// 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);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
@ -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,7 +47,6 @@ public:
|
||||
std::string pat[MAXTAG];
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
void ChSet(unsigned char c);
|
||||
void ChSetWithCase(unsigned char c, bool caseSensitive);
|
||||
int GetBackslashExpression(const char *pattern, int &incr);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
@ -20,6 +20,7 @@ namespace Scintilla {
|
||||
enum { SURROGATE_LEAD_FIRST = 0xD800 };
|
||||
enum { SURROGATE_TRAIL_FIRST = 0xDC00 };
|
||||
enum { SURROGATE_TRAIL_LAST = 0xDFFF };
|
||||
enum { SUPPLEMENTAL_PLANE_FIRST = 0x10000 };
|
||||
|
||||
unsigned int UTF8Length(const wchar_t *uptr, unsigned int tlen) {
|
||||
unsigned int len = 0;
|
||||
@ -138,6 +139,51 @@ unsigned int UTF16FromUTF8(const char *s, unsigned int len, wchar_t *tbuf, unsig
|
||||
return ui;
|
||||
}
|
||||
|
||||
unsigned int UTF32FromUTF8(const char *s, unsigned int len, unsigned int *tbuf, unsigned int tlen) {
|
||||
unsigned int ui=0;
|
||||
const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
|
||||
unsigned int i=0;
|
||||
while ((i<len) && (ui<tlen)) {
|
||||
unsigned char ch = us[i++];
|
||||
wchar_t value = 0;
|
||||
if (ch < 0x80) {
|
||||
value = ch;
|
||||
} else if (((len-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<wchar_t>(val);
|
||||
return 1;
|
||||
} else {
|
||||
tbuf[0] = static_cast<wchar_t>(((val - SUPPLEMENTAL_PLANE_FIRST) >> 10) + SURROGATE_LEAD_FIRST);
|
||||
tbuf[1] = static_cast<wchar_t>((val & 0x3ff) + SURROGATE_TRAIL_FIRST);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int UTF8BytesOfLead[256];
|
||||
static bool initialisedBytesOfLead = false;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -1 +1 @@
|
||||
351
|
||||
352
|
||||
|
Loading…
x
Reference in New Issue
Block a user