diff options
Diffstat (limited to 'jim-interactive.c')
-rw-r--r-- | jim-interactive.c | 105 |
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; } |