autocomplete: add global $tcl::autocomplete_commands
[jimtcl.git] / jim-interactive.c
blob932e8e112313f74f4734592f5f3d0d768011b426
1 #include <errno.h>
2 #include <string.h>
4 #include "jimautoconf.h"
5 #include <jim.h>
7 #ifdef USE_LINENOISE
8 #ifdef HAVE_UNISTD_H
9 #include <unistd.h>
10 #include <sys/stat.h>
11 #endif
12 #include "linenoise.h"
13 #else
14 #define MAX_LINE_LEN 512
15 #endif
17 /**
18 * Returns an allocated line, or NULL if EOF.
20 char *Jim_HistoryGetline(const char *prompt)
22 #ifdef USE_LINENOISE
23 return linenoise(prompt);
24 #else
25 int len;
26 char *line = malloc(MAX_LINE_LEN);
28 fputs(prompt, stdout);
29 fflush(stdout);
31 if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
32 free(line);
33 return NULL;
35 len = strlen(line);
36 if (len && line[len - 1] == '\n') {
37 line[len - 1] = '\0';
39 return line;
40 #endif
43 void Jim_HistoryLoad(const char *filename)
45 #ifdef USE_LINENOISE
46 linenoiseHistoryLoad(filename);
47 #endif
50 void Jim_HistoryAdd(const char *line)
52 #ifdef USE_LINENOISE
53 linenoiseHistoryAdd(line);
54 #endif
57 void Jim_HistorySave(const char *filename)
59 #ifdef USE_LINENOISE
60 mode_t mask;
61 /* Just u=rw, but note that this is only effective for newly created files */
62 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
63 linenoiseHistorySave(filename);
64 mask = umask(mask);
65 #endif
68 void Jim_HistoryShow(void)
70 #ifdef USE_LINENOISE
71 /* built-in history command */
72 int i;
73 int len;
74 char **history = linenoiseHistory(&len);
75 for (i = 0; i < len; i++) {
76 printf("%4d %s\n", i + 1, history[i]);
78 #endif
81 #ifdef USE_LINENOISE
82 struct JimCompletionInfo {
83 Jim_Interp *interp;
84 Jim_Obj *command;
87 void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
89 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
90 Jim_Obj *objv[2];
92 objv[0] = info->command;
93 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
95 int ret = Jim_EvalObjVector(info->interp, 2, objv);
97 /* XXX: Consider how best to handle errors here. bgerror? */
98 if (ret == JIM_OK) {
99 int i;
100 Jim_Obj *listObj = Jim_GetResult(info->interp);
101 int len = Jim_ListLength(info->interp, listObj);
102 for (i = 0; i < len; i++) {
103 linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
107 #endif
109 int Jim_InteractivePrompt(Jim_Interp *interp)
111 int retcode = JIM_OK;
112 char *history_file = NULL;
113 #ifdef USE_LINENOISE
114 const char *home;
115 struct JimCompletionInfo compinfo;
117 home = getenv("HOME");
118 if (home && isatty(STDIN_FILENO)) {
119 int history_len = strlen(home) + sizeof("/.jim_history");
120 history_file = Jim_Alloc(history_len);
121 snprintf(history_file, history_len, "%s/.jim_history", home);
122 Jim_HistoryLoad(history_file);
125 compinfo.interp = interp;
126 compinfo.command = Jim_NewStringObj(interp, "tcl::autocomplete", -1);
127 Jim_IncrRefCount(compinfo.command);
129 /* Register a callback function for tab-completion. */
130 linenoiseSetCompletionCallback(JimCompletionCallback, &compinfo);
131 #endif
133 printf("Welcome to Jim version %d.%d\n",
134 JIM_VERSION / 100, JIM_VERSION % 100);
135 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
137 while (1) {
138 Jim_Obj *scriptObjPtr;
139 const char *result;
140 int reslen;
141 char prompt[20];
143 if (retcode != JIM_OK) {
144 const char *retcodestr = Jim_ReturnCode(retcode);
146 if (*retcodestr == '?') {
147 snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
149 else {
150 snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
153 else {
154 strcpy(prompt, ". ");
157 scriptObjPtr = Jim_NewStringObj(interp, "", 0);
158 Jim_IncrRefCount(scriptObjPtr);
159 while (1) {
160 char state;
161 char *line;
163 line = Jim_HistoryGetline(prompt);
164 if (line == NULL) {
165 if (errno == EINTR) {
166 continue;
168 Jim_DecrRefCount(interp, scriptObjPtr);
169 retcode = JIM_OK;
170 goto out;
172 if (Jim_Length(scriptObjPtr) != 0) {
173 /* Line continuation */
174 Jim_AppendString(interp, scriptObjPtr, "\n", 1);
176 Jim_AppendString(interp, scriptObjPtr, line, -1);
177 free(line);
178 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
179 break;
181 snprintf(prompt, sizeof(prompt), "%c> ", state);
183 #ifdef USE_LINENOISE
184 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
185 /* built-in history command */
186 Jim_HistoryShow();
187 Jim_DecrRefCount(interp, scriptObjPtr);
188 continue;
191 Jim_HistoryAdd(Jim_String(scriptObjPtr));
192 if (history_file) {
193 Jim_HistorySave(history_file);
195 #endif
196 retcode = Jim_EvalObj(interp, scriptObjPtr);
197 Jim_DecrRefCount(interp, scriptObjPtr);
199 if (retcode == JIM_EXIT) {
200 break;
202 if (retcode == JIM_ERR) {
203 Jim_MakeErrorMessage(interp);
205 result = Jim_GetString(Jim_GetResult(interp), &reslen);
206 if (reslen) {
207 printf("%s\n", result);
210 out:
211 Jim_Free(history_file);
213 #ifdef USE_LINENOISE
214 Jim_DecrRefCount(interp, compinfo.command);
215 linenoiseSetCompletionCallback(NULL, NULL);
216 #endif
218 return retcode;