aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/jtclsh.tcl2
-rw-r--r--jim-history.c15
-rw-r--r--jim-interactive.c70
-rw-r--r--jim.h3
4 files changed, 72 insertions, 18 deletions
diff --git a/examples/jtclsh.tcl b/examples/jtclsh.tcl
index b384717..772b327 100644
--- a/examples/jtclsh.tcl
+++ b/examples/jtclsh.tcl
@@ -8,6 +8,8 @@ package require history
set histfile [env HOME]/.jtclsh
history load $histfile
+# Use the standard Tcl autocompletion
+history completion tcl::autocomplete
set prefix ""
while {1} {
# Read a complete line (script)
diff --git a/jim-history.c b/jim-history.c
index 9a56e04..fe6e628 100644
--- a/jim-history.c
+++ b/jim-history.c
@@ -9,7 +9,7 @@
static int history_cmd_getline(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr;
- char *line = Jim_HistoryGetline(Jim_String(argv[0]));
+ char *line = Jim_HistoryGetline(interp, Jim_String(argv[0]));
/* On EOF returns -1 if varName was specified; otherwise the empty string. */
if (line == NULL) {
@@ -35,6 +35,12 @@ static int history_cmd_getline(Jim_Interp *interp, int argc, Jim_Obj *const *arg
return JIM_OK;
}
+static int history_cmd_setcompletion(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_HistorySetCompletion(interp, Jim_Length(argv[0]) ? argv[0] : NULL);
+ return JIM_OK;
+}
+
static int history_cmd_load(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_HistoryLoad(Jim_String(argv[0]));
@@ -67,6 +73,13 @@ static const jim_subcmd_type history_command_table[] = {
2,
/* Description: Reads one line from the user. Similar to gets. */
},
+ { "completion",
+ "command",
+ history_cmd_setcompletion,
+ 1,
+ 1,
+ /* Description: Sets an autocompletion callback command, or none if "" */
+ },
{ "load",
"filename",
history_cmd_load,
diff --git a/jim-interactive.c b/jim-interactive.c
index 8a18092..8a163c8 100644
--- a/jim-interactive.c
+++ b/jim-interactive.c
@@ -16,13 +16,29 @@
#define MAX_LINE_LEN 512
#endif
+#ifdef USE_LINENOISE
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
+static const char completion_callback_assoc_key[] = "interactive-completion";
+#endif
+
/**
* Returns an allocated line, or NULL if EOF.
*/
-char *Jim_HistoryGetline(const char *prompt)
+char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
{
#ifdef USE_LINENOISE
- return linenoise(prompt);
+ struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
+ char *result;
+ /* Set any completion callback just during the call to linenoise()
+ * to allow for per-interp settings
+ */
+ if (compinfo) {
+ linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
+ }
+ result = linenoise(prompt);
+ /* unset the callback */
+ linenoiseSetCompletionCallback(NULL, NULL);
+ return result;
#else
int len;
char *line = malloc(MAX_LINE_LEN);
@@ -90,7 +106,7 @@ struct JimCompletionInfo {
Jim_Obj *command;
};
-void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
{
struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
Jim_Obj *objv[2];
@@ -111,15 +127,47 @@ void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void
}
}
}
+
+static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
+{
+ struct JimCompletionInfo *compinfo = data;
+
+ Jim_DecrRefCount(interp, compinfo->command);
+
+ Jim_Free(compinfo);
+}
#endif
+/**
+ * Sets a completion command to be used with Jim_HistoryGetline()
+ * If commandObj is NULL, deletes any existing completion command.
+ */
+void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj)
+{
+#ifdef USE_LINENOISE
+ if (commandObj) {
+ /* Increment now in case the existing object is the same */
+ Jim_IncrRefCount(commandObj);
+ }
+
+ Jim_DeleteAssocData(interp, completion_callback_assoc_key);
+
+ if (commandObj) {
+ struct JimCompletionInfo *compinfo = Jim_Alloc(sizeof(*compinfo));
+ compinfo->interp = interp;
+ compinfo->command = commandObj;
+
+ Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
+ }
+#endif
+}
+
int Jim_InteractivePrompt(Jim_Interp *interp)
{
int retcode = JIM_OK;
char *history_file = NULL;
#ifdef USE_LINENOISE
const char *home;
- struct JimCompletionInfo compinfo;
home = getenv("HOME");
if (home && isatty(STDIN_FILENO)) {
@@ -129,12 +177,7 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
Jim_HistoryLoad(history_file);
}
- compinfo.interp = interp;
- compinfo.command = Jim_NewStringObj(interp, "tcl::autocomplete", -1);
- Jim_IncrRefCount(compinfo.command);
-
- /* Register a callback function for tab-completion. */
- linenoiseSetCompletionCallback(JimCompletionCallback, &compinfo);
+ Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
#endif
printf("Welcome to Jim version %d.%d\n",
@@ -167,7 +210,7 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
char state;
char *line;
- line = Jim_HistoryGetline(prompt);
+ line = Jim_HistoryGetline(interp, prompt);
if (line == NULL) {
if (errno == EINTR) {
continue;
@@ -217,10 +260,5 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
out:
Jim_Free(history_file);
-#ifdef USE_LINENOISE
- Jim_DecrRefCount(interp, compinfo.command);
- linenoiseSetCompletionCallback(NULL, NULL);
-#endif
-
return retcode;
}
diff --git a/jim.h b/jim.h
index 9338f86..bf8acb2 100644
--- a/jim.h
+++ b/jim.h
@@ -880,7 +880,8 @@ JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
JIM_EXPORT void Jim_HistoryLoad(const char *filename);
JIM_EXPORT void Jim_HistorySave(const char *filename);
-JIM_EXPORT char *Jim_HistoryGetline(const char *prompt);
+JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
+JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj);
JIM_EXPORT void Jim_HistoryAdd(const char *line);
JIM_EXPORT void Jim_HistoryShow(void);