📄 document.cxx
字号:
continue; // Can't match start of line if end position after start of line
startOfLine = endPos;
}
if (line == lineRangeStart) {
if ((startPos != endOfLine) && (searchEnd == '$'))
continue; // Can't match end of line if start position before end of line
endOfLine = startPos;
}
}
DocumentIndexer di(this, endOfLine);
int success = pre->Execute(di, startOfLine, endOfLine);
if (success) {
pos = pre->bopat[0];
lenRet = pre->eopat[0] - pre->bopat[0];
if (increment == -1) {
// Check for the last match on this line.
int repetitions = 1000; // Break out of infinite loop
while (success && (pre->eopat[0] <= endOfLine) && (repetitions--)) {
success = pre->Execute(di, pos+1, endOfLine);
if (success) {
if (pre->eopat[0] <= minPos) {
pos = pre->bopat[0];
lenRet = pre->eopat[0] - pre->bopat[0];
} else {
success = 0;
}
}
}
}
break;
}
}
*length = lenRet;
return pos;
} else {
bool forward = minPos <= maxPos;
int increment = forward ? 1 : -1;
// Range endpoints should not be inside DBCS characters, but just in case, move them.
int startPos = MovePositionOutsideChar(minPos, increment, false);
int endPos = MovePositionOutsideChar(maxPos, increment, false);
// Compute actual search ranges needed
int lengthFind = *length;
if (lengthFind == -1)
lengthFind = static_cast<int>(strlen(s));
int endSearch = endPos;
if (startPos <= endPos) {
endSearch = endPos - lengthFind + 1;
}
//Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind);
char firstChar = s[0];
if (!caseSensitive)
firstChar = static_cast<char>(MakeUpperCase(firstChar));
int pos = forward ? startPos : (startPos - 1);
while (forward ? (pos < endSearch) : (pos >= endSearch)) {
char ch = CharAt(pos);
if (caseSensitive) {
if (ch == firstChar) {
bool found = true;
if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false;
for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) {
ch = CharAt(pos + posMatch);
if (ch != s[posMatch])
found = false;
}
if (found) {
if ((!word && !wordStart) ||
word && IsWordAt(pos, pos + lengthFind) ||
wordStart && IsWordStartAt(pos))
return pos;
}
}
} else {
if (MakeUpperCase(ch) == firstChar) {
bool found = true;
if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false;
for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) {
ch = CharAt(pos + posMatch);
if (MakeUpperCase(ch) != MakeUpperCase(s[posMatch]))
found = false;
}
if (found) {
if ((!word && !wordStart) ||
word && IsWordAt(pos, pos + lengthFind) ||
wordStart && IsWordStartAt(pos))
return pos;
}
}
}
pos += increment;
if (dbcsCodePage && (pos >= 0)) {
// Ensure trying to match from start of character
pos = MovePositionOutsideChar(pos, increment, false);
}
}
}
//Platform::DebugPrintf("Not found\n");
return -1;
}
const char *Document::SubstituteByPosition(const char *text, int *length) {
if (!pre)
return 0;
delete []substituted;
substituted = 0;
DocumentIndexer di(this, Length());
if (!pre->GrabMatches(di))
return 0;
unsigned int lenResult = 0;
for (int i = 0; i < *length; i++) {
if (text[i] == '\\') {
if (text[i + 1] >= '1' && text[i + 1] <= '9') {
unsigned int patNum = text[i + 1] - '0';
lenResult += pre->eopat[patNum] - pre->bopat[patNum];
i++;
} else {
switch (text[i + 1]) {
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
i++;
}
lenResult++;
}
} else {
lenResult++;
}
}
substituted = new char[lenResult + 1];
if (!substituted)
return 0;
char *o = substituted;
for (int j = 0; j < *length; j++) {
if (text[j] == '\\') {
if (text[j + 1] >= '1' && text[j + 1] <= '9') {
unsigned int patNum = text[j + 1] - '0';
unsigned int len = pre->eopat[patNum] - pre->bopat[patNum];
if (pre->pat[patNum]) // Will be null if try for a match that did not occur
memcpy(o, pre->pat[patNum], len);
o += len;
j++;
} else {
j++;
switch (text[j]) {
case 'a':
*o++ = '\a';
break;
case 'b':
*o++ = '\b';
break;
case 'f':
*o++ = '\f';
break;
case 'n':
*o++ = '\n';
break;
case 'r':
*o++ = '\r';
break;
case 't':
*o++ = '\t';
break;
case 'v':
*o++ = '\v';
break;
default:
*o++ = '\\';
j--;
}
}
} else {
*o++ = text[j];
}
}
*o = '\0';
*length = lenResult;
return substituted;
}
int Document::LinesTotal() {
return cb.Lines();
}
void Document::ChangeCase(Range r, bool makeUpperCase) {
for (int pos = r.start; pos < r.end;) {
int len = LenChar(pos);
if (len == 1) {
char ch = CharAt(pos);
if (makeUpperCase) {
if (IsLowerCase(ch)) {
ChangeChar(pos, static_cast<char>(MakeUpperCase(ch)));
}
} else {
if (IsUpperCase(ch)) {
ChangeChar(pos, static_cast<char>(MakeLowerCase(ch)));
}
}
}
pos += len;
}
}
void Document::SetDefaultCharClasses(bool includeWordClass) {
charClass.SetDefaultCharClasses(includeWordClass);
}
void Document::SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass) {
charClass.SetCharClasses(chars, newCharClass);
}
void Document::SetStylingBits(int bits) {
stylingBits = bits;
stylingBitsMask = 0;
for (int bit = 0; bit < stylingBits; bit++) {
stylingBitsMask <<= 1;
stylingBitsMask |= 1;
}
}
void Document::StartStyling(int position, char mask) {
stylingMask = mask;
endStyled = position;
}
bool Document::SetStyleFor(int length, char style) {
if (enteredCount != 0) {
return false;
} else {
enteredCount++;
style &= stylingMask;
int prevEndStyled = endStyled;
if (cb.SetStyleFor(endStyled, length, style, stylingMask)) {
DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER,
prevEndStyled, length);
NotifyModified(mh);
}
endStyled += length;
enteredCount--;
return true;
}
}
bool Document::SetStyles(int length, char *styles) {
if (enteredCount != 0) {
return false;
} else {
enteredCount++;
bool didChange = false;
int startMod = 0;
int endMod = 0;
for (int iPos = 0; iPos < length; iPos++, endStyled++) {
PLATFORM_ASSERT(endStyled < Length());
if (cb.SetStyleAt(endStyled, styles[iPos], stylingMask)) {
if (!didChange) {
startMod = endStyled;
}
didChange = true;
endMod = endStyled;
}
}
if (didChange) {
DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER,
startMod, endMod - startMod + 1);
NotifyModified(mh);
}
enteredCount--;
return true;
}
}
bool Document::EnsureStyledTo(int pos) {
if (pos > GetEndStyled()) {
IncrementStyleClock();
// Ask the watchers to style, and stop as soon as one responds.
for (int i = 0; pos > GetEndStyled() && i < lenWatchers; i++) {
watchers[i].watcher->NotifyStyleNeeded(this, watchers[i].userData, pos);
}
}
return pos <= GetEndStyled();
}
void Document::IncrementStyleClock() {
styleClock++;
if (styleClock > 0x100000) {
styleClock = 0;
}
}
bool Document::AddWatcher(DocWatcher *watcher, void *userData) {
for (int i = 0; i < lenWatchers; i++) {
if ((watchers[i].watcher == watcher) &&
(watchers[i].userData == userData))
return false;
}
WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers + 1];
if (!pwNew)
return false;
for (int j = 0; j < lenWatchers; j++)
pwNew[j] = watchers[j];
pwNew[lenWatchers].watcher = watcher;
pwNew[lenWatchers].userData = userData;
delete []watchers;
watchers = pwNew;
lenWatchers++;
return true;
}
bool Document::RemoveWatcher(DocWatcher *watcher, void *userData) {
for (int i = 0; i < lenWatchers; i++) {
if ((watchers[i].watcher == watcher) &&
(watchers[i].userData == userData)) {
if (lenWatchers == 1) {
delete []watchers;
watchers = 0;
lenWatchers = 0;
} else {
WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers];
if (!pwNew)
return false;
for (int j = 0; j < lenWatchers - 1; j++) {
pwNew[j] = (j < i) ? watchers[j] : watchers[j + 1];
}
delete []watchers;
watchers = pwNew;
lenWatchers--;
}
return true;
}
}
return false;
}
void Document::NotifyModifyAttempt() {
for (int i = 0; i < lenWatchers; i++) {
watchers[i].watcher->NotifyModifyAttempt(this, watchers[i].userData);
}
}
void Document::NotifySavePoint(bool atSavePoint) {
for (int i = 0; i < lenWatchers; i++) {
watchers[i].watcher->NotifySavePoint(this, watchers[i].userData, atSavePoint);
}
}
void Document::NotifyModified(DocModification mh) {
for (int i = 0; i < lenWatchers; i++) {
watchers[i].watcher->NotifyModified(this, mh, watchers[i].userData);
}
}
bool Document::IsWordPartSeparator(char ch) {
return (WordCharClass(ch) == CharClassify::ccWord) && IsPunctuation(ch);
}
int Document::WordPartLeft(int pos) {
if (pos > 0) {
--pos;
char startChar = cb.CharAt(pos);
if (IsWordPartSeparator(startChar)) {
while (pos > 0 && IsWordPartSeparator(cb.CharAt(pos))) {
--pos;
}
}
if (pos > 0) {
startChar = cb.CharAt(pos);
--pos;
if (IsLowerCase(startChar)) {
while (pos > 0 && IsLowerCase(cb.CharAt(pos)))
--pos;
if (!IsUpperCase(cb.CharAt(pos)) && !IsLowerCase(cb.CharAt(pos)))
++pos;
} else if (IsUpperCase(startChar)) {
while (pos > 0 && IsUpperCase(cb.CharAt(pos)))
--pos;
if (!IsUpperCase(cb.CharAt(pos)))
++pos;
} else if (IsADigit(startChar)) {
while (pos > 0 && IsADigit(cb.CharAt(pos)))
--pos;
if (!IsADigit(cb.CharAt(pos)))
++pos;
} else if (IsPunctuation(startChar)) {
while (pos > 0 && IsPunctuation(cb.CharAt(pos)))
--pos;
if (!IsPunctuation(cb.CharAt(pos)))
++pos;
} else if (isspacechar(startChar)) {
while (pos > 0 && isspacechar(cb.CharAt(pos)))
--pos;
if (!isspacechar(cb.CharAt(pos)))
++pos;
} else if (!isascii(startChar)) {
while (pos > 0 && !isascii(cb.CharAt(pos)))
--pos;
if (isascii(cb.CharAt(pos)))
++pos;
} else {
++pos;
}
}
}
return pos;
}
int Document::WordPartRight(int pos) {
char startChar = cb.CharAt(pos);
int length = Length();
if (IsWordPartSeparator(startChar)) {
while (pos < length && IsWordPartSeparator(cb.CharAt(pos)))
++pos;
startChar = cb.CharAt(pos);
}
if (!isascii(startChar)) {
while (pos < length && !isascii(cb.CharAt(pos)))
++pos;
} else if (IsLowerCase(startChar)) {
while (pos < length && IsLowerCase(cb.CharAt(pos)))
++pos;
} else if (IsUpperCase(startChar)) {
if (IsLowerCase(cb.CharAt(pos + 1))) {
++pos;
while (pos < length && IsLowerCase(cb.CharAt(pos)))
++pos;
} else {
while (pos < length && IsUpperCase(cb.CharAt(pos)))
++pos;
}
if (IsLowerCase(cb.CharAt(pos)) && IsUpperCase(cb.CharAt(pos - 1)))
--pos;
} else if (IsADigit(startChar)) {
while (pos < length && IsADigit(cb.CharAt(pos)))
++pos;
} else if (IsPunctuation(startChar)) {
while (pos < length && IsPunctuation(cb.CharAt(pos)))
++pos;
} else if (isspacechar(startChar)) {
while (pos < length && isspacechar(cb.CharAt(pos)))
++pos;
} else {
++pos;
}
return pos;
}
bool IsLineEndChar(char c) {
return (c == '\n' || c == '\r');
}
int Document::ExtendStyleRange(int pos, int delta, bool singleLine) {
int sStart = cb.StyleAt(pos);
if (delta < 0) {
while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos))) )
pos--;
pos++;
} else {
while (pos < (Length()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos))) )
pos++;
}
return pos;
}
static char BraceOpposite(char ch) {
switch (ch) {
case '(':
return ')';
case ')':
return '(';
case '[':
return ']';
case ']':
return '[';
case '{':
return '}';
case '}':
return '{';
case '<':
return '>';
case '>':
return '<';
default:
return '\0';
}
}
// TODO: should be able to extend styled region to find matching brace
int Document::BraceMatch(int position, int /*maxReStyle*/) {
char chBrace = CharAt(position);
char chSeek = BraceOpposite(chBrace);
if (chSeek == '\0')
return - 1;
char styBrace = static_cast<char>(StyleAt(position) & stylingBitsMask);
int direction = -1;
if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<')
direction = 1;
int depth = 1;
position = position + direction;
while ((position >= 0) && (position < Length())) {
position = MovePositionOutsideChar(position, direction);
char chAtPos = CharAt(position);
char styAtPos = static_cast<char>(StyleAt(position) & stylingBitsMask);
if ((position > GetEndStyled()) || (styAtPos == styBrace)) {
if (chAtPos == chBrace)
depth++;
if (chAtPos == chSeek)
depth--;
if (depth == 0)
return position;
}
position = position + direction;
}
return - 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -