work save
This commit is contained in:
parent
813bacebfb
commit
100ceeda6c
|
@ -16,6 +16,9 @@ SOURCES += \
|
|||
compiler/executablerunner.cpp \
|
||||
compiler/filecompiler.cpp \
|
||||
compiler/stdincompiler.cpp \
|
||||
qsynedit/Search.cpp \
|
||||
qsynedit/SearchBase.cpp \
|
||||
qsynedit/SearchRegex.cpp \
|
||||
settingsdialog/debuggeneralwidget.cpp \
|
||||
widgets/cpudialog.cpp \
|
||||
debugger.cpp \
|
||||
|
@ -68,6 +71,9 @@ HEADERS += \
|
|||
compiler/executablerunner.h \
|
||||
compiler/filecompiler.h \
|
||||
compiler/stdincompiler.h \
|
||||
qsynedit/Search.h \
|
||||
qsynedit/SearchBase.h \
|
||||
qsynedit/SearchRegex.h \
|
||||
settingsdialog/debuggeneralwidget.h \
|
||||
widgets/cpudialog.h \
|
||||
debugger.h \
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#include "Search.h"
|
||||
|
||||
SynSearch::SynSearch(QObject *parent):SynSearchBase(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SynSearch::length(int aIndex)
|
||||
{
|
||||
if (aIndex<0 || aIndex >= mResults.length())
|
||||
return 0;
|
||||
return pattern().length();
|
||||
}
|
||||
|
||||
int SynSearch::result(int aIndex)
|
||||
{
|
||||
if (aIndex<0 || aIndex >= mResults.length())
|
||||
return -1;
|
||||
return mResults[aIndex];
|
||||
}
|
||||
|
||||
int SynSearch::resultCount()
|
||||
{
|
||||
return mResults.count();
|
||||
}
|
||||
|
||||
int SynSearch::findAll(const QString &newText)
|
||||
{
|
||||
mResults.clear();
|
||||
if (pattern().isEmpty())
|
||||
return 0;
|
||||
int start=0;
|
||||
int next=-1;
|
||||
while (true) {
|
||||
if (options.testFlag(ssoMatchCase)) {
|
||||
next = newText.indexOf(pattern(),start,Qt::CaseSensitive);
|
||||
} else {
|
||||
next = newText.indexOf(pattern(),start,Qt::CaseInsensitive);
|
||||
}
|
||||
if (next<0) {
|
||||
break;
|
||||
}
|
||||
mResults.append(next);
|
||||
start = next;
|
||||
}
|
||||
return mResults.size();
|
||||
}
|
||||
|
||||
QString SynSearch::replace(const QString &aOccurrence, const QString &aReplacement)
|
||||
{
|
||||
return aReplacement;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef SYNSEARCH_H
|
||||
#define SYNSEARCH_H
|
||||
#include "SearchBase.h"
|
||||
|
||||
|
||||
class SynSearch : public SynSearchBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SynSearch(QObject* parent = nullptr);
|
||||
|
||||
// SynSearchBase interface
|
||||
public:
|
||||
int length(int aIndex) override;
|
||||
int result(int aIndex) override;
|
||||
int resultCount() override;
|
||||
int findAll(const QString &newText) override;
|
||||
QString replace(const QString &aOccurrence, const QString &aReplacement) override;
|
||||
private:
|
||||
QList<int> mResults;
|
||||
};
|
||||
|
||||
#endif // SYNSEARCH_H
|
|
@ -0,0 +1,26 @@
|
|||
#include "SearchBase.h"
|
||||
|
||||
SynSearchBase::SynSearchBase(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString SynSearchBase::pattern()
|
||||
{
|
||||
return mPattern;
|
||||
}
|
||||
|
||||
void SynSearchBase::setPattern(const QString &value)
|
||||
{
|
||||
mPattern = value;
|
||||
}
|
||||
|
||||
SynSearchOptions SynSearchBase::options() const
|
||||
{
|
||||
return mOptions;
|
||||
}
|
||||
|
||||
void SynSearchBase::setOptions(const SynSearchOptions &options)
|
||||
{
|
||||
mOptions = options;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef SYNSEARCHBASE_H
|
||||
#define SYNSEARCHBASE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
enum SynSearchOption {
|
||||
ssoMatchCase, ssoWholeWord, ssoBackwards,
|
||||
ssoEntireScope, ssoSelectedOnly, ssoReplace, ssoReplaceAll, ssoPrompt,
|
||||
ssoRegExp};
|
||||
|
||||
Q_DECLARE_FLAGS(SynSearchOptions, SynSearchOption)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(SynSearchOptions)
|
||||
|
||||
class SynSearchBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SynSearchBase(QObject *parent = nullptr);
|
||||
QString pattern();
|
||||
virtual void setPattern(const QString& value);
|
||||
virtual int length(int aIndex) = 0;
|
||||
virtual int result(int aIndex) = 0;
|
||||
virtual int resultCount() = 0;
|
||||
virtual int findAll(const QString& newText) = 0;
|
||||
virtual QString replace(const QString& aOccurrence, const QString& aReplacement) = 0;
|
||||
SynSearchOptions options() const;
|
||||
virtual void setOptions(const SynSearchOptions &options);
|
||||
|
||||
private:
|
||||
QString mPattern;
|
||||
SynSearchOptions mOptions;
|
||||
};
|
||||
|
||||
using PSynSearchBase = std::shared_ptr<SynSearchBase>;
|
||||
|
||||
#endif // SYNSEARCHBASE_H
|
|
@ -0,0 +1,74 @@
|
|||
#include "SearchRegex.h"
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
SynSearchRegex::SynSearchRegex(QObject* parent):SynSearchBase(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SynSearchRegex::length(int aIndex)
|
||||
{
|
||||
if (aIndex<0 || aIndex >= mResults.length())
|
||||
return -1;
|
||||
return mLengths[aIndex];
|
||||
}
|
||||
|
||||
int SynSearchRegex::result(int aIndex)
|
||||
{
|
||||
if (aIndex<0 || aIndex >= mResults.length())
|
||||
return -1;
|
||||
return mResults[aIndex];
|
||||
}
|
||||
|
||||
int SynSearchRegex::resultCount()
|
||||
{
|
||||
return mResults.size();
|
||||
}
|
||||
|
||||
int SynSearchRegex::findAll(const QString &newText)
|
||||
{
|
||||
if (pattern().isEmpty())
|
||||
return 0;
|
||||
mResults.clear();
|
||||
mLengths.clear();
|
||||
QRegularExpressionMatchIterator it = mRegex.globalMatch(newText);
|
||||
while (it.hasNext()) {
|
||||
QRegularExpressionMatch match = it.next();
|
||||
mLengths.append(match.capturedLength());
|
||||
mResults.append(match.capturedStart());
|
||||
}
|
||||
return mResults.size();
|
||||
}
|
||||
|
||||
QString SynSearchRegex::replace(const QString &aOccurrence, const QString &aReplacement)
|
||||
{
|
||||
QString s=aOccurrence;
|
||||
return s.replace(mRegex,aReplacement);
|
||||
}
|
||||
|
||||
void SynSearchRegex::setPattern(const QString &value)
|
||||
{
|
||||
SynSearchBase::setPattern(value);
|
||||
mRegex.setPattern(value);
|
||||
updateRegexOptions();
|
||||
}
|
||||
|
||||
void SynSearchRegex::setOptions(const SynSearchOptions &options)
|
||||
{
|
||||
SynSearchBase::setOptions(options);
|
||||
updateRegexOptions();
|
||||
}
|
||||
|
||||
void SynSearchRegex::updateRegexOptions()
|
||||
{
|
||||
if (options().testFlag(SynSearchOption::ssoMatchCase)) {
|
||||
mRegex.setPatternOptions(
|
||||
mRegex.patternOptions() &
|
||||
~QRegularExpression::CaseInsensitiveOption);
|
||||
} else {
|
||||
mRegex.setPatternOptions(
|
||||
mRegex.patternOptions() |
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef SYNSEARCHREGEX_H
|
||||
#define SYNSEARCHREGEX_H
|
||||
#include "SearchBase.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
class SynSearchRegex : public SynSearchBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SynSearchRegex(QObject* parent=nullptr);
|
||||
|
||||
// SynSearchBase interface
|
||||
public:
|
||||
int length(int aIndex) override;
|
||||
int result(int aIndex) override;
|
||||
int resultCount() override;
|
||||
int findAll(const QString &newText) override;
|
||||
QString replace(const QString &aOccurrence, const QString &aReplacement) override;
|
||||
void setPattern(const QString &value) override;
|
||||
void setOptions(const SynSearchOptions &options) override;
|
||||
private:
|
||||
void updateRegexOptions();
|
||||
private:
|
||||
QRegularExpression mRegex;
|
||||
QList<int> mLengths;
|
||||
QList<int> mResults;
|
||||
};
|
||||
|
||||
#endif // SYNSEARCHREGEX_H
|
|
@ -3208,6 +3208,16 @@ void SynEdit::doScrolled(int)
|
|||
invalidate();
|
||||
}
|
||||
|
||||
PSynSearchBase SynEdit::searchEngine() const
|
||||
{
|
||||
return mSearchEngine;
|
||||
}
|
||||
|
||||
void SynEdit::setSearchEngine(const PSynSearchBase &searchEngine)
|
||||
{
|
||||
mSearchEngine = searchEngine;
|
||||
}
|
||||
|
||||
int SynEdit::textHeight() const
|
||||
{
|
||||
return mTextHeight;
|
||||
|
@ -4155,6 +4165,169 @@ void SynEdit::setSelText(const QString &Value)
|
|||
mActiveSelectionMode);
|
||||
}
|
||||
|
||||
int SynEdit::searchReplace(const QString &ASearch, const QString &AReplace, SynSearchOptions AOptions)
|
||||
{
|
||||
if (!mSearchEngine)
|
||||
return 0;
|
||||
|
||||
// can't search for or replace an empty string
|
||||
if (ASearch.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 bReplace = AOptions.testFlag(ssoReplace);
|
||||
bool bReplaceAll = AOptions.testFlag(ssoReplaceAll);
|
||||
bool bFromCursor = !AOptions.testFlag(ssoEntireScope);
|
||||
BufferCoord ptCurrent;
|
||||
BufferCoord ptStart;
|
||||
BufferCoord ptEnd;
|
||||
if (!selAvail())
|
||||
AOptions.setFlag(ssoSelectedOnly,false);
|
||||
if (AOptions.testFlag(ssoSelectedOnly)) {
|
||||
ptStart = blockBegin();
|
||||
ptEnd = blockEnd();
|
||||
// search the whole line in the line selection mode
|
||||
if (mActiveSelectionMode == SynSelectionMode::smLine) {
|
||||
ptStart.Char = 1;
|
||||
ptEnd.Char = mLines->getString(ptEnd.Line - 1).length();
|
||||
} else if (mActiveSelectionMode == SynSelectionMode::smColumn) {
|
||||
// make sure the start column is smaller than the end column
|
||||
if (ptStart.Char > ptEnd.Char)
|
||||
std::swap(ptStart.Char,ptEnd.Char);
|
||||
}
|
||||
// ignore the cursor position when searching in the selection
|
||||
if (bBackward) {
|
||||
ptCurrent = ptEnd;
|
||||
} else {
|
||||
ptCurrent = ptStart;
|
||||
}
|
||||
} else {
|
||||
ptStart.Char = 1;
|
||||
ptStart.Line = 1;
|
||||
ptEnd.Line = mLines->count();
|
||||
ptEnd.Char = mLines->getString(ptEnd.Line - 1).length();
|
||||
if (bFromCursor) {
|
||||
if (bBackward)
|
||||
ptEnd = caretXY();
|
||||
else
|
||||
ptStart = caretXY();
|
||||
}
|
||||
if (bBackward)
|
||||
ptCurrent = ptEnd;
|
||||
else
|
||||
ptCurrent = ptStart;
|
||||
}
|
||||
// initialize the search engine
|
||||
mSearchEngine->setOptions(AOptions);
|
||||
mSearchEngine->setPattern(ASearch);
|
||||
// search while the current search position is inside of the search range
|
||||
int nReplaceLen = 0;
|
||||
bool bEndUndoBlock =false;
|
||||
doOnPaintTransient(SynTransientType::ttBefore);
|
||||
if (bReplaceAll && !bPrompt) {
|
||||
incPaintLock();
|
||||
mUndoList->BeginBlock();
|
||||
bEndUndoBlock = true;
|
||||
}
|
||||
{
|
||||
auto action = finally([&,this]{
|
||||
if (bReplaceAll && !bPrompt)
|
||||
decPaintLock();
|
||||
if (bEndUndoBlock)
|
||||
mUndoList->EndBlock();
|
||||
doOnPaintTransient(SynTransientType::ttAfter);
|
||||
});
|
||||
while ((ptCurrent.Line >= ptStart.Line) && (ptCurrent.Line <= ptEnd.Line)) {
|
||||
nInLine := fSearchEngine.FindAll(Lines[ptCurrent.Line - 1]);
|
||||
iResultOffset := 0;
|
||||
if bBackward then
|
||||
n := Pred(fSearchEngine.ResultCount)
|
||||
else
|
||||
n := 0;
|
||||
// Operate on all results in this line.
|
||||
while nInLine > 0 do begin
|
||||
// An occurrence may have been replaced with a text of different length
|
||||
nFound := fSearchEngine.Results[n] + iResultOffset;
|
||||
nSearchLen := fSearchEngine.Lengths[n];
|
||||
if bBackward then
|
||||
Dec(n)
|
||||
else
|
||||
Inc(n);
|
||||
Dec(nInLine);
|
||||
// Is the search result entirely in the search range?
|
||||
if not InValidSearchRange(nFound, nFound + nSearchLen) then
|
||||
continue;
|
||||
Inc(Result);
|
||||
// Select the text, so the user can see it in the OnReplaceText event
|
||||
// handler or as the search result.
|
||||
|
||||
ptCurrent.Char := nFound;
|
||||
BlockBegin := ptCurrent;
|
||||
//Be sure to use the Ex version of CursorPos so that it appears in the middle if necessary
|
||||
SetCaretXYEx(False, BufferCoord(1, ptCurrent.Line));
|
||||
EnsureCursorPosVisibleEx(True);
|
||||
Inc(ptCurrent.Char, nSearchLen);
|
||||
BlockEnd := ptCurrent;
|
||||
InternalCaretXY := ptCurrent;
|
||||
if bBackward then
|
||||
InternalCaretXY := BlockBegin
|
||||
else
|
||||
InternalCaretXY := ptCurrent;
|
||||
// If it's a search only we can leave the procedure now.
|
||||
if not (bReplace or bReplaceAll) then
|
||||
exit;
|
||||
// Prompt and replace or replace all. If user chooses to replace
|
||||
// all after prompting, turn off prompting.
|
||||
if bPrompt and Assigned(fOnReplaceText) then begin
|
||||
nAction := DoOnReplaceText(ASearch, AReplace, ptCurrent.Line, nFound, nSearchLen);
|
||||
if nAction = raCancel then
|
||||
exit;
|
||||
end else
|
||||
nAction := raReplace;
|
||||
if nAction <> raSkip then begin
|
||||
// user has been prompted and has requested to silently replace all
|
||||
// so turn off prompting
|
||||
if nAction = raReplaceAll then begin
|
||||
if (not bReplaceAll) or bPrompt then begin
|
||||
bReplaceAll := TRUE;
|
||||
IncPaintLock;
|
||||
end;
|
||||
bPrompt := False;
|
||||
if bEndUndoBlock = false then
|
||||
BeginUndoBlock;
|
||||
bEndUndoBlock := true;
|
||||
end;
|
||||
//Allow advanced substition in the search engine
|
||||
SelText := fSearchEngine.Replace(SelText, AReplace);
|
||||
nReplaceLen := CaretX - nFound;
|
||||
end;
|
||||
// fix the caret position and the remaining results
|
||||
if not bBackward then begin
|
||||
InternalCaretX := nFound + nReplaceLen;
|
||||
if (nSearchLen <> nReplaceLen) and (nAction <> raSkip) then begin
|
||||
Inc(iResultOffset, nReplaceLen - nSearchLen);
|
||||
if (fActiveSelectionMode <> smColumn) and (CaretY = ptEnd.Line) then begin
|
||||
Inc(ptEnd.Char, nReplaceLen - nSearchLen);
|
||||
BlockEnd := ptEnd;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if not bReplaceAll then
|
||||
exit;
|
||||
end;
|
||||
// search next / previous line
|
||||
if bBackward then
|
||||
Dec(ptCurrent.Line)
|
||||
else
|
||||
Inc(ptCurrent.Line);
|
||||
end;
|
||||
}
|
||||
}
|
||||
|
||||
void SynEdit::DoLinesDeleted(int FirstLine, int Count)
|
||||
{
|
||||
// // gutter marks
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Types.h"
|
||||
#include "TextBuffer.h"
|
||||
#include "KeyStrokes.h"
|
||||
#include "SearchBase.h"
|
||||
|
||||
enum class SynFontSmoothMethod {
|
||||
None, AntiAlias, ClearType
|
||||
|
@ -214,6 +215,8 @@ public:
|
|||
PSynEditFoldRange foldHidesLine(int line);
|
||||
void setSelText(const QString& Value);
|
||||
|
||||
int searchReplace(const QString& ASearch, const QString& AReplace, SynSearchOptions AOptions);
|
||||
|
||||
int maxScrollWidth() const;
|
||||
int maxScrollHeight() const;
|
||||
|
||||
|
@ -322,6 +325,9 @@ public:
|
|||
|
||||
int textHeight() const;
|
||||
|
||||
PSynSearchBase searchEngine() const;
|
||||
void setSearchEngine(const PSynSearchBase &searchEngine);
|
||||
|
||||
signals:
|
||||
void Changed();
|
||||
|
||||
|
@ -587,6 +593,8 @@ private:
|
|||
int mScrollDeltaX;
|
||||
int mScrollDeltaY;
|
||||
|
||||
PSynSearchBase mSearchEngine;
|
||||
|
||||
PSynEdit fChainedEditor;
|
||||
|
||||
int mPaintTransientLock;
|
||||
|
|
Loading…
Reference in New Issue