From b5e2bc33ed6b34c6e92dc15b095592c06e5d57dd Mon Sep 17 00:00:00 2001 From: rate Date: Wed, 4 Mar 2020 23:20:13 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Grep=E3=82=A6=E3=82=A3=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=A6=E3=81=AB=E3=80=8Cripgrep=E3=82=92=E4=BD=BF=E3=81=86?= =?UTF-8?q?=E3=80=8D=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sakura/sakura.vcxproj | 2 ++ sakura/sakura.vcxproj.filters | 6 ++++ sakura_core/Makefile | 1 + sakura_core/dlg/CDlgGrep.cpp | 54 +++++++++++++++++++++++++++++ sakura_core/dlg/CDlgGrep.h | 2 ++ sakura_core/env/CShareData_IO.cpp | 1 + sakura_core/env/CommonSetting.h | 2 ++ sakura_core/extmodule/CRipgrep.cpp | 55 ++++++++++++++++++++++++++++++ sakura_core/extmodule/CRipgrep.h | 42 +++++++++++++++++++++++ sakura_core/sakura.hh | 1 + sakura_core/sakura_rc.h | 1 + sakura_core/sakura_rc.rc | 1 + 12 files changed, 168 insertions(+) create mode 100644 sakura_core/extmodule/CRipgrep.cpp create mode 100644 sakura_core/extmodule/CRipgrep.h diff --git a/sakura/sakura.vcxproj b/sakura/sakura.vcxproj index 4a962cbf47..c586be9acc 100644 --- a/sakura/sakura.vcxproj +++ b/sakura/sakura.vcxproj @@ -416,6 +416,7 @@ + @@ -783,6 +784,7 @@ + diff --git a/sakura/sakura.vcxproj.filters b/sakura/sakura.vcxproj.filters index 205b9f2b03..d0f848c2d4 100644 --- a/sakura/sakura.vcxproj.filters +++ b/sakura/sakura.vcxproj.filters @@ -1097,6 +1097,9 @@ Cpp Source Files + + Cpp Source Files\extmodule + @@ -2276,6 +2279,9 @@ Cpp Source Files + + Cpp Source Files\extmodule + diff --git a/sakura_core/Makefile b/sakura_core/Makefile index a2a250e456..fd5810e34b 100644 --- a/sakura_core/Makefile +++ b/sakura_core/Makefile @@ -233,6 +233,7 @@ extmodule/CDllHandler.o \ extmodule/CHtmlHelp.o \ extmodule/CIcu4cI18n.o \ extmodule/CMigemo.o \ +extmodule/CRipgrep.o \ extmodule/CUxTheme.o \ func/CFuncKeyWnd.o \ func/CFuncLookup.o \ diff --git a/sakura_core/dlg/CDlgGrep.cpp b/sakura_core/dlg/CDlgGrep.cpp index d826edf958..e563848da8 100644 --- a/sakura_core/dlg/CDlgGrep.cpp +++ b/sakura_core/dlg/CDlgGrep.cpp @@ -28,6 +28,7 @@ #include "util/window.h" #include "env/DLLSHAREDATA.h" #include "env/CSakuraEnvironment.h" +#include "extmodule/CRipgrep.h" #include "sakura_rc.h" #include "sakura.hh" @@ -61,6 +62,7 @@ const DWORD p_helpids[] = { //12000 IDC_CHECK_FILE_ONLY, HIDC_CHECK_FILE_ONLY, //ファイル毎最初のみ検索 IDC_CHECK_BASE_PATH, HIDC_CHECK_BASE_PATH, //ベースフォルダ表示 IDC_CHECK_SEP_FOLDER, HIDC_CHECK_SEP_FOLDER, //フォルダ毎に表示 + IDC_CHK_USERIPGREP, HIDC_CHK_USERIPGREP, //ripgrepを使う // IDC_STATIC, -1, 0, 0 }; //@@@ 2002.01.07 add end MIK @@ -78,6 +80,7 @@ CDlgGrep::CDlgGrep() m_bGrepOutputFileOnly = false; m_bGrepOutputBaseFolder = false; m_bGrepSeparateFolder = false; + m_bUseRipgrep = false; m_bSetText = false; m_szFile[0] = 0; @@ -150,6 +153,7 @@ int CDlgGrep::DoModal( HINSTANCE hInstance, HWND hwndParent, const WCHAR* pszCur m_bGrepOutputFileOnly = m_pShareData->m_Common.m_sSearch.m_bGrepOutputFileOnly; m_bGrepOutputBaseFolder = m_pShareData->m_Common.m_sSearch.m_bGrepOutputBaseFolder; m_bGrepSeparateFolder = m_pShareData->m_Common.m_sSearch.m_bGrepSeparateFolder; + m_bUseRipgrep = m_pShareData->m_Common.m_sSearch.m_bUseRipgrep; // 2013.05.21 コンストラクタからDoModalに移動 // m_strText は呼び出し元で設定済み @@ -454,6 +458,16 @@ BOOL CDlgGrep::OnBnClicked( int wID ) ::EnableWindow( GetItemHwnd( IDC_CHECK_SEP_FOLDER ),TRUE ); } break; + case IDC_CHK_USERIPGREP: + if (ExistRipgrep()) { + SetUseripgrep(0 != ::IsDlgButtonChecked(GetHwnd(), IDC_CHK_USERIPGREP)); + } + else { + // rg.exeが存在していなければチェックできないようにする + ::CheckDlgButton(GetHwnd(), IDC_CHK_USERIPGREP, 0); + SetUseripgrep(false); + } + break; case IDOK: /* ダイアログデータの取得 */ if( GetData() ){ @@ -604,6 +618,17 @@ void CDlgGrep::SetData( void ) // フォルダの初期値をカレントフォルダにする ::CheckDlgButton( GetHwnd(), IDC_CHK_DEFAULTFOLDER, m_pShareData->m_Common.m_sSearch.m_bGrepDefaultFolder ); + //ripgrepが使えるか + if (ExistRipgrep()) { + ::CheckDlgButton(GetHwnd(), IDC_CHK_USERIPGREP, m_bUseRipgrep); + SetUseripgrep(m_bUseRipgrep); + } + else { + // rg.exeが存在していなければチェックできないようにする + ::CheckDlgButton(GetHwnd(), IDC_CHK_USERIPGREP, 0); + SetUseripgrep(false); + } + return; } @@ -634,6 +659,31 @@ void CDlgGrep::SetDataFromThisText( bool bChecked ) return; } +/*! + ripgrepを使うチェックでの設定 +*/ +void CDlgGrep::SetUseripgrep(bool bChecked ) +{ + int nUnsupported[] = { + IDC_CHK_SUBFOLDER, // サブフォルダからも検索する + IDC_CHK_FROMTHISTEXT, // 現在編集中のファイルから検索 + IDC_CHECK_FILE_ONLY, // ファイル毎最初のみ検索 + IDC_CHECK_SEP_FOLDER, // フォルダ毎に表示 + IDC_CHECK_BASE_PATH, // ベースフォルダ表示 + IDC_RADIO_OUTPUTLINE, // 結果出力:該当行 + IDC_RADIO_OUTPUTMARKED, // 結果出力:該当部分 + IDC_RADIO_NOHIT, // 結果出力:否該当行 + IDC_RADIO_OUTPUTSTYLE1, // 結果出力形式:ノーマル + IDC_RADIO_OUTPUTSTYLE2, // 結果出力形式:ファイル毎 + IDC_RADIO_OUTPUTSTYLE3 // 結果出力形式:結果のみ + }; + + for ( auto hwnd : nUnsupported) { + ::EnableWindow(GetItemHwnd(hwnd), !bChecked); + } + return; +} + /*! ダイアログデータの取得 @retval TRUE 正常 @retval FALSE 入力エラー @@ -656,6 +706,9 @@ int CDlgGrep::GetData( void ) /* 正規表現 */ m_sSearchOption.bRegularExp = (0!=::IsDlgButtonChecked( GetHwnd(), IDC_CHK_REGULAREXP )); + /* ripgrepを使う */ + m_bUseRipgrep = (0!=::IsDlgButtonChecked( GetHwnd(), IDC_CHK_USERIPGREP )); + /* 文字コード自動判別 */ // m_bKanjiCode_AutoDetect = ::IsDlgButtonChecked( GetHwnd(), IDC_CHK_KANJICODEAUTODETECT ); @@ -712,6 +765,7 @@ int CDlgGrep::GetData( void ) m_pShareData->m_Common.m_sSearch.m_bGrepOutputFileOnly = m_bGrepOutputFileOnly; m_pShareData->m_Common.m_sSearch.m_bGrepOutputBaseFolder = m_bGrepOutputBaseFolder; m_pShareData->m_Common.m_sSearch.m_bGrepSeparateFolder = m_bGrepSeparateFolder; + m_pShareData->m_Common.m_sSearch.m_bUseRipgrep = m_bUseRipgrep; if( 0 != wcslen( m_szFile ) ){ CGrepEnumKeys enumKeys; diff --git a/sakura_core/dlg/CDlgGrep.h b/sakura_core/dlg/CDlgGrep.h index 69432e6a9c..c6a146e030 100644 --- a/sakura_core/dlg/CDlgGrep.h +++ b/sakura_core/dlg/CDlgGrep.h @@ -40,6 +40,7 @@ class CDlgGrep : public CDialog BOOL m_bSubFolder;/*!< サブフォルダからも検索する */ BOOL m_bFromThisText;/*!< この編集中のテキストから検索する */ + BOOL m_bUseRipgrep;//! +#include +#include +#include "CRipgrep.h" +#include "charset/charcode.h" +#include "env/CShareData.h" +#include "env/DLLSHAREDATA.h" + + +CRipgrep::CRipgrep() +{ +} + +CRipgrep::~CRipgrep() +{ +} + + +//rg.exeの存在チェック +bool ExistRipgrep() +{ + WCHAR cmdline[1024]; + WCHAR szExeFolder[_MAX_PATH + 1]; + + GetExedir( cmdline, RIPGREP_COMMAND ); + SplitPath_FolderAndFile( cmdline, szExeFolder, NULL ); + + return ( (DWORD)-1 != ::GetFileAttributes( cmdline ) ); +} diff --git a/sakura_core/extmodule/CRipgrep.h b/sakura_core/extmodule/CRipgrep.h new file mode 100644 index 0000000000..61418aa9c3 --- /dev/null +++ b/sakura_core/extmodule/CRipgrep.h @@ -0,0 +1,42 @@ +/*! @file */ +/* + Copyright (C) 2018-2020 Sakura Editor Organization + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is + not required. + + 2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ +#pragma once + +#define RIPGREP_COMMAND L"rg.exe" + +class CRipgrep{ +public: + CRipgrep(); + virtual ~CRipgrep(); + +protected: + + +private: + +}; + +bool ExistRipgrep(); + diff --git a/sakura_core/sakura.hh b/sakura_core/sakura.hh index 4d7e90e03b..13555d9447 100644 --- a/sakura_core/sakura.hh +++ b/sakura_core/sakura.hh @@ -832,6 +832,7 @@ #define HIDC_GREP_CHECK_CP 12025 //コードページ #define HIDC_GREP_COMBO_EXCLUDE_FILE 12026 //除外ファイル #define HIDC_GREP_COMBO_EXCLUDE_FOLDER 12027 //除外フォルダ +#define HIDC_CHK_USERIPGREP 12028 //ripgrepを使う //外部コマンド #define HIDC_EXEC_BUTTON_REFERENCE 12100 //参照 diff --git a/sakura_core/sakura_rc.h b/sakura_core/sakura_rc.h index 5d6f8d2af8..737812bee7 100644 --- a/sakura_core/sakura_rc.h +++ b/sakura_core/sakura_rc.h @@ -808,6 +808,7 @@ #define IDC_COMBO_EXCLUDE_FOLDER 1734 #define IDC_COMBO_EXCLUDE_FILE 1735 #define IDC_CHECK_VISTA_STYLE_FILEDIALOG 1737 +#define IDC_CHK_USERIPGREP 1738 #define IDS_AUTHOR_PAGE 4054 #define IDS_ABOUT_DESCRIPTION 4056 #define IDD_TYPELIST 5000 diff --git a/sakura_core/sakura_rc.rc b/sakura_core/sakura_rc.rc index e8dce9be6c..dd85d0721f 100644 --- a/sakura_core/sakura_rc.rc +++ b/sakura_core/sakura_rc.rc @@ -218,6 +218,7 @@ BEGIN DEFPUSHBUTTON "検索(&F)", IDOK, 288, 125, 49, 14, WS_GROUP PUSHBUTTON "キャンセル(&X)", IDCANCEL, 288, 149, 49, 14 PUSHBUTTON "ヘルプ(&H)", IDC_BUTTON_HELP, 288, 174, 49,14 + CONTROL "ripgrepを使う", IDC_CHK_USERIPGREP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 155, 220, 60, 10 END IDD_GREP_REPLACE DIALOGEX 0, 0, 348, 304 From 2fd077af187d9601c4dd25b759181aaa8a5582a4 Mon Sep 17 00:00:00 2001 From: rate Date: Thu, 5 Mar 2020 21:49:04 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E3=80=8Cripgrep=E3=82=92=E4=BD=BF=E3=81=86?= =?UTF-8?q?=E3=80=8D=E3=81=AE=E3=81=A8=E3=81=8D=E3=80=81ripgrep=E3=81=A7Gr?= =?UTF-8?q?ep=E5=AE=9F=E8=A1=8C=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sakura_core/CGrepAgent.cpp | 632 +++++++++++++++++++++++- sakura_core/CGrepAgent.h | 55 ++- sakura_core/GrepInfo.cpp | 1 + sakura_core/GrepInfo.h | 1 + sakura_core/_main/CCommandLine.cpp | 2 + sakura_core/_main/CControlTray.cpp | 5 +- sakura_core/_main/CNormalProcess.cpp | 3 +- sakura_core/cmd/CViewCommander_Grep.cpp | 6 +- 8 files changed, 696 insertions(+), 9 deletions(-) diff --git a/sakura_core/CGrepAgent.cpp b/sakura_core/CGrepAgent.cpp index f04532d4d0..a1ebef5528 100644 --- a/sakura_core/CGrepAgent.cpp +++ b/sakura_core/CGrepAgent.cpp @@ -23,6 +23,9 @@ #include #include #include "sakura_rc.h" +#include "env/CShareData.h" +#include "util/tchar_template.h" +#include "extmodule/CRipgrep.h" #define UICHECK_INTERVAL_MILLISEC 100 // UI確認の時間間隔 #define ADDTAIL_INTERVAL_MILLISEC 50 // 結果出力の時間間隔 @@ -174,6 +177,630 @@ void CGrepAgent::AddTail( CEditView* pcEditView, const CNativeW& cmem, bool bAdd } /*! Grep実行 +*/ +DWORD CGrepAgent::DoGrep( + CEditView* pcViewDst, + bool bGrepReplace, + const CNativeW* pcmGrepKey, + const CNativeW* pcmGrepReplace, + const CNativeW* pcmGrepFile, + const CNativeW* pcmGrepFolder, + const CNativeW* pcmExcludeFile, + const CNativeW* pcmExcludeFolder, + bool bGrepCurFolder, + BOOL bGrepSubFolder, + bool bGrepStdout, + bool bGrepHeader, + const SSearchOption& sSearchOption, + ECodeType nGrepCharSet, + int nGrepOutputLineType, + int nGrepOutputStyle, + bool bGrepOutputFileOnly, + bool bGrepOutputBaseFolder, + bool bGrepSeparateFolder, + bool bGrepPaste, + bool bGrepBackup, + bool bUseRipgrep +) +{ + DWORD ret; + + if ( bUseRipgrep && !bGrepReplace) { + ret = DoGrepRipgrep( + pcViewDst, + bGrepReplace, + pcmGrepKey, + pcmGrepReplace, + pcmGrepFile, + pcmGrepFolder, + pcmExcludeFile, + pcmExcludeFolder, + bGrepCurFolder, + bGrepSubFolder, + bGrepStdout, + bGrepHeader, + sSearchOption, + nGrepCharSet, + nGrepOutputLineType, + nGrepOutputStyle, + bGrepOutputFileOnly, + bGrepOutputBaseFolder, + bGrepSeparateFolder, + bGrepPaste, + bGrepBackup + ); + } + else { + ret = DoGrepSakura( + pcViewDst, + bGrepReplace, + pcmGrepKey, + pcmGrepReplace, + pcmGrepFile, + pcmGrepFolder, + pcmExcludeFile, + pcmExcludeFolder, + bGrepCurFolder, + bGrepSubFolder, + bGrepStdout, + bGrepHeader, + sSearchOption, + nGrepCharSet, + nGrepOutputLineType, + nGrepOutputStyle, + bGrepOutputFileOnly, + bGrepOutputBaseFolder, + bGrepSeparateFolder, + bGrepPaste, + bGrepBackup + ); + } + + return ret; +} + +/* 指定したパスにある適当なファイルのフルパスを返す */ +std::wstring CGrepAgent::GetFirstFilePath( + const WCHAR* pszPath, + CGrepEnumKeys& cGrepEnumKeys, + CGrepEnumOptions& cGrepEnumOptions +) +{ + //適当なファイル検索 + CGrepEnumFiles cGrepExceptAbsFiles; + cGrepExceptAbsFiles.Enumerates(L"", cGrepEnumKeys.m_vecExceptAbsFileKeys, cGrepEnumOptions); + + CGrepEnumFilterFiles cGrepEnumFilterFiles; + cGrepEnumFilterFiles.Enumerates(pszPath, cGrepEnumKeys, cGrepEnumOptions, cGrepExceptAbsFiles); + + if ( cGrepEnumFilterFiles.GetCount() != 0 ) { + return cGrepEnumFilterFiles.GetFileName(0); + } + + //pszPathに適当なファイルが無ければサブディレクトリから検索 + CGrepEnumFolders cGrepExceptAbsFolders; + cGrepExceptAbsFolders.Enumerates(L"", cGrepEnumKeys.m_vecExceptAbsFolderKeys, cGrepEnumOptions); + + CGrepEnumFilterFolders cGrepEnumFilterFolders; + cGrepEnumFilterFolders.Enumerates( pszPath, cGrepEnumKeys, cGrepEnumOptions, cGrepExceptAbsFolders ); + + for ( int i = 0; i < cGrepEnumFilterFolders.GetCount(); i++ ) { + std::wstring folderName = cGrepEnumFilterFolders.GetFileName(i); + std::wstring currentPath = pszPath; + currentPath += L"\\"; + currentPath += folderName; + std::wstring fileName = GetFirstFilePath(currentPath.c_str(), cGrepEnumKeys, cGrepEnumOptions); + if (!fileName.empty()) { + folderName += L"\\"; + folderName += fileName; + return folderName; + } + } + + return L""; +} + +/* ripgrepでGrep実行 */ +DWORD CGrepAgent::DoGrepRipgrep( + CEditView* pcViewDst, + bool bGrepReplace, + const CNativeW* pcmGrepKey, + const CNativeW* pcmGrepReplace, + const CNativeW* pcmGrepFile, + const CNativeW* pcmGrepFolder, + const CNativeW* pcmExcludeFile, + const CNativeW* pcmExcludeFolder, + bool bGrepCurFolder, + BOOL bGrepSubFolder, + bool bGrepStdout, + bool bGrepHeader, + const SSearchOption& sSearchOption, + ECodeType nGrepCharSet, + int nGrepOutputLineType, + int nGrepOutputStyle, + bool bGrepOutputFileOnly, + bool bGrepOutputBaseFolder, + bool bGrepSeparateFolder, + bool bGrepPaste, + bool bGrepBackup +) +{ + // 再入不可 + if( this->m_bGrepRunning ){ + assert_warning( false == this->m_bGrepRunning ); + return 0xffffffff; + } + this->m_bGrepRunning = true; + pcViewDst->m_bDoing_UndoRedo = true; + + // アンドゥバッファの処理 + if( NULL == pcViewDst->GetDocument()->m_cDocEditor.m_pcOpeBlk ){ // 操作ブロック + pcViewDst->GetDocument()->m_cDocEditor.m_pcOpeBlk = new COpeBlk; + pcViewDst->GetDocument()->m_cDocEditor.m_nOpeBlkRedawCount = 0; + } + pcViewDst->GetDocument()->m_cDocEditor.m_pcOpeBlk->AddRef(); + + pcViewDst->m_bCurSrchKeyMark = true; // 検索文字列のマーク + pcViewDst->m_strCurSearchKey = pcmGrepKey->GetStringPtr(); // 検索文字列 + pcViewDst->m_sCurSearchOption = sSearchOption; // 検索オプション + pcViewDst->m_nCurSearchKeySequence = GetDllShareData().m_Common.m_sSearch.m_nSearchKeySequence; + + /* + Grepを行うに当たって検索・画面色分け用正規表現バッファも + 初期化する.これはGrep検索結果の色分けを行うため. + + Note: ここで強調するのは最後の検索文字列であって + Grep対象パターンではないことに注意 + */ + if( !pcViewDst->m_sSearchPattern.SetPattern(pcViewDst->GetHwnd(), pcViewDst->m_strCurSearchKey.c_str(), pcViewDst->m_strCurSearchKey.size(), + pcViewDst->m_sCurSearchOption, &pcViewDst->m_CurRegexp) ){ + this->m_bGrepRunning = false; + pcViewDst->m_bDoing_UndoRedo = false; + pcViewDst->SetUndoBuffer(); + return 0; + } + + //別ウィンドウで検索したとき用にGrepダイアログの検索キーを設定 + pcViewDst->m_pcEditWnd->m_cDlgGrep.m_strText = pcmGrepKey->GetStringPtr(); + pcViewDst->m_pcEditWnd->m_cDlgGrep.m_bSetText = true; + pcViewDst->m_pcEditWnd->m_cDlgGrepReplace.m_strText = pcmGrepKey->GetStringPtr(); + pcViewDst->m_pcEditWnd->m_cDlgGrepReplace.m_bSetText = true; + + CDlgCancel cDlgCancel; + HWND hwndCancel = cDlgCancel.DoModeless( G_AppInstance(), pcViewDst->m_hwndParent, IDD_GREPRUNNING ); + ::SetDlgItemInt( hwndCancel, IDC_STATIC_HITCOUNT, 0, FALSE ); + ::DlgItem_SetText( hwndCancel, IDC_STATIC_CURFILE, L" " ); + ::CheckDlgButton( hwndCancel, IDC_CHECK_REALTIMEVIEW, GetDllShareData().m_Common.m_sSearch.m_bGrepRealTimeView ); + + // rg.exeのパス取得 + WCHAR cmdline[2048]; + WCHAR szExeFolder[_MAX_PATH + 1]; + GetExedir(cmdline, RIPGREP_COMMAND); + SplitPath_FolderAndFile(cmdline, szExeFolder, NULL); + + // オプション設定 + WCHAR options[1024] = { 0 }; + wcscpy(options, L" --line-number --column"); //デフォルトオプション付加 行数出力 + if (!sSearchOption.bLoHiCase) wcscat(options, L" -i"); //大文字小文字区別 + if (!sSearchOption.bRegularExp) wcscat(options, L" -F"); //正規表現使用 + if (sSearchOption.bWordOnly) wcscat(options, L" -w"); //単語単位検索 + + // 検索対象のファイル拡張子設定 + const WCHAR* pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS0); + CGrepEnumKeys cGrepEnumKeys; + int nErrorNo = cGrepEnumKeys.SetFileKeys(pcmGrepFile->GetStringPtr()); + int nErrorNo_ExcludeFile = cGrepEnumKeys.AddExceptFile(pcmExcludeFile->GetStringPtr()); + int nErrorNo_ExcludeFolder = cGrepEnumKeys.AddExceptFolder(pcmExcludeFolder->GetStringPtr()); + if (nErrorNo != 0 || nErrorNo_ExcludeFile != 0 || nErrorNo_ExcludeFolder != 0) { + this->m_bGrepRunning = false; + pcViewDst->m_bDoing_UndoRedo = false; + pcViewDst->SetUndoBuffer(); + + const WCHAR* pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS0); + if (nErrorNo == 1) { + pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS1); + } + else if (nErrorNo == 2) { + pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS2); + } + else if (nErrorNo_ExcludeFile == 1) { + pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS1); + } + else if (nErrorNo_ExcludeFile == 2) { + pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS2); + } + else if (nErrorNo_ExcludeFolder == 1) { + pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS1); + } + else if (nErrorNo_ExcludeFolder == 2) { + pszErrorMessage = LS(STR_GREP_ERR_ENUMKEYS2); + } + ErrorMessage(pcViewDst->m_hwndParent, L"%s", pszErrorMessage); + return 0; + } + // 検索対象ファイル + for (auto key : cGrepEnumKeys.m_vecSearchFileKeys) { + wcscat(options, L" -g \""); + wcscat(options, key); + wcscat(options, L"\""); + } + + // 検索除外ファイル + for (auto key : cGrepEnumKeys.m_vecExceptFileKeys) { + wcscat(options, L" -g \"!"); + wcscat(options, key); + wcscat(options, L"\""); + } + + // エンコーディング設定 + if (IsValidCodeOrCPType(nGrepCharSet)) { + //エンコーディング指定 + WCHAR szCpName[32]; + CCodePage::GetNameNormal(szCpName, nGrepCharSet); + wcscat(options, L" -E "); + wcscat(options, szCpName); + } + else { + // エンコーディング自動判別 + CGrepEnumOptions cGrepEnumOptions; + std::wstring currentFile = pcmGrepFolder->GetStringPtr(); + std::wstring lpFileName = GetFirstFilePath(currentFile.c_str(), cGrepEnumKeys, cGrepEnumOptions); + currentFile += L"\\"; + currentFile += lpFileName; + const STypeConfigMini* type = NULL; + if (!CDocTypeManager().GetTypeConfigMini(CDocTypeManager().GetDocumentTypeOfPath(lpFileName.c_str()), &type)) { + return -1; + } + CCodeMediator cmediator(type->m_encoding); + ECodeType nCharCode = cmediator.CheckKanjiCodeOfFile(currentFile.c_str());; + const WCHAR* pszCodeName = L""; + if (IsValidCodeType(nCharCode)) { + pszCodeName = CCodeTypeName(nCharCode).Short(); + wcscat(options, L" -E "); + wcscat(options, pszCodeName); + } + } + + //コマンドライン文字列作成 + WCHAR szCmdDir[_MAX_PATH]; + ::GetSystemDirectory(szCmdDir, _countof(szCmdDir)); + auto_sprintf(cmdline, L"\"%s\\cmd.exe\" /D /C \"\"%s\\%s\" %s %s %s\"", + szCmdDir, + szExeFolder, //sakura.exeパス + RIPGREP_COMMAND, //rg.exe + options, //rgオプション + pcmGrepKey->GetStringPtr(), + pcmGrepFolder->GetStringPtr() + ); + + HANDLE hStdOutWrite, hStdOutRead; + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(pi)); + + //子プロセスの標準出力と接続するパイプを作成 + SECURITY_ATTRIBUTES sa; + ZeroMemory(&sa, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + hStdOutRead = hStdOutWrite = 0; + if (CreatePipe(&hStdOutRead, &hStdOutWrite, &sa, 1000) == FALSE) { + return -1; + } + + //CreateProcessに渡すSTARTUPINFOを作成 + STARTUPINFO sui; + ZeroMemory(&sui, sizeof(sui)); + sui.cb = sizeof(sui); + sui.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + sui.wShowWindow = SW_HIDE; + sui.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + sui.hStdOutput = hStdOutWrite; + sui.hStdError = hStdOutWrite; + + //Grep開始 + wcsncpy_s( CAppMode::getInstance()->m_szGrepKey, _countof(CAppMode::getInstance()->m_szGrepKey), pcmGrepKey->GetStringPtr(), _TRUNCATE ); + this->m_bGrepMode = true; + BOOL bProcessResult = CreateProcess( + NULL, + cmdline, + NULL, + NULL, + TRUE, + CREATE_NEW_CONSOLE, + NULL, + pcmGrepFolder->GetStringPtr(), + &sui, + &pi + ); + + // CEditWndに新設した関数を使うように + HICON hIconBig, hIconSmall; + hIconBig = GetAppIcon( G_AppInstance(), ICON_DEFAULT_GREP, FN_GREP_ICON, false ); + hIconSmall = GetAppIcon( G_AppInstance(), ICON_DEFAULT_GREP, FN_GREP_ICON, true ); + + // アイコン設定 + CEditWnd* pCEditWnd = CEditWnd::getInstance(); + pCEditWnd->SetWindowIcon( hIconSmall, ICON_SMALL ); + pCEditWnd->SetWindowIcon( hIconBig, ICON_BIG ); + + // Grep出力のヘッダを作成 + CNativeW cmemMessage; + cmemMessage.AllocStringBuffer( 4000 ); + const STypeConfig& type = pcViewDst->m_pcEditDoc->m_cDocType.GetDocumentAttribute(); + + std::vector vPaths; + CreateFolders( pcmGrepFolder->GetStringPtr(), vPaths ); + cmemMessage.AppendString( LS( STR_GREP_SEARCH_CONDITION ) ); //L"\r\n□検索条件 " + int nWork = pcmGrepKey->GetStringLength(); + if( 0 < nWork ){ + cmemMessage.AppendString( L"\"" ); + cmemMessage += EscapeStringLiteral(type, *pcmGrepKey); + cmemMessage.AppendString( L"\"\r\n" ); + }else{ + cmemMessage.AppendString( LS( STR_GREP_SEARCH_FILE ) ); //L"「ファイル検索」\r\n" + } + + cmemMessage.AppendString( LS( STR_GREP_SEARCH_TARGET ) ); //L"検索対象 " + cmemMessage.AppendString( pcmGrepFile->GetStringPtr() ); + cmemMessage.AppendString( L"\r\n" ); + + cmemMessage.AppendString( LS( STR_GREP_SEARCH_FOLDER ) ); //L"フォルダ " + { + std::wstring grepFolder; + for( int i = 0; i < (int)vPaths.size(); i++ ){ + // パスリストは ':' で区切る(2つ目以降の前に付加する) + if( i ){ + grepFolder += L';'; + } + // 末尾のバックスラッシュを削る + std::wstring sPath = ChopYen( vPaths[i] ); + + // ';' を含むパス名は引用符で囲む + if( auto_strchr( sPath.c_str(), L';' ) ){ + grepFolder += L'"'; + grepFolder += sPath; + grepFolder += L'"'; + }else{ + grepFolder += sPath; + } + } + cmemMessage.AppendString( grepFolder.c_str() ); + } + cmemMessage.AppendString( L"\r\n" ); + + cmemMessage.AppendString(LS(STR_GREP_EXCLUDE_FILE)); //L"除外ファイル " + cmemMessage.AppendString( pcmExcludeFile->GetStringPtr() ); + cmemMessage.AppendString(L"\r\n"); + + cmemMessage.AppendString(LS(STR_GREP_EXCLUDE_FOLDER)); //L"除外フォルダ " + cmemMessage.AppendString( pcmExcludeFolder->GetStringPtr() ); + cmemMessage.AppendString(L"\r\n"); + + const wchar_t* pszWork; + pszWork = LS( STR_GREP_SUBFOLDER_YES ); //L" (サブフォルダも検索)\r\n" + cmemMessage.AppendString( pszWork ); + + if( 0 < nWork ){ // ファイル検索の場合は表示しない + if( sSearchOption.bWordOnly ){ + /* 単語単位で探す */ + cmemMessage.AppendString( LS( STR_GREP_COMPLETE_WORD ) ); //L" (単語単位で探す)\r\n" + } + + if( sSearchOption.bLoHiCase ){ + pszWork = LS( STR_GREP_CASE_SENSITIVE ); //L" (英大文字小文字を区別する)\r\n" + }else{ + pszWork = LS( STR_GREP_IGNORE_CASE ); //L" (英大文字小文字を区別しない)\r\n" + } + cmemMessage.AppendString( pszWork ); + + //正規表現ライブラリのバージョンも出力する + if (sSearchOption.bRegularExp) { + cmemMessage.AppendString(LS(STR_GREP_REGEX_DLL)); //L" (正規表現:" + cmemMessage.AppendString(L"ripgrep"); + cmemMessage.AppendString(L")\r\n"); + } + } + + if( CODE_AUTODETECT == nGrepCharSet ){ + cmemMessage.AppendString( LS( STR_GREP_CHARSET_AUTODETECT ) ); //L" (文字コードセットの自動判別)\r\n" + }else if(IsValidCodeOrCPType(nGrepCharSet)){ + cmemMessage.AppendString( LS( STR_GREP_CHARSET ) ); //L" (文字コードセット:" + WCHAR szCpName[100]; + CCodePage::GetNameNormal(szCpName, nGrepCharSet); + cmemMessage.AppendString( szCpName ); + cmemMessage.AppendString( L")\r\n" ); + } + + cmemMessage.AppendString( L"\r\n\r\n" ); + nWork = cmemMessage.GetStringLength(); + + // Grep開始時のカーソル位置を保持(Grep後にカーソル位置を戻すため) + CLayoutInt PosY_beforeGrep = pcViewDst->m_pcEditDoc->m_cLayoutMgr.GetLineCount(); + if( 0 < nWork && bGrepHeader ){ + AddTail( pcViewDst, cmemMessage, bGrepStdout ); + } + cmemMessage._SetStringLength(0); + pszWork = NULL; + + // 検索数算出のためのカーソル位置を保持(ヘッダ出力後のカーソル位置) + CLayoutInt PosY_afterHeadPrint = pcViewDst->m_pcEditDoc->m_cLayoutMgr.GetLineCount(); + + const bool bDrawSwitchOld = pcViewDst->SetDrawSwitch(0 != GetDllShareData().m_Common.m_sSearch.m_bGrepRealTimeView); + + //実行結果の取り込み + typedef char PIPE_CHAR; + const int WORK_NULL_TERMS = sizeof(wchar_t); // 出力用\0の分 + const int MAX_BUFIDX = 10; // bufidxの分 + const DWORD MAX_WORK_READ = 1024 * 5; // 5KiB ReadFileで読み込む限界値 + PIPE_CHAR work[MAX_WORK_READ + MAX_BUFIDX + WORK_NULL_TERMS]; + + DWORD new_cnt; + int bufidx = 0; + bool bLoopFlag = true; + bool bCancelEnd = false; // キャンセルでプロセス停止 + do { + switch (MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 20, QS_ALLEVENTS)) { + case WAIT_OBJECT_0: + //終了していればループフラグをfalseとする + //ただしループの終了条件は プロセス終了 && パイプが空 + bLoopFlag = false; + break; + case WAIT_OBJECT_0 + 1: + //処理中のユーザー操作を可能にする + if (!::BlockingHook(cDlgCancel.GetHwnd())) { + // WM_QUIT受信。ただちに終了処理 + ::TerminateProcess(pi.hProcess, 0); + goto finish; + } + break; + default: + break; + } + //中断ボタン押下チェック + if (cDlgCancel.IsCanceled()) { + //指定されたプロセスと、そのプロセスが持つすべてのスレッドを終了させます。 + ::TerminateProcess(pi.hProcess, 0); + bCancelEnd = true; + break; + } + new_cnt = 0; + + if (PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &new_cnt, NULL)) { //パイプの中の読み出し待機中の文字数を取得 + while (new_cnt > 0) { + if (new_cnt > MAX_WORK_READ) { //パイプから読み出す量を調整 + new_cnt = MAX_WORK_READ; + } + DWORD read_cnt = 0; + ::ReadFile(hStdOutRead, &work[bufidx], new_cnt, &read_cnt, NULL); //パイプから読み出し + read_cnt += bufidx; //work内の実際のサイズにする + + if (read_cnt == 0) { + break; + } + + int j; + int checklen = 0; + for (j = 0; j < (int)read_cnt;) { + ECharSet echarset; + checklen = CheckUtf8Char2(work + j, read_cnt - j, &echarset, true, 0); + if (echarset == CHARSET_BINARY2) { + break; + } + else if (read_cnt - 1 == j && work[j] == _T2(PIPE_CHAR, '\r')) { + // CRLFの一部ではない改行が末尾にある + // 次の読み込みで、CRLFの一部になる可能性がある + break; + } + else { + j += checklen; + } + } + if (j == (int)read_cnt) { //ぴったり出力できる場合 + work[read_cnt] = '\0'; + CMemory input; + CNativeW buf; + input.SetRawData(work, read_cnt); + CCodeBase* pcCodeBase = CCodeFactory::CreateCodeBase(CODE_UTF8, 0); + pcCodeBase->CodeToUnicode(input, &buf); + + cmemMessage.AppendString(buf.GetStringPtr(), buf.GetStringLength()); + AddTail( pcViewDst, cmemMessage, bGrepStdout ); + cmemMessage._SetStringLength(0); + bufidx = 0; + } + else { + char tmp[5]; + int len = read_cnt - j; + memcpy(tmp, &work[j], len); + work[j] = '\0'; + cmemMessage.AppendString((wchar_t*)work, j); + AddTail( pcViewDst, cmemMessage, bGrepStdout ); + cmemMessage._SetStringLength(0); + memcpy(work, tmp, len); + bufidx = len; + } + + // 子プロセスの出力をどんどん受け取らないと子プロセスが + // 停止してしまうため,バッファが空になるまでどんどん読み出す. + new_cnt = 0; + if (!PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &new_cnt, NULL)) { + break; + } + Sleep(0); + + // 相手が出力しつづけていると止められないから + // BlockingHookとキャンセル確認を読取ループ中でも行う + // bLoopFlag が立っていないときは、すでにプロセスは終了しているからTerminateしない + if (!::BlockingHook(cDlgCancel.GetHwnd())) { + if (bLoopFlag) { + ::TerminateProcess(pi.hProcess, 0); + } + goto finish; + } + if (cDlgCancel.IsCanceled()) { + // 指定されたプロセスと、そのプロセスが持つすべてのスレッドを終了させます。 + if (bLoopFlag) { + ::TerminateProcess(pi.hProcess, 0); + } + bCancelEnd = true; + goto user_cancel; + } + } + } + } while (bLoopFlag || new_cnt > 0); + +user_cancel: + // キャンセル表示(中断しました。) + if( bCancelEnd && bGrepHeader ){ + const wchar_t* p = LS( STR_GREP_SUSPENDED ); + CNativeW cmemSuspend; + cmemSuspend.SetString( p ); + AddTail( pcViewDst, cmemSuspend, bGrepStdout ); + } + +finish: + // 結果出力(%d 個が検索されました。) + CLayoutInt PosY_afterGrep = pcViewDst->m_pcEditDoc->m_cLayoutMgr.GetLineCount(); + int nHitCount = PosY_afterGrep.GetValue() - PosY_afterHeadPrint.GetValue(); + if( bGrepHeader ){ + WCHAR szBuffer[128]; + auto_sprintf( szBuffer, LS( STR_GREP_MATCH_COUNT ), nHitCount ); + CNativeW cmemOutput; + cmemOutput.SetString( szBuffer ); + AddTail( pcViewDst, cmemOutput, bGrepStdout ); + } + + // カーソルをGrep直前の位置に戻す + pcViewDst->GetCaret().MoveCursor( CLayoutPoint(CLayoutInt(0), PosY_beforeGrep), true ); + + cDlgCancel.CloseDialog( 0 ); + + // アクティブにする + ActivateFrameWindow( CEditWnd::getInstance()->GetHwnd() ); + + // Grep実行後はファイルを変更無しの状態にする + pcViewDst->m_pcEditDoc->m_cDocEditor.SetModified(false,false); + + this->m_bGrepRunning = false; + pcViewDst->m_bDoing_UndoRedo = false; + + // 表示処理ON/OFF + pCEditWnd->SetDrawSwitchOfAllViews( bDrawSwitchOld ); + + // 再描画 + if( !pCEditWnd->UpdateTextWrap() ) // 折り返し方法関連の更新 + pCEditWnd->RedrawAllViews( NULL ); + + if (hStdOutWrite) CloseHandle(hStdOutWrite); + CloseHandle(hStdOutRead); + if (pi.hProcess) CloseHandle(pi.hProcess); + if (pi.hThread) CloseHandle(pi.hThread); + + return 0; +} + +/*! sakuraでGrep実行 @param[in] pcmGrepKey 検索パターン @param[in] pcmGrepFile 検索対象ファイルパターン(!で除外指定)) @@ -183,7 +810,7 @@ void CGrepAgent::AddTail( CEditView* pcEditView, const CNativeW& cmem, bool bAdd @date 2008.12.13 genta 検索パターンのバッファオーバラン対策 @date 2012.10.13 novice 検索オプションをクラスごと代入 */ -DWORD CGrepAgent::DoGrep( +DWORD CGrepAgent::DoGrepSakura( CEditView* pcViewDst, bool bGrepReplace, const CNativeW* pcmGrepKey, @@ -207,7 +834,7 @@ DWORD CGrepAgent::DoGrep( bool bGrepBackup ) { - MY_RUNNINGTIMER( cRunningTimer, "CEditView::DoGrep" ); + MY_RUNNINGTIMER( cRunningTimer, "CEditView::DoGrepSakura" ); // 再入不可 if( this->m_bGrepRunning ){ @@ -539,7 +1166,6 @@ DWORD CGrepAgent::DoGrep( cmemMessage.AppendString( L"\r\n\r\n" ); nWork = cmemMessage.GetStringLength(); - pszWork = cmemMessage.GetStringPtr(); //@@@ 2002.01.03 YAZAKI Grep直後はカーソルをGrep直前の位置に動かす CLayoutInt tmp_PosY_Layout = pcViewDst->m_pcEditDoc->m_cLayoutMgr.GetLineCount(); if( 0 < nWork && sGrepOption.bGrepHeader ){ diff --git a/sakura_core/CGrepAgent.h b/sakura_core/CGrepAgent.h index bb99de5760..6576d7dc5d 100644 --- a/sakura_core/CGrepAgent.h +++ b/sakura_core/CGrepAgent.h @@ -31,6 +31,7 @@ class CSearchStringPattern; class CGrepEnumKeys; class CGrepEnumFiles; class CGrepEnumFolders; +class CGrepEnumOptions; struct SGrepOption{ bool bGrepReplace; //!< Grep置換 @@ -98,10 +99,62 @@ class CGrepAgent : public CDocListenerEx{ bool bGrepOutputBaseFolder, //!< [in] ベースフォルダ表示 bool bGrepSeparateFolder, //!< [in] フォルダ毎に表示 bool bGrepPaste, - bool bGrepBackup + bool bGrepBackup, + bool bUseRipgrep ); private: + std::wstring GetFirstFilePath( const WCHAR* pszPath, CGrepEnumKeys& cGrepEnumKeys, CGrepEnumOptions& cGrepEnumOptions ); + + // Grep実行(ripgrep) + DWORD DoGrepRipgrep( + CEditView* pcViewDst, + bool bGrepReplace, + const CNativeW* pcmGrepKey, + const CNativeW* pcmGrepReplace, + const CNativeW* pcmGrepFile, + const CNativeW* pcmGrepFolder, + const CNativeW* pcmExcludeFile, + const CNativeW* pcmExcludeFolder, + bool bGrepCurFolder, + BOOL bGrepSubFolder, + bool bGrepStdout, + bool bGrepHeader, + const SSearchOption& sSearchOption, + ECodeType nGrepCharSet, // 2002/09/21 Moca 文字コードセット選択 + int nGrepOutputLineType, + int nGrepOutputStyle, + bool bGrepOutputFileOnly, //!< [in] ファイル毎最初のみ出力 + bool bGrepOutputBaseFolder, //!< [in] ベースフォルダ表示 + bool bGrepSeparateFolder, //!< [in] フォルダ毎に表示 + bool bGrepPaste, + bool bGrepBackup + ); + // Grep実行(sakura) + DWORD DoGrepSakura( + CEditView* pcViewDst, + bool bGrepReplace, + const CNativeW* pcmGrepKey, + const CNativeW* pcmGrepReplace, + const CNativeW* pcmGrepFile, + const CNativeW* pcmGrepFolder, + const CNativeW* pcmExcludeFile, + const CNativeW* pcmExcludeFolder, + bool bGrepCurFolder, + BOOL bGrepSubFolder, + bool bGrepStdout, + bool bGrepHeader, + const SSearchOption& sSearchOption, + ECodeType nGrepCharSet, // 2002/09/21 Moca 文字コードセット選択 + int nGrepOutputLineType, + int nGrepOutputStyle, + bool bGrepOutputFileOnly, //!< [in] ファイル毎最初のみ出力 + bool bGrepOutputBaseFolder, //!< [in] ベースフォルダ表示 + bool bGrepSeparateFolder, //!< [in] フォルダ毎に表示 + bool bGrepPaste, + bool bGrepBackup + ); + // Grep実行 int DoGrepTree( CEditView* pcViewDst, diff --git a/sakura_core/GrepInfo.cpp b/sakura_core/GrepInfo.cpp index cfb2382aed..348ade92f3 100644 --- a/sakura_core/GrepInfo.cpp +++ b/sakura_core/GrepInfo.cpp @@ -50,5 +50,6 @@ GrepInfo::GrepInfo() noexcept , bGrepReplace(false) , bGrepPaste(false) , bGrepBackup(false) + , bUseRipgrep(false) { } diff --git a/sakura_core/GrepInfo.h b/sakura_core/GrepInfo.h index dacda5eb49..3568f392b1 100644 --- a/sakura_core/GrepInfo.h +++ b/sakura_core/GrepInfo.h @@ -57,6 +57,7 @@ struct GrepInfo { bool bGrepReplace; //!< Grep置換 bool bGrepPaste; //!< クリップボードから貼り付け bool bGrepBackup; //!< 置換でバックアップを保存 + bool bUseRipgrep; //!< Ripgrepを使う // コンストラクタ GrepInfo() noexcept; diff --git a/sakura_core/_main/CCommandLine.cpp b/sakura_core/_main/CCommandLine.cpp index 1a3b9c36c3..d87a736466 100644 --- a/sakura_core/_main/CCommandLine.cpp +++ b/sakura_core/_main/CCommandLine.cpp @@ -487,6 +487,8 @@ void CCommandLine::ParseCommandLine( LPCWSTR pszCmdLineSrc, bool bResponse ) m_gi.bGrepPaste = true; break; case 'O': m_gi.bGrepBackup = true; break; + case 'Q': + m_gi.bUseRipgrep = true; break; } } break; diff --git a/sakura_core/_main/CControlTray.cpp b/sakura_core/_main/CControlTray.cpp index 44cb9c1760..182e9db413 100644 --- a/sakura_core/_main/CControlTray.cpp +++ b/sakura_core/_main/CControlTray.cpp @@ -212,9 +212,10 @@ void CControlTray::DoGrepCreateWindow(HINSTANCE hinst, HWND msgParent, CDlgGrep& if( 1 == cDlgGrep.m_nGrepOutputStyle )wcscat( pOpt, L"1" ); // Grep: 出力形式 if( 2 == cDlgGrep.m_nGrepOutputStyle )wcscat( pOpt, L"2" ); // Grep: 出力形式 if( 3 == cDlgGrep.m_nGrepOutputStyle )wcscat( pOpt, L"3" ); - if( cDlgGrep.m_bGrepOutputFileOnly )wcscat( pOpt, L"F" ); + if( cDlgGrep.m_bGrepOutputFileOnly )wcscat( pOpt, L"F" ); if( cDlgGrep.m_bGrepOutputBaseFolder )wcscat( pOpt, L"B" ); - if( cDlgGrep.m_bGrepSeparateFolder )wcscat( pOpt, L"D" ); + if( cDlgGrep.m_bGrepSeparateFolder )wcscat( pOpt, L"D" ); + if( cDlgGrep.m_bUseRipgrep )wcscat( pOpt, L"Q" ); if( pOpt[0] != L'\0' ){ cCmdLine.AppendString( L" -GOPT=" ); cCmdLine.AppendString( pOpt ); diff --git a/sakura_core/_main/CNormalProcess.cpp b/sakura_core/_main/CNormalProcess.cpp index 5ddd0c04ad..8cf6c9edc1 100644 --- a/sakura_core/_main/CNormalProcess.cpp +++ b/sakura_core/_main/CNormalProcess.cpp @@ -224,7 +224,8 @@ bool CNormalProcess::InitializeProcess() gi.bGrepOutputBaseFolder, gi.bGrepSeparateFolder, gi.bGrepPaste, - gi.bGrepBackup + gi.bGrepBackup, + gi.bUseRipgrep ); pEditWnd->m_cDlgFuncList.Refresh(); // アウトラインを再解析する } diff --git a/sakura_core/cmd/CViewCommander_Grep.cpp b/sakura_core/cmd/CViewCommander_Grep.cpp index a71de64fe2..642ac6bfac 100644 --- a/sakura_core/cmd/CViewCommander_Grep.cpp +++ b/sakura_core/cmd/CViewCommander_Grep.cpp @@ -111,7 +111,8 @@ void CViewCommander::Command_GREP( void ) GetEditWindow()->m_cDlgGrep.m_bGrepOutputBaseFolder, GetEditWindow()->m_cDlgGrep.m_bGrepSeparateFolder, false, - false + false, + GetEditWindow()->m_cDlgGrep.m_bUseRipgrep ); //プラグイン:DocumentOpenイベント実行 @@ -211,7 +212,8 @@ void CViewCommander::Command_GREP_REPLACE( void ) cDlgGrepRep.m_bGrepOutputBaseFolder, cDlgGrepRep.m_bGrepSeparateFolder, cDlgGrepRep.m_bPaste, - cDlgGrepRep.m_bBackup + cDlgGrepRep.m_bBackup, + cDlgGrepRep.m_bUseRipgrep ); } else{ From 35c79a3e7fc2dc1906201c664461055e0010ad5c Mon Sep 17 00:00:00 2001 From: rate Date: Thu, 5 Mar 2020 22:02:16 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=E3=83=98=E3=83=AB=E3=83=97=E8=BF=BD?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- help/sakura/res/HLP000067.html | 3 +++ help/sakura/res/images/Grep.png | Bin 50368 -> 18181 bytes 2 files changed, 3 insertions(+) diff --git a/help/sakura/res/HLP000067.html b/help/sakura/res/HLP000067.html index 0c2d3fa486..a48b55daf0 100644 --- a/help/sakura/res/HLP000067.html +++ b/help/sakura/res/HLP000067.html @@ -74,6 +74,9 @@

Grep

フォルダの初期値をカレントフォルダにする
    現在開いているファイルがあるフォルダを(フォルダ)の初期値にします。次回のダイアログ表示時に反映されます。
+ □ripgrepを使う
+     sakura.exeと同ディレクトリにrg.exeがあればripgrepを使用します。(sakura:2.4.0.0以降)
+ <結果出力> … 検索条件に合致した箇所の出力方法を指定します。合致した箇所はその先頭の合致箇所の位置が示され、タイプ別設定 『カラー』プロパティで「検索文字列」に指定した色でハイライト表示されます。
該当行 … 合致した箇所のある行全体を表示します。
diff --git a/help/sakura/res/images/Grep.png b/help/sakura/res/images/Grep.png index 79bb69c420a8c5c14f4991fbb05feeabae23ee60..f9feeb40ad853375c15d9b2ae55de0f684d4ee1c 100644 GIT binary patch literal 18181 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 #jNr}bCJ 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 CHF13a literal 50368 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 From 2eb1ebb922a3a71cc1ae6eb30c88c8ebc325d717 Mon Sep 17 00:00:00 2001 From: rate Date: Fri, 6 Mar 2020 19:52:58 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Release=E3=83=93=E3=83=AB=E3=83=89=E3=81=AE?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sakura_core/CGrepAgent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sakura_core/CGrepAgent.cpp b/sakura_core/CGrepAgent.cpp index a1ebef5528..b7774f5c2d 100644 --- a/sakura_core/CGrepAgent.cpp +++ b/sakura_core/CGrepAgent.cpp @@ -762,10 +762,10 @@ DWORD CGrepAgent::DoGrepRipgrep( finish: // 結果出力(%d 個が検索されました。) CLayoutInt PosY_afterGrep = pcViewDst->m_pcEditDoc->m_cLayoutMgr.GetLineCount(); - int nHitCount = PosY_afterGrep.GetValue() - PosY_afterHeadPrint.GetValue(); + CLayoutInt cLyoutInt_HitCount = PosY_afterGrep - PosY_afterHeadPrint; if( bGrepHeader ){ WCHAR szBuffer[128]; - auto_sprintf( szBuffer, LS( STR_GREP_MATCH_COUNT ), nHitCount ); + auto_sprintf( szBuffer, LS( STR_GREP_MATCH_COUNT ), cLyoutInt_HitCount); CNativeW cmemOutput; cmemOutput.SetString( szBuffer ); AddTail( pcViewDst, cmemOutput, bGrepStdout );