Make external language library work again after upgrading to Scintilla5

Make external lexer library work again after upgrading to Scintilla5.
Old external lexer libraries needs to add CreateLexer export function which returns ILexer5 instance (Lexilla protocol interface of Scintilla5).

Tested with papyrus lexer plugin, this external lexer plugin is compatible with Notepad++ next release:
https://github.com/blu3mania/npp-papyrus

Close #11468
This commit is contained in:
Don Ho 2022-04-03 03:52:51 +02:00
parent 252468c29b
commit 121a396bf0
8 changed files with 77 additions and 52 deletions

View File

@ -22,6 +22,8 @@
#include "PluginsManager.h" #include "PluginsManager.h"
#include "resource.h" #include "resource.h"
#include "pluginsAdmin.h" #include "pluginsAdmin.h"
#include "ILexer.h"
#include "Lexilla.h"
using namespace std; using namespace std;
@ -169,40 +171,58 @@ int PluginsManager::loadPlugin(const TCHAR *pluginFilePath)
pi->_pluginMenu = ::CreateMenu(); pi->_pluginMenu = ::CreateMenu();
GetLexerCountFn GetLexerCount = (GetLexerCountFn)::GetProcAddress(pi->_hLib, "GetLexerCount"); Lexilla::GetLexerCountFn GetLexerCount = (Lexilla::GetLexerCountFn)::GetProcAddress(pi->_hLib, LEXILLA_GETLEXERCOUNT);
// it's a lexer plugin // it's a lexer plugin
if (GetLexerCount) if (GetLexerCount)
{ {
GetLexerNameFn GetLexerName = (GetLexerNameFn)::GetProcAddress(pi->_hLib, "GetLexerName"); Lexilla::GetLexerNameFn GetLexerName = (Lexilla::GetLexerNameFn)::GetProcAddress(pi->_hLib, LEXILLA_GETLEXERNAME);
if (!GetLexerName) if (!GetLexerName)
throw generic_string(TEXT("Loading GetLexerName function failed.")); throw generic_string(TEXT("Loading GetLexerName function failed."));
GetLexerStatusTextFn GetLexerStatusText = (GetLexerStatusTextFn)::GetProcAddress(pi->_hLib, "GetLexerStatusText"); //Lexilla::GetLexerFactoryFn GetLexerFactory = (Lexilla::GetLexerFactoryFn)::GetProcAddress(pi->_hLib, LEXILLA_GETLEXERFACTORY);
//if (!GetLexerFactory)
//throw generic_string(TEXT("Loading GetLexerFactory function failed."));
if (!GetLexerStatusText) Lexilla::CreateLexerFn CreateLexer = (Lexilla::CreateLexerFn)::GetProcAddress(pi->_hLib, LEXILLA_CREATELEXER);
throw generic_string(TEXT("Loading GetLexerStatusText function failed.")); if (!CreateLexer)
throw generic_string(TEXT("Loading CreateLexer function failed."));
//Lexilla::GetLibraryPropertyNamesFn GetLibraryPropertyNames = (Lexilla::GetLibraryPropertyNamesFn)::GetProcAddress(pi->_hLib, LEXILLA_GETLIBRARYPROPERTYNAMES);
//if (!GetLibraryPropertyNames)
//throw generic_string(TEXT("Loading GetLibraryPropertyNames function failed."));
//Lexilla::SetLibraryPropertyFn SetLibraryProperty = (Lexilla::SetLibraryPropertyFn)::GetProcAddress(pi->_hLib, LEXILLA_SETLIBRARYPROPERTY);
//if (!SetLibraryProperty)
//throw generic_string(TEXT("Loading SetLibraryProperty function failed."));
//Lexilla::GetNameSpaceFn GetNameSpace = (Lexilla::GetNameSpaceFn)::GetProcAddress(pi->_hLib, LEXILLA_GETNAMESPACE);
//if (!GetNameSpace)
//throw generic_string(TEXT("Loading GetNameSpace function failed."));
// Assign a buffer for the lexer name. // Assign a buffer for the lexer name.
char lexName[MAX_EXTERNAL_LEXER_NAME_LEN]; char lexName[MAX_EXTERNAL_LEXER_NAME_LEN];
lexName[0] = '\0'; lexName[0] = '\0';
TCHAR lexDesc[MAX_EXTERNAL_LEXER_DESC_LEN];
lexDesc[0] = '\0';
int numLexers = GetLexerCount(); int numLexers = GetLexerCount();
ExternalLangContainer* containers[30]; ExternalLangContainer* containers[30];
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
for (int x = 0; x < numLexers; ++x) for (int x = 0; x < numLexers; ++x)
{ {
GetLexerName(x, lexName, MAX_EXTERNAL_LEXER_NAME_LEN); GetLexerName(x, lexName, MAX_EXTERNAL_LEXER_NAME_LEN);
GetLexerStatusText(x, lexDesc, MAX_EXTERNAL_LEXER_DESC_LEN); if (!nppParams.isExistingExternalLangName(lexName) && nppParams.ExternalLangHasRoom())
const TCHAR *pLexerName = wmc.char2wchar(lexName, CP_ACP); {
if (!nppParams.isExistingExternalLangName(pLexerName) && nppParams.ExternalLangHasRoom()) containers[x] = new ExternalLangContainer;
containers[x] = new ExternalLangContainer(pLexerName, lexDesc); containers[x]->_name = lexName;
containers[x]->fnCL = CreateLexer;
//containers[x]->fnGLPN = GetLibraryPropertyNames;
//containers[x]->fnSLP = SetLibraryProperty;
}
else else
{
containers[x] = NULL; containers[x] = NULL;
} }
}
TCHAR xmlPath[MAX_PATH]; TCHAR xmlPath[MAX_PATH];
wcscpy_s(xmlPath, nppParams.getNppPath().c_str()); wcscpy_s(xmlPath, nppParams.getNppPath().c_str());
@ -243,9 +263,12 @@ int PluginsManager::loadPlugin(const TCHAR *pluginFilePath)
nppParams.getExternalLexerFromXmlTree(pXmlDoc); nppParams.getExternalLexerFromXmlTree(pXmlDoc);
nppParams.getExternalLexerDoc()->push_back(pXmlDoc); nppParams.getExternalLexerDoc()->push_back(pXmlDoc);
//const char *pDllName = wmc.wchar2char(pluginFilePath, CP_ACP); //const char *pDllName = wmc.wchar2char(pluginFilePath, CP_ACP);
//::SendMessage(_nppData._scintillaMainHandle, SCI_LOADLEXERLIBRARY, 0, reinterpret_cast<LPARAM>(pDllName)); //::SendMessage(_nppData._scintillaMainHandle, SCI_LOADLEXERLIBRARY, 0, reinterpret_cast<LPARAM>(pDllName));
} }
addInLoadedDlls(pluginFilePath, pluginFileName); addInLoadedDlls(pluginFilePath, pluginFileName);
_pluginInfos.push_back(pi); _pluginInfos.push_back(pi);

View File

@ -157,10 +157,3 @@ private:
_loadedDlls.push_back(LoadedDllInfo(fullPath, fn)); _loadedDlls.push_back(LoadedDllInfo(fullPath, fn));
} }
}; };
#define EXT_LEXER_DECL __stdcall
// External Lexer function definitions...
typedef int (EXT_LEXER_DECL *GetLexerCountFn)();
typedef void (EXT_LEXER_DECL *GetLexerNameFn)(unsigned int Index, char *name, int buflength);
typedef void (EXT_LEXER_DECL *GetLexerStatusTextFn)(unsigned int Index, TCHAR *desc, int buflength);

View File

@ -467,6 +467,7 @@ LRESULT Notepad_plus::init(HWND hwnd)
//Languages Menu //Languages Menu
HMENU hLangMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_LANGUAGE); HMENU hLangMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_LANGUAGE);
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
// Add external languages to menu // Add external languages to menu
for (int i = 0; i < nppParam.getNbExternalLang(); ++i) for (int i = 0; i < nppParam.getNbExternalLang(); ++i)
{ {
@ -475,14 +476,15 @@ LRESULT Notepad_plus::init(HWND hwnd)
int numLangs = ::GetMenuItemCount(hLangMenu); int numLangs = ::GetMenuItemCount(hLangMenu);
const int bufferSize = 100; const int bufferSize = 100;
TCHAR buffer[bufferSize]; TCHAR buffer[bufferSize];
const TCHAR* lexerNameW = wmc.char2wchar(externalLangContainer._name.c_str(), CP_ACP);
int x; int x = 0;
for (x = 0; (x == 0 || lstrcmp(externalLangContainer._name, buffer) > 0) && x < numLangs; ++x) for (; (x == 0 || lstrcmp(lexerNameW, buffer) > 0) && x < numLangs; ++x)
{ {
::GetMenuString(hLangMenu, x, buffer, bufferSize, MF_BYPOSITION); ::GetMenuString(hLangMenu, x, buffer, bufferSize, MF_BYPOSITION);
} }
::InsertMenu(hLangMenu, x - 1, MF_BYPOSITION, IDM_LANG_EXTERNAL + i, externalLangContainer._name); ::InsertMenu(hLangMenu, x - 1, MF_BYPOSITION, IDM_LANG_EXTERNAL + i, lexerNameW);
} }
if (nppGUI._excludedLangList.size() > 0) if (nppGUI._excludedLangList.size() > 0)
@ -2363,10 +2365,9 @@ generic_string Notepad_plus::getLangDesc(LangType langType, bool getName)
if ((langType >= L_EXTERNAL) && (langType < nppParams.L_END)) if ((langType >= L_EXTERNAL) && (langType < nppParams.L_END))
{ {
ExternalLangContainer & elc = nppParams.getELCFromIndex(langType - L_EXTERNAL); ExternalLangContainer & elc = nppParams.getELCFromIndex(langType - L_EXTERNAL);
if (getName) WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
return generic_string(elc._name); const TCHAR* lexerNameW = wmc.char2wchar(elc._name.c_str(), CP_ACP);
else return generic_string(lexerNameW);
return generic_string(elc._desc);
} }
if (langType > L_EXTERNAL) if (langType > L_EXTERNAL)

View File

@ -1591,14 +1591,14 @@ void NppParameters::SetTransparent(HWND hwnd, int percent)
} }
bool NppParameters::isExistingExternalLangName(const TCHAR *newName) const bool NppParameters::isExistingExternalLangName(const char* newName) const
{ {
if ((!newName) || (!newName[0])) if ((!newName) || (!newName[0]))
return true; return true;
for (int i = 0 ; i < _nbExternalLang ; ++i) for (int i = 0 ; i < _nbExternalLang ; ++i)
{ {
if (!lstrcmp(_externalLangArray[i]->_name, newName)) if (_externalLangArray[i]->_name == newName)
return true; return true;
} }
return false; return false;
@ -1645,9 +1645,10 @@ const TCHAR* NppParameters::getUserDefinedLangNameFromExt(TCHAR *ext, TCHAR *ful
int NppParameters::getExternalLangIndexFromName(const TCHAR* externalLangName) const int NppParameters::getExternalLangIndexFromName(const TCHAR* externalLangName) const
{ {
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
for (int i = 0 ; i < _nbExternalLang ; ++i) for (int i = 0 ; i < _nbExternalLang ; ++i)
{ {
if (!lstrcmp(externalLangName, _externalLangArray[i]->_name)) if (!lstrcmp(externalLangName, wmc.char2wchar(_externalLangArray[i]->_name.c_str(), CP_ACP)))
return i; return i;
} }
return -1; return -1;

View File

@ -30,6 +30,8 @@
#include <assert.h> #include <assert.h>
#include <tchar.h> #include <tchar.h>
#include <map> #include <map>
#include "ILexer.h"
#include "Lexilla.h"
#ifdef _WIN64 #ifdef _WIN64
@ -1072,23 +1074,21 @@ private:
friend class StylerDlg; friend class StylerDlg;
}; };
#define MAX_EXTERNAL_LEXER_NAME_LEN 16 #define MAX_EXTERNAL_LEXER_NAME_LEN 128
#define MAX_EXTERNAL_LEXER_DESC_LEN 32
class ExternalLangContainer final class ExternalLangContainer final
{ {
public: public:
TCHAR _name[MAX_EXTERNAL_LEXER_NAME_LEN]; // Mandatory for Lexilla
TCHAR _desc[MAX_EXTERNAL_LEXER_DESC_LEN]; std::string _name;
ExternalLexerAutoIndentMode _autoIndentMode = ExternalLexerAutoIndentMode::Standard; Lexilla::CreateLexerFn fnCL = nullptr;
//Lexilla::GetLibraryPropertyNamesFn fnGLPN = nullptr;
//Lexilla::SetLibraryPropertyFn fnSLP = nullptr;
ExternalLangContainer(const TCHAR* name, const TCHAR* desc) // For Notepad++
{ ExternalLexerAutoIndentMode _autoIndentMode = ExternalLexerAutoIndentMode::Standard;
generic_strncpy(_name, name, MAX_EXTERNAL_LEXER_NAME_LEN);
generic_strncpy(_desc, desc, MAX_EXTERNAL_LEXER_DESC_LEN);
}
}; };
@ -1437,7 +1437,7 @@ public:
int addUserLangToEnd(const UserLangContainer & userLang, const TCHAR *newName); int addUserLangToEnd(const UserLangContainer & userLang, const TCHAR *newName);
void removeUserLang(size_t index); void removeUserLang(size_t index);
bool isExistingExternalLangName(const TCHAR *newName) const; bool isExistingExternalLangName(const char* newName) const;
int addExternalLangToEnd(ExternalLangContainer * externalLang); int addExternalLangToEnd(ExternalLangContainer * externalLang);

View File

@ -1066,7 +1066,10 @@ const TCHAR * AutoCompletion::getApiFileName()
} }
if (_curLang >= L_EXTERNAL && _curLang < NppParameters::getInstance().L_END) if (_curLang >= L_EXTERNAL && _curLang < NppParameters::getInstance().L_END)
return NppParameters::getInstance().getELCFromIndex(_curLang - L_EXTERNAL)._name; {
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
return wmc.char2wchar(NppParameters::getInstance().getELCFromIndex(_curLang - L_EXTERNAL)._name.c_str(), CP_ACP);
}
if (_curLang > L_EXTERNAL) if (_curLang > L_EXTERNAL)
_curLang = L_TEXT; _curLang = L_TEXT;

View File

@ -1456,10 +1456,10 @@ bool FileManager::loadFileData(Document doc, int64_t fileSize, const TCHAR * fil
else else
{ {
int id = fileFormat._language - L_EXTERNAL; int id = fileFormat._language - L_EXTERNAL;
TCHAR * name = nppParam.getELCFromIndex(id)._name; ExternalLangContainer& externalLexer = nppParam.getELCFromIndex(id);
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); const char* lexerName = externalLexer._name.c_str();
const char *pName = wmc.wchar2char(name, CP_ACP); if (externalLexer.fnCL)
_pscratchTilla->execute(SCI_SETILEXER, 0, reinterpret_cast<LPARAM>(CreateLexer(pName))); _pscratchTilla->execute(SCI_SETILEXER, 0, reinterpret_cast<LPARAM>(externalLexer.fnCL(lexerName)));
} }
if (fileFormat._encoding != -1) if (fileFormat._encoding != -1)

View File

@ -880,14 +880,18 @@ void ScintillaEditView::setUserLexer(const TCHAR *userLangName)
void ScintillaEditView::setExternalLexer(LangType typeDoc) void ScintillaEditView::setExternalLexer(LangType typeDoc)
{ {
int id = typeDoc - L_EXTERNAL; int id = typeDoc - L_EXTERNAL;
TCHAR * name = NppParameters::getInstance().getELCFromIndex(id)._name;
ExternalLangContainer& externalLexer = NppParameters::getInstance().getELCFromIndex(id);
if (!externalLexer.fnCL)
return;
ILexer5* iLex5 = externalLexer.fnCL(externalLexer._name.c_str());
if (!iLex5)
return;
execute(SCI_SETILEXER, 0, reinterpret_cast<LPARAM>(iLex5));
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance(); WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
const char *pName = wmc.wchar2char(name, CP_ACP); const wchar_t* lexerNameW = wmc.char2wchar(externalLexer._name.c_str(), CP_ACP);
LexerStyler *pStyler = (NppParameters::getInstance().getLStylerArray()).getLexerStylerByName(lexerNameW);
execute(SCI_SETILEXER, 0, reinterpret_cast<LPARAM>(CreateLexer(pName)));
LexerStyler *pStyler = (NppParameters::getInstance().getLStylerArray()).getLexerStylerByName(name);
if (pStyler) if (pStyler)
{ {
for (const Style & style : *pStyler) for (const Style & style : *pStyler)