aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authormitchell <unknown>2020-07-07 20:10:13 -0400
committermitchell <unknown>2020-07-07 20:10:13 -0400
commit3830699d90aa69b1ddde382e47983d26c84d6bcf (patch)
tree8ffd7d14294ac501ff5765a38ae20a0c95d6ba7c
parent9b2cfc0e05f666c31bfa2b6fa60956f3943b3b07 (diff)
downloadscintilla-mirror-3830699d90aa69b1ddde382e47983d26c84d6bcf.tar.gz
Forward-declare LexerLPeg.
This allows access to public members like PropertyGet/PropertySet from Lua and prevents the need for a separate "_PROPS" object in the registry.
-rw-r--r--lexers/LexLPeg.cxx1351
1 files changed, 688 insertions, 663 deletions
diff --git a/lexers/LexLPeg.cxx b/lexers/LexLPeg.cxx
index f4fea6e63..d4f21f25c 100644
--- a/lexers/LexLPeg.cxx
+++ b/lexers/LexLPeg.cxx
@@ -68,6 +68,173 @@ using namespace Scintilla;
#define lua_rawget(l, i) (lua_rawget(l, i), lua_type(l, -1))
#endif
+/** The LPeg Scintilla lexer. */
+class LexerLPeg : public DefaultLexer {
+ // Lexer property keys.
+ const char * const LexerErrorKey = "lexer.lpeg.error";
+ const char * const LexerHomeKey = "lexer.lpeg.home";
+ const char * const LexerNameKey = "lexer.lpeg.name";
+ const char * const LexerThemeKey = "lexer.lpeg.color.theme";
+
+ /**
+ * The lexer's Lua state.
+ * It is cleared each time the lexer language changes unless `ownLua` is
+ * `true`.
+ */
+ lua_State *L;
+ /**
+ * The flag indicating whether or not the Lua State is owned by the lexer.
+ */
+ bool ownLua = true;
+ /**
+ * The set of properties for the lexer.
+ * The LexerHomeKey and LexerNameKey properties must be defined before running
+ * the lexer.
+ */
+ PropSetSimple props;
+ /** The function to send Scintilla messages with. */
+ SciFnDirect SS = nullptr;
+ /** The Scintilla object the lexer belongs to. */
+ sptr_t sci = 0;
+ /**
+ * The flag indicating whether or not the lexer needs to be re-initialized.
+ * Re-initialization is required after the lexer language changes.
+ */
+ bool reinit = true;
+ /**
+ * The flag indicating whether or not the lexer language has embedded lexers.
+ */
+ bool multilang = false;
+ /**
+ * The list of style numbers considered to be whitespace styles.
+ * This is used in multi-language lexers when backtracking to whitespace to
+ * determine which lexer grammar to use.
+ */
+ bool ws[STYLE_MAX + 1];
+ /** List of known lexer names. */
+ std::set<std::string> lexerNames;
+ /** Style name to return for `NameOfStyle()`. */
+ std::string styleName;
+
+ /**
+ * Searches the given directory for lexers and records their names.
+ * @param path Path to a directory containing lexers.
+ */
+ void ReadLexerNames(const char *path);
+
+ /**
+ * Logs the given error message or a Lua error message, prints it, and clears
+ * the stack.
+ * Error messages are logged to the LexerErrorKey property.
+ * @param L The Lua State.
+ * @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 LogError(lua_State *L, const char *str = nullptr);
+
+ /**
+ * Parses the given style string to set the properties for the given style
+ * number.
+ * Style strings mimic SciTE's "style.*.stylenumber" properties.
+ * (https://scintilla.org/SciTEDoc.html)
+ * @param num The style number to set properties for.
+ * @param style The style string containing properties to set.
+ */
+ void SetStyle(int num, const char *style);
+
+ /**
+ * Iterates through the lexer's `_TOKENSTYLES`, setting the style properties
+ * for all defined styles.
+ */
+ void SetStyles();
+
+ /**
+ * Initializes the lexer once the LexerHomeKey and LexerNameKey properties are
+ * set.
+ */
+ bool Init();
+
+ /**
+ * When *lparam* is `0`, returns the size of the buffer needed to store the
+ * given string *str* in; otherwise copies *str* into the buffer *lparam* and
+ * returns the number of bytes copied.
+ * @param lparam `0` to get the number of bytes needed to store *str* or a
+ * pointer to a buffer large enough to copy *str* into.
+ * @param str The string to copy.
+ * @return number of bytes needed to hold *str*
+ */
+ void *StringResult(long lparam, const char *str);
+
+public:
+ /** Constructor. */
+ LexerLPeg();
+
+ /** Destructor. */
+ virtual ~LexerLPeg() = default;
+
+ /** Destroys the lexer object. */
+ void SCI_METHOD Release() override;
+
+ /**
+ * Lexes the Scintilla document.
+ * @param startPos The position in the document to start lexing at.
+ * @param lengthDoc The number of bytes in the document to lex.
+ * @param initStyle The initial style at position *startPos* in the document.
+ * @param buffer The document interface.
+ */
+ void SCI_METHOD Lex(
+ Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle,
+ IDocument *buffer) override;
+
+ /**
+ * Folds the Scintilla document.
+ * @param startPos The position in the document to start folding at.
+ * @param lengthDoc The number of bytes in the document to fold.
+ * @param initStyle The initial style at position *startPos* in the document.
+ * @param buffer The document interface.
+ */
+ void SCI_METHOD Fold(
+ Sci_PositionU startPos, Sci_Position lengthDoc, int, IDocument *buffer)
+ override;
+
+ /**
+ * Sets the *key* lexer property to *value*.
+ * If *key* starts with "style.", also set the style for the token.
+ * @param key The string property key.
+ * @param val The string value.
+ */
+ Sci_Position SCI_METHOD PropertySet(
+ const char *key, const char *value) override;
+
+ /**
+ * Allows for direct communication between the application and the lexer.
+ * The application uses this to set `SS`, `sci`, `L`, and lexer properties,
+ * and to retrieve style names.
+ * @param code The communication code.
+ * @param arg The argument.
+ * @return void *data
+ */
+ void * SCI_METHOD PrivateCall(int code, void *arg) override;
+
+ /**
+ * Returns the style name for the given style number.
+ * Note: the returned pointer is not guaranteed to exist after the next call
+ * to `NameOfStyle()`, so its contents should be immediately copied.
+ * @param style The style number to get the style name for.
+ * @return style name or nullptr
+ */
+ const char * SCI_METHOD NameOfStyle(int style) override;
+
+ /**
+ * Returns the lexer property for *key*.
+ * @param key The string property key.
+ */
+ const char * SCI_METHOD PropertyGet(const char *key) override;
+
+ /** Constructs a new instance of the lexer. */
+ static ILexer *LexerFactoryLPeg();
+};
+
/** Lua pcall error message handler that adds a traceback. */
static int lua_error_handler(lua_State *L) {
luaL_traceback(L, L, lua_tostring(L, -1), 1);
@@ -78,10 +245,9 @@ static int lua_error_handler(lua_State *L) {
static int lexer_property_index(lua_State *L) {
const char *property = lua_tostring(L, lua_upvalueindex(1));
lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ LexerLPeg *lexer = reinterpret_cast<LexerLPeg *>(lua_touserdata(L, -1));
lua_rawgetp(L, LUA_REGISTRYINDEX, lua_touserdata(L, -1));
- lua_getfield(L, -1, "_PROPS");
- auto props = static_cast<PropSetSimple *>(lua_touserdata(L, -1));
- lua_getfield(L, -2, "_BUFFER");
+ lua_getfield(L, -1, "_BUFFER");
auto buffer = static_cast<IDocument *>(lua_touserdata(L, -1));
if (strcmp(property, "fold_level") == 0) {
luaL_argcheck(L, buffer, 1, "must be lexing or folding");
@@ -90,9 +256,9 @@ static int lexer_property_index(lua_State *L) {
luaL_argcheck(L, buffer, 1, "must be lexing or folding");
lua_pushinteger(L, buffer->GetLineIndentation(luaL_checkinteger(L, 2) - 1));
} else if (strcmp(property, "property") == 0) {
- lua_pushstring(L, props->Get(luaL_checkstring(L, 2)));
+ lua_pushstring(L, lexer->PropertyGet(luaL_checkstring(L, 2)));
} else if (strcmp(property, "property_int") == 0) {
- lua_pushstring(L, props->Get(luaL_checkstring(L, 2)));
+ lua_pushstring(L, lexer->PropertyGet(luaL_checkstring(L, 2)));
lua_pushinteger(L, lua_tointeger(L, -1));
} else if (strcmp(property, "style_at") == 0) {
luaL_argcheck(L, buffer, 1, "must be lexing or folding");
@@ -121,15 +287,11 @@ static int lexer_property_newindex(lua_State *L) {
strcmp(property, "style_at") != 0 &&
strcmp(property, "line_from_position") != 0, 3, "read-only property");
lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ LexerLPeg *lexer = reinterpret_cast<LexerLPeg *>(lua_touserdata(L, -1));
lua_rawgetp(L, LUA_REGISTRYINDEX, lua_touserdata(L, -1));
- if (strcmp(property, "property") == 0) {
- lua_getfield(L, -1, "_PROPS");
- auto props = static_cast<PropSetSimple *>(lua_touserdata(L, -1));
- // TODO: ideally would use lexer->PropertySet().
- props->Set(
- luaL_checkstring(L, 2), luaL_checkstring(L, 3), lua_rawlen(L, 2),
- lua_rawlen(L, 3));
- } else if (strcmp(property, "line_state") == 0) {
+ if (strcmp(property, "property") == 0)
+ lexer->PropertySet(luaL_checkstring(L, 2), luaL_checkstring(L, 3));
+ else if (strcmp(property, "line_state") == 0) {
luaL_argcheck(
L, lua_getfield(L, -1, "_BUFFER"), 1, "must be lexing or folding");
auto buffer = static_cast<IDocument *>(lua_touserdata(L, -1));
@@ -195,720 +357,583 @@ static void expand_property(lua_State *L) {
ASSERT_STACK_TOP(L);
}
-/** The LPeg Scintilla lexer. */
-class LexerLPeg : public DefaultLexer {
- // Lexer property keys.
- const char * const LexerErrorKey = "lexer.lpeg.error";
- const char * const LexerHomeKey = "lexer.lpeg.home";
- const char * const LexerNameKey = "lexer.lpeg.name";
- const char * const LexerThemeKey = "lexer.lpeg.color.theme";
-
- /**
- * The lexer's Lua state.
- * It is cleared each time the lexer language changes unless `ownLua` is
- * `true`.
- */
- lua_State *L;
- /**
- * The flag indicating whether or not the Lua State is owned by the lexer.
- */
- bool ownLua = true;
- /**
- * The set of properties for the lexer.
- * The LexerHomeKey and LexerNameKey properties must be defined before running
- * the lexer.
- */
- PropSetSimple props;
- /** The function to send Scintilla messages with. */
- SciFnDirect SS = nullptr;
- /** The Scintilla object the lexer belongs to. */
- sptr_t sci = 0;
- /**
- * The flag indicating whether or not the lexer needs to be re-initialized.
- * Re-initialization is required after the lexer language changes.
- */
- bool reinit = true;
- /**
- * The flag indicating whether or not the lexer language has embedded lexers.
- */
- bool multilang = false;
- /**
- * The list of style numbers considered to be whitespace styles.
- * This is used in multi-language lexers when backtracking to whitespace to
- * determine which lexer grammar to use.
- */
- bool ws[STYLE_MAX + 1];
- /** List of known lexer names. */
- std::set<std::string> lexerNames;
- /** Style name to return for `NameOfStyle()`. */
- std::string styleName;
-
- /**
- * Searches the given directory for lexers and records their names.
- * @param path Path to a directory containing lexers.
- */
- void ReadLexerNames(const char *path) {
+void LexerLPeg::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) lexerNames.emplace(entry->d_name, p - entry->d_name);
- }
- closedir(dir);
+ DIR *dir = opendir(path);
+ if (!dir) return;
+ struct dirent *entry;
+ while ((entry = readdir(dir))) {
+ char *p = strstr(entry->d_name, ".lua");
+ if (p) lexerNames.emplace(entry->d_name, p - entry->d_name);
+ }
+ closedir(dir);
#else
- struct _finddata_t file;
- std::string glob(path);
- glob += "/*";
- intptr_t handle = _findfirst(glob.c_str(), &file);
- if (handle == -1) return;
- do {
- char *p = strstr(file.name, ".lua");
- if (p) lexerNames.emplace(file.name, p - file.name);
- } while (_findnext(handle, &file) != -1);
- _findclose(handle);
+ struct _finddata_t file;
+ std::string glob(path);
+ glob += "/*";
+ intptr_t handle = _findfirst(glob.c_str(), &file);
+ if (handle == -1) return;
+ do {
+ char *p = strstr(file.name, ".lua");
+ if (p) lexerNames.emplace(file.name, p - file.name);
+ } while (_findnext(handle, &file) != -1);
+ _findclose(handle);
#endif
- }
+}
- /**
- * Logs the given error message or a Lua error message, prints it, and clears
- * the stack.
- * Error messages are logged to the LexerErrorKey property.
- * @param L The Lua State.
- * @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 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);
- lua_settop(L, 0);
- }
+void LexerLPeg::LogError(lua_State *L, const char *str) {
+ const char *value = str ? str : lua_tostring(L, -1);
+ PropertySet(LexerErrorKey, value);
+ fprintf(stderr, "Lua Error: %s.\n", value);
+ lua_settop(L, 0);
+}
- /**
- * Parses the given style string to set the properties for the given style
- * number.
- * Style strings mimic SciTE's "style.*.stylenumber" properties.
- * (https://scintilla.org/SciTEDoc.html)
- * @param num The style number to set properties for.
- * @param style The style string containing properties to set.
- */
- void SetStyle(int num, const char *style) {
- auto style_copy = static_cast<char *>(malloc(strlen(style) + 1));
- char *key = strcpy(style_copy, style), *next = nullptr, *val = nullptr;
- while (key) {
- if ((next = strchr(key, ','))) *next++ = '\0';
- if ((val = strchr(key, ':'))) *val++ = '\0';
- if (strcmp(key, "font") == 0 && val)
- SS(sci, SCI_STYLESETFONT, num, reinterpret_cast<sptr_t>(val));
- else if (strcmp(key, "size") == 0 && val)
- SS(sci, SCI_STYLESETSIZE, num, static_cast<int>(atoi(val)));
- else if (strcmp(key, "bold") == 0 || strcmp(key, "notbold") == 0 ||
- strcmp(key, "weight") == 0) {
+void LexerLPeg::SetStyle(int num, const char *style) {
+ auto style_copy = static_cast<char *>(malloc(strlen(style) + 1));
+ char *key = strcpy(style_copy, style), *next = nullptr, *val = nullptr;
+ while (key) {
+ if ((next = strchr(key, ','))) *next++ = '\0';
+ if ((val = strchr(key, ':'))) *val++ = '\0';
+ if (strcmp(key, "font") == 0 && val)
+ SS(sci, SCI_STYLESETFONT, num, reinterpret_cast<sptr_t>(val));
+ else if (strcmp(key, "size") == 0 && val)
+ SS(sci, SCI_STYLESETSIZE, num, static_cast<int>(atoi(val)));
+ else if (strcmp(key, "bold") == 0 || strcmp(key, "notbold") == 0 ||
+ strcmp(key, "weight") == 0) {
#if !CURSES
- int weight = SC_WEIGHT_NORMAL;
- if (*key == 'b')
- weight = SC_WEIGHT_BOLD;
- else if (*key == 'w' && val)
- weight = atoi(val);
- SS(sci, SCI_STYLESETWEIGHT, num, weight);
+ int weight = SC_WEIGHT_NORMAL;
+ if (*key == 'b')
+ weight = SC_WEIGHT_BOLD;
+ else if (*key == 'w' && val)
+ weight = atoi(val);
+ SS(sci, SCI_STYLESETWEIGHT, num, weight);
#else
- // Scintilla curses requires font attributes to be stored in the "font
- // weight" style attribute.
- // First, clear any existing SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD, or
- // SC_WEIGHT_BOLD values stored in the lower 16 bits. Then set the
- // appropriate curses attr.
- sptr_t weight =
- SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~(A_COLOR | A_CHARTEXT);
- int bold =
- *key == 'b' || (*key == 'w' && val && atoi(val) > SC_WEIGHT_NORMAL);
- SS(
- sci, SCI_STYLESETWEIGHT, num,
- bold ? weight | A_BOLD : weight & ~A_BOLD);
+ // Scintilla curses requires font attributes to be stored in the "font
+ // weight" style attribute.
+ // First, clear any existing SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD, or
+ // SC_WEIGHT_BOLD values stored in the lower 16 bits. Then set the
+ // appropriate curses attr.
+ sptr_t weight =
+ SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~(A_COLOR | A_CHARTEXT);
+ int bold =
+ *key == 'b' || (*key == 'w' && val && atoi(val) > SC_WEIGHT_NORMAL);
+ SS(
+ sci, SCI_STYLESETWEIGHT, num,
+ bold ? weight | A_BOLD : weight & ~A_BOLD);
#endif
- } else if (strcmp(key, "italics") == 0 || strcmp(key, "notitalics") == 0)
- SS(sci, SCI_STYLESETITALIC, num, *key == 'i');
- else if (strcmp(key, "underlined") == 0 ||
- strcmp(key, "notunderlined") == 0) {
+ } else if (strcmp(key, "italics") == 0 || strcmp(key, "notitalics") == 0)
+ SS(sci, SCI_STYLESETITALIC, num, *key == 'i');
+ else if (strcmp(key, "underlined") == 0 ||
+ strcmp(key, "notunderlined") == 0) {
#if !CURSES
- SS(sci, SCI_STYLESETUNDERLINE, num, *key == 'u');
+ SS(sci, SCI_STYLESETUNDERLINE, num, *key == 'u');
#else
- // Scintilla curses requires font attributes to be stored in the "font
- // weight" style attribute.
- // First, clear any existing SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD, or
- // SC_WEIGHT_BOLD values stored in the lower 16 bits. Then set the
- // appropriate curses attr.
- sptr_t weight =
- SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~(A_COLOR | A_CHARTEXT);
- SS(
- sci, SCI_STYLESETWEIGHT, num,
- (*key == 'u') ? weight | A_UNDERLINE : weight & ~A_UNDERLINE);
+ // Scintilla curses requires font attributes to be stored in the "font
+ // weight" style attribute.
+ // First, clear any existing SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD, or
+ // SC_WEIGHT_BOLD values stored in the lower 16 bits. Then set the
+ // appropriate curses attr.
+ sptr_t weight =
+ SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~(A_COLOR | A_CHARTEXT);
+ SS(
+ sci, SCI_STYLESETWEIGHT, num,
+ (*key == 'u') ? weight | A_UNDERLINE : weight & ~A_UNDERLINE);
#endif
- } else if ((strcmp(key, "fore") == 0 || strcmp(key, "back") == 0) &&
- val) {
- int msg = (*key == 'f') ? SCI_STYLESETFORE : SCI_STYLESETBACK;
- int color = static_cast<int>(strtol(val, nullptr, 0));
- if (*val == '#') { // #RRGGBB format; Scintilla format is 0xBBGGRR
- color = static_cast<int>(strtol(val + 1, nullptr, 16));
- color =
- ((color & 0xFF0000) >> 16) | (color & 0xFF00) |
- ((color & 0xFF) << 16); // convert to 0xBBGGRR
- }
- SS(sci, msg, num, color);
- } else if (strcmp(key, "eolfilled") == 0 ||
- strcmp(key, "noteolfilled") == 0)
- SS(sci, SCI_STYLESETEOLFILLED, num, *key == 'e');
- else if (strcmp(key, "characterset") == 0 && val)
- SS(sci, SCI_STYLESETCHARACTERSET, num, static_cast<int>(atoi(val)));
- else if (strcmp(key, "case") == 0 && val) {
- if (*val == 'u')
- SS(sci, SCI_STYLESETCASE, num, SC_CASE_UPPER);
- else if (*val == 'l')
- SS(sci, SCI_STYLESETCASE, num, SC_CASE_LOWER);
- } else if (strcmp(key, "visible") == 0 || strcmp(key, "notvisible") == 0)
- SS(sci, SCI_STYLESETVISIBLE, num, *key == 'v');
- else if (strcmp(key, "changeable") == 0 ||
- strcmp(key, "notchangeable") == 0)
- SS(sci, SCI_STYLESETCHANGEABLE, num, *key == 'c');
- else if (strcmp(key, "hotspot") == 0 || strcmp(key, "nothotspot") == 0)
- SS(sci, SCI_STYLESETHOTSPOT, num, *key == 'h');
- key = next;
- }
- free(style_copy);
+ } else if ((strcmp(key, "fore") == 0 || strcmp(key, "back") == 0) &&
+ val) {
+ int msg = (*key == 'f') ? SCI_STYLESETFORE : SCI_STYLESETBACK;
+ int color = static_cast<int>(strtol(val, nullptr, 0));
+ if (*val == '#') { // #RRGGBB format; Scintilla format is 0xBBGGRR
+ color = static_cast<int>(strtol(val + 1, nullptr, 16));
+ color =
+ ((color & 0xFF0000) >> 16) | (color & 0xFF00) |
+ ((color & 0xFF) << 16); // convert to 0xBBGGRR
+ }
+ SS(sci, msg, num, color);
+ } else if (strcmp(key, "eolfilled") == 0 ||
+ strcmp(key, "noteolfilled") == 0)
+ SS(sci, SCI_STYLESETEOLFILLED, num, *key == 'e');
+ else if (strcmp(key, "characterset") == 0 && val)
+ SS(sci, SCI_STYLESETCHARACTERSET, num, static_cast<int>(atoi(val)));
+ else if (strcmp(key, "case") == 0 && val) {
+ if (*val == 'u')
+ SS(sci, SCI_STYLESETCASE, num, SC_CASE_UPPER);
+ else if (*val == 'l')
+ SS(sci, SCI_STYLESETCASE, num, SC_CASE_LOWER);
+ } else if (strcmp(key, "visible") == 0 || strcmp(key, "notvisible") == 0)
+ SS(sci, SCI_STYLESETVISIBLE, num, *key == 'v');
+ else if (strcmp(key, "changeable") == 0 ||
+ strcmp(key, "notchangeable") == 0)
+ SS(sci, SCI_STYLESETCHANGEABLE, num, *key == 'c');
+ else if (strcmp(key, "hotspot") == 0 || strcmp(key, "nothotspot") == 0)
+ SS(sci, SCI_STYLESETHOTSPOT, num, *key == 'h');
+ key = next;
}
+ free(style_copy);
+}
- /**
- * Iterates through the lexer's `_TOKENSTYLES`, setting the style properties
- * for all defined styles.
- */
- void SetStyles() {
- RECORD_STACK_TOP(L);
- // If the lexer defines additional styles, set their properties first (if
- // the user has not already defined them).
- lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- lua_getfield(L, -1, "_EXTRASTYLES");
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
- lua_pushstring(L, "style."), lua_pushvalue(L, -3), lua_concat(L, 2);
- if (!*props.Get(lua_tostring(L, -1)))
- PropertySet(lua_tostring(L, -1), lua_tostring(L, -2));
- lua_pop(L, 1); // style name
- }
- lua_pop(L, 1); // value
- }
- lua_pop(L, 1); // _EXTRASTYLES
-
- if (!SS || !sci) {
- lua_pop(L, 1); // lexer object
- // Skip, but do not report an error since `reinit` would remain `false`
- // and subsequent calls to `Lex()` and `Fold()` would repeatedly call this
- // function and error.
- ASSERT_STACK_TOP(L);
- return;
- }
- lua_pushstring(L, "style.default"), expand_property(L);
- SetStyle(STYLE_DEFAULT, lua_tostring(L, -1));
- lua_pop(L, 1); // style
- SS(sci, SCI_STYLECLEARALL, 0, 0); // set default styles
- lua_getfield(L, -1, "_TOKENSTYLES");
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (lua_isstring(L, -2) && lua_isnumber(L, -1) &&
- lua_tointeger(L, -1) - 1 != STYLE_DEFAULT) {
- lua_pushstring(L, "style."), lua_pushvalue(L, -3), lua_concat(L, 2);
- expand_property(L);
- SetStyle(lua_tointeger(L, -2) - 1, lua_tostring(L, -1));
- lua_pop(L, 1); // style
- }
- lua_pop(L, 1); // value
+void LexerLPeg::SetStyles() {
+ RECORD_STACK_TOP(L);
+ // If the lexer defines additional styles, set their properties first (if
+ // the user has not already defined them).
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_getfield(L, -1, "_EXTRASTYLES");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
+ lua_pushstring(L, "style."), lua_pushvalue(L, -3), lua_concat(L, 2);
+ if (!*props.Get(lua_tostring(L, -1)))
+ PropertySet(lua_tostring(L, -1), lua_tostring(L, -2));
+ lua_pop(L, 1); // style name
}
- lua_pop(L, 2); // _TOKENSTYLES, lexer object
- ASSERT_STACK_TOP(L);
+ lua_pop(L, 1); // value
}
+ lua_pop(L, 1); // _EXTRASTYLES
- /**
- * Initializes the lexer once the LexerHomeKey and LexerNameKey properties are
- * set.
- */
- bool Init() {
- if (!props.GetExpanded(LexerHomeKey, nullptr) ||
- !*props.Get(LexerNameKey) || !L)
- return false;
- char *_home = reinterpret_cast<char *>(
- malloc(props.GetExpanded(LexerHomeKey, nullptr) + 1));
- props.GetExpanded(LexerHomeKey, _home);
- std::string home(_home);
- free(_home);
- const char *lexer = props.Get(LexerNameKey);
- RECORD_STACK_TOP(L);
+ if (!SS || !sci) {
+ lua_pop(L, 1); // lexer object
+ // Skip, but do not report an error since `reinit` would remain `false`
+ // and subsequent calls to `Lex()` and `Fold()` would repeatedly call this
+ // function and error.
+ ASSERT_STACK_TOP(L);
+ return;
+ }
+ lua_pushstring(L, "style.default"), expand_property(L);
+ SetStyle(STYLE_DEFAULT, lua_tostring(L, -1));
+ lua_pop(L, 1); // style
+ SS(sci, SCI_STYLECLEARALL, 0, 0); // set default styles
+ lua_getfield(L, -1, "_TOKENSTYLES");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_isstring(L, -2) && lua_isnumber(L, -1) &&
+ lua_tointeger(L, -1) - 1 != STYLE_DEFAULT) {
+ lua_pushstring(L, "style."), lua_pushvalue(L, -3), lua_concat(L, 2);
+ expand_property(L);
+ SetStyle(lua_tointeger(L, -2) - 1, lua_tostring(L, -1));
+ lua_pop(L, 1); // style
+ }
+ lua_pop(L, 1); // value
+ }
+ lua_pop(L, 2); // _TOKENSTYLES, lexer object
+ ASSERT_STACK_TOP(L);
+}
- // Designate the currently running LexerLPeg instance.
- // This needs to be done prior to calling any Lua lexer code, particularly
- // when `ownLua` is `false`, as there may be multiple LexerLPeg instances
- // floating around, and the lexer module methods and metamethods need to
- // know which instance to use.
- lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+bool LexerLPeg::Init() {
+ if (!props.GetExpanded(LexerHomeKey, nullptr) ||
+ !*props.Get(LexerNameKey) || !L)
+ return false;
+ char *_home = reinterpret_cast<char *>(
+ malloc(props.GetExpanded(LexerHomeKey, nullptr) + 1));
+ props.GetExpanded(LexerHomeKey, _home);
+ std::string home(_home);
+ free(_home);
+ const char *lexer = props.Get(LexerNameKey);
+ RECORD_STACK_TOP(L);
- // Determine where to look for the lexer module and themes.
- 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;
+ // Designate the currently running LexerLPeg instance.
+ // This needs to be done prior to calling any Lua lexer code, particularly
+ // when `ownLua` is `false`, as there may be multiple LexerLPeg instances
+ // floating around, and the lexer module methods and metamethods need to
+ // know which instance to use.
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+
+ // Determine where to look for the lexer module and themes.
+ 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 (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));
+ if (status == LUA_ERRFILE) {
+ lua_pop(L, 2); // error message, filename
+ continue; // try next directory
+ }
+ lua_remove(L, -2); // filename
+ lua_pushcfunction(L, lua_error_handler);
+ lua_insert(L, -2);
+ if (status == LUA_OK && lua_pcall(L, 0, 1, -2) == LUA_OK) break;
+ return (LogError(L), false);
}
- 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) {
+ if (lua_isnil(L, -1))
+ return (LogError(L, "'lexer.lua' module not found"), false);
+ lua_remove(L, -2); // lua_error_handler
+ lua_replace(L, -2); // nil
+ lua_pushinteger(L, SC_FOLDLEVELBASE);
+ lua_setfield(L, -2, "FOLD_BASE");
+ lua_pushinteger(L, SC_FOLDLEVELWHITEFLAG);
+ lua_setfield(L, -2, "FOLD_BLANK");
+ lua_pushinteger(L, SC_FOLDLEVELHEADERFLAG);
+ lua_setfield(L, -2, "FOLD_HEADER");
+ lua_createtable(L, 0, 2);
+ lua_pushcfunction(L, lexer_index), lua_setfield(L, -2, "__index");
+ lua_pushcfunction(L, lexer_newindex), lua_setfield(L, -2, "__newindex");
+ lua_setmetatable(L, -2);
+ lua_pushvalue(L, -1), lua_setfield(L, -3, "lexer");
+ }
+ lua_replace(L, -2);
+ // Update the userdata needed by lexer metamethods.
+ lua_pushvalue(L, -1);
+ lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+
+ // Load the language lexer.
+ if (lua_getfield(L, -1, "load") != LUA_TFUNCTION)
+ 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 (LogError(L), false);
+ lua_remove(L, -2); // lua_error_handler
+ lua_remove(L, -2); // lexer module
+ lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+
+ // Load the theme and set up styles.
+ if (props.GetExpanded(LexerThemeKey, nullptr)) {
+ char *theme = reinterpret_cast<char *>(
+ malloc(props.GetExpanded(LexerThemeKey, nullptr) + 1));
+ props.GetExpanded(LexerThemeKey, theme);
+ if (!strstr(theme, "/") && !strstr(theme, "\\")) { // theme name
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));
- if (status == LUA_ERRFILE) {
- lua_pop(L, 2); // error message, filename
- continue; // try next directory
+ lua_pushstring(L, "/themes/");
+ lua_pushstring(L, theme);
+ lua_pushstring(L, ".lua");
+ lua_concat(L, 4);
+ if (luaL_loadfile(L, lua_tostring(L, -1)) != LUA_ERRFILE ||
+ dir == dirs.back()) {
+ lua_pop(L, 1); // function, leaving filename on top
+ break;
}
- lua_remove(L, -2); // filename
- lua_pushcfunction(L, lua_error_handler);
- lua_insert(L, -2);
- if (status == LUA_OK && lua_pcall(L, 0, 1, -2) == LUA_OK) break;
- return (LogError(L), false);
+ lua_pop(L, 2); // error message, filename
}
- if (lua_isnil(L, -1))
- return (LogError(L, "'lexer.lua' module not found"), false);
- lua_remove(L, -2); // lua_error_handler
- lua_replace(L, -2); // nil
- lua_pushinteger(L, SC_FOLDLEVELBASE);
- lua_setfield(L, -2, "FOLD_BASE");
- lua_pushinteger(L, SC_FOLDLEVELWHITEFLAG);
- lua_setfield(L, -2, "FOLD_BLANK");
- lua_pushinteger(L, SC_FOLDLEVELHEADERFLAG);
- lua_setfield(L, -2, "FOLD_HEADER");
- lua_createtable(L, 0, 2);
- lua_pushcfunction(L, lexer_index), lua_setfield(L, -2, "__index");
- lua_pushcfunction(L, lexer_newindex), lua_setfield(L, -2, "__newindex");
- lua_setmetatable(L, -2);
- lua_pushvalue(L, -1), lua_setfield(L, -3, "lexer");
- }
- lua_replace(L, -2);
- // Update the userdata needed by lexer metamethods.
- lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
- lua_setfield(L, -2, "_PROPS");
- lua_pushvalue(L, -1);
- lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
-
- // Load the language lexer.
- if (lua_getfield(L, -1, "load") != LUA_TFUNCTION)
- 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 (LogError(L), false);
- lua_remove(L, -2); // lua_error_handler
- lua_remove(L, -2); // lexer module
- lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
- lua_setfield(L, -2, "_PROPS");
- lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
-
- // Load the theme and set up styles.
- if (props.GetExpanded(LexerThemeKey, nullptr)) {
- char *theme = reinterpret_cast<char *>(
- malloc(props.GetExpanded(LexerThemeKey, nullptr) + 1));
- props.GetExpanded(LexerThemeKey, theme);
- if (!strstr(theme, "/") && !strstr(theme, "\\")) { // theme name
- for (const std::string& dir : dirs) {
- lua_pushstring(L, dir.c_str());
- lua_pushstring(L, "/themes/");
- lua_pushstring(L, theme);
- lua_pushstring(L, ".lua");
- lua_concat(L, 4);
- if (luaL_loadfile(L, lua_tostring(L, -1)) != LUA_ERRFILE ||
- dir == dirs.back()) {
- lua_pop(L, 1); // function, leaving filename on top
- break;
- }
- lua_pop(L, 2); // error message, filename
- }
- } else lua_pushstring(L, theme); // path to theme
- lua_pushcfunction(L, lua_error_handler);
- lua_insert(L, -2);
- if (luaL_loadfile(L, lua_tostring(L, -1)) == LUA_OK &&
- lua_pcall(L, 0, 0, -3) == LUA_OK)
- lua_pop(L, 2); // theme, lua_error_handler
- else
- LogError(L);
- free(theme);
- }
- SetStyles();
+ } else lua_pushstring(L, theme); // path to theme
+ lua_pushcfunction(L, lua_error_handler);
+ lua_insert(L, -2);
+ if (luaL_loadfile(L, lua_tostring(L, -1)) == LUA_OK &&
+ lua_pcall(L, 0, 0, -3) == LUA_OK)
+ lua_pop(L, 2); // theme, lua_error_handler
+ else
+ LogError(L);
+ free(theme);
+ }
+ SetStyles();
+
+ // If the lexer is a parent, it will have children in its _CHILDREN table.
+ // In that case, determine which styles are language whitespace styles
+ // ([lang]_whitespace). This is necessary for determining which language
+ // to start lexing with.
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ if (lua_getfield(L, -1, "_CHILDREN") == LUA_TTABLE) {
+ multilang = true;
+ for (int i = 0; i <= STYLE_MAX; i++)
+ ws[i] = strstr(NameOfStyle(i), "whitespace") ? true : false;
+ }
+ lua_pop(L, 2); // _CHILDREN, lexer object
- // If the lexer is a parent, it will have children in its _CHILDREN table.
- // In that case, determine which styles are language whitespace styles
- // ([lang]_whitespace). This is necessary for determining which language
- // to start lexing with.
- lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- if (lua_getfield(L, -1, "_CHILDREN") == LUA_TTABLE) {
- multilang = true;
- for (int i = 0; i <= STYLE_MAX; i++)
- ws[i] = strstr(NameOfStyle(i), "whitespace") ? true : false;
- }
- lua_pop(L, 2); // _CHILDREN, lexer object
+ reinit = false;
+ PropertySet(LexerErrorKey, "");
+ ASSERT_STACK_TOP(L);
+ return true;
+}
- reinit = false;
- PropertySet(LexerErrorKey, "");
- ASSERT_STACK_TOP(L);
- return true;
- }
+void *LexerLPeg::StringResult(long lparam, const char *str) {
+ if (lparam) strcpy(reinterpret_cast<char *>(lparam), str);
+ return reinterpret_cast<void *>(strlen(str));
+}
- /**
- * When *lparam* is `0`, returns the size of the buffer needed to store the
- * given string *str* in; otherwise copies *str* into the buffer *lparam* and
- * returns the number of bytes copied.
- * @param lparam `0` to get the number of bytes needed to store *str* or a
- * pointer to a buffer large enough to copy *str* into.
- * @param str The string to copy.
- * @return number of bytes needed to hold *str*
- */
- void *StringResult(long lparam, const char *str) {
- if (lparam) strcpy(reinterpret_cast<char *>(lparam), str);
- return reinterpret_cast<void *>(strlen(str));
+LexerLPeg::LexerLPeg() : DefaultLexer("lpeg", SCLEX_LPEG), L(luaL_newstate()) {
+ // Initialize the Lua state, load libraries, and set platform variables.
+ if (!L) {
+ fprintf(stderr, "Lua failed to initialize.\n");
+ return;
}
-
-public:
- /** Constructor. */
- LexerLPeg() : DefaultLexer("lpeg", SCLEX_LPEG), L(luaL_newstate()) {
- // Initialize the Lua state, load libraries, and set platform variables.
- if (!L) {
- fprintf(stderr, "Lua failed to initialize.\n");
- return;
- }
#if LUA_VERSION_NUM < 502
- luaL_requiref(L, "", luaopen_base, 1), lua_pop(L, 1);
+ luaL_requiref(L, "", luaopen_base, 1), lua_pop(L, 1);
#else
- luaL_requiref(L, "_G", luaopen_base, 1), lua_pop(L, 1);
+ luaL_requiref(L, "_G", luaopen_base, 1), lua_pop(L, 1);
#endif
- luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1), lua_pop(L, 1);
- luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1), lua_pop(L, 1);
- // TODO: figure out why lua_setglobal() is needed for lpeg.
- luaL_requiref(L, "lpeg", luaopen_lpeg, 1), lua_setglobal(L, "lpeg");
+ luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1), lua_pop(L, 1);
+ luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1), lua_pop(L, 1);
+ // TODO: figure out why lua_setglobal() is needed for lpeg.
+ luaL_requiref(L, "lpeg", luaopen_lpeg, 1), lua_setglobal(L, "lpeg");
#if _WIN32
- lua_pushboolean(L, 1), lua_setglobal(L, "WIN32");
+ lua_pushboolean(L, 1), lua_setglobal(L, "WIN32");
#endif
#if __APPLE__
- lua_pushboolean(L, 1), lua_setglobal(L, "OSX");
+ lua_pushboolean(L, 1), lua_setglobal(L, "OSX");
#endif
#if GTK
- lua_pushboolean(L, 1), lua_setglobal(L, "GTK");
+ lua_pushboolean(L, 1), lua_setglobal(L, "GTK");
#endif
#if CURSES
- lua_pushboolean(L, 1), lua_setglobal(L, "CURSES");
+ lua_pushboolean(L, 1), lua_setglobal(L, "CURSES");
#endif
+}
+
+void SCI_METHOD LexerLPeg::Release() {
+ if (ownLua && L)
+ lua_close(L);
+ else if (!ownLua) {
+ lua_pushnil(L);
+ lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_pushnil(L), lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
}
+ delete this;
+}
- /** Destructor. */
- virtual ~LexerLPeg() = default;
+void SCI_METHOD LexerLPeg::Lex(
+ Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle,
+ IDocument *buffer)
+{
+ LexAccessor styler(buffer);
+ if ((reinit && !Init()) || !L) {
+ // Style everything in the default style.
+ styler.StartAt(startPos);
+ styler.StartSegment(startPos);
+ styler.ColourTo(startPos + lengthDoc - 1, STYLE_DEFAULT);
+ styler.Flush();
+ return;
+ }
+ RECORD_STACK_TOP(L);
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(buffer));
+ lua_setfield(L, -2, "_BUFFER");
+
+ // Ensure the lexer has a grammar.
+ // This could be done in the lexer module's `lex()`, but for large files,
+ // passing string arguments from C to Lua is expensive.
+ if (!lua_getfield(L, -1, "_GRAMMAR")) {
+ lua_pop(L, 2); // _GRAMMAR, lexer object
+ // Style everything in the default style.
+ styler.StartAt(startPos);
+ styler.StartSegment(startPos);
+ styler.ColourTo(startPos + lengthDoc - 1, STYLE_DEFAULT);
+ styler.Flush();
+ return;
+ } else lua_pop(L, 1); // _GRAMMAR
+
+ // Start from the beginning of the current style so LPeg matches it.
+ // For multilang lexers, start at whitespace since embedded languages have
+ // [lang]_whitespace styles. This is so LPeg can start matching child
+ // languages instead of parent ones if necessary.
+ if (startPos > 0) {
+ Sci_PositionU i = startPos;
+ while (i > 0 && styler.StyleAt(i - 1) == initStyle) i--;
+ if (multilang)
+ while (i > 0 && !ws[static_cast<size_t>(styler.StyleAt(i))]) i--;
+ lengthDoc += startPos - i, startPos = i;
+ }
- /** Destroys the lexer object. */
- void SCI_METHOD Release() override {
- if (ownLua && L)
- lua_close(L);
- else if (!ownLua) {
- lua_pushnil(L);
- lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- lua_pushnil(L), lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ if (lua_getfield(L, -1, "lex") != LUA_TFUNCTION)
+ 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) + 1);
+ if (lua_pcall(L, 3, 1, -5) != LUA_OK) return LogError(L);
+ if (!lua_istable(L, -1))
+ 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) {
+ int style = STYLE_DEFAULT;
+ styler.StartAt(startPos);
+ styler.StartSegment(startPos);
+ lua_getfield(L, -3, "_TOKENSTYLES");
+ // Loop through token-position pairs.
+ for (int i = 1; i < len; i += 2) {
+ style = STYLE_DEFAULT;
+ if (lua_rawgeti(L, -2, i), lua_rawget(L, -2))
+ style = lua_tointeger(L, -1) - 1;
+ lua_pop(L, 1); // _TOKENSTYLES[token]
+ lua_rawgeti(L, -2, i + 1); // pos
+ unsigned int position = lua_tointeger(L, -1) - 1;
+ 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), LogError(L);
+ if (position > startPos + lengthDoc) break;
}
- delete this;
+ lua_pop(L, 1); // _TOKENSTYLES
+ styler.ColourTo(startPos + lengthDoc - 1, style);
+ styler.Flush();
}
+ lua_pop(L, 3); // token table returned, lua_error_handler, lexer object
+ ASSERT_STACK_TOP(L);
+}
- /**
- * Lexes the Scintilla document.
- * @param startPos The position in the document to start lexing at.
- * @param lengthDoc The number of bytes in the document to lex.
- * @param initStyle The initial style at position *startPos* in the document.
- * @param buffer The document interface.
- */
- void SCI_METHOD Lex(
- Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle,
- IDocument *buffer) override
- {
- LexAccessor styler(buffer);
- if ((reinit && !Init()) || !L) {
- // Style everything in the default style.
- styler.StartAt(startPos);
- styler.StartSegment(startPos);
- styler.ColourTo(startPos + lengthDoc - 1, STYLE_DEFAULT);
- styler.Flush();
- return;
- }
+void SCI_METHOD LexerLPeg::Fold(
+ Sci_PositionU startPos, Sci_Position lengthDoc, int, IDocument *buffer)
+{
+ if ((reinit && !Init()) || !L) return;
+ RECORD_STACK_TOP(L);
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(buffer));
+ lua_setfield(L, -2, "_BUFFER");
+ LexAccessor styler(buffer);
+
+ if (lua_getfield(L, -1, "fold") != LUA_TFUNCTION)
+ 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);
+ lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
+ lua_pushinteger(L, startPos + 1);
+ lua_pushinteger(L, currentLine + 1);
+ lua_pushinteger(L, styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK);
+ if (lua_pcall(L, 5, 1, -7) != LUA_OK) return LogError(L);
+ if (!lua_istable(L, -1))
+ 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
+ styler.SetLevel(lua_tointeger(L, -2) - 1, lua_tointeger(L, -1));
+ lua_pop(L, 1); // level
+ }
+ lua_pop(L, 3); // fold table returned, lua_error_handler, lexer object
+ ASSERT_STACK_TOP(L);
+}
+
+Sci_Position SCI_METHOD LexerLPeg::PropertySet(
+ const char *key, const char *value)
+{
+ props.Set(key, value, strlen(key), strlen(value));
+ if (strcmp(key, LexerHomeKey) == 0 && lexerNames.empty())
+ ReadLexerNames(value); // not using SCI_LOADLEXERLIBRARY private call
+ if (reinit &&
+ (strcmp(key, LexerHomeKey) == 0 || strcmp(key, LexerNameKey) == 0))
+ Init();
+ else if (L && SS && sci && strncmp(key, "style.", 6) == 0) {
+ // The container is managing styles manually.
RECORD_STACK_TOP(L);
lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
- lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- lua_pushlightuserdata(L, reinterpret_cast<void *>(buffer));
- lua_setfield(L, -2, "_BUFFER");
-
- // Ensure the lexer has a grammar.
- // This could be done in the lexer module's `lex()`, but for large files,
- // passing string arguments from C to Lua is expensive.
- if (!lua_getfield(L, -1, "_GRAMMAR")) {
- lua_pop(L, 2); // _GRAMMAR, lexer object
- // Style everything in the default style.
- styler.StartAt(startPos);
- styler.StartSegment(startPos);
- styler.ColourTo(startPos + lengthDoc - 1, STYLE_DEFAULT);
- styler.Flush();
- return;
- } else lua_pop(L, 1); // _GRAMMAR
-
- // Start from the beginning of the current style so LPeg matches it.
- // For multilang lexers, start at whitespace since embedded languages have
- // [lang]_whitespace styles. This is so LPeg can start matching child
- // languages instead of parent ones if necessary.
- if (startPos > 0) {
- Sci_PositionU i = startPos;
- while (i > 0 && styler.StyleAt(i - 1) == initStyle) i--;
- if (multilang)
- while (i > 0 && !ws[static_cast<size_t>(styler.StyleAt(i))]) i--;
- lengthDoc += startPos - i, startPos = i;
- }
-
- if (lua_getfield(L, -1, "lex") != LUA_TFUNCTION)
- 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) + 1);
- if (lua_pcall(L, 3, 1, -5) != LUA_OK) return LogError(L);
- if (!lua_istable(L, -1))
- 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) {
- int style = STYLE_DEFAULT;
- styler.StartAt(startPos);
- styler.StartSegment(startPos);
- lua_getfield(L, -3, "_TOKENSTYLES");
- // Loop through token-position pairs.
- for (int i = 1; i < len; i += 2) {
- style = STYLE_DEFAULT;
- if (lua_rawgeti(L, -2, i), lua_rawget(L, -2))
- style = lua_tointeger(L, -1) - 1;
- lua_pop(L, 1); // _TOKENSTYLES[token]
- lua_rawgeti(L, -2, i + 1); // pos
- unsigned int position = lua_tointeger(L, -1) - 1;
- 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), LogError(L);
- if (position > startPos + lengthDoc) break;
+ if (lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this))) {
+ lua_getfield(L, -1, "_TOKENSTYLES");
+ lua_pushstring(L, key + 6);
+ if (lua_rawget(L, -2) == LUA_TNUMBER) {
+ lua_pushstring(L, key), expand_property(L);
+ int style_num = lua_tointeger(L, -2) - 1;
+ SetStyle(style_num, lua_tostring(L, -1));
+ if (style_num == STYLE_DEFAULT)
+ // Assume a theme change, with the default style being set first.
+ // Subsequent style settings will be based on the default.
+ SS(sci, SCI_STYLECLEARALL, 0, 0);
+ lua_pop(L, 1); // style
}
- lua_pop(L, 1); // _TOKENSTYLES
- styler.ColourTo(startPos + lengthDoc - 1, style);
- styler.Flush();
+ lua_pop(L, 2); // style number, _TOKENSTYLES
}
- lua_pop(L, 3); // token table returned, lua_error_handler, lexer object
+ lua_pop(L, 1); // lexer object or nil
ASSERT_STACK_TOP(L);
}
+ return -1; // no need to re-lex
+}
- /**
- * Folds the Scintilla document.
- * @param startPos The position in the document to start folding at.
- * @param lengthDoc The number of bytes in the document to fold.
- * @param initStyle The initial style at position *startPos* in the document.
- * @param buffer The document interface.
- */
- void SCI_METHOD Fold(
- Sci_PositionU startPos, Sci_Position lengthDoc, int, IDocument *buffer)
- override
- {
- if ((reinit && !Init()) || !L) return;
+void * SCI_METHOD LexerLPeg::PrivateCall(int code, void *arg) {
+ auto lParam = reinterpret_cast<sptr_t>(arg);
+ switch(code) {
+ case SCI_GETDIRECTFUNCTION:
+ SS = reinterpret_cast<SciFnDirect>(lParam);
+ return nullptr;
+ case SCI_SETDOCPOINTER:
+ sci = lParam;
+ return nullptr;
+ case SCI_CHANGELEXERSTATE:
+ if (ownLua) lua_close(L);
+ L = reinterpret_cast<lua_State *>(arg), ownLua = false;
+ return nullptr;
+ case SCI_LOADLEXERLIBRARY: {
+ const char *path = reinterpret_cast<const char*>(arg);
+ 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 : lexerNames) names << name << '\n';
+ return StringResult(lParam, names.str().c_str());
+ } case SCI_SETLEXERLANGUAGE:
+ if (strcmp(
+ props.Get(LexerNameKey),
+ reinterpret_cast<const char *>(arg)) != 0) {
+ reinit = true;
+ PropertySet(LexerErrorKey, "");
+ PropertySet(LexerNameKey, reinterpret_cast<const char *>(arg));
+ } else if (L)
+ ownLua ? SetStyles() : static_cast<void>(Init());
+ return nullptr;
+ case SCI_GETLEXERLANGUAGE: {
+ if (!L) return StringResult(lParam, "null");
RECORD_STACK_TOP(L);
- lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- lua_pushlightuserdata(L, reinterpret_cast<void *>(buffer));
- lua_setfield(L, -2, "_BUFFER");
- LexAccessor styler(buffer);
-
- if (lua_getfield(L, -1, "fold") != LUA_TFUNCTION)
- 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);
- lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
- lua_pushinteger(L, startPos + 1);
- lua_pushinteger(L, currentLine + 1);
- lua_pushinteger(L, styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK);
- if (lua_pcall(L, 5, 1, -7) != LUA_OK) return LogError(L);
- if (!lua_istable(L, -1))
- 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
- styler.SetLevel(lua_tointeger(L, -2) - 1, lua_tointeger(L, -1));
- lua_pop(L, 1); // level
- }
- lua_pop(L, 3); // fold table returned, lua_error_handler, lexer object
+ lua_getfield(L, -1, "_NAME");
+ std::string val(lua_tostring(L, -1));
+ lua_pop(L, 2); // lexer name, lexer object
ASSERT_STACK_TOP(L);
- }
-
- /**
- * Sets the *key* lexer property to *value*.
- * If *key* starts with "style.", also set the style for the token.
- * @param key The string property key.
- * @param val The string value.
- */
- Sci_Position SCI_METHOD PropertySet(
- const char *key, const char *value) override
- {
- props.Set(key, value, strlen(key), strlen(value));
- if (strcmp(key, LexerHomeKey) == 0 && lexerNames.empty())
- ReadLexerNames(value); // not using SCI_LOADLEXERLIBRARY private call
- if (reinit &&
- (strcmp(key, LexerHomeKey) == 0 || strcmp(key, LexerNameKey) == 0))
- Init();
- else if (L && SS && sci && strncmp(key, "style.", 6) == 0) {
- // The container is managing styles manually.
- RECORD_STACK_TOP(L);
- lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
- if (lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this))) {
- lua_getfield(L, -1, "_TOKENSTYLES");
- lua_pushstring(L, key + 6);
- if (lua_rawget(L, -2) == LUA_TNUMBER) {
- lua_pushstring(L, key), expand_property(L);
- int style_num = lua_tointeger(L, -2) - 1;
- SetStyle(style_num, lua_tostring(L, -1));
- if (style_num == STYLE_DEFAULT)
- // Assume a theme change, with the default style being set first.
- // Subsequent style settings will be based on the default.
- SS(sci, SCI_STYLECLEARALL, 0, 0);
- lua_pop(L, 1); // style
- }
- lua_pop(L, 2); // style number, _TOKENSTYLES
- }
- lua_pop(L, 1); // lexer object or nil
- ASSERT_STACK_TOP(L);
- }
- return -1; // no need to re-lex
- }
-
- /**
- * Allows for direct communication between the application and the lexer.
- * The application uses this to set `SS`, `sci`, `L`, and lexer properties,
- * and to retrieve style names.
- * @param code The communication code.
- * @param arg The argument.
- * @return void *data
- */
- void * SCI_METHOD PrivateCall(int code, void *arg) override {
- auto lParam = reinterpret_cast<sptr_t>(arg);
- switch(code) {
- case SCI_GETDIRECTFUNCTION:
- SS = reinterpret_cast<SciFnDirect>(lParam);
- return nullptr;
- case SCI_SETDOCPOINTER:
- sci = lParam;
- return nullptr;
- case SCI_CHANGELEXERSTATE:
- if (ownLua) lua_close(L);
- L = reinterpret_cast<lua_State *>(arg), ownLua = false;
- return nullptr;
- case SCI_LOADLEXERLIBRARY: {
- const char *path = reinterpret_cast<const char*>(arg);
- 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 : lexerNames) names << name << '\n';
- return StringResult(lParam, names.str().c_str());
- } case SCI_SETLEXERLANGUAGE:
- if (strcmp(
- props.Get(LexerNameKey),
- reinterpret_cast<const char *>(arg)) != 0) {
- reinit = true;
- PropertySet(LexerErrorKey, "");
- PropertySet(LexerNameKey, reinterpret_cast<const char *>(arg));
- } else if (L)
- ownLua ? SetStyles() : static_cast<void>(Init());
- return nullptr;
- case SCI_GETLEXERLANGUAGE: {
- if (!L) return StringResult(lParam, "null");
- RECORD_STACK_TOP(L);
- lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- lua_getfield(L, -1, "_NAME");
- 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 = NameOfStyle(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 (!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 = NameOfStyle(SS(sci, SCI_GETSTYLEAT, pos, 0)), *p;
+ if (name && (p = strstr(name, "_whitespace"))) {
+ val.append(name, p - name);
+ return StringResult(lParam, val.c_str());
}
- val.append(val, 0, val.length() - 1); // "lexer/lexer" fallback
- return StringResult(lParam, val.c_str());
- } case SCI_GETNAMEDSTYLES:
- if (!L) return reinterpret_cast<void *>(STYLE_DEFAULT);
- for (int i = 0; i < STYLE_MAX; i++)
- if (strcmp(NameOfStyle(i), reinterpret_cast<const char *>(arg)) == 0)
- return reinterpret_cast<void *>(i);
- return reinterpret_cast<void *>(STYLE_DEFAULT);
- case SCI_GETSTATUS:
- return StringResult(lParam, props.Get(LexerErrorKey));
}
- return nullptr;
+ val.append(val, 0, val.length() - 1); // "lexer/lexer" fallback
+ return StringResult(lParam, val.c_str());
+ } case SCI_GETNAMEDSTYLES:
+ if (!L) return reinterpret_cast<void *>(STYLE_DEFAULT);
+ for (int i = 0; i < STYLE_MAX; i++)
+ if (strcmp(NameOfStyle(i), reinterpret_cast<const char *>(arg)) == 0)
+ return reinterpret_cast<void *>(i);
+ return reinterpret_cast<void *>(STYLE_DEFAULT);
+ case SCI_GETSTATUS:
+ return StringResult(lParam, props.Get(LexerErrorKey));
}
+ return nullptr;
+}
- /**
- * Returns the style name for the given style number.
- * Note: the returned pointer is not guaranteed to exist after the next call
- * to `NameOfStyle()`, so its contents should be immediately copied.
- * @param style The style number to get the style name for.
- * @return style name or nullptr
- */
- const char * SCI_METHOD NameOfStyle(int style) override {
- if (style < 0 || style > STYLE_MAX || !L) return nullptr;
- RECORD_STACK_TOP(L);
- styleName = "Not Available";
- lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
- lua_getfield(L, -1, "_TOKENSTYLES");
- lua_pushnil(L);
- while (lua_next(L, -2))
- if (lua_tointeger(L, -1) - 1 == style) {
+const char * SCI_METHOD LexerLPeg::NameOfStyle(int style) {
+ if (style < 0 || style > STYLE_MAX || !L) return nullptr;
+ RECORD_STACK_TOP(L);
+ styleName = "Not Available";
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_getfield(L, -1, "_TOKENSTYLES");
+ lua_pushnil(L);
+ while (lua_next(L, -2))
+ if (lua_tointeger(L, -1) - 1 == style) {
styleName = lua_tostring(L, -2);
lua_pop(L, 2); // value and key
break;
- } else lua_pop(L, 1); // value
- lua_pop(L, 2); // _TOKENSTYLES, lexer object
- ASSERT_STACK_TOP(L);
- return styleName.c_str();
- }
+ } else lua_pop(L, 1); // value
+ lua_pop(L, 2); // _TOKENSTYLES, lexer object
+ ASSERT_STACK_TOP(L);
+ return styleName.c_str();
+}
- /**
- * Returns the lexer property for *key*.
- * @param key The string property key.
- */
- const char * SCI_METHOD PropertyGet(const char *key) override {
- return props.Get(key);
- }
+const char * SCI_METHOD LexerLPeg::PropertyGet(const char *key) {
+ return props.Get(key);
+}
- /** Constructs a new instance of the lexer. */
- static ILexer *LexerFactoryLPeg() { return new LexerLPeg(); }
-};
+ILexer *LexerLPeg::LexerFactoryLPeg() { return new LexerLPeg(); }
LexerModule lmLPeg(SCLEX_LPEG, LexerLPeg::LexerFactoryLPeg, "lpeg");