From 5be9af9cc9c6ab7952d9cd8af54d71a5c49b8e26 Mon Sep 17 00:00:00 2001 From: donho Date: Sun, 22 Jun 2008 23:32:56 +0000 Subject: [PATCH] [NEW_FEATURE] Add Matched Tag Highlighting feature. git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository@248 f5eea248-9336-0410-98b8-ebc06183d4e3 --- PowerEditor/installer/nppSetup.nsi | 2 +- PowerEditor/src/Notepad_plus.cpp | 200 +++++++++++++++++- PowerEditor/src/Notepad_plus.h | 14 ++ .../src/ScitillaComponent/FindReplaceDlg.cpp | 9 +- .../src/ScitillaComponent/FindReplaceDlg.rc | 2 +- .../ScitillaComponent/ScintillaEditView.cpp | 10 + PowerEditor/src/stylers.model.xml | 1 + scintilla/include/SciLexer.h | 1 + 8 files changed, 229 insertions(+), 10 deletions(-) diff --git a/PowerEditor/installer/nppSetup.nsi b/PowerEditor/installer/nppSetup.nsi index 977e6ffb0..5d4a89b3f 100644 --- a/PowerEditor/installer/nppSetup.nsi +++ b/PowerEditor/installer/nppSetup.nsi @@ -504,7 +504,7 @@ GLOBAL_INST: Delete "$INSTDIR\plugins\MultiClipboard.dll" IfFileExists "$INSTDIR\plugins\Explorer.dll" 0 +3 - MessageBox MB_OK "Due to the problem of compability with this version,$\Explorer.dll is about to be deleted." + MessageBox MB_OK "Due to the problem of compability with this version,$\nExplorer.dll is about to be deleted." Delete "$INSTDIR\plugins\Explorer.dll" ; detect the right of diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index c4ab9761f..f9307672d 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -48,6 +48,9 @@ const int smartHighlightFileSizeLimit = 1024 * 1024 * 3; // 3 MB int docTabIconIDs[] = {IDI_SAVED_ICON, IDI_UNSAVED_ICON, IDI_READONLY_ICON}; enum tb_stat {tb_saved, tb_unsaved, tb_ro}; +#define DIR_LEFT true +#define DIR_RIGHT false + struct SortTaskListPred { DocTabView *_views[2]; @@ -2103,6 +2106,7 @@ BOOL Notepad_plus::notify(SCNotification *notification) case SCN_UPDATEUI: { braceMatch(); + tagMatch(); markSelectedText(); updateStatusBar(); AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; @@ -2288,6 +2292,201 @@ void Notepad_plus::findMatchingBracePos(int & braceAtCaret, int & braceOpposite) braceOpposite = int(_pEditView->execute(SCI_BRACEMATCH, braceAtCaret, 0)); } +int Notepad_plus::getFirstTokenPosFrom(int currentPos, bool direction, const char *token, pair & foundPos) +{ + int start = currentPos; + int end = (direction == DIR_LEFT)?0:_pEditView->getCurrentDocLen(); + + _pEditView->execute(SCI_SETTARGETSTART, start); + _pEditView->execute(SCI_SETTARGETEND, end); + _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 gtPos = getFirstTokenPosFrom(curPos, DIR_LEFT, ">", foundPos); + int ltPos = getFirstTokenPosFrom(curPos, DIR_LEFT, "<", 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, DIR_RIGHT, ">", foundPos); + int ltPosOnR = getFirstTokenPosFrom(curPos, DIR_RIGHT, "<", 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::getXmlMatchedTagsPos(XmlMatchedTagsPos & tagsPos) +{ + // get word where caret is on + int caretPos = _pEditView->execute(SCI_GETCURRENTPOS); + + // determinate the nature of current word : tagOpen, tagClose or outOfTag + TagCateg tagCateg = getTagCategory(tagsPos, caretPos); + + /* +string toto; + switch (tagCateg) + { + case tagOpen : toto = "tag open"; break; + case tagClose : toto = "tag close"; break; + case inSingleTag : toto = "tag single"; break; + case invalidTag : toto = "tag invalid"; break; + case unknownPb : toto = "unknown Pb"; break; + } + ::SetWindowText(_hSelf, toto.c_str()); + */ + switch (tagCateg) + { + case tagOpen : // if tagOpen search right + { + int startPos = _pEditView->execute(SCI_WORDSTARTPOSITION, tagsPos.tagOpenStart+1, true); + int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagOpenStart+1, true); + char * tagName = new char[endPos-startPos+1]; + + _pEditView->getText(tagName, startPos, endPos); + + string closeTag = ""; + + string openTag = "<"; + openTag += tagName; + openTag += "[ >]"; + + delete [] tagName; + + pair foundPos; + int ltPosOnR = getFirstTokenPosFrom(caretPos, DIR_RIGHT, closeTag.c_str(), foundPos); + if (ltPosOnR == -1) + return false; + + pair tmpPos; + int openLtPosOnR = getFirstTokenPosFrom(caretPos, DIR_RIGHT, openTag.c_str(), tmpPos); + if ((openLtPosOnR != -1) && (openLtPosOnR < ltPosOnR)) + return false; + + tagsPos.tagCloseStart = foundPos.first; + tagsPos.tagCloseEnd = foundPos.second; + return true; + } + + case tagClose : // if tagClose search left + { + int startPos = _pEditView->execute(SCI_WORDSTARTPOSITION, tagsPos.tagCloseStart+2, true); + int endPos = _pEditView->execute(SCI_WORDENDPOSITION, tagsPos.tagCloseStart+2, true); + char * tagName = new char[endPos-startPos+1]; + + _pEditView->getText(tagName, startPos, endPos); + + string openTag = "<"; + openTag += tagName; + openTag += "[ >]"; + + delete [] tagName; + + pair foundPos; + int ltPosOnL = getFirstTokenPosFrom(caretPos, DIR_LEFT, openTag.c_str(), foundPos); + if (ltPosOnL == -1) + return false; + + if (getTagCategory(tagsPos, ltPosOnL+2) != tagOpen) + return false; + return true; + } + + case inSingleTag : // if in single tag + return true; + + default: // if outOfTag, just quit + return false; + + } + return false; +} + +void Notepad_plus::tagMatch() +{ + // Clean up all marks of previous action + _pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH); + + // 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; + + // Detect if it's a xml/html tag + // if yes, Colour it! + + XmlMatchedTagsPos xmlTags; + if (getXmlMatchedTagsPos(xmlTags)) + { + _pEditView->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_TAGMATCH); + _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagOpenStart, xmlTags.tagOpenEnd - xmlTags.tagOpenStart); + _pEditView->execute(SCI_INDICATORFILLRANGE, xmlTags.tagCloseStart, xmlTags.tagCloseEnd - xmlTags.tagCloseStart); + } +} + void Notepad_plus::braceMatch() { int braceAtCaret = -1; @@ -7825,7 +8024,6 @@ void Notepad_plus::markSelectedText() if (!nppGUI._enableSmartHilite) return; - //short if (_pEditView->isSelecting()) //printStr("catch u!!!"); return; diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index 47434809f..d42e8a5a2 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -89,6 +89,8 @@ 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: @@ -265,6 +267,13 @@ private: //For Dynamic selection highlight CharacterRange _prevSelectedRange; + struct XmlMatchedTagsPos { + int tagOpenStart; + int tagOpenEnd; + + int tagCloseStart; + int tagCloseEnd; + }; struct ActivateAppInfo { bool _isActivated; @@ -649,6 +658,11 @@ private: void findMatchingBracePos(int & braceAtCaret, int & braceOpposite); void braceMatch(); + + int getFirstTokenPosFrom(int currentPos, bool direction, const char *token, pair & foundPos); + TagCateg getTagCategory(XmlMatchedTagsPos & tagsPos, int curPos); + bool getXmlMatchedTagsPos(XmlMatchedTagsPos & tagsPos); + void tagMatch(); void activateNextDoc(bool direction); void activateDoc(int pos); diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp index d0f18d3f7..4b2de66a5 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.cpp @@ -848,7 +848,7 @@ bool FindReplaceDlg::processFindNext(const char *txt2find, FindOption *options) (*_ppEditView)->execute(SCI_SETTARGETEND, endPosition); (*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags); - int posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, stringSizeFind, (LPARAM)pText)); + int posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, stringSizeFind, (LPARAM)pText)); if (posFind == -1) //no match found in target, check if a new target should be used { if (pOptions->_isWrapAround) @@ -1048,12 +1048,7 @@ int FindReplaceDlg::processAll(ProcessOperation op, const char *txt2find, const bool isRegExp = pOptions->_searchType == FindRegex; int flags = Searching::buildSearchFlags(pOptions); -/* - if (op == ProcessMarkAll_2) - flags = SCFIND_WHOLEWORD; - else if (op == ProcessMarkAll_IncSearch) - flags ^= SCFIND_WHOLEWORD; -*/ + CharacterRange cr = (*_ppEditView)->getSelection(); int docLength = int((*_ppEditView)->execute(SCI_GETLENGTH)); diff --git a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.rc b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.rc index 50cd99921..16c6dd622 100644 --- a/PowerEditor/src/ScitillaComponent/FindReplaceDlg.rc +++ b/PowerEditor/src/ScitillaComponent/FindReplaceDlg.rc @@ -57,7 +57,7 @@ BEGIN GROUPBOX "Search mode",IDC_MODE_STATIC,6,126,138,48 CONTROL "&Normal",IDNORMAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,138,126,10 - CONTROL "&Extended",IDEXTENDED,"Button",BS_AUTORADIOBUTTON,12, 150,126,10 + CONTROL "&Extended (\\n, \\r, \\t, \\0, \\x...)",IDEXTENDED,"Button",BS_AUTORADIOBUTTON,12, 150,126,10 CONTROL "Regular e&xpression",IDREGEXP,"Button", BS_AUTORADIOBUTTON,12,162,126,10 CONTROL "&Up",IDDIRECTIONUP,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,155,94,45,12 diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 7ac8eb2f0..ae7f12e47 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -171,10 +171,12 @@ void ScintillaEditView::init(HINSTANCE hInst, HWND hPere) execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_2, INDIC_ROUNDBOX); execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE, INDIC_ROUNDBOX); execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_INC, INDIC_ROUNDBOX); + execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_TAGMATCH, INDIC_ROUNDBOX); execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_2, 100); execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE, 100); execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_INC, 100); + execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_TAGMATCH, 100); _pParameter = NppParameters::getInstance(); @@ -727,6 +729,14 @@ void ScintillaEditView::defineDocType(LangType typeDoc) setSpecialIndicator(styleFind); } + iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_TAGMATCH); + if (iFind != -1) + { + Style & styleFind = stylers.getStyler(iFind); + //setSpecialStyle(styleFind); + setSpecialIndicator(styleFind); + } + iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_SELECT_STYLE); if (iFind != -1) { diff --git a/PowerEditor/src/stylers.model.xml b/PowerEditor/src/stylers.model.xml index ef671d60a..6d6b0853c 100644 --- a/PowerEditor/src/stylers.model.xml +++ b/PowerEditor/src/stylers.model.xml @@ -713,6 +713,7 @@ + diff --git a/scintilla/include/SciLexer.h b/scintilla/include/SciLexer.h index 0f3818026..d9a910031 100644 --- a/scintilla/include/SciLexer.h +++ b/scintilla/include/SciLexer.h @@ -111,6 +111,7 @@ #define SCE_UNIVERSAL_FOUND_STYLE 31 #define SCE_UNIVERSAL_FOUND_STYLE_2 29 #define SCE_UNIVERSAL_FOUND_STYLE_INC 28 +#define SCE_UNIVERSAL_TAGMATCH 27 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1