diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/keysets.lua | 2 | ||||
-rw-r--r-- | src/nvim/api/win_config.c | 118 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 12 | ||||
-rw-r--r-- | src/nvim/decoration.h | 1 | ||||
-rw-r--r-- | src/nvim/drawscreen.c | 31 | ||||
-rw-r--r-- | src/nvim/extmark_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/highlight_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/highlight_group.c | 1 | ||||
-rw-r--r-- | src/nvim/window.c | 4 |
9 files changed, 171 insertions, 2 deletions
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index ea8949bd2c..7e0d399573 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -81,6 +81,8 @@ return { "focusable"; "zindex"; "border"; + "title"; + "title_pos"; "style"; "noautocmd"; }; diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 636b9566ce..9f15e5a85b 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -2,14 +2,17 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <assert.h> +#include <inttypes.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> +#include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/win_config.h" #include "nvim/ascii.h" +#include "nvim/buffer_defs.h" #include "nvim/drawscreen.h" #include "nvim/highlight_group.h" #include "nvim/option.h" @@ -134,6 +137,11 @@ /// 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 `FloatBorderTitle`. +/// - title_pos: Title position must set with title option. +/// value can be of `left` `center` `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. @@ -273,6 +281,21 @@ Dictionary nvim_win_get_config(Window window, Error *err) } } PUT(rv, "border", ARRAY_OBJ(border)); + if (config->title) { + Array titles = ARRAY_DICT_INIT; + VirtText title_datas = config->title_chunks; + for (size_t i = 0; i < title_datas.size; i++) { + Array tuple = ARRAY_DICT_INIT; + ADD(tuple, CSTR_TO_OBJ((const char *)title_datas.items[i].text)); + if (title_datas.items[i].hl_id > 0) { + ADD(tuple, + STRING_OBJ(cstr_to_string((const char *)syn_id2name(title_datas.items[i].hl_id)))); + } + ADD(titles, ARRAY_OBJ(tuple)); + } + PUT(rv, "title", ARRAY_OBJ(titles)); + PUT(rv, "title_pos", INTEGER_OBJ(config->title_pos)); + } } } @@ -330,7 +353,75 @@ static bool parse_float_bufpos(Array bufpos, lpos_T *out) return true; } -static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) +static void parse_border_title(Object title, Object title_pos, FloatConfig *fconfig, Error *err) +{ + if (!parse_title_pos(title_pos, fconfig, err)) { + return; + } + + if (title.type == kObjectTypeString) { + if (title.data.string.size == 0) { + fconfig->title = false; + return; + } + int hl_id = syn_check_group(S_LEN("FloatBorderTitle")); + kv_push(fconfig->title_chunks, ((VirtTextChunk){ .text = xstrdup(title.data.string.data), + .hl_id = hl_id })); + fconfig->title_width = (int)mb_string2cells(title.data.string.data); + fconfig->title = true; + return; + } + + if (title.type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, "title must be string or array"); + return; + } + + if (title.type == kObjectTypeArray && title.data.array.size == 0) { + api_set_error(err, kErrorTypeValidation, "title cannot be an empty array"); + return; + } + + fconfig->title_width = 0; + fconfig->title_chunks = parse_virt_text(title.data.array, err, &fconfig->title_width); + + fconfig->title = true; + return; +} + +static bool parse_title_pos(Object title_pos, FloatConfig *fconfig, Error *err) +{ + if (!HAS_KEY(title_pos)) { + fconfig->title_pos = kAlignLeft; + return true; + } + + if (title_pos.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, "title_pos must be string"); + return false; + } + + if (title_pos.data.string.size == 0) { + fconfig->title_pos = kAlignLeft; + return true; + } + + char *pos = title_pos.data.string.data; + + if (strequal(pos, "left")) { + fconfig->title_pos = kAlignLeft; + } else if (strequal(pos, "center")) { + fconfig->title_pos = kAlignCenter; + } else if (strequal(pos, "right")) { + fconfig->title_pos = kAlignRight; + } else { + api_set_error(err, kErrorTypeValidation, "invalid title_pos value"); + return false; + } + return true; +} + +static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) { struct { const char *name; @@ -414,6 +505,8 @@ 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 + fconfig->title = false; return; } for (size_t i = 0; defaults[i].name; i++) { @@ -603,6 +696,29 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, return false; } + if (HAS_KEY(config->title_pos)) { + if (!HAS_KEY(config->title)) { + api_set_error(err, kErrorTypeException, "title_pos requires title to be set"); + return false; + } + } + + if (HAS_KEY(config->title)) { + // title only work with border + if (!HAS_KEY(config->border) && !fconfig->border) { + api_set_error(err, kErrorTypeException, "title requires border to be set"); + return false; + } + + if (fconfig->title) { + clear_virttext(&fconfig->title_chunks); + } + parse_border_title(config->title, config->title_pos, fconfig, err); + if (ERROR_SET(err)) { + return false; + } + } + if (HAS_KEY(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 4e46a1aef2..2b42289858 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -44,6 +44,8 @@ typedef struct { #include "klib/kvec.h" // for marktree #include "nvim/marktree.h" +// for float window title +#include "nvim/extmark_defs.h" #define GETFILE_SUCCESS(x) ((x) <= 0) #define MODIFIABLE(buf) (buf->b_p_ma) @@ -1048,6 +1050,12 @@ typedef enum { kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc } WinStyle; +typedef enum { + kAlignLeft = 0, + kAlignCenter = 1, + kAlignRight = 2, +} AlignTextPos; + typedef struct { Window window; lpos_T bufpos; @@ -1060,10 +1068,14 @@ 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]; + AlignTextPos title_pos; + VirtText title_chunks; + int title_width; bool noautocmd; } FloatConfig; diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index bdbfd72a81..9ba621d7a4 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -28,7 +28,6 @@ typedef enum { EXTERN const char *const hl_mode_str[] INIT(= { "", "replace", "combine", "blend" }); -typedef kvec_t(VirtTextChunk) VirtText; #define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE) typedef kvec_t(struct virt_line { VirtText line; bool left_col; }) VirtLines; diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index adf52ef6e4..30abcd1a31 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -60,11 +60,13 @@ #include <string.h> #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/ex_getln.h" +#include "nvim/extmark_defs.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" @@ -614,6 +616,20 @@ int update_screen(void) return OK; } +static void win_border_redr_title(win_T *wp, ScreenGrid *grid, int col) +{ + VirtText title_chunks = wp->w_float_config.title_chunks; + + for (size_t i = 0; i < title_chunks.size; i++) { + char *text = title_chunks.items[i].text; + int cell = (int)mb_string2cells(text); + int hl_id = title_chunks.items[i].hl_id; + int attr = hl_id ? syn_id2attr(hl_id) : 0; + grid_puts(grid, text, 0, col, attr); + col += cell; + } +} + static void win_redr_border(win_T *wp) { wp->w_redr_border = false; @@ -634,9 +650,24 @@ static void win_redr_border(win_T *wp) if (adj[3]) { grid_put_schar(grid, 0, 0, chars[0], attrs[0]); } + for (int i = 0; i < icol; i++) { grid_put_schar(grid, 0, i + adj[3], chars[1], attrs[1]); } + + if (wp->w_float_config.title) { + int title_col = 0; + int title_width = wp->w_float_config.title_width; + AlignTextPos title_pos = wp->w_float_config.title_pos; + + if (title_pos == kAlignCenter) { + title_col = (icol - title_width) / 2 + 1; + } else { + title_col = title_pos == kAlignLeft ? 1 : icol - title_width + 1; + } + + win_border_redr_title(wp, grid, title_col); + } if (adj[1]) { grid_put_schar(grid, 0, icol + adj[3], chars[2], attrs[2]); } diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h index 9ef4ec23e5..51b60dcf6d 100644 --- a/src/nvim/extmark_defs.h +++ b/src/nvim/extmark_defs.h @@ -9,6 +9,8 @@ typedef struct { int hl_id; } VirtTextChunk; +typedef kvec_t(VirtTextChunk) VirtText; + typedef struct undo_object ExtmarkUndoObject; typedef kvec_t(ExtmarkUndoObject) extmark_undo_vec_t; diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index ffcb0f3f22..d66bcca57f 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -114,6 +114,7 @@ typedef enum { HLF_WBR, // Window bars HLF_WBRNC, // Window bars of not-current windows HLF_CU, // Cursor + HLF_BTITLE, // Float Border Title HLF_COUNT, // MUST be the last one } hlf_T; @@ -178,6 +179,7 @@ EXTERN const char *hlf_names[] INIT(= { [HLF_WBR] = "WinBar", [HLF_WBRNC] = "WinBarNC", [HLF_CU] = "Cursor", + [HLF_BTITLE] = "FloatBorderTitle", }); EXTERN int highlight_attr[HLF_COUNT + 1]; // Highl. attr for each context. diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 9a09118939..a83f4ea969 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -131,6 +131,7 @@ static const char *highlight_init_both[] = { "default link MsgSeparator StatusLine", "default link NormalFloat Pmenu", "default link FloatBorder WinSeparator", + "default link FloatBorderTitle Title", "default FloatShadow blend=80 guibg=Black", "default FloatShadowThrough blend=100 guibg=Black", "RedrawDebugNormal cterm=reverse gui=reverse", diff --git a/src/nvim/window.c b/src/nvim/window.c index 10b366ce23..1cde433b0a 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4,6 +4,7 @@ #include <assert.h> #include <inttypes.h> #include <stdbool.h> +#include <string.h> #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" @@ -5066,6 +5067,9 @@ static void win_free(win_T *wp, tabpage_T *tp) } } + // free the border title text + clear_virttext(&wp->w_float_config.title_chunks); + clear_matches(wp); free_jumplist(wp); |