aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/view.c
diff options
context:
space:
mode:
authorRobin Haberkorn <rhaberkorn@fmsbw.de>2026-08-02 15:24:45 +0200
committerRobin Haberkorn <rhaberkorn@fmsbw.de>2026-08-11 00:38:31 +0200
commit44f5bf677282308b959411c416da2b5b08db2062 (patch)
treef350d7a16c3c3c431e2744ae321d781b27641413 /src/view.c
parent9b78fc83dbd29b5594431b1c49b7d13865141aaa (diff)
support lookups via language servers (LSP)master-fmsbw-ci
* The main interface is the `FT` command. `FT` was an undocumented Video TECO command for etags/ctags lookups. I don't want to exactly copy its interface, though. * `FT` allows looking up symbol names, definitions and references. * ctags will be supported via ctags-lsp. LSP support is more powerful though and works without regenerating TAGS files all the time. The LSP will also allow you to customize auto-completions using SciTECO itself (i.e. by writing a language server in SciTECO). * For multiple results, `FT$` can be used to cycle through results - this should mimic repeated `S$` or `N$`. * `:FT...$` does a fuzzy search. IMHO it's not important to return a status integer instead. `FT` will only really be used in interactive mode. * Document synchronization is supported via hooks from ring.c and via Scintilla notifications. * Currently, the LSP communication is based on blocking GIOChannels. This means that a misbehaving hanging server could "lock up" the entire editor (FIXME). Only on ncurses you can always kill the subprocess by pressing CTRL+C. We need helper functions in spawn.c to read and write with interruptions. * The textDocument/didChange notification transmits not only all edits, but all files' contents as well during initial synchronization. Therefore it is optimized to write and JSON-escape data without copying them around in memory and without destroying the buffer gap. * Use $SCITECO_LSP to configure the language server. You can also use `tee` to capture stdin and stdout. Perhaps $SCITECO_LSP should be saved in .teco_session, so you can change it between projects? * $SCITECO_LSP_ROOT is used to point to the project's root directory. session.tes will set it up automatically.
Diffstat (limited to 'src/view.c')
-rw-r--r--src/view.c64
1 files changed, 52 insertions, 12 deletions
diff --git a/src/view.c b/src/view.c
index 7a9e0cc..43cdd3f 100644
--- a/src/view.c
+++ b/src/view.c
@@ -47,13 +47,24 @@
#include "eol.h"
#include "memory.h"
#include "lexer.h"
+#include "ring.h"
+#include "lsp.h"
#include "view.h"
+//#define DEBUG
+
/** @memberof teco_view_t */
void
teco_view_setup(teco_view_t *ctx)
{
/*
+ * Avoid unnecessary notifications.
+ */
+ teco_view_ssm(ctx, SCI_SETCOMMANDEVENTS, FALSE, 0);
+ teco_view_ssm(ctx, SCI_SETMODEVENTMASK,
+ SC_MOD_INSERTTEXT | SC_MOD_BEFOREDELETE, 0);
+
+ /*
* Start with or without undo collection,
* depending on teco_undo_enabled.
*/
@@ -825,20 +836,49 @@ teco_view_get_character(teco_view_t *ctx, gsize pos, gsize len)
}
void
-teco_view_process_notify(teco_view_t *ctx, SCNotification *notify)
+teco_view_process_notify(teco_view_t *ctx, const SCNotification *notify)
{
#ifdef DEBUG
- g_printf("SCINTILLA NOTIFY: code=%d\n", notify->nmhdr.code);
+ g_printf("SCINTILLA NOTIFY: code=%u\n", notify->nmhdr.code);
#endif
- /*
- * Lexing in the container: only used for SciTECO.
- *
- * The "identifier" is abused to enable/disable lexing.
- * It could be extended later on for several internal lexers.
- * The alternative would be an ILexer5 wrapper, written in C++.
- */
- if (notify->nmhdr.code == SCN_STYLENEEDED &&
- teco_view_ssm(ctx, SCI_GETIDENTIFIER, 0, 0) != 0)
- teco_lexer_style(ctx, notify->position);
+ switch (notify->nmhdr.code) {
+ case SCN_STYLENEEDED:
+ /*
+ * Lexing in the container: only used for SciTECO.
+ *
+ * The "identifier" is abused to enable/disable lexing.
+ * It could be extended later on for several internal lexers.
+ * The alternative would be an ILexer5 wrapper, written in C++.
+ */
+ if (teco_view_ssm(ctx, SCI_GETIDENTIFIER, 0, 0) != 0)
+ teco_lexer_style(ctx, notify->position);
+ break;
+
+ case SCN_MODIFIED:
+#ifdef DEBUG
+ g_printf("SCINTILLA NOTIFY: modification=0x%02X\n", notify->modificationType);
+#endif
+
+ if (!teco_ring_current || ctx != teco_ring_current->view)
+ break;
+
+ if (notify->modificationType & SC_MOD_INSERTTEXT) {
+#ifdef DEBUG
+ g_printf("SCINTILLA NOTIFY: INSERT: pos=%ld, text=\"%.*s\"\n",
+ notify->position, (gint)notify->length, notify->text);
+#endif
+ teco_lsp_didchange_insert(teco_ring_current, notify->position,
+ notify->length, notify->text, NULL);
+ }
+ if (notify->modificationType & SC_MOD_BEFOREDELETE) {
+#ifdef DEBUG
+ g_printf("SCINTILLA NOTIFY: BEFORE DELETE: pos=%ld, len=%ld\n",
+ notify->position, notify->length);
+#endif
+ teco_lsp_didchange_delete(teco_ring_current, notify->position,
+ notify->length, NULL);
+ }
+ break;
+ }
}