mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
+ fix: support groups/regions in replacement string
This commit is contained in:
parent
80e6a87d52
commit
eba23c6cdc
@ -42,14 +42,20 @@ using namespace Scintilla;
|
||||
|
||||
#define Cast2long(n) static_cast<long>(n)
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// ============================================================================
|
||||
// *** Oninuruma configuration ***
|
||||
// ============================================================================
|
||||
|
||||
const int MAX_GROUP_COUNT = 10;
|
||||
const bool gOnigExtended = false; // ignore spaces and use '#' as line-comment)
|
||||
|
||||
const OnigEncoding g_pEncodingType = ONIG_ENCODING_ASCII; // ONIG_ENCODING_SJIS
|
||||
static OnigEncoding use_encs[] = { g_pEncodingType };
|
||||
const OnigEncoding g_pOnigEncodingType = ONIG_ENCODING_ASCII; // ONIG_ENCODING_SJIS
|
||||
|
||||
const bool gExtended = false; // ignore spaces and use '#' as line-comment)
|
||||
static OnigSyntaxType* g_pOnigSyntaxType = ONIG_SYNTAX_DEFAULT;
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
static OnigEncoding use_encs[] = { g_pOnigEncodingType };
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@ -60,21 +66,19 @@ public:
|
||||
explicit OniguRegExEngine(CharClassify* charClassTable)
|
||||
: m_RegExprStrg()
|
||||
, m_CmplOptions(ONIG_OPTION_DEFAULT)
|
||||
, m_pRegExpr(nullptr)
|
||||
, m_RegExpr(nullptr)
|
||||
, m_Region({0,0,nullptr,nullptr,nullptr})
|
||||
, m_ErrorInfo()
|
||||
, m_MatchPos(ONIG_MISMATCH)
|
||||
, m_MatchLen(0)
|
||||
, m_SubstBuffer()
|
||||
{
|
||||
onig_initialize(use_encs, sizeof(use_encs) / sizeof(use_encs[0]));
|
||||
m_pRegion = onig_region_new();
|
||||
}
|
||||
|
||||
virtual ~OniguRegExEngine()
|
||||
{
|
||||
if (m_pRegion)
|
||||
onig_region_free(m_pRegion, 1);
|
||||
|
||||
onig_region_free(&m_Region, 0);
|
||||
onig_end();
|
||||
}
|
||||
|
||||
@ -94,8 +98,9 @@ private:
|
||||
std::string m_RegExprStrg;
|
||||
|
||||
OnigOptionType m_CmplOptions;
|
||||
regex_t* m_pRegExpr;
|
||||
OnigRegion* m_pRegion;
|
||||
OnigRegex m_RegExpr;
|
||||
OnigRegion m_Region;
|
||||
|
||||
char m_ErrorInfo[ONIG_MAX_ERROR_MESSAGE_LEN];
|
||||
|
||||
Sci::Position m_MatchPos;
|
||||
@ -123,40 +128,52 @@ long OniguRegExEngine::FindText(Document* doc, Sci::Position minPos, Sci::Positi
|
||||
bool caseSensitive, bool word, bool wordStart, int searchFlags, Sci::Position *length)
|
||||
{
|
||||
|
||||
// Range endpoints should not be inside DBCS characters, but just in case, move them.
|
||||
// Range endpoints should not be inside DBCS characters, but just in case, move them.
|
||||
minPos = doc->MovePositionOutsideChar(minPos, 1, false);
|
||||
maxPos = doc->MovePositionOutsideChar(maxPos, 1, false);
|
||||
const bool findprevious = (minPos > maxPos);
|
||||
|
||||
|
||||
OnigOptionType cmplOptions = ONIG_OPTION_DEFAULT;
|
||||
cmplOptions |= (ONIG_OPTION_MULTILINE | ONIG_OPTION_CAPTURE_GROUP); // the .(dot) does not match line-breaks
|
||||
cmplOptions |= (gExtended) ? ONIG_OPTION_EXTEND : ONIG_OPTION_NONE;
|
||||
cmplOptions |= (caseSensitive) ? ONIG_OPTION_NONE : ONIG_OPTION_IGNORECASE;
|
||||
ONIG_OPTION_ON(cmplOptions, ONIG_OPTION_MULTILINE); // the .(dot) does not match line-breaks
|
||||
ONIG_OPTION_ON(cmplOptions, ONIG_OPTION_CAPTURE_GROUP);
|
||||
ONIG_OPTION_ON(cmplOptions, gOnigExtended ? ONIG_OPTION_EXTEND : ONIG_OPTION_NONE);
|
||||
ONIG_OPTION_ON(cmplOptions, caseSensitive ? ONIG_OPTION_NONE : ONIG_OPTION_IGNORECASE);
|
||||
|
||||
|
||||
std::string sRegExprStrg = translateRegExpr(std::string(pattern), word, wordStart, doc->eolMode);
|
||||
|
||||
bool bReCompile = (m_CmplOptions != cmplOptions) || (m_RegExprStrg.compare(sRegExprStrg) != 0);
|
||||
bool bReCompile = (m_RegExpr == nullptr) || (m_CmplOptions != cmplOptions) || (m_RegExprStrg.compare(sRegExprStrg) != 0);
|
||||
|
||||
if (bReCompile) {
|
||||
if (bReCompile)
|
||||
{
|
||||
m_RegExprStrg.clear();
|
||||
m_RegExprStrg = sRegExprStrg;
|
||||
m_CmplOptions = cmplOptions;
|
||||
m_ErrorInfo[0] = '\0';
|
||||
try {
|
||||
OnigErrorInfo einfo;
|
||||
int result = onig_new(&m_pRegExpr, (UChar*)m_RegExprStrg.c_str(), (UChar*)(m_RegExprStrg.c_str() + m_RegExprStrg.length()),
|
||||
m_CmplOptions, g_pEncodingType, ONIG_SYNTAX_DEFAULT, &einfo);
|
||||
if (result != 0) {
|
||||
onig_error_code_to_str((UChar*)m_ErrorInfo, result, &einfo);
|
||||
|
||||
onig_region_free(&m_Region, 0);
|
||||
|
||||
int res = onig_new(&m_RegExpr, (UChar*)m_RegExprStrg.c_str(), (UChar*)(m_RegExprStrg.c_str() + m_RegExprStrg.length()),
|
||||
m_CmplOptions, g_pOnigEncodingType, g_pOnigSyntaxType, &einfo);
|
||||
if (res != 0) {
|
||||
onig_error_code_to_str((UChar*)m_ErrorInfo, res, &einfo);
|
||||
return Cast2long(-2);
|
||||
}
|
||||
|
||||
onig_region_init(&m_Region);
|
||||
}
|
||||
catch (...) {
|
||||
return Cast2long(-2); // -1 is normally used for not found, -2 is used here for invalid regex
|
||||
}
|
||||
}
|
||||
|
||||
m_MatchPos = SciPos(ONIG_MISMATCH); // not found
|
||||
m_MatchLen = SciPos(0);
|
||||
|
||||
// --- search document range for pattern match ---
|
||||
|
||||
UChar* docBegPtr = (UChar*)doc->RangePointer(0, SciPos(doc->Length()));
|
||||
UChar* docSEndPtr = (UChar*)doc->RangePointer(SciPos(doc->Length()),0);
|
||||
@ -164,35 +181,34 @@ long OniguRegExEngine::FindText(Document* doc, Sci::Position minPos, Sci::Positi
|
||||
UChar* rangeBegPtr = (UChar*)doc->RangePointer((findprevious) ? maxPos : minPos, rangeLength);
|
||||
UChar* rangeEndPtr = (UChar*)doc->RangePointer((findprevious) ? minPos : maxPos, rangeLength);
|
||||
|
||||
m_MatchPos = SciPos(ONIG_MISMATCH); // not found
|
||||
m_MatchLen = SciPos(0);
|
||||
OnigOptionType searchOptions = ONIG_OPTION_NONE;
|
||||
ONIG_OPTION_ON(searchOptions, ONIG_OPTION_NOTBOL);
|
||||
ONIG_OPTION_ON(searchOptions, ONIG_OPTION_NOTEOL);
|
||||
|
||||
int result = onig_search(m_pRegExpr, docBegPtr, docSEndPtr, rangeBegPtr, rangeEndPtr, m_pRegion, ONIG_OPTION_NONE);
|
||||
int result = onig_search(m_RegExpr, docBegPtr, docSEndPtr, rangeBegPtr, rangeEndPtr, &m_Region, searchOptions);
|
||||
|
||||
if (result < ONIG_MISMATCH) {
|
||||
onig_error_code_to_str((UChar*)m_ErrorInfo, result);
|
||||
return Cast2long(-2);
|
||||
}
|
||||
|
||||
if (findprevious) // search previous
|
||||
if (findprevious) // search for last occurrence in range
|
||||
{
|
||||
// search for last occurrence in range
|
||||
//SPEEDUP: onig_scan() ???
|
||||
while ((result >= 0) && (rangeBegPtr <= rangeEndPtr))
|
||||
{
|
||||
m_MatchPos = SciPos(m_pRegion->beg[0]);
|
||||
m_MatchLen = SciPos(m_pRegion->end[0] - m_pRegion->beg[0]);
|
||||
m_MatchPos = SciPos(result); //SciPos(m_Region.beg[0]);
|
||||
m_MatchLen = SciPos(m_Region.end[0] - result);
|
||||
|
||||
rangeBegPtr = docBegPtr + (m_MatchPos + m_MatchLen);
|
||||
|
||||
result = onig_search(m_pRegExpr, docBegPtr, docSEndPtr, rangeBegPtr, rangeEndPtr, m_pRegion, ONIG_OPTION_NONE);
|
||||
result = onig_search(m_RegExpr, docBegPtr, docSEndPtr, rangeBegPtr, rangeEndPtr, &m_Region, searchOptions);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((result >= 0) && (rangeBegPtr <= rangeEndPtr)) {
|
||||
m_MatchPos = SciPos(m_pRegion->beg[0]);
|
||||
m_MatchLen = SciPos(m_pRegion->end[0] - m_pRegion->beg[0]);
|
||||
}
|
||||
else if ((result >= 0) && (rangeBegPtr <= rangeEndPtr))
|
||||
{
|
||||
m_MatchPos = SciPos(result); //SciPos(m_Region.beg[0]);
|
||||
m_MatchLen = SciPos(m_Region.end[0] - result);
|
||||
}
|
||||
|
||||
//NOTE: potential 64-bit-size issue at interface here:
|
||||
@ -204,8 +220,46 @@ long OniguRegExEngine::FindText(Document* doc, Sci::Position minPos, Sci::Positi
|
||||
|
||||
const char* OniguRegExEngine::SubstituteByPosition(Document* doc, const char* text, Sci::Position* length)
|
||||
{
|
||||
|
||||
if (m_MatchPos < 0) {
|
||||
*length = SciPos(-1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string rawReplStrg = convertReplExpr(std::string(text, *length));
|
||||
|
||||
m_SubstBuffer.clear();
|
||||
|
||||
for (int j = 0; j < rawReplStrg.length(); j++) {
|
||||
if ((rawReplStrg[j] == '$') || (rawReplStrg[j] == '\\'))
|
||||
{
|
||||
if ((rawReplStrg[j + 1] >= '0') && (rawReplStrg[j + 1] <= '9'))
|
||||
{
|
||||
int grpNum = rawReplStrg[j + 1] - '0';
|
||||
|
||||
if (grpNum < m_Region.num_regs)
|
||||
{
|
||||
Sci::Position rBeg = SciPos(m_Region.beg[grpNum]);
|
||||
Sci::Position len = SciPos(m_Region.end[grpNum] - rBeg);
|
||||
|
||||
m_SubstBuffer.append(doc->RangePointer(rBeg, len), (size_t)len);
|
||||
}
|
||||
++j;
|
||||
}
|
||||
else if (rawReplStrg[j] == '\\') {
|
||||
m_SubstBuffer.push_back('\\');
|
||||
++j;
|
||||
}
|
||||
else {
|
||||
m_SubstBuffer.push_back(rawReplStrg[j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_SubstBuffer.push_back(rawReplStrg[j]);
|
||||
}
|
||||
}
|
||||
//NOTE: potential 64-bit-size issue at interface here:
|
||||
*length = SciPos(0);
|
||||
*length = SciPos(m_SubstBuffer.length());
|
||||
return m_SubstBuffer.c_str();
|
||||
}
|
||||
// ============================================================================
|
||||
|
||||
@ -5670,7 +5670,6 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)
|
||||
case SCN_SAVEPOINTREACHED:
|
||||
bModified = FALSE;
|
||||
UpdateToolbar();
|
||||
EditUpdateUrlHotspots(hwndEdit, 0, SciCall_GetTextLength(), bHyperlinkHotspot);
|
||||
break;
|
||||
|
||||
case SCN_MARGINCLICK:
|
||||
@ -5686,7 +5685,6 @@ LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)
|
||||
case SCN_SAVEPOINTLEFT:
|
||||
bModified = TRUE;
|
||||
UpdateToolbar();
|
||||
EditUpdateUrlHotspots(hwndEdit, 0, SciCall_GetTextLength(), bHyperlinkHotspot);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user