[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
This commit is contained in:
Don Ho 2013-09-02 09:05:37 +00:00
parent 01f3148e0e
commit 0b5687052e
6 changed files with 183 additions and 70 deletions

View File

@ -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<TCHAR>(notification->ch));
AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub;
MatchedPairConf matchedPairConf;
if (matchedPairConf.hasAnyPairsPair())
autoC->insertMatchedChars(notification->ch, matchedPairConf);
autoC->update(notification->ch);
break;
}

View File

@ -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, char>(char(open), char(close)));
}
}
}
else if (!lstrcmp(nm, TEXT("sessionExt")))
{

View File

@ -675,6 +675,23 @@ private:
unsigned long _day;
};
struct MatchedPairConf {
vector< pair<char, char> > _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;

View File

@ -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] == '\\') // "</toto>" 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<char, char> > & 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();

View File

@ -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;

View File

@ -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)
{