Example #1
0
Filerange text_object_indentation(Text *txt, size_t pos) {
    char c;
    size_t bol = text_line_begin(txt, pos);
    size_t sol = text_line_start(txt, bol);
    size_t start = bol;
    size_t end = text_line_next(txt, bol);
    size_t line_indent = sol - bol;
    bool line_empty = text_byte_get(txt, bol, &c) && (c == '\r' || c == '\n');

    char *buf = text_bytes_alloc0(txt, bol, line_indent);
    char *tmp = malloc(line_indent);

    if (!buf || !tmp) {
        free(buf);
        free(tmp);
        return text_range_empty();
    }

    while ((bol = text_line_begin(txt, text_line_prev(txt, start))) != start) {
        sol = text_line_start(txt, bol);
        size_t indent = sol - bol;
        if (indent < line_indent)
            break;
        bool empty = text_byte_get(txt, bol, &c) && (c == '\r' || c == '\n');
        if (line_empty && !empty)
            break;
        if (line_indent == 0 && empty)
            break;
        text_bytes_get(txt, bol, line_indent, tmp);
        if (memcmp(buf, tmp, line_indent))
            break;
        start = bol;
    }

    do {
        bol = end;
        sol = text_line_start(txt, bol);
        size_t indent = sol - bol;
        if (indent < line_indent)
            break;
        bool empty = text_byte_get(txt, bol, &c) && (c == '\r' || c == '\n');
        if (line_empty && !empty)
            break;
        if (line_indent == 0 && empty)
            break;
        text_bytes_get(txt, bol, line_indent, tmp);
        if (memcmp(buf, tmp, line_indent))
            break;
        end = text_line_next(txt, bol);
    } while (bol != end);

    free(buf);
    free(tmp);
    return text_range_new(start, end);
}
bool register_put(Register *reg, Text *txt, Filerange *range) {
	size_t len = range->end - range->start;
	if (!buffer_alloc((Buffer*)reg, len))
		return false;
	reg->len = text_bytes_get(txt, range->start, len, reg->data);
	return true;
}
Example #3
0
File: main.c Project: SUMPaul/vis
static const char *cursors_select_next(Vis *vis, const char *keys, const Arg *arg) {
	Text *txt = vis_text(vis);
	View *view = vis_view(vis);
	Cursor *cursor = view_cursor(view);
	Filerange sel = view_cursors_selection_get(cursor);
	if (!text_range_valid(&sel))
		return keys;

	size_t len = text_range_size(&sel);
	char *buf = malloc(len+1);
	if (!buf)
		return keys;
	len = text_bytes_get(txt, sel.start, len, buf);
	buf[len] = '\0';
	Filerange word = text_object_word_find_next(txt, sel.end, buf);
	free(buf);

	if (text_range_valid(&word)) {
		cursor = view_cursors_new(view);
		if (!cursor)
			return keys;
		view_cursors_selection_set(cursor, &word);
		view_cursors_to(cursor, text_char_prev(txt, word.end));
	}
	return keys;
}
bool register_append(Register *reg, Text *txt, Filerange *range) {
	size_t rem = reg->size - reg->len;
	size_t len = range->end - range->start;
	if (len > rem && !buffer_alloc((Buffer*)reg, reg->size + len - rem))
		return false;
	reg->len += text_bytes_get(txt, range->start, len, reg->data + reg->len);
	return true;
}
Example #5
0
static size_t text_function_end_direction(Text *txt, size_t pos, int direction) {
	size_t start = pos, match;
	if (direction < 0 && pos > 0)
		pos--;
	for (;;) {
		char c[3];
		if (direction > 0)
			match = text_find_next(txt, pos, "\n}");
		else
			match = text_find_prev(txt, pos, "\n}");
		if (text_bytes_get(txt, match, sizeof c, c) != 3 || c[0] != '\n' || c[1] != '}')
			break;
		if (c[2] == '\r' || c[2] == '\n')
			return match+1;
		if (match == pos)
			match += direction;
		pos = match;
	}
	return start;
}
Example #6
0
static size_t op_case_change(Vis *vis, Text *txt, OperatorContext *c) {
	size_t len = text_range_size(&c->range);
	char *buf = malloc(len);
	if (!buf)
		return c->pos;
	len = text_bytes_get(txt, c->range.start, len, buf);
	size_t rem = len;
	for (char *cur = buf; rem > 0; cur++, rem--) {
		int ch = (unsigned char)*cur;
		if (isascii(ch)) {
			if (c->arg->i == VIS_OP_CASE_SWAP)
				*cur = islower(ch) ? toupper(ch) : tolower(ch);
			else if (c->arg->i == VIS_OP_CASE_UPPER)
				*cur = toupper(ch);
			else
				*cur = tolower(ch);
		}
	}

	text_delete(txt, c->range.start, len);
	text_insert(txt, c->range.start, buf, len);
	free(buf);
	return c->pos;
}
Example #7
0
size_t text_line_width_set(Text *txt, size_t pos, int width) {
	int cur_width = 0;
	mbstate_t ps = { 0 };
	size_t bol = text_line_begin(txt, pos);
	Iterator it = text_iterator_get(txt, bol);

	for (;;) {
		char buf[MB_CUR_MAX];
		size_t len = text_bytes_get(txt, it.pos, sizeof buf, buf);
		if (len == 0 || buf[0] == '\r' || buf[0] == '\n')
			break;
		wchar_t wc;
		size_t wclen = mbrtowc(&wc, buf, len, &ps);
		if (wclen == (size_t)-1 && errno == EILSEQ) {
			/* assume a replacement symbol will be displayed */
			cur_width++;
		} else if (wclen == (size_t)-2) {
			/* do nothing, advance to next character */
		} else if (wclen == 0) {
			/* assume NUL byte will be displayed as ^@ */
			cur_width += 2;
		} else if (buf[0] == '\t') {
			cur_width++;
		} else {
			int w = wcwidth(wc);
			if (w == -1)
				w = 2; /* assume non-printable will be displayed as ^{char} */
			cur_width += w;
		}

		if (cur_width >= width || !text_iterator_codepoint_next(&it, NULL))
			break;
	}

	return it.pos;
}
Example #8
0
File: view.c Project: mulianov/vis
/* redraw the complete with data starting from view->start bytes into the file.
 * stop once the screen is full, update view->end, view->lastline */
void view_draw(View *view) {
	view_clear(view);
	/* current absolute file position */
	size_t pos = view->start;
	/* number of bytes to read in one go */
	size_t text_len = view->width * view->height;
	/* current buffer to work with */
	char text[text_len+1];
	/* remaining bytes to process in buffer*/
	size_t rem = text_bytes_get(view->text, pos, text_len, text);
	/* NUL terminate because regex(3) function expect it */
	text[rem] = '\0';
	/* current position into buffer from which to interpret a character */
	char *cur = text;
	/* current selection */
	Filerange sel = view_selection_get(view);
	/* syntax definition to use */
	Syntax *syntax = view->syntax;
	/* matched tokens for each syntax rule */
	regmatch_t match[syntax ? LENGTH(syntax->rules) : 1][1], *matched = NULL;
	memset(match, 0, sizeof match);
	/* default and current curses attributes to use */
	int default_attrs = COLOR_PAIR(0) | A_NORMAL, attrs = default_attrs;

	while (rem > 0) {

		/* current 'parsed' character' */
		wchar_t wchar;
		Cell cell;
		memset(&cell, 0, sizeof cell);
	
		if (syntax) {
			if (matched && cur >= text + matched->rm_eo) {
				/* end of current match */
				matched = NULL;
				attrs = default_attrs;
				for (int i = 0; i < LENGTH(syntax->rules); i++) {
					if (match[i][0].rm_so == -1)
						continue; /* no match on whole text */
					/* reset matches which overlap with matched */
					if (text + match[i][0].rm_so <= cur && cur < text + match[i][0].rm_eo) {
						match[i][0].rm_so = 0;
						match[i][0].rm_eo = 0;
					}
				}
			}

			if (!matched) {
				size_t off = cur - text; /* number of already processed bytes */
				for (int i = 0; i < LENGTH(syntax->rules); i++) {
					SyntaxRule *rule = &syntax->rules[i];
					if (!rule->rule)
						break;
					if (match[i][0].rm_so == -1)
						continue; /* no match on whole text */
					if (off >= (size_t)match[i][0].rm_eo) {
						/* past match, continue search from current position */
						if (regexec(&rule->regex, cur, 1, match[i], 0) ||
						    match[i][0].rm_so == match[i][0].rm_eo) {
							match[i][0].rm_so = -1;
							match[i][0].rm_eo = -1;
							continue;
						}
						match[i][0].rm_so += off;
						match[i][0].rm_eo += off;
					}

					if (text + match[i][0].rm_so <= cur && cur < text + match[i][0].rm_eo) {
						/* within matched expression */
						matched = &match[i][0];
						attrs = rule->color->attr;
						break; /* first match views */
					}
				}
			}
		}

		size_t len = mbrtowc(&wchar, cur, rem, NULL);
		if (len == (size_t)-1 && errno == EILSEQ) {
			/* ok, we encountered an invalid multibyte sequence,
			 * replace it with the Unicode Replacement Character
			 * (FFFD) and skip until the start of the next utf8 char */
			for (len = 1; rem > len && !ISUTF8(cur[len]); len++);
			cell = (Cell){ .data = "\xEF\xBF\xBD", .len = len, .width = 1, .istab = false };
		} else if (len == (size_t)-2) {
			/* not enough bytes available to convert to a
			 * wide character. advance file position and read
			 * another junk into buffer.
			 */
			rem = text_bytes_get(view->text, pos, text_len, text);
			text[rem] = '\0';
			cur = text;
			continue;
		} else if (len == 0) {
			/* NUL byte encountered, store it and continue */
			cell = (Cell){ .data = "\x00", .len = 1, .width = 0, .istab = false };
		} else {
			for (size_t i = 0; i < len; i++)
				cell.data[i] = cur[i];
			cell.data[len] = '\0';
			cell.istab = false;
			cell.len = len;
			cell.width = wcwidth(wchar);
			if (cell.width == -1)
				cell.width = 1;
		}

		if (cur[0] == '\r' && rem > 1 && cur[1] == '\n') {
			/* convert views style newline \r\n into a single char with len = 2 */
			cell = (Cell){ .data = "\n", .len = 2, .width = 1, .istab = false };
		}

		cell.attr = attrs;
		if (sel.start <= pos && pos < sel.end)
			cell.attr |= A_REVERSE;
		if (!view_addch(view, &cell))
			break;

 		rem -= cell.len;
		cur += cell.len;
		pos += cell.len;
	}