Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,024 changes: 910 additions & 114 deletions sakura_core/agent/CGrepAgent.cpp

Large diffs are not rendered by default.

78 changes: 74 additions & 4 deletions sakura_core/agent/CGrepAgent.h
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
/*! @file */
/*! @file */
/*
Copyright (C) 2008, kobake
Copyright (C) 2018-2022, Sakura Editor Organization
Copyright (C) 2018-2026, Sakura Editor Organization

SPDX-License-Identifier: Zlib
*/
#ifndef SAKURA_CGREPAGENT_97F2B632_71C8_4E4A_AC42_13A6098B248F_H_
#define SAKURA_CGREPAGENT_97F2B632_71C8_4E4A_AC42_13A6098B248F_H_
#pragma once

#include <atomic>
#include <string>
#include <vector>
#include "doc/CDocListener.h"
#include "extmodule/CBregexp.h"
class CDlgCancel;
class CEditView;
class CSearchStringPattern;
class CGrepEnumKeys;
class CGrepEnumFiles;
class CGrepEnumFolders;

//! 並列Grep処理で使用するファイルタスク情報
// 1 ファイルを 1 タスクとして扱い、検索対象の実体情報と表示用文字列を分けて保持する。
struct SGrepFileTask {
std::wstring fullPath; //!< 処理対象ファイルのフルパス
std::wstring fileName; //!< ファイル名(タイプ別設定取得用)
std::wstring baseFolder; //!< ベースフォルダー
std::wstring folder; //!< 表示用フォルダー(bGrepSeparateFolder時)
std::wstring relPath; //!< 相対パス(bGrepSeparateFolder時はファイル名のみ)
};

struct SGrepOption{
bool bGrepReplace; //!< Grep置換
bool bGrepSubFolder; //!< サブフォルダーからも検索する
Expand Down Expand Up @@ -57,6 +71,34 @@ class CGrepAgent : public CDocListenerEx{
ECallbackResult OnBeforeClose() override;
void OnAfterSave(const SSaveInfo& sSaveInfo) override;

//! 検索結果 1 件分のフォーマット生成(HWND 非依存)
static void FormatGrepResultLine(
CNativeW& cmemMessage,
const WCHAR* pszFilePath,
const WCHAR* pszCodeName,
LONGLONG nLine,
int nColumn,
const wchar_t* pCompareData,
int nLineLen,
int nEolCodeLen,
const wchar_t* pMatchData,
int nMatchLen,
const SGrepOption& sGrepOption
);

//! 結果ヘッダ生成("検索条件 ...")
static CNativeW BuildGrepHeader(
const wchar_t* pszKey,
const wchar_t* pszFile,
const wchar_t* pszFolder,
const SSearchOption& sSearchOption,
const SGrepOption& sGrepOption,
const wchar_t* pszReplace = nullptr
);

//! 結果フッタ生成("該当 N 件" / "N 件を置換")
static CNativeW BuildGrepFooter(int nHitCount, bool bGrepReplace = false);

static void CreateFolders( const WCHAR* pszPath, std::vector<std::wstring>& vPaths );
static std::wstring ChopYen( const std::wstring& str );
void AddTail( CEditView* pcEditView, const CNativeW& cmem, bool bAddStdout );
Expand Down Expand Up @@ -84,6 +126,20 @@ class CGrepAgent : public CDocListenerEx{
bool bGrepBackup
);

// 並列 Grep のワーカー本体。UI に触れず、1 ファイル分の検索だけを担当する。
// テストから直接呼び出せるように public 化。
int DoGrepFileWorker(
const SGrepFileTask& task,
const wchar_t* pszKey,
const SSearchOption& sSearchOption,
const SGrepOption& sGrepOption,
CBregexp* pLocalRegexp,
const CSearchStringPattern& localPattern,
CNativeW& cmemMessage,
CNativeW& cUnicodeBuffer,
const std::atomic<bool>& bCancelled
);

private:
// Grep実行
int DoGrepTree(
Expand All @@ -100,11 +156,11 @@ class CGrepAgent : public CDocListenerEx{
const SGrepOption& sGrepOption, //!< [in] Grepオプション
const CSearchStringPattern& pattern, //!< [in] 検索パターン
CBregexp* pRegexp, //!< [in] 正規表現コンパイルデータ。既にコンパイルされている必要がある
int nNest, //!< [in] ネストレベル
bool& bOutputBaseFolder,
int* pnHitCount, //!< [i/o] ヒット数の合計
CNativeW& cmemMessage,
CNativeW& cUnicodeBuffer
CNativeW& cUnicodeBuffer,
std::vector<CBregexp>* pExclRegexps = nullptr //!< [in] コンパイル済み除外正規表現(再帰呼び出し用・nullptrなら内部でコンパイル)
);

// Grep実行
Expand Down Expand Up @@ -170,6 +226,20 @@ class CGrepAgent : public CDocListenerEx{
const SGrepOption& sGrepOption
);

// ファイル列挙(メインスレッド用・キャンセル対応)
// 検索は行わず、ワーカーへ渡すタスクだけを作る。
void DoGrepTreeEnumerate(
CDlgCancel* pcDlgCancel,
CGrepEnumKeys& cGrepEnumKeys,
CGrepEnumFiles& cGrepExceptAbsFiles,
CGrepEnumFolders& cGrepExceptAbsFolders,
const WCHAR* pszPath,
const WCHAR* pszBasePath,
const SGrepOption& sGrepOption,
std::vector<SGrepFileTask>& vecTasks,
bool& bCancelled
);

DWORD m_dwTickAddTail = 0; // AddTail() を呼び出した時間
DWORD m_dwTickUICheck = 0; // 処理中にユーザーによるUI操作が行われていないか確認した時間
DWORD m_dwTickUIFileName = 0; // Cancelダイアログのファイル名表示更新を行った時間
Expand Down
108 changes: 65 additions & 43 deletions sakura_core/dlg/CDlgGrep.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! @file
/*! @file
@brief GREPダイアログボックス

@author Norio Nakatani
Expand All @@ -11,7 +11,7 @@
Copyright (C) 2006, ryoji
Copyright (C) 2010, ryoji
Copyright (C) 2012, Uchi
Copyright (C) 2018-2022, Sakura Editor Organization
Copyright (C) 2018-2026, Sakura Editor Organization

This source code is designed for sakura editor.
Please contact the copyright holder to use this code for other purpose.
Expand Down Expand Up @@ -170,7 +170,8 @@ static void AppendExcludeFilePatterns(CNativeW& cFilePattern, const CNativeW& cm
CNativeW CDlgGrep::GetPackedGFileString() const
{
// ダイアログデータを取得
CNativeW cmFilePattern( m_szFile );
// ファイルパターンが空なら UI 既定値の "*.*" を補って、検索対象なしの状態を避ける。
CNativeW cmFilePattern( m_szFile[0] != L'\0' ? m_szFile : L"*.*" );
CNativeW cmExcludeFiles( m_szExcludeFile );
CNativeW cmExcludeFolders( m_szExcludeFolder );

Expand Down Expand Up @@ -257,33 +258,8 @@ int CDlgGrep::DoModal( HINSTANCE hInstance, HWND hwndParent, const WCHAR* pszCur
wcscpy( m_szFolder, m_pShareData->m_sSearchKeywords.m_aGrepFolders[0] ); /* 検索フォルダー */
}

/* 除外ファイル */
if (m_szExcludeFile[0] == L'\0') {
if (m_pShareData->m_sSearchKeywords.m_aExcludeFiles.size()) {
wcscpy(m_szExcludeFile, m_pShareData->m_sSearchKeywords.m_aExcludeFiles[0]);
}
else {
/* ユーザーの利便性向上のために除外ファイルに対して初期値を設定する */
wcscpy(m_szExcludeFile, DEFAULT_EXCLUDE_FILE_PATTERN); /* 除外ファイル */

/* 履歴に残して後で選択できるようにする */
m_pShareData->m_sSearchKeywords.m_aExcludeFiles.push_back(DEFAULT_EXCLUDE_FILE_PATTERN);
}
}

/* 除外フォルダー */
if (m_szExcludeFolder[0] == L'\0') {
if (m_pShareData->m_sSearchKeywords.m_aExcludeFolders.size()) {
wcscpy(m_szExcludeFolder, m_pShareData->m_sSearchKeywords.m_aExcludeFolders[0]);
}
else {
/* ユーザーの利便性向上のために除外フォルダーに対して初期値を設定する */
wcscpy(m_szExcludeFolder, DEFAULT_EXCLUDE_FOLDER_PATTERN); /* 除外フォルダー */

/* 履歴に残して後で選択できるようにする */
m_pShareData->m_sSearchKeywords.m_aExcludeFolders.push_back(DEFAULT_EXCLUDE_FOLDER_PATTERN);
}
}
/* 除外ファイル / 除外フォルダー */
DetermineDefaultExcludePatterns();

if( pszCurrentFilePath ){ // 2010.01.10 ryoji
wcscpy(m_szCurrentFilePath, pszCurrentFilePath);
Expand Down Expand Up @@ -739,8 +715,7 @@ void CDlgGrep::SetDataFromThisText( bool bChecked )
ApiWrap::DlgItem_SetText( GetHwnd(), IDC_COMBO_EXCLUDE_FOLDER, L"" );
bEnableControls = FALSE;
}else{
std::wstring strFile(m_szFile);
if (strFile.substr(0, 6) == L":HWND:") {
if (IsHwndFileToken(m_szFile)) {
wcsncpy_s(m_szFile, std::size(m_szFile), L"*.*", _TRUNCATE);
}
ApiWrap::DlgItem_SetText(GetHwnd(), IDC_COMBO_FILE, m_szFile);
Expand Down Expand Up @@ -825,16 +800,9 @@ int CDlgGrep::GetData( void )
ApiWrap::DlgItem_GetText( GetHwnd(), IDC_COMBO_FILE, m_szFile, std::size(m_szFile) );
bool bFromThisText = IsDlgButtonCheckedBool(GetHwnd(), IDC_CHK_FROMTHISTEXT);
if( bFromThisText ){
WCHAR szHwnd[_MAX_PATH];
#ifdef _WIN64
auto_sprintf(szHwnd, L":HWND:%016I64x", ::GetParent(GetHwnd()));
#else
auto_sprintf(szHwnd, L":HWND:%08x", ::GetParent(GetHwnd()));
#endif
m_szFile = szHwnd;
wcscpy(m_szFile, BuildHwndFileToken(::GetParent(GetHwnd())).c_str());
}else{
std::wstring strFile(m_szFile);
if (strFile.substr(0, 6) == L":HWND:") {
if (IsHwndFileToken(m_szFile)) {
ErrorMessage(GetHwnd(), LS(STR_DLGGREP_THISDOC_ERROR));
return FALSE;
}
Expand Down Expand Up @@ -929,12 +897,16 @@ int CDlgGrep::GetData( void )
}
// To Here Jun. 26, 2001 genta 正規表現ライブラリ差し替え
if( m_strText.size() < _MAX_PATH ){
CSearchKeywordManager().AddToSearchKeyArr( m_strText.c_str() );
if( !m_bFromThisText ){
CSearchKeywordManager().AddToSearchKeyArr( m_strText.c_str() );
}
m_pShareData->m_Common.m_sSearch.m_sSearchOption = m_sSearchOption; // 検索オプション
}
}else{
// 2014.07.01 空キーも登録する
CSearchKeywordManager().AddToSearchKeyArr( L"" );
if( !m_bFromThisText ){
CSearchKeywordManager().AddToSearchKeyArr( L"" );
}
}

// この編集中のテキストから検索する場合、履歴に残さない Uchi 2008/5/23
Expand Down Expand Up @@ -976,3 +948,53 @@ static void SetGrepFolder( HWND hwndCtrl, LPCWSTR folder )
::SetWindowText( hwndCtrl, folder );
}
}

void CDlgGrep::DetermineDefaultExcludePatterns()
{
// 初期表示とテストで共通に使う、除外パターンの既定値補完ロジック。
/* 除外ファイル */
if (m_szExcludeFile[0] == L'\0') {
if (m_pShareData->m_sSearchKeywords.m_aExcludeFiles.size()) {
wcscpy(m_szExcludeFile, m_pShareData->m_sSearchKeywords.m_aExcludeFiles[0]);
}
else {
/* ユーザーの利便性向上のために除外ファイルに対して初期値を設定する */
wcscpy(m_szExcludeFile, DEFAULT_EXCLUDE_FILE_PATTERN); /* 除外ファイル */

/* 履歴に残して後で選択できるようにする */
m_pShareData->m_sSearchKeywords.m_aExcludeFiles.push_back(DEFAULT_EXCLUDE_FILE_PATTERN);
}
}

/* 除外フォルダー */
if (m_szExcludeFolder[0] == L'\0') {
if (m_pShareData->m_sSearchKeywords.m_aExcludeFolders.size()) {
wcscpy(m_szExcludeFolder, m_pShareData->m_sSearchKeywords.m_aExcludeFolders[0]);
}
else {
/* ユーザーの利便性向上のために除外フォルダーに対して初期値を設定する */
wcscpy(m_szExcludeFolder, DEFAULT_EXCLUDE_FOLDER_PATTERN); /* 除外フォルダー */

/* 履歴に残して後で選択できるようにする */
m_pShareData->m_sSearchKeywords.m_aExcludeFolders.push_back(DEFAULT_EXCLUDE_FOLDER_PATTERN);
}
}
}

std::wstring CDlgGrep::BuildHwndFileToken(HWND hwnd)
{
// HWND を 16 進の文字列にして、コンボボックス内の擬似ファイル名として保持する。
WCHAR buf[_MAX_PATH];
#ifdef _WIN64
auto_sprintf(buf, L":HWND:%016I64x", reinterpret_cast<uintptr_t>(hwnd));
#else
auto_sprintf(buf, L":HWND:%08x", reinterpret_cast<uintptr_t>(hwnd));
#endif
return std::wstring(buf);
}

bool CDlgGrep::IsHwndFileToken(const wchar_t* s)
{
// 実際の値比較ではなく、特別な擬似ファイル名であるかどうかだけを判定する。
return s != nullptr && wcsncmp(s, L":HWND:", 6) == 0;
}
17 changes: 14 additions & 3 deletions sakura_core/dlg/CDlgGrep.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! @file
/*! @file
@brief GREPダイアログボックス

@author Norio Nakatani
Expand All @@ -8,7 +8,7 @@
/*
Copyright (C) 1998-2001, Norio Nakatani
Copyright (C) 2002, Moca
Copyright (C) 2018-2022, Sakura Editor Organization
Copyright (C) 2018-2026, Sakura Editor Organization

This source code is designed for sakura editor.
Please contact the copyright holder to use this code for other purpose.
Expand All @@ -25,7 +25,8 @@
#include "recent/CRecentExcludeFile.h"
#include "recent/CRecentExcludeFolder.h"

#define DEFAULT_EXCLUDE_FILE_PATTERN L"*.msi;*.exe;*.obj;*.pdb;*.ilk;*.res;*.pch;*.iobj;*.ipdb"
// 除外ファイルパターン(正規表現、フルパスに対してマッチング)
#define DEFAULT_EXCLUDE_FILE_PATTERN L".*\\.msi$;.*\\.exe$;.*\\.obj$;.*\\.pdb$;.*\\.ilk$;.*\\.res$;.*\\.pch$;.*\\.iobj$;.*\\.ipdb$"
#define DEFAULT_EXCLUDE_FOLDER_PATTERN L".git;.svn;.vs"

//! GREPダイアログボックス
Expand All @@ -44,6 +45,16 @@ class CDlgGrep : public CDialog
int DoModal( HINSTANCE, HWND, const WCHAR* ); /* モーダルダイアログの表示 */
// HWND DoModeless( HINSTANCE, HWND, const char* ); /* モードレスダイアログの表示 */

//! 除外パターンの初期値を決定する
// 履歴が空なら既定値を補い、次回以降に選べるよう履歴にも積む。
void DetermineDefaultExcludePatterns();

//! HWND ファイルトークンの生成と判定(":HWND:..." 形式)
// 「編集中のテキストから検索」時の擬似ファイル名として使う。
static std::wstring BuildHwndFileToken(HWND hwnd);
// 実ファイルパスと区別するため、接頭辞だけを見て判定する。
static bool IsHwndFileToken(const wchar_t* s);

bool m_bEnableThisText;
bool m_bSelectOnceThisText;
BOOL m_bSubFolder;/*!< サブフォルダーからも検索する */
Expand Down
4 changes: 4 additions & 0 deletions sakura_core/tests1.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@
<ClCompile Include="..\src\test\cpp\tests1\test-file.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-charcode.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-format.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-cdlggrep.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-cgrepagent-flow.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-grep-irregular.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-grep.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-grepinfo.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-int2dec.cpp" />
<ClCompile Include="..\src\test\cpp\tests1\test-is_mailaddress.cpp" />
Expand Down
12 changes: 12 additions & 0 deletions sakura_core/tests1.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@
<ClCompile Include="..\src\test\cpp\tests1\test-format.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="..\src\test\cpp\tests1\test-cdlggrep.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="..\src\test\cpp\tests1\test-cgrepagent-flow.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="..\src\test\cpp\tests1\test-grep-irregular.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="..\src\test\cpp\tests1\test-grep.cpp">
<Filter>Test Files</Filter>
</ClCompile>
<ClCompile Include="..\src\test\cpp\tests1\test-cwordparse.cpp">
<Filter>Test Files</Filter>
</ClCompile>
Expand Down
Loading
Loading