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 "resource.h"
#include "pluginsAdmin.h"
#include "ILexer.h"
#include "Lexilla.h"
using namespace std;
@ -169,39 +171,57 @@ int PluginsManager::loadPlugin(const TCHAR *pluginFilePath)
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
if (GetLexerCount)
{
GetLexerNameFn GetLexerName = (GetLexerNameFn)::GetProcAddress(pi->_hLib, "GetLexerName");
Lexilla::GetLexerNameFn GetLexerName = (Lexilla::GetLexerNameFn)::GetProcAddress(pi->_hLib, LEXILLA_GETLEXERNAME);
if (!GetLexerName)
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)
throw generic_string(TEXT("Loading GetLexerStatusText function failed."));
Lexilla::CreateLexerFn CreateLexer = (Lexilla::CreateLexerFn)::GetProcAddress(pi->_hLib, LEXILLA_CREATELEXER);
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.
char lexName[MAX_EXTERNAL_LEXER_NAME_LEN];
lexName[0] = '\0';
TCHAR lexDesc[MAX_EXTERNAL_LEXER_DESC_LEN];
lexDesc[0] = '\0';
int numLexers = GetLexerCount();
ExternalLangContainer *containers[30];
ExternalLangContainer* containers[30];
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
for (int x = 0; x < numLexers; ++x)
{
GetLexerName(x, lexName, MAX_EXTERNAL_LEXER_NAME_LEN);
GetLexerStatusText(x, lexDesc, MAX_EXTERNAL_LEXER_DESC_LEN);
const TCHAR *pLexerName = wmc.char2wchar(lexName, CP_ACP);
if (!nppParams.isExistingExternalLangName(pLexerName) && nppParams.ExternalLangHasRoom())
containers[x] = new ExternalLangContainer(pLexerName, lexDesc);
if (!nppParams.isExistingExternalLangName(lexName) && nppParams.ExternalLangHasRoom())
{
containers[x] = new ExternalLangContainer;
containers[x]->_name = lexName;
containers[x]->fnCL = CreateLexer;
//containers[x]->fnGLPN = GetLibraryPropertyNames;
//containers[x]->fnSLP = SetLibraryProperty;
}
else
{
containers[x] = NULL;
}
}
TCHAR xmlPath[MAX_PATH];
@ -243,9 +263,12 @@ int PluginsManager::loadPlugin(const TCHAR *pluginFilePath)
nppParams.getExternalLexerFromXmlTree(pXmlDoc);
nppParams.getExternalLexerDoc()->push_back(pXmlDoc);
//const char *pDllName = wmc.wchar2char(pluginFilePath, CP_ACP);
//::SendMessage(_nppData._scintillaMainHandle, SCI_LOADLEXERLIBRARY, 0, reinterpret_cast<LPARAM>(pDllName));
}
addInLoadedDlls(pluginFilePath, pluginFileName);
_pluginInfos.push_back(pi);

View File

@ -157,10 +157,3 @@ private:
_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
HMENU hLangMenu = ::GetSubMenu(_mainMenuHandle, MENUINDEX_LANGUAGE);
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
// Add external languages to menu
for (int i = 0; i < nppParam.getNbExternalLang(); ++i)
{
@ -475,14 +476,15 @@ LRESULT Notepad_plus::init(HWND hwnd)
int numLangs = ::GetMenuItemCount(hLangMenu);
const int bufferSize = 100;
TCHAR buffer[bufferSize];
const TCHAR* lexerNameW = wmc.char2wchar(externalLangContainer._name.c_str(), CP_ACP);
int x;
for (x = 0; (x == 0 || lstrcmp(externalLangContainer._name, buffer) > 0) && x < numLangs; ++x)
int x = 0;
for (; (x == 0 || lstrcmp(lexerNameW, buffer) > 0) && x < numLangs; ++x)
{
::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)
@ -2363,10 +2365,9 @@ generic_string Notepad_plus::getLangDesc(LangType langType, bool getName)
if ((langType >= L_EXTERNAL) && (langType < nppParams.L_END))
{
ExternalLangContainer & elc = nppParams.getELCFromIndex(langType - L_EXTERNAL);
if (getName)
return generic_string(elc._name);
else
return generic_string(elc._desc);
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
const TCHAR* lexerNameW = wmc.char2wchar(elc._name.c_str(), CP_ACP);
return generic_string(lexerNameW);
}
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]))
return true;
for (int i = 0 ; i < _nbExternalLang ; ++i)
{
if (!lstrcmp(_externalLangArray[i]->_name, newName))
if (_externalLangArray[i]->_name == newName)
return true;
}
return false;
@ -1645,9 +1645,10 @@ const TCHAR* NppParameters::getUserDefinedLangNameFromExt(TCHAR *ext, TCHAR *ful
int NppParameters::getExternalLangIndexFromName(const TCHAR* externalLangName) const
{
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
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 -1;

View File

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

View File

@ -1066,7 +1066,10 @@ const TCHAR * AutoCompletion::getApiFileName()
}
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)
_curLang = L_TEXT;

View File

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

View File

@ -880,14 +880,18 @@ void ScintillaEditView::setUserLexer(const TCHAR *userLangName)
void ScintillaEditView::setExternalLexer(LangType typeDoc)
{
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();
const char *pName = wmc.wchar2char(name, CP_ACP);
execute(SCI_SETILEXER, 0, reinterpret_cast<LPARAM>(CreateLexer(pName)));
LexerStyler *pStyler = (NppParameters::getInstance().getLStylerArray()).getLexerStylerByName(name);
const wchar_t* lexerNameW = wmc.char2wchar(externalLexer._name.c_str(), CP_ACP);
LexerStyler *pStyler = (NppParameters::getInstance().getLStylerArray()).getLexerStylerByName(lexerNameW);
if (pStyler)
{
for (const Style & style : *pStyler)