summaryrefslogtreecommitdiffstats
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
parentdde403c2d8f3dabe6fefa7b526958b49a8f2e6e9 (diff)
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.
-rw-r--r--runtime/doc/gui.txt23
-rw-r--r--runtime/doc/terminal.txt14
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim85
-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
20 files changed, 679 insertions, 238 deletions
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index a66fbb31e9..7fb6a59719 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -1,4 +1,4 @@
-*gui.txt* For Vim version 8.0. Last change: 2017 Aug 27
+*gui.txt* For Vim version 8.0. Last change: 2017 Sep 16
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -784,10 +784,31 @@ In the Win32 and GTK+ GUI, starting a menu name with ']' excludes that menu
from the main menu bar. You must then use the |:popup| or |:tearoff| command
to display it.
+ *window-toolbar*
+Each window can have a local toolbar. This uses the first line of the window,
+thus reduces the space for the text by one line.
+
+Only text can be used. When using Unicode special characters can be used to
+make the items look like icons.
+
+If the items do not fit then the last ones cannot be used. The toolbar does
+not wrap.
+
+Example for debugger tools: >
+ amenu 1.10 WinBar.Step :Step<CR>
+ amenu 1.20 WinBar.Next :Next<CR>
+ amenu 1.30 WinBar.Finish :Finish<CR>
+ amenu 1.40 WinBar.Cont :Continue<CR>
+<
+The window toolbar uses the ToolbarLine and ToolbarButton highlight groups.
+
*popup-menu*
In the Win32, GTK+, Motif, Athena and Photon GUI, you can define the
special menu "PopUp". This is the menu that is displayed when the right mouse
button is pressed, if 'mousemodel' is set to popup or popup_setpos.
+Example: >
+ nnoremenu 1.40 PopUp.&Paste "+gP
+ menu PopUp
5.3 Showing What Menus Are Mapped To *showing-menus*
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index aad8e4a5f6..bce1d6fb00 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -1,4 +1,4 @@
-*terminal.txt* For Vim version 8.0. Last change: 2017 Sep 14
+*terminal.txt* For Vim version 8.0. Last change: 2017 Sep 17
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -226,7 +226,7 @@ Use CTRL-W N (or 'termkey' N) to switch to Terminal-Normal mode. Now the
contents of the terminal window is under control of Vim, the job output is
suspended. CTRL-\ CTRL-N does the same.
-Terminal-Job mode is where |tmap| mappings are applied. Keys sent by
+Terminal-Job mode is where |:tmap| mappings are applied. Keys sent by
|term_sendkeys()| are not subject to tmap, but keys from |feedkeys()| are.
*E946*
@@ -234,7 +234,7 @@ In Terminal-Normal mode you can move the cursor around with the usual Vim
commands, Visually mark text, yank text, etc. But you cannot change the
contents of the buffer. The commands that would start insert mode, such as
'i' and 'a', return to Terminal-Job mode. The window will be updated to show
-the contents of the terminal.
+the contents of the terminal. |:startinsert| is ineffective.
In Terminal-Normal mode the statusline and window title show "(Terminal)". If
the job ends while in Terminal-Normal mode this changes to
@@ -372,6 +372,14 @@ In the window showing the source code some commands can used to control gdb:
:Finish execute the gdb "finish" command
:Continue execute the gdb "continue" command
+The plugin adds a window toolbar with these entries:
+ Step :Step
+ Next :Over
+ Finish :Finish
+ Cont :Continue
+ Eval :Evaluate
+This way you can use the mouse to perform the most common commands.
+
Inspecting variables ~
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index ffd53fa578..d23a883e7f 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -104,6 +104,11 @@ func s:StartDebug(cmd)
call win_gotoid(s:gdbwin)
let s:breakpoints = {}
+
+ augroup TermDebug
+ au BufRead * call s:BufRead()
+ au BufUnload * call s:BufUnloaded()
+ augroup END
endfunc
func s:EndDebug(job, status)
@@ -120,6 +125,8 @@ func s:EndDebug(job, status)
if s:save_columns > 0
let &columns = s:save_columns
endif
+
+ au! TermDebug
endfunc
" Handle a message received from gdb on the GDB/MI interface.
@@ -132,7 +139,7 @@ func s:CommOutput(chan, msg)
let msg = msg[1:]
endif
if msg != ''
- if msg =~ '^\*\(stopped\|running\)'
+ if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
call s:HandleCursor(msg)
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
call s:HandleNewBreakpoint(msg)
@@ -161,6 +168,14 @@ func s:InstallCommands()
" TODO: can the K mapping be restored?
nnoremap K :Evaluate<CR>
+
+ if has('menu')
+ amenu WinBar.Step :Step<CR>
+ amenu WinBar.Next :Over<CR>
+ amenu WinBar.Finish :Finish<CR>
+ amenu WinBar.Cont :Continue<CR>
+ amenu WinBar.Eval :Evaluate<CR>
+ endif
endfunc
" Delete installed debugger commands in the current window.
@@ -176,6 +191,15 @@ func s:DeleteCommands()
delcommand Program
nunmap K
+
+ if has('menu')
+ aunmenu WinBar.Step
+ aunmenu WinBar.Next
+ aunmenu WinBar.Finish
+ aunmenu WinBar.Cont
+ aunmenu WinBar.Eval
+ endif
+
exe 'sign unplace ' . s:pc_id
for key in keys(s:breakpoints)
exe 'sign unplace ' . (s:break_id + key)
@@ -232,7 +256,15 @@ endfunc
" Handle the result of data-evaluate-expression
func s:HandleEvaluate(msg)
- echomsg '"' . s:evalexpr . '": ' . substitute(a:msg, '.*value="\(.*\)"', '\1', '')
+ let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '')
+ let value = substitute(value, '\\"', '"', 'g')
+ echomsg '"' . s:evalexpr . '": ' . value
+
+ if s:evalexpr[0] != '*' && value =~ '^0x' && value !~ '"$'
+ " Looks like a pointer, also display what it points to.
+ let s:evalexpr = '*' . s:evalexpr
+ call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . s:evalexpr . "\"\r")
+ endif
endfunc
" Handle an error.
@@ -247,10 +279,10 @@ func s:HandleCursor(msg)
if win_gotoid(s:startwin)
let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
- if a:msg =~ '^\*stopped' && filereadable(fname)
+ if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$'
- if expand('%:h') != fname
+ if expand('%:p') != fnamemodify(fname, ':p')
if &modified
" TODO: find existing window
exe 'split ' . fnameescape(fname)
@@ -260,7 +292,7 @@ func s:HandleCursor(msg)
endif
endif
exe lnum
- exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
+ exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname
setlocal signcolumn=yes
endif
else
@@ -288,11 +320,17 @@ func s:HandleNewBreakpoint(msg)
let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
-
- exe 'sign place ' . (s:break_id + nr) . ' line=' . lnum . ' name=debugBreakpoint file=' . fnameescape(fname)
-
let entry['fname'] = fname
let entry['lnum'] = lnum
+
+ if bufloaded(fname)
+ call s:PlaceSign(nr, entry)
+ endif
+endfunc
+
+func s:PlaceSign(nr, entry)
+ exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname']
+ let a:entry['placed'] = 1
endfunc
" Handle deleting a breakpoint
@@ -302,6 +340,33 @@ func s:HandleBreakpointDelete(msg)
if nr == 0
return
endif
- exe 'sign unplace ' . (s:break_id + nr)
- unlet s:breakpoints[nr]
+ if has_key(s:breakpoints, nr)
+ let entry = s:breakpoints[nr]
+ if has_key(entry, 'placed')
+ exe 'sign unplace ' . (s:break_id + nr)
+ unlet entry['placed']
+ endif
+ unlet s:breakpoints[nr]
+ endif
endfunc
+
+" Handle a BufRead autocommand event: place any signs.
+func s:BufRead()
+ let fname = expand('<afile>:p')
+ for [nr, entry] in items(s:breakpoints)
+ if entry['fname'] == fname
+ call s:PlaceSign(nr, entry)
+ endif
+ endfor
+endfunc
+
+" Handle a BufUnloaded autocommand event: unplace any signs.
+func s:BufUnloaded()
+ let fname = expand('<afile>:p')
+ for [nr, entry] in items(s:breakpoints)
+ if entry['fname'] == fname
+ let entry['placed'] = 0
+ endif
+ endfor
+endfunc
+
diff --git a/src/Makefile b/src/Makefile
index 247fee6100..ad96784a6d 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 0d954a0ee1..8b1ceaea80 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 8d370d49a2..6c2a73e800 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 8936838137..d67645cd57 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 343a1b8ec5..1ad8a5cb90 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 a8b6ffa16d..6fffbcbc17 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 e370835845..bd3d26b92c 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 0f64ceaf8c..f6ecb8c491 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 d93ce50f3c..9f39edf04f 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 =