summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-09-17 23:03:31 +0200
committerBram Moolenaar <Bram@vim.org>2017-09-17 23:03:31 +0200
commit1b9645de3c05f37b5c30e78f999351b0cf486ade (patch)
tree4041a73d7fd4ab444372919e99962587a689388a /src
parentdde403c2d8f3dabe6fefa7b526958b49a8f2e6e9 (diff)
downloadvim-git-1b9645de3c05f37b5c30e78f999351b0cf486ade.tar.gz
patch 8.0.1123: cannot define a toolbar for a windowv8.0.1123
Problem: Cannot define a toolbar for a window. Solution: Add a window-local toolbar.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile1
-rw-r--r--src/eval.c8
-rw-r--r--src/evalfunc.c3
-rw-r--r--src/if_perl.xs13
-rw-r--r--src/menu.c290
-rw-r--r--src/normal.c4
-rw-r--r--src/proto/menu.pro3
-rw-r--r--src/proto/syntax.pro1
-rw-r--r--src/screen.c362
-rw-r--r--src/structs.h22
-rw-r--r--src/syntax.c26
-rw-r--r--src/terminal.c7
-rw-r--r--src/testdir/Make_all.mak5
-rw-r--r--src/testdir/test_winbar.vim23
-rw-r--r--src/ui.c20
-rw-r--r--src/version.c2
-rw-r--r--src/window.c5
17 files changed, 571 insertions, 224 deletions
diff --git a/src/Makefile b/src/Makefile
index 247fee610..ad96784a6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2278,6 +2278,7 @@ test_arglist \
test_vimscript \
test_virtualedit \
test_visual \
+ test_winbar \
test_window_cmd \
test_window_id \
test_windows_home \
diff --git a/src/eval.c b/src/eval.c
index 0d954a0ee..8b1ceaea8 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -8252,13 +8252,7 @@ ex_echo(exarg_T *eap)
void
ex_echohl(exarg_T *eap)
{
- int id;
-
- id = syn_name2id(eap->arg);
- if (id == 0)
- echo_attr = 0;
- else
- echo_attr = syn_id2attr(id);
+ echo_attr = syn_name2attr(eap->arg);
}
/*
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 8d370d49a..6c2a73e80 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -5229,6 +5229,9 @@ get_win_info(win_T *wp, short tpnr, short winnr)
dict_add_nr_str(dict, "winnr", winnr, NULL);
dict_add_nr_str(dict, "winid", wp->w_id, NULL);
dict_add_nr_str(dict, "height", wp->w_height, NULL);
+#ifdef FEAT_MENU
+ dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
+#endif
dict_add_nr_str(dict, "width", wp->w_width, NULL);
dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
diff --git a/src/if_perl.xs b/src/if_perl.xs
index 893683813..d67645cd5 100644
--- a/src/if_perl.xs
+++ b/src/if_perl.xs
@@ -1387,11 +1387,8 @@ PerlIOVim_pushed(pTHX_ PerlIO *f, const char *mode,
{
PerlIOVim *s = PerlIOSelf(f, PerlIOVim);
s->attr = 0;
- if (arg && SvPOK(arg)) {
- int id = syn_name2id((char_u *)SvPV_nolen(arg));
- if (id != 0)
- s->attr = syn_id2attr(id);
- }
+ if (arg && SvPOK(arg))
+ s->attr = syn_name2attr((char_u *)SvPV_nolen(arg));
return PerlIOBase_pushed(aTHX_ f, mode, (SV *)NULL, tab);
}
@@ -1482,11 +1479,7 @@ Msg(text, hl=NULL)
{
attr = 0;
if (hl != NULL)
- {
- id = syn_name2id((char_u *)hl);
- if (id != 0)
- attr = syn_id2attr(id);
- }
+ attr = syn_name2attr((char_u *)hl);
msg_split((char_u *)text, attr);
}
diff --git a/src/menu.c b/src/menu.c
index 343a1b8ec..1ad8a5cb9 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -83,6 +83,31 @@ static const char *toolbar_names[] =
#endif
/*
+ * Return TRUE if "name" is a window toolbar menu name.
+ */
+ static int
+menu_is_winbar(char_u *name)
+{
+ return (STRNCMP(name, "WinBar", 5) == 0);
+}
+
+ int
+winbar_height(win_T *wp)
+{
+ if (wp->w_winbar != NULL && wp->w_winbar->children != NULL)
+ return 1;
+ return 0;
+}
+
+ static vimmenu_T **
+get_root_menu(char_u *name)
+{
+ if (menu_is_winbar(name))
+ return &curwin->w_winbar;
+ return &root_menu;
+}
+
+/*
* Do the :menu command and relatives.
*/
void
@@ -113,6 +138,7 @@ ex_menu(
char_u *icon = NULL;
#endif
vimmenu_T menuarg;
+ vimmenu_T **root_menu_ptr;
modes = get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
arg = eap->arg;
@@ -279,6 +305,11 @@ ex_menu(
# endif
#endif
+ root_menu_ptr = get_root_menu(menu_path);
+ if (root_menu_ptr == &curwin->w_winbar)
+ /* Assume the window toolbar menu will change. */
+ redraw_later(NOT_VALID);
+
if (enable != MAYBE)
{
/*
@@ -297,13 +328,13 @@ ex_menu(
p = popup_mode_name(menu_path, i);
if (p != NULL)
{
- menu_nable_recurse(root_menu, p, MENU_ALL_MODES,
+ menu_nable_recurse(*root_menu_ptr, p, MENU_ALL_MODES,
enable);
vim_free(p);
}
}
}
- menu_nable_recurse(root_menu, menu_path, modes, enable);
+ menu_nable_recurse(*root_menu_ptr, menu_path, modes, enable);
}
else if (unmenu)
{
@@ -324,14 +355,14 @@ ex_menu(
p = popup_mode_name(menu_path, i);
if (p != NULL)
{
- remove_menu(&root_menu, p, MENU_ALL_MODES, TRUE);
+ remove_menu(root_menu_ptr, p, MENU_ALL_MODES, TRUE);
vim_free(p);
}
}
}
/* Careful: remove_menu() changes menu_path */
- remove_menu(&root_menu, menu_path, modes, FALSE);
+ remove_menu(root_menu_ptr, menu_path, modes, FALSE);
}
else
{
@@ -401,6 +432,19 @@ ex_menu(
))
gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
#endif
+ if (root_menu_ptr == &curwin->w_winbar)
+ {
+ int h = winbar_height(curwin);
+
+ if (h != curwin->w_winbar_height)
+ {
+ if (h == 0)
+ ++curwin->w_height;
+ else if (curwin->w_height > 0)
+ --curwin->w_height;
+ curwin->w_winbar_height = h;
+ }
+ }
theend:
;
@@ -445,12 +489,14 @@ add_menu_path(
char_u *en_name;
char_u *map_to = NULL;
#endif
+ vimmenu_T **root_menu_ptr;
/* Make a copy so we can stuff around with it, since it could be const */
path_name = vim_strsave(menu_path);
if (path_name == NULL)
return FAIL;
- menup = &root_menu;
+ root_menu_ptr = get_root_menu(menu_path);
+ menup = root_menu_ptr;
parent = NULL;
name = path_name;
while (*name)
@@ -786,7 +832,7 @@ erret:
while (parent != NULL && parent->children == NULL)
{
if (parent->parent == NULL)
- menup = &root_menu;
+ menup = root_menu_ptr;
else
menup = &parent->parent->children;
for ( ; *menup != NULL && *menup != parent; menup = &((*menup)->next))
@@ -986,6 +1032,16 @@ remove_menu(
}
/*
+ * Remove the WinBar menu from window "wp".
+ */
+ void
+remove_winbar(win_T *wp)
+{
+ remove_menu(&wp->w_winbar, (char_u *)"", MENU_ALL_MODES, TRUE);
+ vim_free(wp->w_winbar_items);
+}
+
+/*
* Free the given menu structure and remove it from the linked list.
*/
static void
@@ -1057,10 +1113,10 @@ show_menus(char_u *path_name, int modes)
vimmenu_T *menu;
vimmenu_T *parent = NULL;
- menu = root_menu;
name = path_name = vim_strsave(path_name);
if (path_name == NULL)
return FAIL;
+ menu = *get_root_menu(path_name);
/* First, find the (sub)menu with the given name */
while (*name)
@@ -1190,6 +1246,7 @@ show_menus_recursive(vimmenu_T *menu, int modes, int depth)
* Used when expanding menu names.
*/
static vimmenu_T *expand_menu = NULL;
+static vimmenu_T *expand_menu_alt = NULL;
static int expand_modes = 0x0;
static int expand_emenu; /* TRUE for ":emenu" command */
@@ -1251,6 +1308,8 @@ set_context_in_menu_cmd(
return NULL; /* TODO: check for next command? */
if (*p == NUL) /* Complete the menu name */
{
+ int try_alt_menu = TRUE;
+
/*
* With :unmenu, you only want to match menus for the appropriate mode.
* With :menu though you might want to add a menu with the same name as
@@ -1290,6 +1349,11 @@ set_context_in_menu_cmd(
break;
}
menu = menu->next;
+ if (menu == NULL && try_alt_menu)
+ {
+ menu = curwin->w_winbar;
+ try_alt_menu = FALSE;
+ }
}
if (menu == NULL)
{
@@ -1299,12 +1363,17 @@ set_context_in_menu_cmd(
}
name = p;
menu = menu->children;
+ try_alt_menu = FALSE;
}
vim_free(path_name);
xp->xp_context = expand_menus ? EXPAND_MENUNAMES : EXPAND_MENUS;
xp->xp_pattern = after_dot;
expand_menu = menu;
+ if (expand_menu == root_menu)
+ expand_menu_alt = curwin->w_winbar;
+ else
+ expand_menu_alt = NULL;
}
else /* We're in the mapping part */
xp->xp_context = EXPAND_NOTHING;
@@ -1319,6 +1388,7 @@ set_context_in_menu_cmd(
get_menu_name(expand_T *xp UNUSED, int idx)
{
static vimmenu_T *menu = NULL;
+ static int did_alt_menu = FALSE;
char_u *str;
#ifdef FEAT_MULTI_LANG
static int should_advance = FALSE;
@@ -1327,6 +1397,7 @@ get_menu_name(expand_T *xp UNUSED, int idx)
if (idx == 0) /* first call: start at first item */
{
menu = expand_menu;
+ did_alt_menu = FALSE;
#ifdef FEAT_MULTI_LANG
should_advance = FALSE;
#endif
@@ -1337,7 +1408,14 @@ get_menu_name(expand_T *xp UNUSED, int idx)
|| menu_is_separator(menu->dname)
|| menu_is_tearoff(menu->dname)
|| menu->children == NULL))
+ {
menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
if (menu == NULL) /* at end of linked list */
return NULL;
@@ -1361,8 +1439,15 @@ get_menu_name(expand_T *xp UNUSED, int idx)
#ifdef FEAT_MULTI_LANG
if (should_advance)
#endif
+ {
/* Advance to next menu entry. */
menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
#ifdef FEAT_MULTI_LANG
should_advance = !should_advance;
@@ -1379,6 +1464,7 @@ get_menu_name(expand_T *xp UNUSED, int idx)
get_menu_names(expand_T *xp UNUSED, int idx)
{
static vimmenu_T *menu = NULL;
+ static int did_alt_menu = FALSE;
#define TBUFFER_LEN 256
static char_u tbuffer[TBUFFER_LEN]; /*hack*/
char_u *str;
@@ -1389,6 +1475,7 @@ get_menu_names(expand_T *xp UNUSED, int idx)
if (idx == 0) /* first call: start at first item */
{
menu = expand_menu;
+ did_alt_menu = FALSE;
#ifdef FEAT_MULTI_LANG
should_advance = FALSE;
#endif
@@ -1403,7 +1490,14 @@ get_menu_names(expand_T *xp UNUSED, int idx)
|| menu->dname[STRLEN(menu->dname) - 1] == '.'
#endif
))
+ {
menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
if (menu == NULL) /* at end of linked list */
return NULL;
@@ -1451,8 +1545,15 @@ get_menu_names(expand_T *xp UNUSED, int idx)
#ifdef FEAT_MULTI_LANG
if (should_advance)
#endif
+ {
/* Advance to next menu entry. */
menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
#ifdef FEAT_MULTI_LANG
should_advance = !should_advance;
@@ -2134,62 +2235,16 @@ gui_destroy_tearoffs_recurse(vimmenu_T *menu)
#endif /* FEAT_GUI_W32 && FEAT_TEAROFF */
/*
- * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
- * execute it.
+ * Execute "menu". Use by ":emenu" and the window toolbar.
+ * "eap" is NULL for the window toolbar.
*/
- void
-ex_emenu(exarg_T *eap)
+ static void
+execute_menu(exarg_T *eap, vimmenu_T *menu)
{
- vimmenu_T *menu;
- char_u *name;
- char_u *saved_name;
- char_u *p;
- int idx;
char_u *mode;
+ int idx;
- saved_name = vim_strsave(eap->arg);
- if (saved_name == NULL)
- return;
-
- menu = root_menu;
- name = saved_name;
- while (*name)
- {
- /* Find in the menu hierarchy */
- p = menu_name_skip(name);
-
- while (menu != NULL)
- {
- if (menu_name_equal(name, menu))
- {
- if (*p == NUL && menu->children != NULL)
- {
- EMSG(_("E333: Menu path must lead to a menu item"));
- menu = NULL;
- }
- else if (*p != NUL && menu->children == NULL)
- {
- EMSG(_(e_notsubmenu));
- menu = NULL;
- }
- break;
- }
- menu = menu->next;
- }
- if (menu == NULL || *p == NUL)
- break;
- menu = menu->children;
- name = p;
- }
- vim_free(saved_name);
- if (menu == NULL)
- {
- EMSG2(_("E334: Menu not found: %s"), eap->arg);
- return;
- }
-
- /* Found the menu, so execute.
- * Use the Insert mode entry when returning to Insert mode. */
+ /* Use the Insert mode entry when returning to Insert mode. */
if (restart_edit
#ifdef FEAT_EVAL
&& !current_SID
@@ -2199,7 +2254,12 @@ ex_emenu(exarg_T *eap)
mode = (char_u *)"Insert";
idx = MENU_INDEX_INSERT;
}
- else if (eap->addr_count)
+ else if (VIsual_active)
+ {
+ mode = (char_u *)"Visual";
+ idx = MENU_INDEX_VISUAL;
+ }
+ else if (eap != NULL && eap->addr_count)
{
pos_T tpos;
@@ -2255,22 +2315,120 @@ ex_emenu(exarg_T *eap)
if (idx != MENU_INDEX_INVALID && menu->strings[idx] != NULL)
{
/* When executing a script or function execute the commands right now.
+ * Also for the window toolbar.
* Otherwise put them in the typeahead buffer. */
+ if (eap == NULL
#ifdef FEAT_EVAL
- if (current_SID != 0)
+ || current_SID != 0
+#endif
+ )
exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
menu->silent[idx]);
else
-#endif
ins_typebuf(menu->strings[idx], menu->noremap[idx], 0,
TRUE, menu->silent[idx]);
}
- else
+ else if (eap != NULL)
EMSG2(_("E335: Menu not defined for %s mode"), mode);
}
-#if defined(FEAT_GUI_MSWIN) \
- || (defined(FEAT_GUI_GTK) && defined(FEAT_MENU)) \
+/*
+ * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
+ * execute it.
+ */
+ void
+ex_emenu(exarg_T *eap)
+{
+ vimmenu_T *menu;
+ char_u *name;
+ char_u *saved_name;
+ char_u *p;
+
+ saved_name = vim_strsave(eap->arg);
+ if (saved_name == NULL)
+ return;
+
+ menu = *get_root_menu(saved_name);
+ name = saved_name;
+ while (*name)
+ {
+ /* Find in the menu hierarchy */
+ p = menu_name_skip(name);
+
+ while (menu != NULL)
+ {
+ if (menu_name_equal(name, menu))
+ {
+ if (*p == NUL && menu->children != NULL)
+ {
+ EMSG(_("E333: Menu path must lead to a menu item"));
+ menu = NULL;
+ }
+ else if (*p != NUL && menu->children == NULL)
+ {
+ EMSG(_(e_notsubmenu));
+ menu = NULL;
+ }
+ break;
+ }
+ menu = menu->next;
+ }
+ if (menu == NULL || *p == NUL)
+ break;
+ menu = menu->children;
+ name = p;
+ }
+ vim_free(saved_name);
+ if (menu == NULL)
+ {
+ EMSG2(_("E334: Menu not found: %s"), eap->arg);
+ return;
+ }
+
+ /* Found the menu, so execute. */
+ execute_menu(eap, menu);
+}
+
+/*
+ * Handle a click in the window toolbar of "wp" at column "col".
+ */
+ void
+winbar_click(win_T *wp, int col)
+{
+ int idx;
+
+ if (wp->w_winbar_items == NULL)
+ return;
+ for (idx = 0; wp->w_winbar_items[idx].wb_menu != NULL; ++idx)
+ {
+ winbar_item_T *item = &wp->w_winbar_items[idx];
+
+ if (col >= item->wb_startcol && col <= item->wb_endcol)
+ {
+ win_T *save_curwin = NULL;
+
+ if (wp != curwin)
+ {
+ /* Clicking in the window toolbar of a not-current window.
+ * Make that window the current one and go to Normal mode. */
+ save_curwin = curwin;
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ check_cursor();
+ }
+
+ execute_menu(NULL, item->wb_menu);
+
+ if (save_curwin != NULL)
+ {
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ }
+ }
+ }
+}
+
+#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \
|| defined(FEAT_BEVAL_TIP) || defined(PROTO)
/*
* Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
@@ -2283,7 +2441,7 @@ gui_find_menu(char_u *path_name)
char_u *saved_name;
char_u *p;
- menu = root_menu;
+ menu = *get_root_menu(path_name);
saved_name = vim_strsave(path_name);
if (saved_name == NULL)
diff --git a/src/normal.c b/src/normal.c
index a8b6ffa16..6fffbcbc1 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -2679,9 +2679,9 @@ do_mouse(
* selection or the current window (might have false
* negative here)
*/
- if (mouse_row < W_WINROW(curwin)
+ if (mouse_row < curwin->w_winrow
|| mouse_row
- > (W_WINROW(curwin) + curwin->w_height))
+ > (curwin->w_winrow + curwin->w_height))
jump_flags = MOUSE_MAY_STOP_VIS;
else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
jump_flags = MOUSE_MAY_STOP_VIS;
diff --git a/src/proto/menu.pro b/src/proto/menu.pro
index e37083584..bd3d26b92 100644
--- a/src/proto/menu.pro
+++ b/src/proto/menu.pro
@@ -1,5 +1,7 @@
/* menu.c */
+int winbar_height(win_T *wp);
void ex_menu(exarg_T *eap);
+void remove_winbar(win_T *wp);
char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit);
char_u *get_menu_name(expand_T *xp, int idx);
char_u *get_menu_names(expand_T *xp, int idx);
@@ -17,6 +19,7 @@ int gui_is_menu_shortcut(int key);
void gui_show_popupmenu(void);
void gui_mch_toggle_tearoffs(int enable);
void ex_emenu(exarg_T *eap);
+void winbar_click(win_T *wp, int col);
vimmenu_T *gui_find_menu(char_u *path_name);
void ex_menutranslate(exarg_T *eap);
/* vim: set ft=c : */
diff --git a/src/proto/syntax.pro b/src/proto/syntax.pro
index 0f64ceaf8..f6ecb8c49 100644
--- a/src/proto/syntax.pro
+++ b/src/proto/syntax.pro
@@ -46,6 +46,7 @@ char_u *highlight_has_attr(int id, int flag, int modec);
char_u *highlight_color(int id, char_u *what, int modec);
long_u highlight_gui_color_rgb(int id, int fg);
int syn_name2id(char_u *name);
+int syn_name2attr(char_u *name);
int highlight_exists(char_u *name);
char_u *syn_id2name(int id);
int syn_namen2id(char_u *linep, int len);
diff --git a/src/screen.c b/src/screen.c
index d93ce50f3..9f39edf04 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -107,6 +107,9 @@ static int screen_cur_row, screen_cur_col; /* last known cursor position */
static match_T search_hl; /* used for 'hlsearch' highlight matching */
#endif
+#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
+static int text_to_screenline(win_T *wp, char_u *text, int col);
+#endif
#ifdef FEAT_FOLDING
static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
static int compute_foldcolumn(win_T *wp, int col);
@@ -160,6 +163,9 @@ static void recording_mode(int attr);
static void draw_tabline(void);
static int fillchar_status(int *attr, win_T *wp);
static int fillchar_vsep(int *attr);
+#ifdef FEAT_MENU
+static void redraw_win_toolbar(win_T *wp);
+#endif
#ifdef FEAT_STL_OPT
static void win_redr_custom(win_T *wp, int draw_ruler);
#endif
@@ -455,7 +461,7 @@ redraw_after_callback(int call_update_screen)
* editing the command. */
redrawcmdline_ex(FALSE);
}
- else if (State & (NORMAL | INSERT))
+ else if (State & (NORMAL | INSERT | TERMINAL))
{
/* keep the command line if possible */
update_screen(VALID_NO_UPDATE);
@@ -1804,6 +1810,15 @@ win_update(win_T *wp)
win_foldinfo.fi_level = 0;
#endif
+#ifdef FEAT_MENU
+ /*
+ * Draw the window toolbar, if there is one.
+ * TODO: only when needed.
+ */
+ if (winbar_height(wp) > 0)
+ redraw_win_toolbar(wp);
+#endif
+
/*
* Update all the window rows.
*/
@@ -2433,6 +2448,143 @@ advance_color_col(int vcol, int **color_cols)
}
#endif
+#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
+/*
+ * Copy "text" to ScreenLines using "attr".
+ * Returns the next screen column.
+ */
+ static int
+text_to_screenline(win_T *wp, char_u *text, int col)
+{
+ int off = (int)(current_ScreenLine - ScreenLines);
+
+#ifdef FEAT_MBYTE
+ if (has_mbyte)
+ {
+ int cells;
+ int u8c, u8cc[MAX_MCO];
+ int i;
+ int idx;
+ int c_len;
+ char_u *p;
+# ifdef FEAT_ARABIC
+ int prev_c = 0; /* previous Arabic character */
+ int prev_c1 = 0; /* first composing char for prev_c */
+# endif
+
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ idx = off;
+ else
+# endif
+ idx = off + col;
+
+ /* Store multibyte characters in ScreenLines[] et al. correctly. */
+ for (p = text; *p != NUL; )
+ {
+ cells = (*mb_ptr2cells)(p);
+ c_len = (*mb_ptr2len)(p);
+ if (col + cells > W_WIDTH(wp)
+# ifdef FEAT_RIGHTLEFT
+ - (wp->w_p_rl ? col : 0)
+# endif
+ )
+ break;
+ ScreenLines[idx] = *p;
+ if (enc_utf8)
+ {
+ u8c = utfc_ptr2char(p, u8cc);
+ if (*p < 0x80 && u8cc[0] == 0)
+ {
+ ScreenLinesUC[idx] = 0;
+#ifdef FEAT_ARABIC
+ prev_c = u8c;
+#endif
+ }
+ else
+ {
+#ifdef FEAT_ARABIC
+ if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
+ {
+ /* Do Arabic shaping. */
+ int pc, pc1, nc;
+ int pcc[MAX_MCO];
+ int firstbyte = *p;
+
+ /* The idea of what is the previous and next
+ * character depends on 'rightleft'. */
+ if (wp->w_p_rl)
+ {
+ pc = prev_c;
+ pc1 = prev_c1;
+ nc = utf_ptr2char(p + c_len);
+ prev_c1 = u8cc[0];
+ }
+ else
+ {
+ pc = utfc_ptr2char(p + c_len, pcc);
+ nc = prev_c;
+ pc1 = pcc[0];
+ }
+ prev_c = u8c;
+
+ u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
+ pc, pc1, nc);
+ ScreenLines[idx] = firstbyte;
+ }
+ else
+ prev_c = u8c;
+#endif
+ /* Non-BMP character: display as ? or fullwidth ?. */
+#ifdef UNICODE16
+ if (u8c >= 0x10000)
+ ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
+ else
+#endif
+ ScreenLinesUC[idx] = u8c;
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ ScreenLinesC[i][idx] = u8cc[i];
+ if (u8cc[i] == 0)
+ break;
+ }
+ }
+ if (cells > 1)
+ ScreenLines[idx + 1] = 0;
+ }
+ else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
+ /* double-byte single width character */
+ ScreenLines2[idx] = p[1];
+ else if (cells > 1)
+ /* double-width character */
+ ScreenLines[idx + 1] = p[1];
+ col += cells;
+ idx += cells;
+ p += c_len;
+ }
+ }
+ else
+#endif
+ {
+ int len = (int)STRLEN(text);
+
+ if (len > W_WIDTH(wp) - col)
+ len = W_WIDTH(wp) - col;
+ if (len > 0)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ STRNCPY(current_ScreenLine, text, len);
+ else
+#endif
+ STRNCPY(current_ScreenLine + col, text, len);
+ col += len;
+ }
+ }
+ return col;
+}
+#endif
+
#ifdef FEAT_FOLDING
/*
* Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
@@ -2618,128 +2770,7 @@ fold_line(
* Right-left text is put in columns 0 - number-col, normal text is put
* in columns number-col - window-width.
*/
-#ifdef FEAT_MBYTE
- if (has_mbyte)
- {
- int cells;
- int u8c, u8cc[MAX_MCO];
- int i;
- int idx;
- int c_len;
- char_u *p;
-# ifdef FEAT_ARABIC
- int prev_c = 0; /* previous Arabic character */
- int prev_c1 = 0; /* first composing char for prev_c */
-# endif
-
-# ifdef FEAT_RIGHTLEFT
- if (wp->w_p_rl)
- idx = off;
- else
-# endif
- idx = off + col;
-
- /* Store multibyte characters in ScreenLines[] et al. correctly. */
- for (p = text; *p != NUL; )
- {
- cells = (*mb_ptr2cells)(p);
- c_len = (*mb_ptr2len)(p);
- if (col + cells > W_WIDTH(wp)
-# ifdef FEAT_RIGHTLEFT
- - (wp->w_p_rl ? col : 0)
-# endif
- )
- break;
- ScreenLines[idx] = *p;
- if (enc_utf8)
- {
- u8c = utfc_ptr2char(p, u8cc);
- if (*p < 0x80 && u8cc[0] == 0)
- {
- ScreenLinesUC[idx] = 0;
-#ifdef FEAT_ARABIC
- prev_c = u8c;
-#endif
- }
- else
- {
-#ifdef FEAT_ARABIC
- if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
- {
- /* Do Arabic shaping. */
- int pc, pc1, nc;
- int pcc[MAX_MCO];
- int firstbyte = *p;
-
- /* The idea of what is the previous and next
- * character depends on 'rightleft'. */
- if (wp->w_p_rl)
- {
- pc = prev_c;
- pc1 = prev_c1;
- nc = utf_ptr2char(p + c_len);
- prev_c1 = u8cc[0];
- }
- else
- {
- pc = utfc_ptr2char(p + c_len, pcc);
- nc = prev_c;
- pc1 = pcc[0];
- }
- prev_c = u8c;
-
- u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
- pc, pc1, nc);
- ScreenLines[idx] = firstbyte;
- }
- else
- prev_c = u8c;
-#endif
- /* Non-BMP character: display as ? or fullwidth ?. */
-#ifdef UNICODE16
- if (u8c >= 0x10000)
- ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
- else
-#endif
- ScreenLinesUC[idx] = u8c;
- for (i = 0; i < Screen_mco; ++i)
- {
- ScreenLinesC[i][idx] = u8cc[i];
- if (u8cc[i] == 0)
- break;
- }
- }
- if (cells > 1)
- ScreenLines[idx + 1] = 0;
- }
- else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
- /* double-byte single width character */
- ScreenLines2[idx] = p[1];
- else if (cells > 1)
- /* double-width character */
- ScreenLines[idx + 1] = p[1];
- col += cells;
- idx += cells;
- p += c_len;
- }
- }
- else
-#endif
- {
- len = (int)STRLEN(text);
- if (len > W_WIDTH(wp) - col)
- len = W_WIDTH(wp) - col;
- if (len > 0)
- {
-#ifdef FEAT_RIGHTLEFT
- if (wp->w_p_rl)
- STRNCPY(current_ScreenLine, text, len);
- else
-#endif
- STRNCPY(current_ScreenLine + col, text, len);
- col += len;
- }
- }
+ col = text_to_screenline(wp, text, col);
/* Fill the rest of the line with the fold filler */
#ifdef FEAT_RIGHTLEFT
@@ -8397,6 +8428,17 @@ redraw_block(int row, int end, win_T *wp)
screen_draw_rectangle(row, col, end - row, width, FALSE);
}
+ static void
+space_to_screenline(int off, int attr)
+{
+ ScreenLines[off] = ' ';
+ ScreenAttrs[off] = attr;
+# ifdef FEAT_MBYTE
+ if (enc_utf8)
+ ScreenLinesUC[off] = 0;
+# endif
+}
+
/*
* Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
* with character 'c1' in first column followed by 'c2' in the other columns.
@@ -8502,12 +8544,7 @@ screen_fill(
col = end_col - col;
while (col--) /* clear chars in ScreenLines */
{
- ScreenLines[off] = ' ';
-#ifdef FEAT_MBYTE
- if (enc_utf8)
- ScreenLinesUC[off] = 0;
-#endif
- ScreenAttrs[off] = 0;
+ space_to_screenline(off, 0);
++off;
}
}
@@ -10671,6 +10708,73 @@ messaging(void)
return (!(p_lz && char_avail() && !KeyTyped));
}
+#ifdef FEAT_MENU
+/*
+ * Draw the window toolbar.
+ */
+ static void
+redraw_win_toolbar(win_T *wp)
+{
+ vimmenu_T *menu;
+ int item_idx = 0;
+ int item_count = 0;
+ int col = 0;
+ int next_col;
+ int off = (int)(current_ScreenLine - ScreenLines);
+ int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
+ int button_attr = syn_name2attr((char_u *)"ToolbarButton");
+
+ vim_free(wp->w_winbar_items);
+ for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
+ ++item_count;
+ wp->w_winbar_items = (winbar_item_T *)alloc_clear(
+ (unsigned)sizeof(winbar_item_T) * (item_count + 1));
+
+ /* TODO: use fewer spaces if there is not enough room */
+ for (menu = wp->w_winbar->children;
+ menu != NULL && col < W_WIDTH(wp); menu = menu->next)
+ {
+ space_to_screenline(off + col, fill_attr);
+ if (++col >= W_WIDTH(wp))
+ break;
+ if (col > 1)
+ {
+ space_to_screenline(off + col, fill_attr);
+ if (++col >= W_WIDTH(wp))
+ break;
+ }
+
+ wp->w_winbar_items[item_idx].wb_startcol = col;
+ space_to_screenline(off + col, button_attr);
+ if (++col >= W_WIDTH(wp))
+ break;
+
+ next_col = text_to_screenline(wp, menu->name, col);
+ while (col < next_col)
+ {
+ ScreenAttrs[off + col] = button_attr;
+ ++col;
+ }
+ wp->w_winbar_items[item_idx].wb_endcol = col;
+ wp->w_winbar_items[item_idx].wb_menu = menu;
+ ++item_idx;
+
+ if (col >= W_WIDTH(wp))
+ break;
+ space_to_screenline(off + col, button_attr);
+ ++col;
+ }
+ while (col < W_WIDTH(wp))
+ {
+ space_to_screenline(off + col, fill_attr);
+ ++col;
+ }
+ wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
+
+ screen_line(wp->w_winrow, W_WINCOL(wp), (int)W_WIDTH(wp),
+ (int)W_WIDTH(wp), FALSE);
+}
+#endif
/*
* Show current status info in ruler and various other places
* If always is FALSE, only show ruler if position has changed.
diff --git a/src/structs.h b/src/structs.h
index 18a047c51..94d739191 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -70,6 +70,10 @@ typedef int scid_T; /* script ID */
typedef struct file_buffer buf_T; /* forward declaration */
typedef struct terminal_S term_T;
+#ifdef FEAT_MENU
+typedef struct VimMenu vimmenu_T;
+#endif
+
/*
* Reference to a buffer that stores the value of buf_free_count.
* bufref_valid() only needs to check "buf" when the count differs.
@@ -2611,6 +2615,14 @@ struct matchitem
#endif
};
+#ifdef FEAT_MENU
+typedef struct {
+ int wb_startcol;
+ int wb_endcol;
+ vimmenu_T *wb_menu;
+} winbar_item_T;
+#endif
+
/*
* Structure which contains all information that belongs to a window
*
@@ -2686,7 +2698,7 @@ struct window_S
*/
int w_winrow; /* first row of window in screen */
int w_height; /* number of rows in window, excluding
- status/command line(s) */
+ status/command/winbar line(s) */
int w_status_height; /* number of status lines (0 or 1) */
int w_wincol; /* Leftmost column of window in screen.
use W_WINCOL() */
@@ -2798,6 +2810,12 @@ struct window_S
char_u *w_localdir; /* absolute path of local directory or
NULL */
+#ifdef FEAT_MENU
+ vimmenu_T *w_winbar; /* The root of the WinBar menu hierarchy. */
+ winbar_item_T *w_winbar_items; /* list of items in the WinBar */
+ int w_winbar_height; /* 1 if there is a window toolbar */
+#endif
+
/*
* Options local to a window.
* They are local because they influence the layout of the window or
@@ -3064,8 +3082,6 @@ typedef struct cursor_entry
/* Start a menu name with this to not include it on the main menu bar */
#define MNU_HIDDEN_CHAR ']'
-typedef struct VimMenu vimmenu_T;
-
struct VimMenu
{
int modes; /* Which modes is this menu visible for? */
diff --git a/src/syntax.c b/src/syntax.c
index c6e01562e..6361bd7aa 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -7002,6 +7002,12 @@ static char *(highlight_init_light[]) = {
CENT("StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen",
"StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen guifg=bg guibg=DarkGreen"),
#endif
+#ifdef FEAT_MENU
+ CENT("ToolbarLine term=underline ctermbg=LightGrey",
+ "ToolbarLine term=underline ctermbg=LightGrey guibg=LightGrey"),
+ CENT("ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey",
+ "ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey gui=bold guifg=White guibg=DarkGrey"),
+#endif
NULL
};
@@ -7094,6 +7100,12 @@ static char *(highlight_init_dark[]) = {
CENT("StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen",
"StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen guifg=bg guibg=LightGreen"),
#endif
+#ifdef FEAT_MENU
+ CENT("ToolbarLine term=underline ctermbg=DarkGrey",
+ "ToolbarLine term=underline ctermbg=DarkGrey guibg=DarkGrey"),
+ CENT("ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey",
+ "ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey gui=bold guifg=Black guibg=LightGrey"),
+#endif
NULL
};
@@ -9525,6 +9537,20 @@ syn_name2id(char_u *name)
return i + 1;
}
+/*
+ * Lookup a highlight group name and return its attributes.
+ * Return zero if not found.
+ */
+ int
+syn_name2attr(char_u *name)
+{
+ int id = syn_name2id(name);
+
+ if (id != 0)
+ return syn_id2attr(syn_get_final_id(id));
+ return 0;
+}
+
#if defined(FEAT_EVAL) || defined(PROTO)
/*
* Return TRUE if highlight group "name" exists.
diff --git a/src/terminal.c b/src/terminal.c
index db1741703..7dc21d612 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -38,7 +38,8 @@
* in tl_scrollback are no longer used.
*
* TODO:
- * - test_terminal_no_cmd hangs (Christian)
+ * - Shift-Tab does not work.
+ * - click in Window toolbar of other window: save/restore Insert and Visual
* - Redirecting output does not work on MS-Windows, Test_terminal_redir_file()
* is disabled.
* - implement term_setsize()
@@ -703,7 +704,7 @@ write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
update_screen(0);
update_cursor(term, TRUE);
}
- else if (buffer->b_nwindows > 0)
+ else
redraw_after_callback(TRUE);
}
}
@@ -1545,7 +1546,7 @@ terminal_loop(int blocking)
{
/* TODO: skip screen update when handling a sequence of keys. */
/* Repeat redrawing in case a message is received while redrawing. */
- while (curwin->w_redr_type != 0)
+ while (must_redraw != 0)
if (update_screen(0) == FAIL)
break;
update_cursor(curbuf->b_term, FALSE);
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index b979c975b..169d84fd5 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -201,12 +201,13 @@ NEW_TESTS = test_arabic.res \
test_viminfo.res \
test_vimscript.res \
test_visual.res \
+ test_winbar.res \
test_window_id.res \
+ test_windows_home.res \
test_writefile.res \
test_alot_latin.res \
test_alot_utf8.res \
- test_alot.res \
- test_windows_home.res
+ test_alot.res
# Explicit dependencies.
diff --git a/src/testdir/test_winbar.vim b/src/testdir/test_winbar.vim
new file mode 100644
index 000000000..19616073c
--- /dev/null
+++ b/src/testdir/test_winbar.vim
@@ -0,0 +1,23 @@
+" Test WinBar
+
+if !has('menu')
+ finish
+endif
+
+func Test_add_remove_menu()
+ new
+ amenu 1.10 WinBar.Next :let g:did_next = 11<CR>
+ amenu 1.20 WinBar.Cont :let g:did_cont = 12<CR>
+ emenu WinBar.Next
+ call assert_equal(11, g:did_next)
+ emenu WinBar.Cont
+ call assert_equal(12, g:did_cont)
+
+ wincmd w
+ call assert_fails('emenu WinBar.Next', 'E334')
+ wincmd p
+
+ aunmenu WinBar.Next
+ aunmenu WinBar.Cont
+ close
+endfunc
diff --git a/src/ui.c b/src/ui.c
index 49782ae62..c26cb378f 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -2657,7 +2657,7 @@ retnomove:
}
#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
/* Continue a modeless selection in another window. */
- if (cmdwin_type != 0 && row < W_WINROW(curwin))
+ if (cmdwin_type != 0 && row < curwin->w_winrow)
return IN_OTHER_WIN;
#endif
return IN_BUFFER;
@@ -2692,6 +2692,17 @@ retnomove:
if (wp == NULL)
return IN_UNKNOWN;
dragwin = NULL;
+
+#ifdef FEAT_MENU
+ if (row == -1)
+ {
+ /* A click in the window toolbar does not enter another window or
+ * change Visual highlighting. */
+ winbar_click(wp, col);
+ return IN_OTHER_WIN;
+ }
+#endif
+
/*
* winpos and height may change in win_enter()!
*/
@@ -2829,7 +2840,7 @@ retnomove:
#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
/* Continue a modeless selection in another window. */
- if (cmdwin_type != 0 && row < W_WINROW(curwin))
+ if (cmdwin_type != 0 && row < curwin->w_winrow)
return IN_OTHER_WIN;
#endif
@@ -3117,7 +3128,12 @@ mouse_find_win(int *rowp, int *colp UNUSED)
* exist. */
FOR_ALL_WINDOWS(wp)
if (wp == fp->fr_win)
+ {
+#ifdef FEAT_MENU
+ *rowp -= wp->w_winbar_height;
+#endif
return wp;
+ }
return NULL;
}
diff --git a/src/version.c b/src/version.c
index a24116628..03431c79e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -762,6 +762,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1123,
+/**/
1122,
/**/
1121,
diff --git a/src/window.c b/src/window.c
index 9b470f6c3..be8e20ade 100644
--- a/src/window.c
+++ b/src/window.c
@@ -4692,6 +4692,10 @@ win_free(
}
#endif /* FEAT_GUI */
+#ifdef FEAT_MENU
+ remove_winbar(wp);
+#endif
+
#ifdef FEAT_SYN_HL
vim_free(wp->w_p_cc_cols);
#endif
@@ -5667,6 +5671,7 @@ set_fraction(win_T *wp)
/*
* Set the height of a window.
+ * "height" excludes any window toolbar.
* This takes care of the things inside the window, not what happens to the
* window position, the frame or to other windows.
*/