From 63626f65c14d499b9398fe422a79d5c83298ab26 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Sun, 16 Feb 2014 02:13:05 +0000 Subject: [PATCH] [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 --- PowerEditor/src/Notepad_plus.cpp | 12 +- PowerEditor/src/Parameters.h | 4 +- .../src/ScitillaComponent/AutoCompletion.cpp | 189 ++++++++++++------ .../src/ScitillaComponent/AutoCompletion.h | 8 +- .../src/WinControls/Preference/preference.rc | 8 +- .../WinControls/Preference/preferenceDlg.cpp | 28 ++- .../WinControls/Preference/preference_rc.h | 1 + 7 files changed, 173 insertions(+), 77 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.cpp b/PowerEditor/src/Notepad_plus.cpp index e3ddbd84e..1e35c9093 100644 --- a/PowerEditor/src/Notepad_plus.cpp +++ b/PowerEditor/src/Notepad_plus.cpp @@ -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."}, diff --git a/PowerEditor/src/Parameters.h b/PowerEditor/src/Parameters.h index 12749ffbc..f7d647012 100644 --- a/PowerEditor/src/Parameters.h +++ b/PowerEditor/src/Parameters.h @@ -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; diff --git a/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp b/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp index f184a6ec8..1d2e79c33 100644 --- a/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp +++ b/PowerEditor/src/ScitillaComponent/AutoCompletion.cpp @@ -40,6 +40,7 @@ static bool isInList(generic_string word, const vector & 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 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 & 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 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 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; diff --git a/PowerEditor/src/ScitillaComponent/AutoCompletion.h b/PowerEditor/src/ScitillaComponent/AutoCompletion.h index a207fca7e..40dc122e5 100644 --- a/PowerEditor/src/ScitillaComponent/AutoCompletion.h +++ b/PowerEditor/src/ScitillaComponent/AutoCompletion.h @@ -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 _keyWordArray; generic_string _keyWords; + size_t _keyWordMaxLen; FunctionCallTip _funcCalltip; + const TCHAR * getApiFileName(); + void getWordArray(vector & wordArray, TCHAR *beginChars); }; #endif //AUTOCOMPLETION_H diff --git a/PowerEditor/src/WinControls/Preference/preference.rc b/PowerEditor/src/WinControls/Preference/preference.rc index e2b65bebd..79a9f0070 100644 --- a/PowerEditor/src/WinControls/Preference/preference.rc +++ b/PowerEditor/src/WinControls/Preference/preference.rc @@ -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 diff --git a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp index 8fc8c8f40..06df3d876 100644 --- a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp +++ b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp @@ -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)); diff --git a/PowerEditor/src/WinControls/Preference/preference_rc.h b/PowerEditor/src/WinControls/Preference/preference_rc.h index cfca6f9db..588d7d399 100644 --- a/PowerEditor/src/WinControls/Preference/preference_rc.h +++ b/PowerEditor/src/WinControls/Preference/preference_rc.h @@ -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)