[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
This commit is contained in:
Don Ho 2009-12-02 02:24:37 +00:00
parent 51e96391c6
commit 6f052ca8dc
4 changed files with 254 additions and 29 deletions

View File

@ -2753,7 +2753,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
} }
break; break;
case SCN_UPDATEUI: case SCN_UPDATEUI:
{ {
NppParameters *nppParam = NppParameters::getInstance(); NppParameters *nppParam = NppParameters::getInstance();
@ -2764,10 +2764,51 @@ BOOL Notepad_plus::notify(SCNotification *notification)
if (notification->nmhdr.hwndFrom != _pEditView->getHSelf()) if (notification->nmhdr.hwndFrom != _pEditView->getHSelf())
break; break;
NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI(); braceMatch();
static int originalColour = _pEditView->execute(SCI_STYLEGETFORE, STYLE_BRACELIGHT); NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI();
_pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, originalColour);
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()) if (braceMatch())
{ {
@ -2781,6 +2822,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView); XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView);
pair<int, int> tagPos = xmlTagMatchHiliter.tagMatch(nppGui._enableTagAttrsHilite); pair<int, int> tagPos = xmlTagMatchHiliter.tagMatch(nppGui._enableTagAttrsHilite);
int braceAtCaret = tagPos.first; int braceAtCaret = tagPos.first;
int braceOpposite = tagPos.second; int braceOpposite = tagPos.second;
@ -2788,6 +2830,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
{ {
_pEditView->execute(SCI_SETHIGHLIGHTGUIDE, 0); _pEditView->execute(SCI_SETHIGHLIGHTGUIDE, 0);
} }
else if (_pEditView->isShownIndentGuide()) else if (_pEditView->isShownIndentGuide())
{ {
int columnAtCaret = int(_pEditView->execute(SCI_GETCOLUMN, braceAtCaret)); int columnAtCaret = int(_pEditView->execute(SCI_GETCOLUMN, braceAtCaret));
@ -2797,19 +2840,18 @@ BOOL Notepad_plus::notify(SCNotification *notification)
int lineOpposite = int(_pEditView->execute(SCI_LINEFROMPOSITION, braceOpposite)); int lineOpposite = int(_pEditView->execute(SCI_LINEFROMPOSITION, braceOpposite));
if (lineAtCaret != lineOpposite) if (lineAtCaret != lineOpposite)
{ {
static int iTagMatchStyle = stylers.getStylerIndexByID(SCE_UNIVERSAL_TAGMATCH);
StyleArray & stylers = nppParam->getMiscStylerArray(); if (iTagMatchStyle != -1)
int iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_TAGMATCH);
if (iFind)
{ {
Style *pStyle = &(stylers.getStyler(iFind)); Style *pTagStyle = &(stylers.getStyler(iTagMatchStyle));
_pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, pStyle->_bgColor); _pEditView->execute(SCI_STYLESETFORE, STYLE_BRACELIGHT, pTagStyle->_bgColor);
} }
// braceAtCaret - 1, braceOpposite-1 : walk around to not highlight the '<' // braceAtCaret - 1, braceOpposite-1 : walk around to not highlight the '<'
_pEditView->execute(SCI_BRACEHIGHLIGHT, braceAtCaret-1, braceOpposite-1); _pEditView->execute(SCI_BRACEHIGHLIGHT, braceAtCaret-1, braceOpposite-1);
_pEditView->execute(SCI_SETHIGHLIGHTGUIDE, (columnAtCaret < columnOpposite)?columnAtCaret:columnOpposite); _pEditView->execute(SCI_SETHIGHLIGHTGUIDE, (columnAtCaret < columnOpposite)?columnAtCaret:columnOpposite);
} }
} }
} }
} }
@ -2826,6 +2868,7 @@ BOOL Notepad_plus::notify(SCNotification *notification)
autoC->update(0); autoC->update(0);
break; break;
} }
*/
case SCN_SCROLLED: case SCN_SCROLLED:
{ {

View File

@ -439,7 +439,7 @@ vector< pair<int, int> > XmlMatchedTagsHighlighter::getAttributesPos(int start,
pair<int, int> XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr) void XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr)
{ {
// Clean up all marks of previous action // Clean up all marks of previous action
_pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH); _pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH);
@ -449,21 +449,22 @@ pair<int, int> XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr)
LangType lang = (_pEditView->getCurrentBuffer())->getLangType(); LangType lang = (_pEditView->getCurrentBuffer())->getLangType();
if (lang != L_XML && lang != L_HTML && lang != L_PHP && lang != L_ASP) if (lang != L_XML && lang != L_HTML && lang != L_PHP && lang != L_ASP)
return pair<int, int>(-1, -1); return;
// Get the original targets and search options to restore after tag matching operation // Get the original targets and search options to restore after tag matching operation
int originalStartPos = _pEditView->execute(SCI_GETTARGETSTART); int originalStartPos = _pEditView->execute(SCI_GETTARGETSTART);
int originalEndPos = _pEditView->execute(SCI_GETTARGETEND); int originalEndPos = _pEditView->execute(SCI_GETTARGETEND);
int originalSearchFlags = _pEditView->execute(SCI_GETSEARCHFLAGS); int originalSearchFlags = _pEditView->execute(SCI_GETSEARCHFLAGS);
// Detect if it's a xml/html tag. If yes, Colour it!
XmlMatchedTagsPos xmlTags; XmlMatchedTagsPos xmlTags;
// Detect if it's a xml/html tag. If yes, Colour it!
if (getXmlMatchedTagsPos(xmlTags)) if (getXmlMatchedTagsPos(xmlTags))
{ {
_pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH); _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH);
int openTagTailLen = 2; int openTagTailLen = 2;
// We colourise the close tag firstly
// Colourising the close tag firstly
if ((xmlTags.tagCloseStart != -1) && (xmlTags.tagCloseEnd != -1)) if ((xmlTags.tagCloseStart != -1) && (xmlTags.tagCloseEnd != -1))
{ {
_pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagCloseStart, xmlTags.tagCloseEnd - xmlTags.tagCloseStart); _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagCloseStart, xmlTags.tagCloseEnd - xmlTags.tagCloseStart);
@ -471,11 +472,13 @@ pair<int, int> XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr)
openTagTailLen = 1; 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.tagOpenStart, xmlTags.tagNameEnd - xmlTags.tagOpenStart);
_pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenEnd - openTagTailLen, openTagTailLen); _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenEnd - openTagTailLen, openTagTailLen);
if (doHiliteAttr)
// Colouising its attributs
if (doHiliteAttr)
{ {
vector< pair<int, int> > attributes = getAttributesPos(xmlTags.tagNameEnd, xmlTags.tagOpenEnd - openTagTailLen); vector< pair<int, int> > attributes = getAttributesPos(xmlTags.tagNameEnd, xmlTags.tagOpenEnd - openTagTailLen);
_pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGATTR); _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGATTR);
@ -483,6 +486,19 @@ pair<int, int> XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr)
{ {
_pEditView->execute(SCI_INDICATORFILLRANGE, attributes[i].first, attributes[i].second - attributes[i].first); _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<int, int> XmlMatchedTagsHighlighter::tagMatch(bool doHiliteAttr)
_pEditView->execute(SCI_SETTARGETSTART, originalStartPos); _pEditView->execute(SCI_SETTARGETSTART, originalStartPos);
_pEditView->execute(SCI_SETTARGETEND, originalEndPos); _pEditView->execute(SCI_SETTARGETEND, originalEndPos);
_pEditView->execute(SCI_SETSEARCHFLAGS, originalSearchFlags); _pEditView->execute(SCI_SETSEARCHFLAGS, originalSearchFlags);
return pair<int, int>(xmlTags.tagOpenStart, xmlTags.tagCloseStart);
} }

View File

@ -27,7 +27,7 @@ enum TagCateg {tagOpen, tagClose, inSingleTag, outOfTag, invalidTag, unknownPb};
class XmlMatchedTagsHighlighter { class XmlMatchedTagsHighlighter {
public: public:
XmlMatchedTagsHighlighter(ScintillaEditView *pEditView):_pEditView(pEditView){}; XmlMatchedTagsHighlighter(ScintillaEditView *pEditView):_pEditView(pEditView){};
pair<int, int> tagMatch(bool doHiliteAttr); void tagMatch(bool doHiliteAttr);
private: private:
struct XmlMatchedTagsPos { struct XmlMatchedTagsPos {

View File

@ -27,6 +27,98 @@
using namespace Scintilla; using namespace Scintilla;
#endif #endif
//Vitaliy
#include "UniConversion.h"
#include <windows.h>
#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<char>(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<char>(ch - 'A' + 'a');
else
return Platform_MakeLowerCharA(ch);
}
// yilatiV
// This is ASCII specific but is safe with chars >= 0x80 // This is ASCII specific but is safe with chars >= 0x80
static inline bool isspacechar(unsigned char ch) { static inline bool isspacechar(unsigned char ch) {
return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
@ -1104,9 +1196,34 @@ long Document::FindText(int minPos, int maxPos, const char *s,
endSearch = endPos - lengthFind + 1; endSearch = endPos - lengthFind + 1;
} }
//Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); //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]; char firstChar = s[0];
if (!caseSensitive) if (!caseSensitive)
firstChar = static_cast<char>(MakeUpperCase(firstChar)); firstChar = static_cast<char>(MakeUpperCaseA(firstChar));
int pos = forward ? startPos : (startPos - 1); int pos = forward ? startPos : (startPos - 1);
while (forward ? (pos < endSearch) : (pos >= endSearch)) { while (forward ? (pos < endSearch) : (pos >= endSearch)) {
char ch = CharAt(pos); char ch = CharAt(pos);
@ -1126,13 +1243,57 @@ long Document::FindText(int minPos, int maxPos, const char *s,
return pos; 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; bool found = true;
if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false; if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false;
for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) {
ch = CharAt(pos + posMatch); ch = CharAt(pos + posMatch);
if (MakeUpperCase(ch) != MakeUpperCase(s[posMatch])) if (MakeUpperCaseA(ch) != MakeUpperCaseA(s[posMatch]))
found = false; found = false;
} }
if (found) { if (found) {
@ -1149,6 +1310,13 @@ long Document::FindText(int minPos, int maxPos, const char *s,
pos = MovePositionOutsideChar(pos, increment, false); pos = MovePositionOutsideChar(pos, increment, false);
} }
} }
// >>> Added by DV
if (ws_upr) {
delete [] ws_upr;
}
// <<< Added by DV
} }
//Platform::DebugPrintf("Not found\n"); //Platform::DebugPrintf("Not found\n");
return -1; return -1;
@ -1169,11 +1337,11 @@ void Document::ChangeCase(Range r, bool makeUpperCase) {
char ch = CharAt(pos); char ch = CharAt(pos);
if (makeUpperCase) { if (makeUpperCase) {
if (IsLowerCase(ch)) { if (IsLowerCase(ch)) {
ChangeChar(pos, static_cast<char>(MakeUpperCase(ch))); ChangeChar(pos, static_cast<char>(MakeUpperCaseA(ch)));
} }
} else { } else {
if (IsUpperCase(ch)) { if (IsUpperCase(ch)) {
ChangeChar(pos, static_cast<char>(MakeLowerCase(ch))); ChangeChar(pos, static_cast<char>(MakeLowerCaseA(ch)));
} }
} }
} }