[NEW_FEATURE] Add function + word completion option in auto-completion feature.

git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@1177 f5eea248-9336-0410-98b8-ebc06183d4e3
This commit is contained in:
Don Ho 2014-02-16 02:13:05 +00:00
parent f1e1cfbe90
commit 63626f65c1
7 changed files with 173 additions and 77 deletions

View File

@ -5269,7 +5269,7 @@ struct Quote{
const char *_quote;
};
const int nbQuote = 183;
const int nbQuote = 193;
Quote quotes[nbQuote] = {
{"Notepad++", "Good programmers use Notepad++ to code.\nExtreme programmers use MS Word to code, in Comic Sans, center aligned."},
{"Martin Golding", "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."},
@ -5438,6 +5438,16 @@ Quote quotes[nbQuote] = {
{"Anonymous #134", "Linux is user friendly.\nIt's just picky about its friends."},
{"Anonymous #135", "Theory is when you know something, but it doesn't work.\nPractice is when something works, but you don't know why.\nProgrammers combine theory and practice: nothing works and they don't know why."},
{"Anonymous #136", "Documentation is like sex:\nwhen it's good, it's very, very good;\nwhen it's bad, it's better than nothing."},
{"Anonymous #137", "Home is where you poop most comfortably."},
{"Anonymous #138", "Laptop Speakers problem: too quiet for music, too loud for porn."},
{"Anonymous #139", "Chinese food to go: $16\nGas to go get the food: $2\nDrove home just to realize they forgot one of your containers: RICELESS"},
{"Anonymous #140", "MS Windows is like religion to most people: they are born into it, accept it as default, never consider switching to another."},
{"Anonymous #141", "To most religious people, the holy books are like a software license (EULA).\nNobody actually reads it. They just scroll to the bottom and click \"I agree\"."},
{"Anonymous #142", "You are nothing but a number of days,\nwhenever each day passes then part of you has gone."},
{"Anonymous #143", "If 666 is evil, does that make 25.8069758011 the root of all evil?"},
{"Simon Amstell", "If you have some problem in your life and need to deal with it, then use religion, that's fine.\nI use Google."},
{"James Bond", "James, James Bond."},
{"Albert Einstein", "Only 3 things are infinite:\n1. Universe.\n2. Human Stupidity.\n3. Winrar's free trial."},
{"Terry Pratchett", "Artificial Intelligence is no match for natural stupidity."},
{"Stewart Brand", "Once a new technology starts rolling, if you're not part of the steamroller,\nyou're part of the road."},
{"Sam Redwine", "Software and cathedrals are much the same - first we build them, then we pray."},

View File

@ -706,7 +706,7 @@ struct NppGUI
_checkHistoryFiles(true) ,_enableSmartHilite(true), _disableSmartHiliteTmp(false), _enableTagsMatchHilite(true), _enableTagAttrsHilite(true), _enableHiliteNonHTMLZone(false),\
_isMaximized(false), _isMinimizedToTray(false), _rememberLastSession(true), _backup(bak_none), _useDir(false), _backupDir(TEXT("")),\
_doTaskList(true), _maitainIndent(true), _openSaveDir(dir_followCurrent), _styleMRU(true), _styleURL(0),\
_autocStatus(autoc_none), _autocFromLen(1), _funcParams(false), _definedSessionExt(TEXT("")),\
_autocStatus(autoc_both), _autocFromLen(1), _funcParams(false), _definedSessionExt(TEXT("")),\
_doesExistUpdater(false), _caretBlinkRate(250), _caretWidth(1), _enableMultiSelection(false), _shortTitlebar(false), _themeName(TEXT("")), _isLangMenuCompact(false),\
_smartHiliteCaseSensitive(false), _leftmostDelimiter('('), _rightmostDelimiter(')'), _delimiterSelectionOnEntireDocument(false), _multiInstSetting(monoInst),\
_fileSwitcherWithoutExtColumn(false) {
@ -778,7 +778,7 @@ struct NppGUI
generic_string _backupDir;
DockingManagerData _dockingData;
GlobalOverride _globalOverride;
enum AutocStatus{autoc_none, autoc_func, autoc_word};
enum AutocStatus{autoc_none, autoc_func, autoc_word, autoc_both};
AutocStatus _autocStatus;
size_t _autocFromLen;
bool _funcParams;

View File

@ -40,6 +40,7 @@ static bool isInList(generic_string word, const vector<generic_string> & wordArr
return false;
};
bool AutoCompletion::showApiComplete()
{
if (!_funcCompletionActive)
@ -47,40 +48,108 @@ bool AutoCompletion::showApiComplete()
// calculate entered word's length
int curPos = int(_pEditView->execute(SCI_GETCURRENTPOS));
int line = _pEditView->getCurrentLineNumber();
int startLinePos = int(_pEditView->execute(SCI_POSITIONFROMLINE, line ));
int startWordPos = startLinePos;
int startPos = int(_pEditView->execute(SCI_WORDSTARTPOSITION, curPos, true));
int len = curPos - startLinePos;
char * lineBuffer = new char[len+1];
_pEditView->getText(lineBuffer, startLinePos, curPos);
if (curPos == startPos)
return false;
int offset = len - 1;
int nrChars = 0;
char c;
while (offset >= 0)
{
c = lineBuffer[offset];
if (isalnum(c) || c == '_')
{
++nrChars;
}
else
{
break;
}
--offset;
}
startWordPos = curPos - nrChars;
size_t len = (curPos > startPos)?(curPos - startPos):(startPos - curPos);
if (len >= _keyWordMaxLen)
return false;
_pEditView->execute(SCI_AUTOCSETSEPARATOR, WPARAM('\n'));
_pEditView->execute(SCI_AUTOCSETSEPARATOR, WPARAM(' '));
_pEditView->execute(SCI_AUTOCSETIGNORECASE, _ignoreCase);
_pEditView->showAutoComletion(curPos - startWordPos, _keyWords.c_str());
_pEditView->showAutoComletion(curPos - startPos, _keyWords.c_str());
return true;
}
bool AutoCompletion::showApiAndWordComplete()
{
int curPos = int(_pEditView->execute(SCI_GETCURRENTPOS));
int startPos = int(_pEditView->execute(SCI_WORDSTARTPOSITION, curPos, true));
if (curPos == startPos)
return false;
const size_t bufSize = 256;
TCHAR beginChars[bufSize];
size_t len = (curPos > startPos)?(curPos - startPos):(startPos - curPos);
if (len >= bufSize)
return false;
// Get word array
vector<generic_string> wordArray;
_pEditView->getGenericText(beginChars, bufSize, startPos, curPos);
getWordArray(wordArray, beginChars);
for (size_t i = 0, len = _keyWordArray.size(); i < len; ++i)
{
if (_keyWordArray[i].find(beginChars) == 0)
{
if (!isInList(_keyWordArray[i], wordArray))
wordArray.push_back(_keyWordArray[i]);
}
}
sort(wordArray.begin(), wordArray.end());
// Get word list
generic_string words(TEXT(""));
for (size_t i = 0, len = wordArray.size(); i < len; ++i)
{
words += wordArray[i];
if (i != wordArray.size()-1)
words += TEXT(" ");
}
_pEditView->execute(SCI_AUTOCSETSEPARATOR, WPARAM(' '));
_pEditView->execute(SCI_AUTOCSETIGNORECASE, _ignoreCase);
_pEditView->showAutoComletion(curPos - startPos, words.c_str());
return true;
}
void AutoCompletion::getWordArray(vector<generic_string> & wordArray, TCHAR *beginChars)
{
const size_t bufSize = 256;
generic_string expr(TEXT("\\<"));
expr += beginChars;
expr += TEXT("[^ \\t\\n\\r.,;:\"()=<>'+!\\[\\]]*");
int docLength = int(_pEditView->execute(SCI_GETLENGTH));
int flags = SCFIND_WORDSTART | SCFIND_MATCHCASE | SCFIND_REGEXP | SCFIND_POSIX;
_pEditView->execute(SCI_SETSEARCHFLAGS, flags);
int posFind = _pEditView->searchInTarget(expr.c_str(), expr.length(), 0, docLength);
while (posFind != -1)
{
int wordStart = int(_pEditView->execute(SCI_GETTARGETSTART));
int wordEnd = int(_pEditView->execute(SCI_GETTARGETEND));
size_t foundTextLen = wordEnd - wordStart;
if (foundTextLen < bufSize)
{
TCHAR w[bufSize];
_pEditView->getGenericText(w, bufSize, wordStart, wordEnd);
if (lstrcmp(w, beginChars) != 0)
if (!isInList(w, wordArray))
wordArray.push_back(w);
}
posFind = _pEditView->searchInTarget(expr.c_str(), expr.length(), wordEnd, docLength);
}
}
static generic_string addTrailingSlash(generic_string path)
{
if(path.length() >=1 && path[path.length() - 1] == '\\')
@ -237,7 +306,7 @@ void AutoCompletion::showPathCompletion()
return;
}
bool AutoCompletion::showWordComplete(bool autoInsert)
bool AutoCompletion::showWordComplete(bool autoInsert)
{
int curPos = int(_pEditView->execute(SCI_GETCURRENTPOS));
int startPos = int(_pEditView->execute(SCI_WORDSTARTPOSITION, curPos, true));
@ -246,46 +315,18 @@ bool AutoCompletion::showWordComplete(bool autoInsert)
return false;
const size_t bufSize = 256;
TCHAR beginChars[bufSize];
size_t len = (curPos > startPos)?(curPos - startPos):(startPos - curPos);
if (len >= bufSize)
return false;
// Get word array
TCHAR beginChars[bufSize];
vector<generic_string> wordArray;
_pEditView->getGenericText(beginChars, bufSize, startPos, curPos);
generic_string expr(TEXT("\\<"));
expr += beginChars;
expr += TEXT("[^ \\t\\n\\r.,;:\"()=<>'+!\\[\\]]*");
getWordArray(wordArray, beginChars);
int docLength = int(_pEditView->execute(SCI_GETLENGTH));
int flags = SCFIND_WORDSTART | SCFIND_MATCHCASE | SCFIND_REGEXP | SCFIND_POSIX;
_pEditView->execute(SCI_SETSEARCHFLAGS, flags);
vector<generic_string> wordArray;
int posFind = _pEditView->searchInTarget(expr.c_str(), expr.length(), 0, docLength);
while (posFind != -1)
{
int wordStart = int(_pEditView->execute(SCI_GETTARGETSTART));
int wordEnd = int(_pEditView->execute(SCI_GETTARGETEND));
size_t foundTextLen = wordEnd - wordStart;
if (foundTextLen < bufSize)
{
TCHAR w[bufSize];
_pEditView->getGenericText(w, bufSize, wordStart, wordEnd);
if (lstrcmp(w, beginChars) != 0)
if (!isInList(w, wordArray))
wordArray.push_back(w);
}
posFind = _pEditView->searchInTarget(expr.c_str(), expr.length(), wordEnd, docLength);
}
if (wordArray.size() == 0) return false;
if (wordArray.size() == 1 && autoInsert)
@ -464,6 +505,9 @@ void AutoCompletion::update(int character)
}
else if (nppGUI._autocStatus == nppGUI.autoc_func)
showApiComplete();
else if (nppGUI._autocStatus == nppGUI.autoc_both)
showApiAndWordComplete();
}
}
@ -559,18 +603,35 @@ bool AutoCompletion::setLanguage(LangType language) {
}
_keyWords = TEXT("");
_keyWordArray.clear();
if (_funcCompletionActive)
{
//Cache the keywords
//Iterate through all keywords
TiXmlElement *funcNode = _pXmlKeyword;
const TCHAR * name = NULL;
for (; funcNode; funcNode = funcNode->NextSiblingElement(TEXT("KeyWord")) ) {
for (; funcNode; funcNode = funcNode->NextSiblingElement(TEXT("KeyWord")) )
{
name = funcNode->Attribute(TEXT("name"));
if (!name) //malformed node
continue;
_keyWords.append(name);
_keyWords.append(TEXT("\n"));
if (name)
{
size_t len = lstrlen(name);
if (len)
{
_keyWordArray.push_back(name);
if (len > _keyWordMaxLen)
_keyWordMaxLen = len;
}
}
}
sort(_keyWordArray.begin(), _keyWordArray.end());
for (size_t i = 0, len = _keyWordArray.size(); i < len; ++i)
{
_keyWords.append(_keyWordArray[i]);
_keyWords.append(TEXT(" "));
}
}
return _funcCompletionActive;

View File

@ -44,7 +44,7 @@ public:
enum ActiveCompletion {CompletionNone = 0, CompletionAuto, CompletionWord, CompletionFunc, CompletionPath};
AutoCompletion(ScintillaEditView * pEditView) : _funcCompletionActive(false), _pEditView(pEditView), _funcCalltip(pEditView),
_curLang(L_TEXT), _pXmlFile(NULL),
_curLang(L_TEXT), _pXmlFile(NULL), _keyWordMaxLen(0),
_pXmlKeyword(NULL), _ignoreCase(true), _keyWords(TEXT("")) {
//Do not load any language yet
};
@ -60,6 +60,8 @@ public:
bool showApiComplete();
//WordCompletion from the current file
bool showWordComplete(bool autoInsert); //autoInsert true if completion should fill in the word on a single match
// AutoComplete from both the list and the current file
bool showApiAndWordComplete();
//Parameter display from the list
bool showFunctionComplete();
// Autocomplete from path.
@ -79,10 +81,14 @@ private:
bool _ignoreCase;
vector<generic_string> _keyWordArray;
generic_string _keyWords;
size_t _keyWordMaxLen;
FunctionCallTip _funcCalltip;
const TCHAR * getApiFileName();
void getWordArray(vector<generic_string> & wordArray, TCHAR *beginChars);
};
#endif //AUTOCOMPLETION_H

View File

@ -310,15 +310,15 @@ BEGIN
GROUPBOX "Auto-Completion",IDD_AUTOC_GRPSTATIC,86,4,289,84,BS_CENTER
CONTROL "Enable auto-completion on each input",IDD_AUTOC_ENABLECHECK,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,15,150,10
CONTROL "Function completion",IDD_AUTOC_FUNCRADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,118,29,145,10
CONTROL "Word completion",IDD_AUTOC_WORDRADIO,"Button",BS_AUTORADIOBUTTON,118,45,145,10
CONTROL "Function completion",IDD_AUTOC_FUNCRADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,118,27,145,10
CONTROL "Word completion",IDD_AUTOC_WORDRADIO,"Button",BS_AUTORADIOBUTTON,118,41,145,10
CONTROL "Function and Word completion",IDD_AUTOC_BOTHRADIO,"Button",BS_AUTORADIOBUTTON,118,55,145,10
RTEXT "From",IDD_AUTOC_STATIC_FROM,248,15,47,8
CTEXT "1",IDD_AUTOC_STATIC_N,299,15,8,8,WS_TABSTOP
LTEXT "th character",IDD_AUTOC_STATIC_CHAR,313,15,57,8
LTEXT "Valid value : 1 - 9",IDD_AUTOC_STATIC_NOTE,278,25,93,8
CONTROL "Function parameters hint on input",IDD_FUNC_CHECK,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,67,160,10
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,72,160,10
GROUPBOX "Auto-Insert",IDD_AUTOCINSERT_GRPSTATIC,86,94,289,84,BS_CENTER
CONTROL " (",IDD_AUTOCPARENTHESES_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,115,24,10
CONTROL " [",IDD_AUTOCBRACKET_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,133,24,10

View File

@ -2288,13 +2288,22 @@ BOOL CALLBACK AutoCompletionDlg::run_dlgProc(UINT Message, WPARAM wParam, LPARAM
bool isEnableAutoC = nppGUI._autocStatus != nppGUI.autoc_none;
::SendDlgItemMessage(_hSelf, IDD_AUTOC_ENABLECHECK, BM_SETCHECK, isEnableAutoC?BST_CHECKED:BST_UNCHECKED, 0);
::SendDlgItemMessage(_hSelf, IDD_AUTOC_FUNCRADIO, BM_SETCHECK, nppGUI._autocStatus == nppGUI.autoc_func?BST_CHECKED:BST_UNCHECKED, 0);
::SendDlgItemMessage(_hSelf, IDD_AUTOC_WORDRADIO, BM_SETCHECK, nppGUI._autocStatus == nppGUI.autoc_word?BST_CHECKED:BST_UNCHECKED, 0);
::SendDlgItemMessage(_hSelf, IDD_FUNC_CHECK, BM_SETCHECK, nppGUI._funcParams?BST_CHECKED:BST_UNCHECKED, 0);
int selectedID = IDD_AUTOC_BOTHRADIO;
if (nppGUI._autocStatus == nppGUI.autoc_func)
selectedID = IDD_AUTOC_FUNCRADIO;
else if (nppGUI._autocStatus == nppGUI.autoc_word)
selectedID = IDD_AUTOC_WORDRADIO;
else if (nppGUI._autocStatus == nppGUI.autoc_both)
selectedID = IDD_AUTOC_BOTHRADIO;
::SendDlgItemMessage(_hSelf, selectedID, BM_SETCHECK, BST_CHECKED, 0);
if (!isEnableAutoC)
{
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_FUNCRADIO), FALSE);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_WORDRADIO), FALSE);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_BOTHRADIO), FALSE);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_STATIC_FROM), FALSE);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_STATIC_N), FALSE);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_STATIC_CHAR), FALSE);
@ -2408,17 +2417,19 @@ BOOL CALLBACK AutoCompletionDlg::run_dlgProc(UINT Message, WPARAM wParam, LPARAM
if (isEnableAutoC)
{
::SendDlgItemMessage(_hSelf, IDD_AUTOC_FUNCRADIO, BM_SETCHECK, BST_CHECKED, 0);
nppGUI._autocStatus = nppGUI.autoc_func;
::SendDlgItemMessage(_hSelf, IDD_AUTOC_BOTHRADIO, BM_SETCHECK, BST_CHECKED, 0);
nppGUI._autocStatus = nppGUI.autoc_both;
}
else
{
::SendDlgItemMessage(_hSelf, IDD_AUTOC_FUNCRADIO, BM_SETCHECK, BST_UNCHECKED, 0);
::SendDlgItemMessage(_hSelf, IDD_AUTOC_WORDRADIO, BM_SETCHECK, BST_UNCHECKED, 0);
::SendDlgItemMessage(_hSelf, IDD_AUTOC_BOTHRADIO, BM_SETCHECK, BST_UNCHECKED, 0);
nppGUI._autocStatus = nppGUI.autoc_none;
}
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_FUNCRADIO), isEnableAutoC);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_WORDRADIO), isEnableAutoC);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_BOTHRADIO), isEnableAutoC);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_STATIC_FROM), isEnableAutoC);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_STATIC_N), isEnableAutoC);
::EnableWindow(::GetDlgItem(_hSelf, IDD_AUTOC_STATIC_CHAR), isEnableAutoC);
@ -2437,6 +2448,13 @@ BOOL CALLBACK AutoCompletionDlg::run_dlgProc(UINT Message, WPARAM wParam, LPARAM
nppGUI._autocStatus = nppGUI.autoc_word;
return TRUE;
}
case IDD_AUTOC_BOTHRADIO :
{
nppGUI._autocStatus = nppGUI.autoc_both;
return TRUE;
}
case IDD_FUNC_CHECK :
{
nppGUI._funcParams = (BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDD_FUNC_CHECK, BM_GETCHECK, 0, 0));

View File

@ -278,6 +278,7 @@
#define IDD_AUTOC_STATIC_CHAR (IDD_PREFERENCE_BACKUP_BOX + 13)
#define IDD_AUTOC_STATIC_NOTE (IDD_PREFERENCE_BACKUP_BOX + 14)
#define IDD_FUNC_CHECK (IDD_PREFERENCE_BACKUP_BOX + 15)
#define IDD_AUTOC_BOTHRADIO (IDD_PREFERENCE_BACKUP_BOX + 16)
#define IDD_PREFERENCE_AUTOCOMPLETION_BOX 6850 //(IDD_PREFERENCE_BOX + 850)
#define IDD_AUTOCINSERT_GRPSTATIC (IDD_PREFERENCE_AUTOCOMPLETION_BOX + 1)