Merge pull request #9571 from bfredl/pum_transparent

UI: implement 'pumblend' option for semi-transparent popupmenu
This commit is contained in:
Björn Linse 2019-02-07 17:52:58 +01:00 committed by GitHub
commit fa2580f953
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 417 additions and 19 deletions

View File

@ -4486,6 +4486,16 @@ A jump table for the options with a short description can be found at |Q_op|.
Insert mode completion. When zero as much space as available is used. Insert mode completion. When zero as much space as available is used.
|ins-completion-menu|. |ins-completion-menu|.
*'pumblend'* *'pb'*
'pumblend' 'pb' number (default 0)
global
Enables semi-transparency for the completion popupmenu. Valid values
are in the range from 0 for fully opaque popupmenu (disabled) to 100
for fully transparent background. Lower values 0-30 are typically most
useful.
UI-dependent. Supported by TUI with 'termguicolors' enabled.
*'pyxversion'* *'pyx'* *'pyxversion'* *'pyx'*
'pyxversion' 'pyx' number (default depends on the build) 'pyxversion' 'pyx' number (default depends on the build)
global global

View File

@ -189,6 +189,7 @@ Options:
for |hl-EndOfBuffer| marker for |hl-EndOfBuffer| marker
'inccommand' shows interactive results for |:substitute|-like commands 'inccommand' shows interactive results for |:substitute|-like commands
'listchars' local to window 'listchars' local to window
'pumblend' semi-transparent popupmenu
'scrollback' 'scrollback'
'statusline' supports unlimited alignment sections 'statusline' supports unlimited alignment sections
'tabline' %@Func@foo%X can call any function on mouse-click 'tabline' %@Func@foo%X can call any function on mouse-click

View File

@ -357,10 +357,7 @@ static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg,
Integer cterm_fg, Integer cterm_bg) Integer cterm_fg, Integer cterm_bg)
{ {
if (!ui->ui_ext[kUITermColors]) { if (!ui->ui_ext[kUITermColors]) {
bool dark = (*p_bg == 'd'); HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp);
rgb_fg = rgb_fg != -1 ? rgb_fg : (dark ? 0xFFFFFF : 0x000000);
rgb_bg = rgb_bg != -1 ? rgb_bg : (dark ? 0x000000 : 0xFFFFFF);
rgb_sp = rgb_sp != -1 ? rgb_sp : 0xFF0000;
} }
Array args = ARRAY_DICT_INIT; Array args = ARRAY_DICT_INIT;
ADD(args, INTEGER_OBJ(rgb_fg)); ADD(args, INTEGER_OBJ(rgb_fg));

View File

@ -23,11 +23,15 @@ static kvec_t(HlEntry) attr_entries = KV_INITIAL_VALUE;
static Map(HlEntry, int) *attr_entry_ids; static Map(HlEntry, int) *attr_entry_ids;
static Map(int, int) *combine_attr_entries; static Map(int, int) *combine_attr_entries;
static Map(int, int) *blend_attr_entries;
static Map(int, int) *blendthrough_attr_entries;
void highlight_init(void) void highlight_init(void)
{ {
attr_entry_ids = map_new(HlEntry, int)(); attr_entry_ids = map_new(HlEntry, int)();
combine_attr_entries = map_new(int, int)(); combine_attr_entries = map_new(int, int)();
blend_attr_entries = map_new(int, int)();
blendthrough_attr_entries = map_new(int, int)();
// index 0 is no attribute, add dummy entry: // index 0 is no attribute, add dummy entry:
kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown, kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown,
@ -213,6 +217,8 @@ void clear_hl_tables(bool reinit)
kv_size(attr_entries) = 1; kv_size(attr_entries) = 1;
map_clear(HlEntry, int)(attr_entry_ids); map_clear(HlEntry, int)(attr_entry_ids);
map_clear(int, int)(combine_attr_entries); map_clear(int, int)(combine_attr_entries);
map_clear(int, int)(blend_attr_entries);
map_clear(int, int)(blendthrough_attr_entries);
highlight_attr_set_all(); highlight_attr_set_all();
highlight_changed(); highlight_changed();
screen_invalidate_highlights(); screen_invalidate_highlights();
@ -220,15 +226,22 @@ void clear_hl_tables(bool reinit)
kv_destroy(attr_entries); kv_destroy(attr_entries);
map_free(HlEntry, int)(attr_entry_ids); map_free(HlEntry, int)(attr_entry_ids);
map_free(int, int)(combine_attr_entries); map_free(int, int)(combine_attr_entries);
map_free(int, int)(blend_attr_entries);
map_free(int, int)(blendthrough_attr_entries);
} }
} }
void hl_invalidate_blends(void)
{
map_clear(int, int)(blend_attr_entries);
map_clear(int, int)(blendthrough_attr_entries);
}
// Combine special attributes (e.g., for spelling) with other attributes // Combine special attributes (e.g., for spelling) with other attributes
// (e.g., for syntax highlighting). // (e.g., for syntax highlighting).
// "prim_attr" overrules "char_attr". // "prim_attr" overrules "char_attr".
// This creates a new group when required. // This creates a new group when required.
// Since we expect there to be few spelling mistakes we don't cache the // Since we expect there to be a lot of spelling mistakes we cache the result.
// result.
// Return the resulting attributes. // Return the resulting attributes.
int hl_combine_attr(int char_attr, int prim_attr) int hl_combine_attr(int char_attr, int prim_attr)
{ {
@ -283,6 +296,85 @@ int hl_combine_attr(int char_attr, int prim_attr)
return id; return id;
} }
/// Get the used rgb colors for an attr group.
///
/// If colors are unset, use builtin default colors. Never returns -1
/// Cterm colors are unchanged.
static HlAttrs get_colors_force(int attr)
{
HlAttrs attrs = syn_attr2entry(attr);
if (attrs.rgb_bg_color == -1) {
attrs.rgb_bg_color = normal_bg;
}
if (attrs.rgb_fg_color == -1) {
attrs.rgb_fg_color = normal_fg;
}
if (attrs.rgb_sp_color == -1) {
attrs.rgb_sp_color = normal_sp;
}
HL_SET_DEFAULT_COLORS(attrs.rgb_fg_color, attrs.rgb_bg_color,
attrs.rgb_sp_color);
return attrs;
}
/// Blend overlay attributes (for popupmenu) with other attributes
///
/// This creates a new group when required.
/// This will be called on a per-cell basis when in use, so cache the result.
/// @return the resulting attributes.
int hl_blend_attrs(int back_attr, int front_attr, bool through)
{
int combine_tag = (back_attr << 16) + front_attr;
Map(int, int) *map = through ? blendthrough_attr_entries : blend_attr_entries;
int id = map_get(int, int)(map, combine_tag);
if (id > 0) {
return id;
}
HlAttrs battrs = get_colors_force(back_attr);
HlAttrs fattrs = get_colors_force(front_attr);
HlAttrs cattrs;
if (through) {
cattrs = battrs;
cattrs.rgb_fg_color = rgb_blend((int)p_pb, battrs.rgb_fg_color,
fattrs.rgb_bg_color);
cattrs.cterm_bg_color = fattrs.cterm_bg_color;
cattrs.cterm_fg_color = fattrs.cterm_bg_color;
} else {
cattrs = fattrs;
if (p_pb >= 50) {
cattrs.rgb_ae_attr |= battrs.rgb_ae_attr;
}
cattrs.rgb_fg_color = rgb_blend((int)p_pb/2, battrs.rgb_fg_color,
fattrs.rgb_fg_color);
}
cattrs.rgb_bg_color = rgb_blend((int)p_pb, battrs.rgb_bg_color,
fattrs.rgb_bg_color);
HlKind kind = through ? kHlBlendThrough : kHlBlend;
id = get_attr_entry((HlEntry){ .attr = cattrs, .kind = kind,
.id1 = back_attr, .id2 = front_attr });
if (id > 0) {
map_put(int, int)(map, combine_tag, id);
}
return id;
}
static int rgb_blend(int ratio, int rgb1, int rgb2)
{
int a = ratio, b = 100-ratio;
int r1 = (rgb1 & 0xFF0000) >> 16;
int g1 = (rgb1 & 0x00FF00) >> 8;
int b1 = (rgb1 & 0x0000FF) >> 0;
int r2 = (rgb2 & 0xFF0000) >> 16;
int g2 = (rgb2 & 0x00FF00) >> 8;
int b2 = (rgb2 & 0x0000FF) >> 0;
int mr = (a * r1 + b * r2)/100;
int mg = (a * g1 + b * g2)/100;
int mb = (a * b1 + b * b2)/100;
return (mr << 16) + (mg << 8) + mb;
}
/// Get highlight attributes for a attribute code /// Get highlight attributes for a attribute code
HlAttrs syn_attr2entry(int attr) HlAttrs syn_attr2entry(int attr)
{ {
@ -406,6 +498,8 @@ static void hl_inspect_impl(Array *arr, int attr)
break; break;
case kHlCombine: case kHlCombine:
case kHlBlend:
case kHlBlendThrough:
// attribute combination is associative, so flatten to an array // attribute combination is associative, so flatten to an array
hl_inspect_impl(arr, e.id1); hl_inspect_impl(arr, e.id1);
hl_inspect_impl(arr, e.id2); hl_inspect_impl(arr, e.id2);

View File

@ -10,4 +10,12 @@
# include "highlight.h.generated.h" # include "highlight.h.generated.h"
#endif #endif
# define HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp) \
do { \
bool dark_ = (*p_bg == 'd'); \
rgb_fg = rgb_fg != -1 ? rgb_fg : (dark_ ? 0xFFFFFF : 0x000000); \
rgb_bg = rgb_bg != -1 ? rgb_bg : (dark_ ? 0x000000 : 0xFFFFFF); \
rgb_sp = rgb_sp != -1 ? rgb_sp : 0xFF0000; \
} while (0);
#endif // NVIM_HIGHLIGHT_H #endif // NVIM_HIGHLIGHT_H

View File

@ -160,6 +160,8 @@ typedef enum {
kHlSyntax, kHlSyntax,
kHlTerminal, kHlTerminal,
kHlCombine, kHlCombine,
kHlBlend,
kHlBlendThrough,
} HlKind; } HlKind;
typedef struct { typedef struct {

View File

@ -50,6 +50,7 @@
#include "nvim/fold.h" #include "nvim/fold.h"
#include "nvim/getchar.h" #include "nvim/getchar.h"
#include "nvim/hardcopy.h" #include "nvim/hardcopy.h"
#include "nvim/highlight.h"
#include "nvim/indent_c.h" #include "nvim/indent_c.h"
#include "nvim/mbyte.h" #include "nvim/mbyte.h"
#include "nvim/memfile.h" #include "nvim/memfile.h"
@ -65,6 +66,7 @@
#include "nvim/normal.h" #include "nvim/normal.h"
#include "nvim/os_unix.h" #include "nvim/os_unix.h"
#include "nvim/path.h" #include "nvim/path.h"
#include "nvim/popupmnu.h"
#include "nvim/regexp.h" #include "nvim/regexp.h"
#include "nvim/screen.h" #include "nvim/screen.h"
#include "nvim/spell.h" #include "nvim/spell.h"
@ -4338,6 +4340,14 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
if (p_uc && !old_value) { if (p_uc && !old_value) {
ml_open_files(); ml_open_files();
} }
} else if (pp == &p_pb) {
p_pb = MAX(MIN(p_pb, 100), 0);
if (old_value != 0) {
hl_invalidate_blends();
}
if (pum_drawn()) {
pum_recompose();
}
} else if (pp == &p_pyx) { } else if (pp == &p_pyx) {
if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) { if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) {
errmsg = e_invarg; errmsg = e_invarg;

View File

@ -375,6 +375,7 @@ EXTERN int p_confirm; // 'confirm'
EXTERN int p_cp; // 'compatible' EXTERN int p_cp; // 'compatible'
EXTERN char_u *p_cot; // 'completeopt' EXTERN char_u *p_cot; // 'completeopt'
EXTERN long p_ph; // 'pumheight' EXTERN long p_ph; // 'pumheight'
EXTERN long p_pb; // 'pumblend'
EXTERN char_u *p_cpo; // 'cpoptions' EXTERN char_u *p_cpo; // 'cpoptions'
EXTERN char_u *p_csprg; // 'cscopeprg' EXTERN char_u *p_csprg; // 'cscopeprg'
EXTERN int p_csre; // 'cscoperelative' EXTERN int p_csre; // 'cscoperelative'

View File

@ -1805,6 +1805,14 @@ return {
varname='p_ph', varname='p_ph',
defaults={if_true={vi=0}} defaults={if_true={vi=0}}
}, },
{
full_name='pumblend', abbreviation='pb',
type='number', scope={'global'},
vi_def=true,
redraw={'ui_option'},
varname='p_pb',
defaults={if_true={vi=0}}
},
{ {
full_name='pyxversion', abbreviation='pyx', full_name='pyxversion', abbreviation='pyx',
type='number', scope={'global'}, type='number', scope={'global'},

View File

@ -44,6 +44,7 @@ static int pum_col; // left column of pum
static bool pum_is_visible = false; static bool pum_is_visible = false;
static bool pum_is_drawn = false; static bool pum_is_drawn = false;
static bool pum_external = false; static bool pum_external = false;
static bool pum_invalid = false; // the screen was just cleared
static ScreenGrid pum_grid = SCREEN_GRID_INIT; static ScreenGrid pum_grid = SCREEN_GRID_INIT;
@ -360,12 +361,14 @@ void pum_redraw(void)
grid_assign_handle(&pum_grid); grid_assign_handle(&pum_grid);
bool moved = ui_comp_put_grid(&pum_grid, pum_row, pum_col-col_off, bool moved = ui_comp_put_grid(&pum_grid, pum_row, pum_col-col_off,
pum_height, grid_width); pum_height, grid_width);
bool invalid_grid = moved || pum_invalid;
pum_invalid = false;
if (!pum_grid.chars if (!pum_grid.chars
|| pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) { || pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
grid_alloc(&pum_grid, pum_height, grid_width, !moved, false); grid_alloc(&pum_grid, pum_height, grid_width, !invalid_grid, false);
ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows); ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows);
} else if (moved) { } else if (invalid_grid) {
grid_invalidate(&pum_grid); grid_invalidate(&pum_grid);
} }
@ -806,6 +809,17 @@ bool pum_drawn(void)
return pum_visible() && !pum_external; return pum_visible() && !pum_external;
} }
/// Screen was cleared, need to redraw next time
void pum_invalidate(void)
{
pum_invalid = true;
}
void pum_recompose(void)
{
ui_comp_compose_grid(&pum_grid);
}
/// Gets the height of the menu. /// Gets the height of the menu.
/// ///
/// @return the height of the popup menu, the number of entries visible. /// @return the height of the popup menu, the number of entries visible.

View File

@ -154,7 +154,7 @@ static bool highlights_invalid = false;
static bool conceal_cursor_used = false; static bool conceal_cursor_used = false;
static bool floats_invalid = false; static bool redraw_popupmenu = false;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h" # include "screen.c.generated.h"
@ -466,13 +466,13 @@ void update_screen(int type)
end_search_hl(); end_search_hl();
// May need to redraw the popup menu. // May need to redraw the popup menu.
if (pum_drawn() && floats_invalid) { if (pum_drawn() && redraw_popupmenu) {
pum_redraw(); pum_redraw();
} }
send_grid_resize = false; send_grid_resize = false;
highlights_invalid = false; highlights_invalid = false;
floats_invalid = false; redraw_popupmenu = false;
/* Reset b_mod_set flags. Going through all windows is probably faster /* Reset b_mod_set flags. Going through all windows is probably faster
* than going through all buffers (there could be many buffers). */ * than going through all buffers (there could be many buffers). */
@ -6185,7 +6185,6 @@ static void screenclear2(void)
default_grid.line_wraps[i] = false; default_grid.line_wraps[i] = false;
} }
floats_invalid = true;
ui_call_grid_clear(1); // clear the display ui_call_grid_clear(1); // clear the display
clear_cmdline = false; clear_cmdline = false;
mode_displayed = false; mode_displayed = false;
@ -6193,6 +6192,8 @@ static void screenclear2(void)
redraw_all_later(NOT_VALID); redraw_all_later(NOT_VALID);
redraw_cmdline = true; redraw_cmdline = true;
redraw_tabline = true; redraw_tabline = true;
redraw_popupmenu = true;
pum_invalidate();
if (must_redraw == CLEAR) { if (must_redraw == CLEAR) {
must_redraw = NOT_VALID; // no need to clear again must_redraw = NOT_VALID; // no need to clear again
} }
@ -7196,6 +7197,10 @@ void screen_resize(int width, int height)
} else { } else {
update_topline(); update_topline();
if (pum_drawn()) { if (pum_drawn()) {
// TODO(bfredl): ins_compl_show_pum wants to redraw the screen first.
// For now make sure the nested update_screen(0) won't redraw the
// pum at the old position. Try to untangle this later.
redraw_popupmenu = false;
ins_compl_show_pum(); ins_compl_show_pum();
} }
update_screen(NOT_VALID); update_screen(NOT_VALID);

View File

@ -15,6 +15,7 @@
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/ui.h" #include "nvim/ui.h"
#include "nvim/highlight.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/ui_compositor.h" #include "nvim/ui_compositor.h"
#include "nvim/ugrid.h" #include "nvim/ugrid.h"
@ -169,11 +170,9 @@ void ui_comp_remove_grid(ScreenGrid *grid)
(void)kv_pop(layers); (void)kv_pop(layers);
grid->comp_index = 0; grid->comp_index = 0;
if (ui_comp_should_draw()) { // recompose the area under the grid
// inefficent: only draw up to grid->comp_index // inefficent when being overlapped: only draw up to grid->comp_index
compose_area(grid->comp_row, grid->comp_row+grid->Rows, ui_comp_compose_grid(grid);
grid->comp_col, grid->comp_col+grid->Columns);
}
} }
bool ui_comp_set_grid(handle_T handle) bool ui_comp_set_grid(handle_T handle)
@ -229,6 +228,10 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
int col = (int)startcol; int col = (int)startcol;
ScreenGrid *grid = NULL; ScreenGrid *grid = NULL;
schar_T *bg_line = &default_grid.chars[default_grid.line_offset[row]
+(size_t)startcol];
sattr_T *bg_attrs = &default_grid.attrs[default_grid.line_offset[row]
+(size_t)startcol];
while (col < endcol) { while (col < endcol) {
int until = 0; int until = 0;
@ -256,6 +259,16 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf)); memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf));
memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf)); memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
if (grid != &default_grid && p_pb) {
for (int i = col-(int)startcol; i < until-startcol; i++) {
bool thru = strequal((char *)linebuf[i], " ");
attrbuf[i] = (sattr_T)hl_blend_attrs(bg_attrs[i], attrbuf[i], thru);
if (thru) {
memcpy(linebuf[i], bg_line[i], sizeof(linebuf[i]));
}
}
}
// Tricky: if overlap caused a doublewidth char to get cut-off, must // Tricky: if overlap caused a doublewidth char to get cut-off, must
// replace the visible half with a space. // replace the visible half with a space.
if (linebuf[col-startcol][0] == NUL) { if (linebuf[col-startcol][0] == NUL) {
@ -272,6 +285,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
skip = 0; skip = 0;
} }
} }
col = until; col = until;
} }
assert(endcol <= chk_width); assert(endcol <= chk_width);
@ -293,11 +307,25 @@ static void compose_area(Integer startrow, Integer endrow,
{ {
endrow = MIN(endrow, default_grid.Rows); endrow = MIN(endrow, default_grid.Rows);
endcol = MIN(endcol, default_grid.Columns); endcol = MIN(endcol, default_grid.Columns);
if (endcol <= startcol) {
return;
}
for (int r = (int)startrow; r < endrow; r++) { for (int r = (int)startrow; r < endrow; r++) {
compose_line(r, startcol, endcol, kLineFlagInvalid); compose_line(r, startcol, endcol, kLineFlagInvalid);
} }
} }
/// compose the area under the grid.
///
/// This is needed when some option affecting composition is changed,
/// such as 'pumblend' for popupmenu grid.
void ui_comp_compose_grid(ScreenGrid *grid)
{
if (ui_comp_should_draw()) {
compose_area(grid->comp_row, grid->comp_row+grid->Rows,
grid->comp_col, grid->comp_col+grid->Columns);
}
}
static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol, Integer startcol, Integer endcol,
@ -316,8 +344,10 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
if (curgrid != &default_grid) { if (curgrid != &default_grid) {
flags = flags & ~kLineFlagWrap; flags = flags & ~kLineFlagWrap;
} }
assert(row < default_grid.Rows);
assert(clearcol <= default_grid.Columns); assert(clearcol <= default_grid.Columns);
if (flags & kLineFlagInvalid || kv_size(layers) > curgrid->comp_index+1) { if (flags & kLineFlagInvalid
|| kv_size(layers) > (p_pb ? 1 : curgrid->comp_index+1)) {
compose_line(row, startcol, clearcol, flags); compose_line(row, startcol, clearcol, flags);
} else { } else {
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr, ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,

View File

@ -18,6 +18,7 @@ describe('ui receives option updates', function()
guifontset='', guifontset='',
guifontwide='', guifontwide='',
linespace=0, linespace=0,
pumblend=0,
showtabline=1, showtabline=1,
termguicolors=false, termguicolors=false,
ext_cmdline=false, ext_cmdline=false,

View File

@ -999,9 +999,52 @@ describe('builtin popupmenu', function()
{1:~ }| {1:~ }|
{2:-- INSERT --} | {2:-- INSERT --} |
]]) ]])
screen:try_resize(25,10)
screen:expect([[
some long prefix before |
the text^ |
{1:~ }{n: word }{1: }|
{1:~ }{n: choice }{1: }|
{1:~ }{s: text }{1: }|
{1:~ }{n: thing }{1: }|
{1:~ }|
{1:~ }|
{1:~ }|
{2:-- INSERT --} |
]])
screen:try_resize(12,5)
screen:expect([[
some long |
prefix |
bef{n: word } |
tex{n: }^ |
{2:-- }{s: text } |
]])
-- can't draw the pum, but check we don't crash
screen:try_resize(12,2)
screen:expect([[
text^ |
{2:-- INSERT -} |
]])
-- but state is preserved, pum reappears
screen:try_resize(20,8)
screen:expect([[
some long prefix |
before the text^ |
{1:~ }{n: word }|
{1:~ }{n: choice }|
{1:~ }{s: text }|
{1:~ }{n: thing }|
{1:~ }|
{2:-- INSERT --} |
]])
end) end)
it('can be moved due to wrap or resize', function() it('works with rightleft window', function()
command("set rl") command("set rl")
feed('isome rightleft ') feed('isome rightleft ')
screen:expect([[ screen:expect([[
@ -1230,4 +1273,176 @@ describe('builtin popupmenu', function()
]]) ]])
end) end)
it('works with pumblend', function()
screen:try_resize(60,14)
screen:set_default_attr_ids({
[1] = {background = Screen.colors.Yellow},
[2] = {bold = true, reverse = true},
[3] = {bold = true, foreground = Screen.colors.Brown},
[4] = {foreground = Screen.colors.Blue1},
[5] = {reverse = true},
[6] = {background = Screen.colors.Gray55, foreground = Screen.colors.Grey45, special = Screen.colors.Red},
[7] = {background = Screen.colors.Gray55, foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[8] = {background = tonumber('0x191919'), foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[9] = {background = tonumber('0xffc1ff'), foreground = tonumber('0xe5a8e5'), special = Screen.colors.Red},
[10] = {background = tonumber('0xffc1ff'), foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[11] = {foreground = tonumber('0xe5a8e5'), special = Screen.colors.Red, background = tonumber('0xffc1ff'), reverse = true, bold = true},
[12] = {foreground = Screen.colors.Grey45, special = Screen.colors.Red, background = Screen.colors.Gray55, reverse = true, bold = true},
[13] = {background = tonumber('0xffc1e5'), foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[14] = {background = tonumber('0xffc1e5'), foreground = tonumber('0xe5a8e5'), special = Screen.colors.Red},
[15] = {background = tonumber('0xffc1ff'), foreground = tonumber('0x080202'), special = Screen.colors.Red},
[16] = {special = Screen.colors.Red, background = tonumber('0xffc1ff'), bold = true, foreground = tonumber('0xf6ace9')},
[17] = {background = tonumber('0xffc1ff'), foreground = tonumber('0xe5a8ff'), special = Screen.colors.Red},
[18] = {special = Screen.colors.Red, background = tonumber('0xffc1ff'), reverse = true, foreground = tonumber('0xe5a8e5')},
[19] = {special = Screen.colors.Red, background = Screen.colors.Gray55, reverse = true, foreground = Screen.colors.Grey45},
[20] = {bold = true},
[21] = {bold = true, foreground = Screen.colors.SeaGreen4},
[22] = {background = Screen.colors.WebGray},
[23] = {background = Screen.colors.Grey0},
[24] = {background = Screen.colors.LightMagenta},
[25] = {background = Screen.colors.Gray75, foreground = Screen.colors.Grey25, special = Screen.colors.Red},
[26] = {background = Screen.colors.Gray75, foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[27] = {background = Screen.colors.Gray50, foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[28] = {background = tonumber('0xffddff'), foreground = tonumber('0x7f5d7f'), special = Screen.colors.Red},
[29] = {background = tonumber('0xffddff'), foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[30] = {foreground = tonumber('0x7f5d7f'), special = Screen.colors.Red, background = tonumber('0xffddff'), reverse = true, bold = true},
[31] = {foreground = Screen.colors.Grey0, special = Screen.colors.Red, background = tonumber('0xffddff'), reverse = true, bold = true},
[32] = {foreground = Screen.colors.Grey25, special = Screen.colors.Red, background = Screen.colors.Gray75, reverse = true, bold = true},
[33] = {background = tonumber('0xffdd7f'), foreground = Screen.colors.Grey0, special = Screen.colors.Red},
[34] = {background = tonumber('0xffdd7f'), foreground = tonumber('0x7f5d7f'), special = Screen.colors.Red},
[35] = {special = Screen.colors.Red, background = tonumber('0xffddff'), bold = true, foreground = tonumber('0x290a0a')},
[36] = {special = Screen.colors.Red, background = tonumber('0xffddff'), bold = true, foreground = tonumber('0xd27294')},
[37] = {background = tonumber('0xffddff'), foreground = tonumber('0x7f5dff'), special = Screen.colors.Red},
[38] = {special = Screen.colors.Red, background = tonumber('0xffddff'), reverse = true, foreground = tonumber('0x7f5d7f')},
[39] = {special = Screen.colors.Red, background = tonumber('0xffddff'), reverse = true, foreground = Screen.colors.Grey0},
[40] = {special = Screen.colors.Red, background = Screen.colors.Gray75, reverse = true, foreground = Screen.colors.Grey25},
[41] = {background = tonumber('0xffddff'), foreground = tonumber('0x00003f'), special = Screen.colors.Red},
})
command('syntax on')
command('set mouse=a')
command('set pumblend=10')
insert([[
Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex
ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est
laborum.]])
command('match Statement /el/')
command('2match Comment /ut/')
command('1')
command('split')
command('/ol')
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
^incididunt ut labore et d{1:ol}ore magna aliqua. |
Ut enim ad minim veniam, quis nostrud |
exercitation ullamco laboris nisi ut aliquip ex |
ea commodo consequat. Duis aute irure d{1:ol}or in |
{2:[No Name] [+] }|
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing {3:el}it, sed do eiusmod tempor |
incididunt {4:ut} labore et d{1:ol}ore magna aliqua. |
Ut enim ad minim veniam, quis nostrud |
exercitation ullamco laboris nisi {4:ut} aliquip ex |
{5:[No Name] [+] }|
|
]])
feed('Obla bla <c-x><c-n>')
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
bla bla incididunt^ |
incidid{6:u}{7:incididunt}{6:re et}{8: }d{1:ol}ore magna aliqua. |
Ut enim{9: }{10:ut}{9: minim veniam}{6:,} quis nostrud |
exercit{9:a}{10:labore}{9:llamco la}{6:b}oris nisi ut aliquip ex |
{2:[No Nam}{11:e}{10:et}{11:[+] }{12: }{2: }|
Lorem i{9:p}{10:dolor}{13:e}{14:l}{9:or sit a}{6:m}et, consectetur |
adipisi{9:c}{10:magn}{15:a}{16:l}{9:it, sed d}{6:o} eiusmod tempor |
bla bla{9: }{10:aliqua}{9:dunt }{6: } |
incidid{9:u}{10:Ut}{9: }{17:ut}{9: labore et}{6: }d{1:ol}ore magna aliqua. |
Ut enim{9: }{10:enim}{9:inim veniam}{6:,} quis nostrud |
{5:[No Nam}{18:e}{10:ad}{18:[+] }{19: }{5: }|
{20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
]])
command('set pumblend=0')
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
bla bla incididunt^ |
incidid{22: incididunt }{23: }d{1:ol}ore magna aliqua. |
Ut enim{24: ut }{22: } quis nostrud |
exercit{24: labore }{22: }oris nisi ut aliquip ex |
{2:[No Nam}{24: et }{22: }{2: }|
Lorem i{24: dolore }{22: }et, consectetur |
adipisi{24: magna }{22: } eiusmod tempor |
bla bla{24: aliqua }{22: } |
incidid{24: Ut }{22: }d{1:ol}ore magna aliqua. |
Ut enim{24: enim }{22: } quis nostrud |
{5:[No Nam}{24: ad }{22: }{5: }|
{20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
]])
command('set pumblend=50')
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
bla bla incididunt^ |
incidid{25:u}{26:incididunt}{25:re et}{27: }d{1:ol}ore magna aliqua. |
Ut enim{28: }{29:ut}{28: minim veniam}{25:,} quis nostrud |
exercit{28:a}{29:labore}{28:llamco la}{25:b}oris nisi ut aliquip ex |
{2:[No Nam}{30:e}{31:et}{30:[+] }{32: }{2: }|
Lorem i{28:p}{29:dolor}{33:e}{34:l}{28:or sit a}{25:m}et, consectetur |
adipisi{28:c}{29:magn}{35:a}{36:l}{28:it, sed d}{25:o} eiusmod tempor |
bla bla{28: }{29:aliqua}{28:dunt }{25: } |
incidid{28:u}{29:Ut}{28: }{37:ut}{28: labore et}{25: }d{1:ol}ore magna aliqua. |
Ut enim{28: }{29:enim}{28:inim veniam}{25:,} quis nostrud |
{5:[No Nam}{38:e}{39:ad}{38:[+] }{40: }{5: }|
{20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
]])
meths.input_mouse('wheel', 'down', '', 0, 9, 40)
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
bla bla incididunt^ |
incidid{25:u}{26:incididunt}{25:re et}{27: }d{1:ol}ore magna aliqua. |
Ut enim{28: }{29:ut}{28: minim veniam}{25:,} quis nostrud |
exercit{28:a}{29:labore}{28:llamco la}{25:b}oris nisi ut aliquip ex |
{2:[No Nam}{30:e}{31:et}{30:[+] }{32: }{2: }|
incidid{28:u}{29:dol}{41:or}{29:e}{28:labore et}{25: }d{1:ol}ore magna aliqua. |
Ut enim{28: }{29:magna}{28:nim veniam}{25:,} quis nostrud |
exercit{28:a}{29:aliqua}{28:llamco la}{25:b}oris nisi {4:ut} aliquip ex |
ea comm{28:o}{29:Ut}{28: consequat. D}{25:u}is a{4:ut}e irure d{1:ol}or in |
reprehe{28:n}{29:enim}{28:t in v}{34:ol}{28:upt}{25:a}te v{3:el}it esse cillum |
{5:[No Nam}{38:e}{39:ad}{38:[+] }{40: }{5: }|
{20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
]])
feed('<c-e>')
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
bla bla ^ |
incididunt ut labore et d{1:ol}ore magna aliqua. |
Ut enim ad minim veniam, quis nostrud |
exercitation ullamco laboris nisi ut aliquip ex |
{2:[No Name] [+] }|
incididunt {4:ut} labore et d{1:ol}ore magna aliqua. |
Ut enim ad minim veniam, quis nostrud |
exercitation ullamco laboris nisi {4:ut} aliquip ex |
ea commodo consequat. Duis a{4:ut}e irure d{1:ol}or in |
reprehenderit in v{1:ol}uptate v{3:el}it esse cillum |
{5:[No Name] [+] }|
{20:-- INSERT --} |
]])
end)
end) end)

View File

@ -1303,6 +1303,8 @@ function Screen:_pprint_attrs(attrs)
if f == "foreground" or f == "background" or f == "special" then if f == "foreground" or f == "background" or f == "special" then
if Screen.colornames[v] ~= nil then if Screen.colornames[v] ~= nil then
desc = "Screen.colors."..Screen.colornames[v] desc = "Screen.colors."..Screen.colornames[v]
else
desc = string.format("tonumber('0x%06x')",v)
end end
end end
table.insert(items, f.." = "..desc) table.insert(items, f.." = "..desc)