aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--doc/sciteco.1.in6
-rw-r--r--doc/sciteco.7.template11
-rw-r--r--src/error.h9
-rw-r--r--src/symbols.c108
5 files changed, 124 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index 72fc56d..41c0a05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -126,7 +126,7 @@ AC_SUBST(DOXYGEN_HAVE_DOT)
AC_CHECK_PROG(SCITECO, sciteco, sciteco)
# Checks for libraries.
-PKG_CHECK_MODULES(LIBGLIB, [glib-2.0 >= 2.44], [
+PKG_CHECK_MODULES(LIBGLIB, [glib-2.0 >= 2.44 gmodule-2.0], [
CFLAGS="$CFLAGS $LIBGLIB_CFLAGS"
CXXFLAGS="$CXXFLAGS $LIBGLIB_CFLAGS"
LIBS="$LIBS $LIBGLIB_LIBS"
diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in
index 82c1a47..2b3d3bf 100644
--- a/doc/sciteco.1.in
+++ b/doc/sciteco.1.in
@@ -289,6 +289,12 @@ on Windows.
On all other platforms (including UNIX/Linux) this variable
defaults to the standard library installation path at
.BR "@scitecolibdir@" .
+.TP
+.SCITECO_TOPIC "$SCITECO_SCINTILLUA_LEXERS"
+.B SCITECO_SCINTILLUA_LEXERS
+The Scintillua \(lqlexers/\(rq directory.
+This is passed as the \(lqscintillua.lexers\(rq library property when
+loading a Scintillua lexer via the \fBSCI_SETILEXER\fP Scintilla message.
.
.LP
The \fBHOME\fP, \fBSCITECOCONFIG\fP and \fBSCITECOPATH\fP environment
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index 8c049ee..053a5cb 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -2383,9 +2383,14 @@ Scintilla messages and other documentation:
Scintilla
.UE
.TP
-Scinterm manual, documenting the mapping of \(lqRGB\(rq values to terminal colors on curses user interfaces:
-.UR http://foicica.com/scinterm/manual.html
-Scinterm manual
+Scinterm website, documenting the mapping of \(lqRGB\(rq values to terminal colors on curses user interfaces:
+.UR https://orbitalquark.github.io/scinterm/
+Scinterm website
+.UE
+.TP
+Scintillua manual, detailing usage of Lua-based Scintilla lexers:
+.UR https://orbitalquark.github.io/scintillua/manual.html
+Scintillua manual
.UE
.TP
Suitable terminal fonts for icon support in Curses (see \fBED\fP flags):
diff --git a/src/error.h b/src/error.h
index c51f528..021f759 100644
--- a/src/error.h
+++ b/src/error.h
@@ -17,6 +17,7 @@
#pragma once
#include <glib.h>
+#include <gmodule.h>
#include "sciteco.h"
#include "string-utils.h"
@@ -53,6 +54,7 @@ typedef enum {
TECO_ERROR_MEMLIMIT,
TECO_ERROR_CLIPBOARD,
TECO_ERROR_WIN32,
+ TECO_ERROR_MODULE,
/** Interrupt current operation */
TECO_ERROR_INTERRUPTED,
@@ -165,6 +167,13 @@ teco_error_win32_set(GError **error, const gchar *prefix, gint err)
#endif
static inline void
+teco_error_module_set(GError **error, const gchar *prefix)
+{
+ g_set_error(error, TECO_ERROR, TECO_ERROR_MODULE, "%s: %s",
+ prefix, g_module_error());
+}
+
+static inline void
teco_error_interrupted_set(GError **error)
{
g_set_error_literal(error, TECO_ERROR, TECO_ERROR_INTERRUPTED, "Interrupted");
diff --git a/src/symbols.c b/src/symbols.c
index 944d01d..7198639 100644
--- a/src/symbols.c
+++ b/src/symbols.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <glib.h>
+#include <gmodule.h>
#include <Scintilla.h>
#ifdef HAVE_LEXILLA
@@ -288,6 +289,27 @@ gboolean teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx,
* Lexilla lexer name as a string argument for the \fBSCI_SETILEXER\fP
* message, i.e. in order to load a Lexilla lexer
* (this works similar to the old \fBSCI_SETLEXERLANGUAGE\fP message).
+ * If the lexer name contains a null-byte, the second string
+ * argument is split into two:
+ * Up until the null-byte, the path of an external lexer library
+ * (shared library or DLL) is expected,
+ * that implements the Lexilla protocol.
+ * The \(lq.so\(rq or \(lq.dll\(rq extension is optional.
+ * The concrete lexer name is the remaining of the string after
+ * the null-byte.
+ * This allows you to use lexers from external lexer libraries
+ * like Scintillua.
+ * When detecting Scintillua, \*(ST will automatically pass down
+ * the \fBSCITECO_SCINTILLUA_LEXERS\fP environment variable as
+ * the \(lqscintillua.lexers\(rq library property for specifying
+ * the location of Scintillua's Lua lexer files.
+ *
+ * In order to facilitate the use of Scintillua lexers, the semantics
+ * of \fBSCI_NAMEOFSTYLE\fP have also been changed.
+ * Instead of returning the name for a given style id, it now
+ * returns the style id when given the name of a style in the
+ * second string argument of \fBES\fP, i.e. it allows you
+ * to look up style ids by name.
*
* .BR Warning :
* Almost all Scintilla messages may be dispatched using
@@ -321,24 +343,94 @@ teco_state_scintilla_lparam_done(teco_machine_main_t *ctx, const teco_string_t *
sptr_t lParam = 0;
-#ifdef HAVE_LEXILLA
- if (ctx->scintilla.iMessage == SCI_SETILEXER) {
+ if (ctx->scintilla.iMessage == SCI_NAMEOFSTYLE) {
+ /*
+ * FIXME: This customized version of SCI_NAMEOFSTYLE could be avoided
+ * if we had a way to call Scintilla messages that return strings into
+ * Q-Registers.
+ */
if (teco_string_contains(str, '\0')) {
g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED,
- "Lexer name must not contain null-byte.");
+ "Style name must not contain null-byte.");
return NULL;
}
- const gchar *lexer = str->data ? : "";
- lParam = (sptr_t)CreateLexer(lexer);
+ /*
+ * FIXME: Should we cache the name to style id?
+ */
+ guint count = teco_interface_ssm(SCI_GETNAMEDSTYLES, 0, 0);
+ for (guint id = 0; id < count; id++) {
+ gchar style[128] = "";
+ teco_interface_ssm(SCI_NAMEOFSTYLE, id, (sptr_t)style);
+ if (!teco_string_cmp(str, style, strlen(style))) {
+ teco_expressions_push(id);
+ return &teco_state_start;
+ }
+ }
+
+ g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED,
+ "Style name \"%s\" not found.", str->data ? : "");
+ return NULL;
+ }
+#ifdef HAVE_LEXILLA
+ else if (ctx->scintilla.iMessage == SCI_SETILEXER) {
+ CreateLexerFn CreateLexerFn = CreateLexer;
+
+ const gchar *lexer = memchr(str->data ? : "", '\0', str->len);
+ if (lexer) {
+ /* external lexer */
+ lexer++;
+
+ /*
+ * NOTE: The same module can be opened multiple times.
+ * They are internally reference counted.
+ */
+ GModule *module = g_module_open(str->data, G_MODULE_BIND_LAZY);
+ if (!module) {
+ teco_error_module_set(error, "Error opening lexer module");
+ return NULL;
+ }
+
+ GetNameSpaceFn GetNameSpaceFn;
+ SetLibraryPropertyFn SetLibraryPropertyFn;
+
+ if (!g_module_symbol(module, LEXILLA_GETNAMESPACE, (gpointer *)&GetNameSpaceFn) ||
+ !g_module_symbol(module, LEXILLA_SETLIBRARYPROPERTY, (gpointer *)&SetLibraryPropertyFn) ||
+ !g_module_symbol(module, LEXILLA_CREATELEXER, (gpointer *)&CreateLexerFn)) {
+ teco_error_module_set(error, "Cannot find lexer function");
+ return NULL;
+ }
+
+ if (!g_strcmp0(GetNameSpaceFn(), "scintillua")) {
+ /*
+ * Scintillua's lexer directory must be configured before calling CreateLexer().
+ *
+ * FIXME: In Scintillua distributions, the lexers are usually contained in the
+ * same directory as the prebuilt shared libraries.
+ * Perhaps we should default scintillua.lexers to the dirname in str->data?
+ */
+ teco_qreg_t *reg = teco_qreg_table_find(&teco_qreg_table_globals, "$SCITECO_SCINTILLUA_LEXERS", 26);
+ if (reg) {
+ teco_string_t dir;
+ if (!reg->vtable->get_string(reg, &dir.data, &dir.len, NULL, error))
+ return NULL;
+ SetLibraryPropertyFn("scintillua.lexers", dir.data ? : "");
+ }
+ }
+ } else {
+ /* Lexilla lexer */
+ lexer = str->data ? : "";
+ }
+
+ lParam = (sptr_t)CreateLexerFn(lexer);
if (!lParam) {
g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED,
- "Lexilla lexer \"%s\" not found.", lexer);
+ "Lexer \"%s\" not found.", lexer);
return NULL;
}
- } else
+ }
#endif
- if (str->len > 0) {
+ else if (str->len > 0) {
/*
* NOTE: There may even be messages that read strings
* with embedded nulls.