Jim Tcl
Check-in [bc78c3f08b]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:history: Add autocompletion support

With 'history completion <cmd>'

Signed-off-by: Steve Bennett <steveb@workware.net.au>

Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:bc78c3f08b18a387d0fe5dcb8ed68e2431f75823
User & Date: steveb@workware.net.au 2017-09-15 02:11:33
Context
2017-09-15
02:12
docs: Update documentation for recent changes

Add aio sockopt Add history completion Remove aio tcp_nodelay

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 954bfa31a8 user: steveb@workware.net.au tags: trunk

02:11
history: Add autocompletion support

With 'history completion <cmd>'

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: bc78c3f08b user: steveb@workware.net.au tags: trunk

02:11
aio: Add support for many socket options

Add aio sockopt to get and set various socket options via setsockopt()/getsockopt()

And remove 'aio tcp_nodelay' in favour of 'aio sockopt tcp_nodelay'

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 05177bba18 user: steveb@workware.net.au tags: trunk

Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to examples/jtclsh.tcl.

4
5
6
7
8
9
10


11
12
13
14
15
16
17
# Build jimsh with the history extension and enable line editing (the default)
# ./configure --with-ext=history

package require history

set histfile [env HOME]/.jtclsh
history load $histfile


set prefix ""
while {1} {
	# Read a complete line (script)
	set prompt "${prefix}jim> "
	set cmd {}
	while {1} {
		if {[history getline $prompt line] < 0} {







>
>







4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Build jimsh with the history extension and enable line editing (the default)
# ./configure --with-ext=history

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)
	set prompt "${prefix}jim> "
	set cmd {}
	while {1} {
		if {[history getline $prompt line] < 0} {

Changes to jim-history.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
30
31
32
33
34
35
36






37
38
39
40
41
42
43
..
63
64
65
66
67
68
69







70
71
72
73
74
75
76
#include "jim.h"
#include "jimautoconf.h"
#include "jim-subcmd.h"

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]));

    /* On EOF returns -1 if varName was specified; otherwise the empty string. */
    if (line == NULL) {
        if (argc == 2) {
            Jim_SetResultInt(interp, -1);
        }
        return JIM_OK;
................................................................................
        Jim_SetResultInt(interp, Jim_Length(objPtr));
    }
    else {
        Jim_SetResult(interp, objPtr);
    }
    return JIM_OK;
}







static int history_cmd_load(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_HistoryLoad(Jim_String(argv[0]));
    return JIM_OK;
}

................................................................................
    {   "getline",
        "prompt ?varname?",
        history_cmd_getline,
        1,
        2,
        /* Description: Reads one line from the user. Similar to gets. */
    },







    {   "load",
        "filename",
        history_cmd_load,
        1,
        1,
        /* Description: Loads history from the given file, if possible */
    },







|







 







>
>
>
>
>
>







 







>
>
>
>
>
>
>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "jim.h"
#include "jimautoconf.h"
#include "jim-subcmd.h"

static int history_cmd_getline(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *objPtr;
    char *line = Jim_HistoryGetline(interp, Jim_String(argv[0]));

    /* On EOF returns -1 if varName was specified; otherwise the empty string. */
    if (line == NULL) {
        if (argc == 2) {
            Jim_SetResultInt(interp, -1);
        }
        return JIM_OK;
................................................................................
        Jim_SetResultInt(interp, Jim_Length(objPtr));
    }
    else {
        Jim_SetResult(interp, objPtr);
    }
    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]));
    return JIM_OK;
}

................................................................................
    {   "getline",
        "prompt ?varname?",
        history_cmd_getline,
        1,
        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,
        1,
        1,
        /* Description: Loads history from the given file, if possible */
    },

Changes to jim-interactive.c.

12
13
14
15
16
17
18





19
20
21
22
23
24








25



26
27
28
29
30
31
32
..
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
107
108
109
110
111
112
113









114
























115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    #include <sys/stat.h>
#endif
#include "linenoise.h"
#else
#define MAX_LINE_LEN 512
#endif






/**
 * Returns an allocated line, or NULL if EOF.
 */
char *Jim_HistoryGetline(const char *prompt)
{
#ifdef USE_LINENOISE








    return linenoise(prompt);



#else
    int len;
    char *line = malloc(MAX_LINE_LEN);

    fputs(prompt, stdout);
    fflush(stdout);

................................................................................

#ifdef USE_LINENOISE
struct JimCompletionInfo {
    Jim_Interp *interp;
    Jim_Obj *command;
};

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);
................................................................................
        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)));
        }
    }
}









#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)) {
        int history_len = strlen(home) + sizeof("/.jim_history");
        history_file = Jim_Alloc(history_len);
        snprintf(history_file, history_len, "%s/.jim_history", home);
        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);
#endif

    printf("Welcome to Jim version %d.%d\n",
        JIM_VERSION / 100, JIM_VERSION % 100);
    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");

    while (1) {
................................................................................

        scriptObjPtr = Jim_NewStringObj(interp, "", 0);
        Jim_IncrRefCount(scriptObjPtr);
        while (1) {
            char state;
            char *line;

            line = Jim_HistoryGetline(prompt);
            if (line == NULL) {
                if (errno == EINTR) {
                    continue;
                }
                Jim_DecrRefCount(interp, scriptObjPtr);
                retcode = JIM_OK;
                goto out;
................................................................................
        if (reslen) {
            printf("%s\n", result);
        }
    }
  out:
    Jim_Free(history_file);

#ifdef USE_LINENOISE
    Jim_DecrRefCount(interp, compinfo.command);
    linenoiseSetCompletionCallback(NULL, NULL);
#endif

    return retcode;
}







>
>
>
>
>



|


>
>
>
>
>
>
>
>
|
>
>
>







 







|







 







>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







<









<
|
<
<
<
<







 







|







 







<
<
<
<
<


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179

180




181
182
183
184
185
186
187
...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
256
257
258
259
260
261
262





263
264
    #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(Jim_Interp *interp, const char *prompt)
{
#ifdef USE_LINENOISE
    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);

    fputs(prompt, stdout);
    fflush(stdout);

................................................................................

#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);
................................................................................
        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;
    char *history_file = NULL;
#ifdef USE_LINENOISE
    const char *home;


    home = getenv("HOME");
    if (home && isatty(STDIN_FILENO)) {
        int history_len = strlen(home) + sizeof("/.jim_history");
        history_file = Jim_Alloc(history_len);
        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",
        JIM_VERSION / 100, JIM_VERSION % 100);
    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");

    while (1) {
................................................................................

        scriptObjPtr = Jim_NewStringObj(interp, "", 0);
        Jim_IncrRefCount(scriptObjPtr);
        while (1) {
            char state;
            char *line;

            line = Jim_HistoryGetline(interp, prompt);
            if (line == NULL) {
                if (errno == EINTR) {
                    continue;
                }
                Jim_DecrRefCount(interp, scriptObjPtr);
                retcode = JIM_OK;
                goto out;
................................................................................
        if (reslen) {
            printf("%s\n", result);
        }
    }
  out:
    Jim_Free(history_file);






    return retcode;
}

Changes to jim.h.

876
877
878
879
880
881
882
883

884
885
886
887
888
889
890
/* error messages */
JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);

/* interactive mode */
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 void Jim_HistoryAdd(const char *line);
JIM_EXPORT void Jim_HistoryShow(void);

/* Misc */
JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
JIM_EXPORT int Jim_IsBigEndian(void);







|
>







876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
/* error messages */
JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);

/* interactive mode */
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(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);

/* Misc */
JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
JIM_EXPORT int Jim_IsBigEndian(void);