aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README5
-rw-r--r--doc/sciteco.7.template22
-rw-r--r--src/cmdline.c149
-rw-r--r--src/file-utils.c2
-rw-r--r--src/glob.h3
-rw-r--r--src/goto-commands.c8
-rw-r--r--src/help.c6
-rw-r--r--src/interface-curses/curses-info-popup.c68
-rw-r--r--src/interface-curses/curses-info-popup.h11
-rw-r--r--src/interface-curses/interface.c74
-rw-r--r--src/interface-gtk/gtk-info-popup.c41
-rw-r--r--src/interface-gtk/gtk-label.c6
-rw-r--r--src/interface-gtk/gtk-label.h1
-rw-r--r--src/interface-gtk/interface.c44
-rw-r--r--src/interface.h4
-rw-r--r--src/parser.c5
-rw-r--r--src/parser.h32
-rw-r--r--src/qreg-commands.h7
-rw-r--r--src/qreg.c13
-rw-r--r--src/rb3str.c2
-rw-r--r--src/ring.c2
-rw-r--r--src/symbols.c8
22 files changed, 454 insertions, 59 deletions
diff --git a/README b/README
index bf0ed55..a1c7a04 100644
--- a/README
+++ b/README
@@ -44,7 +44,7 @@ master branch and between releases until version 3.0 is released.__
Features
========
-* Supports most of the [Video TECO](http://www.copters.com/teco.html) commands
+* Supports most of the [Video TECO](http://www.copters.com/teco.html) commands.
* Improved parser compared to classic TECOs, making SciTECO
more similar to other imperative languages.
* Operator precedence in arithmetic expressions and an argument stack that may be modified
@@ -57,7 +57,8 @@ Features
by the standard library `fnkeys.tes`.
In fact, all keys with printable representation and control keys can be remapped using
key macros - and they can be context-sensitive as well!
-* Scriptable mouse support via the key macro mechanism (see also `fnkeys.tes`)
+* There is scriptable mouse support via the key macro mechanism (see also `fnkeys.tes`).
+ Autocompletion popups can also be scrolled and clicked.
* Many TECO-11 features, like that most commands have a colon-modified form, string-building
characters, exotic match characters...
* Interactivity: Immediate searching (similar to search-as-you-type) and
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index 97e1fd7..95c3503 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -303,7 +303,7 @@ current parser state (see below).
.SCITECO_TOPIC ^KMOUSE
.B ^KMOUSE
Mouse event occurred.
-This may not be delivered unless bit 7 (64) is set in the
+This will not be delivered on Curses unless bit 7 (64) is set in the
\fBED\fP flags.
You can use \fBEJ\fP with negative keys to retrieve
the event type, mouse coordinates and other information
@@ -755,10 +755,12 @@ Global and local Q-Registers are not affected by command line termination.
.SS Auto Completion
.
.SCITECO_TOPIC autocomplete
-The immediate editing commands that perform auto-completions, do
+The immediate editing commands, that perform auto-completions, do
so in a manner similar to Posix shells.
Upon first invocation they try to fully or partially complete the file
name (or token).
+If the token can be fully completed, the current command or Q-Register
+specification will also usually be terminated automatically.
If no completion can be performed, the invocation will display a
list of file names (or tokens) that begin with the token to complete
in \*(ST's popup area.
@@ -770,6 +772,15 @@ of file names or tokens is displayed in the popup area.
I.e. it is possible to cycle through long lists of possible
auto-completions.
.LP
+You can also scroll through the popup area with the mouse wheel.
+Furthermore, you can click on entries in the popup area with the
+mouse in order to fully complete them.
+Often this will also automatically terminate the current command or
+Q-Register specification, just like an unambiguous completion via
+immediate editing commands.
+On Curses, mouse events are not processed unless bit 7 (64) is set
+in the \fBED\fP flags.
+.LP
When completing file names, hidden files are not considered for
completion unless a prefix of the hidden file's name has already
been typed.
@@ -789,6 +800,13 @@ file names with \(lq./\(rq.
This is useful for writing cross-platform \*(ST macros (see
.BR "FILE NAMES AND DIRECTORIES" ).
.LP
+File name completions are case-sensitive or insensitive depending
+on operating system defaults.
+On some operating systems \*(ST can determine the case-sensitivity
+of individual directories as well.
+\# Should be supported on Mac OS and newer versions of Windows,
+\# but it's still untested.
+.LP
Note that completions take place after string building and
tilde-expansion is also performed by file name completions,
so for instance both \(lq~/foo\(rq and \(lq^EQ[$HOME]/foo\(rq
diff --git a/src/cmdline.c b/src/cmdline.c
index d32df03..dde096d 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -614,7 +614,7 @@ teco_state_stringbuilding_start_process_edit_cmd(teco_machine_stringbuilding_t *
*/
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -645,6 +645,16 @@ teco_state_stringbuilding_start_process_edit_cmd(teco_machine_stringbuilding_t *
}
gboolean
+teco_state_stringbuilding_insert_completion(teco_machine_stringbuilding_t *ctx, const teco_string_t *str, GError **error)
+{
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(ctx, str->data, str->len, &str_escaped);
+ if (!str->len || !G_IS_DIR_SEPARATOR(str->data[str->len-1]))
+ teco_string_append_c(&str_escaped, ' ');
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_stringbuilding_escaped_process_edit_cmd(teco_machine_stringbuilding_t *ctx, teco_machine_t *parent_ctx,
gunichar key, GError **error)
{
@@ -684,6 +694,14 @@ teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_
}
gboolean
+teco_state_expectstring_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+ teco_state_t *stringbuilding_current = stringbuilding_ctx->parent.current;
+ return stringbuilding_current->insert_completion_cb(&stringbuilding_ctx->parent, str, error);
+}
+
+gboolean
teco_state_insert_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
@@ -778,7 +796,7 @@ teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -801,6 +819,20 @@ teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t
}
gboolean
+teco_state_expectfile_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, str->data, str->len, &str_escaped);
+ if ((!str->len || !G_IS_DIR_SEPARATOR(str->data[str->len-1])) &&
+ ctx->expectstring.nesting == 1)
+ teco_string_append_wc(&str_escaped,
+ ctx->expectstring.machine.escape_char == '{' ? '}' : ctx->expectstring.machine.escape_char);
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_expectglob_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
@@ -820,7 +852,7 @@ teco_state_expectglob_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -855,6 +887,21 @@ teco_state_expectglob_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t
}
gboolean
+teco_state_expectglob_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+
+ g_autofree gchar *pattern_escaped = teco_globber_escape_pattern(str->data);
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, pattern_escaped, strlen(pattern_escaped), &str_escaped);
+ if ((!str->len || !G_IS_DIR_SEPARATOR(str->data[str->len-1])) &&
+ ctx->expectstring.nesting == 1)
+ teco_string_append_wc(&str_escaped,
+ ctx->expectstring.machine.escape_char == '{' ? '}' : ctx->expectstring.machine.escape_char);
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
@@ -874,7 +921,7 @@ teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -898,6 +945,19 @@ teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *
}
gboolean
+teco_state_expectdir_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+
+ /*
+ * FIXME: We might terminate the command in case of leaf directories.
+ */
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, str->data, str->len, &str_escaped);
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_expectqreg_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
g_assert(ctx->expectqreg != NULL);
@@ -910,6 +970,18 @@ teco_state_expectqreg_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t
}
gboolean
+teco_state_expectqreg_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ g_assert(ctx->expectqreg != NULL);
+ /*
+ * NOTE: teco_machine_qregspec_t is private, so we downcast to teco_machine_t.
+ * Otherwise, we'd have to move this callback into qreg.c.
+ */
+ teco_state_t *expectqreg_current = ((teco_machine_t *)ctx->expectqreg)->current;
+ return expectqreg_current->insert_completion_cb((teco_machine_t *)ctx->expectqreg, str, error);
+}
+
+gboolean
teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
switch (key) {
@@ -919,7 +991,7 @@ teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -945,6 +1017,12 @@ teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_
}
gboolean
+teco_state_qregspec_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str, GError **error)
+{
+ return teco_cmdline_insert(str->data, str->len, error);
+}
+
+gboolean
teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = teco_machine_qregspec_get_stringbuilding(ctx);
@@ -967,7 +1045,7 @@ teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_m
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -985,6 +1063,17 @@ teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_m
}
gboolean
+teco_state_qregspec_string_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = teco_machine_qregspec_get_stringbuilding(ctx);
+
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, str->data, str->len, &str_escaped);
+ teco_string_append_c(&str_escaped, ']');
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_execute_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
@@ -1003,14 +1092,14 @@ teco_state_execute_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *pa
break;
/*
- * In the EC command, <TAB> completes files just like ^T
+ * In the EC command, <TAB> completes files just like ^G<TAB>.
*
* TODO: Implement shell-command completion by iterating
* executables in $PATH
*/
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -1049,7 +1138,7 @@ teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx, teco_mac
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -1075,6 +1164,17 @@ teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx, teco_mac
}
gboolean
+teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, str->data, str->len, &str_escaped);
+ teco_string_append_c(&str_escaped, ',');
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_goto_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
@@ -1094,7 +1194,7 @@ teco_state_goto_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *paren
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -1122,6 +1222,20 @@ teco_state_goto_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *paren
}
gboolean
+teco_state_goto_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, str->data, str->len, &str_escaped);
+ /*
+ * FIXME: This does not escape `,`. Cannot be escaped via ^Q currently?
+ */
+ teco_string_append_c(&str_escaped, ',');
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
+gboolean
teco_state_help_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error)
{
teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
@@ -1141,7 +1255,7 @@ teco_state_help_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *paren
if (teco_interface_popup_is_shown()) {
/* cycle through popup pages */
- teco_interface_popup_show();
+ teco_interface_popup_scroll();
return TRUE;
}
@@ -1163,6 +1277,19 @@ teco_state_help_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *paren
return stringbuilding_current->process_edit_cmd_cb(&stringbuilding_ctx->parent, &ctx->parent, key, error);
}
+gboolean
+teco_state_help_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ teco_machine_stringbuilding_t *stringbuilding_ctx = &ctx->expectstring.machine;
+
+ g_auto(teco_string_t) str_escaped;
+ teco_machine_stringbuilding_escape(stringbuilding_ctx, str->data, str->len, &str_escaped);
+ if (ctx->expectstring.nesting == 1)
+ teco_string_append_wc(&str_escaped,
+ ctx->expectstring.machine.escape_char == '{' ? '}' : ctx->expectstring.machine.escape_char);
+ return teco_cmdline_insert(str_escaped.data, str_escaped.len, error);
+}
+
/*
* Command states
*/
diff --git a/src/file-utils.c b/src/file-utils.c
index fc5e410..02816b4 100644
--- a/src/file-utils.c
+++ b/src/file-utils.c
@@ -483,7 +483,7 @@ teco_file_auto_complete(const gchar *filename, GFileTest file_test, teco_string_
strlen((gchar *)file->data), is_buffer);
}
- teco_interface_popup_show();
+ teco_interface_popup_show(filename ? strlen(filename) : 0);
}
/*
diff --git a/src/glob.h b/src/glob.h
index e3286dd..d11fbce 100644
--- a/src/glob.h
+++ b/src/glob.h
@@ -48,6 +48,7 @@ GRegex *teco_globber_compile_pattern(const gchar *pattern);
/* in cmdline.c */
gboolean teco_state_expectglob_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_expectglob_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTGLOB
@@ -58,6 +59,8 @@ gboolean teco_state_expectglob_process_edit_cmd(teco_machine_main_t *ctx, teco_m
TECO_DEFINE_STATE_EXPECTFILE(NAME, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectglob_process_edit_cmd, \
+ .insert_completion_cb = (teco_state_insert_completion_cb_t) \
+ teco_state_expectglob_insert_completion, \
##__VA_ARGS__ \
)
diff --git a/src/goto-commands.c b/src/goto-commands.c
index b87fc32..99288c1 100644
--- a/src/goto-commands.c
+++ b/src/goto-commands.c
@@ -157,7 +157,10 @@ teco_state_goto_done(teco_machine_main_t *ctx, const teco_string_t *str, GError
}
/* in cmdline.c */
-gboolean teco_state_goto_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error);
+gboolean teco_state_goto_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx,
+ gunichar chr, GError **error);
+gboolean teco_state_goto_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str,
+ GError **error);
/*$ O
* Olabel$ -- Go to label
@@ -186,7 +189,8 @@ gboolean teco_state_goto_process_edit_cmd(teco_machine_main_t *ctx, teco_machine
* terminate the command-line.
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_goto,
- .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_goto_process_edit_cmd
+ .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_goto_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_goto_insert_completion
);
/*
diff --git a/src/help.c b/src/help.c
index 886354c..a093032 100644
--- a/src/help.c
+++ b/src/help.c
@@ -314,7 +314,10 @@ teco_state_help_done(teco_machine_main_t *ctx, const teco_string_t *str, GError
}
/* in cmdline.c */
-gboolean teco_state_help_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error);
+gboolean teco_state_help_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx,
+ gunichar chr, GError **error);
+gboolean teco_state_help_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str,
+ GError **error);
/*$ "?" help
* ?[topic]$ -- Get help for topic
@@ -384,5 +387,6 @@ gboolean teco_state_help_process_edit_cmd(teco_machine_main_t *ctx, teco_machine
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_help,
.initial_cb = (teco_state_initial_cb_t)teco_state_help_initial,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_help_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_help_insert_completion,
.expectstring.string_building = FALSE
);
diff --git a/src/interface-curses/curses-info-popup.c b/src/interface-curses/curses-info-popup.c
index 9525391..e470879 100644
--- a/src/interface-curses/curses-info-popup.c
+++ b/src/interface-curses/curses-info-popup.c
@@ -200,6 +200,61 @@ teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr)
wmove(ctx->window, bar_y, cols-1);
wattron(ctx->window, A_REVERSE);
wvline(ctx->window, ' ', bar_height);
+}
+
+/**
+ * Find the entry at the given character coordinates.
+ *
+ * @param ctx The popup widget to look up
+ * @param y The pointer's Y position, relative to the popup's window
+ * @param x The pointer's X position, relative to the popup's window
+ * @return Pointer to the entry's string under the pointer or NULL.
+ * This string is owned by the popup and is only valid until the
+ * popup is cleared.
+ *
+ * @note This must match the calculations in teco_curses_info_popup_init_pad().
+ */
+const teco_string_t *
+teco_curses_info_popup_getentry(teco_curses_info_popup_t *ctx, gint y, gint x)
+{
+ int cols = getmaxx(stdscr); /**! screen width */
+ gint pad_cols; /**! entry columns */
+ gint pad_colwidth; /**! width per entry column */
+
+ /*
+ * With Unicode icons enabled, we reserve 2 characters at the beginning and one
+ * after the filename/directory.
+ * Otherwise 2 characters after the entry.
+ */
+ gint reserve = teco_ed & TECO_ED_ICONS ? 2+1 : 2;
+ pad_colwidth = MIN(ctx->longest + reserve, cols - 2);
+
+ /* pad_cols = floor((cols - 2) / pad_colwidth) */
+ pad_cols = (cols - 2) / pad_colwidth;
+
+ gint cur_col = 0;
+ for (teco_stailq_entry_t *cur = ctx->list.first; cur != NULL; cur = cur->next) {
+ teco_popup_entry_t *entry = (teco_popup_entry_t *)cur;
+ gint cur_line = cur_col/pad_cols + 1;
+
+ if (cur_line > ctx->pad_first_line+y)
+ break;
+ if (cur_line == ctx->pad_first_line+y &&
+ x > (cur_col % pad_cols)*pad_colwidth && x <= ((cur_col % pad_cols)+1)*pad_colwidth)
+ return &entry->name;
+
+ cur_col++;
+ }
+
+ return NULL;
+}
+
+void
+teco_curses_info_popup_scroll_page(teco_curses_info_popup_t *ctx)
+{
+ gint lines = getmaxy(stdscr);
+ gint pad_lines = getmaxy(ctx->pad);
+ gint popup_lines = MIN(pad_lines + 1, lines - 1);
/* progress scroll position */
ctx->pad_first_line += popup_lines - 1;
@@ -211,6 +266,19 @@ teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr)
}
void
+teco_curses_info_popup_scroll(teco_curses_info_popup_t *ctx, gint delta)
+{
+ gint lines = getmaxy(stdscr);
+ gint pad_lines = getmaxy(ctx->pad);
+ gint popup_lines = MIN(pad_lines + 1, lines - 1);
+
+ ctx->pad_first_line = MAX(ctx->pad_first_line+delta, 0);
+ if (pad_lines - ctx->pad_first_line < popup_lines - 1)
+ /* show last page */
+ ctx->pad_first_line = pad_lines - (popup_lines - 1);
+}
+
+void
teco_curses_info_popup_clear(teco_curses_info_popup_t *ctx)
{
if (ctx->window)
diff --git a/src/interface-curses/curses-info-popup.h b/src/interface-curses/curses-info-popup.h
index 96dee5a..6f2ac9a 100644
--- a/src/interface-curses/curses-info-popup.h
+++ b/src/interface-curses/curses-info-popup.h
@@ -23,6 +23,7 @@
#include <curses.h>
#include "list.h"
+#include "string-utils.h"
#include "interface.h"
typedef struct {
@@ -49,6 +50,10 @@ void teco_curses_info_popup_add(teco_curses_info_popup_t *ctx, teco_popup_entry_
const gchar *name, gsize name_len, gboolean highlight);
void teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr);
+const teco_string_t *teco_curses_info_popup_getentry(teco_curses_info_popup_t *ctx, gint y, gint x);
+void teco_curses_info_popup_scroll_page(teco_curses_info_popup_t *ctx);
+void teco_curses_info_popup_scroll(teco_curses_info_popup_t *ctx, gint delta);
+
static inline bool
teco_curses_info_popup_is_shown(teco_curses_info_popup_t *ctx)
{
@@ -58,8 +63,10 @@ teco_curses_info_popup_is_shown(teco_curses_info_popup_t *ctx)
static inline void
teco_curses_info_popup_noutrefresh(teco_curses_info_popup_t *ctx)
{
- if (ctx->window)
- wnoutrefresh(ctx->window);
+ if (!ctx->window)
+ return;
+ redrawwin(ctx->window);
+ wnoutrefresh(ctx->window);
}
void teco_curses_info_popup_clear(teco_curses_info_popup_t *ctx);
diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c
index 9480822..3be1001 100644
--- a/src/interface-curses/interface.c
+++ b/src/interface-curses/interface.c
@@ -356,6 +356,7 @@ static struct {
GQueue *input_queue;
teco_curses_info_popup_t popup;
+ gsize popup_prefix_len;
/**
* GError "thrown" by teco_interface_event_loop_iter().
@@ -1480,7 +1481,7 @@ teco_interface_popup_add(teco_popup_entry_type_t type, const gchar *name, gsize
}
void
-teco_interface_popup_show(void)
+teco_interface_popup_show(gsize prefix_len)
{
if (!teco_interface.cmdline_window)
/* batch mode */
@@ -1489,9 +1490,21 @@ teco_interface_popup_show(void)
short fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0));
short bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0));
+ teco_interface.popup_prefix_len = prefix_len;
teco_curses_info_popup_show(&teco_interface.popup, SCI_COLOR_ATTR(fg, bg));
}
+void
+teco_interface_popup_scroll(void)
+{
+ if (!teco_interface.cmdline_window)
+ /* batch mode */
+ return;
+
+ teco_curses_info_popup_scroll_page(&teco_interface.popup);
+ teco_interface_popup_show(teco_interface.popup_prefix_len);
+}
+
gboolean
teco_interface_popup_is_shown(void)
{
@@ -1583,6 +1596,11 @@ teco_interface_refresh(void)
teco_view_noutrefresh(teco_interface_current_view);
wnoutrefresh(teco_interface.msg_window);
wnoutrefresh(teco_interface.cmdline_window);
+ /*
+ * FIXME: Why do we have to redrawwin() the popup window
+ * to keep it on the screen?
+ * Perhaps something is causing a redraw of the entire Scinterm view.
+ */
teco_curses_info_popup_noutrefresh(&teco_interface.popup);
doupdate();
}
@@ -1596,20 +1614,59 @@ teco_interface_refresh(void)
(BUTTON1_##X | BUTTON2_##X | BUTTON3_##X | BUTTON4_##X | BUTTON5_##X)
static gboolean
-teco_interface_getmouse(void)
+teco_interface_getmouse(GError **error)
{
MEVENT event;
- WINDOW *current = teco_view_get_window(teco_interface_current_view);
+
+ if (getmouse(&event) != OK)
+ return TRUE;
+
+ if (teco_curses_info_popup_is_shown(&teco_interface.popup) &&
+ wmouse_trafo(teco_interface.popup.window, &event.y, &event.x, FALSE)) {
+ /*
+ * NOTE: Not all curses variants report the RELEASED event,
+ * but may also return REPORT_MOUSE_POSITION.
+ * So we might react to all button presses as well.
+ */
+ if (event.bstate & (BUTTON1_RELEASED | REPORT_MOUSE_POSITION)) {
+ teco_machine_t *machine = &teco_cmdline.machine.parent;
+ const teco_string_t *insert = teco_curses_info_popup_getentry(&teco_interface.popup, event.y, event.x);
+
+ if (insert && machine->current->insert_completion_cb) {
+ /* successfully clicked popup item */
+ const teco_string_t insert_suffix = {insert->data + teco_interface.popup_prefix_len,
+ insert->len - teco_interface.popup_prefix_len};
+ if (!machine->current->insert_completion_cb(machine, &insert_suffix, error))
+ return FALSE;
+
+ teco_interface_popup_clear();
+ teco_interface_msg_clear();
+ teco_interface_cmdline_update(&teco_cmdline);
+ }
+
+ return TRUE;
+ }
+ if (event.bstate & BUTTON_NUM(4))
+ teco_curses_info_popup_scroll(&teco_interface.popup, -1);
+ else if (event.bstate & BUTTON_NUM(5))
+ teco_curses_info_popup_scroll(&teco_interface.popup, +1);
+
+ short fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0));
+ short bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0));
+ teco_curses_info_popup_show(&teco_interface.popup, SCI_COLOR_ATTR(fg, bg));
+
+ return TRUE;
+ }
/*
* Return mouse coordinates relative to the view.
* They will be in characters, but that's what SCI_POSITIONFROMPOINT
* expects on Scinterm anyway.
*/
- if (getmouse(&event) != OK ||
- !wmouse_trafo(current, &event.y, &event.x, FALSE))
+ WINDOW *current = teco_view_get_window(teco_interface_current_view);
+ if (!wmouse_trafo(current, &event.y, &event.x, FALSE))
/* no event inside of current view */
- return FALSE;
+ return TRUE;
/*
* NOTE: There will only be one of the button bits
@@ -1654,7 +1711,7 @@ teco_interface_getmouse(void)
if (event.bstate & BUTTON_ALT)
teco_mouse.mods |= TECO_MOUSE_ALT;
- return TRUE;
+ return teco_cmdline_keymacro("MOUSE", -1, error);
}
#endif /* NCURSES_MOUSE_VERSION >= 2 */
@@ -1789,8 +1846,7 @@ teco_interface_event_loop_iter(void)
#if NCURSES_MOUSE_VERSION >= 2
case KEY_MOUSE:
/* ANY of the mouse events */
- if (teco_interface_getmouse() &&
- !teco_cmdline_keymacro("MOUSE", -1, error))
+ if (!teco_interface_getmouse(error))
return;
break;
#endif
diff --git a/src/interface-gtk/gtk-info-popup.c b/src/interface-gtk/gtk-info-popup.c
index 29a1fa9..b9ca41c 100644
--- a/src/interface-gtk/gtk-info-popup.c
+++ b/src/interface-gtk/gtk-info-popup.c
@@ -53,6 +53,8 @@ struct _TecoGtkInfoPopup {
gboolean frozen;
};
+static guint teco_gtk_info_popup_clicked_signal;
+
static gboolean teco_gtk_info_popup_scroll_event(GtkWidget *widget, GdkEventScroll *event);
static void teco_gtk_info_popup_show(GtkWidget *widget);
static void teco_gtk_info_popup_vadjustment_changed(GtkAdjustment *vadjustment, GtkWidget *scrollbar);
@@ -82,6 +84,31 @@ teco_gtk_info_popup_class_init(TecoGtkInfoPopupClass *klass)
GTK_WIDGET_CLASS(klass)->scroll_event = teco_gtk_info_popup_scroll_event;
GTK_WIDGET_CLASS(klass)->show = teco_gtk_info_popup_show;
G_OBJECT_CLASS(klass)->finalize = teco_gtk_info_popup_finalize;
+
+ teco_gtk_info_popup_clicked_signal =
+ g_signal_new("clicked", G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_ULONG);
+}
+
+static void
+teco_gtk_info_popup_activated_cb(GtkFlowBox *box, GtkFlowBoxChild *child, gpointer user_data)
+{
+ TecoGtkInfoPopup *popup = TECO_GTK_INFO_POPUP(user_data);
+
+ /*
+ * Find the TecoGtkLabel in the flow box child.
+ */
+ GtkWidget *hbox = gtk_bin_get_child(GTK_BIN(child));
+ g_autoptr(GList) child_list = gtk_container_get_children(GTK_CONTAINER(hbox));
+ GList *entry;
+ for (entry = child_list; entry != NULL && !TECO_IS_GTK_LABEL(entry->data); entry = g_list_next(entry));
+ g_assert(entry != NULL);
+ const teco_string_t *str = teco_gtk_label_get_text(TECO_GTK_LABEL(entry->data));
+
+ g_signal_emit(popup, teco_gtk_info_popup_clicked_signal, 0,
+ str->data, (gulong)str->len);
}
static void
@@ -106,6 +133,8 @@ teco_gtk_info_popup_init(TecoGtkInfoPopup *self)
G_CALLBACK(teco_gtk_info_popup_vadjustment_changed), scrollbar);
self->flow_box = gtk_flow_box_new();
+ g_signal_connect(self->flow_box, "child-activated",
+ G_CALLBACK(teco_gtk_info_popup_activated_cb), self);
/* take as little height as necessary */
gtk_orientable_set_orientation(GTK_ORIENTABLE(self->flow_box),
GTK_ORIENTATION_HORIZONTAL);
@@ -311,12 +340,6 @@ teco_gtk_info_popup_idle_add(TecoGtkInfoPopup *self, teco_popup_entry_type_t typ
gtk_widget_set_halign(label, GTK_ALIGN_START);
gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
- /*
- * FIXME: This makes little sense once we've got mouse support.
- * But for the time being, it's a useful setting.
- */
- gtk_label_set_selectable(GTK_LABEL(label), TRUE);
-
switch (type) {
case TECO_POPUP_PLAIN:
gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_START);
@@ -417,12 +440,10 @@ teco_gtk_info_popup_scroll_page(TecoGtkInfoPopup *self)
* Adjust this so only complete entries are shown.
* Effectively, this rounds down to the line height.
*/
- GList *child_list = gtk_container_get_children(GTK_CONTAINER(self->flow_box));
- if (child_list) {
+ g_autoptr(GList) child_list = gtk_container_get_children(GTK_CONTAINER(self->flow_box));
+ if (child_list)
new_value -= (gint)new_value %
gtk_widget_get_allocated_height(GTK_WIDGET(child_list->data));
- g_list_free(child_list);
- }
/* clip to the maximum possible value */
new_value = MIN(new_value, gtk_adjustment_get_upper(adj));
diff --git a/src/interface-gtk/gtk-label.c b/src/interface-gtk/gtk-label.c
index ebbb40e..ef370a2 100644
--- a/src/interface-gtk/gtk-label.c
+++ b/src/interface-gtk/gtk-label.c
@@ -269,3 +269,9 @@ teco_gtk_label_set_text(TecoGtkLabel *self, const gchar *str, gssize len)
gtk_label_set_text(GTK_LABEL(self), plaintext);
}
+
+const teco_string_t *
+teco_gtk_label_get_text(TecoGtkLabel *self)
+{
+ return &self->string;
+}
diff --git a/src/interface-gtk/gtk-label.h b/src/interface-gtk/gtk-label.h
index e852104..c52d073 100644
--- a/src/interface-gtk/gtk-label.h
+++ b/src/interface-gtk/gtk-label.h
@@ -27,6 +27,7 @@ G_DECLARE_FINAL_TYPE(TecoGtkLabel, teco_gtk_label, TECO, GTK_LABEL, GtkLabel)
GtkWidget *teco_gtk_label_new(const gchar *str, gssize len);
void teco_gtk_label_set_text(TecoGtkLabel *self, const gchar *str, gssize len);
+const teco_string_t *teco_gtk_label_get_text(TecoGtkLabel *self);
void teco_gtk_label_parse_string(const gchar *str, gssize len,
PangoColor *fg, guint16 fg_alpha,
diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c
index ed9271b..9c740a6 100644
--- a/src/interface-gtk/interface.c
+++ b/src/interface-gtk/interface.c
@@ -70,6 +70,8 @@ static void teco_interface_size_allocate_cb(GtkWidget *widget,
gpointer user_data);
static gboolean teco_interface_input_cb(GtkWidget *widget, GdkEvent *event,
gpointer user_data);
+static void teco_interface_popup_clicked_cb(GtkWidget *popup, gchar *str, gulong len,
+ gpointer user_data);
static gboolean teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event,
gpointer user_data);
static gboolean teco_interface_sigterm_handler(gpointer user_data) G_GNUC_UNUSED;
@@ -194,6 +196,7 @@ static struct {
GtkIMContext *input_method;
GtkWidget *popup_widget;
+ gsize popup_prefix_len;
GtkWidget *current_view_widget;
@@ -381,6 +384,8 @@ teco_interface_init(void)
*/
teco_interface.popup_widget = teco_gtk_info_popup_new();
gtk_widget_set_name(teco_interface.popup_widget, "sciteco-info-popup");
+ g_signal_connect(teco_interface.popup_widget, "clicked",
+ G_CALLBACK(teco_interface_popup_clicked_cb), NULL);
gtk_overlay_add_overlay(GTK_OVERLAY(overlay_widget), teco_interface.popup_widget);
g_signal_connect(overlay_widget, "get-child-position",
G_CALLBACK(teco_gtk_info_popup_get_position_in_overlay), NULL);
@@ -754,12 +759,16 @@ teco_interface_popup_add(teco_popup_entry_type_t type, const gchar *name, gsize
}
void
-teco_interface_popup_show(void)
+teco_interface_popup_show(gsize prefix_len)
+{
+ teco_interface.popup_prefix_len = prefix_len;
+ gtk_widget_show(teco_interface.popup_widget);
+}
+
+void
+teco_interface_popup_scroll(void)
{
- if (gtk_widget_get_visible(teco_interface.popup_widget))
- teco_gtk_info_popup_scroll_page(TECO_GTK_INFO_POPUP(teco_interface.popup_widget));
- else
- gtk_widget_show(teco_interface.popup_widget);
+ teco_gtk_info_popup_scroll_page(TECO_GTK_INFO_POPUP(teco_interface.popup_widget));
}
gboolean
@@ -1349,7 +1358,6 @@ static gboolean
teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
static gboolean recursed = FALSE;
- g_autoptr(GError) error = NULL;
#ifdef DEBUG
if (event->type == GDK_KEY_PRESS)
@@ -1393,6 +1401,8 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
GdkWindow *top_window = gdk_window_get_toplevel(gtk_widget_get_window(teco_interface.window));
do {
+ g_autoptr(GError) error = NULL;
+
/*
* The event queue might be filled when pressing keys when SciTECO
* is busy executing code.
@@ -1461,6 +1471,28 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
return TRUE;
}
+static void
+teco_interface_popup_clicked_cb(GtkWidget *popup, gchar *str, gulong len, gpointer user_data)
+{
+ g_assert(len >= teco_interface.popup_prefix_len);
+ const teco_string_t insert = {str+teco_interface.popup_prefix_len, len-teco_interface.popup_prefix_len};
+ teco_machine_t *machine = &teco_cmdline.machine.parent;
+
+ const teco_view_t *last_view = teco_interface_current_view;
+
+ /*
+ * NOTE: It shouldn't really be necessary to catch TECO_ERROR_QUIT here.
+ * A auto completion should never result in program termination.
+ */
+ if (machine->current->insert_completion_cb &&
+ !machine->current->insert_completion_cb(machine, &insert, NULL))
+ return;
+ teco_interface_popup_clear();
+ teco_interface_cmdline_update(&teco_cmdline);
+
+ teco_interface_refresh(teco_interface_current_view != last_view);
+}
+
static gboolean
teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer user_data)
{
diff --git a/src/interface.h b/src/interface.h
index 967f14d..33b094b 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -132,7 +132,9 @@ typedef enum {
void teco_interface_popup_add(teco_popup_entry_type_t type,
const gchar *name, gsize name_len, gboolean highlight);
/** @pure */
-void teco_interface_popup_show(void);
+void teco_interface_popup_show(gsize prefix_len);
+/** @pure */
+void teco_interface_popup_scroll(void);
/** @pure */
gboolean teco_interface_popup_is_shown(void);
/** @pure */
diff --git a/src/parser.c b/src/parser.c
index c17186e..295c635 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -447,11 +447,14 @@ teco_state_stringbuilding_start_input(teco_machine_stringbuilding_t *ctx, gunich
/* in cmdline.c */
gboolean teco_state_stringbuilding_start_process_edit_cmd(teco_machine_stringbuilding_t *ctx, teco_machine_t *parent_ctx,
gunichar key, GError **error);
+gboolean teco_state_stringbuilding_insert_completion(teco_machine_stringbuilding_t *ctx, const teco_string_t *str, GError **error);
TECO_DEFINE_STATE(teco_state_stringbuilding_start,
.is_start = TRUE,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)
- teco_state_stringbuilding_start_process_edit_cmd
+ teco_state_stringbuilding_start_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)
+ teco_state_stringbuilding_insert_completion
);
static teco_state_t *
diff --git a/src/parser.h b/src/parser.h
index f8bae90..fe8e764 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -110,6 +110,7 @@ typedef gboolean (*teco_state_refresh_cb_t)(teco_machine_t *ctx, GError **error)
typedef gboolean (*teco_state_end_of_macro_cb_t)(teco_machine_t *ctx, GError **error);
typedef gboolean (*teco_state_process_edit_cmd_cb_t)(teco_machine_t *ctx, teco_machine_t *parent_ctx,
gunichar key, GError **error);
+typedef gboolean (*teco_state_insert_completion_cb_t)(teco_machine_t *ctx, const teco_string_t *str, GError **error);
typedef enum {
TECO_KEYMACRO_MASK_START = (1 << 0),
@@ -187,6 +188,19 @@ struct teco_state_t {
teco_state_process_edit_cmd_cb_t process_edit_cmd_cb;
/**
+ * Insert completion after clicking an entry in the popup
+ * window.
+ *
+ * All implementations of this method are currently
+ * defined in cmdline.c.
+ *
+ * It can be NULL if not required.
+ *
+ * @fixme Perhaps move all implementations to interface.c.
+ */
+ teco_state_insert_completion_cb_t insert_completion_cb;
+
+ /**
* Whether this state is a start state (i.e. not within any
* escape sequence etc.).
* This is separate of TECO_KEYMACRO_MASK_START which is set
@@ -241,11 +255,12 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent
#define TECO_DEFINE_STATE(NAME, ...) \
/** @ingroup states */ \
teco_state_t NAME = { \
- .initial_cb = NULL, /* do nothing */ \
+ .initial_cb = NULL, /* do nothing */ \
.input_cb = (teco_state_input_cb_t)NAME##_input, /* always required */ \
- .refresh_cb = NULL, /* do nothing */ \
+ .refresh_cb = NULL, /* do nothing */ \
.end_of_macro_cb = teco_state_end_of_macro, \
.process_edit_cmd_cb = teco_state_process_edit_cmd, \
+ .insert_completion_cb = NULL, /* do nothing */ \
.is_start = FALSE, \
.keymacro_mask = TECO_KEYMACRO_MASK_DEFAULT, \
.style = SCE_SCITECO_DEFAULT, \
@@ -552,7 +567,10 @@ teco_state_t *teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar c
gboolean teco_state_expectstring_refresh(teco_machine_main_t *ctx, GError **error);
/* in cmdline.c */
-gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx,
+ gunichar key, GError **error);
+gboolean teco_state_expectstring_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str,
+ GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTSTRING
@@ -577,6 +595,8 @@ gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco
.refresh_cb = (teco_state_refresh_cb_t)teco_state_expectstring_refresh, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectstring_process_edit_cmd, \
+ .insert_completion_cb = (teco_state_insert_completion_cb_t) \
+ teco_state_expectstring_insert_completion, \
.keymacro_mask = TECO_KEYMACRO_MASK_STRING, \
.style = SCE_SCITECO_STRING, \
.expectstring.string_building = TRUE, \
@@ -591,6 +611,7 @@ gboolean teco_state_expectfile_process(teco_machine_main_t *ctx, const teco_stri
/* in cmdline.c */
gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_expectfile_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTFILE
@@ -601,12 +622,15 @@ gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_m
TECO_DEFINE_STATE_EXPECTSTRING(NAME, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectfile_process_edit_cmd, \
+ .insert_completion_cb = (teco_state_insert_completion_cb_t) \
+ teco_state_expectfile_insert_completion, \
.expectstring.process_cb = teco_state_expectfile_process, \
##__VA_ARGS__ \
)
/* in cmdline.c */
gboolean teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_expectdir_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str, GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTDIR
@@ -617,5 +641,7 @@ gboolean teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_ma
TECO_DEFINE_STATE_EXPECTFILE(NAME, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectdir_process_edit_cmd, \
+ .insert_completion_cb = (teco_state_insert_completion_cb_t) \
+ teco_state_expectdir_insert_completion, \
##__VA_ARGS__ \
)
diff --git a/src/qreg-commands.h b/src/qreg-commands.h
index be31f23..6dbd1c4 100644
--- a/src/qreg-commands.h
+++ b/src/qreg-commands.h
@@ -37,7 +37,10 @@ gboolean teco_state_expectqreg_initial(teco_machine_main_t *ctx, GError **error)
teco_state_t *teco_state_expectqreg_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
/* in cmdline.c */
-gboolean teco_state_expectqreg_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_expectqreg_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx,
+ gunichar key, GError **error);
+gboolean teco_state_expectqreg_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str,
+ GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTQREG
@@ -56,6 +59,8 @@ gboolean teco_state_expectqreg_process_edit_cmd(teco_machine_main_t *ctx, teco_m
.initial_cb = (teco_state_initial_cb_t)teco_state_expectqreg_initial, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectqreg_process_edit_cmd, \
+ .insert_completion_cb = (teco_state_insert_completion_cb_t) \
+ teco_state_expectqreg_insert_completion, \
.style = SCE_SCITECO_QREG, \
.expectqreg.type = TECO_QREG_REQUIRED, \
.expectqreg.got_register_cb = NAME##_got_register, /* always required */ \
diff --git a/src/qreg.c b/src/qreg.c
index 68c8db8..4beea74 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -1445,11 +1445,15 @@ teco_state_qregspec_start_input(teco_machine_qregspec_t *ctx, gunichar chr, GErr
}
/* in cmdline.c */
-gboolean teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx,
+ gunichar key, GError **error);
+gboolean teco_state_qregspec_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str,
+ GError **error);
TECO_DEFINE_STATE(teco_state_qregspec_start,
.is_start = TRUE,
- .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd
+ .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_qregspec_insert_completion
);
static teco_state_t *
@@ -1585,9 +1589,12 @@ teco_state_qregspec_string_input(teco_machine_qregspec_t *ctx, gunichar chr, GEr
/* in cmdline.c */
gboolean teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ctx, teco_machine_t *parent_ctx,
gunichar key, GError **error);
+gboolean teco_state_qregspec_string_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str,
+ GError **error);
TECO_DEFINE_STATE(teco_state_qregspec_string,
- .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_string_process_edit_cmd
+ .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_string_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_qregspec_string_insert_completion
);
/** @static @memberof teco_machine_qregspec_t */
diff --git a/src/rb3str.c b/src/rb3str.c
index e43b6ba..276b624 100644
--- a/src/rb3str.c
+++ b/src/rb3str.c
@@ -143,7 +143,7 @@ teco_rb3str_auto_complete(teco_rb3str_tree_t *tree, gboolean case_sensitive,
cur->key.data, cur->key.len, FALSE);
}
- teco_interface_popup_show();
+ teco_interface_popup_show(str_len);
}
return prefixed_entries == 1;
diff --git a/src/ring.c b/src/ring.c
index 319d3c8..2c235af 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -413,7 +413,7 @@ teco_state_edit_file_initial(teco_machine_main_t *ctx, GError **error)
strlen(filename), cur == teco_ring_current);
}
- teco_interface_popup_show();
+ teco_interface_popup_show(0);
} else if (id > 0) {
allow_filename = FALSE;
if (!teco_current_doc_undo_edit(error) ||
diff --git a/src/symbols.c b/src/symbols.c
index 17e0b29..7dcc601 100644
--- a/src/symbols.c
+++ b/src/symbols.c
@@ -155,7 +155,7 @@ teco_symbol_list_auto_complete(teco_symbol_list_t *ctx, const gchar *symbol, tec
strlen(entry->data), FALSE);
}
- teco_interface_popup_show();
+ teco_interface_popup_show(symbol_len);
}
return glist_len == 1;
@@ -252,7 +252,10 @@ teco_state_scintilla_symbols_done(teco_machine_main_t *ctx, const teco_string_t
}
/* in cmdline.c */
-gboolean teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
+gboolean teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx,
+ gunichar key, GError **error);
+gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx, const teco_string_t *str,
+ GError **error);
/*$ ES scintilla message
* -- Send Scintilla message
@@ -332,6 +335,7 @@ gboolean teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx,
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_scintilla_symbols,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_scintilla_symbols_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_scintilla_symbols_insert_completion,
.expectstring.last = FALSE
);