aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjΓΆrn Linse <bjorn.linse@gmail.com>2019-07-07 21:35:55 +0200
committerGitHub <noreply@github.com>2019-07-07 21:35:55 +0200
commit524fe6205d01d8ced45bc4b00ed397add01a41bf (patch)
tree8fd4cb84d1149da6f636b5bd5bbb114df86b982b
parent28a86608a84672b3b64981c3b47b80b051cb5177 (diff)
parentef3e32d57ee0ebe3f425998216d8bf61ffdc28bb (diff)
downloadrneovim-524fe6205d01d8ced45bc4b00ed397add01a41bf.tar.gz
rneovim-524fe6205d01d8ced45bc4b00ed397add01a41bf.tar.bz2
rneovim-524fe6205d01d8ced45bc4b00ed397add01a41bf.zip
Merge pull request #10090 from bfredl/floatpopup
api/window: add style="minimal" flag to disable unwanted UI features for simple floats
-rw-r--r--runtime/doc/api.txt8
-rw-r--r--src/nvim/api/vim.c18
-rw-r--r--src/nvim/api/window.c5
-rw-r--r--src/nvim/buffer.c5
-rw-r--r--src/nvim/buffer_defs.h14
-rw-r--r--src/nvim/highlight.c21
-rw-r--r--src/nvim/option.c3
-rw-r--r--src/nvim/screen.c3
-rw-r--r--src/nvim/window.c48
-rw-r--r--test/functional/ui/float_spec.lua142
10 files changed, 237 insertions, 30 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 065a052175..709e5885e4 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -284,14 +284,18 @@ highlighting, or |api-highlights|.
By default, floats will use |hl-NormalFloat| as normal highlight, which
links to |hl-Pmenu| in the builtin color scheme. The 'winhighlight' option can
be used to override it. Currently, floating windows don't support any visual
-decorations like a border or additional widgets like scrollbar.
+decorations like a border or additional widgets like scrollbar. By default,
+floats will inherit options from the current window. This is not always
+useful for some options, like 'number'. Use `style='minimal'` flag to
+|nvim_open_win()| to disable many UI features that are unwanted for a simple
+float, like end-of-buffer region or special columns.
Here is an example for creating a float with scratch buffer: >
let buf = nvim_create_buf(v:false, v:true)
call nvim_buf_set_lines(buf, 0, -1, v:true, ["test", "text"])
let opts = {'relative': 'cursor', 'width': 10, 'height': 2, 'col': 0,
- \ 'row': 1, 'anchor': 'NW'}
+ \ 'row': 1, 'anchor': 'NW', 'style': 'minimal'}
let win = nvim_open_win(buf, 0, opts)
" optional: change highlight, otherwise Pmenu is used
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 8e5650633a..dbe3b66fd5 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1064,6 +1064,19 @@ fail:
/// - `external`: GUI should display the window as an external
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
+/// - `style`: Configure the apparance of the window. Currently only takes
+/// one non-empty value:
+/// - "minimal" Nvim will display the window with many UI options
+/// disabled. This is useful when displaing a temporary
+/// float where the text should not be edited. Disables
+/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn',
+/// 'spell' and 'list' options. 'signcolumn' is changed to
+/// `auto`. The end-of-buffer region is hidden by setting
+/// `eob` flag of 'fillchars' to a space char, and clearing
+/// the |EndOfBuffer| region in 'winhighlight'.
+///
+/// top-level window. Currently accepts no other positioning
+/// configuration together with this.
/// @param[out] err Error details, if any
///
/// @return Window handle, or 0 on error
@@ -1085,6 +1098,11 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
if (buffer > 0) {
nvim_win_set_buf(wp->handle, buffer, err);
}
+
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(wp);
+ didset_window_options(wp);
+ }
return wp->handle;
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 9fd1818a5c..4922dd7efc 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -13,6 +13,7 @@
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/option.h"
#include "nvim/window.h"
#include "nvim/screen.h"
#include "nvim/move.h"
@@ -475,6 +476,10 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
win_config_float(win, fconfig);
win->w_pos_changed = true;
}
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(win);
+ didset_window_options(win);
+ }
}
/// Return window configuration.
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 5678f518f5..cd31adbaff 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2543,6 +2543,11 @@ void get_winopts(buf_T *buf)
} else
copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
+ if (curwin->w_float_config.style == kWinStyleMinimal) {
+ didset_window_options(curwin);
+ win_set_minimal_style(curwin);
+ }
+
// Set 'foldlevel' to 'foldlevelstart' if it's not negative.
if (p_fdls >= 0) {
curwin->w_p_fdl = p_fdls;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ad10f6baa2..a27672488e 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -972,7 +972,6 @@ struct matchitem {
};
typedef int FloatAnchor;
-typedef int FloatRelative;
enum {
kFloatAnchorEast = 1,
@@ -985,15 +984,20 @@ enum {
// SE -> kFloatAnchorSouth | kFloatAnchorEast
EXTERN const char *const float_anchor_str[] INIT(= { "NW", "NE", "SW", "SE" });
-enum {
+typedef enum {
kFloatRelativeEditor = 0,
kFloatRelativeWindow = 1,
kFloatRelativeCursor = 2,
-};
+} FloatRelative;
EXTERN const char *const float_relative_str[] INIT(= { "editor", "window",
"cursor" });
+typedef enum {
+ kWinStyleUnused = 0,
+ kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
+} WinStyle;
+
typedef struct {
Window window;
int height, width;
@@ -1002,12 +1006,14 @@ typedef struct {
FloatRelative relative;
bool external;
bool focusable;
+ WinStyle style;
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
.row = 0, .col = 0, .anchor = 0, \
.relative = 0, .external = false, \
- .focusable = true })
+ .focusable = true, \
+ .style = kWinStyleUnused })
// Structure to store last cursor position and topline. Used by check_lnums()
// and reset_lnums().
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 15c3d0eb7b..e5cbb4f944 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -141,10 +141,12 @@ int hl_get_ui_attr(int idx, int final_id, bool optional)
HlAttrs attrs = HLATTRS_INIT;
bool available = false;
- int syn_attr = syn_id2attr(final_id);
- if (syn_attr != 0) {
- attrs = syn_attr2entry(syn_attr);
- available = true;
+ if (final_id > 0) {
+ int syn_attr = syn_id2attr(final_id);
+ if (syn_attr != 0) {
+ attrs = syn_attr2entry(syn_attr);
+ available = true;
+ }
}
if (HLF_PNI <= idx && idx <= HLF_PST) {
@@ -176,15 +178,14 @@ void update_window_hl(win_T *wp, bool invalid)
// determine window specific background set in 'winhighlight'
bool float_win = wp->w_floating && !wp->w_float_config.external;
- if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_INACTIVE,
wp->w_hl_ids[HLF_INACTIVE],
!has_blend);
- } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] > 0) {
+ } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_NFLOAT,
- // 'cursorline'
wp->w_hl_ids[HLF_NFLOAT], !has_blend);
- } else if (wp->w_hl_id_normal > 0) {
+ } else if (wp->w_hl_id_normal != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, !has_blend);
} else {
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
@@ -199,14 +200,14 @@ void update_window_hl(win_T *wp, bool invalid)
}
}
- if (wp != curwin) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] == 0) {
wp->w_hl_attr_normal = hl_combine_attr(HL_ATTR(HLF_INACTIVE),
wp->w_hl_attr_normal);
}
for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
int attr;
- if (wp->w_hl_ids[hlf] > 0) {
+ if (wp->w_hl_ids[hlf] != 0) {
attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false);
} else {
attr = HL_ATTR(hlf);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 62f736ea31..9cdcf4cc34 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -3762,7 +3762,8 @@ static bool parse_winhl_opt(win_T *wp)
size_t nlen = (size_t)(colon-p);
char *hi = colon+1;
char *commap = xstrchrnul(hi, ',');
- int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi));
+ int len = (int)(commap-hi);
+ int hl_id = len ? syn_check_group((char_u *)hi, len) : -1;
if (strncmp("Normal", p, nlen) == 0) {
w_hl_id_normal = hl_id;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 846ffeb442..a007aa9a47 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1612,7 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row,
}
}
- int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, hl));
+ int attr = hl_combine_attr(wp->w_hl_attr_normal,
+ hl ? win_hl_attr(wp, hl) : 0);
if (wp->w_p_rl) {
grid_fill(&wp->w_grid, row, endrow, wp->w_wincol, W_ENDCOL(wp) - 1 - n,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index a3b1efeaaa..acaff8327d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -584,15 +584,43 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
wp->w_status_height = 0;
wp->w_vsep_width = 0;
- // TODO(bfredl): use set_option_to() after merging #9110 ?
- wp->w_p_nu = false;
- wp->w_allbuf_opt.wo_nu = false;
win_config_float(wp, fconfig);
wp->w_pos_changed = true;
redraw_win_later(wp, VALID);
return wp;
}
+void win_set_minimal_style(win_T *wp)
+{
+ wp->w_p_nu = false;
+ wp->w_p_rnu = false;
+ wp->w_p_cul = false;
+ wp->w_p_cuc = false;
+ wp->w_p_spell = false;
+ wp->w_p_list = false;
+
+ // Hide EOB region: use " " fillchar and cleared highlighting
+ if (wp->w_p_fcs_chars.eob != ' ') {
+ char_u *old = wp->w_p_fcs;
+ wp->w_p_fcs = ((*old == NUL)
+ ? (char_u *)xstrdup("eob: ")
+ : concat_str(old, (char_u *)",eob: "));
+ xfree(old);
+ }
+ if (wp->w_hl_ids[HLF_EOB] != -1) {
+ char_u *old = wp->w_p_winhl;
+ wp->w_p_winhl = ((*old == NUL)
+ ? (char_u *)xstrdup("EndOfBuffer:")
+ : concat_str(old, (char_u *)",EndOfBuffer:"));
+ xfree(old);
+ }
+
+ if (wp->w_p_scl[0] != 'a') {
+ xfree(wp->w_p_scl);
+ wp->w_p_scl = (char_u *)xstrdup("auto");
+ }
+}
+
void win_config_float(win_T *wp, FloatConfig fconfig)
{
wp->w_width = MAX(fconfig.width, 1);
@@ -821,6 +849,20 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
"'focusable' key must be Boolean");
return false;
}
+ } else if (!strcmp(key, "style")) {
+ if (val.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "'style' key must be String");
+ return false;
+ }
+ if (val.data.string.data[0] == NUL) {
+ fconfig->style = kWinStyleUnused;
+ } else if (striequal(val.data.string.data, "minimal")) {
+ fconfig->style = kWinStyleMinimal;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'style' key");
+ }
} else {
api_set_error(err, kErrorTypeValidation,
"Invalid key '%s'", key);
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 41ba542899..b717ec1118 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -35,6 +35,10 @@ describe('floating windows', function()
[15] = {background = Screen.colors.Grey20},
[16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1},
[17] = {background = Screen.colors.Yellow},
+ [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20},
+ [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [20] = {bold = true, foreground = Screen.colors.Brown},
+ [21] = {background = Screen.colors.Gray90},
}
it('behavior', function()
@@ -182,7 +186,7 @@ describe('floating windows', function()
end
end)
- it('defaults to nonumber and NormalFloat highlight', function()
+ it('defaults to NormalFloat highlight and inherited options', function()
command('set number')
command('hi NormalFloat guibg=#333333')
feed('ix<cr>y<cr><esc>gg')
@@ -205,18 +209,18 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
## grid 3
- {15:x }|
- {15:y }|
- {15: }|
+ {18: 1 }{15:x }|
+ {18: 2 }{15:y }|
+ {18: 3 }{15: }|
{16:~ }|
]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect([[
{14: 1 }^x |
{14: 2 }y |
- {14: 3 } {15:x } |
- {0:~ }{15:y }{0: }|
- {0:~ }{15: }{0: }|
+ {14: 3 } {18: 1 }{15:x } |
+ {0:~ }{18: 2 }{15:y }{0: }|
+ {0:~ }{18: 3 }{15: }{0: }|
{0:~ }{16:~ }{0: }|
|
]])
@@ -242,7 +246,7 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
## grid 3
- {15: }|
+ {18: 1 }{15: }|
{16:~ }|
{16:~ }|
{16:~ }|
@@ -251,7 +255,7 @@ describe('floating windows', function()
screen:expect([[
{14: 1 }^x |
{14: 2 }y |
- {14: 3 } {15: } |
+ {14: 3 } {18: 1 }{15: } |
{0:~ }{16:~ }{0: }|
{0:~ }{16:~ }{0: }|
{0:~ }{16:~ }{0: }|
@@ -260,6 +264,126 @@ describe('floating windows', function()
end
end)
+ it("can use 'minimal' style", function()
+ command('set number')
+ command('set signcolumn=yes')
+ command('set cursorline')
+ command('hi NormalFloat guibg=#333333')
+ feed('ix<cr>y<cr><esc>gg')
+ local win = meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {15:x }|
+ {15:y }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect([[
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {15:x } |
+ {0:~ }{15:y }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+
+ -- signcolumn=yes still works if there actually are signs
+ command('sign define piet1 text=πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„ texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{15:x }|
+ {19: }{15:y }|
+ {19: }{15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+
+ else
+ screen:expect([[
+ {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{15:x } |
+ {0:~ }{19: }{15:y }{0: }|
+ {0:~ }{19: }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+ command('sign unplace 1 buffer=1')
+
+ local buf = meths.create_buf(false, true)
+ meths.win_set_buf(win, buf)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {15: }|
+ {15: }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect([[
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {15: } |
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+ end)
+
it('can have minimum size', function()
insert("the background text")
local buf = meths.create_buf(false, true)