diff options
author | Famiu Haque <famiuhaque@protonmail.com> | 2021-10-19 01:44:17 +0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-18 12:44:17 -0700 |
commit | 9086938f7bd6d6ccb7f4a30fb78aeaf0d84e4471 (patch) | |
tree | 9e286903da8123085956beaf7eb9dd33e5741aad /src/nvim/api/vim.c | |
parent | e7ea54a3dfaf937021e68bc690c4d27eed9c1cca (diff) | |
download | rneovim-9086938f7bd6d6ccb7f4a30fb78aeaf0d84e4471.tar.gz rneovim-9086938f7bd6d6ccb7f4a30fb78aeaf0d84e4471.tar.bz2 rneovim-9086938f7bd6d6ccb7f4a30fb78aeaf0d84e4471.zip |
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
Diffstat (limited to 'src/nvim/api/vim.c')
-rw-r--r-- | src/nvim/api/vim.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 847e142939..a3143efe0c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -17,6 +17,7 @@ #include "nvim/api/window.h" #include "nvim/ascii.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/context.h" #include "nvim/decoration.h" #include "nvim/edit.h" @@ -2906,3 +2907,165 @@ Array nvim_get_mark(String name, Error *err) 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; +} |