summaryrefslogtreecommitdiff
path: root/jim-interactive.c
diff options
context:
space:
mode:
Diffstat (limited to 'jim-interactive.c')
-rw-r--r--jim-interactive.c105
1 files changed, 102 insertions, 3 deletions
diff --git a/jim-interactive.c b/jim-interactive.c
index 78f5470..baad909 100644
--- a/jim-interactive.c
+++ b/jim-interactive.c
@@ -8,18 +8,44 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef HAVE_SYS_STAT_H
+ #include <sys/stat.h>
+#endif
#include "linenoise.h"
#else
#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;
+ Jim_Obj *objPtr;
+ long mlmode = 0;
+ /* Set any completion callback just during the call to linenoise()
+ * to allow for per-interp settings
+ */
+ if (compinfo) {
+ linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
+ }
+ objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
+ if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
+ linenoiseSetMultiLine(mlmode);
+ }
+
+ result = linenoise(prompt);
+ /* unset the callback */
+ linenoiseSetCompletionCallback(NULL, NULL);
+ return result;
#else
int len;
char *line = malloc(MAX_LINE_LEN);
@@ -56,7 +82,15 @@ void Jim_HistoryAdd(const char *line)
void Jim_HistorySave(const char *filename)
{
#ifdef USE_LINENOISE
+#ifdef HAVE_UMASK
+ mode_t mask;
+ /* Just u=rw, but note that this is only effective for newly created files */
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
linenoiseHistorySave(filename);
+#ifdef HAVE_UMASK
+ umask(mask);
+#endif
#endif
}
@@ -73,6 +107,68 @@ void Jim_HistoryShow(void)
#endif
}
+#ifdef USE_LINENOISE
+struct JimCompletionInfo {
+ Jim_Interp *interp;
+ Jim_Obj *command;
+};
+
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
+{
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+ Jim_Obj *objv[2];
+ int ret;
+
+ objv[0] = info->command;
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+
+ ret = Jim_EvalObjVector(info->interp, 2, objv);
+
+ /* XXX: Consider how best to handle errors here. bgerror? */
+ if (ret == JIM_OK) {
+ int i;
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
+ int len = Jim_ListLength(info->interp, listObj);
+ for (i = 0; i < len; i++) {
+ linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
+ }
+ }
+}
+
+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;
@@ -87,6 +183,8 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
snprintf(history_file, history_len, "%s/.jim_history", home);
Jim_HistoryLoad(history_file);
}
+
+ Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
#endif
printf("Welcome to Jim version %d.%d\n",
@@ -119,7 +217,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;
@@ -168,5 +266,6 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
}
out:
Jim_Free(history_file);
+
return retcode;
}