diff options
author | Evgeni Chasnovski <evgeni.chasnovski@gmail.com> | 2023-08-25 10:53:35 +0300 |
---|---|---|
committer | Evgeni Chasnovski <evgeni.chasnovski@gmail.com> | 2023-08-26 19:37:43 +0300 |
commit | 35570e4a11bef061777d741929f74fa66ba3f45a (patch) | |
tree | ef0a8587fa7f7cb30ca8241dae5b2d2cb6d72fc3 /src | |
parent | 617fd5bdc6ab9a82bfc6136f549fc31dcf442ed7 (diff) | |
download | rneovim-35570e4a11bef061777d741929f74fa66ba3f45a.tar.gz rneovim-35570e4a11bef061777d741929f74fa66ba3f45a.tar.bz2 rneovim-35570e4a11bef061777d741929f74fa66ba3f45a.zip |
feat(float): implement footer
Problem: Now way to show text at the bottom part of floating window
border (a.k.a. "footer").
Solution: Allows `footer` and `footer_pos` config fields similar to
`title` and `title_pos`.
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/keysets.h | 2 | ||||
-rw-r--r-- | src/nvim/api/win_config.c | 83 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 7 | ||||
-rw-r--r-- | src/nvim/drawscreen.c | 7 | ||||
-rw-r--r-- | src/nvim/window.c | 3 |
5 files changed, 90 insertions, 12 deletions
diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h index a47e278cad..1f5c7069a9 100644 --- a/src/nvim/api/keysets.h +++ b/src/nvim/api/keysets.h @@ -99,6 +99,8 @@ typedef struct { Object border; Object title; String title_pos; + Object footer; + String footer_pos; String style; Boolean noautocmd; } Dict(float_config); diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 9473803652..325d0cbfa0 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -145,11 +145,18 @@ /// By default, `FloatBorder` highlight is used, which links to `WinSeparator` /// when not defined. It could also be specified by character: /// [ ["+", "MyCorner"], ["x", "MyBorder"] ]. -/// - title: Title (optional) in window border, String or list. -/// List is [text, highlight] tuples. if is string the default -/// highlight group is `FloatTitle`. -/// - title_pos: Title position must set with title option. -/// value can be of `left` `center` `right` default is left. +/// - title: Title (optional) in window border, string or list. +/// List should consist of `[text, highlight]` tuples. +/// If string, the default highlight group is `FloatTitle`. +/// - title_pos: Title position. Must be set with `title` option. +/// Value can be one of "left", "center", or "right". +/// Default is `"left"`. +/// - footer: Footer (optional) in window border, string or list. +/// List should consist of `[text, highlight]` tuples. +/// If string, the default highlight group is `FloatTitle`. +/// - footer_pos: Footer position. Must be set with `footer` option. +/// Value can be one of "left", "center", or "right". +/// Default is `"left"`. /// - noautocmd: If true then no buffer-related autocommand events such as /// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from /// calling this function. @@ -247,11 +254,19 @@ Dictionary config_put_bordertext(Dictionary config, FloatConfig *fconfig, AlignTextPos align; char *field_name; char *field_pos_name; - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: chunks = fconfig->title_chunks; align = fconfig->title_pos; field_name = "title"; field_pos_name = "title_pos"; + break; + case kBorderTextFooter: + chunks = fconfig->footer_chunks; + align = fconfig->footer_pos; + field_name = "footer"; + field_pos_name = "footer_pos"; + break; } Array bordertext = ARRAY_DICT_INIT; @@ -345,6 +360,9 @@ Dictionary nvim_win_get_config(Window window, Error *err) if (config->title) { rv = config_put_bordertext(rv, config, kBorderTextTitle); } + if (config->footer) { + rv = config_put_bordertext(rv, config, kBorderTextFooter); + } } } @@ -410,10 +428,17 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, bool *is_present; VirtText *chunks; int *width; - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: is_present = &fconfig->title; chunks = &fconfig->title_chunks; width = &fconfig->title_width; + break; + case kBorderTextFooter: + is_present = &fconfig->footer; + chunks = &fconfig->footer_chunks; + width = &fconfig->footer_width; + break; } if (bordertext.type == kObjectTypeString) { @@ -449,8 +474,13 @@ static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertex FloatConfig *fconfig, Error *err) { AlignTextPos *align; - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: align = &fconfig->title_pos; + break; + case kBorderTextFooter: + align = &fconfig->footer_pos; + break; } if (bordertext_pos.size == 0) { @@ -467,8 +497,13 @@ static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertex } else if (strequal(pos, "right")) { *align = kAlignRight; } else { - if (bordertext_type == kBorderTextTitle) { + switch (bordertext_type) { + case kBorderTextTitle: api_set_error(err, kErrorTypeValidation, "invalid title_pos value"); + break; + case kBorderTextFooter: + api_set_error(err, kErrorTypeValidation, "invalid footer_pos value"); + break; } return false; } @@ -559,8 +594,9 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) String str = style.data.string; if (str.size == 0 || strequal(str.data, "none")) { fconfig->border = false; - // title does not work with border equal none + // border text does not work with border equal none fconfig->title = false; + fconfig->footer = false; return; } for (size_t i = 0; defaults[i].name; i++) { @@ -750,6 +786,33 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, } } + if (HAS_KEY_X(config, footer)) { + // footer only work with border + if (!HAS_KEY_X(config, border) && !fconfig->border) { + api_set_error(err, kErrorTypeException, "footer requires border to be set"); + return false; + } + + if (fconfig->footer) { + clear_virttext(&fconfig->footer_chunks); + } + + parse_bordertext(config->footer, kBorderTextFooter, fconfig, err); + if (ERROR_SET(err)) { + return false; + } + + // handles unset 'footer_pos' same as empty string + if (!parse_bordertext_pos(config->footer_pos, kBorderTextFooter, fconfig, err)) { + return false; + } + } else { + if (HAS_KEY_X(config, footer_pos)) { + api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set"); + return false; + } + } + if (HAS_KEY_X(config, border)) { parse_border_style(config->border, fconfig, err); if (ERROR_SET(err)) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index ba6a3a1e27..3f55dbbc00 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -938,6 +938,7 @@ typedef enum { typedef enum { kBorderTextTitle = 0, + kBorderTextFooter = 1, } BorderTextType; typedef struct { @@ -952,14 +953,18 @@ typedef struct { int zindex; WinStyle style; bool border; - bool title; bool shadow; schar_T border_chars[8]; int border_hl_ids[8]; int border_attr[8]; + bool title; AlignTextPos title_pos; VirtText title_chunks; int title_width; + bool footer; + AlignTextPos footer_pos; + VirtText footer_chunks; + int footer_width; bool noautocmd; } FloatConfig; diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 4b23a9f1eb..f71a47a596 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -782,10 +782,17 @@ static void win_redr_border(win_T *wp) if (adj[3]) { grid_put_schar(grid, irow + adj[0], 0, chars[6], attrs[6]); } + for (int i = 0; i < icol; i++) { int ic = (i == 0 && !adj[3] && chars[6][0]) ? 6 : 5; grid_put_schar(grid, irow + adj[0], i + adj[3], chars[ic], attrs[ic]); } + + if (wp->w_float_config.footer) { + int footer_col = win_get_bordertext_col(icol, wp->w_float_config.footer_width, + wp->w_float_config.footer_pos); + win_redr_bordertext(wp, grid, wp->w_float_config.footer_chunks, grid->rows - 1, footer_col); + } if (adj[1]) { grid_put_schar(grid, irow + adj[0], icol + adj[3], chars[4], attrs[4]); } diff --git a/src/nvim/window.c b/src/nvim/window.c index 970027b2f8..e72c32700d 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5239,8 +5239,9 @@ static void win_free(win_T *wp, tabpage_T *tp) } } - // free the border title text + // free the border text clear_virttext(&wp->w_float_config.title_chunks); + clear_virttext(&wp->w_float_config.footer_chunks); clear_matches(wp); |