mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	feat(api): set statuscolumn line number in nvim_eval_statusline()
Having the user set `v:lnum` before calling `nvim_eval_statusline()` is unnecesarily fragile. Redraws inbetween setting `v:lnum` and the `nvim_eval_statusline()` call will overwrite `v:lnum`.
This commit is contained in:
		| @@ -773,8 +773,8 @@ nvim_eval_statusline({str}, {*opts})                  *nvim_eval_statusline()* | |||||||
|                 • use_tabline: (boolean) Evaluate tabline instead of |                 • use_tabline: (boolean) Evaluate tabline instead of | ||||||
|                   statusline. When true, {winid} is ignored. Mutually |                   statusline. When true, {winid} is ignored. Mutually | ||||||
|                   exclusive with {use_winbar}. |                   exclusive with {use_winbar}. | ||||||
|                 • use_statuscol: (boolean) Evaluate statuscolumn instead of |                 • use_statuscol_lnum: (number) Evaluate statuscolumn for this | ||||||
|                   statusline. |                   line number instead of statusline. | ||||||
|  |  | ||||||
|     Return: ~ |     Return: ~ | ||||||
|         Dictionary containing statusline information, with these keys: |         Dictionary containing statusline information, with these keys: | ||||||
|   | |||||||
| @@ -74,7 +74,7 @@ NEW FEATURES                                                    *news-features* | |||||||
| The following new APIs or features were added. | The following new APIs or features were added. | ||||||
|  |  | ||||||
| • |nvim_eval_statusline()| supports evaluating the |'statuscolumn'| through a | • |nvim_eval_statusline()| supports evaluating the |'statuscolumn'| through a | ||||||
|   new `opts` field: `use_statuscol`. |   new `opts` field: `use_statuscol_lnum`. | ||||||
|  |  | ||||||
| • |nvim_buf_get_extmarks()| now accepts a -1 `ns_id` to request extmarks from | • |nvim_buf_get_extmarks()| now accepts a -1 `ns_id` to request extmarks from | ||||||
|   all namespaces and adds the namespace id to the details array. |   all namespaces and adds the namespace id to the details array. | ||||||
|   | |||||||
| @@ -97,7 +97,7 @@ return { | |||||||
|     "highlights"; |     "highlights"; | ||||||
|     "use_winbar"; |     "use_winbar"; | ||||||
|     "use_tabline"; |     "use_tabline"; | ||||||
|     "use_statuscol"; |     "use_statuscol_lnum"; | ||||||
|   }}; |   }}; | ||||||
|   { 'option', { |   { 'option', { | ||||||
|     "scope"; |     "scope"; | ||||||
|   | |||||||
| @@ -2056,7 +2056,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) | |||||||
| ///           - use_winbar: (boolean) Evaluate winbar instead of statusline. | ///           - use_winbar: (boolean) Evaluate winbar instead of statusline. | ||||||
| ///           - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} | ///           - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} | ||||||
| ///                                    is ignored. Mutually exclusive with {use_winbar}. | ///                                    is ignored. Mutually exclusive with {use_winbar}. | ||||||
| ///           - use_statuscol: (boolean) Evaluate statuscolumn instead of statusline. | ///           - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline. | ||||||
| /// | /// | ||||||
| /// @param[out] err Error details, if any. | /// @param[out] err Error details, if any. | ||||||
| /// @return Dictionary containing statusline information, with these keys: | /// @return Dictionary containing statusline information, with these keys: | ||||||
| @@ -2075,10 +2075,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|   int maxwidth; |   int maxwidth; | ||||||
|   int fillchar = 0; |   int fillchar = 0; | ||||||
|   int use_bools = 0; |   int use_bools = 0; | ||||||
|  |   int statuscol_lnum = 0; | ||||||
|   Window window = 0; |   Window window = 0; | ||||||
|   bool use_winbar = false; |   bool use_winbar = false; | ||||||
|   bool use_tabline = false; |   bool use_tabline = false; | ||||||
|   bool use_statuscol = false; |  | ||||||
|   bool highlights = false; |   bool highlights = false; | ||||||
|  |  | ||||||
|   if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { |   if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { | ||||||
| @@ -2116,47 +2116,48 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|   } |   } | ||||||
|   if (HAS_KEY(opts->use_winbar)) { |   if (HAS_KEY(opts->use_winbar)) { | ||||||
|     use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err); |     use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err); | ||||||
|     use_bools++; |  | ||||||
|     if (ERROR_SET(err)) { |     if (ERROR_SET(err)) { | ||||||
|       return result; |       return result; | ||||||
|     } |     } | ||||||
|  |     use_bools++; | ||||||
|   } |   } | ||||||
|   if (HAS_KEY(opts->use_tabline)) { |   if (HAS_KEY(opts->use_tabline)) { | ||||||
|     use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err); |     use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err); | ||||||
|     use_bools++; |  | ||||||
|     if (ERROR_SET(err)) { |     if (ERROR_SET(err)) { | ||||||
|       return result; |       return result; | ||||||
|     } |     } | ||||||
|  |     use_bools++; | ||||||
|   } |   } | ||||||
|   if (HAS_KEY(opts->use_statuscol)) { |  | ||||||
|     use_statuscol = api_object_to_bool(opts->use_statuscol, "use_statuscol", false, err); |   win_T *wp = use_tabline ? curwin : find_window_by_handle(window, err); | ||||||
|     use_bools++; |   if (wp == NULL) { | ||||||
|     if (ERROR_SET(err)) { |     api_set_error(err, kErrorTypeException, "unknown winid %d", window); | ||||||
|  |     return result; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (HAS_KEY(opts->use_statuscol_lnum)) { | ||||||
|  |     VALIDATE_T("use_statuscol_lnum", kObjectTypeInteger, opts->use_statuscol_lnum.type, { | ||||||
|       return result; |       return result; | ||||||
|     } |     }); | ||||||
|  |     statuscol_lnum = (int)opts->use_statuscol_lnum.data.integer; | ||||||
|  |     VALIDATE_RANGE(statuscol_lnum > 0 && statuscol_lnum <= wp->w_buffer->b_ml.ml_line_count, | ||||||
|  |                    "use_statuscol_lnum", { | ||||||
|  |       return result; | ||||||
|  |     }); | ||||||
|  |     use_bools++; | ||||||
|   } |   } | ||||||
|   VALIDATE(use_bools <= 1, "%s", |   VALIDATE(use_bools <= 1, "%s", | ||||||
|            "Can only use one of 'use_winbar', 'use_tabline' and 'use_statuscol'", { |            "Can only use one of 'use_winbar', 'use_tabline' and 'use_statuscol_lnum'", { | ||||||
|     return result; |     return result; | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   win_T *wp, *ewp; |  | ||||||
|   int stc_hl_id = 0; |   int stc_hl_id = 0; | ||||||
|   statuscol_T statuscol = { 0 }; |   statuscol_T statuscol = { 0 }; | ||||||
|   SignTextAttrs sattrs[SIGN_SHOW_MAX] = { 0 }; |   SignTextAttrs sattrs[SIGN_SHOW_MAX] = { 0 }; | ||||||
|  |  | ||||||
|   if (use_tabline) { |   if (use_tabline) { | ||||||
|     wp = NULL; |  | ||||||
|     ewp = curwin; |  | ||||||
|     fillchar = ' '; |     fillchar = ' '; | ||||||
|   } else { |   } else { | ||||||
|     wp = find_window_by_handle(window, err); |  | ||||||
|     if (wp == NULL) { |  | ||||||
|       api_set_error(err, kErrorTypeException, "unknown winid %d", window); |  | ||||||
|       return result; |  | ||||||
|     } |  | ||||||
|     ewp = wp; |  | ||||||
|  |  | ||||||
|     if (fillchar == 0) { |     if (fillchar == 0) { | ||||||
|       if (use_winbar) { |       if (use_winbar) { | ||||||
|         fillchar = wp->w_p_fcs_chars.wbr; |         fillchar = wp->w_p_fcs_chars.wbr; | ||||||
| @@ -2165,18 +2166,25 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|         fillchar = fillchar_status(&attr, wp); |         fillchar = fillchar_status(&attr, wp); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (use_statuscol) { |     if (statuscol_lnum) { | ||||||
|       HlPriId line = { 0 }; |       HlPriId line = { 0 }; | ||||||
|       HlPriId cul  = { 0 }; |       HlPriId cul  = { 0 }; | ||||||
|       HlPriId num  = { 0 }; |       HlPriId num  = { 0 }; | ||||||
|       linenr_T lnum = (linenr_T)get_vim_var_nr(VV_LNUM); |       linenr_T lnum = statuscol_lnum; | ||||||
|       int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); |       int num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs, &num, &line, &cul); | ||||||
|       decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); |       decor_redraw_signs(wp->w_buffer, lnum - 1, &num_signs, sattrs, &num, &line, &cul); | ||||||
|  |  | ||||||
|       statuscol.sattrs = sattrs; |       statuscol.sattrs = sattrs; | ||||||
|       statuscol.foldinfo = fold_info(wp, lnum); |       statuscol.foldinfo = fold_info(wp, lnum); | ||||||
|       statuscol.use_cul = wp->w_p_cul && lnum == wp->w_cursorline |       wp->w_cursorline = win_cursorline_standout(wp) ? wp->w_cursor.lnum : 0; | ||||||
|                           && (wp->w_p_culopt_flags & CULOPT_NBR); |  | ||||||
|  |       if (wp->w_p_cul) { | ||||||
|  |         if (statuscol.foldinfo.fi_level > 0 && statuscol.foldinfo.fi_lines > 0) { | ||||||
|  |           wp->w_cursorline = statuscol.foldinfo.fi_lnum; | ||||||
|  |         } | ||||||
|  |         statuscol.use_cul = lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); | ||||||
|  |       } | ||||||
|  |  | ||||||
|       statuscol.sign_cul_id = statuscol.use_cul ? cul.hl_id : 0; |       statuscol.sign_cul_id = statuscol.use_cul ? cul.hl_id : 0; | ||||||
|       if (num.hl_id) { |       if (num.hl_id) { | ||||||
|         stc_hl_id = num.hl_id; |         stc_hl_id = num.hl_id; | ||||||
| @@ -2187,6 +2195,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|       } else { |       } else { | ||||||
|         stc_hl_id = HLF_N + 1; |         stc_hl_id = HLF_N + 1; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       set_vim_var_nr(VV_LNUM, lnum); | ||||||
|       set_vim_var_nr(VV_RELNUM, labs(get_cursor_rel_lnum(wp, lnum))); |       set_vim_var_nr(VV_RELNUM, labs(get_cursor_rel_lnum(wp, lnum))); | ||||||
|       set_vim_var_nr(VV_VIRTNUM, 0); |       set_vim_var_nr(VV_VIRTNUM, 0); | ||||||
|     } |     } | ||||||
| @@ -2199,7 +2209,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|  |  | ||||||
|     maxwidth = (int)opts->maxwidth.data.integer; |     maxwidth = (int)opts->maxwidth.data.integer; | ||||||
|   } else { |   } else { | ||||||
|     maxwidth = use_statuscol ? win_col_off(wp) |     maxwidth = statuscol_lnum ? win_col_off(wp) | ||||||
|                : (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; |                : (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -2207,10 +2217,10 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|   stl_hlrec_t *hltab; |   stl_hlrec_t *hltab; | ||||||
|  |  | ||||||
|   // Temporarily reset 'cursorbind' to prevent side effects from moving the cursor away and back. |   // Temporarily reset 'cursorbind' to prevent side effects from moving the cursor away and back. | ||||||
|   int p_crb_save = ewp->w_p_crb; |   int p_crb_save = wp->w_p_crb; | ||||||
|   ewp->w_p_crb = false; |   wp->w_p_crb = false; | ||||||
|  |  | ||||||
|   int width = build_stl_str_hl(ewp, |   int width = build_stl_str_hl(wp, | ||||||
|                                buf, |                                buf, | ||||||
|                                sizeof(buf), |                                sizeof(buf), | ||||||
|                                str.data, |                                str.data, | ||||||
| @@ -2220,12 +2230,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|                                maxwidth, |                                maxwidth, | ||||||
|                                highlights ? &hltab : NULL, |                                highlights ? &hltab : NULL, | ||||||
|                                NULL, |                                NULL, | ||||||
|                                use_statuscol ? &statuscol : NULL); |                                statuscol_lnum ? &statuscol : NULL); | ||||||
|  |  | ||||||
|   PUT(result, "width", INTEGER_OBJ(width)); |   PUT(result, "width", INTEGER_OBJ(width)); | ||||||
|  |  | ||||||
|   // Restore original value of 'cursorbind' |   // Restore original value of 'cursorbind' | ||||||
|   ewp->w_p_crb = p_crb_save; |   wp->w_p_crb = p_crb_save; | ||||||
|  |  | ||||||
|   if (highlights) { |   if (highlights) { | ||||||
|     Array hl_values = ARRAY_DICT_INIT; |     Array hl_values = ARRAY_DICT_INIT; | ||||||
| @@ -2236,7 +2246,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|     // add the default highlight at the beginning of the highlight list |     // add the default highlight at the beginning of the highlight list | ||||||
|     if (hltab->start == NULL || (hltab->start - buf) != 0) { |     if (hltab->start == NULL || (hltab->start - buf) != 0) { | ||||||
|       Dictionary hl_info = ARRAY_DICT_INIT; |       Dictionary hl_info = ARRAY_DICT_INIT; | ||||||
|       grpname = get_default_stl_hl(wp, use_winbar, stc_hl_id); |       grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id); | ||||||
|  |  | ||||||
|       PUT(hl_info, "start", INTEGER_OBJ(0)); |       PUT(hl_info, "start", INTEGER_OBJ(0)); | ||||||
|       PUT(hl_info, "group", CSTR_TO_OBJ(grpname)); |       PUT(hl_info, "group", CSTR_TO_OBJ(grpname)); | ||||||
| @@ -2250,7 +2260,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * | |||||||
|       PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); |       PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); | ||||||
|  |  | ||||||
|       if (sp->userhl == 0) { |       if (sp->userhl == 0) { | ||||||
|         grpname = get_default_stl_hl(wp, use_winbar, stc_hl_id); |         grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id); | ||||||
|       } else if (sp->userhl < 0) { |       } else if (sp->userhl < 0) { | ||||||
|         grpname = syn_id2name(-sp->userhl); |         grpname = syn_id2name(-sp->userhl); | ||||||
|       } else { |       } else { | ||||||
|   | |||||||
| @@ -3422,7 +3422,7 @@ describe('API', function() | |||||||
|             { use_winbar = true, highlights = true })) |             { use_winbar = true, highlights = true })) | ||||||
|       end) |       end) | ||||||
|       it('works with statuscolumn', function() |       it('works with statuscolumn', function() | ||||||
|         command([[ |         exec([[ | ||||||
|           let &stc='%C%s%=%l ' |           let &stc='%C%s%=%l ' | ||||||
|           set cul nu nuw=3 scl=yes:2 fdc=2 |           set cul nu nuw=3 scl=yes:2 fdc=2 | ||||||
|           call setline(1, repeat(['aaaaa'], 5)) |           call setline(1, repeat(['aaaaa'], 5)) | ||||||
| @@ -3431,9 +3431,8 @@ describe('API', function() | |||||||
|           call sign_place(2, 1, 'a', bufnr(), {'lnum':4}) |           call sign_place(2, 1, 'a', bufnr(), {'lnum':4}) | ||||||
|           call nvim_buf_set_extmark(0, g:ns, 3, 1, { 'sign_text':'bb', 'sign_hl_group':'ErrorMsg' }) |           call nvim_buf_set_extmark(0, g:ns, 3, 1, { 'sign_text':'bb', 'sign_hl_group':'ErrorMsg' }) | ||||||
|           1,5fold | 1,5 fold | foldopen! |           1,5fold | 1,5 fold | foldopen! | ||||||
|  |           norm 4G | ||||||
|         ]]) |         ]]) | ||||||
|         command('norm 4G') |  | ||||||
|         command('let v:lnum=4') |  | ||||||
|         eq({ |         eq({ | ||||||
|           str = '││aabb 4 ', |           str = '││aabb 4 ', | ||||||
|           width = 9, |           width = 9, | ||||||
| @@ -3444,8 +3443,7 @@ describe('API', function() | |||||||
|             { group = 'ErrorMsg', start = 8 }, |             { group = 'ErrorMsg', start = 8 }, | ||||||
|             { group = 'Normal', start = 10 } |             { group = 'Normal', start = 10 } | ||||||
|           } |           } | ||||||
|         }, meths.eval_statusline('%C%s%=%l ', { use_statuscol = true, highlights = true })) |         }, meths.eval_statusline('%C%s%=%l ', { use_statuscol_lnum = 4, highlights = true })) | ||||||
|         command('let v:lnum=3') |  | ||||||
|         eq({ |         eq({ | ||||||
|           str = '3 ' , |           str = '3 ' , | ||||||
|           width = 2, |           width = 2, | ||||||
| @@ -3453,7 +3451,7 @@ describe('API', function() | |||||||
|             { group = 'LineNr', start = 0 }, |             { group = 'LineNr', start = 0 }, | ||||||
|             { group = 'ErrorMsg', start = 1 } |             { group = 'ErrorMsg', start = 1 } | ||||||
|           } |           } | ||||||
|         }, meths.eval_statusline('%l%#ErrorMsg# ', { use_statuscol = true, highlights = true })) |         }, meths.eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true })) | ||||||
|       end) |       end) | ||||||
|       it('no memory leak with click functions', function() |       it('no memory leak with click functions', function() | ||||||
|         meths.eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {}) |         meths.eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Luuk van Baal
					Luuk van Baal