@ -23,6 +23,9 @@
# include "Common.h"
# include "Common.h"
# include "Utf8.h"
# include "Utf8.h"
下 面 是 对 给 定 代 码 的 详 细 注 释 :
` ` ` cpp
using namespace std ;
using namespace std ;
FindOption * FindReplaceDlg : : _env ;
FindOption * FindReplaceDlg : : _env ;
@ -35,12 +38,15 @@ void addText2Combo(const TCHAR * txt2add, HWND hCombo)
if ( ! hCombo ) return ;
if ( ! hCombo ) return ;
if ( ! lstrcmp ( txt2add , TEXT ( " " ) ) ) return ;
if ( ! lstrcmp ( txt2add , TEXT ( " " ) ) ) return ;
// 在组合框中查找是否已存在相同的文本
auto i = : : SendMessage ( hCombo , CB_FINDSTRINGEXACT , static_cast < WPARAM > ( - 1 ) , reinterpret_cast < LPARAM > ( txt2add ) ) ;
auto i = : : SendMessage ( hCombo , CB_FINDSTRINGEXACT , static_cast < WPARAM > ( - 1 ) , reinterpret_cast < LPARAM > ( txt2add ) ) ;
if ( i ! = CB_ERR ) // found
if ( i ! = CB_ERR ) // 找到了相同的文本
{
{
// 删除已存在的文本
: : SendMessage ( hCombo , CB_DELETESTRING , i , 0 ) ;
: : SendMessage ( hCombo , CB_DELETESTRING , i , 0 ) ;
}
}
// 向组合框中插入新的文本,并设置为当前选中项
i = : : SendMessage ( hCombo , CB_INSERTSTRING , 0 , reinterpret_cast < LPARAM > ( txt2add ) ) ;
i = : : SendMessage ( hCombo , CB_INSERTSTRING , 0 , reinterpret_cast < LPARAM > ( txt2add ) ) ;
: : SendMessage ( hCombo , CB_SETCURSEL , i , 0 ) ;
: : SendMessage ( hCombo , CB_SETCURSEL , i , 0 ) ;
}
}
@ -59,6 +65,8 @@ void delLeftWordInEdit(HWND hEdit)
WORD cursor = 0 ;
WORD cursor = 0 ;
: : SendMessage ( hEdit , EM_GETSEL , ( WPARAM ) & cursor , 0 ) ;
: : SendMessage ( hEdit , EM_GETSEL , ( WPARAM ) & cursor , 0 ) ;
WORD wordstart = cursor ;
WORD wordstart = cursor ;
// 删除光标左边的单词
while ( wordstart > 0 ) {
while ( wordstart > 0 ) {
TCHAR c = str [ wordstart - 1 ] ;
TCHAR c = str [ wordstart - 1 ] ;
if ( c ! = ' ' & & c ! = ' \t ' )
if ( c ! = ' ' & & c ! = ' \t ' )
@ -83,6 +91,7 @@ LRESULT run_swapButtonProc(WNDPROC oldEditProc, HWND hwnd, UINT message, WPARAM
{
{
case WM_RBUTTONUP :
case WM_RBUTTONUP :
{
{
// 模拟右键点击事件,发送给父窗口处理
: : SendMessage ( GetParent ( hwnd ) , message , wParam , lParam ) ;
: : SendMessage ( GetParent ( hwnd ) , message , wParam , lParam ) ;
break ;
break ;
}
}
@ -94,19 +103,22 @@ LRESULT run_swapButtonProc(WNDPROC oldEditProc, HWND hwnd, UINT message, WPARAM
}
}
int Searching : : convertExtendedToString ( const TCHAR * query , TCHAR * result , int length )
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 i = 0 , j = 0 ;
int charLeft = length ;
int charLeft = length ;
TCHAR current ;
TCHAR current ;
while ( i < length )
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 ] ;
current = query [ i ] ;
- - charLeft ;
- - charLeft ;
if ( current = = ' \\ ' & & charLeft )
if ( current = = ' \\ ' & & charLeft )
{ //possible escape sequence
{
+ + i ;
+ + i ;
- - charLeft ;
- - charLeft ;
current = query [ i ] ;
current = query [ i ] ;
switch ( current )
switch ( current )
{
{
case ' r ' :
case ' r ' :
@ -131,24 +143,26 @@ int Searching::convertExtendedToString(const TCHAR * query, TCHAR * result, int
case ' u ' :
case ' u ' :
{
{
int size = 0 , base = 0 ;
int size = 0 , base = 0 ;
// 根据转义序列的类型设置不同的大小和进制
if ( current = = ' b ' )
if ( current = = ' b ' )
{ //11111111
{
size = 8 , base = 2 ;
size = 8 , base = 2 ;
}
}
else if ( current = = ' o ' )
else if ( current = = ' o ' )
{ //377
{
size = 3 , base = 8 ;
size = 3 , base = 8 ;
}
}
else if ( current = = ' d ' )
else if ( current = = ' d ' )
{ //255
{
size = 3 , base = 10 ;
size = 3 , base = 10 ;
}
}
else if ( current = = ' x ' )
else if ( current = = ' x ' )
{ //0xFF
{
size = 2 , base = 16 ;
size = 2 , base = 16 ;
}
}
else if ( current = = ' u ' )
else if ( current = = ' u ' )
{ //0xCDCD
{
size = 4 , base = 16 ;
size = 4 , base = 16 ;
}
}
@ -162,12 +176,14 @@ int Searching::convertExtendedToString(const TCHAR * query, TCHAR * result, int
break ;
break ;
}
}
}
}
//not enough chars to make parameter, use default method as fallback
// 字符不足以构成参数,则使用默认方法作为备选方案
[[fallthrough]] ;
[[fallthrough]] ;
}
}
default :
default :
{ //unknown sequence, treat as regular text
{
// 未知序列,当做普通文本处理
result [ j ] = ' \\ ' ;
result [ j ] = ' \\ ' ;
+ + j ;
+ + j ;
result [ j ] = current ;
result [ j ] = current ;
@ -182,6 +198,7 @@ int Searching::convertExtendedToString(const TCHAR * query, TCHAR * result, int
+ + i ;
+ + i ;
+ + j ;
+ + j ;
}
}
result [ j ] = 0 ;
result [ j ] = 0 ;
return j ;
return j ;
}
}
@ -195,6 +212,7 @@ bool Searching::readBase(const TCHAR * str, int * value, int base, int size)
while ( i < size )
while ( i < size )
{
{
current = str [ i ] ;
current = str [ i ] ;
if ( current > = ' A ' )
if ( current > = ' A ' )
{
{
current & = 0xdf ;
current & = 0xdf ;
@ -220,105 +238,110 @@ bool Searching::readBase(const TCHAR * str, int * value, int base, int size)
void Searching : : displaySectionCentered ( size_t posStart , size_t posEnd , ScintillaEditView * pEditView , bool isDownwards )
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 , posStart ) ) ;
pEditView - > execute ( SCI_ENSUREVISIBLE , pEditView - > execute ( SCI_LINEFROMPOSITION , posEnd ) ) ;
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_SETVISIBLEPOLICY , CARET_JUMPS | CARET_EVEN ) ;
pEditView - > execute ( SCI_ENSUREVISIBLEENFORCEPOLICY , pEditView - > execute ( SCI_LINEFROMPOSITION , isDownwards ? posEnd : posStart ) ) ;
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_GOTOPOS , isDownwards ? posEnd : posStart ) ;
pEditView - > execute ( SCI_SETVISIBLEPOLICY , CARET_EVEN ) ;
pEditView - > execute ( SCI_SETVISIBLEPOLICY , CARET_EVEN ) ;
pEditView - > execute ( SCI_ENSUREVISIBLEENFORCEPOLICY , pEditView - > execute ( SCI_LINEFROMPOSITION , isDownwards ? posEnd : posStart ) ) ;
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 ) ;
pEditView - > execute ( SCI_SCROLLRANGE , posStart , posEnd ) ;
// Move cursor to end of result and select result
// 将光标移到结果的末尾并选中结果
pEditView - > execute ( SCI_GOTOPOS , posEnd ) ;
pEditView - > execute ( SCI_GOTOPOS , posEnd ) ;
pEditView - > execute ( SCI_SETANCHOR , posStart ) ;
pEditView - > execute ( SCI_SETANCHOR , posStart ) ;
// Update Scintilla's knowledge about what column the caret is in, so that if user
// 更新 Scintilla 中光标所在列的位置信息,以防用户在选择搜索结果后使用上下箭头导航时光标跳到意外的列
// 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_CHOOSECARETX ) ;
}
}
WNDPROC FindReplaceDlg : : originalFinderProc = nullptr ;
WNDPROC FindReplaceDlg : : originalFinderProc = nullptr ;
WNDPROC FindReplaceDlg : : originalComboEditProc = nullptr ;
WNDPROC FindReplaceDlg : : originalComboEditProc = nullptr ;
` ` `
// important : to activate all styles
// important : to activate all styles
const int STYLING_MASK = 255 ;
const int STYLING_MASK = 255 ;
` ` ` cpp
// 定义 FindReplaceDlg 类的析构函数
FindReplaceDlg : : ~ FindReplaceDlg ( )
FindReplaceDlg : : ~ FindReplaceDlg ( )
{
{
_tab . destroy ( ) ;
_tab . destroy ( ) ; // 销毁标签页控件
delete _pFinder ;
delete _pFinder ; // 删除查找对象指针
// 删除与查找对象相关的所有查找器对象
for ( int n = static_cast < int32_t > ( _findersOfFinder . size ( ) ) - 1 ; n > = 0 ; n - - )
for ( int n = static_cast < int32_t > ( _findersOfFinder . size ( ) ) - 1 ; n > = 0 ; n - - )
{
{
delete _findersOfFinder [ n ] ;
delete _findersOfFinder [ n ] ;
_findersOfFinder . erase ( _findersOfFinder . begin ( ) + n ) ;
_findersOfFinder . erase ( _findersOfFinder . begin ( ) + n ) ;
}
}
// 销毁窗口句柄
if ( _shiftTrickUpTip )
if ( _shiftTrickUpTip )
: : DestroyWindow ( _shiftTrickUpTip ) ;
: : DestroyWindow ( _shiftTrickUpTip ) ;
if ( _2ButtonsTip )
if ( _2ButtonsTip )
: : DestroyWindow ( _2ButtonsTip ) ;
: : DestroyWindow ( _2ButtonsTip ) ;
if ( _filterTip )
if ( _filterTip )
: : DestroyWindow ( _filterTip ) ;
: : DestroyWindow ( _filterTip ) ;
// 释放字体对象
if ( _hMonospaceFont )
if ( _hMonospaceFont )
: : DeleteObject ( _hMonospaceFont ) ;
: : DeleteObject ( _hMonospaceFont ) ;
if ( _hLargerBolderFont )
if ( _hLargerBolderFont )
: : DeleteObject ( _hLargerBolderFont ) ;
: : DeleteObject ( _hLargerBolderFont ) ;
if ( _hCourrierNewFont )
if ( _hCourrierNewFont )
: : DeleteObject ( _hCourrierNewFont ) ;
: : DeleteObject ( _hCourrierNewFont ) ;
delete [ ] _uniFileName ;
delete [ ] _uniFileName ; // 释放存储文件名的数组内存
}
}
// 创建 FindReplaceDlg 对话框
void FindReplaceDlg : : create ( int dialogID , bool isRTL , bool msgDestParent , bool toShow )
void FindReplaceDlg : : create ( int dialogID , bool isRTL , bool msgDestParent , bool toShow )
{
{
// 创建静态对话框
StaticDialog : : create ( dialogID , isRTL , msgDestParent ) ;
StaticDialog : : create ( dialogID , isRTL , msgDestParent ) ;
fillFindHistory ( ) ;
fillFindHistory ( ) ; // 填充查找历史记录
_currentStatus = REPLACE_DLG ;
_currentStatus = REPLACE_DLG ; // 设置当前状态为替换对话框
initOptionsFromDlg ( ) ;
initOptionsFromDlg ( ) ; // 从对话框初始化选项
_statusBar . init ( GetModuleHandle ( NULL ) , _hSelf , 0 ) ;
_statusBar . init ( GetModuleHandle ( NULL ) , _hSelf , 0 ) ; // 初始化状态栏
_statusBar . display ( ) ;
_statusBar . display ( ) ; // 显示状态栏
// 获取 DPI 管理器
DPIManager & dpiManager = NppParameters : : getInstance ( ) . _dpiManager ;
DPIManager & dpiManager = NppParameters : : getInstance ( ) . _dpiManager ;
RECT rect { } ;
RECT rect { } ;
getClientRect ( rect ) ;
getClientRect ( rect ) ; // 获取客户区矩形
_tab . init ( _hInst , _hSelf , false , true ) ;
_tab . init ( _hInst , _hSelf , false , true ) ; // 初始化标签页控件
NppDarkMode : : subclassTabControl ( _tab . getHSelf ( ) ) ;
NppDarkMode : : subclassTabControl ( _tab . getHSelf ( ) ) ; // 子类化标签页控件以适配暗黑模式
int tabDpiDynamicalHeight = dpiManager . scaleY ( 13 ) ;
int tabDpiDynamicalHeight = dpiManager . scaleY ( 13 ) ; // 根据 DPI 缩放标签页高度
_tab . setFont ( TEXT ( " Tahoma " ) , tabDpiDynamicalHeight ) ;
_tab . setFont ( TEXT ( " Tahoma " ) , tabDpiDynamicalHeight ) ; // 设置标签页字体
// 插入标签页内容
const TCHAR * find = TEXT ( " Find " ) ;
const TCHAR * find = TEXT ( " Find " ) ;
const TCHAR * replace = TEXT ( " Replace " ) ;
const TCHAR * replace = TEXT ( " Replace " ) ;
const TCHAR * findInFiles = TEXT ( " Find in Files " ) ;
const TCHAR * findInFiles = TEXT ( " Find in Files " ) ;
const TCHAR * findInProjects = TEXT ( " Find in Projects " ) ;
const TCHAR * findInProjects = TEXT ( " Find in Projects " ) ;
const TCHAR * mark = TEXT ( " Mark " ) ;
const TCHAR * mark = TEXT ( " Mark " ) ;
_tab . insertAtEnd ( find ) ;
_tab . insertAtEnd ( find ) ;
_tab . insertAtEnd ( replace ) ;
_tab . insertAtEnd ( replace ) ;
_tab . insertAtEnd ( findInFiles ) ;
_tab . insertAtEnd ( findInFiles ) ;
_tab . insertAtEnd ( findInProjects ) ;
_tab . insertAtEnd ( findInProjects ) ;
_tab . insertAtEnd ( mark ) ;
_tab . insertAtEnd ( mark ) ;
_tab . reSizeTo ( rect ) ; // 调整标签页大小以适应客户区
_tab . display ( ) ; // 显示标签页
_tab . reSizeTo ( rect ) ;
_initialClientWidth = rect . right - rect . left ; // 记录初始客户区宽度
_tab . display ( ) ;
_initialClientWidth = rect . right - rect . left ;
// fill min dialog size info
// 填充最小对话框大小信息
getWindowRect ( _initialWindowRect ) ;
getWindowRect ( _initialWindowRect ) ;
_initialWindowRect . right = _initialWindowRect . right - _initialWindowRect . left + dpiManager . scaleX ( 10 ) ;
_initialWindowRect . right = _initialWindowRect . right - _initialWindowRect . left + dpiManager . scaleX ( 10 ) ;
_initialWindowRect . left = 0 ;
_initialWindowRect . left = 0 ;
@ -335,88 +358,65 @@ void FindReplaceDlg::create(int dialogID, bool isRTL, bool msgDestParent, bool t
NppGUI & nppGUI = nppParam . getNppGUI ( ) ;
NppGUI & nppGUI = nppParam . getNppGUI ( ) ;
const UINT swpFlags = toShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW ;
const UINT swpFlags = toShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW ;
if ( nppGUI . _findWindowPos . bottom - nppGUI . _findWindowPos . top ! = 0 ) // check height against 0 as a test of valid data from config
if ( nppGUI . _findWindowPos . bottom - nppGUI . _findWindowPos . top ! = 0 ) // 检查配置数据是否有效
{
{
RECT rc = getViewablePositionRect ( nppGUI . _findWindowPos ) ;
RECT rc = getViewablePositionRect ( nppGUI . _findWindowPos ) ;
: : SetWindowPos ( _hSelf , HWND_TOP , rc . left , rc . top , rc . right - rc . left , rc . bottom - rc . top , swpFlags ) ;
: : SetWindowPos ( _hSelf , HWND_TOP , rc . left , rc . top , rc . right - rc . left , rc . bottom - rc . top , swpFlags ) ;
}
}
else
else
{
{
goToCenter ( swpFlags ) ;
goToCenter ( swpFlags ) ; // 居中显示
}
}
// 获取状态栏客户区矩形
RECT rcStatusBar { } ;
RECT rcStatusBar { } ;
: : GetClientRect ( _statusBar . getHSelf ( ) , & rcStatusBar ) ;
: : GetClientRect ( _statusBar . getHSelf ( ) , & rcStatusBar ) ;
_lesssModeHeight = ( countRc . bottom - dlgRc . top ) + ( rcStatusBar . bottom - rcStatusBar . top ) + dpiManager . scaleY ( 10 ) ;
_lesssModeHeight = ( countRc . bottom - dlgRc . top ) + ( rcStatusBar . bottom - rcStatusBar . top ) + dpiManager . scaleY ( 10 ) ;
if ( nppGUI . _findWindowLessMode )
if ( nppGUI . _findWindowLessMode )
{
{
// reverse the value of _findWindowLessMode because the value will be inversed again in IDD_RESIZE_TOGGLE_BUTTON
// 反转 _findWindowLessMode 的值,因为在 IDD_RESIZE_TOGGLE_BUTTON 中会再次反转该值
nppGUI . _findWindowLessMode = false ;
nppGUI . _findWindowLessMode = false ;
: : SendMessage ( _hSelf , WM_COMMAND , IDD_RESIZE_TOGGLE_BUTTON , 0 ) ;
: : SendMessage ( _hSelf , WM_COMMAND , IDD_RESIZE_TOGGLE_BUTTON , 0 ) ;
}
}
}
}
// 填充查找历史记录
void FindReplaceDlg : : fillFindHistory ( )
void FindReplaceDlg : : fillFindHistory ( )
{
{
NppParameters & nppParams = NppParameters : : getInstance ( ) ;
NppParameters & nppParams = NppParameters : : getInstance ( ) ;
FindHistory & findHistory = nppParams . getFindHistory ( ) ;
FindHistory & findHistory = nppParams . getFindHistory ( ) ;
// 填充各个 Combo Box 的历史记录
fillComboHistory ( IDFINDWHAT , findHistory . _findHistoryFinds ) ;
fillComboHistory ( IDFINDWHAT , findHistory . _findHistoryFinds ) ;
fillComboHistory ( IDREPLACEWITH , findHistory . _findHistoryReplaces ) ;
fillComboHistory ( IDREPLACEWITH , findHistory . _findHistoryReplaces ) ;
fillComboHistory ( IDD_FINDINFILES_FILTERS_COMBO , findHistory . _findHistoryFilters ) ;
fillComboHistory ( IDD_FINDINFILES_FILTERS_COMBO , findHistory . _findHistoryFilters ) ;
fillComboHistory ( IDD_FINDINFILES_DIR_COMBO , findHistory . _findHistoryPaths ) ;
fillComboHistory ( IDD_FINDINFILES_DIR_COMBO , findHistory . _findHistoryPaths ) ;
// 设置各个复选框的选中状态
: : SendDlgItemMessage ( _hSelf , IDWRAP , BM_SETCHECK , findHistory . _isWrap , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDWRAP , BM_SETCHECK , findHistory . _isWrap , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDWHOLEWORD , BM_SETCHECK , findHistory . _isMatchWord , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDWHOLEWORD , BM_SETCHECK , findHistory . _isMatchWord , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDMATCHCASE , BM_SETCHECK , findHistory . _isMatchCase , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDMATCHCASE , BM_SETCHECK , findHistory . _isMatchCase , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDC_BACKWARDDIRECTION , BM_SETCHECK , ! findHistory . _isDirectionDown , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDC_BACKWARDDIRECTION , BM_SETCHECK , ! findHistory . _isDirectionDown , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDD_FINDINFILES_INHIDDENDIR_CHECK , BM_SETCHECK , findHistory . _isFifInHiddenFolder , 0 ) ;
// 设置其他复选框的选中状态
: : SendDlgItemMessage ( _hSelf , IDD_FINDINFILES_RECURSIVE_CHECK , BM_SETCHECK , findHistory . _isFifRecuisive , 0 ) ;
// ...
: : SendDlgItemMessage ( _hSelf , IDD_FINDINFILES_FOLDERFOLLOWSDOC_CHECK , BM_SETCHECK , findHistory . _isFolderFollowDoc , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDD_FINDINFILES_PROJECT1_CHECK , BM_SETCHECK , findHistory . _isFifProjectPanel_1 , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDD_FINDINFILES_PROJECT2_CHECK , BM_SETCHECK , findHistory . _isFifProjectPanel_2 , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDD_FINDINFILES_PROJECT3_CHECK , BM_SETCHECK , findHistory . _isFifProjectPanel_3 , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDNORMAL , BM_SETCHECK , findHistory . _searchMode = = FindHistory : : normal , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDEXTENDED , BM_SETCHECK , findHistory . _searchMode = = FindHistory : : extended , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDREGEXP , BM_SETCHECK , findHistory . _searchMode = = FindHistory : : regExpr , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDREDOTMATCHNL , BM_SETCHECK , findHistory . _dotMatchesNewline , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDC_MARKLINE_CHECK , BM_SETCHECK , findHistory . _isBookmarkLine , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDC_PURGE_CHECK , BM_SETCHECK , findHistory . _isPurge , 0 ) ;
: : SendDlgItemMessage ( _hSelf , IDC_2_BUTTONS_MODE , BM_SETCHECK , findHistory . _isSearch2ButtonsMode , 0 ) ;
if ( findHistory . _searchMode = = FindHistory : : regExpr )
{
//regex doesn't allow wholeword
: : SendDlgItemMessage ( _hSelf , IDWHOLEWORD , BM_SETCHECK , BST_UNCHECKED , 0 ) ;
enableFindDlgItem ( IDWHOLEWORD , false ) ;
// regex upward search is disabled
: : SendDlgItemMessage ( _hSelf , IDC_BACKWARDDIRECTION , BM_SETCHECK , BST_UNCHECKED , 0 ) ;
enableFindDlgItem ( IDC_BACKWARDDIRECTION , nppParams . regexBackward4PowerUser ( ) ) ;
enableFindDlgItem ( IDC_FINDPREV , nppParams . regexBackward4PowerUser ( ) ) ;
// If the search mode from history is regExp then enable the checkbox (. matches newline)
enableFindDlgItem ( IDREDOTMATCHNL ) ;
}
// 如果系统支持透明度,则设置透明度相关控件的显示状态和属性
if ( nppParams . isTransparentAvailable ( ) )
if ( nppParams . isTransparentAvailable ( ) )
{
{
// 显示透明度相关控件
showFindDlgItem ( IDC_TRANSPARENT_CHECK ) ;
showFindDlgItem ( IDC_TRANSPARENT_CHECK ) ;
showFindDlgItem ( IDC_TRANSPARENT_GRPBOX ) ;
showFindDlgItem ( IDC_TRANSPARENT_GRPBOX ) ;
showFindDlgItem ( IDC_TRANSPARENT_LOSSFOCUS_RADIO ) ;
showFindDlgItem ( IDC_TRANSPARENT_LOSSFOCUS_RADIO ) ;
showFindDlgItem ( IDC_TRANSPARENT_ALWAYS_RADIO ) ;
showFindDlgItem ( IDC_TRANSPARENT_ALWAYS_RADIO ) ;
showFindDlgItem ( IDC_PERCENTAGE_SLIDER ) ;
showFindDlgItem ( IDC_PERCENTAGE_SLIDER ) ;
// 设置滑动条范围和位置
: : SendDlgItemMessage ( _hSelf , IDC_PERCENTAGE_SLIDER , TBM_SETRANGE , FALSE , MAKELONG ( 20 , 200 ) ) ;
: : SendDlgItemMessage ( _hSelf , IDC_PERCENTAGE_SLIDER , TBM_SETRANGE , FALSE , MAKELONG ( 20 , 200 ) ) ;
: : SendDlgItemMessage ( _hSelf , IDC_PERCENTAGE_SLIDER , TBM_SETPOS , TRUE , findHistory . _transparency ) ;
: : SendDlgItemMessage ( _hSelf , IDC_PERCENTAGE_SLIDER , TBM_SETPOS , TRUE , findHistory . _transparency ) ;
// 根据透明度模式设置相应的复选框选中状态
if ( findHistory . _transparencyMode = = FindHistory : : none )
if ( findHistory . _transparencyMode = = FindHistory : : none )
{
{
enableFindDlgItem ( IDC_TRANSPARENT_LOSSFOCUS_RADIO , false ) ;
enableFindDlgItem ( IDC_TRANSPARENT_LOSSFOCUS_RADIO , false ) ;
@ -436,44 +436,47 @@ void FindReplaceDlg::fillFindHistory()
{
{
id = IDC_TRANSPARENT_ALWAYS_RADIO ;
id = IDC_TRANSPARENT_ALWAYS_RADIO ;
( NppParameters : : getInstance ( ) ) . SetTransparent ( _hSelf , findHistory . _transparency ) ;
( NppParameters : : getInstance ( ) ) . SetTransparent ( _hSelf , findHistory . _transparency ) ;
}
}
: : SendDlgItemMessage ( _hSelf , id , BM_SETCHECK , TRUE , 0 ) ;
: : SendDlgItemMessage ( _hSelf , id , BM_SETCHECK , TRUE , 0 ) ;
}
}
}
}
}
}
// 填充 Combo Box 的历史记录
void FindReplaceDlg : : fillComboHistory ( int id , const vector < generic_string > & strings )
void FindReplaceDlg : : fillComboHistory ( int id , const vector < generic_string > & strings )
{
{
HWND hCombo = : : GetDlgItem ( _hSelf , id ) ;
HWND hCombo = : : GetDlgItem ( _hSelf , id ) ;
// 将历史记录添加到 Combo Box
for ( vector < generic_string > : : const_reverse_iterator i = strings . rbegin ( ) ; i ! = strings . rend ( ) ; + + i )
for ( vector < generic_string > : : const_reverse_iterator i = strings . rbegin ( ) ; i ! = strings . rend ( ) ; + + i )
{
{
addText2Combo ( i - > c_str ( ) , hCombo ) ;
addText2Combo ( i - > c_str ( ) , hCombo ) ;
}
}
// empty string is not added to CB items, so we need to set it manually
// 如果历史记录不为空且第一个元素为空字符串,则手动设置 Combo Box 文本为空
if ( ! strings . empty ( ) & & strings . begin ( ) - > empty ( ) )
if ( ! strings . empty ( ) & & strings . begin ( ) - > empty ( ) )
{
{
SetWindowText ( hCombo , _T ( " " ) ) ;
SetWindowText ( hCombo , _T ( " " ) ) ;
return ;
return ;
}
}
: : SendMessage ( hCombo , CB_SETCURSEL , 0 , 0 ) ; // select first item
: : SendMessage ( hCombo , CB_SETCURSEL , 0 , 0 ) ; // 选择第一项
}
}
// 保存查找历史记录
void FindReplaceDlg : : saveFindHistory ( )
void FindReplaceDlg : : saveFindHistory ( )
{
{
if ( ! isCreated ( ) ) return ;
if ( ! isCreated ( ) ) return ;
FindHistory & findHistory = ( NppParameters : : getInstance ( ) ) . getFindHistory ( ) ;
FindHistory & findHistory = ( NppParameters : : getInstance ( ) ) . getFindHistory ( ) ;
// 保存各个 Combo Box 的历史记录
saveComboHistory ( IDD_FINDINFILES_DIR_COMBO , findHistory . _nbMaxFindHistoryPath , findHistory . _findHistoryPaths , false ) ;
saveComboHistory ( IDD_FINDINFILES_DIR_COMBO , findHistory . _nbMaxFindHistoryPath , findHistory . _findHistoryPaths , false ) ;
saveComboHistory ( IDD_FINDINFILES_FILTERS_COMBO , findHistory . _nbMaxFindHistoryFilter , findHistory . _findHistoryFilters , true ) ;
saveComboHistory ( IDD_FINDINFILES_FILTERS_COMBO , findHistory . _nbMaxFindHistoryFilter , findHistory . _findHistoryFilters , true ) ;
saveComboHistory ( IDFINDWHAT , findHistory . _nbMaxFindHistoryFind , findHistory . _findHistoryFinds , false ) ;
saveComboHistory ( IDFINDWHAT , findHistory . _nbMaxFindHistoryFind , findHistory . _findHistoryFinds , false ) ;
saveComboHistory ( IDREPLACEWITH , findHistory . _nbMaxFindHistoryReplace , findHistory . _findHistoryReplaces , true ) ;
saveComboHistory ( IDREPLACEWITH , findHistory . _nbMaxFindHistoryReplace , findHistory . _findHistoryReplaces , true ) ;
}
}
// 保存 Combo Box 的历史记录
int FindReplaceDlg : : saveComboHistory ( int id , int maxcount , vector < generic_string > & strings , bool saveEmpty )
int FindReplaceDlg : : saveComboHistory ( int id , int maxcount , vector < generic_string > & strings , bool saveEmpty )
{
{
TCHAR text [ FINDREPLACE_MAXLENGTH ] = { ' \0 ' } ;
TCHAR text [ FINDREPLACE_MAXLENGTH ] = { ' \0 ' } ;
@ -485,6 +488,7 @@ int FindReplaceDlg::saveComboHistory(int id, int maxcount, vector<generic_string
strings . clear ( ) ;
strings . clear ( ) ;
// 如果允许保存空字符串,则检查 Combo Box 文本是否为空,并加入历史记录
if ( saveEmpty )
if ( saveEmpty )
{
{
if ( : : GetWindowTextLength ( hCombo ) = = 0 )
if ( : : GetWindowTextLength ( hCombo ) = = 0 )
@ -493,6 +497,7 @@ int FindReplaceDlg::saveComboHistory(int id, int maxcount, vector<generic_string
}
}
}
}
// 保存 Combo Box 中的文本到历史记录
for ( int i = 0 ; i < count ; + + i )
for ( int i = 0 ; i < count ; + + i )
{
{
auto cbTextLen = : : SendMessage ( hCombo , CB_GETLBTEXTLEN , i , 0 ) ;
auto cbTextLen = : : SendMessage ( hCombo , CB_GETLBTEXTLEN , i , 0 ) ;
@ -504,13 +509,14 @@ int FindReplaceDlg::saveComboHistory(int id, int maxcount, vector<generic_string
}
}
return count ;
return count ;
}
}
` ` `
//更新数据Combo
void FindReplaceDlg : : updateCombos ( )
void FindReplaceDlg : : updateCombos ( )
{
{
updateCombo ( IDREPLACEWITH ) ;
updateCombo ( IDREPLACEWITH ) ;
updateCombo ( IDFINDWHAT ) ;
updateCombo ( IDFINDWHAT ) ;
}
}
//
void FindReplaceDlg : : updateCombo ( int comboID )
void FindReplaceDlg : : updateCombo ( int comboID )
{
{
HWND hCombo = : : GetDlgItem ( _hSelf , comboID ) ;
HWND hCombo = : : GetDlgItem ( _hSelf , comboID ) ;
@ -725,162 +731,181 @@ bool Finder::canFind(const TCHAR *fileName, size_t lineNumber, size_t* indexToSt
// [ ] [ ] [ Y [ ] : pos_between 3
// [ ] [ ] [ Y [ ] : pos_between 3
// [ ] [ ] Y [ ] [ ] : pos_between 2
// [ ] [ ] Y [ ] [ ] : pos_between 2
// [ ] [ ] [ ] [ ] Y : pos_behind 4
// [ ] [ ] [ ] [ ] Y : pos_behind 4
下 面 是 对 代 码 的 详 细 注 释 :
` ` ` cpp
Finder : : CurrentPosInLineInfo Finder : : getCurrentPosInLineInfo ( intptr_t currentPosInLine , const SearchResultMarkingLine & markingLine ) const
Finder : : CurrentPosInLineInfo Finder : : getCurrentPosInLineInfo ( intptr_t currentPosInLine , const SearchResultMarkingLine & markingLine ) const
{
{
CurrentPosInLineInfo cpili ;
// 定义用于返回的结构体
size_t count = 0 ;
CurrentPosInLineInfo cpili ;
intptr_t lastEnd = 0 ;
// 初始化计数器count为0
auto selStart = _scintView . execute ( SCI_GETSELECTIONSTART ) ;
size_t count = 0 ;
auto selEnd = _scintView . execute ( SCI_GETSELECTIONEND ) ;
// 初始化上一个区间的结束位置为0
bool hasSel = ( selEnd - selStart ) ! = 0 ;
intptr_t lastEnd = 0 ;
// 获取当前文本框选择的起始位置和结束位置
for ( std : : pair < intptr_t , intptr_t > range : markingLine . _segmentPostions )
auto selStart = _scintView . execute ( SCI_GETSELECTIONSTART ) ;
{
auto selEnd = _scintView . execute ( SCI_GETSELECTIONEND ) ;
+ + count ;
// 判断是否有选择文本
bool hasSel = ( selEnd - selStart ) ! = 0 ;
if ( lastEnd < = currentPosInLine & & currentPosInLine < range . first )
{
// 遍历每个区间
if ( count = = 1 )
for ( std : : pair < intptr_t , intptr_t > range : markingLine . _segmentPostions )
{
{
cpili . _status = pos_infront ;
+ + count ;
break ;
}
// 判断当前位置在区间的前面
else
if ( lastEnd < = currentPosInLine & & currentPosInLine < range . first )
{
{
cpili . _status = pos_between ;
if ( count = = 1 )
cpili . auxiliaryInfo = count - 1 ;
{
break ;
cpili . _status = pos_infront ; // 在第一个区间的前面
}
break ;
}
}
else
if ( range . first < = currentPosInLine & & currentPosInLine < = range . second )
{
{
cpili . _status = pos_between ; // 在两个区间之间
if ( currentPosInLine = = range . first & & ! hasSel )
cpili . auxiliaryInfo = count - 1 ;
{
break ;
cpili . _status = pos_between ;
}
cpili . auxiliaryInfo = count - 1 ; // c1 c2
}
// [ ] I[ ] : I is recongnized with c2, so auxiliaryInfo should be c1 (c2-1)
}
// 判断当前位置在区间内部
else if ( currentPosInLine = = range . second & & ! hasSel )
if ( range . first < = currentPosInLine & & currentPosInLine < = range . second )
{
{
cpili . _status = pos_between ;
if ( currentPosInLine = = range . first & & ! hasSel )
cpili . auxiliaryInfo = count ; // c1 c2
{
// [ ]I [ ] : I is recongnized with c1, so auxiliaryInfo should be c1
cpili . _status = pos_between ; // 在区间的起始位置,在没有选择文本的情况下
}
cpili . auxiliaryInfo = count - 1 ;
else
}
{
else if ( currentPosInLine = = range . second & & ! hasSel )
cpili . _status = pos_inside ;
{
cpili . auxiliaryInfo = count ;
cpili . _status = pos_between ; // 在区间的结束位置,在没有选择文本的情况下
}
cpili . auxiliaryInfo = count ;
break ;
}
}
else
{
if ( range . second < currentPosInLine )
cpili . _status = pos_inside ; // 在区间内部
{
cpili . auxiliaryInfo = count ;
if ( markingLine . _segmentPostions . size ( ) = = count )
}
{
break ;
cpili . _status = pos_behind ;
}
cpili . auxiliaryInfo = count ;
break ;
// 判断当前位置在区间的后面
}
if ( range . second < currentPosInLine )
}
{
if ( markingLine . _segmentPostions . size ( ) = = count )
lastEnd = range . second ;
{
}
cpili . _status = pos_behind ; // 在最后一个区间的后面
cpili . auxiliaryInfo = count ;
break ;
}
}
lastEnd = range . second ;
}
return cpili ;
return cpili ;
}
}
void Finder : : anchorWithNoHeaderLines ( intptr_t & currentL , intptr_t initL , intptr_t minL , intptr_t maxL , int direction )
void Finder : : anchorWithNoHeaderLines ( intptr_t & currentL , intptr_t initL , intptr_t minL , intptr_t maxL , int direction )
{
{
if ( currentL > maxL & & direction = = 0 )
// 如果当前行大于最大行并且方向为0, 则将当前行设置为最小行
currentL = minL ;
if ( currentL > maxL & & direction = = 0 )
currentL = minL ;
while ( _scintView . execute ( SCI_GETFOLDLEVEL , currentL ) & SC_FOLDLEVELHEADERFLAG )
{
// 循环直到当前行不是折叠标题行
currentL + = direction = = - 1 ? - 1 : 1 ;
while ( _scintView . execute ( SCI_GETFOLDLEVEL , currentL ) & SC_FOLDLEVELHEADERFLAG )
{
if ( currentL > maxL )
// 根据方向更新当前行
currentL = minL ;
currentL + = direction = = - 1 ? - 1 : 1 ;
else if ( currentL < minL )
currentL = maxL ;
// 如果当前行超过最大行,则将当前行设置为最小行
if ( currentL > maxL )
if ( currentL = = initL )
currentL = minL ;
break ;
// 如果当前行低于最小行,则将当前行设置为最大行
}
else if ( currentL < minL )
currentL = maxL ;
// 如果当前行等于初始行,则跳出循环
if ( currentL = = initL )
break ;
}
auto extremityAbsoltePos = _scintView . execute ( direction = = - 1 ? SCI_GETLINEENDPOSITION : SCI_POSITIONFROMLINE , currentL ) ;
// 获取当前行的绝对位置
_scintView . execute ( SCI_SETSEL , extremityAbsoltePos , extremityAbsoltePos ) ;
auto extremityAbsoltePos = _scintView . execute ( direction = = - 1 ? SCI_GETLINEENDPOSITION : SCI_POSITIONFROMLINE , currentL ) ;
// 设置选择范围为当前行的绝对位置
_scintView . execute ( SCI_SETSEL , extremityAbsoltePos , extremityAbsoltePos ) ;
}
}
void Finder : : gotoNextFoundResult ( int direction )
void Finder : : gotoNextFoundResult ( int direction )
{
{
//
// 获取当前光标位置及所在行号
// Get currentLine & currentPosInLine from CurrentPos
auto currentPos = _scintView . execute ( SCI_GETCURRENTPOS ) ;
//
intptr_t lno = _scintView . execute ( SCI_LINEFROMPOSITION , currentPos ) ;
auto currentPos = _scintView . execute ( SCI_GETCURRENTPOS ) ;
auto total_lines = _scintView . execute ( SCI_GETLINECOUNT ) ;
intptr_t lno = _scintView . execute ( SCI_LINEFROMPOSITION , currentPos ) ;
// 如果总行数小于等于1, 则直接返回
auto total_lines = _scintView . execute ( SCI_GETLINECOUNT ) ;
if ( total_lines < = 1 ) return ;
if ( total_lines < = 1 ) return ;
// 获取当前行的起始位置和光标在行内的位置
auto lineStartAbsPos = _scintView . execute ( SCI_POSITIONFROMLINE , lno ) ;
auto lineStartAbsPos = _scintView . execute ( SCI_POSITIONFROMLINE , lno ) ;
intptr_t currentPosInLine = currentPos - lineStartAbsPos ;
intptr_t currentPosInLine = currentPos - lineStartAbsPos ;
auto init_lno = lno ;
auto init_lno = lno ;
auto max_lno = _scintView . execute ( SCI_GETLASTCHILD , lno , searchHeaderLevel ) ;
auto max_lno = _scintView . execute ( SCI_GETLASTCHILD , lno , searchHeaderLevel ) ;
assert ( max_lno < = total_lines - 2 ) ;
// 获取当前搜索行号( searchHeaderLevel)
int level = _scintView . execute ( SCI_GETFOLDLEVEL , lno ) & SC_FOLDLEVELNUMBERMASK ;
auto min_lno = lno ;
while ( level - - > = fileHeaderLevel )
{
min_lno = _scintView . execute ( SCI_GETFOLDPARENT , min_lno ) ;
assert ( min_lno > = 0 ) ;
}
assert ( max_lno < = total_lines - 2 ) ;
if ( min_lno < 0 ) min_lno = lno ; // 当lno是一个搜索标题行时
// get the line number of the current search (searchHeaderLevel)
assert ( min_lno < = max_lno ) ;
int level = _scintView . execute ( SCI_GETFOLDLEVEL , lno ) & SC_FOLDLEVELNUMBERMASK ;
auto min_lno = lno ;
while ( level - - > = fileHeaderLevel )
{
min_lno = _scintView . execute ( SCI_GETFOLDPARENT , min_lno ) ;
assert ( min_lno > = 0 ) ;
}
if ( min_lno < 0 ) min_lno = lno ; // when lno is a search header line
// 根据方向更新当前行号
if ( lno > max_lno & & direction = = 0 ) lno = min_lno ;
else if ( lno < min_lno ) lno = max_lno ;
assert ( min_lno < = max_lno ) ;
// 设置锚点,确保锚点不在最后一行或折叠标题行上
while ( _scintView . execute ( SCI_GETFOLDLEVEL , lno ) & SC_FOLDLEVELHEADERFLAG )
{
lno + = direction = = - 1 ? - 1 : 1 ;
if ( lno > max_lno & & direction = = 0 ) lno = min_lno ;
if ( lno > max_lno )
else if ( lno < min_lno ) lno = max_lno ;
lno = min_lno ;
else if ( lno < min_lno )
lno = max_lno ;
//
if ( lno = = init_lno )
// Set anchor and make sure that achor is not on the last (empty) line or head lines
break ;
//
}
while ( _scintView . execute ( SCI_GETFOLDLEVEL , lno ) & SC_FOLDLEVELHEADERFLAG )
{
lno + = direction = = - 1 ? - 1 : 1 ;
if ( lno > max_lno )
lno = min_lno ;
else if ( lno < min_lno )
lno = max_lno ;
if ( lno = = init_lno )
break ;
}
if ( lno ! = init_lno )
// 如果当前行与初始行不同
{
if ( lno ! = init_lno )
auto extremityAbsoltePos = _scintView . execute ( direction = = - 1 ? SCI_GETLINEENDPOSITION : SCI_POSITIONFROMLINE , lno ) ;
{
_scintView . execute ( SCI_SETSEL , extremityAbsoltePos , extremityAbsoltePos ) ;
// 获取当前行的绝对位置
currentPos = extremityAbsoltePos ;
auto extremityAbsoltePos = _scintView . execute ( direction = = - 1 ? SCI_GETLINEENDPOSITION : SCI_POSITIONFROMLINE , lno ) ;
auto start = _scintView . execute ( SCI_POSITIONFROMLINE , lno ) ;
// 设置选择范围为当前行的绝对位置
currentPosInLine = currentPos - start ;
_scintView . execute ( SCI_SETSEL , extremityAbsoltePos , extremityAbsoltePos ) ;
}
currentPos = extremityAbsoltePos ;
// 获取当前行的起始位置和光标在行内的位置
auto start = _scintView . execute ( SCI_POSITIONFROMLINE , lno ) ;
currentPosInLine = currentPos - start ;
}
size_t n = 0 ;
const SearchResultMarkingLine & markingLine = * ( _pMainMarkings - > begin ( ) + lno ) ;
size_t n = 0 ;
// 获取当前位置在行内的状态
const SearchResultMarkingLine & markingLine = * ( _pMainMarkings - > begin ( ) + lno ) ;
CurrentPosInLineInfo cpili = getCurrentPosInLineInfo ( currentPosInLine , markingLine ) ;
//
// 根据方向和当前
// Determinate currentPosInLine status among pos_infront, pose_between, pos_inside and pos_behind
//
CurrentPosInLineInfo cpili = getCurrentPosInLineInfo ( currentPosInLine , markingLine ) ;
//
//
// According CurrentPosInLineInfo and direction, set position and get number of occurrence
// According CurrentPosInLineInfo and direction, set position and get number of occurrence