[NEW_FEATURE] (Author: Andreas Jonsson) Add auto-completion for absolute path feature.

git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@1129 f5eea248-9336-0410-98b8-ebc06183d4e3
This commit is contained in:
Don Ho 2013-10-10 23:05:50 +00:00
parent 7cd1965585
commit 73cfa3785e
8 changed files with 176 additions and 1 deletions

View File

@ -3385,6 +3385,13 @@ void Notepad_plus::showAutoComp()
autoC->showAutoComplete();
}
void Notepad_plus::showPathCompletion()
{
bool isFromPrimary = _pEditView == &_mainEditView;
AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub;
autoC->showPathCompletion();
}
void Notepad_plus::autoCompFromCurrentFile(bool autoInsert)
{
bool isFromPrimary = _pEditView == &_mainEditView;

View File

@ -583,6 +583,7 @@ private:
void showAutoComp();
void autoCompFromCurrentFile(bool autoInsert = true);
void showFunctionComp();
void showPathCompletion();
//void changeStyleCtrlsLang(HWND hDlg, int *idArray, const char **translatedText);
bool replaceInOpenedFiles();

View File

@ -279,6 +279,7 @@ BEGIN
MENUITEM "Function Completion", IDM_EDIT_AUTOCOMPLETE
MENUITEM "Word Completion", IDM_EDIT_AUTOCOMPLETE_CURRENTFILE
MENUITEM "Function Parameters Hint", IDM_EDIT_FUNCCALLTIP
MENUITEM "Path Completion", IDM_EDIT_AUTOCOMPLETE_PATH
END
POPUP "EOL Conversion"
BEGIN

View File

@ -2258,6 +2258,10 @@ void Notepad_plus::command(int id)
autoCompFromCurrentFile();
break;
case IDM_EDIT_AUTOCOMPLETE_PATH :
showPathCompletion();
break;
case IDM_EDIT_FUNCCALLTIP :
showFunctionComp();
break;

View File

@ -118,6 +118,7 @@ WinMenuKeyDefinition winKeyDefs[] = {
{VK_K, IDM_EDIT_BLOCK_UNCOMMENT, true, false, true, NULL},
{VK_Q, IDM_EDIT_STREAM_COMMENT, true, false, true, NULL},
{VK_SPACE, IDM_EDIT_AUTOCOMPLETE, true, false, false, NULL},
{VK_SPACE, IDM_EDIT_AUTOCOMPLETE_PATH, true, true, false, NULL},
{VK_RETURN, IDM_EDIT_AUTOCOMPLETE_CURRENTFILE, true, false, false, NULL},
{VK_SPACE, IDM_EDIT_FUNCCALLTIP, true, false, true, NULL},
{VK_R, IDM_EDIT_RTL, true, true, false, NULL},

View File

@ -30,6 +30,7 @@
#include "AutoCompletion.h"
#include "Notepad_plus_msgs.h"
#include <locale>
static bool isInList(generic_string word, const vector<generic_string> & wordArray)
{
@ -76,6 +77,163 @@ bool AutoCompletion::showAutoComplete() {
return true;
}
static generic_string addTrailingSlash(generic_string path)
{
if(path.length() >=1 && path[path.length() - 1] == '\\')
return path;
else
return path + L"\\";
}
static generic_string removeTrailingSlash(generic_string path)
{
if(path.length() >= 1 && path[path.length() - 1] == '\\')
return path.substr(0, path.length() - 1);
else
return path;
}
static bool isDirectory(generic_string path)
{
DWORD type = ::GetFileAttributes(path.c_str());
return type != INVALID_FILE_ATTRIBUTES && (type & FILE_ATTRIBUTE_DIRECTORY);
}
static bool isFile(generic_string path)
{
DWORD type = ::GetFileAttributes(path.c_str());
return type != INVALID_FILE_ATTRIBUTES && ! (type & FILE_ATTRIBUTE_DIRECTORY);
}
static bool isAllowedBeforeDriveLetter(TCHAR c)
{
locale loc;
return c == '\'' || c == '"' || std::isspace(c, loc);
}
static bool getRawPath(generic_string input, generic_string &rawPath_out)
{
// Try to find a path in the given input.
// Algorithm: look for a colon. The colon must be preceded by an alphabetic character.
// The alphabetic character must, in turn, be preceded by nothing, or by whitespace, or by
// a quotation mark.
locale loc;
size_t lastOccurrence = input.rfind(L":");
if(lastOccurrence == std::string::npos) // No match.
return false;
else if(lastOccurrence == 0)
return false;
else if(!std::isalpha(input[lastOccurrence - 1], loc))
return false;
else if(lastOccurrence >= 2 && !isAllowedBeforeDriveLetter(input[lastOccurrence - 2]))
return false;
rawPath_out = input.substr(lastOccurrence - 1);
return true;
}
static bool getPathsForPathCompletion(generic_string input, generic_string &rawPath_out, generic_string &pathToMatch_out)
{
generic_string rawPath;
if(! getRawPath(input, rawPath))
{
return false;
}
else if(isFile(rawPath) || isFile(removeTrailingSlash(rawPath)))
{
return false;
}
else if(isDirectory(rawPath))
{
rawPath_out = rawPath;
pathToMatch_out = rawPath;
return true;
}
else
{
locale loc;
size_t last_occurrence = rawPath.rfind(L"\\");
if(last_occurrence == std::string::npos) // No match.
return false;
else
{
rawPath_out = rawPath;
pathToMatch_out = rawPath.substr(0, last_occurrence);
return true;
}
}
}
void AutoCompletion::showPathCompletion()
{
// Get current line (at most MAX_PATH characters "backwards" from current caret).
generic_string currentLine;
{
const long bufSize = MAX_PATH;
TCHAR buf[bufSize + 1];
const int currentPos = _pEditView->execute(SCI_GETCURRENTPOS);
const int startPos = max(0, currentPos - bufSize);
_pEditView->getGenericText(buf, bufSize, startPos, currentPos);
currentLine = buf;
}
/* Try to figure out which path the user wants us to complete.
We need to know the "raw path", which is what the user actually wrote.
But we also need to know which directory to look in (pathToMatch), which might
not be the same as what the user wrote. This happens when the user types an
incomplete name.
For instance: the user wants to autocomplete "C:\Wind", and assuming that no such directory
exists, this means we should list all files and directories in C:.
*/
generic_string rawPath, pathToMatch;
if(! getPathsForPathCompletion(currentLine, rawPath, pathToMatch))
return;
// Get all files and directories in the path.
generic_string autoCompleteEntries;
{
HANDLE hFind;
WIN32_FIND_DATA data;
generic_string pathToMatchPlusSlash = addTrailingSlash(pathToMatch);
generic_string searchString = pathToMatchPlusSlash + TEXT("*.*");
hFind = ::FindFirstFile(searchString.c_str(), &data);
if(hFind != INVALID_HANDLE_VALUE)
{
// Maximum number of entries to show. Without this it appears to the user like N++ hangs when autocompleting
// some really large directories (c:\windows\winxsys on my system for instance).
const unsigned int maxEntries = 2000;
unsigned int counter = 0;
do
{
if(++counter > maxEntries)
break;
if(generic_string(data.cFileName) == TEXT(".") || generic_string(data.cFileName) == TEXT(".."))
continue;
if(! autoCompleteEntries.empty())
autoCompleteEntries += TEXT("\n");
autoCompleteEntries += pathToMatchPlusSlash;
autoCompleteEntries += data.cFileName;
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // If directory, add trailing slash.
autoCompleteEntries += TEXT("\\");
} while(::FindNextFile(hFind, &data));
::FindClose(hFind);
}
else
return;
}
// Show autocompletion box.
_pEditView->execute(SCI_AUTOCSETSEPARATOR, WPARAM('\n'));
_pEditView->execute(SCI_AUTOCSETIGNORECASE, true);
_pEditView->showAutoComletion(rawPath.length(), autoCompleteEntries.c_str());
_activeCompletion = CompletionPath;
return;
}
bool AutoCompletion::showWordComplete(bool autoInsert)
{
int curPos = int(_pEditView->execute(SCI_GETCURRENTPOS));

View File

@ -41,7 +41,7 @@ class ScintillaEditView;
class AutoCompletion {
public:
enum ActiveCompletion {CompletionNone = 0, CompletionAuto, CompletionWord, CompletionFunc};
enum ActiveCompletion {CompletionNone = 0, CompletionAuto, CompletionWord, CompletionFunc, CompletionPath};
AutoCompletion(ScintillaEditView * pEditView) : _funcCompletionActive(false), _pEditView(pEditView), _funcCalltip(pEditView),
_curLang(L_TEXT), _pXmlFile(NULL), _activeCompletion(CompletionNone),
@ -62,6 +62,8 @@ public:
bool showWordComplete(bool autoInsert); //autoInsert true if completion should fill in the word on a single match
//Parameter display from the list
bool showFunctionComplete();
// Autocomplete from path.
void showPathCompletion();
void insertMatchedChars(int character, const MatchedPairConf & matchedPairConf);
void update(int character);

View File

@ -129,6 +129,7 @@
#define IDM_EDIT_AUTOCOMPLETE (50000 + 0)
#define IDM_EDIT_AUTOCOMPLETE_CURRENTFILE (50000 + 1)
#define IDM_EDIT_FUNCCALLTIP (50000 + 2)
#define IDM_EDIT_AUTOCOMPLETE_PATH (50000 + 6)
//Belong to MENU FILE
#define IDM_OPEN_ALL_RECENT_FILE (IDM_EDIT + 40)