mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-27 15:54:17 +02:00
[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:
parent
7cd1965585
commit
73cfa3785e
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user