mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
feat(api): evaluate statusline string #16020
Adds API function `nvim_eval_statusline` to allow evaluating a statusline string and obtaining information regarding it. Closes https://github.com/neovim/neovim/issues/15849
This commit is contained in:
parent
e7ea54a3df
commit
9086938f7b
@ -51,5 +51,12 @@ return {
|
|||||||
runtime = {
|
runtime = {
|
||||||
"is_lua";
|
"is_lua";
|
||||||
};
|
};
|
||||||
|
eval_statusline = {
|
||||||
|
"winid";
|
||||||
|
"maxwidth";
|
||||||
|
"fillchar";
|
||||||
|
"highlights";
|
||||||
|
"use_tabline";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1681,3 +1681,15 @@ bool set_mark(buf_T *buf, String name, Integer line, Integer col, Error *err)
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get default statusline highlight for window
|
||||||
|
const char *get_default_stl_hl(win_T *wp)
|
||||||
|
{
|
||||||
|
if (wp == NULL) {
|
||||||
|
return "TabLineFill";
|
||||||
|
} else if (wp == curwin) {
|
||||||
|
return "StatusLine";
|
||||||
|
} else {
|
||||||
|
return "StatusLineNC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "nvim/api/window.h"
|
#include "nvim/api/window.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
#include "nvim/buffer.h"
|
#include "nvim/buffer.h"
|
||||||
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/context.h"
|
#include "nvim/context.h"
|
||||||
#include "nvim/decoration.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/edit.h"
|
#include "nvim/edit.h"
|
||||||
@ -2906,3 +2907,165 @@ Array nvim_get_mark(String name, Error *err)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluates statusline string.
|
||||||
|
///
|
||||||
|
/// @param str Statusline string (see 'statusline').
|
||||||
|
/// @param opts Optional parameters.
|
||||||
|
/// - winid: (number) |window-ID| of the window to use as context for statusline.
|
||||||
|
/// - maxwidth: (number) Maximum width of statusline.
|
||||||
|
/// - fillchar: (string) Character to fill blank spaces in the statusline (see
|
||||||
|
/// 'fillchars').
|
||||||
|
/// - highlights: (boolean) Return highlight information.
|
||||||
|
/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When |TRUE|, {winid}
|
||||||
|
/// is ignored.
|
||||||
|
///
|
||||||
|
/// @param[out] err Error details, if any.
|
||||||
|
/// @return Dictionary containing statusline information, with these keys:
|
||||||
|
/// - str: (string) Characters that will be displayed on the statusline.
|
||||||
|
/// - width: (number) Display width of the statusline.
|
||||||
|
/// - highlights: Array containing highlight information of the statusline. Only included when
|
||||||
|
/// the "highlights" key in {opts} is |TRUE|. Each element of the array is a
|
||||||
|
/// |Dictionary| with these keys:
|
||||||
|
/// - start: (number) Byte index (0-based) of first character that uses the highlight.
|
||||||
|
/// - group: (string) Name of highlight group.
|
||||||
|
Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *err)
|
||||||
|
FUNC_API_SINCE(8) FUNC_API_FAST
|
||||||
|
{
|
||||||
|
Dictionary result = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
|
Window window = 0;
|
||||||
|
int maxwidth = 0;
|
||||||
|
char fillchar = 0;
|
||||||
|
bool use_tabline = false;
|
||||||
|
bool highlights = false;
|
||||||
|
|
||||||
|
if (HAS_KEY(opts->winid)) {
|
||||||
|
if (opts->winid.type != kObjectTypeInteger) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "winid must be an integer");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
window = (Window)opts->winid.data.integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY(opts->maxwidth)) {
|
||||||
|
if (opts->maxwidth.type != kObjectTypeInteger) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "maxwidth must be an integer");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxwidth = (int)opts->maxwidth.data.integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY(opts->fillchar)) {
|
||||||
|
if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size > 1) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "fillchar must be an ASCII character");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillchar = opts->fillchar.data.string.data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY(opts->highlights)) {
|
||||||
|
highlights = api_object_to_bool(opts->highlights, "highlights", false, err);
|
||||||
|
|
||||||
|
if (ERROR_SET(err)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY(opts->use_tabline)) {
|
||||||
|
use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err);
|
||||||
|
|
||||||
|
if (ERROR_SET(err)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
win_T *wp, *ewp;
|
||||||
|
|
||||||
|
if (use_tabline) {
|
||||||
|
wp = NULL;
|
||||||
|
ewp = curwin;
|
||||||
|
fillchar = ' ';
|
||||||
|
} else {
|
||||||
|
wp = find_window_by_handle(window, err);
|
||||||
|
ewp = wp;
|
||||||
|
|
||||||
|
if (fillchar == 0) {
|
||||||
|
int attr;
|
||||||
|
fillchar = (char)fillchar_status(&attr, wp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxwidth == 0) {
|
||||||
|
maxwidth = use_tabline ? Columns : wp->w_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[MAXPATHL];
|
||||||
|
stl_hlrec_t *hltab;
|
||||||
|
stl_hlrec_t **hltab_ptr = highlights ? &hltab : NULL;
|
||||||
|
|
||||||
|
// Temporarily reset 'cursorbind' to prevent side effects from moving the cursor away and back.
|
||||||
|
int p_crb_save = ewp->w_p_crb;
|
||||||
|
ewp->w_p_crb = false;
|
||||||
|
|
||||||
|
int width = build_stl_str_hl(
|
||||||
|
ewp,
|
||||||
|
(char_u *)buf,
|
||||||
|
sizeof(buf),
|
||||||
|
(char_u *)str.data,
|
||||||
|
false,
|
||||||
|
(char_u)fillchar,
|
||||||
|
maxwidth,
|
||||||
|
hltab_ptr,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
PUT(result, "width", INTEGER_OBJ(width));
|
||||||
|
|
||||||
|
// Restore original value of 'cursorbind'
|
||||||
|
ewp->w_p_crb = p_crb_save;
|
||||||
|
|
||||||
|
if (highlights) {
|
||||||
|
Array hl_values = ARRAY_DICT_INIT;
|
||||||
|
const char *grpname;
|
||||||
|
char user_group[6];
|
||||||
|
|
||||||
|
// If first character doesn't have a defined highlight,
|
||||||
|
// add the default highlight at the beginning of the highlight list
|
||||||
|
if (hltab->start == NULL || ((char *)hltab->start - buf) != 0) {
|
||||||
|
Dictionary hl_info = ARRAY_DICT_INIT;
|
||||||
|
grpname = get_default_stl_hl(wp);
|
||||||
|
|
||||||
|
PUT(hl_info, "start", INTEGER_OBJ(0));
|
||||||
|
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
|
||||||
|
|
||||||
|
ADD(hl_values, DICTIONARY_OBJ(hl_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (stl_hlrec_t *sp = hltab; sp->start != NULL; sp++) {
|
||||||
|
Dictionary hl_info = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
|
PUT(hl_info, "start", INTEGER_OBJ((char *)sp->start - buf));
|
||||||
|
|
||||||
|
if (sp->userhl == 0) {
|
||||||
|
grpname = get_default_stl_hl(wp);
|
||||||
|
} else if (sp->userhl < 0) {
|
||||||
|
grpname = (char *)syn_id2name(-sp->userhl);
|
||||||
|
} else {
|
||||||
|
snprintf(user_group, sizeof(user_group), "User%d", sp->userhl);
|
||||||
|
grpname = user_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
|
||||||
|
|
||||||
|
ADD(hl_values, DICTIONARY_OBJ(hl_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
PUT(result, "highlights", ARRAY_OBJ(hl_values));
|
||||||
|
}
|
||||||
|
|
||||||
|
PUT(result, "str", CSTR_TO_OBJ((char *)buf));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -7379,7 +7379,7 @@ void get_trans_bufname(buf_T *buf)
|
|||||||
/*
|
/*
|
||||||
* Get the character to use in a status line. Get its attributes in "*attr".
|
* Get the character to use in a status line. Get its attributes in "*attr".
|
||||||
*/
|
*/
|
||||||
static int fillchar_status(int *attr, win_T *wp)
|
int fillchar_status(int *attr, win_T *wp)
|
||||||
{
|
{
|
||||||
int fill;
|
int fill;
|
||||||
bool is_curwin = (wp == curwin);
|
bool is_curwin = (wp == curwin);
|
||||||
|
@ -2367,4 +2367,79 @@ describe('API', function()
|
|||||||
eq({2, 2, buf.id, mark[4]}, mark)
|
eq({2, 2, buf.id, mark[4]}, mark)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
describe('nvim_eval_statusline', function()
|
||||||
|
it('works', function()
|
||||||
|
eq({
|
||||||
|
str = '%StatusLineStringWithHighlights',
|
||||||
|
width = 31
|
||||||
|
},
|
||||||
|
meths.eval_statusline(
|
||||||
|
'%%StatusLineString%#WarningMsg#WithHighlights',
|
||||||
|
{}))
|
||||||
|
end)
|
||||||
|
it('doesn\'t exceed maxwidth', function()
|
||||||
|
eq({
|
||||||
|
str = 'Should be trun>',
|
||||||
|
width = 15
|
||||||
|
},
|
||||||
|
meths.eval_statusline(
|
||||||
|
'Should be truncated%<',
|
||||||
|
{ maxwidth = 15 }))
|
||||||
|
end)
|
||||||
|
describe('highlight parsing', function()
|
||||||
|
it('works', function()
|
||||||
|
eq({
|
||||||
|
str = "TextWithWarningHighlightTextWithUserHighlight",
|
||||||
|
width = 45,
|
||||||
|
highlights = {
|
||||||
|
{ start = 0, group = 'WarningMsg' },
|
||||||
|
{ start = 24, group = 'User1' }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meths.eval_statusline(
|
||||||
|
'%#WarningMsg#TextWithWarningHighlight%1*TextWithUserHighlight',
|
||||||
|
{ highlights = true }))
|
||||||
|
end)
|
||||||
|
it('works with no highlight', function()
|
||||||
|
eq({
|
||||||
|
str = "TextWithNoHighlight",
|
||||||
|
width = 19,
|
||||||
|
highlights = {
|
||||||
|
{ start = 0, group = 'StatusLine' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meths.eval_statusline(
|
||||||
|
'TextWithNoHighlight',
|
||||||
|
{ highlights = true }))
|
||||||
|
end)
|
||||||
|
it('works with inactive statusline', function()
|
||||||
|
command('split')
|
||||||
|
|
||||||
|
eq({
|
||||||
|
str = 'TextWithNoHighlightTextWithWarningHighlight',
|
||||||
|
width = 43,
|
||||||
|
highlights = {
|
||||||
|
{ start = 0, group = 'StatusLineNC' },
|
||||||
|
{ start = 19, group = 'WarningMsg' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
meths.eval_statusline(
|
||||||
|
'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
|
||||||
|
{ winid = meths.list_wins()[2].id, highlights = true }))
|
||||||
|
end)
|
||||||
|
it('works with tabline', function()
|
||||||
|
eq({
|
||||||
|
str = 'TextWithNoHighlightTextWithWarningHighlight',
|
||||||
|
width = 43,
|
||||||
|
highlights = {
|
||||||
|
{ start = 0, group = 'TabLineFill' },
|
||||||
|
{ start = 19, group = 'WarningMsg' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
meths.eval_statusline(
|
||||||
|
'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
|
||||||
|
{ use_tabline = true, highlights = true }))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user