work save

This commit is contained in:
royqh1979@gmail.com 2021-08-02 17:24:11 +08:00
parent 813bacebfb
commit 100ceeda6c
9 changed files with 429 additions and 0 deletions

View File

@ -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 \

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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;