Skip to content

Commit

Permalink
Add namespace feature with GetNameSpace function.
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamatongwe committed Apr 25, 2021
1 parent f460bdb commit e4817a1
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 46 deletions.
116 changes: 73 additions & 43 deletions access/LexillaAccess.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,18 @@ std::wstring WideStringFromUTF8(std::string_view sv) {

std::string directoryLoadDefault;
std::string lastLoaded;
std::vector<Lexilla::CreateLexerFn> fnCLs;
std::vector<Lexilla::LexerNameFromIDFn> fnLNFIs;
std::vector<Lexilla::GetLibraryPropertyNamesFn> fnGLPNs;

struct LexLibrary {
Lexilla::CreateLexerFn fnCL;
Lexilla::LexerNameFromIDFn fnLNFI;
Lexilla::GetLibraryPropertyNamesFn fnGLPN;
Lexilla::SetLibraryPropertyFn fnSLP;
std::string nameSpace;
};
std::vector<LexLibrary> libraries;

std::vector<std::string> lexers;
std::vector<std::string> libraryProperties;
std::vector<Lexilla::SetLibraryPropertyFn> fnSLPs;

Function FindSymbol(Module m, const char *symbol) noexcept {
#if _WIN32
Expand All @@ -99,6 +105,10 @@ bool NameContainsDot(std::string_view path) noexcept {
return false;
}

constexpr bool HasPrefix(std::string_view s, std::string_view prefix) noexcept {
return (s.size() >= prefix.size()) && (prefix == s.substr(0, prefix.size()));
}

}

void Lexilla::SetDefault(CreateLexerFn pCreate) noexcept {
Expand All @@ -111,16 +121,13 @@ void Lexilla::SetDefaultDirectory(std::string_view directory) {

bool Lexilla::Load(std::string_view sharedLibraryPaths) {
if (sharedLibraryPaths == lastLoaded) {
return !fnCLs.empty();
return !libraries.empty();
}

std::string_view paths = sharedLibraryPaths;
lexers.clear();

fnCLs.clear();
fnLNFIs.clear();
fnGLPNs.clear();
fnSLPs.clear();
libraries.clear();
while (!paths.empty()) {
const size_t separator = paths.find_first_of(';');
std::string path(paths.substr(0, separator));
Expand Down Expand Up @@ -164,57 +171,76 @@ bool Lexilla::Load(std::string_view sharedLibraryPaths) {
}
CreateLexerFn fnCL = FunctionPointer<CreateLexerFn>(
FindSymbol(lexillaDL, LEXILLA_CREATELEXER));
if (fnCL) {
fnCLs.push_back(fnCL);
}
LexerNameFromIDFn fnLNFI = FunctionPointer<LexerNameFromIDFn>(
FindSymbol(lexillaDL, LEXILLA_LEXERNAMEFROMID));
if (fnLNFI) {
fnLNFIs.push_back(fnLNFI);
}
GetLibraryPropertyNamesFn fnGLPN = FunctionPointer<GetLibraryPropertyNamesFn>(
FindSymbol(lexillaDL, LEXILLA_GETLIBRARYPROPERTYNAMES));
if (fnGLPN) {
fnGLPNs.push_back(fnGLPN);
}
SetLibraryPropertyFn fnSLP = FunctionPointer<SetLibraryPropertyFn>(
FindSymbol(lexillaDL, LEXILLA_SETLIBRARYPROPERTY));
if (fnSLP) {
fnSLPs.push_back(fnSLP);
GetNameSpaceFn fnGNS = FunctionPointer<GetNameSpaceFn>(
FindSymbol(lexillaDL, LEXILLA_GETNAMESPACE));
std::string nameSpace;
if (fnGNS) {
nameSpace = fnGNS();
nameSpace += LEXILLA_NAMESPACE_SEPARATOR;
}
LexLibrary lexLib {
fnCL,
fnLNFI,
fnGLPN,
fnSLP,
nameSpace
};
libraries.push_back(lexLib);
}
}
lastLoaded = sharedLibraryPaths;

std::set<std::string> nameSet;
for (GetLibraryPropertyNamesFn fnGLPN : fnGLPNs) {
const char *cpNames = fnGLPN();
if (cpNames) {
std::string_view names = cpNames;
while (!names.empty()) {
const size_t separator = names.find_first_of('\n');
std::string name(names.substr(0, separator));
nameSet.insert(name);
if (separator == std::string::npos) {
names.remove_prefix(names.size());
} else {
names.remove_prefix(separator + 1);
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnGLPN) {
const char *cpNames = lexLib.fnGLPN();
if (cpNames) {
std::string_view names = cpNames;
while (!names.empty()) {
const size_t separator = names.find_first_of('\n');
std::string name(names.substr(0, separator));
nameSet.insert(name);
if (separator == std::string::npos) {
names.remove_prefix(names.size());
} else {
names.remove_prefix(separator + 1);
}
}
}
}
}
// Standard Lexilla does not have any properties so can't be added to set.
libraryProperties = std::vector<std::string>(nameSet.begin(), nameSet.end());

return !fnCLs.empty();
return !libraries.empty();
}

Scintilla::ILexer5 *Lexilla::MakeLexer(std::string_view languageName) {
std::string sLanguageName(languageName); // Ensure NUL-termination
for (CreateLexerFn fnCL : fnCLs) {
Scintilla::ILexer5 *pLexer = fnCL(sLanguageName.c_str());
if (pLexer) {
return pLexer;
// First, try to match namespace then name suffix
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnCL && !lexLib.nameSpace.empty()) {
if (HasPrefix(languageName, lexLib.nameSpace)) {
Scintilla::ILexer5 *pLexer = lexLib.fnCL(sLanguageName.substr(lexLib.nameSpace.size()).c_str());
if (pLexer) {
return pLexer;
}
}
}
}
// If no match with namespace, try to just match name
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnCL) {
Scintilla::ILexer5 *pLexer = lexLib.fnCL(sLanguageName.c_str());
if (pLexer) {
return pLexer;
}
}
}
if (pCreateLexerDefault) {
Expand All @@ -234,10 +260,12 @@ std::vector<std::string> Lexilla::Lexers() {
}

std::string Lexilla::NameFromID(int identifier) {
for (Lexilla::LexerNameFromIDFn fnLNFI : fnLNFIs) {
const char *name = fnLNFI(identifier);
if (name) {
return name;
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnLNFI) {
const char *name = lexLib.fnLNFI(identifier);
if (name) {
return name;
}
}
}
return std::string();
Expand All @@ -248,8 +276,10 @@ std::vector<std::string> Lexilla::LibraryProperties() {
}

void Lexilla::SetProperty(const char *key, const char *value) {
for (SetLibraryPropertyFn fnSLP : fnSLPs) {
fnSLP(key, value);
for (const LexLibrary &lexLib : libraries) {
if (lexLib.fnSLP) {
lexLib.fnSLP(key, value);
}
}
// Standard Lexilla does not have any properties so don't set.
}
12 changes: 9 additions & 3 deletions doc/LexillaDoc.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

<h1>Lexilla Documentation</h1>

<p>Last edited 5 March 2021 NH</p>
<p>Last edited 21 April 2021 NH</p>

<h2>Introduction</h2>

Expand All @@ -95,8 +95,9 @@ <h2>The Lexilla protocol</h2>
<code>LexerFactoryFunction <span class="name">GetLexerFactory</span>(unsigned int index)</code><br />
<code>ILexer5 *<span class="name">CreateLexer</span>(const char *name)</code><br />
<code>const char *<span class="name">LexerNameFromID</span>(int identifier)</code><br />
<code>const char *<span class="name">GetLibraryPropertyNames</span>()</code><br />
<code>void <span class="name">SetLibraryProperty</span>(const char *key, const char *value)</code><br />
<code>const char *<span class="name">GetLibraryPropertyNames</span>()</code>
<code>const char *<span class="name">GetNameSpace</span>()</code>
</p>

<p><span class="name">ILexer5</span> is defined by Scintilla in include/ILexer.h as the interface provided by lexers which is called by Scintilla.
Expand All @@ -119,7 +120,7 @@ <h2>The Lexilla protocol</h2>
<a class="seealso" href="ScintillaDoc.html#SCI_SETILEXER">SCI_SETILEXER</a>.</p>

<p><span class="name">LexerNameFromID</span> is an optional function that returns the name for a lexer identifier.
<code>LexerNameFromID(SCLEX_CPP) -> "cpp"</code>.
<code>LexerNameFromID(SCLEX_CPP) &rarr; "cpp"</code>.
This is a temporary affordance to make it easier to convert applications to using Lexilla.
Applications should move to using lexer names instead of IDs.
This function is deprecated, showing warnings with some compilers, and will be removed in a future version of Lexilla.</p>
Expand All @@ -134,6 +135,11 @@ <h2>The Lexilla protocol</h2>
GetLibraryPropertyNames that can then be used by the application to define configuration file property
names or user interface elements for options dialogs.</p>

<p><span class="name">GetNameSpace</span> is an optional function that returns a namespace string
that can be used to disambiguate lexers with the same name from different providers.
If Lexilla and XMLLexers both provide a "cpp" lexer than a request for "cpp" may be satisfied by either but "xmllexers.cpp"
unambiguously refers to the "cpp" lexer from XMLLexers.</p>

<h2>Building Lexilla</h2>

<p>Before using Lexilla it must be built or downloaded.</p>
Expand Down
8 changes: 8 additions & 0 deletions examples/CheckLexilla/CheckLexilla.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ int main(int argc, char *argv[]) {
} else {
printf("Set property not supported.\n");
}

GetNameSpaceFn libraryNameSpace = (GetLibraryPropertyNamesFn)FindSymbol(lexillaLibrary, LEXILLA_GETNAMESPACE);
if (libraryNameSpace) {
const char *nameSpace = libraryNameSpace();
printf("Name space '%s'.\n", nameSpace);
} else {
printf("Name space not supported.\n");
}
}
}
}
4 changes: 4 additions & 0 deletions examples/SimpleLexer/SimpleLexer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ EXPORT_FUNCTION Scintilla::ILexer5* CALLING_CONVENTION CreateLexer(const char *n
return nullptr;
}

EXPORT_FUNCTION const char * CALLING_CONVENTION GetNameSpace() {
return "example";
}

}
5 changes: 5 additions & 0 deletions include/Lexilla.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,22 @@ typedef ILexer5*(LEXILLA_CALL *CreateLexerFn)(const char *name);
DEPRECATE_DEFINITION typedef const char *(LEXILLA_CALL *LexerNameFromIDFn)(int identifier);
typedef const char *(LEXILLA_CALL *GetLibraryPropertyNamesFn)();
typedef void(LEXILLA_CALL *SetLibraryPropertyFn)(const char *key, const char *value);
typedef const char *(LEXILLA_CALL *GetNameSpaceFn)();

#ifdef __cplusplus
}
#endif

#define LEXILLA_NAMESPACE_SEPARATOR '.'

#define LEXILLA_GETLEXERCOUNT "GetLexerCount"
#define LEXILLA_GETLEXERNAME "GetLexerName"
#define LEXILLA_GETLEXERFACTORY "GetLexerFactory"
#define LEXILLA_CREATELEXER "CreateLexer"
#define LEXILLA_LEXERNAMEFROMID "LexerNameFromID"
#define LEXILLA_GETLIBRARYPROPERTYNAMES "GetLibraryPropertyNames"
#define LEXILLA_SETLIBRARYPROPERTY "SetLibraryProperty"
#define LEXILLA_GETNAMESPACE "GetNameSpace"

// Static linking prototypes

Expand All @@ -87,6 +91,7 @@ LexerFactoryFunction LEXILLA_CALL GetLexerFactory(unsigned int index);
DEPRECATE_DEFINITION const char *LEXILLA_CALL LexerNameFromID(int identifier);
const char * LEXILLA_CALL GetLibraryPropertyNames();
void LEXILLA_CALL SetLibraryProperty(const char *key, const char *value);
const char *LEXILLA_CALL GetNameSpace();

#ifdef __cplusplus
}
Expand Down
4 changes: 4 additions & 0 deletions src/Lexilla.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,8 @@ EXPORT_FUNCTION void CALLING_CONVENTION SetLibraryProperty(const char *, const c
// Null implementation
}

EXPORT_FUNCTION const char * CALLING_CONVENTION GetNameSpace() {
return "lexilla";
}

}
1 change: 1 addition & 0 deletions src/Lexilla.def
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ EXPORTS
CreateLexer
GetLibraryPropertyNames
SetLibraryProperty
GetNameSpace

0 comments on commit e4817a1

Please sign in to comment.