aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/win_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/win_config.c')
-rw-r--r--src/nvim/api/win_config.c158
1 files changed, 145 insertions, 13 deletions
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 6c37df6af8..0ffeac1bff 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -1,19 +1,27 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include <assert.h>
#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
+#include <string.h>
+#include "klib/kvec.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/decoration.h"
#include "nvim/drawscreen.h"
+#include "nvim/extmark_defs.h"
+#include "nvim/globals.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight_group.h"
+#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/memory.h"
#include "nvim/option.h"
-#include "nvim/strings.h"
+#include "nvim/pos.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/window.h"
@@ -47,13 +55,13 @@
/// this should not be used to specify arbitrary WM screen positions.
///
/// Example (Lua): window-relative float
-/// <pre>
+/// <pre>lua
/// vim.api.nvim_open_win(0, false,
/// {relative='win', row=3, col=3, width=12, height=3})
/// </pre>
///
/// Example (Lua): buffer-relative float (travels as buffer is scrolled)
-/// <pre>
+/// <pre>lua
/// vim.api.nvim_open_win(0, false,
/// {relative='win', width=12, height=3, bufpos={100,10}})
/// </pre>
@@ -66,6 +74,7 @@
/// - "editor" The global editor grid
/// - "win" Window given by the `win` field, or current window.
/// - "cursor" Cursor position in current window.
+/// - "mouse" Mouse position
/// - win: |window-ID| for relative="win".
/// - anchor: Decides which corner of the float to place at (row,col):
/// - "NW" northwest (default)
@@ -106,10 +115,11 @@
/// float where the text should not be edited. Disables
/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn',
/// 'foldcolumn', 'spell' and 'list' options. 'signcolumn'
-/// is changed to `auto` and 'colorcolumn' is cleared. The
-/// end-of-buffer region is hidden by setting `eob` flag of
+/// is changed to `auto` and 'colorcolumn' is cleared.
+/// 'statuscolumn' is changed to empty. The end-of-buffer
+/// region is hidden by setting `eob` flag of
/// 'fillchars' to a space char, and clearing the
-/// |EndOfBuffer| region in 'winhighlight'.
+/// |hl-EndOfBuffer| region in 'winhighlight'.
/// - border: Style of (optional) window border. This can either be a string
/// or an array. The string values are
/// - "none": No border (default).
@@ -133,7 +143,12 @@
/// will only make vertical borders but not horizontal ones.
/// By default, `FloatBorder` highlight is used, which links to `WinSeparator`
/// when not defined. It could also be specified by character:
-/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ].
+/// [ ["+", "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.
/// - noautocmd: If true then no buffer-related autocommand events such as
/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from
/// calling this function.
@@ -202,7 +217,7 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
if (!win_new_float(win, false, fconfig, err)) {
return;
}
- redraw_later(win, NOT_VALID);
+ redraw_later(win, UPD_NOT_VALID);
} else {
win_config_float(win, fconfig);
win->w_pos_changed = true;
@@ -263,7 +278,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
String s = cstrn_to_string((const char *)config->border_chars[i], sizeof(schar_T));
int hi_id = config->border_hl_ids[i];
- char *hi_name = (char *)syn_id2name(hi_id);
+ char *hi_name = syn_id2name(hi_id);
if (hi_name[0]) {
ADD(tuple, STRING_OBJ(s));
ADD(tuple, STRING_OBJ(cstr_to_string((const char *)hi_name)));
@@ -273,6 +288,29 @@ 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));
+ char *title_pos;
+ if (config->title_pos == kAlignLeft) {
+ title_pos = "left";
+ } else if (config->title_pos == kAlignCenter) {
+ title_pos = "center";
+ } else {
+ title_pos = "right";
+ }
+ PUT(rv, "title_pos", CSTR_TO_OBJ(title_pos));
+ }
}
}
@@ -312,6 +350,8 @@ static bool parse_float_relative(String relative, FloatRelative *out)
*out = kFloatRelativeWindow;
} else if (striequal(str, "cursor")) {
*out = kFloatRelativeCursor;
+ } else if (striequal(str, "mouse")) {
+ *out = kFloatRelativeMouse;
} else {
return false;
}
@@ -330,7 +370,74 @@ 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("FloatTitle"));
+ 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.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;
+}
+
+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 +521,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 +712,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)) {