aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/keysets.lua2
-rw-r--r--src/nvim/api/win_config.c103
-rw-r--r--src/nvim/buffer_defs.h17
-rw-r--r--src/nvim/drawscreen.c50
-rw-r--r--src/nvim/eval/funcs.c1
-rw-r--r--src/nvim/window.c5
6 files changed, 176 insertions, 2 deletions
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index ea8949bd2c..d9d9c7ee1d 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -83,6 +83,8 @@ return {
"border";
"style";
"noautocmd";
+ "title";
+ "title_position";
};
runtime = {
"is_lua";
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 636b9566ce..7523ff301d 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -437,9 +437,73 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
}
}
+static bool parse_title(FloatConfig* out, String s)
+{
+ // The raw title is going to be at most the length of the string.
+ char* out_title_raw = xcalloc(sizeof(char), s.size + 1);
+ size_t out_cursor = 0;
+
+ char* data = s.data;
+
+ size_t out_hlrec_nalloc = 4;
+ stl_hlrec_t* out_hlrec = xcalloc(sizeof(stl_hlrec_t), out_hlrec_nalloc);
+ out_hlrec[0].start = (char*) out_title_raw;
+ out_hlrec[0].userhl = 0;
+ size_t out_hl_cur = 1;
+
+ char hlbuf[128];
+ size_t hlbuf_cur = 0;
+
+ int hl;
+
+ for (size_t i = 0; i < s.size; i ++) {
+ if (data[i] == '\\' && i < s.size - 1) {
+ i ++;
+ out_title_raw[out_cursor++] = data[i];
+ } else if (
+ data[i] == '%' &&
+ i < s.size - 1 && data[i + 1] == '#') {
+ i += 2;
+ while (i < s.size && data[i] != '#') {
+ if (hlbuf_cur < sizeof(hlbuf) - 1) {
+ hlbuf[hlbuf_cur ++] = data[i];
+ }
+ i ++;
+ }
+ hlbuf[hlbuf_cur++] = 0;
+ hl = syn_check_group(hlbuf, strlen(hlbuf));
+ hlbuf_cur = 0;
+
+ if (out_hl_cur >= out_hlrec_nalloc - 1) { // Leave room for last.
+ out_hlrec =
+ xrealloc(out_hlrec, sizeof(stl_hlrec_t) * (out_hlrec_nalloc *= 2));
+ }
+
+ out_hlrec[out_hl_cur].start = (out_title_raw + out_cursor);
+ out_hlrec[out_hl_cur++].userhl = -hl;
+ } else {
+ out_title_raw[out_cursor++] = data[i];
+ }
+ }
+
+ out->n_title = out_cursor;
+ out_title_raw[out_cursor++] = 0;
+ out_hlrec[out_hl_cur] = (stl_hlrec_t) { 0, 0 };
+ out->title_hl = out_hlrec;
+ out->title = out_title_raw;
+
+ return true;
+}
+
static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, bool reconf,
bool new_win, Error *err)
{
+ xfree(fconfig->title);
+ xfree(fconfig->title_hl);
+ fconfig->title_hl = NULL;
+ fconfig->n_title = 0;
+ fconfig->title = NULL;
+
bool has_relative = false, relative_is_win = false;
if (config->relative.type == kObjectTypeString) {
// ignore empty string, to match nvim_win_get_config
@@ -634,5 +698,44 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
}
}
+ if (HAS_KEY(config->title)) {
+ if (!parse_title(fconfig, config->title.data.string)) {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'title' key.");
+ goto free_and_fail;
+ }
+ } else if (config->title.type == kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation, "'title' must be a string");
+ return false;
+ }
+
+ if (HAS_KEY(config->title_position)) {
+ if (config->title_position.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'title_position' key");
+ goto free_and_fail;
+ }
+
+ if (striequal(config->title_position.data.string.data, "left")) {
+ fconfig->title_pos = kTitleLeft;
+ } else if (striequal(config->title_position.data.string.data, "center")) {
+ fconfig->title_pos = kTitleCenter;
+ } else if (striequal(config->title_position.data.string.data, "right")) {
+ fconfig->title_pos = kTitleRight;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value for 'title_position'");
+ goto free_and_fail;
+ }
+ }
+
return true;
+
+free_and_fail:
+ xfree(fconfig->title);
+ xfree(fconfig->title_hl);
+ fconfig->n_title = 0;
+ fconfig->title_hl = NULL;
+ fconfig->title = NULL;
+ return false;
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 630e1d14a8..829632358f 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1042,6 +1042,12 @@ typedef enum {
kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
} WinStyle;
+typedef enum {
+ kTitleLeft = 0,
+ kTitleCenter,
+ kTitleRight
+} TitlePosition;
+
typedef struct {
Window window;
lpos_T bufpos;
@@ -1059,6 +1065,11 @@ typedef struct {
int border_hl_ids[8];
int border_attr[8];
bool noautocmd;
+
+ stl_hlrec_t* title_hl;
+ char* title;
+ size_t n_title;
+ TitlePosition title_pos;
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
@@ -1068,7 +1079,11 @@ typedef struct {
.focusable = true, \
.zindex = kZIndexFloatDefault, \
.style = kWinStyleUnused, \
- .noautocmd = false })
+ .noautocmd = false, \
+ .title_hl = NULL, \
+ .title = NULL, \
+ .n_title = 0, \
+ .title_pos = kTitleLeft})
// Structure to store last cursor position and topline. Used by check_lnums()
// and reset_lnums().
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 15a7294496..2fbfd7080f 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -641,13 +641,61 @@ static void win_redr_border(win_T *wp)
int *adj = wp->w_border_adj;
int irow = wp->w_height_inner + wp->w_winbar_height, icol = wp->w_width_inner;
+ char* title = wp->w_float_config.title;
+ size_t n_title = wp->w_float_config.n_title;
+ stl_hlrec_t* title_hl = wp->w_float_config.title_hl;
+
+ int m8[MAX_MCO + 1];
+ int cc;
+ int len;
+ int t_attr = title_hl != NULL && title_hl->userhl
+ ? syn_id2attr(title_hl->userhl)
+ : 0;
+ t_attr = hl_combine_attr(attrs[1], t_attr);
+
+ int title_pos = 2;
+ switch (wp->w_float_config.title_pos) {
+ case kTitleLeft:
+ title_pos = 2;
+ break;
+ case kTitleRight:
+ title_pos = icol - 2 - vim_strsize(title);
+ break;
+ case kTitleCenter:
+ title_pos = (icol - vim_strsize(title)) / 2 - 1;
+ break;
+ }
+ title_pos = title_pos < 2 ? 2 : title_pos;
+
if (adj[0]) {
grid_puts_line_start(grid, 0);
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]);
+ schar_T ch;
+ int attr;
+ // Draw the title if in the correct position.
+ if (i > title_pos && n_title > 0 && i < icol - 2) {
+ cc = utfc_ptr2char((char_u*) title, m8);
+ len = utfc_ptr2len(title);
+ n_title -= len;
+ title += len;
+
+ while (title_hl != NULL &&
+ (title_hl + 1)->start != NULL &&
+ (title_hl + 1)->start < title) {
+ ++ title_hl;
+ t_attr = hl_combine_attr(attrs[1], syn_id2attr(-title_hl->userhl));
+ }
+
+ schar_from_cc(ch, cc, m8);
+ attr = t_attr;
+ } else {
+ memcpy(ch, chars[1], sizeof(schar_T));
+ attr = attrs[1];
+ }
+ grid_put_schar(grid, 0, i + adj[3], ch, attr);
}
if (adj[1]) {
grid_put_schar(grid, 0, icol + adj[3], chars[2], attrs[2]);
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index a326c44371..3fff0798c4 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -3658,6 +3658,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"winaltkeys",
"writebackup",
"nvim",
+ "floattitle",
};
// XXX: eval_has_provider() may shell out :(
diff --git a/src/nvim/window.c b/src/nvim/window.c
index d7ca718c68..9be7a91667 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -3053,6 +3053,11 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp)
wp = firstwin;
}
}
+ xfree(win->w_float_config.title);
+ xfree(win->w_float_config.title_hl);
+ win->w_float_config.title_hl = NULL;
+ win->w_float_config.title = NULL;
+ win->w_float_config.n_title = 0;
win_free(win, tp);
// When deleting the current window of another tab page select a new