@ -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 < WPARAM > ( - 1 ) , reinterpret_cast < LPARAM > ( 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 < WPARAM > ( - 1 ) , reinterpret_cast < LPARAM > ( txt2add ) ) ;
if ( i ! = CB_ERR ) // found
{
: : SendMessage ( hCombo , CB_DELETESTRING , i , 0 ) ;
}
i = : : SendMessage ( hCombo , CB_INSERTSTRING , 0 , reinterpret_cast < LPARAM > ( txt2add ) ) ;
: : SendMessage ( hCombo , CB_SETCURSEL , i , 0 ) ;
// 将文本插入 Combo Box, 并设置为当前选中项
i = : : SendMessage ( hCombo , CB_INSERTSTRING , 0 , reinterpret_cast < LPARAM > ( 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 < LPARAM > ( str ) ) ;
return generic_string ( str ) ;
TCHAR str [ FINDREPLACE_MAXLENGTH ] = { ' \0 ' } ;
: : SendMessage ( hCombo , WM_GETTEXT , FINDREPLACE_MAXLENGTH - 1 , reinterpret_cast < LPARAM > ( str ) ) ;
return generic_string ( str ) ;
}
// 删除编辑框中光标左边的单词
void delLeftWordInEdit ( HWND hEdit )
{
TCHAR str [ FINDREPLACE_MAXLENGTH ] = { ' \0 ' } ;
: : SendMessage ( hEdit , WM_GETTEXT , FINDREPLACE_MAXLENGTH - 1 , reinterpret_cast < LPARAM > ( 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 < LPARAM > ( L " " ) ) ;
}
TCHAR str [ FINDREPLACE_MAXLENGTH ] = { ' \0 ' } ;
: : SendMessage ( hEdit , WM_GETTEXT , FINDREPLACE_MAXLENGTH - 1 , reinterpret_cast < LPARAM > ( 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 < LPARAM > ( 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 < TCHAR > ( 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 < TCHAR > ( 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 < TCHAR > ( 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 < TCHAR > ( 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 ;