4 #include "jimautoconf.h"
11 #ifdef HAVE_SYS_STAT_H
14 #include "linenoise.h"
16 #define MAX_LINE_LEN 512
20 static void JimCompletionCallback(const char *prefix
, linenoiseCompletions
*comp
, void *userdata
);
21 static const char completion_callback_assoc_key
[] = "interactive-completion";
25 * Returns an allocated line, or NULL if EOF.
27 char *Jim_HistoryGetline(Jim_Interp
*interp
, const char *prompt
)
30 struct JimCompletionInfo
*compinfo
= Jim_GetAssocData(interp
, completion_callback_assoc_key
);
34 /* Set any completion callback just during the call to linenoise()
35 * to allow for per-interp settings
38 linenoiseSetCompletionCallback(JimCompletionCallback
, compinfo
);
40 objPtr
= Jim_GetVariableStr(interp
, "history::multiline", JIM_NONE
);
41 if (objPtr
&& Jim_GetLong(interp
, objPtr
, &mlmode
) == JIM_NONE
) {
42 linenoiseSetMultiLine(mlmode
);
45 result
= linenoise(prompt
);
46 /* unset the callback */
47 linenoiseSetCompletionCallback(NULL
, NULL
);
51 char *line
= malloc(MAX_LINE_LEN
);
53 fputs(prompt
, stdout
);
56 if (fgets(line
, MAX_LINE_LEN
, stdin
) == NULL
) {
61 if (len
&& line
[len
- 1] == '\n') {
68 void Jim_HistoryLoad(const char *filename
)
71 linenoiseHistoryLoad(filename
);
75 void Jim_HistoryAdd(const char *line
)
78 linenoiseHistoryAdd(line
);
82 void Jim_HistorySave(const char *filename
)
87 /* Just u=rw, but note that this is only effective for newly created files */
88 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
90 linenoiseHistorySave(filename
);
97 void Jim_HistoryShow(void)
100 /* built-in history command */
103 char **history
= linenoiseHistory(&len
);
104 for (i
= 0; i
< len
; i
++) {
105 printf("%4d %s\n", i
+ 1, history
[i
]);
111 struct JimCompletionInfo
{
116 static void JimCompletionCallback(const char *prefix
, linenoiseCompletions
*comp
, void *userdata
)
118 struct JimCompletionInfo
*info
= (struct JimCompletionInfo
*)userdata
;
122 objv
[0] = info
->command
;
123 objv
[1] = Jim_NewStringObj(info
->interp
, prefix
, -1);
125 ret
= Jim_EvalObjVector(info
->interp
, 2, objv
);
127 /* XXX: Consider how best to handle errors here. bgerror? */
130 Jim_Obj
*listObj
= Jim_GetResult(info
->interp
);
131 int len
= Jim_ListLength(info
->interp
, listObj
);
132 for (i
= 0; i
< len
; i
++) {
133 linenoiseAddCompletion(comp
, Jim_String(Jim_ListGetIndex(info
->interp
, listObj
, i
)));
138 static void JimHistoryFreeCompletion(Jim_Interp
*interp
, void *data
)
140 struct JimCompletionInfo
*compinfo
= data
;
142 Jim_DecrRefCount(interp
, compinfo
->command
);
149 * Sets a completion command to be used with Jim_HistoryGetline()
150 * If commandObj is NULL, deletes any existing completion command.
152 void Jim_HistorySetCompletion(Jim_Interp
*interp
, Jim_Obj
*commandObj
)
156 /* Increment now in case the existing object is the same */
157 Jim_IncrRefCount(commandObj
);
160 Jim_DeleteAssocData(interp
, completion_callback_assoc_key
);
163 struct JimCompletionInfo
*compinfo
= Jim_Alloc(sizeof(*compinfo
));
164 compinfo
->interp
= interp
;
165 compinfo
->command
= commandObj
;
167 Jim_SetAssocData(interp
, completion_callback_assoc_key
, JimHistoryFreeCompletion
, compinfo
);
172 int Jim_InteractivePrompt(Jim_Interp
*interp
)
174 int retcode
= JIM_OK
;
175 char *history_file
= NULL
;
179 home
= getenv("HOME");
180 if (home
&& isatty(STDIN_FILENO
)) {
181 int history_len
= strlen(home
) + sizeof("/.jim_history");
182 history_file
= Jim_Alloc(history_len
);
183 snprintf(history_file
, history_len
, "%s/.jim_history", home
);
184 Jim_HistoryLoad(history_file
);
187 Jim_HistorySetCompletion(interp
, Jim_NewStringObj(interp
, "tcl::autocomplete", -1));
190 printf("Welcome to Jim version %d.%d\n",
191 JIM_VERSION
/ 100, JIM_VERSION
% 100);
192 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, "1");
195 Jim_Obj
*scriptObjPtr
;
200 if (retcode
!= JIM_OK
) {
201 const char *retcodestr
= Jim_ReturnCode(retcode
);
203 if (*retcodestr
== '?') {
204 snprintf(prompt
, sizeof(prompt
) - 3, "[%d] . ", retcode
);
207 snprintf(prompt
, sizeof(prompt
) - 3, "[%s] . ", retcodestr
);
211 strcpy(prompt
, ". ");
214 scriptObjPtr
= Jim_NewStringObj(interp
, "", 0);
215 Jim_IncrRefCount(scriptObjPtr
);
220 line
= Jim_HistoryGetline(interp
, prompt
);
222 if (errno
== EINTR
) {
225 Jim_DecrRefCount(interp
, scriptObjPtr
);
229 if (Jim_Length(scriptObjPtr
) != 0) {
230 /* Line continuation */
231 Jim_AppendString(interp
, scriptObjPtr
, "\n", 1);
233 Jim_AppendString(interp
, scriptObjPtr
, line
, -1);
235 if (Jim_ScriptIsComplete(interp
, scriptObjPtr
, &state
))
238 snprintf(prompt
, sizeof(prompt
), "%c> ", state
);
241 if (strcmp(Jim_String(scriptObjPtr
), "h") == 0) {
242 /* built-in history command */
244 Jim_DecrRefCount(interp
, scriptObjPtr
);
248 Jim_HistoryAdd(Jim_String(scriptObjPtr
));
250 Jim_HistorySave(history_file
);
253 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
254 Jim_DecrRefCount(interp
, scriptObjPtr
);
256 if (retcode
== JIM_EXIT
) {
259 if (retcode
== JIM_ERR
) {
260 Jim_MakeErrorMessage(interp
);
262 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
264 fwrite(result
, reslen
, 1, stdout
);
269 Jim_Free(history_file
);