buffer: improvements

- fixed `do_forward_block()` to handle very long lines gracefully
- simplified `to_transpose()`
- add `do_describe_window()` for `describe-window` command on C-h w
This commit is contained in:
Charlie Gordon 2016-12-23 20:12:05 +00:00
commit ef3974ecdd

301
extras.c
View file

@ -420,58 +420,101 @@ void do_show_date_and_time(EditState *s, int argval)
/* forward / backward block */
#define MAX_LEVEL 32
/* Return the matching delimiter for all pairs */
static int matching_delimiter(int c) {
static const char pairs[] = "(){}[]<>";
for (int i = 0; pairs[i]; i++) {
if (pairs[i] == c)
return pairs[i ^ 1];
}
return c;
}
static void do_forward_block(EditState *s, int dir)
{
unsigned int buf[COLORED_MAX_LINE_SIZE];
char balance[MAX_LEVEL];
int line_num, col_num, offset, offset1, len, pos, style, c, c1, level;
int use_colors;
int line_num, col_num, style, style0, c, level;
int pos; /* position of the current character on line */
int len; /* number of colorized positions */
int offset; /* offset of the current character */
int offset0; /* offset of the beginning of line */
int offset1; /* offset of the beginning of the next line */
eb_get_pos(s->b, &line_num, &col_num, s->offset);
offset = eb_goto_bol2(s->b, s->offset, &pos);
offset1 = offset;
/* XXX: deal with truncation */
len = s->get_colorized_line(s, buf, countof(buf), offset1, &offset1, line_num);
if (pos > len) {
/* cannot use colorized line buffer */
/* XXX: should use buffer contents */
pos = len;
offset = s->offset;
eb_get_pos(s->b, &line_num, &col_num, offset);
offset1 = offset0 = eb_goto_bol2(s->b, offset, &pos);
use_colors = s->colorize_func || s->b->b_styles;
style0 = 0;
len = 0;
if (use_colors) {
/* XXX: should only query the syntax colorizer */
len = s->get_colorized_line(s, buf, countof(buf), offset1, &offset1, line_num);
if (len < countof(buf) - 2) {
if (pos < len) {
style0 = buf[pos] >> STYLE_SHIFT;
}
} else {
/* very long line detected, use fallback version */
use_colors = 0;
len = 0;
}
}
style = buf[pos] >> STYLE_SHIFT;
level = 0;
if (dir < 0) {
for (;;) {
if (pos == 0) {
c = eb_prevc(s->b, offset, &offset);
if (c == '\n') {
if (offset <= 0)
break;
line_num--;
offset = eb_prev_line(s->b, offset);
offset1 = offset;
/* XXX: this will actually ignore the end of very long lines */
/* XXX: deal with truncation */
pos = s->get_colorized_line(s, buf, countof(buf), offset1, &offset1, line_num);
offset1 = offset0 = eb_goto_bol2(s->b, offset, &pos);
len = 0;
if (use_colors) {
/* XXX: should only query the syntax colorizer */
len = s->get_colorized_line(s, buf, countof(buf), offset1, &offset1, line_num);
if (len >= countof(buf) - 2) {
/* very long line detected, use fallback version */
use_colors = 0;
len = 0;
style0 = 0;
}
}
continue;
}
c = buf[--pos];
if (style != c >> STYLE_SHIFT) {
if (style == 0)
style = 0;
--pos;
if (pos >= 0 && pos < len) {
style = buf[pos] >> STYLE_SHIFT;
}
if (style != style0) {
if (style0 == 0)
continue;
style = 0;
if ((c >> STYLE_SHIFT) != 0)
style0 = 0;
if (style != 0)
continue;
}
switch (c &= CHAR_MASK) {
switch (c) {
case '\"':
case '\'':
if (pos >= len) {
/* simplistic string skip with escape char */
int c1, off;
while ((c1 = eb_prevc(s->b, offset, &off)) != '\n') {
offset = off;
pos--;
if (c1 == c && eb_prevc(s->b, offset, &off) != '\\')
break;
}
}
break;
case ')':
c1 = '(';
goto push;
case ']':
c1 = '[';
goto push;
case '}':
c1 = '{';
push:
if (level < MAX_LEVEL) {
balance[level] = c1;
balance[level] = matching_delimiter(c);
}
level++;
break;
@ -480,54 +523,82 @@ static void do_forward_block(EditState *s, int dir)
case '{':
if (level > 0) {
--level;
if (balance[level] != c) {
put_status(s, "Unmatched delimiter");
if (level < MAX_LEVEL && balance[level] != c) {
/* XXX: should set mark and offset */
put_status(s, "Unmatched delimiter %c <> %c",
c, balance[level]);
return;
}
if (level <= 0)
goto the_end;
if (level == 0) {
s->offset = offset;
return;
}
} else {
/* silently move up one level */
}
break;
}
}
} else {
for (;;) {
if (pos >= len) {
/* Should simplify with get_colorized_line updating
* offset
*/
c = eb_nextc(s->b, offset, &offset);
if (c == '\n') {
line_num++;
pos = 0;
offset = eb_next_line(s->b, offset);
if (offset >= s->b->total_size)
break;
offset1 = offset;
/* XXX: this will actually ignore the end of very long lines */
/* XXX: deal with truncation */
len = s->get_colorized_line(s, buf, countof(buf), offset1, &offset1, line_num);
offset1 = offset0 = offset;
len = 0;
if (use_colors) {
/* XXX: should only query the syntax colorizer */
len = s->get_colorized_line(s, buf, countof(buf), offset1, &offset1, line_num);
if (len >= countof(buf) - 2) {
/* very long line detected, use fallback version */
use_colors = 0;
len = 0;
style0 = 0;
}
}
pos = 0;
continue;
}
c = buf[pos];
style = 0;
if (pos < len) {
style = buf[pos] >> STYLE_SHIFT;
}
pos++;
if (style != c >> STYLE_SHIFT) {
if (style == 0)
if (style0 != style) {
if (style0 == 0)
continue;
style = 0;
if ((c >> STYLE_SHIFT) != 0)
style0 = 0;
if (style != 0)
continue;
}
switch (c &= CHAR_MASK) {
switch (c) {
case '\"':
case '\'':
if (pos >= len) {
/* simplistic string skip with escape char */
int c1, off;
while ((c1 = eb_nextc(s->b, offset, &off)) != '\n') {
offset = off;
pos++;
if (c1 == '\\') {
if (eb_nextc(s->b, offset, &off) == '\n')
break;
offset = off;
pos++;
} else
if (c1 == c) {
break;
}
}
}
break;
case '(':
c1 = ')';
goto push1;
case '[':
c1 = ']';
goto push1;
case '{':
c1 = '}';
push1:
if (level < MAX_LEVEL) {
balance[level] = c1;
balance[level] = matching_delimiter(c);
}
level++;
break;
@ -536,23 +607,29 @@ static void do_forward_block(EditState *s, int dir)
case '}':
if (level > 0) {
--level;
if (balance[level] != c) {
put_status(s, "Unmatched delimiter");
if (level < MAX_LEVEL && balance[level] != c) {
/* XXX: should set mark and offset */
put_status(s, "Unmatched delimiter %c <> %c",
c, balance[level]);
return;
}
if (level <= 0)
goto the_end;
if (level == 0) {
s->offset = offset;
return;
}
} else {
/* silently move up one level */
}
break;
}
}
}
the_end:
while (pos > 0) {
eb_nextc(s->b, offset, &offset);
pos--;
if (level != 0) {
/* XXX: should set mark and offset */
put_status(s, "Unmatched delimiter");
} else {
s->offset = offset;
}
s->offset = offset;
}
static void do_kill_block(EditState *s, int dir)
@ -578,21 +655,23 @@ static void do_transpose(EditState *s, int cmd)
if (check_read_only(s))
return;
/* compute positions of ranges to swap:
offset0..offset1 and offset2..offset3
end_offset is the ending position after the swap
*/
switch (cmd) {
case CMD_TRANSPOSE_CHARS:
/* at end of line, transpose previous 2 characters,
* otherwise transpose characters before and after point.
*/
end_offset = offset2 = s->offset;
offset1 = offset2 = s->offset;
offset0 = eb_prev(b, offset1);
if (eb_nextc(b, offset2, &offset3) == '\n') {
offset3 = offset2;
offset2 = eb_prev(b, offset3);
end_offset = s->offset;
offset1 = offset2;
end_offset = offset3 = offset2;
offset1 = offset2 = offset0;
offset0 = eb_prev(b, offset1);
} else {
offset1 = offset2;
offset0 = eb_prev(b, offset1);
/* XXX: should have specific flag */
if (s->qe_state->flag_split_window_change_focus) {
/* keep current position between characters */
end_offset = offset0 + offset3 - offset2;
@ -1170,6 +1249,74 @@ static void do_describe_buffer(EditState *s, int argval)
}
}
static void do_describe_window(EditState *s, int argval)
{
EditBuffer *b1;
int show;
b1 = new_help_buffer(&show);
if (!b1)
return;
eb_printf(b1, "Window Description\n\n");
int w = 28;
eb_printf(b1, "%*s: %d, %d\n", w, "xleft, ytop", s->xleft, s->ytop);
eb_printf(b1, "%*s: %d, %d\n", w, "width, height", s->width, s->height);
eb_printf(b1, "%*s: %d, %d, %d, %d\n", w, "x1, y1, x2, y2", s->x1, s->y1, s->x2, s->y2);
eb_printf(b1, "%*s: %#x %s%s%s%s%s\n", w, "flags", s->flags,
(s->flags & WF_POPUP) ? " POPUP" : "",
(s->flags & WF_MODELINE) ? " MODELINE" : "",
(s->flags & WF_RSEPARATOR) ? " RSEPARATOR" : "",
(s->flags & WF_POPLEFT) ? " POPLEFT" : "",
(s->flags & WF_HIDDEN) ? " HIDDEN" : "");
eb_printf(b1, "%*s: %d\n", w, "offset", s->offset);
eb_printf(b1, "%*s: %d\n", w, "offset_top", s->offset_top);
eb_printf(b1, "%*s: %d\n", w, "offset_bottom", s->offset_bottom);
eb_printf(b1, "%*s: %d\n", w, "y_disp", s->y_disp);
eb_printf(b1, "%*s: %d, %d\n", w, "x_disp[]", s->x_disp[0], s->x_disp[1]);
eb_printf(b1, "%*s: %d\n", w, "minibuf", s->minibuf);
eb_printf(b1, "%*s: %d\n", w, "dump_width", s->dump_width);
eb_printf(b1, "%*s: %d\n", w, "hex_mode", s->hex_mode);
eb_printf(b1, "%*s: %d\n", w, "unihex_mode", s->unihex_mode);
eb_printf(b1, "%*s: %d\n", w, "hex_nibble", s->hex_nibble);
eb_printf(b1, "%*s: %d\n", w, "insert", s->insert);
eb_printf(b1, "%*s: %d\n", w, "bidir", s->bidir);
eb_printf(b1, "%*s: %d\n", w, "cur_rtl", s->cur_rtl);
eb_printf(b1, "%*s: %d %s\n", w, "wrap", s->wrap,
s->wrap == WRAP_TRUNCATE ? "TRUNCATE" :
s->wrap == WRAP_LINE ? "LINE" :
s->wrap == WRAP_WORD ? "WORD" : "???");
eb_printf(b1, "%*s: %d\n", w, "line_numbers", s->line_numbers);
eb_printf(b1, "%*s: %d\n", w, "indent_size", s->indent_size);
eb_printf(b1, "%*s: %d\n", w, "indent_tabs_mode", s->indent_tabs_mode);
eb_printf(b1, "%*s: %d\n", w, "interactive", s->interactive);
eb_printf(b1, "%*s: %d\n", w, "force_highlight", s->force_highlight);
eb_printf(b1, "%*s: %d\n", w, "mouse_force_highlight", s->mouse_force_highlight);
eb_printf(b1, "%*s: %p\n", w, "get_colorized_line", (void*)s->get_colorized_line);
eb_printf(b1, "%*s: %p\n", w, "colorize_func", (void*)s->colorize_func);
eb_printf(b1, "%*s: %d\n", w, "default_style", s->default_style);
eb_printf(b1, "%*s: %s\n", w, "buffer", s->b->name);
if (s->last_buffer)
eb_printf(b1, "%*s: %s\n", w, "last_buffer", s->last_buffer->name);
eb_printf(b1, "%*s: %s\n", w, "mode", s->mode->name);
eb_printf(b1, "%*s: %d\n", w, "colorize_nb_lines", s->colorize_nb_lines);
eb_printf(b1, "%*s: %d\n", w, "colorize_nb_valid_lines", s->colorize_nb_valid_lines);
eb_printf(b1, "%*s: %d\n", w, "colorize_max_valid_offset", s->colorize_max_valid_offset);
eb_printf(b1, "%*s: %d\n", w, "busy", s->busy);
eb_printf(b1, "%*s: %d\n", w, "display_invalid", s->display_invalid);
eb_printf(b1, "%*s: %d\n", w, "borders_invalid", s->borders_invalid);
eb_printf(b1, "%*s: %d\n", w, "show_selection", s->show_selection);
eb_printf(b1, "%*s: %d\n", w, "region_style", s->region_style);
eb_printf(b1, "%*s: %d\n", w, "curline_style", s->curline_style);
eb_printf(b1, "\n");
b1->flags |= BF_READONLY;
if (show) {
show_popup(b1);
}
}
/*---------------- buffer contents sorting ----------------*/
struct chunk_ctx {
@ -1321,7 +1468,7 @@ static CmdDef extra_commands[] = {
CMD0( KEY_CTRLH('?'), KEY_F1,
"about-qemacs", do_about_qemacs)
CMD2( KEY_CTRLH('a'), KEY_NONE,
CMD2( KEY_CTRLH('a'), KEY_CTRLH(KEY_CTRL('A')),
"apropos", do_apropos, ESs,
"s{Apropos: }|apropos|")
CMD0( KEY_CTRLH('b'), KEY_NONE,
@ -1329,6 +1476,10 @@ static CmdDef extra_commands[] = {
CMD2( KEY_CTRLH('B'), KEY_NONE,
"show-bindings", do_show_bindings, ESs,
"s{Show bindings of command: }[command]|command|")
CMD2( KEY_CTRLH(KEY_CTRL('B')), KEY_NONE,
"describe-buffer", do_describe_buffer, ESi, "ui")
CMD2( KEY_CTRLH('w'), KEY_CTRLH(KEY_CTRL('W')),
"describe-window", do_describe_window, ESi, "ui")
CMD2( KEY_CTRLC('c'), KEY_NONE,
"set-region-color", do_set_region_color, ESs,
@ -1342,8 +1493,6 @@ static CmdDef extra_commands[] = {
CMD2( KEY_NONE, KEY_NONE,
"set-eol-type", do_set_eol_type, ESi,
"ui{EOL Type [0=Unix, 1=Dos, 2=Mac]: }")
CMD2( KEY_NONE, KEY_NONE,
"describe-buffer", do_describe_buffer, ESi, "ui")
CMD3( KEY_NONE, KEY_NONE,
"sort-buffer", do_sort_buffer, ESi, 0, "*v")