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();
|
autoC->showAutoComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Notepad_plus::showPathCompletion()
|
||||||
|
{
|
||||||
|
bool isFromPrimary = _pEditView == &_mainEditView;
|
||||||
|
AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub;
|
||||||
|
autoC->showPathCompletion();
|
||||||
|
}
|
||||||
|
|
||||||
void Notepad_plus::autoCompFromCurrentFile(bool autoInsert)
|
void Notepad_plus::autoCompFromCurrentFile(bool autoInsert)
|
||||||
{
|
{
|
||||||
bool isFromPrimary = _pEditView == &_mainEditView;
|
bool isFromPrimary = _pEditView == &_mainEditView;
|
||||||
|
@ -583,6 +583,7 @@ private:
|
|||||||
void showAutoComp();
|
void showAutoComp();
|
||||||
void autoCompFromCurrentFile(bool autoInsert = true);
|
void autoCompFromCurrentFile(bool autoInsert = true);
|
||||||
void showFunctionComp();
|
void showFunctionComp();
|
||||||
|
void showPathCompletion();
|
||||||
|
|
||||||
//void changeStyleCtrlsLang(HWND hDlg, int *idArray, const char **translatedText);
|
//void changeStyleCtrlsLang(HWND hDlg, int *idArray, const char **translatedText);
|
||||||
bool replaceInOpenedFiles();
|
bool replaceInOpenedFiles();
|
||||||
|
@ -279,6 +279,7 @@ BEGIN
|
|||||||
MENUITEM "Function Completion", IDM_EDIT_AUTOCOMPLETE
|
MENUITEM "Function Completion", IDM_EDIT_AUTOCOMPLETE
|
||||||
MENUITEM "Word Completion", IDM_EDIT_AUTOCOMPLETE_CURRENTFILE
|
MENUITEM "Word Completion", IDM_EDIT_AUTOCOMPLETE_CURRENTFILE
|
||||||
MENUITEM "Function Parameters Hint", IDM_EDIT_FUNCCALLTIP
|
MENUITEM "Function Parameters Hint", IDM_EDIT_FUNCCALLTIP
|
||||||
|
MENUITEM "Path Completion", IDM_EDIT_AUTOCOMPLETE_PATH
|
||||||
END
|
END
|
||||||
POPUP "EOL Conversion"
|
POPUP "EOL Conversion"
|
||||||
BEGIN
|
BEGIN
|
||||||
|
@ -2258,6 +2258,10 @@ void Notepad_plus::command(int id)
|
|||||||
autoCompFromCurrentFile();
|
autoCompFromCurrentFile();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IDM_EDIT_AUTOCOMPLETE_PATH :
|
||||||
|
showPathCompletion();
|
||||||
|
break;
|
||||||
|
|
||||||
case IDM_EDIT_FUNCCALLTIP :
|
case IDM_EDIT_FUNCCALLTIP :
|
||||||
showFunctionComp();
|
showFunctionComp();
|
||||||
break;
|
break;
|
||||||
|
@ -118,6 +118,7 @@ WinMenuKeyDefinition winKeyDefs[] = {
|
|||||||
{VK_K, IDM_EDIT_BLOCK_UNCOMMENT, true, false, true, NULL},
|
{VK_K, IDM_EDIT_BLOCK_UNCOMMENT, true, false, true, NULL},
|
||||||
{VK_Q, IDM_EDIT_STREAM_COMMENT, 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, 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_RETURN, IDM_EDIT_AUTOCOMPLETE_CURRENTFILE, true, false, false, NULL},
|
||||||
{VK_SPACE, IDM_EDIT_FUNCCALLTIP, true, false, true, NULL},
|
{VK_SPACE, IDM_EDIT_FUNCCALLTIP, true, false, true, NULL},
|
||||||
{VK_R, IDM_EDIT_RTL, true, true, false, NULL},
|
{VK_R, IDM_EDIT_RTL, true, true, false, NULL},
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "AutoCompletion.h"
|
#include "AutoCompletion.h"
|
||||||
#include "Notepad_plus_msgs.h"
|
#include "Notepad_plus_msgs.h"
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
static bool isInList(generic_string word, const vector<generic_string> & wordArray)
|
static bool isInList(generic_string word, const vector<generic_string> & wordArray)
|
||||||
{
|
{
|
||||||
@ -76,6 +77,163 @@ bool AutoCompletion::showAutoComplete() {
|
|||||||
return true;
|
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)
|
bool AutoCompletion::showWordComplete(bool autoInsert)
|
||||||
{
|
{
|
||||||
int curPos = int(_pEditView->execute(SCI_GETCURRENTPOS));
|
int curPos = int(_pEditView->execute(SCI_GETCURRENTPOS));
|
||||||
|
@ -41,7 +41,7 @@ class ScintillaEditView;
|
|||||||
|
|
||||||
class AutoCompletion {
|
class AutoCompletion {
|
||||||
public:
|
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),
|
AutoCompletion(ScintillaEditView * pEditView) : _funcCompletionActive(false), _pEditView(pEditView), _funcCalltip(pEditView),
|
||||||
_curLang(L_TEXT), _pXmlFile(NULL), _activeCompletion(CompletionNone),
|
_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
|
bool showWordComplete(bool autoInsert); //autoInsert true if completion should fill in the word on a single match
|
||||||
//Parameter display from the list
|
//Parameter display from the list
|
||||||
bool showFunctionComplete();
|
bool showFunctionComplete();
|
||||||
|
// Autocomplete from path.
|
||||||
|
void showPathCompletion();
|
||||||
|
|
||||||
void insertMatchedChars(int character, const MatchedPairConf & matchedPairConf);
|
void insertMatchedChars(int character, const MatchedPairConf & matchedPairConf);
|
||||||
void update(int character);
|
void update(int character);
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
#define IDM_EDIT_AUTOCOMPLETE (50000 + 0)
|
#define IDM_EDIT_AUTOCOMPLETE (50000 + 0)
|
||||||
#define IDM_EDIT_AUTOCOMPLETE_CURRENTFILE (50000 + 1)
|
#define IDM_EDIT_AUTOCOMPLETE_CURRENTFILE (50000 + 1)
|
||||||
#define IDM_EDIT_FUNCCALLTIP (50000 + 2)
|
#define IDM_EDIT_FUNCCALLTIP (50000 + 2)
|
||||||
|
#define IDM_EDIT_AUTOCOMPLETE_PATH (50000 + 6)
|
||||||
|
|
||||||
//Belong to MENU FILE
|
//Belong to MENU FILE
|
||||||
#define IDM_OPEN_ALL_RECENT_FILE (IDM_EDIT + 40)
|
#define IDM_OPEN_ALL_RECENT_FILE (IDM_EDIT + 40)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user