Merge branch 'master' into hide-container-impl

This commit is contained in:
ZyX 2017-12-16 14:27:41 +03:00
commit 7f3b9a4acc
38 changed files with 457 additions and 157 deletions

View File

@ -6192,7 +6192,6 @@ A jump table for the options with a short description can be found at |Q_op|.
When on, uses |highlight-guifg| and |highlight-guibg| attributes in When on, uses |highlight-guifg| and |highlight-guibg| attributes in
the terminal (thus using 24-bit color). Requires a ISO-8613-3 the terminal (thus using 24-bit color). Requires a ISO-8613-3
compatible terminal. compatible terminal.
Must be set at startup (in your |init.vim| or |--cmd|).
*'terse'* *'noterse'* *'terse'* *'noterse'*
'terse' boolean (default off) 'terse' boolean (default off)

View File

@ -80,6 +80,27 @@ Global Events *ui-global*
Some keys are missing in some modes. Some keys are missing in some modes.
["option_set", name, value]
The value of ui related option `name` changed. The sent options are
listed below:
'arabicshape'
'ambiwith'
'emoji'
'guifont'
'guifontset'
'guifontwide'
'showtabline'
'termguicolors'
Options are not added to the list if their effects are already taken
care of. For instance, instead of forwarding the raw 'mouse' option
value, `mouse_on` and `mouse_off` directly indicate if mouse support
is active right now. Some options like 'ambiwith' have already taken
effect on the grid, where appropriate empty cells are added, however
an ui might still use these options when rendering raw text sent from
Nvim, like the text of the cmdline when |ui-ext-cmdline| is set.
["mode_change", mode, mode_idx] ["mode_change", mode, mode_idx]
The mode changed. The first parameter `mode` is a string representing The mode changed. The first parameter `mode` is a string representing
the current mode. `mode_idx` is an index into the array received in the current mode. `mode_idx` is an index into the array received in

View File

@ -93,6 +93,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->suspend = remote_ui_suspend; ui->suspend = remote_ui_suspend;
ui->set_title = remote_ui_set_title; ui->set_title = remote_ui_set_title;
ui->set_icon = remote_ui_set_icon; ui->set_icon = remote_ui_set_icon;
ui->option_set = remote_ui_option_set;
ui->event = remote_ui_event; ui->event = remote_ui_event;
memset(ui->ui_ext, 0, sizeof(ui->ui_ext)); memset(ui->ui_ext, 0, sizeof(ui->ui_ext));

View File

@ -58,6 +58,8 @@ void set_title(String title)
FUNC_API_SINCE(3); FUNC_API_SINCE(3);
void set_icon(String icon) void set_icon(String icon)
FUNC_API_SINCE(3); FUNC_API_SINCE(3);
void option_set(String name, Object value)
FUNC_API_SINCE(4) FUNC_API_BRIDGE_IMPL;
void popupmenu_show(Array items, Integer selected, Integer row, Integer col) void popupmenu_show(Array items, Integer selected, Integer row, Integer col)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;

View File

@ -1927,7 +1927,7 @@ bool vim_is_ctrl_x_key(int c)
case CTRL_X_EVAL: case CTRL_X_EVAL:
return (c == Ctrl_P || c == Ctrl_N); return (c == Ctrl_P || c == Ctrl_N);
} }
EMSG(_(e_internal)); internal_error("vim_is_ctrl_x_key()");
return false; return false;
} }
@ -4681,7 +4681,7 @@ static int ins_complete(int c, bool enable_pum)
line = ml_get(curwin->w_cursor.lnum); line = ml_get(curwin->w_cursor.lnum);
compl_pattern = vim_strnsave(line + compl_col, compl_length); compl_pattern = vim_strnsave(line + compl_col, compl_length);
} else { } else {
EMSG2(_(e_intern2), "ins_complete()"); internal_error("ins_complete()");
return FAIL; return FAIL;
} }

View File

@ -1099,10 +1099,11 @@ static void restore_vimvar(int idx, typval_T *save_tv)
vimvars[idx].vv_tv = *save_tv; vimvars[idx].vv_tv = *save_tv;
if (vimvars[idx].vv_type == VAR_UNKNOWN) { if (vimvars[idx].vv_type == VAR_UNKNOWN) {
hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key); hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
if (HASHITEM_EMPTY(hi)) if (HASHITEM_EMPTY(hi)) {
EMSG2(_(e_intern2), "restore_vimvar()"); internal_error("restore_vimvar()");
else } else {
hash_remove(&vimvarht, hi); hash_remove(&vimvarht, hi);
}
} }
} }
@ -1570,7 +1571,7 @@ ex_let_vars (
} }
break; break;
} else if (*arg != ',' && *arg != ']') { } else if (*arg != ',' && *arg != ']') {
EMSG2(_(e_intern2), "ex_let_vars()"); internal_error("ex_let_vars()");
return FAIL; return FAIL;
} }
} }
@ -2969,7 +2970,7 @@ int do_unlet(const char *const name, const size_t name_len, const int forceit)
d = di->di_tv.vval.v_dict; d = di->di_tv.vval.v_dict;
} }
if (d == NULL) { if (d == NULL) {
EMSG2(_(e_intern2), "do_unlet()"); internal_error("do_unlet()");
return FAIL; return FAIL;
} }
hashitem_T *hi = hash_find(ht, (const char_u *)varname); hashitem_T *hi = hash_find(ht, (const char_u *)varname);
@ -7985,7 +7986,7 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break; break;
} }
case VAR_UNKNOWN: { case VAR_UNKNOWN: {
EMSG2(_(e_intern2), "f_empty(UNKNOWN)"); internal_error("f_empty(UNKNOWN)");
break; break;
} }
} }
@ -17149,7 +17150,7 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break; break;
} }
case VAR_UNKNOWN: { case VAR_UNKNOWN: {
EMSG2(_(e_intern2), "f_type(UNKNOWN)"); internal_error("f_type(UNKNOWN)");
break; break;
} }
} }
@ -18999,7 +19000,7 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv,
} }
return; return;
} else if (v->di_tv.v_type != tv->v_type) { } else if (v->di_tv.v_type != tv->v_type) {
EMSG2(_(e_intern2), "set_var()"); internal_error("set_var()");
} }
} }
@ -19266,7 +19267,7 @@ int var_item_copy(const vimconv_T *const conv,
} }
break; break;
case VAR_UNKNOWN: case VAR_UNKNOWN:
EMSG2(_(e_intern2), "var_item_copy(UNKNOWN)"); internal_error("var_item_copy(UNKNOWN)");
ret = FAIL; ret = FAIL;
} }
--recurse; --recurse;
@ -20954,11 +20955,11 @@ void func_unref(char_u *name)
if (fp == NULL && isdigit(*name)) { if (fp == NULL && isdigit(*name)) {
#ifdef EXITFREE #ifdef EXITFREE
if (!entered_free_all_mem) { if (!entered_free_all_mem) {
EMSG2(_(e_intern2), "func_unref()"); internal_error("func_unref()");
abort(); abort();
} }
#else #else
EMSG2(_(e_intern2), "func_unref()"); internal_error("func_unref()");
abort(); abort();
#endif #endif
} }
@ -20997,7 +20998,7 @@ void func_ref(char_u *name)
} else if (isdigit(*name)) { } else if (isdigit(*name)) {
// Only give an error for a numbered function. // Only give an error for a numbered function.
// Fail silently, when named or lambda function isn't found. // Fail silently, when named or lambda function isn't found.
EMSG2(_(e_intern2), "func_ref()"); internal_error("func_ref()");
} }
} }

View File

@ -346,7 +346,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
do { \ do { \
const char *const fun_ = (const char *)(fun); \ const char *const fun_ = (const char *)(fun); \
if (fun_ == NULL) { \ if (fun_ == NULL) { \
EMSG2(_(e_intern2), "string(): NULL function name"); \ internal_error("string(): NULL function name"); \
ga_concat(gap, "function(NULL"); \ ga_concat(gap, "function(NULL"); \
} else { \ } else { \
ga_concat(gap, "function("); \ ga_concat(gap, "function("); \

View File

@ -1880,14 +1880,20 @@ static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID)
tv->v_lock = VAR_UNLOCKED; \ tv->v_lock = VAR_UNLOCKED; \
} while (0) } while (0)
static inline void _nothing_conv_empty_dict(typval_T *const tv,
dict_T **const dictp)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(2)
{
tv_dict_unref(*dictp);
*dictp = NULL;
if (tv != NULL) {
tv->v_lock = VAR_UNLOCKED;
}
}
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
do { \ do { \
assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \ assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \
tv_dict_unref((dict_T *)dict); \ _nothing_conv_empty_dict(tv, ((dict_T **)&dict)); \
*((dict_T **)&dict) = NULL; \
if (tv != NULL) { \
((typval_T *)tv)->v_lock = VAR_UNLOCKED; \
} \
} while (0) } while (0)
static inline int _nothing_conv_real_list_after_start( static inline int _nothing_conv_real_list_after_start(

View File

@ -624,7 +624,7 @@ _convert_one_value_regular_dict: {}
break; break;
} }
case VAR_UNKNOWN: { case VAR_UNKNOWN: {
EMSG2(_(e_intern2), STR(_TYPVAL_ENCODE_CONVERT_ONE_VALUE) "()"); internal_error(STR(_TYPVAL_ENCODE_CONVERT_ONE_VALUE) "()");
return FAIL; return FAIL;
} }
} }

View File

@ -517,7 +517,7 @@ static void discard_exception(except_T *excp, int was_finished)
char_u *saved_IObuff; char_u *saved_IObuff;
if (excp == NULL) { if (excp == NULL) {
EMSG(_(e_internal)); internal_error("discard_exception()");
return; return;
} }
@ -619,8 +619,9 @@ static void catch_exception(except_T *excp)
*/ */
static void finish_exception(except_T *excp) static void finish_exception(except_T *excp)
{ {
if (excp != caught_stack) if (excp != caught_stack) {
EMSG(_(e_internal)); internal_error("finish_exception()");
}
caught_stack = caught_stack->caught; caught_stack = caught_stack->caught;
if (caught_stack != NULL) { if (caught_stack != NULL) {
set_vim_var_string(VV_EXCEPTION, (char *) caught_stack->value, -1); set_vim_var_string(VV_EXCEPTION, (char *) caught_stack->value, -1);
@ -1422,8 +1423,9 @@ void ex_catch(exarg_T *eap)
* ":endtry" or when the catch clause is left by a ":continue", * ":endtry" or when the catch clause is left by a ":continue",
* ":break", ":return", ":finish", error, interrupt, or another * ":break", ":return", ":finish", error, interrupt, or another
* exception. */ * exception. */
if (cstack->cs_exception[cstack->cs_idx] != current_exception) if (cstack->cs_exception[cstack->cs_idx] != current_exception) {
EMSG(_(e_internal)); internal_error("ex_catch()");
}
} else { } else {
/* /*
* If there is a preceding catch clause and it caught the exception, * If there is a preceding catch clause and it caught the exception,
@ -1547,7 +1549,7 @@ void ex_finally(exarg_T *eap)
* exception will be discarded. */ * exception will be discarded. */
if (did_throw && cstack->cs_exception[cstack->cs_idx] if (did_throw && cstack->cs_exception[cstack->cs_idx]
!= current_exception) != current_exception)
EMSG(_(e_internal)); internal_error("ex_finally()");
} }
/* /*

View File

@ -37,7 +37,7 @@ function write_arglist(output, ev, need_copy)
for j = 1, #ev.parameters do for j = 1, #ev.parameters do
local param = ev.parameters[j] local param = ev.parameters[j]
local kind = string.upper(param[1]) local kind = string.upper(param[1])
local do_copy = need_copy and (kind == "ARRAY" or kind == "DICTIONARY" or kind == "STRING") local do_copy = need_copy and (kind == "ARRAY" or kind == "DICTIONARY" or kind == "STRING" or kind == "OBJECT")
output:write(' ADD(args, ') output:write(' ADD(args, ')
if do_copy then if do_copy then
output:write('copy_object(') output:write('copy_object(')
@ -91,7 +91,7 @@ for i = 1, #events do
recv_cleanup = recv_cleanup..' api_free_string('..param[2]..');\n' recv_cleanup = recv_cleanup..' api_free_string('..param[2]..');\n'
argc = argc+2 argc = argc+2
elseif param[1] == 'Array' then elseif param[1] == 'Array' then
send = send..' Array copy_'..param[2]..' = copy_array('..param[2]..');\n' send = send..' Array '..copy..' = copy_array('..param[2]..');\n'
argv = argv..', '..copy..'.items, INT2PTR('..copy..'.size)' argv = argv..', '..copy..'.items, INT2PTR('..copy..'.size)'
recv = (recv..' Array '..param[2].. recv = (recv..' Array '..param[2]..
' = (Array){.items = argv['..argc..'],'.. ' = (Array){.items = argv['..argc..'],'..
@ -99,6 +99,15 @@ for i = 1, #events do
recv_argv = recv_argv..', '..param[2] recv_argv = recv_argv..', '..param[2]
recv_cleanup = recv_cleanup..' api_free_array('..param[2]..');\n' recv_cleanup = recv_cleanup..' api_free_array('..param[2]..');\n'
argc = argc+2 argc = argc+2
elseif param[1] == 'Object' then
send = send..' Object *'..copy..' = xmalloc(sizeof(Object));\n'
send = send..' *'..copy..' = copy_object('..param[2]..');\n'
argv = argv..', '..copy
recv = recv..' Object '..param[2]..' = *(Object *)argv['..argc..'];\n'
recv_argv = recv_argv..', '..param[2]
recv_cleanup = (recv_cleanup..' api_free_object('..param[2]..');\n'..
' xfree(argv['..argc..']);\n')
argc = argc+1
elseif param[1] == 'Integer' or param[1] == 'Boolean' then elseif param[1] == 'Integer' or param[1] == 'Boolean' then
argv = argv..', INT2PTR('..param[2]..')' argv = argv..', INT2PTR('..param[2]..')'
recv_argv = recv_argv..', PTR2INT(argv['..argc..'])' recv_argv = recv_argv..', PTR2INT(argv['..argc..'])'
@ -119,7 +128,7 @@ for i = 1, #events do
write_signature(bridge_output, ev, 'UI *ui') write_signature(bridge_output, ev, 'UI *ui')
bridge_output:write('\n{\n') bridge_output:write('\n{\n')
bridge_output:write(send) bridge_output:write(send)
bridge_output:write(' UI_BRIDGE_CALL(ui, '..ev.name..', '..argc..', ui'..argv..');\n}\n') bridge_output:write(' UI_BRIDGE_CALL(ui, '..ev.name..', '..argc..', ui'..argv..');\n}\n\n')
end end
end end

View File

@ -36,6 +36,7 @@ local redraw_flags={
all_windows='P_RALL', all_windows='P_RALL',
everything='P_RCLR', everything='P_RCLR',
curswant='P_CURSWANT', curswant='P_CURSWANT',
ui_option='P_UI_OPTION',
} }
local list_flags={ local list_flags={

View File

@ -254,16 +254,17 @@ static void add_buff(buffheader_T *const buf, const char *const s,
return; return;
} }
if (buf->bh_first.b_next == NULL) { /* first add to list */ if (buf->bh_first.b_next == NULL) { // first add to list
buf->bh_space = 0; buf->bh_space = 0;
buf->bh_curr = &(buf->bh_first); buf->bh_curr = &(buf->bh_first);
} else if (buf->bh_curr == NULL) { /* buffer has already been read */ } else if (buf->bh_curr == NULL) { // buffer has already been read
EMSG(_("E222: Add to read buffer")); IEMSG(_("E222: Add to read buffer"));
return; return;
} else if (buf->bh_index != 0) } else if (buf->bh_index != 0) {
memmove(buf->bh_first.b_next->b_str, memmove(buf->bh_first.b_next->b_str,
buf->bh_first.b_next->b_str + buf->bh_index, buf->bh_first.b_next->b_str + buf->bh_index,
STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1); STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1);
}
buf->bh_index = 0; buf->bh_index = 0;
size_t len; size_t len;
@ -1152,14 +1153,16 @@ void alloc_typebuf(void)
*/ */
void free_typebuf(void) void free_typebuf(void)
{ {
if (typebuf.tb_buf == typebuf_init) if (typebuf.tb_buf == typebuf_init) {
EMSG2(_(e_intern2), "Free typebuf 1"); internal_error("Free typebuf 1");
else } else {
xfree(typebuf.tb_buf); xfree(typebuf.tb_buf);
if (typebuf.tb_noremap == noremapbuf_init) }
EMSG2(_(e_intern2), "Free typebuf 2"); if (typebuf.tb_noremap == noremapbuf_init) {
else internal_error("Free typebuf 2");
} else {
xfree(typebuf.tb_noremap); xfree(typebuf.tb_noremap);
}
} }
/* /*
@ -3905,7 +3908,7 @@ makemap (
c1 = 't'; c1 = 't';
break; break;
default: default:
EMSG(_("E228: makemap: Illegal mode")); IEMSG(_("E228: makemap: Illegal mode"));
return FAIL; return FAIL;
} }
do { /* do this twice if c2 is set, 3 times with c3 */ do { /* do this twice if c2 is set, 3 times with c3 */

View File

@ -1043,6 +1043,7 @@ EXTERN char_u e_for[] INIT(= N_("E588: :endfor without :for"));
EXTERN char_u e_exists[] INIT(= N_("E13: File exists (add ! to override)")); EXTERN char_u e_exists[] INIT(= N_("E13: File exists (add ! to override)"));
EXTERN char_u e_failed[] INIT(= N_("E472: Command failed")); EXTERN char_u e_failed[] INIT(= N_("E472: Command failed"));
EXTERN char_u e_internal[] INIT(= N_("E473: Internal error")); EXTERN char_u e_internal[] INIT(= N_("E473: Internal error"));
EXTERN char_u e_intern2[] INIT(= N_("E685: Internal error: %s"));
EXTERN char_u e_interr[] INIT(= N_("Interrupted")); EXTERN char_u e_interr[] INIT(= N_("Interrupted"));
EXTERN char_u e_invaddr[] INIT(= N_("E14: Invalid address")); EXTERN char_u e_invaddr[] INIT(= N_("E14: Invalid address"));
EXTERN char_u e_invarg[] INIT(= N_("E474: Invalid argument")); EXTERN char_u e_invarg[] INIT(= N_("E474: Invalid argument"));
@ -1134,7 +1135,6 @@ EXTERN char_u e_write[] INIT(= N_("E80: Error while writing"));
EXTERN char_u e_zerocount[] INIT(= N_("E939: Positive count required")); EXTERN char_u e_zerocount[] INIT(= N_("E939: Positive count required"));
EXTERN char_u e_usingsid[] INIT(= N_( EXTERN char_u e_usingsid[] INIT(= N_(
"E81: Using <SID> not in a script context")); "E81: Using <SID> not in a script context"));
EXTERN char_u e_intern2[] INIT(= N_("E685: Internal error: %s"));
EXTERN char_u e_maxmempat[] INIT(= N_( EXTERN char_u e_maxmempat[] INIT(= N_(
"E363: pattern uses more memory than 'maxmempattern'")); "E363: pattern uses more memory than 'maxmempattern'"));
EXTERN char_u e_emptybuf[] INIT(= N_("E749: empty buffer")); EXTERN char_u e_emptybuf[] INIT(= N_("E749: empty buffer"));

View File

@ -208,7 +208,7 @@ int hash_add(hashtab_T *ht, char_u *key)
hash_T hash = hash_hash(key); hash_T hash = hash_hash(key);
hashitem_T *hi = hash_lookup(ht, (const char *)key, STRLEN(key), hash); hashitem_T *hi = hash_lookup(ht, (const char *)key, STRLEN(key), hash);
if (!HASHITEM_EMPTY(hi)) { if (!HASHITEM_EMPTY(hi)) {
EMSG2(_(e_intern2), "hash_add()"); internal_error("hash_add()");
return FAIL; return FAIL;
} }
hash_add_item(ht, hi, key, hash); hash_add_item(ht, hi, key, hash);

View File

@ -376,8 +376,9 @@ void mf_put(memfile_T *mfp, bhdr_T *hp, bool dirty, bool infile)
{ {
unsigned flags = hp->bh_flags; unsigned flags = hp->bh_flags;
if ((flags & BH_LOCKED) == 0) if ((flags & BH_LOCKED) == 0) {
EMSG(_("E293: block was not locked")); IEMSG(_("E293: block was not locked"));
}
flags &= ~BH_LOCKED; flags &= ~BH_LOCKED;
if (dirty) { if (dirty) {
flags |= BH_DIRTY; flags |= BH_DIRTY;

View File

@ -293,7 +293,7 @@ int ml_open(buf_T *buf)
*/ */
hp = mf_new(mfp, false, 1); hp = mf_new(mfp, false, 1);
if (hp->bh_bnum != 0) { if (hp->bh_bnum != 0) {
EMSG(_("E298: Didn't get block nr 0?")); IEMSG(_("E298: Didn't get block nr 0?"));
goto error; goto error;
} }
b0p = hp->bh_data; b0p = hp->bh_data;
@ -335,7 +335,7 @@ int ml_open(buf_T *buf)
if ((hp = ml_new_ptr(mfp)) == NULL) if ((hp = ml_new_ptr(mfp)) == NULL)
goto error; goto error;
if (hp->bh_bnum != 1) { if (hp->bh_bnum != 1) {
EMSG(_("E298: Didn't get block nr 1?")); IEMSG(_("E298: Didn't get block nr 1?"));
goto error; goto error;
} }
pp = hp->bh_data; pp = hp->bh_data;
@ -351,7 +351,7 @@ int ml_open(buf_T *buf)
*/ */
hp = ml_new_data(mfp, FALSE, 1); hp = ml_new_data(mfp, FALSE, 1);
if (hp->bh_bnum != 2) { if (hp->bh_bnum != 2) {
EMSG(_("E298: Didn't get block nr 2?")); IEMSG(_("E298: Didn't get block nr 2?"));
goto error; goto error;
} }
@ -635,13 +635,14 @@ static void ml_upd_block0(buf_T *buf, upd_block0_T what)
if (mfp == NULL || (hp = mf_get(mfp, 0, 1)) == NULL) if (mfp == NULL || (hp = mf_get(mfp, 0, 1)) == NULL)
return; return;
b0p = hp->bh_data; b0p = hp->bh_data;
if (ml_check_b0_id(b0p) == FAIL) if (ml_check_b0_id(b0p) == FAIL) {
EMSG(_("E304: ml_upd_block0(): Didn't get block 0??")); IEMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
else { } else {
if (what == UB_FNAME) if (what == UB_FNAME) {
set_b0_fname(b0p, buf); set_b0_fname(b0p, buf);
else /* what == UB_SAME_DIR */ } else { // what == UB_SAME_DIR
set_b0_dir_flag(b0p, buf); set_b0_dir_flag(b0p, buf);
}
} }
mf_put(mfp, hp, true, false); mf_put(mfp, hp, true, false);
} }
@ -1742,11 +1743,11 @@ ml_get_buf (
if (lnum > buf->b_ml.ml_line_count) { /* invalid line number */ if (lnum > buf->b_ml.ml_line_count) { /* invalid line number */
if (recursive == 0) { if (recursive == 0) {
/* Avoid giving this message for a recursive call, may happen when // Avoid giving this message for a recursive call, may happen when
* the GUI redraws part of the text. */ // the GUI redraws part of the text.
++recursive; recursive++;
EMSGN(_("E315: ml_get: invalid lnum: %" PRId64), lnum); IEMSGN(_("E315: ml_get: invalid lnum: %" PRId64), lnum);
--recursive; recursive--;
} }
errorret: errorret:
STRCPY(IObuff, "???"); STRCPY(IObuff, "???");
@ -1774,11 +1775,11 @@ errorret:
*/ */
if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL) { if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL) {
if (recursive == 0) { if (recursive == 0) {
/* Avoid giving this message for a recursive call, may happen // Avoid giving this message for a recursive call, may happen
* when the GUI redraws part of the text. */ // when the GUI redraws part of the text.
++recursive; recursive++;
EMSGN(_("E316: ml_get: cannot find line %" PRId64), lnum); IEMSGN(_("E316: ml_get: cannot find line %" PRId64), lnum);
--recursive; recursive--;
} }
goto errorret; goto errorret;
} }
@ -2162,7 +2163,7 @@ ml_append_int (
return FAIL; return FAIL;
pp = hp->bh_data; /* must be pointer block */ pp = hp->bh_data; /* must be pointer block */
if (pp->pb_id != PTR_ID) { if (pp->pb_id != PTR_ID) {
EMSG(_("E317: pointer block id wrong 3")); IEMSG(_("E317: pointer block id wrong 3"));
mf_put(mfp, hp, false, false); mf_put(mfp, hp, false, false);
return FAIL; return FAIL;
} }
@ -2295,8 +2296,8 @@ ml_append_int (
* Safety check: fallen out of for loop? * Safety check: fallen out of for loop?
*/ */
if (stack_idx < 0) { if (stack_idx < 0) {
EMSG(_("E318: Updated too many blocks?")); IEMSG(_("E318: Updated too many blocks?"));
buf->b_ml.ml_stack_top = 0; /* invalidate stack */ buf->b_ml.ml_stack_top = 0; // invalidate stack
} }
} }
@ -2435,7 +2436,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, int message)
return FAIL; return FAIL;
pp = hp->bh_data; /* must be pointer block */ pp = hp->bh_data; /* must be pointer block */
if (pp->pb_id != PTR_ID) { if (pp->pb_id != PTR_ID) {
EMSG(_("E317: pointer block id wrong 4")); IEMSG(_("E317: pointer block id wrong 4"));
mf_put(mfp, hp, false, false); mf_put(mfp, hp, false, false);
return FAIL; return FAIL;
} }
@ -2630,9 +2631,9 @@ static void ml_flush_line(buf_T *buf)
new_line = buf->b_ml.ml_line_ptr; new_line = buf->b_ml.ml_line_ptr;
hp = ml_find_line(buf, lnum, ML_FIND); hp = ml_find_line(buf, lnum, ML_FIND);
if (hp == NULL) if (hp == NULL) {
EMSGN(_("E320: Cannot find line %" PRId64), lnum); IEMSGN(_("E320: Cannot find line %" PRId64), lnum);
else { } else {
dp = hp->bh_data; dp = hp->bh_data;
idx = lnum - buf->b_ml.ml_locked_low; idx = lnum - buf->b_ml.ml_locked_low;
start = ((dp->db_index[idx]) & DB_INDEX_MASK); start = ((dp->db_index[idx]) & DB_INDEX_MASK);
@ -2841,7 +2842,7 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
pp = (PTR_BL *)(dp); /* must be pointer block */ pp = (PTR_BL *)(dp); /* must be pointer block */
if (pp->pb_id != PTR_ID) { if (pp->pb_id != PTR_ID) {
EMSG(_("E317: pointer block id wrong")); IEMSG(_("E317: pointer block id wrong"));
goto error_block; goto error_block;
} }
@ -2878,13 +2879,14 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
break; break;
} }
} }
if (idx >= (int)pp->pb_count) { /* past the end: something wrong! */ if (idx >= (int)pp->pb_count) { // past the end: something wrong!
if (lnum > buf->b_ml.ml_line_count) if (lnum > buf->b_ml.ml_line_count) {
EMSGN(_("E322: line number out of range: %" PRId64 " past the end"), IEMSGN(_("E322: line number out of range: %" PRId64 " past the end"),
lnum - buf->b_ml.ml_line_count); lnum - buf->b_ml.ml_line_count);
else } else {
EMSGN(_("E323: line count wrong in block %" PRId64), bnum); IEMSGN(_("E323: line count wrong in block %" PRId64), bnum);
}
goto error_block; goto error_block;
} }
if (action == ML_DELETE) { if (action == ML_DELETE) {
@ -2960,7 +2962,7 @@ static void ml_lineadd(buf_T *buf, int count)
pp = hp->bh_data; /* must be pointer block */ pp = hp->bh_data; /* must be pointer block */
if (pp->pb_id != PTR_ID) { if (pp->pb_id != PTR_ID) {
mf_put(mfp, hp, false, false); mf_put(mfp, hp, false, false);
EMSG(_("E317: pointer block id wrong 2")); IEMSG(_("E317: pointer block id wrong 2"));
break; break;
} }
pp->pb_pointer[ip->ip_index].pe_line_count += count; pp->pb_pointer[ip->ip_index].pe_line_count += count;

View File

@ -582,20 +582,61 @@ void emsg_invreg(int name)
/// Print an error message with unknown number of arguments /// Print an error message with unknown number of arguments
bool emsgf(const char *const fmt, ...) bool emsgf(const char *const fmt, ...)
{
bool ret;
va_list ap;
va_start(ap, fmt);
ret = emsgfv(fmt, ap);
va_end(ap);
return ret;
}
/// Print an error message with unknown number of arguments
static bool emsgfv(const char *fmt, va_list ap)
{ {
static char errbuf[IOSIZE]; static char errbuf[IOSIZE];
if (emsg_not_now()) { if (emsg_not_now()) {
return true; return true;
} }
va_list ap;
va_start(ap, fmt);
vim_vsnprintf(errbuf, sizeof(errbuf), fmt, ap, NULL); vim_vsnprintf(errbuf, sizeof(errbuf), fmt, ap, NULL);
va_end(ap);
return emsg((const char_u *)errbuf); return emsg((const char_u *)errbuf);
} }
/// Same as emsg(...), but abort on error when ABORT_ON_INTERNAL_ERROR is
/// defined. It is used for internal errors only, so that they can be
/// detected when fuzzing vim.
void iemsg(const char *s)
{
msg((char_u *)s);
#ifdef ABORT_ON_INTERNAL_ERROR
abort();
#endif
}
/// Same as emsgf(...) but abort on error when ABORT_ON_INTERNAL_ERROR is
/// defined. It is used for internal errors only, so that they can be
/// detected when fuzzing vim.
void iemsgf(const char *s, ...)
{
va_list ap;
va_start(ap, s);
(void)emsgfv(s, ap);
va_end(ap);
#ifdef ABORT_ON_INTERNAL_ERROR
abort();
#endif
}
/// Give an "Internal error" message.
void internal_error(char *where)
{
IEMSG2(_(e_intern2), where);
}
static void msg_emsgf_event(void **argv) static void msg_emsgf_event(void **argv)
{ {
char *s = argv[0]; char *s = argv[0];

View File

@ -49,6 +49,15 @@
/// Like #EMSG, but for messages with one "%" PRIu64 inside /// Like #EMSG, but for messages with one "%" PRIu64 inside
#define EMSGU(s, n) emsgf((const char *) (s), (uint64_t)(n)) #define EMSGU(s, n) emsgf((const char *) (s), (uint64_t)(n))
/// Like #EMSG, but for internal messages
#define IEMSG(s) iemsg((const char *)(s))
/// Like #EMSG2, but for internal messages
#define IEMSG2(s, p) iemsgf((const char *)(s), (p))
/// Like #EMSGN, but for internal messages
#define IEMSGN(s, n) iemsgf((const char *)(s), (int64_t)(n))
/// Display message at the recorded position /// Display message at the recorded position
#define MSG_PUTS(s) msg_puts((const char *)(s)) #define MSG_PUTS(s) msg_puts((const char *)(s))

View File

@ -74,6 +74,7 @@
#include "nvim/undo.h" #include "nvim/undo.h"
#include "nvim/window.h" #include "nvim/window.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/api/private/helpers.h"
#include "nvim/os/input.h" #include "nvim/os/input.h"
#include "nvim/os/lang.h" #include "nvim/os/lang.h"
@ -248,6 +249,7 @@ typedef struct vimoption {
#define P_RWINONLY 0x10000000U ///< only redraw current window #define P_RWINONLY 0x10000000U ///< only redraw current window
#define P_NDNAME 0x20000000U ///< only normal dir name chars allowed #define P_NDNAME 0x20000000U ///< only normal dir name chars allowed
#define P_UI_OPTION 0x40000000U ///< send option to remote ui
#define HIGHLIGHT_INIT \ #define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \
@ -1188,6 +1190,7 @@ do_set (
set_options_default(OPT_FREE | opt_flags); set_options_default(OPT_FREE | opt_flags);
didset_options(); didset_options();
didset_options2(); didset_options2();
ui_refresh_options();
redraw_all_later(CLEAR); redraw_all_later(CLEAR);
} else { } else {
showoptions(1, opt_flags); showoptions(1, opt_flags);
@ -1815,6 +1818,10 @@ do_set (
NULL, false, NULL); NULL, false, NULL);
reset_v_option_vars(); reset_v_option_vars();
xfree(saved_origval); xfree(saved_origval);
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
STRING_OBJ(cstr_as_string(*(char **)varp)));
}
} }
} else { } else {
// key code option(FIXME(tarruda): Show a warning or something // key code option(FIXME(tarruda): Show a warning or something
@ -2251,7 +2258,7 @@ int was_set_insecurely(char_u *opt, int opt_flags)
uint32_t *flagp = insecure_flag(idx, opt_flags); uint32_t *flagp = insecure_flag(idx, opt_flags);
return (*flagp & P_INSECURE) != 0; return (*flagp & P_INSECURE) != 0;
} }
EMSG2(_(e_intern2), "was_set_insecurely()"); internal_error("was_set_insecurely()");
return -1; return -1;
} }
@ -2310,8 +2317,8 @@ set_string_option_direct (
if (idx == -1) { // Use name. if (idx == -1) { // Use name.
idx = findoption((const char *)name); idx = findoption((const char *)name);
if (idx < 0) { // Not found (should not happen). if (idx < 0) { // Not found (should not happen).
EMSG2(_(e_intern2), "set_string_option_direct()"); internal_error("set_string_option_direct()");
EMSG2(_("For option %s"), name); IEMSG2(_("For option %s"), name);
return; return;
} }
} }
@ -2417,6 +2424,10 @@ static char *set_string_option(const int opt_idx, const char *const value,
NULL, false, NULL); NULL, false, NULL);
reset_v_option_vars(); reset_v_option_vars();
xfree(saved_oldval); xfree(saved_oldval);
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
STRING_OBJ(cstr_as_string((char *)(*varp))));
}
} }
return r; return r;
@ -4024,6 +4035,10 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
(char_u *) options[opt_idx].fullname, (char_u *) options[opt_idx].fullname,
NULL, false, NULL); NULL, false, NULL);
reset_v_option_vars(); reset_v_option_vars();
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
BOOLEAN_OBJ(value));
}
} }
comp_col(); /* in case 'ruler' or 'showcmd' changed */ comp_col(); /* in case 'ruler' or 'showcmd' changed */
@ -4429,6 +4444,10 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
(char_u *) options[opt_idx].fullname, (char_u *) options[opt_idx].fullname,
NULL, false, NULL); NULL, false, NULL);
reset_v_option_vars(); reset_v_option_vars();
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
INTEGER_OBJ(value));
}
} }
comp_col(); /* in case 'columns' or 'ls' changed */ comp_col(); /* in case 'columns' or 'ls' changed */
@ -4999,6 +5018,29 @@ static int optval_default(vimoption_T *p, char_u *varp)
return STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0; return STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0;
} }
/// Send update to UIs with values of UI relevant options
void ui_refresh_options(void)
{
for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
uint32_t flags = options[opt_idx].flags;
if (!(flags & P_UI_OPTION)) {
continue;
}
String name = cstr_as_string(options[opt_idx].fullname);
void *varp = options[opt_idx].var;
Object value = OBJECT_INIT;
if (flags & P_BOOL) {
value = BOOLEAN_OBJ(*(int *)varp);
} else if (flags & P_NUM) {
value = INTEGER_OBJ(*(long *)varp);
} else if (flags & P_STRING) {
// cstr_as_string handles NULL string
value = STRING_OBJ(cstr_as_string(*(char **)varp));
}
ui_call_option_set(name, value);
}
}
/* /*
* showoneopt: show the value of one option * showoneopt: show the value of one option
* must not be called with a hidden option! * must not be called with a hidden option!
@ -5542,7 +5584,7 @@ static char_u *get_varp(vimoption_T *p)
case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap); case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
case PV_SCL: return (char_u *)&(curwin->w_p_scl); case PV_SCL: return (char_u *)&(curwin->w_p_scl);
case PV_WINHL: return (char_u *)&(curwin->w_p_winhl); case PV_WINHL: return (char_u *)&(curwin->w_p_winhl);
default: EMSG(_("E356: get_varp ERROR")); default: IEMSG(_("E356: get_varp ERROR"));
} }
/* always return a valid pointer to avoid a crash! */ /* always return a valid pointer to avoid a crash! */
return (char_u *)&(curbuf->b_p_wm); return (char_u *)&(curbuf->b_p_wm);

View File

@ -447,6 +447,9 @@ EXTERN char_u *p_popt; // 'printoptions'
EXTERN char_u *p_header; // 'printheader' EXTERN char_u *p_header; // 'printheader'
EXTERN int p_prompt; // 'prompt' EXTERN int p_prompt; // 'prompt'
EXTERN char_u *p_guicursor; // 'guicursor' EXTERN char_u *p_guicursor; // 'guicursor'
EXTERN char_u *p_guifont; // 'guifont'
EXTERN char_u *p_guifontset; // 'guifontset'
EXTERN char_u *p_guifontwide; // 'guifontwide'
EXTERN char_u *p_hf; // 'helpfile' EXTERN char_u *p_hf; // 'helpfile'
EXTERN long p_hh; // 'helpheight' EXTERN long p_hh; // 'helpheight'
EXTERN char_u *p_hlg; // 'helplang' EXTERN char_u *p_hlg; // 'helplang'

View File

@ -68,7 +68,8 @@ return {
type='bool', scope={'global'}, type='bool', scope={'global'},
vi_def=true, vi_def=true,
vim=true, vim=true,
redraw={'everything'}, redraw={'everything', 'ui_option'},
varname='p_arshape', varname='p_arshape',
defaults={if_true={vi=true}} defaults={if_true={vi=true}}
}, },
@ -91,7 +92,7 @@ return {
full_name='ambiwidth', abbreviation='ambw', full_name='ambiwidth', abbreviation='ambw',
type='string', scope={'global'}, type='string', scope={'global'},
vi_def=true, vi_def=true,
redraw={'everything'}, redraw={'everything', 'ui_option'},
varname='p_ambw', varname='p_ambw',
defaults={if_true={vi="single"}} defaults={if_true={vi="single"}}
}, },
@ -661,7 +662,7 @@ return {
full_name='emoji', abbreviation='emo', full_name='emoji', abbreviation='emo',
type='bool', scope={'global'}, type='bool', scope={'global'},
vi_def=true, vi_def=true,
redraw={'everything'}, redraw={'everything', 'ui_option'},
varname='p_emoji', varname='p_emoji',
defaults={if_true={vi=true}} defaults={if_true={vi=true}}
}, },
@ -1021,23 +1022,26 @@ return {
type='string', list='onecomma', scope={'global'}, type='string', list='onecomma', scope={'global'},
deny_duplicates=true, deny_duplicates=true,
vi_def=true, vi_def=true,
redraw={'everything'}, varname='p_guifont',
enable_if=false, redraw={'everything', 'ui_option'},
defaults={if_true={vi=""}}
}, },
{ {
full_name='guifontset', abbreviation='gfs', full_name='guifontset', abbreviation='gfs',
type='string', list='onecomma', scope={'global'}, type='string', list='onecomma', scope={'global'},
vi_def=true, vi_def=true,
redraw={'everything'}, varname='p_guifontset',
enable_if=false, redraw={'everything', 'ui_option'},
defaults={if_true={vi=""}}
}, },
{ {
full_name='guifontwide', abbreviation='gfw', full_name='guifontwide', abbreviation='gfw',
type='string', list='onecomma', scope={'global'}, type='string', list='onecomma', scope={'global'},
deny_duplicates=true, deny_duplicates=true,
vi_def=true, vi_def=true,
redraw={'everything'}, redraw={'everything', 'ui_option'},
enable_if=false, varname='p_guifontwide',
defaults={if_true={vi=""}}
}, },
{ {
full_name='guioptions', abbreviation='go', full_name='guioptions', abbreviation='go',
@ -2164,7 +2168,7 @@ return {
full_name='showtabline', abbreviation='stal', full_name='showtabline', abbreviation='stal',
type='number', scope={'global'}, type='number', scope={'global'},
vi_def=true, vi_def=true,
redraw={'all_windows'}, redraw={'all_windows', 'ui_option'},
varname='p_stal', varname='p_stal',
defaults={if_true={vi=1}} defaults={if_true={vi=1}}
}, },
@ -2435,7 +2439,7 @@ return {
full_name='termguicolors', abbreviation='tgc', full_name='termguicolors', abbreviation='tgc',
type='bool', scope={'global'}, type='bool', scope={'global'},
vi_def=false, vi_def=false,
redraw={'everything'}, redraw={'everything', 'ui_option'},
varname='p_tgc', varname='p_tgc',
defaults={if_true={vi=false}} defaults={if_true={vi=false}}
}, },
@ -2505,11 +2509,10 @@ return {
full_name='titleold', full_name='titleold',
type='string', scope={'global'}, type='string', scope={'global'},
secure=true, secure=true,
gettext=true,
no_mkrc=true, no_mkrc=true,
vi_def=true, vi_def=true,
varname='p_titleold', varname='p_titleold',
defaults={if_true={vi=N_("")}} defaults={if_true={vi=""}}
}, },
{ {
full_name='titlestring', full_name='titlestring',

View File

@ -887,7 +887,7 @@ bool os_setenv_append_path(const char *fname)
# define MAX_ENVPATHLEN INT_MAX # define MAX_ENVPATHLEN INT_MAX
#endif #endif
if (!path_is_absolute_path((char_u *)fname)) { if (!path_is_absolute_path((char_u *)fname)) {
EMSG2(_(e_intern2), "os_setenv_append_path()"); internal_error("os_setenv_append_path()");
return false; return false;
} }
const char *tail = (char *)path_tail_with_sep((char_u *)fname); const char *tail = (char *)path_tail_with_sep((char_u *)fname);

View File

@ -72,8 +72,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
ELOG("forkpty failed: %s", strerror(errno)); ELOG("forkpty failed: %s", strerror(errno));
return status; return status;
} else if (pid == 0) { } else if (pid == 0) {
init_child(ptyproc); init_child(ptyproc); // never returns
abort();
} }
// make sure the master file descriptor is non blocking // make sure the master file descriptor is non blocking
@ -163,14 +162,15 @@ static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
Process *proc = (Process *)ptyproc; Process *proc = (Process *)ptyproc;
if (proc->cwd && os_chdir(proc->cwd) != 0) { if (proc->cwd && os_chdir(proc->cwd) != 0) {
fprintf(stderr, "chdir failed: %s\n", strerror(errno)); ELOG("chdir failed: %s", strerror(errno));
return; return;
} }
char *prog = ptyproc->process.argv[0]; char *prog = ptyproc->process.argv[0];
setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1); setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
execvp(prog, ptyproc->process.argv); execvp(prog, ptyproc->process.argv);
fprintf(stderr, "execvp failed: %s: %s\n", strerror(errno), prog); ELOG("execvp failed: %s: %s", strerror(errno), prog);
_exit(122); // 122 is EXEC_FAILED in the Vim source.
} }
static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL

View File

@ -10,6 +10,7 @@
#endif #endif
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/log.h"
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/globals.h" #include "nvim/globals.h"
#include "nvim/memline.h" #include "nvim/memline.h"
@ -162,7 +163,7 @@ static void on_signal(SignalWatcher *handle, int signum, void *data)
} }
break; break;
default: default:
fprintf(stderr, "Invalid signal %d", signum); ELOG("invalid signal: %d", signum);
break; break;
} }
} }

View File

@ -2856,7 +2856,7 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
if (old_last == NULL) { if (old_last == NULL) {
if (buf != curbuf) { if (buf != curbuf) {
EMSG2(_(e_intern2), "qf_fill_buffer()"); internal_error("qf_fill_buffer()");
return; return;
} }

View File

@ -458,16 +458,13 @@ static int toggle_Magic(int x)
/* Used for an error (down from) vim_regcomp(): give the error message, set /* Used for an error (down from) vim_regcomp(): give the error message, set
* rc_did_emsg and return NULL */ * rc_did_emsg and return NULL */
#define EMSG_RET_NULL(m) return (EMSG(m), rc_did_emsg = TRUE, (void *)NULL) #define EMSG_RET_NULL(m) return (EMSG(m), rc_did_emsg = true, (void *)NULL)
#define EMSG_RET_FAIL(m) return (EMSG(m), rc_did_emsg = TRUE, FAIL) #define IEMSG_RET_NULL(m) return (IEMSG(m), rc_did_emsg = true, (void *)NULL)
#define EMSG2_RET_NULL(m, \ #define EMSG_RET_FAIL(m) return (EMSG(m), rc_did_emsg = true, FAIL)
c) return (EMSG2((m), \ #define EMSG2_RET_NULL(m, c) \
(c) ? "" : "\\"), rc_did_emsg = TRUE, \ return (EMSG2((m), (c) ? "" : "\\"), rc_did_emsg = true, (void *)NULL)
(void *)NULL) #define EMSG2_RET_FAIL(m, c) \
#define EMSG2_RET_FAIL(m, \ return (EMSG2((m), (c) ? "" : "\\"), rc_did_emsg = true, FAIL)
c) return (EMSG2((m), \
(c) ? "" : "\\"), rc_did_emsg = TRUE, \
FAIL)
#define EMSG_ONE_RET_NULL EMSG2_RET_NULL(_( \ #define EMSG_ONE_RET_NULL EMSG2_RET_NULL(_( \
"E369: invalid item in %s%%[]"), reg_magic == MAGIC_ALL) "E369: invalid item in %s%%[]"), reg_magic == MAGIC_ALL)
@ -1891,8 +1888,8 @@ static char_u *regatom(int *flagp)
case Magic(')'): case Magic(')'):
if (one_exactly) if (one_exactly)
EMSG_ONE_RET_NULL; EMSG_ONE_RET_NULL;
EMSG_RET_NULL(_(e_internal)); /* Supposed to be caught earlier. */ IEMSG_RET_NULL(_(e_internal)); // Supposed to be caught earlier.
/* NOTREACHED */ // NOTREACHED
case Magic('='): case Magic('='):
case Magic('?'): case Magic('?'):
@ -4534,7 +4531,7 @@ regmatch (
brace_max[no] = OPERAND_MAX(scan); brace_max[no] = OPERAND_MAX(scan);
brace_count[no] = 0; brace_count[no] = 0;
} else { } else {
EMSG(_(e_internal)); /* Shouldn't happen */ internal_error("BRACE_LIMITS");
status = RA_FAIL; status = RA_FAIL;
} }
} }

View File

@ -5354,7 +5354,7 @@ add_sound_suggest (
// Find the word nr in the soundfold tree. // Find the word nr in the soundfold tree.
sfwordnr = soundfold_find(slang, goodword); sfwordnr = soundfold_find(slang, goodword);
if (sfwordnr < 0) { if (sfwordnr < 0) {
EMSG2(_(e_intern2), "add_sound_suggest()"); internal_error("add_sound_suggest()");
return; return;
} }

View File

@ -70,6 +70,7 @@ typedef struct {
UIBridgeData *bridge; UIBridgeData *bridge;
Loop *loop; Loop *loop;
bool stop; bool stop;
uv_timer_t after_startup_timer;
unibi_var_t params[9]; unibi_var_t params[9];
char buf[OUTBUF_SIZE]; char buf[OUTBUF_SIZE];
size_t bufpos; size_t bufpos;
@ -151,6 +152,7 @@ UI *tui_start(void)
ui->suspend = tui_suspend; ui->suspend = tui_suspend;
ui->set_title = tui_set_title; ui->set_title = tui_set_title;
ui->set_icon = tui_set_icon; ui->set_icon = tui_set_icon;
ui->option_set= tui_option_set;
ui->event = tui_event; ui->event = tui_event;
memset(ui->ui_ext, 0, sizeof(ui->ui_ext)); memset(ui->ui_ext, 0, sizeof(ui->ui_ext));
@ -168,24 +170,6 @@ static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index,
return unibi_run(str, data->params, buf, len); return unibi_run(str, data->params, buf, len);
} }
/// Emits some termcodes after Nvim startup, which were observed to slowdown
/// rendering during startup in tmux 2.3 (+focus-events). #7649
static void terminfo_after_startup_event(void **argv)
{
UI *ui = argv[0];
bool defer = argv[1] != NULL; // clever(?) boolean without malloc() dance.
TUIData *data = ui->data;
if (defer) { // We're on the main-loop. Now forward to the TUI loop.
loop_schedule(data->loop,
event_create(terminfo_after_startup_event, 2, ui, NULL));
return;
}
// Enable bracketed paste
unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
// Enable focus reporting
unibi_out_ext(ui, data->unibi_ext.enable_focus_reporting);
}
static void termname_set_event(void **argv) static void termname_set_event(void **argv)
{ {
char *termname = argv[0]; char *termname = argv[0];
@ -265,6 +249,9 @@ static void terminfo_start(UI *ui)
unibi_out(ui, unibi_enter_ca_mode); unibi_out(ui, unibi_enter_ca_mode);
unibi_out(ui, unibi_keypad_xmit); unibi_out(ui, unibi_keypad_xmit);
unibi_out(ui, unibi_clear_screen); unibi_out(ui, unibi_clear_screen);
// Enable bracketed paste
unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
uv_loop_init(&data->write_loop); uv_loop_init(&data->write_loop);
if (data->out_isatty) { if (data->out_isatty) {
uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0); uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
@ -277,9 +264,6 @@ static void terminfo_start(UI *ui)
uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0); uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
uv_pipe_open(&data->output_handle.pipe, data->out_fd); uv_pipe_open(&data->output_handle.pipe, data->out_fd);
} }
loop_schedule(&main_loop,
event_create(terminfo_after_startup_event, 2, ui, ui));
} }
static void terminfo_stop(UI *ui) static void terminfo_stop(UI *ui)
@ -307,6 +291,18 @@ static void terminfo_stop(UI *ui)
unibi_destroy(data->ut); unibi_destroy(data->ut);
} }
static void after_startup_timer_cb(uv_timer_t *handle)
FUNC_ATTR_NONNULL_ALL
{
UI *ui = handle->data;
TUIData *data = ui->data;
uv_timer_stop(&data->after_startup_timer);
// Emit this after Nvim startup, not during. This works around a tmux
// 2.3 bug(?) which caused slow drawing during startup. #7649
unibi_out_ext(ui, data->unibi_ext.enable_focus_reporting);
}
static void tui_terminal_start(UI *ui) static void tui_terminal_start(UI *ui)
{ {
TUIData *data = ui->data; TUIData *data = ui->data;
@ -316,6 +312,8 @@ static void tui_terminal_start(UI *ui)
update_size(ui); update_size(ui);
signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH); signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
term_input_start(&data->input); term_input_start(&data->input);
uv_timer_start(&data->after_startup_timer, after_startup_timer_cb, 500, 0);
} }
static void tui_terminal_stop(UI *ui) static void tui_terminal_stop(UI *ui)
@ -349,6 +347,8 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
#ifdef UNIX #ifdef UNIX
signal_watcher_start(&data->cont_handle, sigcont_cb, SIGCONT); signal_watcher_start(&data->cont_handle, sigcont_cb, SIGCONT);
#endif #endif
uv_timer_init(&data->loop->uv, &data->after_startup_timer);
data->after_startup_timer.data = ui;
#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 #if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18
data->input.tk_ti_hook_fn = tui_tk_ti_getstr; data->input.tk_ti_hook_fn = tui_tk_ti_getstr;
@ -367,6 +367,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed
} }
uv_close((uv_handle_t *)&data->after_startup_timer, NULL);
ui_bridge_stopped(bridge); ui_bridge_stopped(bridge);
term_input_destroy(&data->input); term_input_destroy(&data->input);
signal_watcher_stop(&data->cont_handle); signal_watcher_stop(&data->cont_handle);
@ -1136,6 +1137,14 @@ static void tui_set_icon(UI *ui, String icon)
{ {
} }
static void tui_option_set(UI *ui, String name, Object value)
{
if (strequal(name.data, "termguicolors")) {
// NB: value for bridge is set in ui_bridge.c
ui->rgb = value.data.boolean;
}
}
// NB: if we start to use this, the ui_bridge must be updated // NB: if we start to use this, the ui_bridge must be updated
// to make a copy for the tui thread // to make a copy for the tui thread
static void tui_event(UI *ui, char *name, Array args, bool *args_consumed) static void tui_event(UI *ui, char *name, Array args, bool *args_consumed)

View File

@ -339,6 +339,7 @@ void ui_attach_impl(UI *ui)
} }
uis[ui_count++] = ui; uis[ui_count++] = ui;
ui_refresh_options();
ui_refresh(); ui_refresh();
} }

View File

@ -31,11 +31,9 @@ struct ui_t {
bool ui_ext[UI_WIDGETS]; ///< Externalized widgets bool ui_ext[UI_WIDGETS]; ///< Externalized widgets
int width, height; int width, height;
void *data; void *data;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_events.generated.h" # include "ui_events.generated.h"
#endif #endif
void (*event)(UI *ui, char *name, Array args, bool *args_consumed); void (*event)(UI *ui, char *name, Array args, bool *args_consumed);
void (*stop)(UI *ui); void (*stop)(UI *ui);
}; };

View File

@ -66,6 +66,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.suspend = ui_bridge_suspend; rv->bridge.suspend = ui_bridge_suspend;
rv->bridge.set_title = ui_bridge_set_title; rv->bridge.set_title = ui_bridge_set_title;
rv->bridge.set_icon = ui_bridge_set_icon; rv->bridge.set_icon = ui_bridge_set_icon;
rv->bridge.option_set = ui_bridge_option_set;
rv->scheduler = scheduler; rv->scheduler = scheduler;
for (UIWidget i = 0; (int)i < UI_WIDGETS; i++) { for (UIWidget i = 0; (int)i < UI_WIDGETS; i++) {
@ -144,6 +145,29 @@ static void ui_bridge_highlight_set_event(void **argv)
xfree(argv[1]); xfree(argv[1]);
} }
static void ui_bridge_option_set(UI *ui, String name, Object value)
{
// Assumes bridge is only used by TUI
if (strequal(name.data, "termguicolors")) {
ui->rgb = value.data.boolean;
}
String copy_name = copy_string(name);
Object *copy_value = xmalloc(sizeof(Object));
*copy_value = copy_object(value);
UI_BRIDGE_CALL(ui, option_set, 4, ui,
copy_name.data, INT2PTR(copy_name.size), copy_value);
}
static void ui_bridge_option_set_event(void **argv)
{
UI *ui = UI(argv[0]);
String name = (String){ .data = argv[1], .size = (size_t)argv[2] };
Object value = *(Object *)argv[3];
ui->option_set(ui, name, value);
api_free_string(name);
api_free_object(value);
xfree(argv[3]);
}
static void ui_bridge_suspend(UI *b) static void ui_bridge_suspend(UI *b)
{ {
UIBridgeData *data = (UIBridgeData *)b; UIBridgeData *data = (UIBridgeData *)b;

View File

@ -2096,8 +2096,8 @@ void undo_time(long step, int sec, int file, int absolute)
uhp = uhp->uh_prev.ptr; uhp = uhp->uh_prev.ptr;
if (uhp == NULL || uhp->uh_walk != mark) { if (uhp == NULL || uhp->uh_walk != mark) {
/* Need to redo more but can't find it... */ // Need to redo more but can't find it...
EMSG2(_(e_intern2), "undo_time()"); internal_error("undo_time()");
break; break;
} }
} }
@ -2163,8 +2163,8 @@ static void u_undoredo(int undo)
if (top > curbuf->b_ml.ml_line_count || top >= bot if (top > curbuf->b_ml.ml_line_count || top >= bot
|| bot > curbuf->b_ml.ml_line_count + 1) { || bot > curbuf->b_ml.ml_line_count + 1) {
unblock_autocmds(); unblock_autocmds();
EMSG(_("E438: u_undo: line numbers wrong")); IEMSG(_("E438: u_undo: line numbers wrong"));
changed(); /* don't want UNCHANGED now */ changed(); // don't want UNCHANGED now
return; return;
} }
@ -2655,7 +2655,7 @@ static void u_unch_branch(u_header_T *uhp)
static u_entry_T *u_get_headentry(void) static u_entry_T *u_get_headentry(void)
{ {
if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL) { if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL) {
EMSG(_("E439: undo list corrupt")); IEMSG(_("E439: undo list corrupt"));
return NULL; return NULL;
} }
return curbuf->b_u_newhead->uh_entry; return curbuf->b_u_newhead->uh_entry;
@ -2684,11 +2684,11 @@ static void u_getbot(void)
extra = curbuf->b_ml.ml_line_count - uep->ue_lcount; extra = curbuf->b_ml.ml_line_count - uep->ue_lcount;
uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra; uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra;
if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count) { if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count) {
EMSG(_("E440: undo line missing")); IEMSG(_("E440: undo line missing"));
uep->ue_bot = uep->ue_top + 1; /* assume all lines deleted, will uep->ue_bot = uep->ue_top + 1; // assume all lines deleted, will
* get all the old lines back // get all the old lines back
* without deleting the current // without deleting the current
* ones */ // ones
} }
curbuf->b_u_newhead->uh_getbot_entry = NULL; curbuf->b_u_newhead->uh_getbot_entry = NULL;

View File

@ -1182,7 +1182,7 @@ static const int included_patches[] = {
// 77 NA // 77 NA
// 76 NA // 76 NA
75, 75,
// 74, 74,
73, 73,
// 72 NA // 72 NA
// 71 NA // 71 NA

View File

@ -2115,7 +2115,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
ptp = ptp->tp_next) ptp = ptp->tp_next)
; ;
if (ptp == NULL) { if (ptp == NULL) {
EMSG2(_(e_intern2), "win_close_othertab()"); internal_error("win_close_othertab()");
return; return;
} }
ptp->tp_next = tp->tp_next; ptp->tp_next = tp->tp_next;

View File

@ -4,6 +4,7 @@ local global_helpers = require('test.helpers')
local uname = global_helpers.uname local uname = global_helpers.uname
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers') local thelpers = require('test.functional.terminal.helpers')
local Screen = require('test.functional.ui.screen')
local eq = helpers.eq local eq = helpers.eq
local feed_data = thelpers.feed_data local feed_data = thelpers.feed_data
local feed_command = helpers.feed_command local feed_command = helpers.feed_command
@ -179,6 +180,58 @@ describe('tui', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
end) end)
it('allows termguicolors to be set at runtime', function()
screen:set_option('rgb', true)
screen:set_default_attr_ids({
[1] = {reverse = true},
[2] = {foreground = 13, special = Screen.colors.Grey0},
[3] = {special = Screen.colors.Grey0, bold = true, reverse = true},
[4] = {bold = true},
[5] = {special = Screen.colors.Grey0, reverse = true, foreground = 4},
[6] = {foreground = 4, special = Screen.colors.Grey0},
[7] = {special = Screen.colors.Grey0, reverse = true, foreground = Screen.colors.SeaGreen4},
[8] = {foreground = Screen.colors.SeaGreen4, special = Screen.colors.Grey0},
[9] = {special = Screen.colors.Grey0, bold = true, foreground = Screen.colors.Blue1},
})
feed_data(':hi SpecialKey ctermfg=3 guifg=SeaGreen\n')
feed_data('i')
feed_data('\022\007') -- ctrl+g
feed_data('\028\014') -- crtl+\ ctrl+N
feed_data(':set termguicolors?\n')
screen:expect([[
{5:^}{6:G} |
{2:~ }|
{2:~ }|
{2:~ }|
{3:[No Name] [+] }|
notermguicolors |
{4:-- TERMINAL --} |
]])
feed_data(':set termguicolors\n')
screen:expect([[
{7:^}{8:G} |
{9:~ }|
{9:~ }|
{9:~ }|
{3:[No Name] [+] }|
|
{4:-- TERMINAL --} |
]])
feed_data(':set notermguicolors\n')
screen:expect([[
{5:^}{6:G} |
{2:~ }|
{2:~ }|
{2:~ }|
{3:[No Name] [+] }|
|
{4:-- TERMINAL --} |
]])
end)
end) end)
describe('tui with non-tty file descriptors', function() describe('tui with non-tty file descriptors', function()

View File

@ -0,0 +1,66 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
describe('ui receives option updates', function()
local screen
before_each(function()
clear()
screen = Screen.new(20,5)
screen:attach()
end)
after_each(function()
screen:detach()
end)
local defaults = {
ambiwidth='single',
arabicshape=true,
emoji=true,
guifont='',
guifontset='',
guifontwide='',
showtabline=1,
termguicolors=false,
}
it("for defaults", function()
screen:expect(function()
eq(defaults, screen.options)
end)
end)
it("when setting options", function()
local changed = {}
for k,v in pairs(defaults) do
changed[k] = v
end
command("set termguicolors")
changed.termguicolors = true
screen:expect(function()
eq(changed, screen.options)
end)
command("set guifont=Comic\\ Sans")
changed.guifont = "Comic Sans"
screen:expect(function()
eq(changed, screen.options)
end)
command("set showtabline=0")
changed.showtabline = 0
screen:expect(function()
eq(changed, screen.options)
end)
command("set all&")
screen:expect(function()
eq(defaults, screen.options)
end)
end)
end)

View File

@ -137,6 +137,7 @@ function Screen.new(width, height)
visual_bell = false, visual_bell = false,
suspended = false, suspended = false,
mode = 'normal', mode = 'normal',
options = {},
_default_attr_ids = nil, _default_attr_ids = nil,
_default_attr_ignore = nil, _default_attr_ignore = nil,
_mouse_enabled = true, _mouse_enabled = true,
@ -482,6 +483,10 @@ function Screen:_handle_set_icon(icon)
self.icon = icon self.icon = icon
end end
function Screen:_handle_option_set(name, value)
self.options[name] = value
end
function Screen:_clear_block(top, bot, left, right) function Screen:_clear_block(top, bot, left, right)
for i = top, bot do for i = top, bot do
self:_clear_row_section(i, left, right) self:_clear_row_section(i, left, right)