aboutsummaryrefslogtreecommitdiffhomepage
path: root/lexers/LexLPeg.cxx
diff options
context:
space:
mode:
authormitchell <unknown>2020-03-07 20:30:24 -0500
committermitchell <unknown>2020-03-07 20:30:24 -0500
commite02a7b49e160cbc00d763a979d99deb3b48a8488 (patch)
treeb3fb29d71384bf61f1afb9361bc65b5ec551ca02 /lexers/LexLPeg.cxx
parent07dc044091ae934afc6c8c8a48f954731c8a5133 (diff)
downloadscintilla-mirror-e02a7b49e160cbc00d763a979d99deb3b48a8488.tar.gz
LexLPeg can now report a list of known lexers via SCI_PRIVATELEXERCALL.
Diffstat (limited to 'lexers/LexLPeg.cxx')
-rw-r--r--lexers/LexLPeg.cxx146
1 files changed, 89 insertions, 57 deletions
diff --git a/lexers/LexLPeg.cxx b/lexers/LexLPeg.cxx
index 6d5167387..2d54e2547 100644
--- a/lexers/LexLPeg.cxx
+++ b/lexers/LexLPeg.cxx
@@ -17,8 +17,16 @@
#include <curses.h>
#endif
+#include <set>
+#include <sstream>
#include <vector>
+#if !_WIN32
+#include <dirent.h>
+#else
+#include <io.h>
+#endif
+
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
@@ -191,7 +199,7 @@ class LexerLPeg : public ILexer {
// Lexer property keys.
const char * const LexerErrorKey = "lexer.lpeg.error";
const char * const LexerHomeKey = "lexer.lpeg.home";
- const char * const LexerNameKey = "lexer.name";
+ const char * const LexerNameKey = "lexer.lpeg.name";
const char * const LexerThemeKey = "lexer.lpeg.color.theme";
/**
@@ -229,6 +237,34 @@ class LexerLPeg : public ILexer {
* determine which lexer grammar to use.
*/
bool ws[STYLE_MAX + 1];
+ /** List of known lexer names. */
+ std::set<std::string> lexer_names;
+
+ /**
+ * Searches the given directory for lexers and records their names.
+ * @param path Path to a directory containing lexers.
+ */
+ void ReadLexerNames(const char *path) {
+#if !_WIN32
+ DIR *dir = opendir(path);
+ if (!dir) return;
+ struct dirent *entry;
+ while ((entry = readdir(dir))) {
+ char *p = strstr(entry->d_name, ".lua");
+ if (p) lexer_names.emplace(entry->d_name, p - entry->d_name);
+ }
+ closedir(dir);
+#else
+ struct __finddata_t file;
+ intptr_t handle = _findfirst(path + "/*", &file); // TODO:
+ while (handle != -1) {
+ char *p = strstr(file.name, ".lua");
+ if (p) lexer_names.emplace(file.name, p - file.name);
+ handle = _findnext(handle, &file)
+ }
+ _findclose(handle);
+#endif
+ }
/**
* Logs the given error message or a Lua error message, prints it, and clears
@@ -238,7 +274,7 @@ class LexerLPeg : public ILexer {
* @param str The error message to log and print. If `nullptr`, logs and
* prints the Lua error message at the top of the stack.
*/
- void log_error(lua_State *L, const char *str = nullptr) {
+ void LogError(lua_State *L, const char *str = nullptr) {
const char *value = str ? str : lua_tostring(L, -1);
PropertySet(LexerErrorKey, value);
fprintf(stderr, "Lua Error: %s.\n", value);
@@ -417,9 +453,11 @@ class LexerLPeg : public ILexer {
if (!props.GetExpanded(LexerHomeKey, nullptr) ||
!*props.Get(LexerNameKey) || !L)
return false;
- char *home = reinterpret_cast<char *>(
+ char *_home = reinterpret_cast<char *>(
malloc(props.GetExpanded(LexerHomeKey, nullptr) + 1));
- props.GetExpanded(LexerHomeKey, home);
+ props.GetExpanded(LexerHomeKey, _home);
+ std::string home(_home);
+ free(_home);
const char *lexer = props.Get(LexerNameKey);
RECORD_STACK_TOP(L);
@@ -432,18 +470,19 @@ class LexerLPeg : public ILexer {
lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
// Determine where to look for the lexer module and themes.
- std::vector<char *> dirs;
- dirs.push_back(home);
- for (char *p = strstr(home, ";"); p; p = strstr(p, ";")) {
- *p++ = '\0';
- dirs.push_back(p);
+ std::vector<std::string> dirs;
+ size_t start = 0, end;
+ while ((end = home.find(';', start)) != std::string::npos) {
+ dirs.emplace_back(home, start, end - start);
+ start = end + 1;
}
+ dirs.emplace_back(home, start);
// If necessary, load the lexer module.
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
if (lua_getfield(L, -1, "lexer") == LUA_TNIL) {
- for (char *dir : dirs) {
- lua_pushstring(L, dir);
+ for (const std::string& dir : dirs) {
+ lua_pushstring(L, dir.c_str());
lua_pushstring(L, "/lexer.lua");
lua_concat(L, 2);
int status = luaL_loadfile(L, lua_tostring(L, -1));
@@ -455,7 +494,7 @@ class LexerLPeg : public ILexer {
lua_pushcfunction(L, lua_error_handler);
lua_insert(L, -2);
if (status == LUA_OK && lua_pcall(L, 0, 1, -2) == LUA_OK) break;
- return (free(home), log_error(L), false);
+ return (LogError(L), false);
}
lua_remove(L, -2); // lua_error_handler
lua_replace(L, -2); // nil
@@ -480,12 +519,10 @@ class LexerLPeg : public ILexer {
// Load the language lexer.
if (lua_getfield(L, -1, "load") != LUA_TFUNCTION)
- return (
- free(home), log_error(L, "'lexer.load' function not found"), false);
+ return (LogError(L, "'lexer.load' function not found"), false);
lua_pushcfunction(L, lua_error_handler), lua_insert(L, -2);
lua_pushstring(L, lexer), lua_pushnil(L), lua_pushboolean(L, 1);
- if (lua_pcall(L, 3, 1, -5) != LUA_OK)
- return (free(home), log_error(L), false);
+ if (lua_pcall(L, 3, 1, -5) != LUA_OK) return (LogError(L), false);
lua_remove(L, -2); // lua_error_handler
lua_remove(L, -2); // lexer module
lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
@@ -498,8 +535,8 @@ class LexerLPeg : public ILexer {
malloc(props.GetExpanded(LexerThemeKey, nullptr) + 1));
props.GetExpanded(LexerThemeKey, theme);
if (!strstr(theme, "/") && !strstr(theme, "\\")) { // theme name
- for (char *dir : dirs) {
- lua_pushstring(L, dir);
+ for (const std::string& dir : dirs) {
+ lua_pushstring(L, dir.c_str());
lua_pushstring(L, "/themes/");
lua_pushstring(L, theme);
lua_pushstring(L, ".lua");
@@ -518,7 +555,7 @@ class LexerLPeg : public ILexer {
lua_pcall(L, 0, 0, -3) == LUA_OK)
lua_pop(L, 2); // theme, lua_error_handler
else
- log_error(L);
+ LogError(L);
free(theme);
}
SetStyles();
@@ -540,7 +577,6 @@ class LexerLPeg : public ILexer {
reinit = false;
PropertySet(LexerErrorKey, "");
- free(home);
ASSERT_STACK_TOP(L);
return true;
}
@@ -658,14 +694,14 @@ public:
}
if (lua_getfield(L, -1, "lex") != LUA_TFUNCTION)
- return log_error(L, "'lexer.lex' function not found");
+ return LogError(L, "'lexer.lex' function not found");
lua_pushcfunction(L, lua_error_handler), lua_insert(L, -2);
lua_pushvalue(L, -3);
lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
lua_pushinteger(L, styler.StyleAt(startPos));
- if (lua_pcall(L, 3, 1, -5) != LUA_OK) return log_error(L);
+ if (lua_pcall(L, 3, 1, -5) != LUA_OK) return LogError(L);
if (!lua_istable(L, -1))
- return log_error(L, "Table of tokens expected from 'lexer.lex'");
+ return LogError(L, "Table of tokens expected from 'lexer.lex'");
// Style the text from the token table returned.
int len = lua_rawlen(L, -1);
if (len > 0) {
@@ -684,10 +720,8 @@ public:
lua_pop(L, 1); // pos
if (style >= 0 && style <= STYLE_MAX)
styler.ColourTo(startPos + position - 1, style);
- else {
- lua_pushfstring(L, "Bad style number: %d", style);
- log_error(L);
- }
+ else
+ lua_pushfstring(L, "Bad style number: %d", style), LogError(L);
if (position > startPos + lengthDoc) break;
}
lua_pop(L, 1); // _TOKENSTYLES
@@ -719,7 +753,7 @@ public:
LexAccessor styler(buffer);
if (lua_getfield(L, -1, "fold") != LUA_TFUNCTION)
- return log_error(L, "'lexer.fold' function not found");
+ return LogError(L, "'lexer.fold' function not found");
lua_pushcfunction(L, lua_error_handler), lua_insert(L, -2);
lua_pushvalue(L, -3);
Sci_Position currentLine = styler.GetLine(startPos);
@@ -727,9 +761,9 @@ public:
lua_pushinteger(L, startPos);
lua_pushinteger(L, currentLine);
lua_pushinteger(L, styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK);
- if (lua_pcall(L, 5, 1, -7) != LUA_OK) return log_error(L);
+ if (lua_pcall(L, 5, 1, -7) != LUA_OK) return LogError(L);
if (!lua_istable(L, -1))
- return log_error(L, "Table of folds expected from 'lexer.fold'");
+ return LogError(L, "Table of folds expected from 'lexer.fold'");
// Fold the text from the fold table returned.
lua_pushnil(L);
while (lua_next(L, -2)) { // line = level
@@ -759,6 +793,8 @@ public:
const char *key, const char *value) override
{
props.Set(key, value, strlen(key), strlen(value));
+ if (strcmp(key, LexerHomeKey) == 0 && lexer_names.empty())
+ ReadLexerNames(value); // not using SCI_LOADLEXERLIBRARY private call
if (reinit &&
(strcmp(key, LexerHomeKey) == 0 || strcmp(key, LexerNameKey) == 0))
Init();
@@ -815,18 +851,16 @@ public:
return nullptr;
case SCI_LOADLEXERLIBRARY: {
const char *path = reinterpret_cast<const char*>(arg);
- const char *old_home = props.Get(LexerHomeKey);
- char *home = reinterpret_cast<char *>(
- malloc(strlen(old_home) + 1 + strlen(path) + 1));
- char *p = home;
- if (*old_home) {
- strcpy(p, old_home), p += strlen(old_home);
- *p++ = ';';
- }
- strcpy(p, path);
- PropertySet(LexerHomeKey, home);
- free(home);
+ ReadLexerNames(path);
+ std::string home(props.Get(LexerHomeKey));
+ if (!home.empty()) home.push_back(';');
+ home.append(path);
+ PropertySet(LexerHomeKey, home.c_str());
return nullptr;
+ } case SCI_PROPERTYNAMES: {
+ std::stringstream names;
+ for (const std::string& name : lexer_names) names << name << '\n';
+ return StringResult(lParam, names.str().c_str());
} case SCI_SETLEXERLANGUAGE:
if (strcmp(
props.Get(LexerNameKey),
@@ -842,24 +876,22 @@ public:
RECORD_STACK_TOP(L);
lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
lua_getfield(L, -1, "_NAME");
- if (SS && sci && multilang) {
- int pos = SS(sci, SCI_GETCURRENTPOS, 0, 0);
- while (pos >= 0 && !ws[SS(sci, SCI_GETSTYLEAT, pos, 0)]) pos--;
- const char *name = nullptr, *p = nullptr;
- if (pos >= 0) {
- name = GetStyleName(SS(sci, SCI_GETSTYLEAT, pos, 0));
- if (name) p = strstr(name, "_whitespace");
+ std::string val(lua_tostring(L, -1));
+ lua_pop(L, 2); // lexer name, lexer object
+ ASSERT_STACK_TOP(L);
+ if (!SS || !sci || !multilang) return StringResult(lParam, val.c_str());
+ val.push_back('/');
+ int pos = SS(sci, SCI_GETCURRENTPOS, 0, 0);
+ while (pos >= 0 && !ws[SS(sci, SCI_GETSTYLEAT, pos, 0)]) pos--;
+ if (pos >= 0) {
+ const char *name = GetStyleName(SS(sci, SCI_GETSTYLEAT, pos, 0)), *p;
+ if (name && (p = strstr(name, "_whitespace"))) {
+ val.append(name, p - name);
+ return StringResult(lParam, val.c_str());
}
- if (!name) name = lua_tostring(L, -1); // "lexer:lexer" fallback
- if (!p) p = name + strlen(name); // "lexer:lexer" fallback
- lua_pushstring(L, "/");
- lua_pushlstring(L, name, p - name);
- lua_concat(L, 3);
}
- const char *val = lua_tostring(L, -1); // no copy needed; remains in mem
- lua_pop(L, 2); // lexer_name or lexer language string, lexer object
- ASSERT_STACK_TOP(L);
- return StringResult(lParam, val);
+ val.append(val, 0, val.length() - 1); // "lexer/lexer" fallback
+ return StringResult(lParam, val.c_str());
} case SCI_GETSTATUS:
return StringResult(lParam, props.Get(LexerErrorKey));
default: // retrieve style names