work save: replace done

This commit is contained in:
royqh1979@gmail.com 2021-08-04 09:13:41 +08:00
parent 590c7adc6e
commit 2be69f0758
8 changed files with 119 additions and 63 deletions

View File

@ -1296,7 +1296,7 @@
<string>Find Previous</string>
</property>
<property name="shortcut">
<string>Ctrl+F3</string>
<string>Shift+F3</string>
</property>
</action>
</widget>

View File

@ -40,8 +40,18 @@ int SynSearch::findAll(const QString &newText)
if (next<0) {
break;
}
mResults.append(next);
start = next + newText.length();
if (options().testFlag(ssoWholeWord)) {
if (((next<=0) || isDelimitChar(newText[next-1]))
&&
( (start>=newText.length()) || isDelimitChar(newText[start]) )
) {
mResults.append(next);
}
} else {
mResults.append(next);
}
}
return mResults.size();
}
@ -50,3 +60,8 @@ QString SynSearch::replace(const QString &aOccurrence, const QString &aReplaceme
{
return aReplacement;
}
bool SynSearch::isDelimitChar(QChar ch)
{
return !(ch == '_' || ch.isLetterOrNumber());
}

View File

@ -16,6 +16,8 @@ public:
int resultCount() override;
int findAll(const QString &newText) override;
QString replace(const QString &aOccurrence, const QString &aReplacement) override;
private:
bool isDelimitChar(QChar ch);
private:
QList<int> mResults;
};

View File

@ -10,8 +10,6 @@ enum SynSearchOption {
ssoBackwards = 0x0004,
ssoEntireScope = 0x0008,
ssoSelectedOnly = 0x0010,
ssoFindAll = 0x0020,
ssoPrompt = 0x0040,
ssoRegExp = 0x0080
};

View File

@ -4155,29 +4155,27 @@ void SynEdit::setSelText(const QString &Value)
mActiveSelectionMode);
}
int SynEdit::search(const QString &ASearch, SynSearchOptions AOptions, PSynSearchBase searchEngine,
int SynEdit::searchReplace(const QString &sSearch, const QString &sReplace, SynSearchOptions sOptions, PSynSearchBase searchEngine,
SynSearchMathedProc matchedCallback)
{
if (!searchEngine)
return 0;
// can't search for or replace an empty string
if (ASearch.isEmpty()) {
if (sSearch.isEmpty()) {
return 0;
}
int result = 0;
// get the text range to search in, ignore the "Search in selection only"
// option if nothing is selected
bool bBackward = AOptions.testFlag(ssoBackwards);
bool bPrompt = AOptions.testFlag(ssoPrompt);
bool bFindAll = AOptions.testFlag(ssoFindAll);
bool bFromCursor = !AOptions.testFlag(ssoEntireScope);
bool bBackward = sOptions.testFlag(ssoBackwards);
bool bFromCursor = !sOptions.testFlag(ssoEntireScope);
BufferCoord ptCurrent;
BufferCoord ptStart;
BufferCoord ptEnd;
if (!selAvail())
AOptions.setFlag(ssoSelectedOnly,false);
if (AOptions.testFlag(ssoSelectedOnly)) {
sOptions.setFlag(ssoSelectedOnly,false);
if (sOptions.testFlag(ssoSelectedOnly)) {
ptStart = blockBegin();
ptEnd = blockEnd();
// search the whole line in the line selection mode
@ -4212,14 +4210,18 @@ int SynEdit::search(const QString &ASearch, SynSearchOptions AOptions, PSynSearc
ptCurrent = ptStart;
}
// initialize the search engine
searchEngine->setOptions(AOptions);
searchEngine->setPattern(ASearch);
searchEngine->setOptions(sOptions);
searchEngine->setPattern(sSearch);
// search while the current search position is inside of the search range
int nReplaceLen = 0;
bool bEndUndoBlock =false;
bool dobatchReplace = false;
doOnPaintTransient(SynTransientType::ttBefore);
{
auto action = finally([&,this]{
if (dobatchReplace) {
decPaintLock();
mUndoList->EndBlock();
}
doOnPaintTransient(SynTransientType::ttAfter);
});
int i;
@ -4235,6 +4237,7 @@ int SynEdit::search(const QString &ASearch, SynSearchOptions AOptions, PSynSearc
// An occurrence may have been replaced with a text of different length
int nFound = searchEngine->result(i) + 1 + iResultOffset;
int nSearchLen = searchEngine->length(i);
int nReplaceLen = 0;
if (bBackward)
i--;
else
@ -4245,7 +4248,7 @@ int SynEdit::search(const QString &ASearch, SynSearchOptions AOptions, PSynSearc
int first = nFound;
int last = nFound + nSearchLen;
if ((mActiveSelectionMode == SynSelectionMode::smNormal)
|| !AOptions.testFlag(ssoSelectedOnly)) {
|| !sOptions.testFlag(ssoSelectedOnly)) {
if (((ptCurrent.Line == ptStart.Line) && (first < ptStart.Char)) ||
((ptCurrent.Line == ptEnd.Line) && (last > ptEnd.Char)))
isInValidSearchRange = false;
@ -4273,23 +4276,38 @@ int SynEdit::search(const QString &ASearch, SynSearchOptions AOptions, PSynSearc
else
internalSetCaretXY(ptCurrent);
// If it's a search only we can leave the procedure now.
if (matchedCallback) {
matchedCallback(ASearch,ptCurrent.Line,
SynSearchAction searchAction = SynSearchAction::Exit;
QString replaceText = searchEngine->replace(selText(), sReplace);
if (matchedCallback && !dobatchReplace) {
searchAction = matchedCallback(sSearch,replaceText,ptCurrent.Line,
nFound,nSearchLen);
}
if (!bFindAll)
if (searchAction==SynSearchAction::Exit) {
return result;
} else if (searchAction == SynSearchAction::Skip) {
continue;
} else if (searchAction == SynSearchAction::Replace
|| searchAction == SynSearchAction::ReplaceAll) {
if (!dobatchReplace &&
(searchAction == SynSearchAction::ReplaceAll) ){
incPaintLock();
mUndoList->BeginBlock();
dobatchReplace = true;
}
setSelText(replaceText);
nReplaceLen = caretX() - nFound;
// fix the caret position and the remaining results
// if (!bBackward) {
// internalSetCaretX(nFound + nReplaceLen);
// if ((nSearchLen != nReplaceLen) && (nAction != SynReplaceAction::raSkip)) {
// iResultOffset += nReplaceLen - nSearchLen;
// if ((mActiveSelectionMode != SynSelectionMode::smColumn) && (caretY() == ptEnd.Line)) {
// ptEnd.Char+=nReplaceLen - nSearchLen;
// setBlockEnd(ptEnd);
// }
// }
// }
if (!bBackward) {
internalSetCaretX(nFound + nReplaceLen);
if ((nSearchLen != nReplaceLen)) {
iResultOffset += nReplaceLen - nSearchLen;
if ((mActiveSelectionMode != SynSelectionMode::smColumn) && (caretY() == ptEnd.Line)) {
ptEnd.Char+=nReplaceLen - nSearchLen;
setBlockEnd(ptEnd);
}
}
}
}
}
// search next / previous line
if (bBackward)

View File

@ -100,8 +100,11 @@ Q_DECLARE_FLAGS(SynEditorOptions, SynEditorOption)
Q_DECLARE_OPERATORS_FOR_FLAGS(SynEditorOptions)
enum class SynReplaceAction {
raCancel, raSkip, raReplace, raReplaceAll
enum class SynSearchAction {
Replace,
ReplaceAll,
Skip,
Exit
};
@ -125,8 +128,8 @@ using SynPaintProc = std::function<void(const QPaintDevice& paintDevice )>;
using SynPreparePaintHighlightTokenProc = std::function<void(int row,
int column, const QString& token, PSynHighlighterAttribute attr,
SynFontStyles& style, QColor& foreground, QColor& background)>;
using SynSearchMathedProc = std::function<void(const QString& ASearch,
int Line, int ch, int wordLen)>;
using SynSearchMathedProc = std::function<SynSearchAction(const QString& sSearch,
const QString& sReplace, int Line, int ch, int wordLen)>;
//using SynSpecialLineColorsProc = std::function<void(int Line,
// bool& Special, QColor& foreground, QColor& backgroundColor)>;
//using SynEditingAreasProc = std::function<void(int Line, SynEditingAreaList& areaList,
@ -215,7 +218,7 @@ public:
PSynEditFoldRange foldHidesLine(int line);
void setSelText(const QString& Value);
int search(const QString& ASearch,SynSearchOptions AOptions,
int searchReplace(const QString& sSearch, const QString& sReplace, SynSearchOptions options,
PSynSearchBase searchEngine, SynSearchMathedProc matchedCallback = nullptr);
int maxScrollWidth() const;

View File

@ -19,7 +19,6 @@ SearchDialog::SearchDialog(QWidget *parent) :
mTabBar->addTab(tr("Find"));
mTabBar->addTab(tr("Find in files"));
mTabBar->addTab(tr("Replace"));
mTabBar->addTab(tr("Replace in files"));
mTabBar->setExpanding(false);
ui->dialogLayout->insertWidget(0,mTabBar);
connect(mTabBar,&QTabBar::currentChanged,this, &SearchDialog::onTabChanged);
@ -35,7 +34,11 @@ SearchDialog::~SearchDialog()
void SearchDialog::find(const QString &text)
{
if (mTabBar->currentIndex()==0) {
this->onTabChanged();
} else {
mTabBar->setCurrentIndex(0);
}
ui->cbFind->setCurrentText(text);
show();
}
@ -69,31 +72,22 @@ void SearchDialog::replace(const QString &sFind, const QString &sReplace)
show();
}
void SearchDialog::replaceInFiles(const QString &sFind, const QString &sReplace)
{
mTabBar->setCurrentIndex(3);
ui->cbFind->setCurrentText(sFind);
ui->cbReplace->setCurrentText(sReplace);
show();
}
void SearchDialog::onTabChanged()
{
bool isfind = (mTabBar->currentIndex() == 0);
bool isfindfiles = (mTabBar->currentIndex() == 1);
bool isreplace = (mTabBar->currentIndex() == 2);
bool isreplacefiles = (mTabBar->currentIndex() == 3);
ui->lblReplace->setVisible(isreplace || isreplacefiles);
ui->cbReplace->setVisible(isreplace || isreplacefiles);
ui->lblReplace->setVisible(isreplace);
ui->cbReplace->setVisible(isreplace);
ui->grpOrigin->setVisible(isfind || isreplace);
ui->grpOrigin->setEnabled(isfind || isreplace);
ui->grpScope->setVisible(isfind || isreplace);
ui->grpScope->setEnabled(isreplace);
ui->grpWhere->setVisible(isfindfiles || isreplacefiles);
ui->grpWhere->setEnabled(isfindfiles || isreplacefiles);
ui->grpWhere->setVisible(isfindfiles);
ui->grpWhere->setEnabled(isfindfiles);
ui->grpDirection->setVisible(isfind || isreplace);
ui->grpDirection->setEnabled(isfind || isreplace);
@ -106,9 +100,9 @@ void SearchDialog::onTabChanged()
// rbOpenFiles.Checked := true;
// Disable prompt when doing finds
ui->chkPrompt->setEnabled(isreplace or isreplacefiles);
ui->chkPrompt->setEnabled(isreplace);
if (isfind || not isfindfiles) {
if (isfind || isfindfiles) {
ui->btnExecute->setText(tr("Find"));
} else {
ui->btnExecute->setText(tr("Replace"));
@ -160,9 +154,6 @@ void SearchDialog::on_btnExecute_clicked()
if (ui->chkWholeWord->isChecked()) {
mSearchOptions.setFlag(ssoWholeWord);
}
if (ui->chkPrompt->isChecked()) {
mSearchOptions.setFlag(ssoPrompt);
}
// Apply scope, when enabled
if (ui->grpScope->isEnabled()) {
@ -196,8 +187,38 @@ void SearchDialog::on_btnExecute_clicked()
if (actionType == SearchAction::Find) {
Editor *e = pMainWindow->editorList()->getEditor();
if (e!=nullptr) {
findcount+=execute(e,SearchAction::Find);
findcount+=execute(e,ui->cbFind->currentText(),"");
}
} else {
Editor *e = pMainWindow->editorList()->getEditor();
if (e!=nullptr) {
bool doPrompt = ui->chkPrompt->isChecked();
findcount+=execute(e,ui->cbFind->currentText(),ui->cbReplace->currentText(),
[&doPrompt](const QString& sSearch,
const QString& sReplace, int Line, int ch, int wordLen){
if (doPrompt) {
switch(QMessageBox::question(pMainWindow,
tr("Replace"),
tr("Replace this occurrence of ''%1''?").arg(sSearch),
QMessageBox::Yes|QMessageBox::YesAll|QMessageBox::No|QMessageBox::Cancel,
QMessageBox::Yes)) {
case QMessageBox::Yes:
return SynSearchAction::Replace;
case QMessageBox::YesAll:
return SynSearchAction::ReplaceAll;
case QMessageBox::No:
return SynSearchAction::Skip;
case QMessageBox::Cancel:
return SynSearchAction::Exit;
default:
return SynSearchAction::Exit;
}
} else {
return SynSearchAction::ReplaceAll;
}
});
}
}
// // Replace first, find to next
@ -359,7 +380,7 @@ void SearchDialog::on_btnExecute_clicked()
//end;
}
int SearchDialog::execute(Editor *editor, SearchDialog::SearchAction actionType)
int SearchDialog::execute(Editor *editor, const QString &sSearch, const QString &sReplace, SynSearchMathedProc matchCallback)
{
if (editor==nullptr)
return 0;
@ -380,9 +401,8 @@ int SearchDialog::execute(Editor *editor, SearchDialog::SearchAction actionType)
mSearchEngine = mBasicSearchEngine;
}
return editor->search(ui->cbFind->currentText(),
mSearchOptions,
mSearchEngine);
return editor->searchReplace(sSearch, sReplace, mSearchOptions,
mSearchEngine, matchCallback);
// // When using find in files, report each find using OnReplaceText

View File

@ -2,7 +2,7 @@
#define SEARCHDIALOG_H
#include <QDialog>
#include "../qsynedit/SearchBase.h"
#include "../qsynedit/SynEdit.h"
namespace Ui {
class SearchDialog;
@ -29,7 +29,6 @@ public:
void findPrevious();
void findInFiles(const QString& text);
void replace(const QString& sFind, const QString& sReplace);
void replaceInFiles(const QString& sFind, const QString& sReplace);
PSynSearchBase searchEngine() const;
QTabBar *tabBar() const;
@ -42,7 +41,8 @@ private slots:
void on_btnExecute_clicked();
private:
int execute(Editor* editor, SearchAction actionType);
int execute(Editor* editor, const QString& sSearch,
const QString& sReplace, SynSearchMathedProc matchCallback = nullptr);
private:
Ui::SearchDialog *ui;
QTabBar *mTabBar;