From 0b5687052e4697373b1d69f223e0c09e5ffe2918 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Mon, 2 Sep 2013 09:05:37 +0000 Subject: [PATCH] [NEW_FEATURE] Add new feature: auto-complete matched delimiters (in progress). git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@1107 f5eea248-9336-0410-98b8-ebc06183d4e3 --- PowerEditor/src/NppNotification.cpp | 8 +- PowerEditor/src/Parameters.cpp | 64 +++++++++++++ PowerEditor/src/Parameters.h | 18 ++++ .../src/ScitillaComponent/AutoCompletion.cpp | 91 +++++++++++++++++++ .../src/ScitillaComponent/AutoCompletion.h | 2 + .../ScitillaComponent/ScintillaEditView.cpp | 70 +------------- 6 files changed, 183 insertions(+), 70 deletions(-) diff --git a/PowerEditor/src/NppNotification.cpp b/PowerEditor/src/NppNotification.cpp index 7b2f2c47c..f9d244fe1 100644 --- a/PowerEditor/src/NppNotification.cpp +++ b/PowerEditor/src/NppNotification.cpp @@ -424,14 +424,20 @@ BOOL Notepad_plus::notify(SCNotification *notification) } return TRUE; } - + case SCN_CHARADDED: { bool indentMaintain = NppParameters::getInstance()->getNppGUI()._maitainIndent; if (indentMaintain) MaintainIndentation(static_cast(notification->ch)); + AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; + + MatchedPairConf matchedPairConf; + if (matchedPairConf.hasAnyPairsPair()) + autoC->insertMatchedChars(notification->ch, matchedPairConf); autoC->update(notification->ch); + break; } diff --git a/PowerEditor/src/Parameters.cpp b/PowerEditor/src/Parameters.cpp index 96f3e79a3..25b7811fa 100644 --- a/PowerEditor/src/Parameters.cpp +++ b/PowerEditor/src/Parameters.cpp @@ -3962,7 +3962,71 @@ void NppParameters::feedGUIParameters(TiXmlNode *node) if (funcParams && !lstrcmp(funcParams, TEXT("yes"))) { _nppGUI._funcParams = true; + } } + else if (!lstrcmp(nm, TEXT("auto-insert"))) + { + const TCHAR * optName = element->Attribute(TEXT("htmlXmlTag")); + if (optName && !lstrcmp(optName, TEXT("yes"))) + { + _nppGUI._matchedPairConf._doHtmlXmlTag = true; + } + + optName = element->Attribute(TEXT("parentheses")); + if (optName && !lstrcmp(optName, TEXT("yes"))) + { + _nppGUI._matchedPairConf._doParentheses = true; + } + + optName = element->Attribute(TEXT("brackets")); + if (optName && !lstrcmp(optName, TEXT("yes"))) + { + _nppGUI._matchedPairConf._doBrackets = true; + } + + optName = element->Attribute(TEXT("curlyBrackets")); + if (optName && !lstrcmp(optName, TEXT("yes"))) + { + _nppGUI._matchedPairConf._doCurlyBrackets = true; + } + + optName = element->Attribute(TEXT("quotes")); + if (optName && !lstrcmp(optName, TEXT("yes"))) + { + _nppGUI._matchedPairConf._doQuotes = true; + } + + optName = element->Attribute(TEXT("doubleQuotes")); + if (optName && !lstrcmp(optName, TEXT("yes"))) + { + _nppGUI._matchedPairConf._doDoubleQuotes = true; + } + + for (TiXmlNode *subChildNode = childNode->FirstChildElement(TEXT("UserDefinePair")); + subChildNode; + subChildNode = subChildNode->NextSibling(TEXT("UserDefinePair")) ) + { + int open = -1; + int openVal = 0; + const TCHAR *openValStr = (subChildNode->ToElement())->Attribute(TEXT("open"), &openVal); + if (openValStr && (openVal >= 0 && openVal <= 255)) + { + open = openVal; + } + + int close = -1; + int closeVal = 0; + const TCHAR *closeValStr = (subChildNode->ToElement())->Attribute(TEXT("close"), &closeVal); + if (closeValStr && (closeVal >= 0 && closeVal <= 255)) + { + close = closeVal; + } + + if (open != -1 && close != -1) + { + _nppGUI._matchedPairConf._matchedPairs.push_back(pair(char(open), char(close))); + } + } } else if (!lstrcmp(nm, TEXT("sessionExt"))) { diff --git a/PowerEditor/src/Parameters.h b/PowerEditor/src/Parameters.h index 405c87052..a68603625 100644 --- a/PowerEditor/src/Parameters.h +++ b/PowerEditor/src/Parameters.h @@ -675,6 +675,23 @@ private: unsigned long _day; }; +struct MatchedPairConf { + vector< pair > _matchedPairs; + bool _doHtmlXmlTag; + bool _doParentheses; + bool _doBrackets; + bool _doCurlyBrackets; + bool _doQuotes; + bool _doDoubleQuotes; + + MatchedPairConf(): _doHtmlXmlTag(false), _doParentheses(false), _doBrackets(false), _doCurlyBrackets(false),\ + _doQuotes(false), _doDoubleQuotes(false) {}; + + bool hasUserDefinedPairs(){ return _matchedPairs.size() != 0; }; + bool hasDefaultPairs() { return _doParentheses||_doBrackets||_doCurlyBrackets||_doQuotes||_doDoubleQuotes||_doHtmlXmlTag; }; + bool hasAnyPairsPair(){ return hasUserDefinedPairs() || hasDefaultPairs(); }; +}; + struct NppGUI { NppGUI() : _toolBarStatus(TB_LARGE), _toolbarShow(true), _statusBarShow(true), _menuBarShow(true),\ @@ -758,6 +775,7 @@ struct NppGUI AutocStatus _autocStatus; size_t _autocFromLen; bool _funcParams; + MatchedPairConf _matchedPairConf; generic_string _definedSessionExt; diff --git a/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp b/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp index 47c5ba6f4..5c6d279bf 100644 --- a/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp +++ b/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp @@ -162,6 +162,97 @@ bool AutoCompletion::showFunctionComplete() { return false; } +void AutoCompletion::getCloseTag(char *closeTag, size_t closeTagSize, size_t caretPos) +{ + int flags = SCFIND_REGEXP | SCFIND_POSIX; + _pEditView->execute(SCI_SETSEARCHFLAGS, flags); + TCHAR tag2find[] = TEXT("<[^\\s>]*"); + int targetStart = _pEditView->searchInTarget(tag2find, lstrlen(tag2find), caretPos, 0); + + if (targetStart == -1 || targetStart == -2) + return; + + int targetEnd = int(_pEditView->execute(SCI_GETTARGETEND)); + int foundTextLen = targetEnd - targetStart; + if (foundTextLen < 2) // "<>" will be ignored + return; + + if (size_t(foundTextLen) > closeTagSize - 2) // buffer size is not large enough. -2 for '/' & '\0' + return; + + char tagHeader[3]; + _pEditView->getText(tagHeader, targetStart, targetStart+2); + + if (tagHeader[1] == '\\') // "" will be ignored + return; + + closeTag[0] = '<'; + closeTag[1] = '\\'; + _pEditView->getText(closeTag + 2, targetStart + 1, targetEnd); + closeTag[foundTextLen+1] = '>'; + closeTag[foundTextLen+2] = '\0'; +} + +void AutoCompletion::insertMatchedChars(int character, const MatchedPairConf & matchedPairConf) +{ + const vector< pair > & matchedPairs = matchedPairConf._matchedPairs; + int caretPos = _pEditView->execute(SCI_GETCURRENTPOS); + char *matchedChars = NULL; + + // User defined matched pairs should be checked firstly + for (size_t i = 0, len = matchedPairs.size(); i < len; ++i) + { + if (int(matchedPairs[i].first) == character) + { + _pEditView->execute(SCI_INSERTTEXT, caretPos, (LPARAM)matchedPairs[i].second); + return; + } + } + + // if there's no user defined matched pair found, continue to check notepad++'s one + + const size_t closeTagLen = 256; + char closeTag[closeTagLen]; + closeTag[0] = '\0'; + switch (character) + { + case int('('): + if (matchedPairConf._doParentheses) + matchedChars = ")"; + break; + case int('['): + if (matchedPairConf._doBrackets) + matchedChars = "]"; + break; + case int('{'): + if (matchedPairConf._doCurlyBrackets) + matchedChars = "}"; + break; + case int('"'): + if (matchedPairConf._doDoubleQuotes) + matchedChars = "\""; + break; + case int('\''): + if (matchedPairConf._doQuotes) + matchedChars = "'"; + break; + case int('>'): + { + if (matchedPairConf._doHtmlXmlTag) + { + getCloseTag(closeTag, closeTagLen, caretPos); + if (closeTag[0] != '\0') + matchedChars = closeTag; + } + } + break; + } + + if (matchedChars) + _pEditView->execute(SCI_INSERTTEXT, caretPos, (LPARAM)matchedChars); +} + + void AutoCompletion::update(int character) { const NppGUI & nppGUI = NppParameters::getInstance()->getNppGUI(); diff --git a/PowerEditor/src/ScitillaComponent/AutoCompletion.h b/PowerEditor/src/ScitillaComponent/AutoCompletion.h index 21bad46df..996d4946f 100644 --- a/PowerEditor/src/ScitillaComponent/AutoCompletion.h +++ b/PowerEditor/src/ScitillaComponent/AutoCompletion.h @@ -63,8 +63,10 @@ public: //Parameter display from the list bool showFunctionComplete(); + void insertMatchedChars(int character, const MatchedPairConf & matchedPairConf); void update(int character); void callTipClick(int direction); + void getCloseTag(char *closeTag, size_t closeTagLen, size_t caretPos); private: bool _funcCompletionActive; diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 2367e4aec..7ad78b78c 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -1762,7 +1762,6 @@ void ScintillaEditView::getText(char *dest, int start, int end) const void ScintillaEditView::getGenericText(TCHAR *dest, size_t destlen, int start, int end) const { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); char *destA = new char[end - start + 1]; getText(destA, start, end); @@ -1770,15 +1769,11 @@ void ScintillaEditView::getGenericText(TCHAR *dest, size_t destlen, int start, i const TCHAR *destW = wmc->char2wchar(destA, cp); _tcsncpy_s(dest, destlen, destW, _TRUNCATE); delete [] destA; -#else - getText(dest, start, end); -#endif } // "mstart" and "mend" are pointers to indexes in the read string, // which are converted to the corresponding indexes in the returned TCHAR string. -#ifdef UNICODE void ScintillaEditView::getGenericText(TCHAR *dest, size_t destlen, int start, int end, int *mstart, int *mend) const { WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); @@ -1789,24 +1784,13 @@ void ScintillaEditView::getGenericText(TCHAR *dest, size_t destlen, int start, i _tcsncpy_s(dest, destlen, destW, _TRUNCATE); delete [] destA; } -#else -void ScintillaEditView::getGenericText(TCHAR *dest, int start, int end, int *, int *) const -{ - getText(dest, start, end); -} -#endif - void ScintillaEditView::insertGenericTextFrom(int position, const TCHAR *text2insert) const { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *text2insertA = wmc->wchar2char(text2insert, cp); execute(SCI_INSERTTEXT, position, (WPARAM)text2insertA); -#else - execute(SCI_INSERTTEXT, position, (WPARAM)text2insert); -#endif } void ScintillaEditView::replaceSelWith(const char * replaceText) @@ -1854,7 +1838,6 @@ char * ScintillaEditView::getWordOnCaretPos(char * txt, int size) TCHAR * ScintillaEditView::getGenericWordOnCaretPos(TCHAR * txt, int size) { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); char *txtA = new char[size + 1]; @@ -1864,9 +1847,6 @@ TCHAR * ScintillaEditView::getGenericWordOnCaretPos(TCHAR * txt, int size) lstrcpy(txt, txtW); delete [] txtA; return txt; -#else - return getWordOnCaretPos(txt, size); -#endif } char * ScintillaEditView::getSelectedText(char * txt, int size, bool expand) @@ -1889,7 +1869,6 @@ char * ScintillaEditView::getSelectedText(char * txt, int size, bool expand) TCHAR * ScintillaEditView::getGenericSelectedText(TCHAR * txt, int size, bool expand) { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); char *txtA = new char[size + 1]; @@ -1899,16 +1878,13 @@ TCHAR * ScintillaEditView::getGenericSelectedText(TCHAR * txt, int size, bool ex lstrcpy(txt, txtW); delete [] txtA; return txt; -#else - return getSelectedText(txt, size, expand); -#endif } int ScintillaEditView::searchInTarget(const TCHAR * text2Find, int lenOfText2Find, int fromPos, int toPos) const { execute(SCI_SETTARGETSTART, fromPos); execute(SCI_SETTARGETEND, toPos); -#ifdef UNICODE + WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *text2FindA = wmc->wchar2char(text2Find, cp); @@ -1916,36 +1892,24 @@ int ScintillaEditView::searchInTarget(const TCHAR * text2Find, int lenOfText2Fin int len = (lenOfText2Find > (int)text2FindALen)?lenOfText2Find:text2FindALen; int targetFound = execute(SCI_SEARCHINTARGET, (WPARAM)len, (LPARAM)text2FindA); return targetFound; -#else - return execute(SCI_SEARCHINTARGET, (WPARAM)lenOfText2Find, (LPARAM)text2Find); -#endif } void ScintillaEditView::appandGenericText(const TCHAR * text2Append) const { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *text2AppendA =wmc->wchar2char(text2Append, cp); execute(SCI_APPENDTEXT, strlen(text2AppendA), (LPARAM)text2AppendA); -#else - execute(SCI_APPENDTEXT, strlen(text2Append), (LPARAM)text2Append); -#endif } void ScintillaEditView::addGenericText(const TCHAR * text2Append) const { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *text2AppendA =wmc->wchar2char(text2Append, cp); execute(SCI_ADDTEXT, strlen(text2AppendA), (LPARAM)text2AppendA); -#else - execute(SCI_ADDTEXT, strlen(text2Append), (LPARAM)text2Append); -#endif } -#ifdef UNICODE void ScintillaEditView::addGenericText(const TCHAR * text2Append, long *mstart, long *mend) const { WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); @@ -1953,12 +1917,6 @@ void ScintillaEditView::addGenericText(const TCHAR * text2Append, long *mstart, const char *text2AppendA =wmc->wchar2char(text2Append, cp, mstart, mend); execute(SCI_ADDTEXT, strlen(text2AppendA), (LPARAM)text2AppendA); } -#else -void ScintillaEditView::addGenericText(const TCHAR * text2Append, long *, long *) const -{ - execute(SCI_ADDTEXT, strlen(text2Append), (LPARAM)text2Append); -} -#endif int ScintillaEditView::replaceTarget(const TCHAR * str2replace, int fromTargetPos, int toTargetPos) const { @@ -1967,14 +1925,10 @@ int ScintillaEditView::replaceTarget(const TCHAR * str2replace, int fromTargetPo execute(SCI_SETTARGETSTART, fromTargetPos); execute(SCI_SETTARGETEND, toTargetPos); } -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *str2replaceA = wmc->wchar2char(str2replace, cp); return execute(SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)str2replaceA); -#else - return execute(SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)str2replace); -#endif } int ScintillaEditView::replaceTargetRegExMode(const TCHAR * re, int fromTargetPos, int toTargetPos) const @@ -1984,42 +1938,28 @@ int ScintillaEditView::replaceTargetRegExMode(const TCHAR * re, int fromTargetPo execute(SCI_SETTARGETSTART, fromTargetPos); execute(SCI_SETTARGETEND, toTargetPos); } -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *reA = wmc->wchar2char(re, cp); return execute(SCI_REPLACETARGETRE, (WPARAM)-1, (LPARAM)reA); -#else - return execute(SCI_REPLACETARGETRE, (WPARAM)-1, (LPARAM)re); -#endif } void ScintillaEditView::showAutoComletion(int lenEntered, const TCHAR * list) { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *listA = wmc->wchar2char(list, cp); execute(SCI_AUTOCSHOW, lenEntered, WPARAM(listA)); -#else - execute(SCI_AUTOCSHOW, lenEntered, WPARAM(list)); -#endif } void ScintillaEditView::showCallTip(int startPos, const TCHAR * def) { -#ifdef UNICODE WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); unsigned int cp = execute(SCI_GETCODEPAGE); const char *defA = wmc->wchar2char(def, cp); execute(SCI_CALLTIPSHOW, startPos, LPARAM(defA)); -#else - execute(SCI_CALLTIPSHOW, startPos, (LPARAM)def); -#endif } - -#ifdef UNICODE void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int lineBufferLen) { WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance(); @@ -2030,14 +1970,6 @@ void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int lineBufferLen) lstrcpy(line, lineW); delete [] lineA; } -#else -void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int) -{ - execute(SCI_GETLINE, lineNumber, (LPARAM)line); -} -#endif - - void ScintillaEditView::addText(int length, const char *buf) {