From 6f052ca8dce0ff845b2af5660c174b022c9d7651 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Wed, 2 Dec 2009 02:24:37 +0000 Subject: [PATCH] [BUG_FIXED] (Author : Vitaliy Dovgan)Fix case-insensitive searching bug for non-ascii characters (for example some characters in French and Cyrillic characters). [BUG_FIXED] Fix brace highlighting performance issue. git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@578 f5eea248-9336-0410-98b8-ebc06183d4e3 --- PowerEditor/src/Notepad_plus.cpp | 67 +++++-- .../xmlMatchedTagsHighlighter.cpp | 34 +++- .../xmlMatchedTagsHighlighter.h | 2 +- scintilla/src/Document.cxx | 180 +++++++++++++++++- 4 files changed, 254 insertions(+), 29 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 0e87fc9b..430e0b4b 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -2753,7 +2753,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) } break; - case SCN_UPDATEUI: + case SCN_UPDATEUI: { NppParameters *nppParam = NppParameters::getInstance(); @@ -2763,11 +2763,52 @@ BOOL Notepad_plus::notify(SCNotification *notification) if (notification->nmhdr.hwndFrom != _pEditView->getHSelf()) break; + + braceMatch(); - NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI(); - - static int originalColour = _pEditView->execute(SCI_STYLEGETFORE, STYLE_BRACELIGHT); - _pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, originalColour); + NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI(); + + if (nppGui._enableTagsMatchHilite) + { + XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView); + xmlTagMatchHiliter.tagMatch(nppGui._enableTagAttrsHilite); + } + + if (nppGui._enableSmartHilite) + { + if (nppGui._disableSmartHiliteTmp) + nppGui._disableSmartHiliteTmp = false; + else + _smartHighlighter.highlightView(notifyView); + } + + updateStatusBar(); + AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; + autoC->update(0); + break; + } + +/* + case SCN_UPDATEUI: + { + + NppParameters *nppParam = NppParameters::getInstance(); + + // if it's searching/replacing, then do nothing + if (nppParam->_isFindReplacing) + break; + + if (notification->nmhdr.hwndFrom != _pEditView->getHSelf()) + break; + + static NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI(); + static StyleArray & stylers = nppParam->getMiscStylerArray(); + static int iBraceStyle = stylers.getStylerIndexByID(STYLE_BRACELIGHT); + if (iBraceStyle != -1) + { + Style *pBraceStyle = &(stylers.getStyler(iBraceStyle)); + _pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, pBraceStyle->_fgColor); + } if (braceMatch()) { @@ -2780,6 +2821,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) { XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView); pair tagPos = xmlTagMatchHiliter.tagMatch(nppGui._enableTagAttrsHilite); + int braceAtCaret = tagPos.first; int braceOpposite = tagPos.second; @@ -2788,6 +2830,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) { _pEditView->execute(SCI_SETHIGHLIGHTGUIDE, 0); } + else if (_pEditView->isShownIndentGuide()) { int columnAtCaret = int(_pEditView->execute(SCI_GETCOLUMN, braceAtCaret)); @@ -2797,22 +2840,21 @@ BOOL Notepad_plus::notify(SCNotification *notification) int lineOpposite = int(_pEditView->execute(SCI_LINEFROMPOSITION, braceOpposite)); if (lineAtCaret != lineOpposite) { - - StyleArray & stylers = nppParam->getMiscStylerArray(); - int iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_TAGMATCH); - if (iFind) + static int iTagMatchStyle = stylers.getStylerIndexByID(SCE_UNIVERSAL_TAGMATCH); + if (iTagMatchStyle != -1) { - Style *pStyle = &(stylers.getStyler(iFind)); - _pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, pStyle->_bgColor); + Style *pTagStyle = &(stylers.getStyler(iTagMatchStyle)); + _pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, pTagStyle->_bgColor); } // braceAtCaret - 1, braceOpposite-1 : walk around to not highlight the '<' _pEditView->execute(SCI_BRACEHIGHLIGHT, braceAtCaret-1, braceOpposite-1); _pEditView->execute(SCI_SETHIGHLIGHTGUIDE, (columnAtCaret < columnOpposite)?columnAtCaret:columnOpposite); } } + } } - + if (nppGui._enableSmartHilite) { @@ -2826,6 +2868,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) autoC->update(0); break; } +*/ case SCN_SCROLLED: { diff --git a/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp index be625290..df651115 100644 --- a/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp +++ b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp @@ -439,7 +439,7 @@ vector< pair > XmlMatchedTagsHighlighter::getAttributesPos(int start, -pair XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) +void XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) { // Clean up all marks of previous action _pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH); @@ -449,21 +449,22 @@ pair XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) LangType lang = (_pEditView->getCurrentBuffer())->getLangType(); if (lang != L_XML && lang != L_HTML && lang != L_PHP && lang != L_ASP) - return pair(-1, -1); + return; // Get the original targets and search options to restore after tag matching operation int originalStartPos = _pEditView->execute(SCI_GETTARGETSTART); int originalEndPos = _pEditView->execute(SCI_GETTARGETEND); int originalSearchFlags = _pEditView->execute(SCI_GETSEARCHFLAGS); - // Detect if it's a xml/html tag. If yes, Colour it! XmlMatchedTagsPos xmlTags; + + // Detect if it's a xml/html tag. If yes, Colour it! if (getXmlMatchedTagsPos(xmlTags)) { - _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH); - + _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH); int openTagTailLen = 2; - // We colourise the close tag firstly + + // Colourising the close tag firstly if ((xmlTags.tagCloseStart != -1) && (xmlTags.tagCloseEnd != -1)) { _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagCloseStart, xmlTags.tagCloseEnd - xmlTags.tagCloseStart); @@ -471,11 +472,13 @@ pair XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) openTagTailLen = 1; } - // Now the open tag and its attributs + // Colourising the open tag _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenStart, xmlTags.tagNameEnd - xmlTags.tagOpenStart); _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenEnd - openTagTailLen, openTagTailLen); - if (doHiliteAttr) + + // Colouising its attributs + if (doHiliteAttr) { vector< pair > attributes = getAttributesPos(xmlTags.tagNameEnd, xmlTags.tagOpenEnd - openTagTailLen); _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGATTR); @@ -483,6 +486,19 @@ pair XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) { _pEditView->execute(SCI_INDICATORFILLRANGE, attributes[i].first, attributes[i].second - attributes[i].first); } + } + + // Colouising indent guide line position + int columnAtCaret = int(_pEditView->execute(SCI_GETCOLUMN, xmlTags.tagOpenStart)); + int columnOpposite = int(_pEditView->execute(SCI_GETCOLUMN, xmlTags.tagCloseStart)); + + int lineAtCaret = int(_pEditView->execute(SCI_LINEFROMPOSITION, xmlTags.tagOpenStart)); + int lineOpposite = int(_pEditView->execute(SCI_LINEFROMPOSITION, xmlTags.tagCloseStart)); + + if (xmlTags.tagCloseStart != -1 && lineAtCaret != lineOpposite) + { + _pEditView->execute(SCI_BRACEHIGHLIGHT, xmlTags.tagOpenStart, xmlTags.tagCloseEnd-1); + _pEditView->execute(SCI_SETHIGHLIGHTGUIDE, (columnAtCaret < columnOpposite)?columnAtCaret:columnOpposite); } } @@ -490,6 +506,4 @@ pair XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) _pEditView->execute(SCI_SETTARGETSTART, originalStartPos); _pEditView->execute(SCI_SETTARGETEND, originalEndPos); _pEditView->execute(SCI_SETSEARCHFLAGS, originalSearchFlags); - - return pair(xmlTags.tagOpenStart, xmlTags.tagCloseStart); } diff --git a/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h index 6c3f9960..b0b40b9f 100644 --- a/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h +++ b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h @@ -27,7 +27,7 @@ enum TagCateg {tagOpen, tagClose, inSingleTag, outOfTag, invalidTag, unknownPb}; class XmlMatchedTagsHighlighter { public: XmlMatchedTagsHighlighter(ScintillaEditView *pEditView):_pEditView(pEditView){}; - pair tagMatch(bool doHiliteAttr); + void tagMatch(bool doHiliteAttr); private: struct XmlMatchedTagsPos { diff --git a/scintilla/src/Document.cxx b/scintilla/src/Document.cxx index 77024948..4b252733 100644 --- a/scintilla/src/Document.cxx +++ b/scintilla/src/Document.cxx @@ -27,6 +27,98 @@ using namespace Scintilla; #endif +//Vitaliy +#include "UniConversion.h" +#include +#ifdef FindText + #undef FindText + #define FindText FindText +#endif + +// Win32 only !!! +static bool IsMustDie9x(void) +{ + OSVERSIONINFO osver; + osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if ( GetVersionEx( &osver ) ) + { + if ( (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && + (osver.dwMajorVersion == 4) ) + { + //MessageBox(NULL, "MustDie9x == true", "Test", MB_OK); + return true; + } + } + //MessageBox(NULL, "MustDie9x == false", "Test", MB_OK); + return false; +} + +static inline void Platform_MakeUpperW(wchar_t* wstr, unsigned int len) { + // TODO: Add platform-specific function here + + // Win32 example: + static bool bIsMustDie9x = IsMustDie9x(); + + if ( !bIsMustDie9x ) + { + ::CharUpperW(wstr); + } + else + { + char* str = new char[len + 1]; + if ( str ) + { + ::WideCharToMultiByte(CP_ACP, 0, wstr, len, str, len, NULL, NULL); + str[len] = 0; + ::CharUpperA(str); + ::MultiByteToWideChar(CP_ACP, 0, str, len, wstr, len); + wstr[len] = 0; + delete [] str; + } + } +} + +static inline char Platform_MakeUpperCharA(const char ch) { + // TODO: Add platform-specific function here + + // Win32 example: + char str[2] = {ch, 0}; + ::CharUpperA(str); + return str[0]; +} + +static inline char Platform_MakeLowerCharA(const char ch) { + // TODO: Add platform-specific function here + + // Win32 example: + char str[2] = {ch, 0}; + ::CharLowerA(str); + return str[0]; +} + +// NOTE: this function is called for non-Unicode characters only! +// ( i.e. when (!dbcsCodePage || isascii(ch)) ) +static inline char MakeUpperCaseA(char ch) { + if (ch >= 'A' && ch <= 'Z') + return ch; + else if (ch >= 'a' && ch <= 'z') + return static_cast(ch - 'a' + 'A'); + else + return Platform_MakeUpperCharA(ch); +} + +// NOTE: this function is called for non-Unicode characters only! +// ( i.e. when (!dbcsCodePage || isascii(ch)) ) +static inline char MakeLowerCaseA(char ch) { + if (ch >= 'a' && ch <= 'z') + return ch; + else if (ch >= 'A' && ch <= 'Z') + return static_cast(ch - 'A' + 'a'); + else + return Platform_MakeLowerCharA(ch); +} +// yilatiV + // This is ASCII specific but is safe with chars >= 0x80 static inline bool isspacechar(unsigned char ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); @@ -1104,9 +1196,34 @@ long Document::FindText(int minPos, int maxPos, const char *s, endSearch = endPos - lengthFind + 1; } //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); + + // >>> Added by DV + wchar_t* ws_upr = NULL; // string we are searching for in UCS-2 + wchar_t temp_ws[4]; // buffer for current character in UCS-2 + char temp_s[8]; // buffer for current character in UTF-8 + int ws_len = 0; + + if (dbcsCodePage == SC_CP_UTF8 && !caseSensitive) + { + ws_len = (int) UTF16Length(s, lengthFind); + if (ws_len != lengthFind) { + const int ws_size = ws_len + 2; + ws_upr = new wchar_t[ws_size]; + if (ws_upr) { + UTF16FromUTF8(s, lengthFind, ws_upr, ws_size - 1); + ws_upr[ws_len] = 0; + Platform_MakeUpperW(ws_upr, ws_len); + // now ws_upr is UCS-2 representation of s in upper-case + } + } + // else we are searching for Latin characters + // i.e. no special processing required + } + // <<< Added by DV + char firstChar = s[0]; if (!caseSensitive) - firstChar = static_cast(MakeUpperCase(firstChar)); + firstChar = static_cast(MakeUpperCaseA(firstChar)); int pos = forward ? startPos : (startPos - 1); while (forward ? (pos < endSearch) : (pos >= endSearch)) { char ch = CharAt(pos); @@ -1126,13 +1243,57 @@ long Document::FindText(int minPos, int maxPos, const char *s, return pos; } } - } else { - if (MakeUpperCase(ch) == firstChar) { + } + + // >>> Added by DV + else if (ws_upr) { + const int maxPos = Platform::Maximum(startPos, endPos); + int charPos = pos; + int ws_len_checked = 0; + + while (ws_len_checked < ws_len) { + // LenChar returns 2 for "\r\n" + // this is wrong for UTF8 because "\r\n" + // is not one character with length=2 + const int charLen = IsCrLf(charPos) ? 1 : LenChar(charPos); + if (charPos + charLen > maxPos) + break; + + // current UTF-8 character + for (int i = 0; i < charLen; i++) { + temp_s[i] = CharAt(charPos + i); + } + temp_s[charLen] = 0; + // current character as UCS-2 + const unsigned int uLen = UTF16FromUTF8(temp_s, charLen, temp_ws, 3); + temp_ws[uLen] = 0; // uLen can be 1 (ordinary) or 2 (surrogate) + // upper case + Platform_MakeUpperW(temp_ws, uLen); + if ((temp_ws[0] == ws_upr[ws_len_checked]) && + (uLen == 1 || temp_ws[1] == ws_upr[ws_len_checked+1])) { + ws_len_checked += uLen; + charPos += charLen; // go to next character + } else + break; + } + if (ws_len_checked == ws_len) { + if ((!word && !wordStart) || + (word && IsWordAt(pos, pos + lengthFind)) || + (wordStart && IsWordStartAt(pos))) { + delete [] ws_upr; + return pos; + } + } + } + // <<< Added by DV + + else { + if (MakeUpperCaseA(ch) == firstChar) { bool found = true; if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false; for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { ch = CharAt(pos + posMatch); - if (MakeUpperCase(ch) != MakeUpperCase(s[posMatch])) + if (MakeUpperCaseA(ch) != MakeUpperCaseA(s[posMatch])) found = false; } if (found) { @@ -1149,6 +1310,13 @@ long Document::FindText(int minPos, int maxPos, const char *s, pos = MovePositionOutsideChar(pos, increment, false); } } + + // >>> Added by DV + if (ws_upr) { + delete [] ws_upr; + } + // <<< Added by DV + } //Platform::DebugPrintf("Not found\n"); return -1; @@ -1169,11 +1337,11 @@ void Document::ChangeCase(Range r, bool makeUpperCase) { char ch = CharAt(pos); if (makeUpperCase) { if (IsLowerCase(ch)) { - ChangeChar(pos, static_cast(MakeUpperCase(ch))); + ChangeChar(pos, static_cast(MakeUpperCaseA(ch))); } } else { if (IsUpperCase(ch)) { - ChangeChar(pos, static_cast(MakeLowerCase(ch))); + ChangeChar(pos, static_cast(MakeLowerCaseA(ch))); } } }