From 2893ff7bb27d022301a789bee38bea9adb2021ee Mon Sep 17 00:00:00 2001 From: "L.Andrew" <3169143112@qq.com> Date: Sun, 3 Dec 2023 22:46:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=98=E5=8D=9A=E9=A1=BA=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ScintillaComponent/FindReplaceDlg.cpp | 389 +++++++++--------- 1 file changed, 201 insertions(+), 188 deletions(-) diff --git a/src/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp b/src/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp index 6344ebe..feb5403 100644 --- a/src/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp +++ b/src/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp @@ -23,231 +23,244 @@ #include "Common.h" #include "Utf8.h" +把代码逐行注释如下: + +// 引入命名空间 using namespace std; +// 定义 FindOption 类指针和静态变量 _options FindOption * FindReplaceDlg::_env; FindOption FindReplaceDlg::_options; +// 定义 SHIFTED 常量 #define SHIFTED 0x8000 +// 向 Combo Box 中添加文本 void addText2Combo(const TCHAR * txt2add, HWND hCombo) { - if (!hCombo) return; - if (!lstrcmp(txt2add, TEXT(""))) return; - - auto i = ::SendMessage(hCombo, CB_FINDSTRINGEXACT, static_cast(-1), reinterpret_cast(txt2add)); - if (i != CB_ERR) // found - { - ::SendMessage(hCombo, CB_DELETESTRING, i, 0); - } + // 如果没有 Combo Box 或者 txt2add 为空,则返回 + if (!hCombo) return; + if (!lstrcmp(txt2add, TEXT(""))) return; + + // 查找是否已经存在该文本,如果存在则删除 + auto i = ::SendMessage(hCombo, CB_FINDSTRINGEXACT, static_cast(-1), reinterpret_cast(txt2add)); + if (i != CB_ERR) // found + { + ::SendMessage(hCombo, CB_DELETESTRING, i, 0); + } - i = ::SendMessage(hCombo, CB_INSERTSTRING, 0, reinterpret_cast(txt2add)); - ::SendMessage(hCombo, CB_SETCURSEL, i, 0); + // 将文本插入 Combo Box,并设置为当前选中项 + i = ::SendMessage(hCombo, CB_INSERTSTRING, 0, reinterpret_cast(txt2add)); + ::SendMessage(hCombo, CB_SETCURSEL, i, 0); } +// 从 Combo Box 中获取文本 generic_string getTextFromCombo(HWND hCombo) { - TCHAR str[FINDREPLACE_MAXLENGTH] = { '\0' }; - ::SendMessage(hCombo, WM_GETTEXT, FINDREPLACE_MAXLENGTH - 1, reinterpret_cast(str)); - return generic_string(str); + TCHAR str[FINDREPLACE_MAXLENGTH] = { '\0' }; + ::SendMessage(hCombo, WM_GETTEXT, FINDREPLACE_MAXLENGTH - 1, reinterpret_cast(str)); + return generic_string(str); } +// 删除编辑框中光标左边的单词 void delLeftWordInEdit(HWND hEdit) { - TCHAR str[FINDREPLACE_MAXLENGTH] = { '\0' }; - ::SendMessage(hEdit, WM_GETTEXT, FINDREPLACE_MAXLENGTH - 1, reinterpret_cast(str)); - WORD cursor = 0; - ::SendMessage(hEdit, EM_GETSEL, (WPARAM)&cursor, 0); - WORD wordstart = cursor; - while (wordstart > 0) { - TCHAR c = str[wordstart - 1]; - if (c != ' ' && c != '\t') - break; - --wordstart; - } - while (wordstart > 0) { - TCHAR c = str[wordstart - 1]; - if (c == ' ' || c == '\t') - break; - --wordstart; - } - if (wordstart < cursor) { - ::SendMessage(hEdit, EM_SETSEL, (WPARAM)wordstart, (LPARAM)cursor); - ::SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, reinterpret_cast(L"")); - } + TCHAR str[FINDREPLACE_MAXLENGTH] = { '\0' }; + ::SendMessage(hEdit, WM_GETTEXT, FINDREPLACE_MAXLENGTH - 1, reinterpret_cast(str)); + WORD cursor = 0; + ::SendMessage(hEdit, EM_GETSEL, (WPARAM)&cursor, 0); + WORD wordstart = cursor; + while (wordstart > 0) { + TCHAR c = str[wordstart - 1]; + if (c != ' ' && c != '\t') + break; + --wordstart; + } + while (wordstart > 0) { + TCHAR c = str[wordstart - 1]; + if (c == ' ' || c == '\t') + break; + --wordstart; + } + if (wordstart < cursor) { + ::SendMessage(hEdit, EM_SETSEL, (WPARAM)wordstart, (LPARAM)cursor); + ::SendMessage(hEdit, EM_REPLACESEL, (WPARAM)TRUE, reinterpret_cast(L"")); + } } +// 运行交换按钮处理函数 LRESULT run_swapButtonProc(WNDPROC oldEditProc, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - switch (message) - { - case WM_RBUTTONUP: - { - ::SendMessage(GetParent(hwnd), message, wParam, lParam); - break; - } - - default: - break; - } - return ::CallWindowProc(oldEditProc, hwnd, message, wParam, lParam); + switch (message) + { + case WM_RBUTTONUP: + { + ::SendMessage(GetParent(hwnd), message, wParam, lParam); + break; + } + + default: + break; + } + return ::CallWindowProc(oldEditProc, hwnd, message, wParam, lParam); } +// 将扩展字符转换为字符串 int Searching::convertExtendedToString(const TCHAR * query, TCHAR * result, int length) -{ //query may equal to result, since it always gets smaller - int i = 0, j = 0; - int charLeft = length; - TCHAR current; - while (i < length) - { //because the backslash escape quences always reduce the size of the generic_string, no overflow checks have to be made for target, assuming parameters are correct - current = query[i]; - --charLeft; - if (current == '\\' && charLeft) - { //possible escape sequence - ++i; - --charLeft; - current = query[i]; - switch(current) - { - case 'r': - result[j] = '\r'; - break; - case 'n': - result[j] = '\n'; - break; - case '0': - result[j] = '\0'; - break; - case 't': - result[j] = '\t'; - break; - case '\\': - result[j] = '\\'; - break; - case 'b': - case 'd': - case 'o': - case 'x': - case 'u': - { - int size = 0, base = 0; - if (current == 'b') - { //11111111 - size = 8, base = 2; - } - else if (current == 'o') - { //377 - size = 3, base = 8; - } - else if (current == 'd') - { //255 - size = 3, base = 10; - } - else if (current == 'x') - { //0xFF - size = 2, base = 16; - } - else if (current == 'u') - { //0xCDCD - size = 4, base = 16; - } - - if (charLeft >= size) - { - int res = 0; - if (Searching::readBase(query+(i+1), &res, base, size)) - { - result[j] = static_cast(res); - i += size; - break; - } - } - //not enough chars to make parameter, use default method as fallback - [[fallthrough]]; - } - - default: - { //unknown sequence, treat as regular text - result[j] = '\\'; - ++j; - result[j] = current; - break; - } - } - } - else - { - result[j] = query[i]; - } - ++i; - ++j; - } - result[j] = 0; - return j; +{ //query may equal to result, since it always gets smaller + int i = 0, j = 0; + int charLeft = length; + TCHAR current; + while (i < length) + { //because the backslash escape quences always reduce the size of the generic_string, no overflow checks have to be made for target, assuming parameters are correct + current = query[i]; + --charLeft; + if (current == '\\' && charLeft) + { //possible escape sequence + ++i; + --charLeft; + current = query[i]; + switch(current) + { + case 'r': + result[j] = '\r'; + break; + case 'n': + result[j] = '\n'; + break; + case '0': + result[j] = '\0'; + break; + case 't': + result[j] = '\t'; + break; + case '\\': + result[j] = '\\'; + break; + case 'b': + case 'd': + case 'o': + case 'x': + case 'u': + { + int size = 0, base = 0; + if (current == 'b') + { //11111111 + size = 8, base = 2; + } + else if (current == 'o') + { //377 + size = 3, base = 8; + } + else if (current == 'd') + { //255 + size = 3, base = 10; + } + else if (current == 'x') + { //0xFF + size = 2, base = 16; + } + else if (current == 'u') + { //0xCDCD + size = 4, base = 16; + } + + if (charLeft >= size) + { + int res = 0; + if (Searching::readBase(query+(i+1), &res, base, size)) + { + result[j] = static_cast(res); + i += size; + break; + } + } + //not enough chars to make parameter, use default method as fallback + [[fallthrough]]; + } + + default: + { //unknown sequence, treat as regular text + result[j] = '\\'; + ++j; + result[j] = current; + break; + } + } + } + else + { + result[j] = query[i]; + } + ++i; + ++j; + } + result[j] = 0; + return j; } +// 将字符串转换为指定进制的整数 bool Searching::readBase(const TCHAR * str, int * value, int base, int size) { - int i = 0, temp = 0; - *value = 0; - TCHAR max = '0' + static_cast(base) - 1; - TCHAR current; - while (i < size) - { - current = str[i]; - if (current >= 'A') - { - current &= 0xdf; - current -= ('A' - '0' - 10); - } - else if (current > '9') - return false; - - if (current >= '0' && current <= max) - { - temp *= base; - temp += (current - '0'); - } - else - { - return false; - } - ++i; - } - *value = temp; - return true; + int i = 0, temp = 0; + *value = 0; + TCHAR max = '0' + static_cast(base) - 1; + TCHAR current; + while (i < size) + { + current = str[i]; + if (current >= 'A') + { + current &= 0xdf; + current -= ('A' - '0' - 10); + } + else if (current > '9') + return false; + + if (current >= '0' && current <= max) + { + temp *= base; + temp += (current - '0'); + } + else + { + return false; + } + ++i; + } + *value = temp; + return true; } +// 在编辑框中显示查找结果 void Searching::displaySectionCentered(size_t posStart, size_t posEnd, ScintillaEditView * pEditView, bool isDownwards) { - // Make sure target lines are unfolded - pEditView->execute(SCI_ENSUREVISIBLE, pEditView->execute(SCI_LINEFROMPOSITION, posStart)); - pEditView->execute(SCI_ENSUREVISIBLE, pEditView->execute(SCI_LINEFROMPOSITION, posEnd)); - - // Jump-scroll to center, if current position is out of view - pEditView->execute(SCI_SETVISIBLEPOLICY, CARET_JUMPS | CARET_EVEN); - pEditView->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, pEditView->execute(SCI_LINEFROMPOSITION, isDownwards ? posEnd : posStart)); - // When searching up, the beginning of the (possible multiline) result is important, when scrolling down the end - pEditView->execute(SCI_GOTOPOS, isDownwards ? posEnd : posStart); - pEditView->execute(SCI_SETVISIBLEPOLICY, CARET_EVEN); - pEditView->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, pEditView->execute(SCI_LINEFROMPOSITION, isDownwards ? posEnd : posStart)); - - // Adjust so that we see the entire match; primarily horizontally - pEditView->execute(SCI_SCROLLRANGE, posStart, posEnd); - - // Move cursor to end of result and select result - pEditView->execute(SCI_GOTOPOS, posEnd); - pEditView->execute(SCI_SETANCHOR, posStart); - - // Update Scintilla's knowledge about what column the caret is in, so that if user - // does up/down arrow as first navigation after the search result is selected, - // the caret doesn't jump to an unexpected column - pEditView->execute(SCI_CHOOSECARETX); + // 确保目标行未折叠 + pEditView->execute(SCI_ENSUREVISIBLE, pEditView->execute(SCI_LINEFROMPOSITION, posStart)); + pEditView->execute(SCI_ENSUREVISIBLE, pEditView->execute(SCI_LINEFROMPOSITION, posEnd)); + + // 跳跃滚动到中心位置,如果当前位置不在视图内 + pEditView->execute(SCI_SETVISIBLEPOLICY, CARET_JUMPS | CARET_EVEN); + pEditView->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, pEditView->execute(SCI_LINEFROMPOSITION, isDownwards ? posEnd : posStart)); + // 当向上查找时,结果的开头很重要,而向下滚动时则是结尾 + pEditView->execute(SCI_GOTOPOS, isDownwards ? posEnd : posStart); + pEditView->execute(SCI_SETVISIBLEPOLICY, CARET_EVEN); + pEditView->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, pEditView->execute(SCI_LINEFROMPOSITION, isDownwards ? posEnd : posStart)); + + // 调整以便看到整个匹配;主要是水平方向 + pEditView->execute(SCI_SCROLLRANGE, posStart, posEnd); + + // 将光标移动到结果的结尾并选择结果 + pEditView->execute(SCI_GOTOPOS, posEnd); + pEditView->execute(SCI_SETANCHOR, posStart); + + // 更新 Scintilla 对插入符所在列的了解,以便如果用户在选择搜索结果后的首次导航时使用上/下箭头,则插入符不会跳到意外的列 + pEditView->execute(SCI_CHOOSECARETX); } +// 定义静态变量 originalFinderProc 和 originalComboEditProc WNDPROC FindReplaceDlg::originalFinderProc = nullptr; WNDPROC FindReplaceDlg::originalComboEditProc = nullptr; - // important : to activate all styles const int STYLING_MASK = 255;