示例#1
0
/* automatic word completion - called when space/enter is pressed */
char *auto_word_complete(const char *line, int *pos)
{
	GString *result;
	const char *replace;
	char *word, *wordstart, *ret;
	int startpos;

	g_return_val_if_fail(line != NULL, NULL);
	g_return_val_if_fail(pos != NULL, NULL);

	word = get_word_at(line, *pos, &wordstart);
	startpos = (int) (wordstart-line);

	result = g_string_new(line);
	g_string_erase(result, startpos, strlen(word));

	/* check for words in autocompletion list */
	replace = wordreplace_find(word);
	if (replace == NULL) {
		ret = NULL;
		g_string_free(result, TRUE);
	} else {
		*pos = startpos+strlen(replace);

		g_string_insert(result, startpos, replace);
		ret = result->str;
		g_string_free(result, FALSE);
	}

	g_free(word);
	return ret;
}
示例#2
0
/* manual word completion - called when TAB is pressed */
char *word_complete(WINDOW_REC *window, const char *line, int *pos)
{
	static int startpos = 0, wordlen = 0;

	GString *result;
	char *word, *wordstart, *linestart, *ret;
	int want_space;

	g_return_val_if_fail(line != NULL, NULL);
	g_return_val_if_fail(pos != NULL, NULL);

	if (complist != NULL && *pos == last_line_pos &&
	    strcmp(line, last_line) == 0) {
		/* complete from old list */
		complist = complist->next != NULL ? complist->next :
			g_list_first(complist);
		want_space = last_want_space;
	} else {
		/* get new completion list */
		free_completions();

		/* get the word we want to complete */
		word = get_word_at(line, *pos, &wordstart);
		startpos = (int) (wordstart-line);
		wordlen = strlen(word);

		/* get the start of line until the word we're completing */
		if (isseparator(*line)) {
			/* empty space at the start of line */
			if (wordstart == line)
				wordstart += strlen(wordstart);
		} else {
			while (wordstart > line && isseparator(wordstart[-1]))
				wordstart--;
		}
		linestart = g_strndup(line, (int) (wordstart-line));

		/* completions usually add space after the word, that makes
		   things a bit harder. When continuing a completion
		   "/msg nick1 "<tab> we have to cycle to nick2, etc.
		   BUT if we start completion with "/msg "<tab>, we don't
		   want to complete the /msg word, but instead complete empty
		   word with /msg being in linestart. */
		if (*pos > 0 && line[*pos-1] == ' ') {
			char *old;

                        old = linestart;
			linestart = *linestart == '\0' ?
				g_strdup(word) :
				g_strconcat(linestart, " ", word, NULL);
			g_free(old);

			g_free(word);
			word = g_strdup("");
			startpos = strlen(linestart)+1;
			wordlen = 0;
		}

		want_space = TRUE;
		signal_emit("complete word", 5, &complist, window, word, linestart, &want_space);
		last_want_space = want_space;

		g_free(linestart);
		g_free(word);
	}

	if (complist == NULL)
		return NULL;

	/* word completed */
	*pos = startpos+strlen(complist->data);

	/* replace the word in line - we need to return
	   a full new line */
	result = g_string_new(line);
	g_string_erase(result, startpos, wordlen);
	g_string_insert(result, startpos, complist->data);

	if (want_space) {
		if (!isseparator(result->str[*pos]))
			g_string_insert_c(result, *pos, ' ');
		(*pos)++;
	}

	wordlen = strlen(complist->data);
	last_line_pos = *pos;
	g_free_not_null(last_line);
	last_line = g_strdup(result->str);

	ret = result->str;
	g_string_free(result, FALSE);
	return ret;
}
示例#3
0
文件: completion.c 项目: irssi/irssi
/* manual word completion - called when TAB is pressed */
char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, int backward)
{
	static int startpos = 0, wordlen = 0;
        int old_startpos, old_wordlen;

	GString *result;
	const char *cmdchars;
	char *word, *wordstart, *linestart, *ret, *data;
	int continue_complete, want_space, expand_escapes;

	g_return_val_if_fail(line != NULL, NULL);
	g_return_val_if_fail(pos != NULL, NULL);

	continue_complete = complist != NULL && *pos == last_line_pos &&
		g_strcmp0(line, last_line) == 0;

	if (erase && !continue_complete)
		return NULL;

	old_startpos = startpos;
	old_wordlen = wordlen;

	if (!erase && continue_complete) {
		word = NULL;
                linestart = NULL;
	} else {
		char* old_wordstart;

		/* get the word we want to complete */
		word = get_word_at(line, *pos, &wordstart);
		old_wordstart = wordstart;

		startpos = (int) (wordstart-line);
		wordlen = strlen(word);

		/* remove trailing spaces from linestart */
		while (wordstart > line && isseparator_space(wordstart[-1]))
			wordstart--;

		/* unless everything was spaces */
		if (old_wordstart > line && wordstart == line)
			wordstart = old_wordstart - 1;

		linestart = g_strndup(line, (int) (wordstart-line));

		/* completions usually add space after the word, that makes
		   things a bit harder. When continuing a completion
		   "/msg nick1 "<tab> we have to cycle to nick2, etc.
		   BUT if we start completion with "/msg "<tab>, we don't
		   want to complete the /msg word, but instead complete empty
		   word with /msg being in linestart. */
		if (!erase && *pos > 0 && isseparator_space(line[*pos-1]) &&
		    (*linestart == '\0' || !isseparator_space(wordstart[-1]))) {
			char *old;

			old = linestart;
			/* we want to move word into linestart */
			if (*linestart == '\0') {
				linestart = g_strdup(word);
			} else {
				GString *str = g_string_new(linestart);
				if (old_wordstart[-1] != str->str[str->len - 1]) {
					/* do not accidentally duplicate the word separator */
					g_string_append_c(str, old_wordstart[-1]);
				}
				g_string_append(str, word);
				linestart = g_string_free(str, FALSE);
			}
			g_free(old);

			g_free(word);
			word = g_strdup("");

			startpos = *linestart == '\0' ? 0 :
				strlen(linestart)+1;
			wordlen = 0;
		}

	}

	if (erase) {
		signal_emit("complete erase", 3, window, word, linestart);

                /* jump to next completion */
                startpos = old_startpos;
		wordlen = old_wordlen;
	}

	if (continue_complete) {
		/* complete from old list */
		if (backward)
			complist = complist->prev != NULL ? complist->prev :
				g_list_last(complist);
		else
			complist = complist->next != NULL ? complist->next :
				g_list_first(complist);
		want_space = last_want_space;
	} else {
		int keep_word = settings_get_bool("completion_keep_word");
		/* get new completion list */
		free_completions();

		want_space = TRUE;
		signal_emit("complete word", 5, &complist, window, word, linestart, &want_space);
		last_want_space = want_space;

		if (complist != NULL) {
			/* Remove all nulls (from the signal) before doing further processing */
			complist = g_list_remove_all(g_list_first(complist), NULL);

			if (keep_word) {
				complist = g_list_append(complist, g_strdup(word));
			}

			if (backward) {
				complist = g_list_last(complist);
				if (keep_word) {
					complist = complist->prev;
				}
			}
		}
	}

	g_free(linestart);
	g_free(word);

	if (complist == NULL)
		return NULL;

        /* get the cmd char */
	cmdchars = settings_get_str("cmdchars");

	/* get the expand_escapes setting */
	expand_escapes = settings_get_bool("expand_escapes");

	/* escape if the word doesn't begin with '/' and expand_escapes are turned on */
	data = strchr(cmdchars, *line) == NULL && expand_escapes ?
		escape_string_backslashes(complist->data) : g_strdup(complist->data);

	/* word completed */
	*pos = startpos + strlen(data);

	/* replace the word in line - we need to return
	   a full new line */
	result = g_string_new(line);
	g_string_erase(result, startpos, wordlen);
	g_string_insert(result, startpos, data);

	if (want_space) {
		if (!isseparator(result->str[*pos]))
			g_string_insert_c(result, *pos, ' ');
		(*pos)++;
	}

	wordlen = strlen(data);
	last_line_pos = *pos;
	g_free_not_null(last_line);
	last_line = g_strdup(result->str);

	ret = result->str;
	g_string_free(result, FALSE);

	/* free the data */
	g_free(data);

	return ret;
}