From 7523faff296398d2f9a8d1028eeabb19a5a2a9bb Mon Sep 17 00:00:00 2001 From: donho Date: Wed, 9 Jul 2008 18:01:47 +0000 Subject: [PATCH] [IMPROVE] Reorganize the xml tag match hilite. git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository@283 f5eea248-9336-0410-98b8-ebc06183d4e3 --- PowerEditor/src/Notepad_plus.cpp | 426 +---------------- PowerEditor/src/Notepad_plus.h | 23 - PowerEditor/src/Parameters.h | 2 +- .../xmlMatchedTagsHighlighter.cpp | 442 ++++++++++++++++++ .../xmlMatchedTagsHighlighter.h | 59 +++ .../WinControls/Preference/preferenceDlg.cpp | 17 + PowerEditor/visual.net/notepadPlus.vcproj | 12 +- 7 files changed, 532 insertions(+), 449 deletions(-) create mode 100644 PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp create mode 100644 PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index 5f89b800b..a14e533db 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -39,6 +39,7 @@ #include "xpm_icons.h" #include #include +#include "xmlMatchedTagsHighlighter.h" const char Notepad_plus::_className[32] = NOTEPAD_PP_CLASS_NAME; const char *urlHttpRegExpr = "http://[a-z0-9_\\-\\+.:?&@=/%#]*"; @@ -2212,7 +2213,8 @@ BOOL Notepad_plus::notify(SCNotification *notification) case SCN_UPDATEUI: { braceMatch(); - tagMatch(); + XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView); + xmlTagMatchHiliter.tagMatch(); markSelectedText(); updateStatusBar(); AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; @@ -2398,428 +2400,6 @@ void Notepad_plus::findMatchingBracePos(int & braceAtCaret, int & braceOpposite) braceOpposite = int(_pEditView->execute(SCI_BRACEMATCH, braceAtCaret, 0)); } -int Notepad_plus::getFirstTokenPosFrom(int targetStart, int targetEnd, const char *token, pair & foundPos) -{ - //int start = currentPos; - //int end = (direction == DIR_LEFT)?0:_pEditView->getCurrentDocLen(); - - _pEditView->execute(SCI_SETTARGETSTART, targetStart); - _pEditView->execute(SCI_SETTARGETEND, targetEnd); - _pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX); - int posFind = _pEditView->execute(SCI_SEARCHINTARGET, (WPARAM)strlen(token), (LPARAM)token); - if (posFind != -1) - { - foundPos.first = _pEditView->execute(SCI_GETTARGETSTART); - foundPos.second = _pEditView->execute(SCI_GETTARGETEND); - } - return posFind; -} - -TagCateg Notepad_plus::getTagCategory(XmlMatchedTagsPos & tagsPos, int curPos) -{ - pair foundPos; - - int docLen = _pEditView->getCurrentDocLen(); - - int gtPos = getFirstTokenPosFrom(curPos, 0, ">", foundPos); - int ltPos = getFirstTokenPosFrom(curPos, 0, "<", foundPos); - if (ltPos != -1) - { - if ((gtPos != -1) && (ltPos < gtPos)) - return outOfTag; - - // Now we are sure about that we are inside of tag - // We'll try to determinate the tag category : - // tagOpen : , - // tagClose : - // tagSigle : , - int charAfterLt = _pEditView->execute(SCI_GETCHARAT, ltPos+1); - if (!charAfterLt) - return unknownPb; - - if ((char)charAfterLt == ' ') - return invalidTag; - - // so now we are sure we have tag sign '<' - // We'll see on the right - int gtPosOnR = getFirstTokenPosFrom(curPos, docLen, ">", foundPos); - int ltPosOnR = getFirstTokenPosFrom(curPos, docLen, "<", foundPos); - - if (gtPosOnR == -1) - return invalidTag; - - if ((ltPosOnR != -1) && (ltPosOnR < gtPosOnR)) - return invalidTag; - - if ((char)charAfterLt == '/') - { - int char2AfterLt = _pEditView->execute(SCI_GETCHARAT, ltPos+1+1); - - if (!char2AfterLt) - return unknownPb; - - if ((char)char2AfterLt == ' ') - return invalidTag; - - tagsPos.tagCloseStart = ltPos; - tagsPos.tagCloseEnd = gtPosOnR + 1; - return tagClose; - } - else - { - // it's sure for not being a tagClose - // So we determinate if it's tagSingle or tagOpen - tagsPos.tagOpenStart = ltPos; - tagsPos.tagOpenEnd = gtPosOnR + 1; - - int charBeforeLt = _pEditView->execute(SCI_GETCHARAT, gtPosOnR-1); - if ((char)charBeforeLt == '/') - return inSingleTag; - - return tagOpen; - } - } - - return outOfTag; -} - -bool Notepad_plus::getMatchedTagPos(int searchStart, int searchEnd, const char *tag2find, const char *oppositeTag2find, vector oppositeTagFound, XmlMatchedTagsPos & tagsPos) -{ - const bool search2Left = false; - const bool search2Right = true; - - bool direction = searchEnd > searchStart; - - pair foundPos; - int ltPosOnR = getFirstTokenPosFrom(searchStart, searchEnd, tag2find, foundPos); - if (ltPosOnR == -1) - return false; - - TagCateg tc = outOfTag; - if (direction == search2Left) - { - tc = getTagCategory(tagsPos, ltPosOnR+2); - - if (tc != tagOpen && tc != inSingleTag) - return false; - if (tc == inSingleTag) - { - int start = foundPos.first; - int end = searchEnd; - return getMatchedTagPos(start, end, tag2find, oppositeTag2find, oppositeTagFound, tagsPos); - } - //oppositeTagFound.push_back(foundPos.first); - } - - pair oppositeTagPos; - int s = foundPos.first; - int e = tagsPos.tagOpenEnd; - if (direction == search2Left) - { - s = foundPos.second; - e = tagsPos.tagCloseStart; - } - - int ltTag = getFirstTokenPosFrom(s, e, oppositeTag2find, oppositeTagPos); - - if (ltTag == -1) - { - if (direction == search2Left) - { - return true; - } - else - { - tagsPos.tagCloseStart = foundPos.first; - tagsPos.tagCloseEnd = foundPos.second; - return true; - } - } - else if (isInList(ltTag, oppositeTagFound)) - { - while (true) - { - ltTag = getFirstTokenPosFrom(ltTag, e, oppositeTag2find, oppositeTagPos); - if (ltTag == -1) - { - if (direction == search2Left) - { - return true; - } - else - { - tagsPos.tagCloseStart = foundPos.first; - tagsPos.tagCloseEnd = foundPos.second; - } - return true; - } - else if (!isInList(ltTag, oppositeTagFound)) - { - oppositeTagFound.push_back(ltTag); - break; - } - else - { - if (direction == search2Left) - { - XmlMatchedTagsPos tmpTagsPos; - getTagCategory(tmpTagsPos, ltTag+1); - ltTag = tmpTagsPos.tagCloseEnd; - } - } - } - } - else - { - oppositeTagFound.push_back(ltTag); - } - - int start, end; - if (direction == search2Left) - { - start = foundPos.first; - end = searchEnd; - } - else - { - start = foundPos.second; - end = searchEnd; - } - - return getMatchedTagPos(start, end, tag2find, oppositeTag2find, oppositeTagFound, tagsPos); -} - - -bool Notepad_plus::getXmlMatchedTagsPos(XmlMatchedTagsPos & tagsPos) -{ - // get word where caret is on - int caretPos = _pEditView->execute(SCI_GETCURRENTPOS); - - int docLen = _pEditView->getCurrentDocLen(); - - // determinate the nature of current word : tagOpen, tagClose or outOfTag - TagCateg tagCateg = getTagCategory(tagsPos, caretPos); - - static const char tagNameChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_:"; - - switch (tagCateg) - { - case tagOpen : // if tagOpen search right - { - _pEditView->execute(SCI_SETWORDCHARS, 0, (LPARAM)tagNameChars); - int startPos = _pEditView->execute(SCI_WORDSTARTPOSITION, tagsPos.tagOpenStart+1, true); - int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagOpenStart+1, true); - tagsPos.tagNameEnd = endPos; - - _pEditView->execute(SCI_SETCHARSDEFAULT); - char * tagName = new char[endPos-startPos+1]; - - _pEditView->getText(tagName, startPos, endPos); - - string closeTag = ""; - - string openTag = "<"; - openTag += tagName; - openTag += "[ >]"; - - delete [] tagName; - - vector passedTagList; - return getMatchedTagPos(tagsPos.tagOpenEnd, docLen, closeTag.c_str(), openTag.c_str(), passedTagList, tagsPos); - } - - case tagClose : // if tagClose search left - { - _pEditView->execute(SCI_SETWORDCHARS, 0, (LPARAM)tagNameChars); - int startPos = _pEditView->execute(SCI_WORDSTARTPOSITION, tagsPos.tagCloseStart+2, true); - int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagCloseStart+2, true); - - _pEditView->execute(SCI_SETCHARSDEFAULT); - char * tagName = new char[endPos-startPos+1]; - _pEditView->getText(tagName, startPos, endPos); - - string openTag = "<"; - openTag += tagName; - - string closeTag = ""; - - delete [] tagName; - - vector passedTagList; - bool isFound = getMatchedTagPos(tagsPos.tagCloseStart, 0, openTag.c_str(), closeTag.c_str(), passedTagList, tagsPos); - if (isFound) - tagsPos.tagNameEnd = tagsPos.tagOpenStart + 1 + (endPos - startPos); - - return isFound; - } - - case inSingleTag : // if in single tag - { - _pEditView->execute(SCI_SETWORDCHARS, 0, (LPARAM)tagNameChars); - int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagOpenStart+1, true); - tagsPos.tagNameEnd = endPos; - _pEditView->execute(SCI_SETCHARSDEFAULT); - - tagsPos.tagCloseStart = -1; - tagsPos.tagCloseEnd = -1; - return true; - } - default: // if outOfTag, just quit - return false; - - } - return false; -} - -vector< pair > Notepad_plus::getAttributesPos(int start, int end) -{ - vector< pair > attributes; - - int bufLen = end - start + 1; - char *buf = new char[bufLen+1]; - _pEditView->getText(buf, start, end); - - enum {\ - attr_invalid,\ - attr_key,\ - attr_pre_assign,\ - attr_assign,\ - attr_string,\ - attr_value,\ - attr_valid\ - } state = attr_invalid; - - int startPos = -1; - int oneMoreChar = 1; - int i = 0; - for (; i < bufLen ; i++) - { - switch (buf[i]) - { - case ' ': - case '\t': - case '\n': - case '\r': - { - if (state == attr_key) - state = attr_pre_assign; - else if (state == attr_value) - { - state = attr_valid; - oneMoreChar = 0; - } - } - break; - - case '=': - { - if (state == attr_key || state == attr_pre_assign) - state = attr_assign; - else if (state == attr_assign || state == attr_value) - state = attr_invalid; - } - break; - - case '"': - { - if (state == attr_string) - { - state = attr_valid; - oneMoreChar = 1; - } - else if (state == attr_key || state == attr_pre_assign || state == attr_value) - state = attr_invalid; - else if (state == attr_assign) - state = attr_string; - } - break; - - default: - { - if (state == attr_invalid) - { - state = attr_key; - startPos = i; - } - else if (state == attr_pre_assign) - state = attr_invalid; - else if (state == attr_assign) - state = attr_value; - } - } - - if (state == attr_valid) - { - attributes.push_back(pair(start+startPos, start+i+oneMoreChar)); - state = attr_invalid; - } - } - if (state == attr_value) - attributes.push_back(pair(start+startPos, start+i-1)); - - delete [] buf; - return attributes; -} - - - -void Notepad_plus::tagMatch() -{ - const NppGUI & nppGUI = (NppParameters::getInstance())->getNppGUI(); - if (!nppGUI._enableTagsMatchHilite) - return; - - // Clean up all marks of previous action - _pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH); - _pEditView->clearIndicator(SCE_UNIVERSAL_TAGATTR); - - // Detect the current lang type. It works only with html and xml - LangType lang = (_pEditView->getCurrentBuffer())->getLangType(); - if (lang != L_XML && lang != L_HTML && lang != L_PHP && lang != L_ASP) - return; - - // Get the original targets to restore after tag matching operation - int originalStartPos = _pEditView->execute(SCI_GETTARGETSTART); - int originalEndPos = _pEditView->execute(SCI_GETTARGETEND); - - // Detect if it's a xml/html tag. If yes, Colour it! - XmlMatchedTagsPos xmlTags; - if (getXmlMatchedTagsPos(xmlTags)) - { - _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH); - - int openTagTailLen = 2; - // We colourise the close tag firstly - if ((xmlTags.tagCloseStart != -1) && (xmlTags.tagCloseEnd != -1)) - { - _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagCloseStart, xmlTags.tagCloseEnd - xmlTags.tagCloseStart); - // tag close is present, so it's not single tag - openTagTailLen = 1; - } - - // Now the open tag and its attributs - _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenStart, xmlTags.tagNameEnd - xmlTags.tagOpenStart); - _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenEnd - openTagTailLen, openTagTailLen); - - if (nppGUI._enableTagAttrsHilite) - { - vector< pair > attributes = getAttributesPos(xmlTags.tagNameEnd, xmlTags.tagOpenEnd - openTagTailLen); - _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGATTR); - for (size_t i = 0 ; i < attributes.size() ; i++) - { - _pEditView->execute(SCI_INDICATORFILLRANGE, attributes[i].first, attributes[i].second - attributes[i].first); - } - } - } - - // restore the original targets to avoid the conflit with search/replace function - _pEditView->execute(SCI_SETTARGETSTART, originalStartPos); - _pEditView->execute(SCI_SETTARGETEND, originalEndPos); -} void Notepad_plus::braceMatch() { diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index 651f3820f..22c1bf940 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -89,8 +89,6 @@ struct iconLocator { class FileDialog; -enum TagCateg {tagOpen, tagClose, inSingleTag, outOfTag, invalidTag, unknownPb}; - class Notepad_plus : public Window { enum comment_mode {cm_comment, cm_uncomment, cm_toggle}; public: @@ -269,14 +267,6 @@ private: //For Dynamic selection highlight CharacterRange _prevSelectedRange; - struct XmlMatchedTagsPos { - int tagOpenStart; - int tagNameEnd; - int tagOpenEnd; - - int tagCloseStart; - int tagCloseEnd; - }; struct ActivateAppInfo { bool _isActivated; @@ -675,19 +665,6 @@ private: void findMatchingBracePos(int & braceAtCaret, int & braceOpposite); void braceMatch(); - int getFirstTokenPosFrom(int targetStart, int targetEnd, const char *token, pair & foundPos); - TagCateg getTagCategory(XmlMatchedTagsPos & tagsPos, int curPos); - bool getMatchedTagPos(int searchStart, int searchEnd, const char *tag2find, const char *oppositeTag2find, vector oppositeTagFound, XmlMatchedTagsPos & tagsPos); - bool getXmlMatchedTagsPos(XmlMatchedTagsPos & tagsPos); - vector< pair > getAttributesPos(int start, int end); - bool isInList(int element, vector elementList) { - for (size_t i = 0 ; i < elementList.size() ; i++) - if (element == elementList[i]) - return true; - return false; - }; - void tagMatch(); - void activateNextDoc(bool direction); void activateDoc(int pos); diff --git a/PowerEditor/src/Parameters.h b/PowerEditor/src/Parameters.h index eae4ef0ed..f11e1748b 100644 --- a/PowerEditor/src/Parameters.h +++ b/PowerEditor/src/Parameters.h @@ -1,5 +1,5 @@ //this file is part of notepad++ -//Copyright (C)2003 Don HO ( donho@altern.org ) +//Copyright (C)2003 Don HO // //This program is free software; you can redistribute it and/or //modify it under the terms of the GNU General Public License diff --git a/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp new file mode 100644 index 000000000..6acb606fb --- /dev/null +++ b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.cpp @@ -0,0 +1,442 @@ +//this file is part of notepad++ +//Copyright (C)2003 Don HO +// +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU General Public License +//as published by the Free Software Foundation; either +//version 2 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include "xmlMatchedTagsHighlighter.h" +#include "ScintillaEditView.h" + +int XmlMatchedTagsHighlighter::getFirstTokenPosFrom(int targetStart, int targetEnd, const char *token, pair & foundPos) +{ + //int start = currentPos; + //int end = (direction == DIR_LEFT)?0:_pEditView->getCurrentDocLen(); + + _pEditView->execute(SCI_SETTARGETSTART, targetStart); + _pEditView->execute(SCI_SETTARGETEND, targetEnd); + _pEditView->execute(SCI_SETSEARCHFLAGS, SCFIND_REGEXP|SCFIND_POSIX); + int posFind = _pEditView->execute(SCI_SEARCHINTARGET, (WPARAM)strlen(token), (LPARAM)token); + if (posFind != -1) + { + foundPos.first = _pEditView->execute(SCI_GETTARGETSTART); + foundPos.second = _pEditView->execute(SCI_GETTARGETEND); + } + return posFind; +} + +TagCateg XmlMatchedTagsHighlighter::getTagCategory(XmlMatchedTagsPos & tagsPos, int curPos) +{ + pair foundPos; + + int docLen = _pEditView->getCurrentDocLen(); + + int gtPos = getFirstTokenPosFrom(curPos, 0, ">", foundPos); + int ltPos = getFirstTokenPosFrom(curPos, 0, "<", foundPos); + if (ltPos != -1) + { + if ((gtPos != -1) && (ltPos < gtPos)) + return outOfTag; + + // Now we are sure about that we are inside of tag + // We'll try to determinate the tag category : + // tagOpen : , + // tagClose : + // tagSigle : , + int charAfterLt = _pEditView->execute(SCI_GETCHARAT, ltPos+1); + if (!charAfterLt) + return unknownPb; + + if ((char)charAfterLt == ' ') + return invalidTag; + + // so now we are sure we have tag sign '<' + // We'll see on the right + int gtPosOnR = getFirstTokenPosFrom(curPos, docLen, ">", foundPos); + int ltPosOnR = getFirstTokenPosFrom(curPos, docLen, "<", foundPos); + + if (gtPosOnR == -1) + return invalidTag; + + if ((ltPosOnR != -1) && (ltPosOnR < gtPosOnR)) + return invalidTag; + + if ((char)charAfterLt == '/') + { + int char2AfterLt = _pEditView->execute(SCI_GETCHARAT, ltPos+1+1); + + if (!char2AfterLt) + return unknownPb; + + if ((char)char2AfterLt == ' ') + return invalidTag; + + tagsPos.tagCloseStart = ltPos; + tagsPos.tagCloseEnd = gtPosOnR + 1; + return tagClose; + } + else + { + // it's sure for not being a tagClose + // So we determinate if it's tagSingle or tagOpen + tagsPos.tagOpenStart = ltPos; + tagsPos.tagOpenEnd = gtPosOnR + 1; + + int charBeforeLt = _pEditView->execute(SCI_GETCHARAT, gtPosOnR-1); + if ((char)charBeforeLt == '/') + return inSingleTag; + + return tagOpen; + } + } + + return outOfTag; +} + +bool XmlMatchedTagsHighlighter::getMatchedTagPos(int searchStart, int searchEnd, const char *tag2find, const char *oppositeTag2find, vector oppositeTagFound, XmlMatchedTagsPos & tagsPos) +{ + const bool search2Left = false; + const bool search2Right = true; + + bool direction = searchEnd > searchStart; + + pair foundPos; + int ltPosOnR = getFirstTokenPosFrom(searchStart, searchEnd, tag2find, foundPos); + if (ltPosOnR == -1) + return false; + + TagCateg tc = outOfTag; + if (direction == search2Left) + { + tc = getTagCategory(tagsPos, ltPosOnR+2); + + if (tc != tagOpen && tc != inSingleTag) + return false; + if (tc == inSingleTag) + { + int start = foundPos.first; + int end = searchEnd; + return getMatchedTagPos(start, end, tag2find, oppositeTag2find, oppositeTagFound, tagsPos); + } + //oppositeTagFound.push_back(foundPos.first); + } + + pair oppositeTagPos; + int s = foundPos.first; + int e = tagsPos.tagOpenEnd; + if (direction == search2Left) + { + s = foundPos.second; + e = tagsPos.tagCloseStart; + } + + int ltTag = getFirstTokenPosFrom(s, e, oppositeTag2find, oppositeTagPos); + + if (ltTag == -1) + { + if (direction == search2Left) + { + return true; + } + else + { + tagsPos.tagCloseStart = foundPos.first; + tagsPos.tagCloseEnd = foundPos.second; + return true; + } + } + else if (isInList(ltTag, oppositeTagFound)) + { + while (true) + { + ltTag = getFirstTokenPosFrom(ltTag, e, oppositeTag2find, oppositeTagPos); + if (ltTag == -1) + { + if (direction == search2Left) + { + return true; + } + else + { + tagsPos.tagCloseStart = foundPos.first; + tagsPos.tagCloseEnd = foundPos.second; + } + return true; + } + else if (!isInList(ltTag, oppositeTagFound)) + { + oppositeTagFound.push_back(ltTag); + break; + } + else + { + if (direction == search2Left) + { + XmlMatchedTagsPos tmpTagsPos; + getTagCategory(tmpTagsPos, ltTag+1); + ltTag = tmpTagsPos.tagCloseEnd; + } + } + } + } + else + { + oppositeTagFound.push_back(ltTag); + } + + int start, end; + if (direction == search2Left) + { + start = foundPos.first; + end = searchEnd; + } + else + { + start = foundPos.second; + end = searchEnd; + } + + return getMatchedTagPos(start, end, tag2find, oppositeTag2find, oppositeTagFound, tagsPos); +} + + +bool XmlMatchedTagsHighlighter::getXmlMatchedTagsPos(XmlMatchedTagsPos & tagsPos) +{ + // get word where caret is on + int caretPos = _pEditView->execute(SCI_GETCURRENTPOS); + + int docLen = _pEditView->getCurrentDocLen(); + + // determinate the nature of current word : tagOpen, tagClose or outOfTag + TagCateg tagCateg = getTagCategory(tagsPos, caretPos); + + static const char tagNameChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_:"; + + switch (tagCateg) + { + case tagOpen : // if tagOpen search right + { + _pEditView->execute(SCI_SETWORDCHARS, 0, (LPARAM)tagNameChars); + int startPos = _pEditView->execute(SCI_WORDSTARTPOSITION, tagsPos.tagOpenStart+1, true); + int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagOpenStart+1, true); + tagsPos.tagNameEnd = endPos; + + _pEditView->execute(SCI_SETCHARSDEFAULT); + char * tagName = new char[endPos-startPos+1]; + + _pEditView->getText(tagName, startPos, endPos); + + string closeTag = ""; + + string openTag = "<"; + openTag += tagName; + openTag += "[ >]"; + + delete [] tagName; + + vector passedTagList; + return getMatchedTagPos(tagsPos.tagOpenEnd, docLen, closeTag.c_str(), openTag.c_str(), passedTagList, tagsPos); + } + + case tagClose : // if tagClose search left + { + _pEditView->execute(SCI_SETWORDCHARS, 0, (LPARAM)tagNameChars); + int startPos = _pEditView->execute(SCI_WORDSTARTPOSITION, tagsPos.tagCloseStart+2, true); + int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagCloseStart+2, true); + + _pEditView->execute(SCI_SETCHARSDEFAULT); + char * tagName = new char[endPos-startPos+1]; + _pEditView->getText(tagName, startPos, endPos); + + string openTag = "<"; + openTag += tagName; + + string closeTag = ""; + + delete [] tagName; + + vector passedTagList; + bool isFound = getMatchedTagPos(tagsPos.tagCloseStart, 0, openTag.c_str(), closeTag.c_str(), passedTagList, tagsPos); + if (isFound) + tagsPos.tagNameEnd = tagsPos.tagOpenStart + 1 + (endPos - startPos); + + return isFound; + } + + case inSingleTag : // if in single tag + { + _pEditView->execute(SCI_SETWORDCHARS, 0, (LPARAM)tagNameChars); + int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagOpenStart+1, true); + tagsPos.tagNameEnd = endPos; + _pEditView->execute(SCI_SETCHARSDEFAULT); + + tagsPos.tagCloseStart = -1; + tagsPos.tagCloseEnd = -1; + return true; + } + default: // if outOfTag, just quit + return false; + + } + return false; +} + +vector< pair > XmlMatchedTagsHighlighter::getAttributesPos(int start, int end) +{ + vector< pair > attributes; + + int bufLen = end - start + 1; + char *buf = new char[bufLen+1]; + _pEditView->getText(buf, start, end); + + enum {\ + attr_invalid,\ + attr_key,\ + attr_pre_assign,\ + attr_assign,\ + attr_string,\ + attr_value,\ + attr_valid\ + } state = attr_invalid; + + int startPos = -1; + int oneMoreChar = 1; + int i = 0; + for (; i < bufLen ; i++) + { + switch (buf[i]) + { + case ' ': + case '\t': + case '\n': + case '\r': + { + if (state == attr_key) + state = attr_pre_assign; + else if (state == attr_value) + { + state = attr_valid; + oneMoreChar = 0; + } + } + break; + + case '=': + { + if (state == attr_key || state == attr_pre_assign) + state = attr_assign; + else if (state == attr_assign || state == attr_value) + state = attr_invalid; + } + break; + + case '"': + { + if (state == attr_string) + { + state = attr_valid; + oneMoreChar = 1; + } + else if (state == attr_key || state == attr_pre_assign || state == attr_value) + state = attr_invalid; + else if (state == attr_assign) + state = attr_string; + } + break; + + default: + { + if (state == attr_invalid) + { + state = attr_key; + startPos = i; + } + else if (state == attr_pre_assign) + state = attr_invalid; + else if (state == attr_assign) + state = attr_value; + } + } + + if (state == attr_valid) + { + attributes.push_back(pair(start+startPos, start+i+oneMoreChar)); + state = attr_invalid; + } + } + if (state == attr_value) + attributes.push_back(pair(start+startPos, start+i-1)); + + delete [] buf; + return attributes; +} + + + +void XmlMatchedTagsHighlighter::tagMatch() +{ + const NppGUI & nppGUI = (NppParameters::getInstance())->getNppGUI(); + if (!nppGUI._enableTagsMatchHilite) + return; + + // Clean up all marks of previous action + _pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH); + _pEditView->clearIndicator(SCE_UNIVERSAL_TAGATTR); + + // Detect the current lang type. It works only with html and xml + LangType lang = (_pEditView->getCurrentBuffer())->getLangType(); + if (lang != L_XML && lang != L_HTML && lang != L_PHP && lang != L_ASP) + return; + + // Get the original targets to restore after tag matching operation + int originalStartPos = _pEditView->execute(SCI_GETTARGETSTART); + int originalEndPos = _pEditView->execute(SCI_GETTARGETEND); + + // Detect if it's a xml/html tag. If yes, Colour it! + XmlMatchedTagsPos xmlTags; + if (getXmlMatchedTagsPos(xmlTags)) + { + _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH); + + int openTagTailLen = 2; + // We colourise the close tag firstly + if ((xmlTags.tagCloseStart != -1) && (xmlTags.tagCloseEnd != -1)) + { + _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagCloseStart, xmlTags.tagCloseEnd - xmlTags.tagCloseStart); + // tag close is present, so it's not single tag + openTagTailLen = 1; + } + + // Now the open tag and its attributs + _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenStart, xmlTags.tagNameEnd - xmlTags.tagOpenStart); + _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenEnd - openTagTailLen, openTagTailLen); + + if (nppGUI._enableTagAttrsHilite) + { + vector< pair > attributes = getAttributesPos(xmlTags.tagNameEnd, xmlTags.tagOpenEnd - openTagTailLen); + _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGATTR); + for (size_t i = 0 ; i < attributes.size() ; i++) + { + _pEditView->execute(SCI_INDICATORFILLRANGE, attributes[i].first, attributes[i].second - attributes[i].first); + } + } + } + + // restore the original targets to avoid the conflit with search/replace function + _pEditView->execute(SCI_SETTARGETSTART, originalStartPos); + _pEditView->execute(SCI_SETTARGETEND, originalEndPos); +} diff --git a/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h new file mode 100644 index 000000000..9872a14b4 --- /dev/null +++ b/PowerEditor/src/ScitillaComponent/xmlMatchedTagsHighlighter.h @@ -0,0 +1,59 @@ +//this file is part of notepad++ +//Copyright (C)2003 Don HO +// +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU General Public License +//as published by the Free Software Foundation; either +//version 2 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef XMLMATCHEDTAGSHIGHLIGHTER_H +#define XMLMATCHEDTAGSHIGHLIGHTER_H + +#include +using namespace std; + +class ScintillaEditView; + +enum TagCateg {tagOpen, tagClose, inSingleTag, outOfTag, invalidTag, unknownPb}; + +class XmlMatchedTagsHighlighter { +public: + XmlMatchedTagsHighlighter(ScintillaEditView *pEditView):_pEditView(pEditView){}; + void tagMatch(); + +private: + struct XmlMatchedTagsPos { + int tagOpenStart; + int tagNameEnd; + int tagOpenEnd; + + int tagCloseStart; + int tagCloseEnd; + }; + + ScintillaEditView *_pEditView; + + int getFirstTokenPosFrom(int targetStart, int targetEnd, const char *token, std::pair & foundPos); + TagCateg getTagCategory(XmlMatchedTagsPos & tagsPos, int curPos); + bool getMatchedTagPos(int searchStart, int searchEnd, const char *tag2find, const char *oppositeTag2find, vector oppositeTagFound, XmlMatchedTagsPos & tagsPos); + bool getXmlMatchedTagsPos(XmlMatchedTagsPos & tagsPos); + vector< pair > getAttributesPos(int start, int end); + bool isInList(int element, vector elementList) { + for (size_t i = 0 ; i < elementList.size() ; i++) + if (element == elementList[i]) + return true; + return false; + }; +}; + +#endif //XMLMATCHEDTAGSHIGHLIGHTER_H + diff --git a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp index 513bf997e..c3a9e3f2a 100644 --- a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp +++ b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp @@ -1,3 +1,20 @@ +//this file is part of notepad++ +//Copyright (C)2003 Don HO ( donho@altern.org ) +// +//This program is free software; you can redistribute it and/or +//modify it under the terms of the GNU General Public License +//as published by the Free Software Foundation; either +//version 2 of the License, or (at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + #include #include "preferenceDlg.h" #include "SysMsg.h" diff --git a/PowerEditor/visual.net/notepadPlus.vcproj b/PowerEditor/visual.net/notepadPlus.vcproj index a134cc225..ca620253e 100644 --- a/PowerEditor/visual.net/notepadPlus.vcproj +++ b/PowerEditor/visual.net/notepadPlus.vcproj @@ -437,6 +437,10 @@ RelativePath="..\src\WinControls\ColourPicker\WordStyleDlg.cpp" > + + + +