Beispiel #1
0
static unsigned char
complete(EditLine *el, int ch)
{
	DIR *dd = opendir(".");
	struct dirent *dp;
	const wchar_t *ptr;
	char *buf, *bptr;
	const LineInfoW *lf = el_wline(el);
	int len, mblen, i;
	unsigned char res = 0;
	wchar_t dir[1024];

	/* Find the last word */
	for (ptr = lf->cursor -1; !iswspace(*ptr) && ptr > lf->buffer; --ptr)
		continue;
	len = lf->cursor - ++ptr;

	/* Convert last word to multibyte encoding, so we can compare to it */
	wctomb(NULL, 0); /* Reset shift state */
	mblen = MB_LEN_MAX * len + 1;
	buf = bptr = malloc(mblen);
	if (buf == NULL)
		err(1, "malloc");
	for (i = 0; i < len; ++i) {
		/* Note: really should test for -1 return from wctomb */
		bptr += wctomb(bptr, ptr[i]);
	}
	*bptr = 0; /* Terminate multibyte string */
	mblen = bptr - buf;

	/* Scan directory for matching name */
	for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
		if (mblen > strlen(dp->d_name))
			continue;
		if (strncmp(dp->d_name, buf, mblen) == 0) {
			mbstowcs(dir, &dp->d_name[mblen],
			    sizeof(dir) / sizeof(*dir));
			if (el_winsertstr(el, dir) == -1)
				res = CC_ERROR;
			else
				res = CC_REFRESH;
			break;
		}
	}

	closedir(dd);
	free(buf);
	return res;
}
Beispiel #2
0
/*
 * Complete the word at or before point,
 * 'what_to_do' says what to do with the completion.
 * \t   means do standard completion.
 * `?' means list the possible completions.
 * `*' means insert all of the possible completions.
 * `!' means to do standard completion, and list all possible completions if
 * there is more than one.
 *
 * Note: '*' support is not implemented
 *       '!' could never be invoked
 */
int
fn_complete(EditLine *el,
            char *(*complet_func)(const char *, int),
            char **(*attempted_completion_function)(const char *, int, int),
            const wchar_t *word_break, const wchar_t *special_prefixes,
            const char *(*app_func)(const char *), size_t query_items,
            int *completion_type, int *over, int *point, int *end)
{
    const LineInfoW *li;
    wchar_t *temp;
    char **matches;
    const wchar_t *ctemp;
    size_t len;
    int what_to_do = '\t';
    int retval = CC_NORM;

    if (el->el_state.lastcmd == el->el_state.thiscmd)
        what_to_do = '?';

    /* readline's rl_complete() has to be told what we did... */
    if (completion_type != NULL)
        *completion_type = what_to_do;

    if (!complet_func)
        complet_func = fn_filename_completion_function;
    if (!app_func)
        app_func = append_char_function;

    /* We now look backwards for the start of a filename/variable word */
    li = el_wline(el);
    ctemp = li->cursor;
    while (ctemp > li->buffer
            && !wcschr(word_break, ctemp[-1])
            && (!special_prefixes || !wcschr(special_prefixes, ctemp[-1]) ) )
        ctemp--;

    len = (size_t)(li->cursor - ctemp);
    temp = el_malloc((len + 1) * sizeof(*temp));
    (void)wcsncpy(temp, ctemp, len);
    temp[len] = '\0';

    /* these can be used by function called in completion_matches() */
    /* or (*attempted_completion_function)() */
    if (point != NULL)
        *point = (int)(li->cursor - li->buffer);
    if (end != NULL)
        *end = (int)(li->lastchar - li->buffer);

    if (attempted_completion_function) {
        int cur_off = (int)(li->cursor - li->buffer);
        matches = (*attempted_completion_function)(
                      ct_encode_string(temp, &el->el_scratch),
                      cur_off - (int)len, cur_off);
    } else
        matches = NULL;
    if (!attempted_completion_function ||
            (over != NULL && !*over && !matches))
        matches = completion_matches(
                      ct_encode_string(temp, &el->el_scratch), complet_func);

    if (over != NULL)
        *over = 0;

    if (matches) {
        int i;
        size_t matches_num, maxlen, match_len, match_display=1;

        retval = CC_REFRESH;
        /*
         * Only replace the completed string with common part of
         * possible matches if there is possible completion.
         */
        if (matches[0][0] != '\0') {
            el_deletestr(el, (int) len);
            el_winsertstr(el,
                          ct_decode_string(matches[0], &el->el_scratch));
        }


        if (matches[2] == NULL &&
                (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) {
            /*
             * We found exact match. Add a space after
             * it, unless we do filename completion and the
             * object is a directory.
             */
            el_winsertstr(el,
                          ct_decode_string((*app_func)(matches[0]),
                                           &el->el_scratch));
        } else if (what_to_do == '!' || what_to_do == '?') {
            /*
             * More than one match and requested to list possible
             * matches.
             */

            for(i = 1, maxlen = 0; matches[i]; i++) {
                match_len = strlen(matches[i]);
                if (match_len > maxlen)
                    maxlen = match_len;
            }
            /* matches[1] through matches[i-1] are available */
            matches_num = (size_t)(i - 1);

            /* newline to get on next line from command line */
            (void)fprintf(el->el_outfile, "\n");

            /*
             * If there are too many items, ask user for display
             * confirmation.
             */
            if (matches_num > query_items) {
                (void)fprintf(el->el_outfile,
                              "Display all %zu possibilities? (y or n) ",
                              matches_num);
                (void)fflush(el->el_outfile);
                if (getc(stdin) != 'y')
                    match_display = 0;
                (void)fprintf(el->el_outfile, "\n");
            }

            if (match_display) {
                /*
                 * Interface of this function requires the
                 * strings be matches[1..num-1] for compat.
                 * We have matches_num strings not counting
                 * the prefix in matches[0], so we need to
                 * add 1 to matches_num for the call.
                 */
                fn_display_match_list(el, matches,
                                      matches_num+1, maxlen);
            }
            retval = CC_REDISPLAY;
        } else if (matches[0][0]) {
            /*
             * There was some common match, but the name was
             * not complete enough. Next tab will print possible
             * completions.
             */
            el_beep(el);
        } else {
            /* lcd is not a valid object - further specification */
            /* is needed */
            el_beep(el);
            retval = CC_NORM;
        }

        /* free elements of array and the array itself */
        for (i = 0; matches[i]; i++)
            el_free(matches[i]);
        el_free(matches);
        matches = NULL;
    }
    el_free(temp);
    return retval;
}