⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 document.cxx

📁 一个可以提供语法高亮显示的编辑器
💻 CXX
📖 第 1 页 / 共 3 页
字号:
		bool endSavePoint = cb.IsSavePoint();
		if (startSavePoint != endSavePoint)
			NotifySavePoint(endSavePoint);
		enteredCount--;
	}
	return newPos;
}

int Document::Redo() {
	int newPos = 0;
	if (enteredCount == 0) {
		enteredCount++;
		bool startSavePoint = cb.IsSavePoint();
		int steps = cb.StartRedo();
		for (int step = 0; step < steps; step++) {
			int prevLinesTotal = LinesTotal();
			const Action &action = cb.GetRedoStep();
			if (action.at == insertAction) {
				NotifyModified(DocModification(
				                   SC_MOD_BEFOREINSERT | SC_PERFORMED_REDO, action));
			} else {
				NotifyModified(DocModification(
				                   SC_MOD_BEFOREDELETE | SC_PERFORMED_REDO, action));
			}
			cb.PerformRedoStep();
			ModifiedAt(action.position / 2);
			newPos = action.position / 2;

			int modFlags = SC_PERFORMED_REDO;
			if (action.at == insertAction) {
				newPos += action.lenData;
				modFlags |= SC_MOD_INSERTTEXT;
			} else {
				modFlags |= SC_MOD_DELETETEXT;
			}
			if (step == steps - 1)
				modFlags |= SC_LASTSTEPINUNDOREDO;
			NotifyModified(
			    DocModification(modFlags, action.position / 2, action.lenData,
			                    LinesTotal() - prevLinesTotal, action.data));
		}

		bool endSavePoint = cb.IsSavePoint();
		if (startSavePoint != endSavePoint)
			NotifySavePoint(endSavePoint);
		enteredCount--;
	}
	return newPos;
}

bool Document::InsertChar(int pos, char ch) {
	char chs[2];
	chs[0] = ch;
	chs[1] = 0;
	return InsertStyledString(pos*2, chs, 2);
}

// Insert a null terminated string
bool Document::InsertString(int position, const char *s) {
	return InsertString(position, s, strlen(s));
}

// Insert a string with a length
bool Document::InsertString(int position, const char *s, size_t insertLength) {
	bool changed = false;
	char *sWithStyle = new char[insertLength * 2];
	if (sWithStyle) {
		for (size_t i = 0; i < insertLength; i++) {
			sWithStyle[i*2] = s[i];
			sWithStyle[i*2 + 1] = 0;
		}
		changed = InsertStyledString(position*2, sWithStyle,
			static_cast<int>(insertLength*2));
		delete []sWithStyle;
	}
	return changed;
}

void Document::ChangeChar(int pos, char ch) {
	DeleteChars(pos, 1);
	InsertChar(pos, ch);
}

void Document::DelChar(int pos) {
	DeleteChars(pos, LenChar(pos));
}

void Document::DelCharBack(int pos) {
	if (pos <= 0) {
		return;
	} else if (IsCrLf(pos - 2)) {
		DeleteChars(pos - 2, 2);
	} else if (dbcsCodePage) {
		int startChar = MovePositionOutsideChar(pos - 1, -1, false);
		DeleteChars(startChar, pos - startChar);
	} else {
		DeleteChars(pos - 1, 1);
	}
}

static bool isindentchar(char ch) {
	return (ch == ' ') || (ch == '\t');
}

static int NextTab(int pos, int tabSize) {
	return ((pos / tabSize) + 1) * tabSize;
}

static void CreateIndentation(char *linebuf, int length, int indent, int tabSize, bool insertSpaces) {
	length--;	// ensure space for \0
	if (!insertSpaces) {
		while ((indent >= tabSize) && (length > 0)) {
			*linebuf++ = '\t';
			indent -= tabSize;
			length--;
		}
	}
	while ((indent > 0) && (length > 0)) {
		*linebuf++ = ' ';
		indent--;
		length--;
	}
	*linebuf = '\0';
}

int Document::GetLineIndentation(int line) {
	int indent = 0;
	if ((line >= 0) && (line < LinesTotal())) {
		int lineStart = LineStart(line);
		int length = Length();
		for (int i = lineStart;i < length;i++) {
			char ch = cb.CharAt(i);
			if (ch == ' ')
				indent++;
			else if (ch == '\t')
				indent = NextTab(indent, tabInChars);
			else
				return indent;
		}
	}
	return indent;
}

void Document::SetLineIndentation(int line, int indent) {
	int indentOfLine = GetLineIndentation(line);
	if (indent < 0)
		indent = 0;
	if (indent != indentOfLine) {
		char linebuf[1000];
		CreateIndentation(linebuf, sizeof(linebuf), indent, tabInChars, !useTabs);
		int thisLineStart = LineStart(line);
		int indentPos = GetLineIndentPosition(line);
		DeleteChars(thisLineStart, indentPos - thisLineStart);
		InsertString(thisLineStart, linebuf);
	}
}

int Document::GetLineIndentPosition(int line) {
	if (line < 0)
		return 0;
	int pos = LineStart(line);
	int length = Length();
	while ((pos < length) && isindentchar(cb.CharAt(pos))) {
		pos++;
	}
	return pos;
}

int Document::GetColumn(int pos) {
	int column = 0;
	int line = LineFromPosition(pos);
	if ((line >= 0) && (line < LinesTotal())) {
		for (int i = LineStart(line);i < pos;) {
			char ch = cb.CharAt(i);
			if (ch == '\t') {
				column = NextTab(column, tabInChars);
				i++;
			} else if (ch == '\r') {
				return column;
			} else if (ch == '\n') {
				return column;
			} else {
				column++;
				i = MovePositionOutsideChar(i + 1, 1);
			}
		}
	}
	return column;
}

int Document::FindColumn(int line, int column) {
	int position = LineStart(line);
	int columnCurrent = 0;
	if ((line >= 0) && (line < LinesTotal())) {
		while (columnCurrent < column) {
			char ch = cb.CharAt(position);
			if (ch == '\t') {
				columnCurrent = NextTab(columnCurrent, tabInChars);
				position++;
			} else if (ch == '\r') {
				return position;
			} else if (ch == '\n') {
				return position;
			} else {
				columnCurrent++;
				position = MovePositionOutsideChar(position + 1, 1);
			}
		}
	}
	return position;
}

void Document::Indent(bool forwards, int lineBottom, int lineTop) {
	// Dedent - suck white space off the front of the line to dedent by equivalent of a tab
	for (int line = lineBottom; line >= lineTop; line--) {
		int indentOfLine = GetLineIndentation(line);
		if (forwards)
			SetLineIndentation(line, indentOfLine + IndentSize());
		else
			SetLineIndentation(line, indentOfLine - IndentSize());
	}
}

void Document::ConvertLineEnds(int eolModeSet) {
	BeginUndoAction();
	for (int pos = 0; pos < Length(); pos++) {
		if (cb.CharAt(pos) == '\r') {
			if (cb.CharAt(pos + 1) == '\n') {
				if (eolModeSet != SC_EOL_CRLF) {
					DeleteChars(pos, 2);
					if (eolModeSet == SC_EOL_CR)
						InsertString(pos, "\r", 1);
					else
						InsertString(pos, "\n", 1);
				} else {
					pos++;
				}
			} else {
				if (eolModeSet != SC_EOL_CR) {
					DeleteChars(pos, 1);
					if (eolModeSet == SC_EOL_CRLF) {
						InsertString(pos, "\r\n", 2);
						pos++;
					} else {
						InsertString(pos, "\n", 1);
					}
				}
			}
		} else if (cb.CharAt(pos) == '\n') {
			if (eolModeSet != SC_EOL_LF) {
				DeleteChars(pos, 1);
				if (eolModeSet == SC_EOL_CRLF) {
					InsertString(pos, "\r\n", 2);
					pos++;
				} else {
					InsertString(pos, "\r", 1);
				}
			}
		}
	}
	EndUndoAction();
}

int Document::ParaDown(int pos) {
	int line = LineFromPosition(pos);
	while (line < LinesTotal() && LineStart(line) != LineEnd(line)) { // skip non-empty lines
		line++;
	}
	while (line < LinesTotal() && LineStart(line) == LineEnd(line)) { // skip empty lines
		line++;
	}
	if (line < LinesTotal())
		return LineStart(line);
	else // end of a document
		return LineEnd(line-1);
}

int Document::ParaUp(int pos) {
	int line = LineFromPosition(pos);
	line--;
	while (line >= 0 && LineStart(line) == LineEnd(line)) { // skip empty lines
		line--;
	}
	while (line >= 0 && LineStart(line) != LineEnd(line)) { // skip non-empty lines
		line--;
	}
	line++;
	return LineStart(line);
}

Document::charClassification Document::WordCharClass(unsigned char ch) {
	if ((SC_CP_UTF8 == dbcsCodePage) && (ch >= 0x80))
		return ccWord;
	return charClass[ch];
}

/**
 * Used by commmands that want to select whole words.
 * Finds the start of word at pos when delta < 0 or the end of the word when delta >= 0.
 */
int Document::ExtendWordSelect(int pos, int delta, bool onlyWordCharacters) {
	charClassification ccStart = ccWord;
	if (delta < 0) {
		if (!onlyWordCharacters)
			ccStart = WordCharClass(cb.CharAt(pos-1));
		while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart))
			pos--;
	} else {
		if (!onlyWordCharacters)
			ccStart = WordCharClass(cb.CharAt(pos));
		while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart))
			pos++;
	}
	return pos;
}

/**
 * Find the start of the next word in either a forward (delta >= 0) or backwards direction
 * (delta < 0).
 * This is looking for a transition between character classes although there is also some
 * additional movement to transit white space.
 * Used by cursor movement by word commands.
 */
int Document::NextWordStart(int pos, int delta) {
	if (delta < 0) {
		while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccSpace))
			pos--;
		if (pos > 0) {
			charClassification ccStart = WordCharClass(cb.CharAt(pos-1));
			while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart)) {
				pos--;
			}
		}
	} else {
		charClassification ccStart = WordCharClass(cb.CharAt(pos));
		while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart))
			pos++;
		while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccSpace))
			pos++;
	}
	return pos;
}

/**
 * Check that the character at the given position is a word or punctuation character and that
 * the previous character is of a different character class.
 */
bool Document::IsWordStartAt(int pos) {
	if (pos > 0) {
		charClassification ccPos = WordCharClass(CharAt(pos));
		return (ccPos == ccWord || ccPos == ccPunctuation) &&
			(ccPos != WordCharClass(CharAt(pos - 1)));
	}
	return true;
}

/**
 * Check that the character at the given position is a word or punctuation character and that
 * the next character is of a different character class.
 */
bool Document::IsWordEndAt(int pos) {
	if (pos < Length() - 1) {
		charClassification ccPrev = WordCharClass(CharAt(pos-1));
		return (ccPrev == ccWord || ccPrev == ccPunctuation) &&
			(ccPrev != WordCharClass(CharAt(pos)));
	}
	return true;
}

/**
 * Check that the given range is has transitions between character classes at both
 * ends and where the characters on the inside are word or punctuation characters.
 */
bool Document::IsWordAt(int start, int end) {
	return IsWordStartAt(start) && IsWordEndAt(end);
}

// The comparison and case changing functions here assume ASCII
// or extended ASCII such as the normal Windows code page.

static inline char MakeUpperCase(char ch) {
	if (ch < 'a' || ch > 'z')
		return ch;
	else
		return static_cast<char>(ch - 'a' + 'A');
}

static inline char MakeLowerCase(char ch) {
	if (ch < 'A' || ch > 'Z')
		return ch;
	else
		return static_cast<char>(ch - 'A' + 'a');
}

// Define a way for the Regular Expression code to access the document
class DocumentIndexer : public CharacterIndexer {
	Document *pdoc;
	int end;
public:
	DocumentIndexer(Document *pdoc_, int end_) :
		pdoc(pdoc_), end(end_) {
	}

	virtual char CharAt(int index) {
		if (index < 0 || index >= end)
			return 0;
		else
			return pdoc->CharAt(index);
	}
};

/**
 * Find text in document, supporting both forward and backward
 * searches (just pass minPos > maxPos to do a backward search)
 * Has not been tested with backwards DBCS searches yet.
 */
long Document::FindText(int minPos, int maxPos, const char *s,
                        bool caseSensitive, bool word, bool wordStart, bool regExp, bool posix,
                        int *length) {
	if (regExp) {
		if (!pre)
			pre = new RESearch();
		if (!pre)
			return -1;

		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 = MovePositionOutsideChar(startPos, 1, false);
		endPos = MovePositionOutsideChar(endPos, 1, false);

		const char *errmsg = pre->Compile(s, *length, caseSensitive, posix);
		if (errmsg) {
			return -1;
		}
		// Find a variable in a property file: \$(\([A-Za-z0-9_.]+\))
		// Replace first '.' with '-' in each property file variable reference:
		//     Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\))
		//     Replace: $(\1-\2)
		int lineRangeStart = LineFromPosition(startPos);
		int lineRangeEnd = LineFromPosition(endPos);
		if ((increment == 1) &&
			(startPos >= LineEnd(lineRangeStart)) &&
			(lineRangeStart < lineRangeEnd)) {
			// the start position is at end of line or between line end characters.
			lineRangeStart++;
			startPos = LineStart(lineRangeStart);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -