mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
Merge pull request #10090 from bfredl/floatpopup
api/window: add style="minimal" flag to disable unwanted UI features for simple floats
This commit is contained in:
commit
524fe6205d
@ -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')
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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().
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user