Shell: improve current directory traking
* parse process output for shell prompts with current directory * parse `make -w -C` output for temporary subdirectory excursions * handle property type and flags separately * add `QE_PROP_MARK` to prevent offset update at range boundary * use `QE_PROP_DUP` to optimize buffer properties with single allocation * use mask in `eb_delete_properties` to delete tags selectively * fix `eb_find_property` range glitch * fix offset tracking for CWD properties * simplify default directory selection for shell commands * fix compiler warnings on variable shadow definitions * optimize `next_error()`: no lookback needed anymore * display buffer properties in `describe-buffer` * update TODO.md
This commit is contained in:
parent
4f3c4dcd60
commit
0cb68d2d74
10 changed files with 429 additions and 201 deletions
4
Makefile
4
Makefile
|
|
@ -416,7 +416,7 @@ $(OBJS_DIR)/haiku.o: haiku.cpp $(DEPENDS) Makefile
|
|||
endif # ifneq(,$(TARGET))
|
||||
|
||||
libqhtml: force
|
||||
$(MAKE) -C libqhtml all
|
||||
$(MAKE) -w -C libqhtml all
|
||||
|
||||
#
|
||||
# Host utilities
|
||||
|
|
@ -650,7 +650,7 @@ TAGS: force
|
|||
|
||||
# autotest target
|
||||
test:
|
||||
$(MAKE) -C tests test
|
||||
$(MAKE) -w -C tests test
|
||||
|
||||
colortest:
|
||||
tests/16colors.pl
|
||||
|
|
|
|||
1
TODO.md
1
TODO.md
|
|
@ -321,7 +321,6 @@ This is the TODO list for qemacs
|
|||
* pass argval and pagewise to `do_scroll_up_down()` or split command
|
||||
* files: fix `SPC` / `TAB` distinct behaviors on **~/comp/project/gnachman/**
|
||||
* basic: update default settings to `indent_tabs_mode = 0`, `indent_width = 4`, my-colors
|
||||
* basic: add property lists in buffer and window for default directory and similar properties (override)
|
||||
* basic: reset last command when executing macro
|
||||
* basic: make `do_word_right`, `do_word_left`, `do_bol`, `do_eol`... return new offset
|
||||
* basic: use visual movement for left, right, up, down and character based for `C-b C-f C-n C-p`
|
||||
|
|
|
|||
81
buffer.c
81
buffer.c
|
|
@ -833,11 +833,11 @@ void eb_free(EditBuffer **bp)
|
|||
qe_free(&cb);
|
||||
}
|
||||
|
||||
eb_delete_properties(b, 0, INT_MAX, 1);
|
||||
eb_delete_properties(b, 0, INT_MAX, QE_PROP_ALL);
|
||||
eb_cache_remove(b);
|
||||
/* eb_clear frees b->log_buffer.
|
||||
* it should also call eb_free_style_buffer(b)
|
||||
* and eb_delete_properties(b, 0, INT_MAX);
|
||||
* and eb_delete_properties(b, 0, INT_MAX, QE_PROP_ALL);
|
||||
*/
|
||||
eb_clear(b);
|
||||
|
||||
|
|
@ -2766,66 +2766,101 @@ static void eb_plist_callback(EditBuffer *b, void *opaque, int edge,
|
|||
/* update properties */
|
||||
if (op == LOGOP_INSERT) {
|
||||
for (p = b->property_list; p; p = p->next) {
|
||||
if (p->offset >= offset)
|
||||
if (p->offset >= offset) {
|
||||
if (p->offset == offset && (p->flags & QE_PROP_MARK))
|
||||
continue;
|
||||
p->offset += size;
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (op == LOGOP_DELETE) {
|
||||
for (pp = &b->property_list; (p = *pp) != NULL;) {
|
||||
if (p->offset >= offset) {
|
||||
if (p->offset == offset && (p->flags & QE_PROP_MARK))
|
||||
continue;
|
||||
if (p->offset < offset + size) {
|
||||
/* property is anchored inside block: remove it */
|
||||
*pp = (*pp)->next;
|
||||
if (p->type & QE_PROP_FREE) {
|
||||
qe_free(&p->data);
|
||||
if (!(p->flags & QE_PROP_KEEP)) {
|
||||
*pp = p->next;
|
||||
if (p->flags & QE_PROP_FREE) {
|
||||
qe_free(&p->data);
|
||||
}
|
||||
qe_free(&p);
|
||||
continue;
|
||||
}
|
||||
qe_free(&p);
|
||||
p->offset = offset;
|
||||
continue;
|
||||
}
|
||||
p->offset -= size;
|
||||
}
|
||||
pp = &(*pp)->next;
|
||||
pp = &p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eb_add_property(EditBuffer *b, int offset, int type, void *data) {
|
||||
QEProperty *eb_add_property(EditBuffer *b, int offset, int type, int flags, const void *data) {
|
||||
QEProperty *p;
|
||||
QEProperty **pp;
|
||||
int extra = 0;
|
||||
|
||||
if (flags & QE_PROP_DUP) {
|
||||
extra = strlen(data) + 1;
|
||||
flags &= ~QE_PROP_FREE;
|
||||
}
|
||||
|
||||
if (!b->property_list) {
|
||||
eb_add_callback(b, eb_plist_callback, NULL, 0);
|
||||
}
|
||||
|
||||
/* insert property in ascending order of offset */
|
||||
for (pp = &b->property_list; (p = *pp) != NULL; pp = &(*pp)->next) {
|
||||
for (pp = &b->property_list; (p = *pp) != NULL; pp = &p->next) {
|
||||
if (p->offset > offset)
|
||||
break;
|
||||
}
|
||||
|
||||
p = qe_mallocz(QEProperty);
|
||||
p = qe_mallocz_hack(QEProperty, extra);
|
||||
p->offset = offset;
|
||||
p->type = type;
|
||||
p->data = data;
|
||||
p->flags = flags;
|
||||
if (extra)
|
||||
data = memcpy(p + 1, data, extra);
|
||||
p->data = unconst(void*)data;
|
||||
p->next = *pp;
|
||||
*pp = p;
|
||||
return *pp = p;
|
||||
}
|
||||
|
||||
int eb_del_property(EditBuffer *b, QEProperty *prop) {
|
||||
QEProperty *p;
|
||||
QEProperty **pp;
|
||||
|
||||
for (pp = &b->property_list; (p = *pp) != NULL; pp = &p->next) {
|
||||
if (p == prop) {
|
||||
*pp = p->next;
|
||||
if (p->flags & QE_PROP_FREE) {
|
||||
qe_free(&p->data);
|
||||
}
|
||||
qe_free(&p);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eb_add_tag(EditBuffer *b, int offset, const char *s) {
|
||||
QEProperty *p;
|
||||
|
||||
/* prevent tag duplicates */
|
||||
for (p = b->property_list; p != NULL; p = p->next) {
|
||||
/* prevent tag duplicates with exact same offset */
|
||||
for (p = b->property_list; p && p->offset <= offset; p = p->next) {
|
||||
if (p->offset == offset && p->type == QE_PROP_TAG && strequal(p->data, s))
|
||||
return;
|
||||
}
|
||||
eb_add_property(b, offset, QE_PROP_TAG, qe_strdup(s));
|
||||
eb_add_property(b, offset, QE_PROP_TAG, QE_PROP_DUP, s);
|
||||
}
|
||||
|
||||
QEProperty *eb_find_property(EditBuffer *b, int offset, int offset2, int type) {
|
||||
QEProperty *eb_find_property(EditBuffer *b, int offset, int offset2, int type, QEProperty *stop) {
|
||||
QEProperty *found = NULL;
|
||||
QEProperty *p;
|
||||
for (p = b->property_list; p && p->offset < offset2; p = p->next) {
|
||||
for (p = b->property_list; p && p != stop && p->offset < offset2; p = p->next) {
|
||||
if (p->offset >= offset && p->type == type) {
|
||||
/* return the last property between offset and offset2 */
|
||||
found = p;
|
||||
|
|
@ -2834,7 +2869,7 @@ QEProperty *eb_find_property(EditBuffer *b, int offset, int offset2, int type) {
|
|||
return found;
|
||||
}
|
||||
|
||||
void eb_delete_properties(EditBuffer *b, int offset, int offset2, int force) {
|
||||
void eb_delete_properties(EditBuffer *b, int offset, int offset2, int mask) {
|
||||
QEProperty *p;
|
||||
QEProperty **pp;
|
||||
|
||||
|
|
@ -2842,14 +2877,14 @@ void eb_delete_properties(EditBuffer *b, int offset, int offset2, int force) {
|
|||
return;
|
||||
|
||||
for (pp = &b->property_list; (p = *pp) != NULL && p->offset < offset2;) {
|
||||
if ((!(p->type & QE_PROP_SKIP) || force) && p->offset >= offset) {
|
||||
*pp = (*pp)->next;
|
||||
if (p->type & QE_PROP_FREE) {
|
||||
if (p->offset >= offset && p->offset < offset2 && (p->type & mask)) {
|
||||
*pp = p->next;
|
||||
if (p->flags & QE_PROP_FREE) {
|
||||
qe_free(&p->data);
|
||||
}
|
||||
qe_free(&p);
|
||||
} else {
|
||||
pp = &(*pp)->next;
|
||||
pp = &p->next;
|
||||
}
|
||||
}
|
||||
if (!b->property_list) {
|
||||
|
|
|
|||
42
extras.c
42
extras.c
|
|
@ -1923,7 +1923,7 @@ static void do_describe_buffer(EditState *s, int argval)
|
|||
if (!b1)
|
||||
return;
|
||||
|
||||
eb_putc(b1, '\n');
|
||||
eb_printf(b1, "Buffer fields:\n");
|
||||
|
||||
eb_printf(b1, " name: %s\n", b->name);
|
||||
eb_printf(b1, " filename: %s\n", b->filename);
|
||||
|
|
@ -2010,7 +2010,7 @@ static void do_describe_buffer(EditState *s, int argval)
|
|||
u8 iobuf[4096];
|
||||
int count[256];
|
||||
int total_size = b->total_size;
|
||||
int offset, c, i, col, max_count, count_width;
|
||||
int offset, c, i, col, len, max_count, count_width;
|
||||
int word_char, word_count, nb_chars, line, column;
|
||||
|
||||
eb_get_pos(b, &line, &column, total_size);
|
||||
|
|
@ -2045,6 +2045,31 @@ static void do_describe_buffer(EditState *s, int argval)
|
|||
eb_printf(b1, " words: %d\n", word_count);
|
||||
eb_printf(b1, " lines: %d\n", line + (column > 0));
|
||||
|
||||
if (b->property_list) {
|
||||
QEProperty *p;
|
||||
|
||||
eb_printf(b1, "\nBuffer property list:\n");
|
||||
|
||||
for (p = b->property_list; p; p = p->next) {
|
||||
eb_printf(b1, " %7d %c%c%c ", p->offset,
|
||||
(p->flags & QE_PROP_FREE) ? 'F' : ' ',
|
||||
(p->flags & QE_PROP_KEEP) ? 'K' : ' ',
|
||||
(p->flags & QE_PROP_MARK) ? 'M' : ' ');
|
||||
switch (p->type) {
|
||||
case QE_PROP_TAG:
|
||||
eb_printf(b1, "tag %s", (char*)p->data);
|
||||
break;
|
||||
case QE_PROP_CWD:
|
||||
eb_printf(b1, "cwd %s", (char*)p->data);
|
||||
break;
|
||||
default:
|
||||
eb_printf(b1, "%3d %p", p->type, p->data);
|
||||
break;
|
||||
}
|
||||
eb_putc(b1, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
eb_printf(b1, "\nByte stats:\n");
|
||||
|
||||
for (col = i = 0; i < 256; i++) {
|
||||
|
|
@ -2055,10 +2080,15 @@ static void do_describe_buffer(EditState *s, int argval)
|
|||
if (i > 0 && i < 0x7f) {
|
||||
char cbuf[8];
|
||||
byte_quote(cbuf, sizeof cbuf, i);
|
||||
col += eb_printf(b1, "'%s'", cbuf);
|
||||
len = eb_printf(b1, "'%s'", cbuf);
|
||||
} else {
|
||||
col += eb_printf(b1, "0x%02x", (unsigned)i);
|
||||
len = eb_printf(b1, "0x%02x", (unsigned)i);
|
||||
}
|
||||
while (len < 4) {
|
||||
eb_putc(b1, ' ');
|
||||
len++;
|
||||
}
|
||||
col += len;
|
||||
if (col >= 60) {
|
||||
eb_putc(b1, '\n');
|
||||
col = 0;
|
||||
|
|
@ -2104,7 +2134,7 @@ static void do_describe_window(EditState *s, int argval)
|
|||
if (!b1)
|
||||
return;
|
||||
|
||||
eb_putc(b1, '\n');
|
||||
eb_printf(b1, "Window fields:\n");
|
||||
|
||||
w = 28;
|
||||
eb_printf(b1, "%*s: %d, %d\n", w, "xleft, ytop", s->xleft, s->ytop);
|
||||
|
|
@ -2201,7 +2231,7 @@ static void do_describe_screen(EditState *e, int argval)
|
|||
if (!b1)
|
||||
return;
|
||||
|
||||
eb_putc(b1, '\n');
|
||||
eb_printf(b1, "Screen fields:\n");
|
||||
|
||||
w = 16;
|
||||
eb_printf(b1, "%*s: %s\n", w, "dpy.name", s->dpy.name);
|
||||
|
|
|
|||
|
|
@ -245,13 +245,7 @@ static void bufed_build_list(EditState *s, BufedState *bs)
|
|||
b->cur_style = BUFED_STYLE_DIRECTORY;
|
||||
else
|
||||
b->cur_style = BUFED_STYLE_FILENAME;
|
||||
if (b1->flags & BF_SHELL) {
|
||||
get_default_path(b1, b1->offset, path, sizeof(path));
|
||||
make_user_path(path, sizeof(path), path);
|
||||
get_dirname(path, sizeof(path), path);
|
||||
} else {
|
||||
make_user_path(path, sizeof(path), b1->filename);
|
||||
}
|
||||
make_user_path(path, sizeof(path), b1->filename);
|
||||
eb_put_filename(b, path, bs->pf_flags);
|
||||
b->cur_style = style0;
|
||||
}
|
||||
|
|
|
|||
453
modes/shell.c
453
modes/shell.c
|
|
@ -57,6 +57,11 @@ enum QETermState {
|
|||
QE_TERM_STATE_STRING,
|
||||
};
|
||||
|
||||
typedef struct ShellCwdEntry {
|
||||
QEProperty *prop;
|
||||
int error_count;
|
||||
} ShellCwdEntry;
|
||||
|
||||
typedef struct ShellState {
|
||||
QEModeData base;
|
||||
/* buffer state */
|
||||
|
|
@ -100,14 +105,18 @@ typedef struct ShellState {
|
|||
const char *caption; /* process caption for exit message */
|
||||
int shell_flags;
|
||||
int last_char; /* last char sent to the process */
|
||||
int cwd_stack_depth;
|
||||
ShellCwdEntry cwd_stack[16];
|
||||
} ShellState;
|
||||
|
||||
typedef struct ShellError {
|
||||
int offset;
|
||||
int msg_offset;
|
||||
int line_num;
|
||||
int col_num;
|
||||
char buffer[MAX_BUFFERNAME_SIZE];
|
||||
char filename[MAX_FILENAME_SIZE];
|
||||
char message[128];
|
||||
} ShellError;
|
||||
|
||||
typedef struct ShellKillContext {
|
||||
|
|
@ -130,6 +139,8 @@ static ShellError error_state = {
|
|||
static void do_shell_refresh(EditState *e, int flags);
|
||||
|
||||
static void shell_close(ShellState *s);
|
||||
static int shell_check_curpath(ShellState *s, int offset, int c);
|
||||
static int match_error(EditBuffer *b, int start_offset, ShellError *dest);
|
||||
|
||||
static void set_error_offset(EditBuffer *b, int offset)
|
||||
{
|
||||
|
|
@ -137,6 +148,20 @@ static void set_error_offset(EditBuffer *b, int offset)
|
|||
error_state.offset = offset - 1;
|
||||
error_state.line_num = error_state.col_num = -1;
|
||||
*error_state.filename = '\0';
|
||||
error_state.msg_offset = offset;
|
||||
*error_state.message = '\0';
|
||||
}
|
||||
|
||||
static QEProperty *shell_add_cwd(EditBuffer *b, int offset, const char *cwd, int force) {
|
||||
// Always set the buffer filename for bufed
|
||||
pstrcpy(unconst(char *)b->filename, countof(b->filename), cwd);
|
||||
if (!force) {
|
||||
QEProperty *last = eb_find_property(b, 0, offset, QE_PROP_CWD, NULL);
|
||||
if (last && strequal(last->data, cwd))
|
||||
return NULL;
|
||||
}
|
||||
return eb_add_property(b, offset, QE_PROP_CWD,
|
||||
QE_PROP_DUP | QE_PROP_KEEP | QE_PROP_MARK, cwd);
|
||||
}
|
||||
|
||||
#define PTYCHAR1 "pqrstuvwxyzabcde"
|
||||
|
|
@ -1528,10 +1553,10 @@ static void qe_term_emulate(ShellState *s, int c)
|
|||
/* add a new line */
|
||||
/* CG: XXX: ignoring charset */
|
||||
qe_term_set_style(s);
|
||||
offset += eb_insert_char32(s->b, offset, '\n');
|
||||
s->cur_offset = offset;
|
||||
offset1 = offset + eb_insert_char32(s->b, offset, '\n');
|
||||
s->cur_offset = offset1;
|
||||
/* update current screen_top */
|
||||
qe_term_get_pos(s, offset, &x, &y);
|
||||
qe_term_get_pos(s, offset1, &x, &y);
|
||||
} else {
|
||||
// XXX: test if cursor is on last row and append a newline
|
||||
// XXX: potential style issue if appending a newline
|
||||
|
|
@ -1539,6 +1564,10 @@ static void qe_term_emulate(ShellState *s, int c)
|
|||
}
|
||||
}
|
||||
s->b->last_log = 0; /* close undo record */
|
||||
if (c == 10 && (s->shell_flags & SF_INTERACTIVE) && !s->grab_keys) {
|
||||
// Track directory from make -w -C messages and error messages
|
||||
shell_check_curpath(s, offset, c);
|
||||
}
|
||||
break;
|
||||
case 13: /* CR Carriage Return (Ctrl-M). */
|
||||
/* move to visual beginning of line */
|
||||
|
|
@ -1611,6 +1640,12 @@ static void qe_term_emulate(ShellState *s, int c)
|
|||
len = 1;
|
||||
}
|
||||
s->cur_offset = qe_term_overwrite(s, offset, 1, buf1, len);
|
||||
|
||||
// Track directory from shell prompt
|
||||
if ((c == '#' || c == '$' || c == '>')
|
||||
&& (s->shell_flags & SF_INTERACTIVE) && !s->grab_keys) {
|
||||
shell_check_curpath(s, offset, c);
|
||||
}
|
||||
} else {
|
||||
TRACE_MSG(s, "control");
|
||||
}
|
||||
|
|
@ -1905,55 +1940,40 @@ static void qe_term_emulate(ShellState *s, int c)
|
|||
{
|
||||
char cwd[MAX_FILENAME_SIZE];
|
||||
buf_t cwdbuf[1];
|
||||
int pos = 7; /* first character after "file://" */
|
||||
const char *p;
|
||||
|
||||
if (!strstart(s->osc_buf, "file://", NULL)) {
|
||||
if (!strstart(s->osc_buf, "file://", &p)) {
|
||||
put_error(qs->active_window,
|
||||
"term_emulate: OSC 7 URI must start with 'file://'");
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip hostname if any */
|
||||
while (pos < s->osc_len && s->osc_buf[pos] != '/')
|
||||
pos++;
|
||||
while (*p && *p != '/')
|
||||
p++;
|
||||
|
||||
if (pos >= s->osc_len) {
|
||||
if (!*p) {
|
||||
put_error(qs->active_window,
|
||||
"term_emulate: missing path in OSC 7 URI: '%s'", s->osc_buf);
|
||||
break;
|
||||
}
|
||||
/* decode URI path */
|
||||
buf_init(cwdbuf, cwd, sizeof(cwd));
|
||||
while (pos < s->osc_len) {
|
||||
if (s->osc_buf[pos] == '%'
|
||||
&& pos + 2 < s->osc_len
|
||||
&& qe_isxdigit(s->osc_buf[pos + 1])
|
||||
&& qe_isxdigit(s->osc_buf[pos + 2]))
|
||||
{
|
||||
buf_put_byte(cwdbuf, ((qe_digit_value(s->osc_buf[pos + 1]) << 4)
|
||||
+ qe_digit_value(s->osc_buf[pos + 2])));
|
||||
pos += 3;
|
||||
while (*p) {
|
||||
if (*p == '%' && qe_isxdigit(p[1]) && qe_isxdigit(p[2])) {
|
||||
buf_put_byte(cwdbuf, qe_digit_value(p[1]) * 16 + qe_digit_value(p[2]));
|
||||
p += 3;
|
||||
} else {
|
||||
buf_put_byte(cwdbuf, s->osc_buf[pos]);
|
||||
pos += 1;
|
||||
buf_put_byte(cwdbuf, *p);
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
if (!strequal(s->b->filename, cwd)) {
|
||||
/* XXX: properties placed at end of buffer move forward whenever
|
||||
output is appended, causing successive cwd properties to share
|
||||
the same position instead of marking where cwd was observed. */
|
||||
int offset = s->b->offset - 1;
|
||||
if (offset > 0) { /* defer first property addition */
|
||||
if (!s->b->property_list && *s->b->filename)
|
||||
eb_add_property(s->b, 0, QE_PROP_CWD, qe_strdup(s->b->filename));
|
||||
eb_add_property(s->b, offset, QE_PROP_CWD, qe_strdup(cwd));
|
||||
}
|
||||
pstrcpy(unconst(char *)s->b->filename, sizeof(s->b->filename), cwd);
|
||||
}
|
||||
append_slash(cwd, countof(cwd));
|
||||
shell_add_cwd(s->b, s->b->offset, cwd, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TRACE_PRINTF(s, "unhandled string: %s", s->osc_buf);
|
||||
TRACE_PRINTF(s, "unhandled string: %.*s", min_int(s->osc_len, 32), s->osc_buf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -2581,7 +2601,7 @@ static void shell_read_cb(void *opaque)
|
|||
}
|
||||
|
||||
EditState *e = qs->active_window;
|
||||
if (e->b == b) {
|
||||
if (e->b == b && !(s->shell_flags & SF_NO_DRAG)) {
|
||||
if ((e->offset == prev_offset) || (qs->last_cmd_func == (CmdFunc)do_eof))
|
||||
e->offset = b->total_size;
|
||||
}
|
||||
|
|
@ -2752,6 +2772,7 @@ EditBuffer *qe_new_shell_buffer(QEmacsState *qs, EditBuffer *b0, EditState *e,
|
|||
EditBuffer *b;
|
||||
const char *lang;
|
||||
int cols, rows;
|
||||
char curpath[MAX_FILENAME_SIZE];
|
||||
|
||||
if (!b0 && (shell_flags & SF_REUSE_BUFFER)) {
|
||||
b0 = qe_find_buffer_name(qs, bufname);
|
||||
|
|
@ -2771,8 +2792,19 @@ EditBuffer *qe_new_shell_buffer(QEmacsState *qs, EditBuffer *b0, EditState *e,
|
|||
}
|
||||
shell_flags &= ~(SF_REUSE_BUFFER | SF_ERASE_BUFFER);
|
||||
|
||||
if (path)
|
||||
pstrcpy(unconst(char *)b->filename, sizeof(b->filename), path);
|
||||
// Set up filename and initial directory property
|
||||
if (path) {
|
||||
pstrcpy(curpath, countof(curpath), path);
|
||||
} else
|
||||
if (e) {
|
||||
get_default_path(e->b, e->offset, curpath, countof(curpath));
|
||||
} else {
|
||||
*curpath = '\0';
|
||||
getcwd(curpath, countof(curpath));
|
||||
}
|
||||
append_slash(curpath, countof(curpath));
|
||||
shell_add_cwd(b, 0, curpath, 1);
|
||||
|
||||
eb_set_buffer_name(b, bufname); /* ensure that the name is unique */
|
||||
if (shell_flags & SF_COLOR) {
|
||||
eb_create_style_buffer(b, BF_STYLE_COMP);
|
||||
|
|
@ -2860,7 +2892,7 @@ static void do_shell(EditState *e, int argval)
|
|||
### `shell(int argval)`
|
||||
|
||||
Start a shell buffer or move to the last shell buffer used.
|
||||
If a argval is provided and equal to one, the command attempts
|
||||
Unless an argument different from one is provided, the command attempts
|
||||
to switch to an existing, active shell buffer. If the process has
|
||||
already terminated, it will restart the shell in the original directory.
|
||||
If no shell buffer exists, or argval is not equal to one, it starts a
|
||||
|
|
@ -3021,6 +3053,9 @@ static EditState *shell_target_window(EditState *e, EditBuffer *b)
|
|||
}
|
||||
}
|
||||
|
||||
if (e1 == NULL)
|
||||
e1 = e;
|
||||
|
||||
switch_to_buffer(e1, b);
|
||||
return e1;
|
||||
}
|
||||
|
|
@ -3052,7 +3087,7 @@ static void do_man(EditState *s, const char *arg)
|
|||
return;
|
||||
|
||||
/* create new buffer */
|
||||
b = qe_new_shell_buffer(qs, NULL, s, bufname, NULL, NULL, cmd, SF_COLOR);
|
||||
b = qe_new_shell_buffer(qs, NULL, s, bufname, NULL, NULL, cmd, SF_COLOR | SF_NO_DRAG);
|
||||
if (!b)
|
||||
return;
|
||||
|
||||
|
|
@ -3115,7 +3150,7 @@ void qe_diff_buffer_with_file(EditState *s, EditBuffer *b)
|
|||
#endif
|
||||
snprintf(bufname, sizeof(bufname), "*Diff %s*", fname);
|
||||
|
||||
b1 = qe_new_shell_buffer(qs, NULL, s, bufname, NULL, NULL, cmd, SF_COLOR);
|
||||
b1 = qe_new_shell_buffer(qs, NULL, s, bufname, NULL, NULL, cmd, SF_COLOR | SF_NO_DRAG);
|
||||
if (!b1) {
|
||||
unlink(tmpdir);
|
||||
return;
|
||||
|
|
@ -3664,10 +3699,105 @@ static void do_shell_toggle_input(EditState *e)
|
|||
}
|
||||
}
|
||||
|
||||
/* check shell output for prompt and track current directory */
|
||||
static int shell_check_curpath(ShellState *s, int offset, int trigger)
|
||||
{
|
||||
char line[1024];
|
||||
char curpath[MAX_FILENAME_SIZE];
|
||||
EditBuffer *b = s->b;
|
||||
int bol, start, stop0, stop, i, len, offset1;
|
||||
|
||||
bol = eb_goto_bol(b, offset);
|
||||
len = eb_fgets(b, line, countof(line), bol, &offset1);
|
||||
line[len] = '\0'; /* strip the trailing newline if any */
|
||||
|
||||
if (trigger == '\n') {
|
||||
// Track make -w -C messages about temporary directory excursion
|
||||
const char *p;
|
||||
if ((p = strstr(line, "Entering directory ")) != NULL) {
|
||||
// Push new directory onto the stack and add a property
|
||||
ShellCwdEntry *cwdp;
|
||||
p += strlen("Entering directory ");
|
||||
if (*p == '`') p++;
|
||||
start = p - line;
|
||||
for (stop = start; line[stop] && line[stop] != '\''; stop++)
|
||||
continue;
|
||||
line[stop] = '\0';
|
||||
canonicalize_absolute_buffer_path(s->b, bol, curpath, countof(curpath), p);
|
||||
append_slash(curpath, countof(curpath));
|
||||
if (s->cwd_stack_depth == countof(s->cwd_stack)) {
|
||||
memmove(s->cwd_stack, s->cwd_stack + 1,
|
||||
sizeof(*s->cwd_stack) * (countof(s->cwd_stack) - 1));
|
||||
s->cwd_stack_depth--;
|
||||
}
|
||||
cwdp = &s->cwd_stack[s->cwd_stack_depth++];
|
||||
cwdp->error_count = 0;
|
||||
cwdp->prop = shell_add_cwd(b, offset1, curpath, 1);
|
||||
return 1;
|
||||
}
|
||||
if ((p = strstr(line, "Leaving directory ")) != NULL) {
|
||||
// Pop directory from the stack and delete the property if no errors
|
||||
if (s->cwd_stack_depth) {
|
||||
ShellCwdEntry *cwdp = &s->cwd_stack[--s->cwd_stack_depth];
|
||||
QEProperty *prev = eb_find_property(b, 0, cwdp->prop->offset,
|
||||
QE_PROP_CWD, cwdp->prop);
|
||||
if (prev) {
|
||||
if (!cwdp->error_count)
|
||||
eb_del_property(b, cwdp->prop);
|
||||
shell_add_cwd(b, offset1, prev->data, 0);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Check for error message:
|
||||
// - maybe parse errors at this time to track error location
|
||||
// for files that are loaded already, especially if the buffer
|
||||
// is out of sync with the corresponding file.
|
||||
if (match_error(b, bol, NULL)) {
|
||||
if (s->cwd_stack_depth) {
|
||||
s->cwd_stack[--s->cwd_stack_depth].error_count += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse shell prompt for current directory
|
||||
start = stop = stop0 = 0;
|
||||
for (i = 0; i < len;) {
|
||||
char c = line[i++];
|
||||
if (c == '#' || c == '$' || c == '>') {
|
||||
stop = stop0;
|
||||
break;
|
||||
}
|
||||
if (c == ':' && line[i] != '\\'
|
||||
&& !(line[i] == '/' && line[i + 1] == '/')
|
||||
&& !(line[i] == '/' && line[i + 1] == '*'))
|
||||
start = i;
|
||||
if (c == ' ') {
|
||||
if (!start || start == i - 1)
|
||||
start = i;
|
||||
} else {
|
||||
stop0 = i;
|
||||
}
|
||||
}
|
||||
if (stop > start) {
|
||||
line[stop] = '\0';
|
||||
/* XXX: should use a lower level function to avoid potential recursion */
|
||||
canonicalize_absolute_path(NULL, curpath, countof(curpath), line + start);
|
||||
if (is_directory(curpath)) {
|
||||
append_slash(curpath, countof(curpath));
|
||||
shell_add_cwd(b, bol, curpath, 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *shell_get_default_path(EditBuffer *b, int offset,
|
||||
char *buf, int buf_size)
|
||||
{
|
||||
QEProperty *p = eb_find_property(b, 0, offset, QE_PROP_CWD);
|
||||
QEProperty *p = eb_find_property(b, 0, offset, QE_PROP_CWD, NULL);
|
||||
return pstrcpy(buf, buf_size, p ? p->data : b->filename);
|
||||
}
|
||||
|
||||
|
|
@ -3806,17 +3936,91 @@ static void do_compile(EditState *s, const char *cmd)
|
|||
set_error_offset(b, 0);
|
||||
}
|
||||
|
||||
/* Scan a buffer for an error message or a grep location */
|
||||
static int match_error(EditBuffer *b, int start_offset, ShellError *dest)
|
||||
{
|
||||
char filename[MAX_FILENAME_SIZE];
|
||||
char fullpath[MAX_FILENAME_SIZE];
|
||||
buf_t fname[1];
|
||||
int line_num, col_num, len;
|
||||
int offset = start_offset;
|
||||
char32_t c;
|
||||
|
||||
/* parse filename:linenum:message */
|
||||
/* and: filename(linenum[, col]) ...: ... */
|
||||
|
||||
/* extract filename */
|
||||
buf_init(fname, filename, countof(filename));
|
||||
for (;;) {
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
if (c == '\n' || c == '\t' || c == ' ')
|
||||
return 0;
|
||||
if (c == ':' || c == '(')
|
||||
break;
|
||||
buf_putc_utf8(fname, c);
|
||||
}
|
||||
|
||||
/* extract line number */
|
||||
for (line_num = 0;;) {
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
if (c == ':' || c == ',' || c == '.' || c == ')')
|
||||
break;
|
||||
if (!qe_isdigit(c))
|
||||
return 0;
|
||||
line_num = line_num * 10 + c - '0';
|
||||
}
|
||||
if (line_num < 1)
|
||||
return 0;
|
||||
|
||||
/* extract optional column number */
|
||||
col_num = 0;
|
||||
if (c == ':' || c == ',' || c == '.') {
|
||||
int offset0 = offset;
|
||||
char32_t c0 = c;
|
||||
for (;;) {
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
if (c == ' ') continue;
|
||||
if (!qe_isdigit(c))
|
||||
break;
|
||||
col_num = col_num * 10 + c - '0';
|
||||
}
|
||||
if (col_num == 0) {
|
||||
offset = offset0;
|
||||
c = c0;
|
||||
}
|
||||
}
|
||||
while (c != ':') {
|
||||
if (c == '\n')
|
||||
return 0;
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
}
|
||||
if (dest) {
|
||||
canonicalize_absolute_buffer_path(b, start_offset,
|
||||
fullpath, countof(fullpath),
|
||||
filename);
|
||||
if (line_num != dest->line_num
|
||||
|| col_num != dest->col_num
|
||||
|| !strequal(fullpath, dest->filename)) {
|
||||
dest->offset = start_offset;
|
||||
dest->msg_offset = offset;
|
||||
dest->line_num = line_num;
|
||||
dest->col_num = col_num;
|
||||
pstrcpy(dest->filename, countof(dest->filename), fullpath);
|
||||
len = eb_fgets(b, dest->message, countof(dest->message),
|
||||
offset, &offset);
|
||||
dest->message[len] = '\0'; /* strip the trailing newline if any */
|
||||
return 2; // new error
|
||||
}
|
||||
}
|
||||
return 1; // has error
|
||||
}
|
||||
|
||||
static void do_next_error(EditState *s, int arg, int dir)
|
||||
{
|
||||
QEmacsState *qs = s->qs;
|
||||
EditState *e, *e_next;
|
||||
EditBuffer *b;
|
||||
int offset, found_offset;
|
||||
char filename[MAX_FILENAME_SIZE];
|
||||
char fullpath[MAX_FILENAME_SIZE];
|
||||
buf_t fnamebuf, *fname;
|
||||
int line_num, col_num;
|
||||
char32_t c;
|
||||
int offset;
|
||||
struct stat sb;
|
||||
|
||||
if (s->flags & (WF_POPUP | WF_MINIBUF)) {
|
||||
|
|
@ -3870,68 +4074,24 @@ static void do_next_error(EditState *s, int arg, int dir)
|
|||
}
|
||||
offset = eb_prev_line(b, offset);
|
||||
}
|
||||
found_offset = offset;
|
||||
/* parse filename:linenum:message */
|
||||
/* and: filename(linenum[, col]) ...: ... */
|
||||
|
||||
/* extract filename */
|
||||
fname = buf_init(&fnamebuf, filename, countof(filename));
|
||||
for (;;) {
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
if (c == '\n' || c == '\t' || c == ' ')
|
||||
goto next_line;
|
||||
if (c == ':' || c == '(')
|
||||
break;
|
||||
buf_putc_utf8(fname, c);
|
||||
if (match_error(b, offset, &error_state) > 1) {
|
||||
// found a new error
|
||||
break;
|
||||
}
|
||||
|
||||
/* XXX: should find directory backward from error offset */
|
||||
canonicalize_absolute_buffer_path(b, found_offset,
|
||||
fullpath, sizeof(fullpath), filename);
|
||||
|
||||
/* extract line number */
|
||||
for (line_num = col_num = 0;;) {
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
if (c == ':' || c == ',' || c == '.' || c == ')')
|
||||
break;
|
||||
if (!qe_isdigit(c))
|
||||
goto next_line;
|
||||
line_num = line_num * 10 + c - '0';
|
||||
}
|
||||
if (c == ':' || c == ',' || c == '.') {
|
||||
int offset0 = offset;
|
||||
char32_t c0 = c;
|
||||
for (;;) {
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
if (c == ' ') continue;
|
||||
if (!qe_isdigit(c))
|
||||
break;
|
||||
col_num = col_num * 10 + c - '0';
|
||||
}
|
||||
if (col_num == 0) {
|
||||
offset = offset0;
|
||||
c = c0;
|
||||
}
|
||||
}
|
||||
while (c != ':') {
|
||||
if (c == '\n')
|
||||
goto next_line;
|
||||
c = eb_nextc(b, offset, &offset);
|
||||
}
|
||||
if (line_num >= 1) {
|
||||
if (line_num != error_state.line_num
|
||||
|| col_num != error_state.col_num
|
||||
|| !strequal(fullpath, error_state.filename)) {
|
||||
error_state.line_num = line_num;
|
||||
error_state.col_num = col_num;
|
||||
pstrcpy(error_state.filename, sizeof(error_state.filename), fullpath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
next_line:
|
||||
offset = found_offset;
|
||||
}
|
||||
error_state.offset = found_offset;
|
||||
|
||||
/* check file and go to the error */
|
||||
if (stat(error_state.filename, &sb) < 0) {
|
||||
// XXX: should prompt for fullpath as a fallback
|
||||
put_error(qs->active_window, "Cannot find error in '%s': %s",
|
||||
error_state.filename, strerror(errno));
|
||||
return;
|
||||
} else
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
put_error(qs->active_window, "Cannot find error in '%s': %s",
|
||||
error_state.filename, "not a regular file");
|
||||
return;
|
||||
}
|
||||
|
||||
for (e = qs->first_window; e != NULL; e = e_next) {
|
||||
e_next = e->next_window;
|
||||
|
|
@ -3939,45 +4099,38 @@ static void do_next_error(EditState *s, int arg, int dir)
|
|||
edit_close(&e);
|
||||
}
|
||||
|
||||
/* check file and go to the error */
|
||||
if (stat(fullpath, &sb) < 0) {
|
||||
// XXX: should prompt for fullpath as a fallback
|
||||
put_error(qs->active_window, "Cannot find error in '%s': %s",
|
||||
fullpath, strerror(errno));
|
||||
} else
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
put_error(qs->active_window, "Cannot find error in '%s': %s",
|
||||
fullpath, "not a regular file");
|
||||
} else {
|
||||
/* find a window showing the error source
|
||||
buffer, split a new one if none is found */
|
||||
if ((e = eb_find_window(b, NULL)) == NULL)
|
||||
e = shell_target_window(s, b);
|
||||
/* find a window showing the error source buffer,
|
||||
split a new one if none is found */
|
||||
if ((e = eb_find_window(b, NULL)) == NULL && qs->shell_command_other_window) {
|
||||
e = shell_target_window(s, b);
|
||||
|
||||
/* if there is only one window and is showing the error
|
||||
source buffer then split a new window to find the file in */
|
||||
/* if there is only one window whoing the error source buffer
|
||||
then find or split a new window to find the file in */
|
||||
if (e == s && (s = get_next_window(s, WF_MINIBUF | WF_HIDDEN, 0)) == NULL)
|
||||
s = shell_target_window(e, b);
|
||||
}
|
||||
|
||||
/* update error window */
|
||||
if (e) {
|
||||
/* update error window to show the error at top */
|
||||
e->interactive = 0;
|
||||
e->offset_top = e->offset = error_state.offset;
|
||||
if (qs->shell_buffer_read_only)
|
||||
b->flags |= BF_READONLY;
|
||||
|
||||
/* set and update active window */
|
||||
qs->active_window = s;
|
||||
do_find_file(s, fullpath, 0);
|
||||
do_goto_line(s, line_num, col_num);
|
||||
do_center_cursor(s, 1);
|
||||
}
|
||||
|
||||
/* set and update active window */
|
||||
qs->active_window = s;
|
||||
do_find_file(s, error_state.filename, 0);
|
||||
do_goto_line(s, error_state.line_num, error_state.col_num);
|
||||
do_center_cursor(s, 1);
|
||||
|
||||
#if 0 // conflicts with muscle memory (chqrlie)
|
||||
if (!qs->first_transient_key) {
|
||||
qe_register_transient_binding(qs, "next-error", "M-n");
|
||||
qe_register_transient_binding(qs, "previous-error", "M-p");
|
||||
}
|
||||
#endif
|
||||
put_status(s, "=> %s", error_state.message);
|
||||
}
|
||||
|
||||
static int match_digits(const char32_t *buf, int n, char32_t sep) {
|
||||
|
|
@ -4063,11 +4216,10 @@ static int shell_grab_filename(const char32_t *buf, int n,
|
|||
return i;
|
||||
}
|
||||
|
||||
#define STATE_SHELL_SHIFT 8
|
||||
#define STATE_SHELL_SHIFT 7
|
||||
#define STATE_SHELL_MODE 0x001F
|
||||
#define STATE_SHELL_SKIP 0x0020
|
||||
#define STATE_SHELL_KEEP 0x0040
|
||||
#define STATE_SHELL_TAG 0x0080
|
||||
#define STATE_SHELL_MASK ((1 << STATE_SHELL_SHIFT) - 1)
|
||||
|
||||
static ModeDef *mode_cache[STATE_SHELL_MODE + 1];
|
||||
|
|
@ -4096,11 +4248,21 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
/* detect match lines for known languages and colorize accordingly */
|
||||
char filename[MAX_FILENAME_SIZE];
|
||||
ModeDef *m;
|
||||
int i = 0, start = 0;
|
||||
int i, start = 0, stop = n;
|
||||
|
||||
if (qe_isspace(str[0])) {
|
||||
if (cp->colorize_state & STATE_SHELL_SKIP)
|
||||
start = 1;
|
||||
/* patch style common lines */
|
||||
if (cp->colorize_state & STATE_SHELL_SKIP) {
|
||||
start = stop = 1;
|
||||
} else {
|
||||
/* clang line number prefix */
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (str[i] != ' ' && !qe_isdigit(str[i]))
|
||||
break;
|
||||
}
|
||||
if (str[i] == '|' && str[i + 1] == ' ')
|
||||
start = stop = i + 2;
|
||||
}
|
||||
} else {
|
||||
/* Detect patches and colorize according to filename */
|
||||
if ((cp->colorize_state & STATE_SHELL_KEEP) && match_diff(str, n)) { /* patch/diff location lines */
|
||||
|
|
@ -4142,12 +4304,13 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
else
|
||||
cp->line_style = QE_STYLE_DIFF_NEW;
|
||||
start = 1;
|
||||
stop = 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (str[0] == '<' || str[0] == '>') {
|
||||
if (str[1] == ' ')
|
||||
start = 2;
|
||||
start = stop = 2;
|
||||
else
|
||||
return;
|
||||
} else
|
||||
|
|
@ -4165,7 +4328,7 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
return;
|
||||
} else {
|
||||
/* Detect compiler messages and colorize according to filename */
|
||||
while (i < n) {
|
||||
for (i = 0; i < n;) {
|
||||
int w = 0;
|
||||
char32_t c = str[i];
|
||||
if (qe_isspace(c)) {
|
||||
|
|
@ -4224,8 +4387,10 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
i += 1;
|
||||
i += match_digits(str + i, n - i, ')');
|
||||
i += (str[i] == ':');
|
||||
cp->colorize_state = mc | STATE_SHELL_TAG;
|
||||
cp->colorize_state = mc;
|
||||
start = i;
|
||||
stop = 0;
|
||||
SET_STYLE(sbuf, 0, i, QE_STYLE_ERROR_LOCATION);
|
||||
break;
|
||||
}
|
||||
/* colorize compiler and grep -[ABC] output */
|
||||
|
|
@ -4235,12 +4400,15 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
i += match_digits(str + i, n - i, c); /* line number */
|
||||
i += match_digits(str + i, n - i, c); /* optional col number */
|
||||
start = i;
|
||||
cp->colorize_state = mc | STATE_SHELL_TAG;
|
||||
cp->colorize_state = mc;
|
||||
stop = 0;
|
||||
SET_STYLE(sbuf, 0, i, QE_STYLE_ERROR_LOCATION);
|
||||
if (match_string(str + i, n - i, " error:")
|
||||
|| match_string(str + i, n - i, " note:")
|
||||
|| match_string(str + i, n - i, " warning:")) {
|
||||
/* clang diagnostic, will colorize the next line */
|
||||
start = n;
|
||||
/* compiler diagnostic, will colorize subsequent lines */
|
||||
cp->colorize_state |= STATE_SHELL_KEEP;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -4262,12 +4430,7 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
} else {
|
||||
cp->colorize_state = 0;
|
||||
}
|
||||
if (save_state & STATE_SHELL_TAG) {
|
||||
SET_STYLE(sbuf, 0, i, QE_STYLE_ERROR_LOCATION);
|
||||
cp->combine_stop = 0;
|
||||
} else {
|
||||
cp->combine_stop = start;
|
||||
}
|
||||
cp->combine_stop = stop;
|
||||
cp->combine_skip = start; // restrict trailing blank colorizer
|
||||
} else {
|
||||
cp->colorize_state = 0;
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ FILENAME.
|
|||
### `shell(int argval)`
|
||||
|
||||
Start a shell buffer or move to the last shell buffer used.
|
||||
If a argval is provided and equal to one, the command attempts
|
||||
Unless an argument different from one is provided, the command attempts
|
||||
to switch to an existing, active shell buffer. If the process has
|
||||
already terminated, it will restart the shell in the original directory.
|
||||
If no shell buffer exists, or argval is not equal to one, it starts a
|
||||
|
|
|
|||
18
qe.c
18
qe.c
|
|
@ -580,11 +580,13 @@ void do_set_emulation(EditState *s, const char *name) {
|
|||
if (strequal(name, "epsilon")) {
|
||||
qe_register_emulation_bindings(qs, epsilon_bindings);
|
||||
qs->emulation_flags = 1;
|
||||
qs->shell_command_other_window = 0;
|
||||
qs->flag_split_window_change_focus = 1;
|
||||
} else
|
||||
if (strequal(name, "emacs") || strequal(name, "xemacs")) {
|
||||
qe_register_emulation_bindings(qs, emacs_bindings);
|
||||
qs->emulation_flags = 0;
|
||||
qs->shell_command_other_window = 1;
|
||||
qs->flag_split_window_change_focus = 0;
|
||||
} else
|
||||
if (strequal(name, "gosmacs")) {
|
||||
|
|
@ -3453,7 +3455,7 @@ void text_mode_line(EditState *s, buf_t *out)
|
|||
buf_printf(out, "--<%d", -s->x_disp[0]);
|
||||
if (s->x_disp[1])
|
||||
buf_printf(out, "-->%d", -s->x_disp[1]);
|
||||
tag = eb_find_property(s->b, 0, s->offset + 1, QE_PROP_TAG);
|
||||
tag = eb_find_property(s->b, 0, s->offset, QE_PROP_TAG, NULL);
|
||||
if (tag)
|
||||
buf_printf(out, "--%s", (char*)tag->data);
|
||||
#if 0
|
||||
|
|
@ -4079,9 +4081,9 @@ static void flush_line(DisplayState *ds,
|
|||
}
|
||||
if (ds->line_num < e->shadow_nb_lines && !disable_crc) {
|
||||
QELineShadow *ls;
|
||||
uint64_t crc;
|
||||
uint64_t crc = ds->line_style + e->region_style * 0x100L + e->default_style * 0x10000L;
|
||||
|
||||
crc = compute_crc(fragments, sizeof(*fragments) * nb_fragments, ds->line_style);
|
||||
crc = compute_crc(fragments, sizeof(*fragments) * nb_fragments, crc);
|
||||
crc = compute_crc(ds->line_chars, sizeof(*ds->line_chars) * ds->line_index, crc);
|
||||
ls = &e->line_shadow[ds->line_num];
|
||||
if (ls->y != ds->y || ls->x != ds->x_line
|
||||
|
|
@ -4849,7 +4851,7 @@ static int syntax_get_colorized_line(QEColorizeContext *cp,
|
|||
line++;
|
||||
if (line < s->colorize_nb_valid_lines)
|
||||
s->colorize_nb_valid_lines = line;
|
||||
eb_delete_properties(b, s->colorize_max_valid_offset, INT_MAX, 0);
|
||||
eb_delete_properties(b, s->colorize_max_valid_offset, INT_MAX, QE_PROP_TAG);
|
||||
s->colorize_max_valid_offset = INT_MAX;
|
||||
}
|
||||
|
||||
|
|
@ -8605,8 +8607,8 @@ void do_kill_buffer(EditState *s, const char *bufname, int force)
|
|||
kill_process_confirm_cb, md);
|
||||
} else {
|
||||
/* if modified and associated to a filename, then ask */
|
||||
if (!force && !(b->flags & (BF_DIRED | BF_SHELL))
|
||||
&& b->modified && b->filename[0] != '\0') {
|
||||
if (!force && b->modified
|
||||
&& !(b->flags & (BF_DIRED | BF_SHELL)) && b->filename[0] != '\0') {
|
||||
qe_stop_macro(qs);
|
||||
snprintf(buf, sizeof(buf),
|
||||
"Buffer %s modified; kill anyway? (yes or no) ", bufname);
|
||||
|
|
@ -9579,8 +9581,8 @@ static void quit_examine_buffers(QuitState *is)
|
|||
|
||||
while (is->b != NULL) {
|
||||
b = is->b;
|
||||
if (!(b->flags & (BF_SYSTEM | BF_DIRED | BF_SHELL))
|
||||
&& b->filename[0] != '\0' && b->modified) {
|
||||
if (b->modified && b->filename[0] != '\0'
|
||||
&& !(b->flags & (BF_SYSTEM | BF_DIRED | BF_SHELL))) {
|
||||
switch (is->state) {
|
||||
case QS_ASK:
|
||||
/* XXX: display cursor */
|
||||
|
|
|
|||
22
qe.h
22
qe.h
|
|
@ -642,19 +642,24 @@ extern EditBufferDataType raw_data_type;
|
|||
|
||||
struct QEProperty {
|
||||
int offset;
|
||||
#define QE_PROP_FREE 1
|
||||
#define QE_PROP_SKIP 4
|
||||
#define QE_PROP_TAG 3
|
||||
#define QE_PROP_CWD 13
|
||||
int type;
|
||||
#define QE_PROP_FREE 1 // p->data should be freed
|
||||
#define QE_PROP_DUP 2 // data should be duplicated with strdup
|
||||
#define QE_PROP_KEEP 4 // property is not removed in delete_range
|
||||
#define QE_PROP_MARK 8 // property offset is not adjusted on exact match
|
||||
int flags : 16;
|
||||
#define QE_PROP_TAG 1 // a source tag
|
||||
#define QE_PROP_CWD 2 // a current directory in a shell buffer
|
||||
#define QE_PROP_ALL 3
|
||||
int type : 16;
|
||||
void *data;
|
||||
QEProperty *next;
|
||||
};
|
||||
|
||||
void eb_add_property(EditBuffer *b, int offset, int type, void *data);
|
||||
QEProperty *eb_find_property(EditBuffer *b, int offset, int offset2, int type);
|
||||
QEProperty *eb_add_property(EditBuffer *b, int offset, int type, int flags, const void *data);
|
||||
int eb_del_property(EditBuffer *b, QEProperty *prop);
|
||||
QEProperty *eb_find_property(EditBuffer *b, int offset, int offset2, int type, QEProperty *stop);
|
||||
void eb_add_tag(EditBuffer *b, int offset, const char *s);
|
||||
void eb_delete_properties(EditBuffer *b, int offset, int offset2, int force);
|
||||
void eb_delete_properties(EditBuffer *b, int offset, int offset2, int mask);
|
||||
|
||||
/* qe module handling */
|
||||
|
||||
|
|
@ -1990,6 +1995,7 @@ void shell_colorize_line(QEColorizeContext *cp,
|
|||
#define SF_AUTO_CODING 0x04
|
||||
#define SF_AUTO_MODE 0x08
|
||||
#define SF_BUFED_MODE 0x10
|
||||
#define SF_NO_DRAG 0x20
|
||||
#define SF_REUSE_BUFFER 0x1000
|
||||
#define SF_ERASE_BUFFER 0x2000
|
||||
EditBuffer *qe_new_shell_buffer(QEmacsState *qs, EditBuffer *b0, EditState *e,
|
||||
|
|
|
|||
|
|
@ -203,7 +203,6 @@ QVarType qe_get_variable(EditState *s, const char *name,
|
|||
const char *endp;
|
||||
|
||||
/* find standard variable and user variables */
|
||||
// XXX: should also have window, buffer, mode properties?
|
||||
vp = qe_find_variable(s->qs, name);
|
||||
if (!vp) {
|
||||
/* Try environment */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue