Example #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;
}
Example #2
0
int
main(int argc, char *argv[])
{
	EditLine *el = NULL;
	int numc, ncontinuation;
	const wchar_t *line;
	TokenizerW *tok;
	HistoryW *hist;
	HistEventW ev;
#ifdef DEBUG
	int i;
#endif

	setlocale(LC_ALL, "");

	(void)signal(SIGINT,  sig);
	(void)signal(SIGQUIT, sig);
	(void)signal(SIGHUP,  sig);
	(void)signal(SIGTERM, sig);

	hist = history_winit();		/* Init built-in history     */
	history_w(hist, &ev, H_SETSIZE, 100);	/* Remember 100 events	     */
	history_w(hist, &ev, H_LOAD, hfile);

	tok = tok_winit(NULL);			/* Init the tokenizer	     */

	el = el_init(argv[0], stdin, stdout, stderr);

	el_wset(el, EL_EDITOR, L"vi");		/* Default editor is vi	     */
	el_wset(el, EL_SIGNAL, 1);		/* Handle signals gracefully */
	el_wset(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */

	el_wset(el, EL_HIST, history_w, hist);	/* FIXME - history_w? */

					/* Add a user-defined function	*/
	el_wset(el, EL_ADDFN, L"ed-complete", L"Complete argument", complete);

					/* Bind <tab> to it */
	el_wset(el, EL_BIND, L"^I", L"ed-complete", NULL);

	/*
	* Bind j, k in vi command mode to previous and next line, instead
	* of previous and next history.
	*/
	el_wset(el, EL_BIND, L"-a", L"k", L"ed-prev-line", NULL);
	el_wset(el, EL_BIND, L"-a", L"j", L"ed-next-line", NULL);

	/* Source the user's defaults file. */
	el_source(el, NULL);

	while((line = el_wgets(el, &numc)) != NULL && numc != 0) {
		int ac, cc, co, rc;
		const wchar_t **av;

		const LineInfoW *li;
		li = el_wline(el);

#ifdef DEBUG
		(void)fwprintf(stderr, L"==> got %d %ls", numc, line);
		(void)fwprintf(stderr, L"  > li `%.*ls_%.*ls'\n",
		    (li->cursor - li->buffer), li->buffer,
		    (li->lastchar - 1 - li->cursor),
		    (li->cursor >= li->lastchar) ? L"" : li->cursor);
#endif

		if (gotsig) {
			(void)fprintf(stderr, "Got signal %d.\n", gotsig);
			gotsig = 0;
			el_reset(el);
		}

		if(!continuation && numc == 1)
			continue;	/* Only got a linefeed */

		ac = cc = co = 0;
		ncontinuation = tok_wline(tok, li, &ac, &av, &cc, &co);
		if (ncontinuation < 0) {
			(void) fprintf(stderr, "Internal error\n");
			continuation = 0;
			continue;
		}

#ifdef DEBUG
		(void)fprintf(stderr, "  > nc %d ac %d cc %d co %d\n",
			ncontinuation, ac, cc, co);
#endif
		history_w(hist, &ev, continuation ? H_APPEND : H_ENTER, line);

		continuation = ncontinuation;
		ncontinuation = 0;
		if(continuation)
			continue;

#ifdef DEBUG
		for (i = 0; i < ac; ++i) {
			(void)fwprintf(stderr, L"  > arg# %2d ", i);
			if (i != cc)
				(void)fwprintf(stderr, L"`%ls'\n", av[i]);
			else
				(void)fwprintf(stderr, L"`%.*ls_%ls'\n",
				    co, av[i], av[i] + co);
		}
#endif

		if (wcscmp (av[0], L"history") == 0) {
			switch(ac) {
			case 1:
				for(rc = history_w(hist, &ev, H_LAST);
				     rc != -1;
				     rc = history_w(hist, &ev, H_PREV))
					(void)fwprintf(stdout, L"%4d %ls",
					     ev.num, ev.str);
				break;
			case 2:
				if (wcscmp(av[1], L"clear") == 0)
					history_w(hist, &ev, H_CLEAR);
				else
					goto badhist;
				break;
			case 3:
				if (wcscmp(av[1], L"load") == 0)
					history_w(hist, &ev, H_LOAD,
					    my_wcstombs(av[2]));
				else if (wcscmp(av[1], L"save") == 0)
					history_w(hist, &ev, H_SAVE,
					    my_wcstombs(av[2]));
				else
					goto badhist;
				break;
			badhist:
			default:
				(void)fprintf(stderr,
				    "Bad history arguments\n");
				break;
			}
		} else if (el_wparse(el, ac, av) == -1) {
			switch (fork()) {
			case 0: {
				Tokenizer *ntok = tok_init(NULL);
				int nargc;
				const char **nav;
				tok_str(ntok, my_wcstombs(line), &nargc, &nav);
				execvp(nav[0],(char **)nav);
				perror(nav[0]);
				_exit(1);
				/* NOTREACHED */
				break;
			}
			case -1:
				perror("fork");
				break;
			default:
				if (wait(&rc) == -1)
					perror("wait");
				(void)fprintf(stderr, "Exit %x\n", rc);
				break;
			}
		}

		tok_wreset(tok);
	}

	el_end(el);
	tok_wend(tok);
	history_w(hist, &ev, H_SAVE, hfile);
	history_wend(hist);

	fprintf(stdout, "\n");
	return 0;
}
Example #3
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;
}