Ejemplo n.º 1
0
Archivo: input.c Proyecto: dmt4/ne
char *request(const char *prompt, const char * const default_string, const bool alpha_allowed, const int completion_type, const bool prefer_utf8) {

	set_attr(0);

	input_buffer[pos = len = offset = 0] = 0;
	encoding = ENC_ASCII;
	x = start_x = print_prompt(prompt);

	init_history();

	if (default_string) {
		strncpy(input_buffer, default_string, MAX_INPUT_LINE_LEN);
		len = strlen(input_buffer);
		encoding = detect_encoding(input_buffer, len);
		input_refresh();
	}

	bool first_char_typed = true, last_char_completion = false, selection = false;

	while(true) {

		assert(input_buffer[len] == 0);

		move_cursor(ne_lines - 1, x);

		int c;
		input_class ic;
		do c = get_key_code(); while((ic = CHAR_CLASS(c)) == IGNORE);

		/* ISO 10646 characters *above 256* can be added only to UTF-8 lines, or ASCII lines (making them, of course, UTF-8). */
		if (ic == ALPHA && c > 0xFF && encoding != ENC_ASCII && encoding != ENC_UTF8) ic = INVALID;

		if (ic != TAB) last_char_completion = false;
		if (ic == TAB && !completion_type) ic = ALPHA;

		switch(ic) {

		case INVALID:
			alert();
			break;

		case ALPHA:

			if (first_char_typed) {
				input_buffer[len = 0] = 0;
				clear_to_eol();
			}

			if (encoding == ENC_ASCII && c > 0x7F) encoding = prefer_utf8 || c > 0xFF ? ENC_UTF8 : ENC_8_BIT;
			int c_len = encoding == ENC_UTF8 ? utf8seqlen(c) : 1;
			int c_width = output_width(c);
			assert(c_len > 0);

			if (len <= MAX_INPUT_LINE_LEN - c_len && (alpha_allowed || (c < 0x100 && isxdigit(c)) || c=='X' || c=='x')) {

				memmove(&input_buffer[pos + c_len], &input_buffer[pos], len - pos + 1);

				if (c_len == 1) input_buffer[pos] = c;
				else utf8str(c, &input_buffer[pos]);

				len += c_len;

				move_cursor(ne_lines - 1, x);

				if (x < ne_columns - c_width) {
					if (pos == len - c_len) output_char(c, 0, encoding);
					else if (char_ins_del_ok) insert_char(c, 0, encoding);
					else input_refresh();
				}

				input_move_right(true);
			}
			break;

		case RETURN:
			selection = true;
			break;

		case TAB:
			if (completion_type == COMPLETE_FILE || completion_type == COMPLETE_SYNTAX) {
				bool quoted = false;
				char *prefix, *completion, *p;
				if (len && input_buffer[len - 1] == '"') {
					input_buffer[len - 1] = 0;
					if (prefix = strrchr(input_buffer, '"')) {
						quoted = true;
						prefix++;
					}
					else input_buffer[len - 1] = '"';
				}

				if (!quoted) {
					prefix = strrchr(input_buffer, ' ');
					if (prefix) prefix++;
					else prefix = input_buffer;
				}

				if (last_char_completion || completion_type == COMPLETE_SYNTAX) {
					if (completion_type == COMPLETE_FILE )
						completion = p = request_files(prefix, true);
					else
						completion = p = request_syntax(prefix, true);
					reset_window();
					if (completion) {
						if (*completion) selection = true;
						else completion++;
					}
				}
				else {
					if (completion_type == COMPLETE_FILE )
						completion = p = complete_filename(prefix);
					else
						completion = p = request_syntax(prefix, true);
					last_char_completion = true;
					if (!completion) alert();
				}

				if (completion && (prefix - input_buffer) + strlen(completion) + 1 < MAX_INPUT_LINE_LEN) {
					const encoding_type completion_encoding = detect_encoding(completion, strlen(completion));
					if (encoding == ENC_ASCII || completion_encoding == ENC_ASCII || encoding == completion_encoding) {
						strcpy(prefix, completion);
						if (quoted) strcat(prefix, "\"");
						len = strlen(input_buffer);
						pos = offset = 0;
						x = start_x;
						if (encoding == ENC_ASCII) encoding = completion_encoding;
						input_move_to_eol();
						if (quoted) input_move_left(false);
						input_refresh();
					}
					else alert();
				}
				else if (quoted) strcat(prefix, "\"");

				free(p);
			}
			break;

		case COMMAND:
			if (c < 0) c = -c - 1;
			const int a = parse_command_line(key_binding[c], NULL, NULL, false);
			if (a >= 0) {
				switch(a) {

				case LINEUP_A:
				case LINEDOWN_A:
				case MOVESOF_A:
				case MOVEEOF_A:
				case PAGEUP_A:
				case PAGEDOWN_A:
				case NEXTPAGE_A:
				case PREVPAGE_A:
					if (history_buff) {
						switch(a) {
						case LINEUP_A: line_up(history_buff); break;
						case LINEDOWN_A: line_down(history_buff); break;
						case MOVESOF_A: move_to_sof(history_buff); break;
						case MOVEEOF_A: move_to_bof(history_buff); break;
						case PAGEUP_A:
						case PREVPAGE_A: prev_page(history_buff); break;
						case PAGEDOWN_A:
						case NEXTPAGE_A: next_page(history_buff); break;
						}

						/* In some cases, the default displayed on the command line will be the same as the 
							first history item. In that case we skip it. */

						if (first_char_typed == true 
							 && a == LINEUP_A 
							 && history_buff->cur_line_desc->line 
							 && !strncmp(history_buff->cur_line_desc->line, input_buffer, history_buff->cur_line_desc->line_len))
							line_up(history_buff);

						if (history_buff->cur_line_desc->line) {
							strncpy(input_buffer,
									  history_buff->cur_line_desc->line,
									  min(history_buff->cur_line_desc->line_len,MAX_INPUT_LINE_LEN));
							input_buffer[min(history_buff->cur_line_desc->line_len,MAX_INPUT_LINE_LEN)] = 0;
							len	 = strlen(input_buffer);
							encoding = detect_encoding(input_buffer, len);
						}
						else {
							input_buffer[len = 0] = 0;
							encoding = ENC_ASCII;
						}

						x		= start_x;
						pos	= 0;
						offset = 0;
						input_refresh();
					}
					break;

				case MOVELEFT_A:
					input_move_left(true);
					break;

				case MOVERIGHT_A:
					input_move_right(true);
					break;

				case BACKSPACE_A:
					if (pos == 0) break;
					input_move_left(true);

				case DELETECHAR_A:
					if (len > 0 && pos < len) {
						int c_len = encoding == ENC_UTF8 ? utf8len(input_buffer[pos]) : 1;
						int c_width = get_char_width(&input_buffer[pos], encoding);
						memmove(&input_buffer[pos], &input_buffer[pos + c_len], len - pos - c_len + 1);
						len -= c_len;
						if (input_buffer_is_ascii()) encoding = ENC_ASCII;

						if (char_ins_del_ok) {
							int i, j;

							move_cursor(ne_lines - 1, x);
							delete_chars(c_width);

							for(i = x, j = pos; j < len && i + get_char_width(&input_buffer[j], encoding) < ne_columns - c_width; i += get_char_width(&input_buffer[j], encoding), j = next_pos(input_buffer, j, encoding));

							if (j < len) {
								move_cursor(ne_lines - 1, i);
								while(j < len && i + get_char_width(&input_buffer[j], encoding) < ne_columns) {
									output_char(get_char(&input_buffer[j], encoding), 0, encoding);
									i += get_char_width(&input_buffer[j], encoding);
									j = next_pos(input_buffer, j, encoding);
								}
							}
						}
						else input_refresh();
					}
					break;

				case DELETELINE_A:
					move_cursor(ne_lines - 1, start_x);
					clear_to_eol();
					input_buffer[len = pos = offset = 0] = 0;
					encoding = ENC_ASCII;
					x = start_x;
					break;

				case DELETEEOL_A:
					input_buffer[len = pos] = 0;
					clear_to_eol();
					if (input_buffer_is_ascii()) encoding = ENC_ASCII;
					break;

				case MOVEINCUP_A:
					if (x != start_x) {
						pos = offset;
						x = start_x;
						break;
					}

				case MOVESOL_A:
					input_move_to_sol();
					break;

				case MOVEINCDOWN_A: {
					int i, j;
					for(i = x, j = pos; j < len && i + get_char_width(&input_buffer[j], encoding) < ne_columns; i += get_char_width(&input_buffer[j], encoding), j = next_pos(input_buffer, j, encoding));
					if (j != pos && j < len) {
						pos = j;
						x = i;
						break;
					}
				}

				case MOVEEOL_A:
					input_move_to_eol();
					break;

				case TOGGLESEOL_A:
				case TOGGLESEOF_A:
					if (pos != 0) input_move_to_sol();
					else input_move_to_eol();
					break;

				case PREVWORD_A:
					input_prev_word();
					break;

				case NEXTWORD_A:
					input_next_word();
					break;

				case REFRESH_A:
					input_refresh();
					break;

				case PASTE_A:
					input_paste();
					break;

				case AUTOCOMPLETE_A:
					input_autocomplete();
					break;

				case ESCAPE_A:
					return NULL;

				default:
					break;
				}
			}
			break;

		default:
			break;
		}

		if (selection) {
			const line_desc * const last = (line_desc *)history_buff->line_desc_list.tail_pred->prev;
			assert(input_buffer[len] == 0);
			if (history_buff->num_lines == 0 || len != last->line_len || strncmp(input_buffer, last->line, last->line_len)) add_to_history(input_buffer);
			return input_buffer;
		}

		first_char_typed = false;
	}
}
Ejemplo n.º 2
0
HIGHLIGHT_STATE parse(struct high_syntax *const syntax, line_desc *const ld, HIGHLIGHT_STATE h_state, const bool utf8)
{
    struct high_frame *stack = h_state.stack;

    struct high_state *h = (stack ? stack->syntax : syntax)->states[h_state.state];

    /* Current state */

    unsigned char buf[24];          /* Name buffer (trunc after 23 characters) */
    unsigned char lbuf[24];         /* Lower case version of name buffer */
    unsigned char lsaved_s[24];     /* Lower case version of delimiter match buffer */
    int buf_idx = 0;            /* Index into buffer */
    int c;                  /* Current character */
    int c_len;              /* Character length in bytes */
    uint32_t *attr = attr_buf;
    uint32_t *attr_end = attr_buf + attr_size;
    int buf_en = 0;             /* Set for name buffering */
    int ofst = 0;               /* record offset after we've stopped buffering */
    int mark1 = 0;              /* offset to mark start from current pos */
    int mark2 = 0;              /* offset to mark end from current pos */
    int mark_en = 0;            /* set if marking */
    int recolor_delimiter_or_keyword;

    const unsigned char *p = (const unsigned char *)ld->line;
    unsigned char *q = (unsigned char *)(ld->line  + ld->line_len);

    buf[0] = 0;             /* Forgot this originally... took 5 months to fix! */


    /* Get next character */
    /* Una iterazione in più: aggiungo '\n' come ultimo carattere. */
    while (p <= q)    /* On the last itteration, process the virtual '\n' character. */
    {
        struct high_cmd *cmd;
        struct high_cmd *kw_cmd;
        int x;

        if (p == q)
        {
            c = '\n';
        }
        else
        {
            c = utf8 ? get_char((const char *)p, ENC_UTF8) : *p;
        }

        c_len = utf8 ? utf8seqlen(c) : 1;
        p += c_len;

        /* Hack so we can have UTF-8 characters without crashing */
        if (c < 0 || c > 255)
        {
            c = 0x1F;
        }

        /* Create or expand attribute array if necessary */
        if (attr == attr_end)
        {
            if (!attr_buf)
            {
                attr_size = 1024;
                attr_buf = joe_malloc(sizeof(int) * attr_size);
                attr = attr_buf;
            }
            else
            {
                attr_buf = joe_realloc(attr_buf, sizeof(int) * (attr_size * 2));
                attr = attr_buf + attr_size;
                attr_size *= 2;
            }
            attr_end = attr_buf + attr_size;
        }

        /* Advance to next attribute position (note attr[-1] below) */
        attr++;

        /* Loop while noeat */
        do
        {
            /* Color with current state */
            attr[-1] = h->color;

            /* Get command for this character */
            if (h->delim && c == h_state.saved_s[0] && h_state.saved_s[1] == 0)
            {
                cmd = h->delim;
            }
            else
            {
                cmd = h->cmd[c];
            }

            /* Lowerize strings for case-insensitive matching */
            if (cmd->ignore)
            {
                zcpy(lbuf, buf);
                lowerize(lbuf);
                if (cmd->delim)
                {
                    zcpy(lsaved_s, h_state.saved_s);
                    lowerize(lsaved_s);
                }
            }

            /* Check for delimiter or keyword matches */
            recolor_delimiter_or_keyword = 0;
            if (cmd->delim && (cmd->ignore ? !zcmp(lsaved_s, lbuf) : !zcmp(h_state.saved_s, buf)))
            {
                cmd = cmd->delim;
                recolor_delimiter_or_keyword = 1;
            }
            else if (cmd->keywords && (cmd->ignore ? (kw_cmd = htfind(cmd->keywords, lbuf)) : (kw_cmd = htfind(cmd->keywords, buf))))
            {
                cmd = kw_cmd;
                recolor_delimiter_or_keyword = 1;
            }

            /* Determine new state */
            if (cmd->call)
            {
                /* Call */
                struct high_frame **frame_ptr = stack ? &stack->child : &syntax->stack_base;
                /* Search for an existing stack frame for this call */
                while (*frame_ptr && !((*frame_ptr)->syntax == cmd->call && (*frame_ptr)->return_state == cmd->new_state))
                {
                    frame_ptr = &(*frame_ptr)->sibling;
                }
                if (*frame_ptr)
                {
                    stack = *frame_ptr;
                }
                else
                {
                    struct high_frame *frame = joe_malloc(sizeof(struct high_frame));
                    frame->parent = stack;
                    frame->child = 0;
                    frame->sibling = 0;
                    frame->syntax = cmd->call;
                    frame->return_state = cmd->new_state;
                    *frame_ptr = frame;
                    stack = frame;
                    ++stack_count;
                }
                h = stack->syntax->states[0];
            }
            else if (cmd->rtn)
            {
                /* Return */
                if (stack)
                {
                    h = stack->return_state;
                    stack = stack->parent;
                }
                else
                    /* Not in a subroutine, so ignore the return */
                {
                    h = cmd->new_state;
                }
            }
            else if (cmd->reset)
            {
                /* Reset the state and call stack */
                h = syntax->states[0];
                stack = syntax->stack_base;
            }
            else
            {
                /* Normal edge */
                h = cmd->new_state;
            }

            /* Recolor if necessary */
            if (recolor_delimiter_or_keyword)
                for (x = -(buf_idx + 1); x < -1; ++x)
                {
                    attr[x - ofst] = h->color;
                }
            for (x = cmd->recolor; x < 0; ++x)
                if (attr + x >= attr_buf)
                {
                    attr[x] = h->color;
                }

            /* Mark recoloring */
            if (cmd->recolor_mark)
                for (x = -mark1; x < -mark2; ++x)
                {
                    attr[x] = h->color;
                }

            /* Save string? */
            if (cmd->save_s)
            {
                zcpy(h_state.saved_s, buf);
            }

            /* Save character? */
            if (cmd->save_c)
            {
                h_state.saved_s[1] = 0;
                if (c == '<')
                {
                    h_state.saved_s[0] = '>';
                }
                else if (c == '(')
                {
                    h_state.saved_s[0] = ')';
                }
                else if (c == '[')
                {
                    h_state.saved_s[0] = ']';
                }
                else if (c == '{')
                {
                    h_state.saved_s[0] = '}';
                }
                else if (c == '`')
                {
                    h_state.saved_s[0] = '\'';
                }
                else
                {
                    h_state.saved_s[0] = c;
                }
            }

            /* Start buffering? */
            if (cmd->start_buffering)
            {
                buf_idx = 0;
                buf_en = 1;
                ofst = 0;
            }

            /* Stop buffering? */
            if (cmd->stop_buffering)
            {
                buf_en = 0;
            }

            /* Set mark begin? */
            if (cmd->start_mark)
            {
                mark2 = 1;
                mark1 = 1;
                mark_en = 1;
            }

            /* Set mark end? */
            if (cmd->stop_mark)
            {
                mark_en = 0;
                mark2 = 1;
            }
        }
        while (cmd->noeat);

        /* Save character in buffer */
        if (buf_idx < 23 && buf_en)
        {
            buf[buf_idx++] = c;
        }
        if (!buf_en)
        {
            ++ofst;
        }
        buf[buf_idx] = 0;

        /* Update mark pointers */
        ++mark1;
        if (!mark_en)
        {
            ++mark2;
        }

        /*  if(c=='\n')
            break;*/
    }
    /* Return new state */
    h_state.stack = stack;
    h_state.state = h->no;
    attr_len = attr - attr_buf - 1; /* -1 because of the fake newline. */
    return h_state;
}
Ejemplo n.º 3
0
Archivo: edit.c Proyecto: vigna/ne
static int to_something(buffer *b, int (to_first)(int), int (to_rest)(int)) {
	assert_buffer(b);

	/* If we are after the end of the line, just return ERROR. */

	if (b->cur_line == b->num_lines -1 && b->cur_pos >= b->cur_line_desc->line_len) return ERROR;

	int64_t pos = b->cur_pos;
	int c;
	/* First of all, we search for the word start, if we're not over it. */
	if (pos >= b->cur_line_desc->line_len || !ne_isword(c = get_char(&b->cur_line_desc->line[pos], b->encoding), b->encoding))
		if (search_word(b, 1) != OK)
			return ERROR;

	bool changed = false;
	int64_t new_len = 0;
	pos = b->cur_pos;
	const int64_t cur_char = b->cur_char;
	const int cur_x = b->cur_x;
	/* Then, we compute the word position extremes, length of the result (which
		may change because of casing). */
	while (pos < b->cur_line_desc->line_len && ne_isword(c = get_char(&b->cur_line_desc->line[pos], b->encoding), b->encoding)) {
		const int new_c = new_len ? to_rest(c) : to_first(c);
		changed |= (c != new_c);

		if (b->encoding == ENC_UTF8) new_len += utf8seqlen(new_c);
		else new_len++;

		pos = next_pos(b->cur_line_desc->line, pos, b->encoding);
	}

	const int64_t len = pos - b->cur_pos;
	if (!len) {
		char_right(b);
		return OK;
	}

	if (changed) {
		/* We actually perform changes only if some character was case folded. */
		char * word = malloc(new_len * sizeof *word);
		if (!word) return OUT_OF_MEMORY;

		pos = b->cur_pos;
		new_len = 0;
		/* Second pass: we actually build the transformed word. */
		while (pos < b->cur_line_desc->line_len && ne_isword(c = get_char(&b->cur_line_desc->line[pos], b->encoding), b->encoding)) {
			if (b->encoding == ENC_UTF8) new_len += utf8str(new_len ? to_rest(c) : to_first(c), word + new_len);
			else {
				word[new_len] = new_len ? to_rest(c) : to_first(c);
				new_len++;
			}

			pos = next_pos(b->cur_line_desc->line, pos, b->encoding);
		}

		start_undo_chain(b);

		delete_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, len);
		if (new_len) insert_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, word, new_len);

		free(word);

		end_undo_chain(b);

		if (cur_char < b->attr_len) b->attr_len = cur_char;
		update_line(b, b->cur_line_desc, b->cur_y, cur_x, false);
		need_attr_update = true;
	}

	return search_word(b, 1);
}