Merge #6917 'UIEnter, UILeave'

This commit is contained in:
Justin M. Keyes 2019-09-12 17:45:33 -07:00 committed by GitHub
commit 3855204f58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 141 additions and 96 deletions

View File

@ -280,8 +280,8 @@ Name triggered by ~
Startup and exit Startup and exit
|VimEnter| after doing all the startup stuff |VimEnter| after doing all the startup stuff
|GUIEnter| after starting the GUI successfully |UIEnter| after a UI attaches
|GUIFailed| after starting the GUI failed |UILeave| after a UI detaches
|TermResponse| after the terminal response to t_RV is received |TermResponse| after the terminal response to t_RV is received
|QuitPre| when using `:quit`, before deciding whether to exit |QuitPre| when using `:quit`, before deciding whether to exit
|ExitPre| when using a command that may make Vim exit |ExitPre| when using a command that may make Vim exit
@ -805,19 +805,17 @@ FuncUndefined When a user function is used but it isn't
NOTE: When writing Vim scripts a better NOTE: When writing Vim scripts a better
alternative is to use an autoloaded function. alternative is to use an autoloaded function.
See |autoload-functions|. See |autoload-functions|.
*GUIEnter* *UIEnter*
GUIEnter After starting the GUI successfully, and after UIEnter After a UI connects via |nvim_ui_attach()|,
opening the window. It is triggered before after VimEnter. Can be used for GUI-specific
VimEnter when using gvim. Can be used to configuration.
position the window from a gvimrc file: > Sets these |v:event| keys:
:autocmd GUIEnter * winpos 100 50 chan
< *GUIFailed* *UILeave*
GUIFailed After starting the GUI failed. Vim may UILeave After a UI disconnects from Nvim.
continue to run in the terminal, if possible Sets these |v:event| keys:
(only on Unix and alikes, when connecting the chan
X server fails). You may want to quit Vim: > *InsertChange*
:autocmd GUIFailed * qall
< *InsertChange*
InsertChange When typing <Insert> while in Insert or InsertChange When typing <Insert> while in Insert or
Replace mode. The |v:insertmode| variable Replace mode. The |v:insertmode| variable
indicates the new mode. indicates the new mode.

View File

@ -28,6 +28,8 @@ Environment Variables ~
Events ~ Events ~
*EncodingChanged* Never fired; 'encoding' is always "utf-8". *EncodingChanged* Never fired; 'encoding' is always "utf-8".
*FileEncoding* Never fired; equivalent to |EncodingChanged|. *FileEncoding* Never fired; equivalent to |EncodingChanged|.
*GUIEnter* Never fired; use |UIEnter| instead.
*GUIFailed* Never fired.
Keycodes ~ Keycodes ~
*<MouseDown>* Use <ScrollWheelUp> instead. *<MouseDown>* Use <ScrollWheelUp> instead.

View File

@ -1567,6 +1567,7 @@ v:event Dictionary of event data for the current |autocommand|. Valid
abort Whether the event triggered during abort Whether the event triggered during
an aborting condition (e.g. |c_Esc| or an aborting condition (e.g. |c_Esc| or
|c_CTRL-C| for |CmdlineLeave|). |c_CTRL-C| for |CmdlineLeave|).
chan |channel-id| or 0 for "internal".
cmdlevel Level of cmdline. cmdlevel Level of cmdline.
cmdtype Type of cmdline, |cmdline-char|. cmdtype Type of cmdline, |cmdline-char|.
cwd Current working directory. cwd Current working directory.

View File

@ -4,7 +4,7 @@
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
Vim's Graphical User Interface *gui* *GUI* Nvim Graphical User Interface *gui* *GUI*
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
@ -12,30 +12,11 @@ Vim's Graphical User Interface *gui* *GUI*
Starting the GUI *gui-start* *E229* *E233* Starting the GUI *gui-start* *E229* *E233*
*ginit.vim* *gui-init* *gvimrc* *$MYGVIMRC* *ginit.vim* *gui-init* *gvimrc* *$MYGVIMRC*
The gvimrc file is where GUI-specific startup commands should be placed. It For GUI-specific configuration Nvim provides the |UIEnter| event. This
is always sourced after the |init.vim| file. If you have one then the happens after other |initialization|s, like reading your vimrc file.
$MYGVIMRC environment variable has its name.
When the GUI starts up initializations are carried out, in this order: Example: this sets "g:gui" to the value of the UI's "rgb" field: >
- If the system menu file exists, it is sourced. The name of this file is :autocmd UIEnter * let g:gui = filter(nvim_list_uis(),{k,v-> v.chan==v:event.chan})[0].rgb
normally "$VIMRUNTIME/menu.vim". You can check this with ":version". Also
see |$VIMRUNTIME|. To skip loading the system menu include 'M' in
'guioptions'. *buffers-menu* *no_buffers_menu*
The system menu file includes a "Buffers" menu. If you don't want this, set
the "no_buffers_menu" variable in your init.vim (not ginit.vim!): >
:let no_buffers_menu = 1
< NOTE: Switching on syntax highlighting also loads the menu file, thus
disabling the Buffers menu must be done before ":syntax on".
The path names are truncated to 35 characters. You can truncate them at a
different length, for example 50, like this: >
:let bmenu_max_pathlen = 50
All this happens AFTER the normal Vim initializations, like reading your
vimrc file. See |initialization|.
But the GUI window is only opened after all the initializations have been
carried out. If you want some commands to be executed just after opening the
GUI window, use the |GUIEnter| autocommand event. Example: >
:autocmd GUIEnter * winpos 100 50
< <
*:winp* *:winpos* *E188* *:winp* *:winpos* *E188*

View File

@ -236,35 +236,6 @@ using the terminal for something else. The "-f" argument is used here to run
the GUI in the foreground. You can also use ":gui -f". the GUI in the foreground. You can also use ":gui -f".
THE GVIM STARTUP FILE
When gvim starts, it reads the gvimrc file. That's similar to the vimrc file
used when starting Vim. The gvimrc file can be used for settings and commands
that are only to be used when the GUI is going to be started. For example,
you can set the 'lines' option to set a different window size: >
:set lines=55
You don't want to do this in a terminal, since its size is fixed (except for
an xterm that supports resizing).
The gvimrc file is searched for in the same locations as the vimrc file.
Normally its name is "~/.config/nvim/ginit.vim".
The $MYGVIMRC environment variable is set to it, thus you can use this command
to edit the file, if you have one: >
:edit $MYGVIMRC
<
If for some reason you don't want to use the normal gvimrc file, you can
specify another one with the "-U" argument: >
gvim -U thisrc ...
That allows starting gvim for different kinds of editing. You could set
another font size, for example.
To completely skip reading a gvimrc file: >
gvim -U NONE ...
============================================================================== ==============================================================================
Next chapter: |usr_32.txt| The undo tree Next chapter: |usr_32.txt| The undo tree

View File

@ -154,6 +154,8 @@ Events:
|TermClose| |TermClose|
|TermOpen| |TermOpen|
|TextYankPost| |TextYankPost|
|UIEnter|
|UILeave|
|VimResume| |VimResume|
|VimSuspend| |VimSuspend|

View File

@ -57,7 +57,7 @@ void remote_ui_disconnect(uint64_t channel_id)
pmap_del(uint64_t)(connected_uis, channel_id); pmap_del(uint64_t)(connected_uis, channel_id);
xfree(ui->data); xfree(ui->data);
ui->data = NULL; // Flag UI as "stopped". ui->data = NULL; // Flag UI as "stopped".
ui_detach_impl(ui); ui_detach_impl(ui, channel_id);
xfree(ui); xfree(ui);
} }
@ -168,7 +168,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->data = data; ui->data = data;
pmap_put(uint64_t)(connected_uis, channel_id, ui); pmap_put(uint64_t)(connected_uis, channel_id, ui);
ui_attach_impl(ui); ui_attach_impl(ui, channel_id);
} }
/// @deprecated /// @deprecated

View File

@ -7,11 +7,32 @@
#include "nvim/main.h" #include "nvim/main.h"
#include "nvim/ui.h" #include "nvim/ui.h"
#include "nvim/aucmd.h" #include "nvim/aucmd.h"
#include "nvim/eval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "aucmd.c.generated.h" # include "aucmd.c.generated.h"
#endif #endif
void do_autocmd_uienter(uint64_t chanid, bool attached)
{
static bool recursive = false;
if (recursive) {
return; // disallow recursion
}
recursive = true;
dict_T *dict = get_vim_var_dict(VV_EVENT);
assert(chanid < VARNUMBER_MAX);
tv_dict_add_nr(dict, S_LEN("chan"), (varnumber_T)chanid);
tv_dict_set_keys_readonly(dict);
apply_autocmds(attached ? EVENT_UIENTER : EVENT_UILEAVE,
NULL, NULL, false, curbuf);
tv_dict_clear(dict);
recursive = false;
}
static void focusgained_event(void **argv) static void focusgained_event(void **argv)
{ {
bool *gainedp = argv[0]; bool *gainedp = argv[0];
@ -38,4 +59,3 @@ static void do_autocmd_focusgained(bool gained)
NULL, NULL, false, curbuf); NULL, NULL, false, curbuf);
recursive = false; recursive = false;
} }

View File

@ -1,6 +1,8 @@
#ifndef NVIM_AUCMD_H #ifndef NVIM_AUCMD_H
#define NVIM_AUCMD_H #define NVIM_AUCMD_H
#include <stdint.h>
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "aucmd.h.generated.h" # include "aucmd.h.generated.h"
#endif #endif

View File

@ -96,6 +96,8 @@ return {
'TextChangedI', -- text was modified in Insert mode(no popup) 'TextChangedI', -- text was modified in Insert mode(no popup)
'TextChangedP', -- text was modified in Insert mode(popup) 'TextChangedP', -- text was modified in Insert mode(popup)
'TextYankPost', -- after a yank or delete was done (y, d, c) 'TextYankPost', -- after a yank or delete was done (y, d, c)
'UIEnter', -- after UI attaches
'UILeave', -- after UI detaches
'User', -- user defined autocommand 'User', -- user defined autocommand
'VimEnter', -- after starting Vim 'VimEnter', -- after starting Vim
'VimLeave', -- before exiting Vim 'VimLeave', -- before exiting Vim
@ -123,5 +125,7 @@ return {
TabNewEntered=true, TabNewEntered=true,
TermClose=true, TermClose=true,
TermOpen=true, TermOpen=true,
UIEnter=true,
UILeave=true,
}, },
} }

View File

@ -172,6 +172,7 @@ static Channel *channel_alloc(ChannelStreamType type)
chan->refcount = 1; chan->refcount = 1;
chan->exit_status = -1; chan->exit_status = -1;
chan->streamtype = type; chan->streamtype = type;
assert(chan->id <= VARNUMBER_MAX);
pmap_put(uint64_t)(channels, chan->id, chan); pmap_put(uint64_t)(channels, chan->id, chan);
return chan; return chan;
} }
@ -190,6 +191,7 @@ void channel_create_event(Channel *chan, const char *ext_source)
source = (const char *)IObuff; source = (const char *)IObuff;
} }
assert(chan->id <= VARNUMBER_MAX);
Dictionary info = channel_info(chan->id); Dictionary info = channel_info(chan->id);
typval_T tv = TV_INITIAL_VALUE; typval_T tv = TV_INITIAL_VALUE;
// TODO(bfredl): do the conversion in one step. Also would be nice // TODO(bfredl): do the conversion in one step. Also would be nice

View File

@ -3111,8 +3111,6 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
} }
if (is_vimrc == DOSO_VIMRC) { if (is_vimrc == DOSO_VIMRC) {
vimrc_found(fname_exp, (char_u *)"MYVIMRC"); vimrc_found(fname_exp, (char_u *)"MYVIMRC");
} else if (is_vimrc == DOSO_GVIMRC) {
vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
} }
#ifdef USE_CRNL #ifdef USE_CRNL

View File

@ -7,19 +7,18 @@
typedef void (*DoInRuntimepathCB)(char_u *, void *); typedef void (*DoInRuntimepathCB)(char_u *, void *);
/* //
* flags for check_changed() // flags for check_changed()
*/ //
#define CCGD_AW 1 /* do autowrite if buffer was changed */ #define CCGD_AW 1 // do autowrite if buffer was changed
#define CCGD_MULTWIN 2 /* check also when several wins for the buf */ #define CCGD_MULTWIN 2 // check also when several wins for the buf
#define CCGD_FORCEIT 4 /* ! used */ #define CCGD_FORCEIT 4 // ! used
#define CCGD_ALLBUF 8 /* may write all buffers */ #define CCGD_ALLBUF 8 // may write all buffers
#define CCGD_EXCMD 16 /* may suggest using ! */ #define CCGD_EXCMD 16 // may suggest using !
/* last argument for do_source() */ // last argument for do_source()
#define DOSO_NONE 0 #define DOSO_NONE 0
#define DOSO_VIMRC 1 /* loading vimrc file */ #define DOSO_VIMRC 1 // loading vimrc file
#define DOSO_GVIMRC 2 /* loading gvimrc file */
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds2.h.generated.h" # include "ex_cmds2.h.generated.h"

View File

@ -12,6 +12,7 @@
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/main.h" #include "nvim/main.h"
#include "nvim/aucmd.h"
#include "nvim/buffer.h" #include "nvim/buffer.h"
#include "nvim/charset.h" #include "nvim/charset.h"
#include "nvim/diff.h" #include "nvim/diff.h"
@ -351,7 +352,7 @@ int main(int argc, char **argv)
bool use_remote_ui = (embedded_mode && !headless_mode); bool use_remote_ui = (embedded_mode && !headless_mode);
bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode); bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode);
if (use_remote_ui || use_builtin_ui) { if (use_remote_ui || use_builtin_ui) {
TIME_MSG("waiting for UI to make request"); TIME_MSG("waiting for UI");
if (use_remote_ui) { if (use_remote_ui) {
remote_ui_wait_for_attach(); remote_ui_wait_for_attach();
} else { } else {
@ -537,6 +538,10 @@ int main(int argc, char **argv)
set_vim_var_nr(VV_VIM_DID_ENTER, 1L); set_vim_var_nr(VV_VIM_DID_ENTER, 1L);
apply_autocmds(EVENT_VIMENTER, NULL, NULL, false, curbuf); apply_autocmds(EVENT_VIMENTER, NULL, NULL, false, curbuf);
TIME_MSG("VimEnter autocommands"); TIME_MSG("VimEnter autocommands");
if (use_remote_ui || use_builtin_ui) {
do_autocmd_uienter(use_remote_ui ? CHAN_STDIO : 0, true);
TIME_MSG("UIEnter autocommands");
}
// Adjust default register name for "unnamed" in 'clipboard'. Can only be // Adjust default register name for "unnamed" in 'clipboard'. Can only be
// done after the clipboard is available and all initial commands that may // done after the clipboard is available and all initial commands that may

View File

@ -9,6 +9,7 @@
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/log.h" #include "nvim/log.h"
#include "nvim/aucmd.h"
#include "nvim/ui.h" #include "nvim/ui.h"
#include "nvim/charset.h" #include "nvim/charset.h"
#include "nvim/cursor.h" #include "nvim/cursor.h"
@ -268,7 +269,7 @@ void ui_busy_stop(void)
} }
} }
void ui_attach_impl(UI *ui) void ui_attach_impl(UI *ui, uint64_t chanid)
{ {
if (ui_count == MAX_UI_COUNT) { if (ui_count == MAX_UI_COUNT) {
abort(); abort();
@ -292,9 +293,14 @@ void ui_attach_impl(UI *ui)
ui_send_all_hls(ui); ui_send_all_hls(ui);
} }
ui_refresh(); ui_refresh();
bool is_compositor = (ui == uis[0]);
if (!is_compositor) {
do_autocmd_uienter(chanid, true);
}
} }
void ui_detach_impl(UI *ui) void ui_detach_impl(UI *ui, uint64_t chanid)
{ {
size_t shift_index = MAX_UI_COUNT; size_t shift_index = MAX_UI_COUNT;
@ -326,6 +332,8 @@ void ui_detach_impl(UI *ui)
if (!ui->ui_ext[kUIMultigrid] && !ui->ui_ext[kUIFloatDebug]) { if (!ui->ui_ext[kUIMultigrid] && !ui->ui_ext[kUIFloatDebug]) {
ui_comp_detach(ui); ui_comp_detach(ui);
} }
do_autocmd_uienter(chanid, false);
} }
void ui_set_ext_option(UI *ui, UIExtension ext, bool active) void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
@ -476,9 +484,7 @@ Array ui_array(void)
PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j])); PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j]));
} }
} }
if (ui->inspect) { ui->inspect(ui, &info);
ui->inspect(ui, &info);
}
ADD(all_uis, DICTIONARY_OBJ(info)); ADD(all_uis, DICTIONARY_OBJ(info));
} }
return all_uis; return all_uis;

View File

@ -63,6 +63,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.set_icon = ui_bridge_set_icon; rv->bridge.set_icon = ui_bridge_set_icon;
rv->bridge.option_set = ui_bridge_option_set; rv->bridge.option_set = ui_bridge_option_set;
rv->bridge.raw_line = ui_bridge_raw_line; rv->bridge.raw_line = ui_bridge_raw_line;
rv->bridge.inspect = ui_bridge_inspect;
rv->scheduler = scheduler; rv->scheduler = scheduler;
for (UIExtension i = 0; (int)i < kUIExtCount; i++) { for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
@ -85,7 +86,8 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
} }
uv_mutex_unlock(&rv->mutex); uv_mutex_unlock(&rv->mutex);
ui_attach_impl(&rv->bridge); ui_attach_impl(&rv->bridge, 0);
return &rv->bridge; return &rv->bridge;
} }
@ -106,7 +108,8 @@ static void ui_bridge_stop(UI *b)
{ {
// Detach bridge first, so that "stop" is the last event the TUI loop // Detach bridge first, so that "stop" is the last event the TUI loop
// receives from the main thread. #8041 // receives from the main thread. #8041
ui_detach_impl(b); ui_detach_impl(b, 0);
UIBridgeData *bridge = (UIBridgeData *)b; UIBridgeData *bridge = (UIBridgeData *)b;
bool stopped = bridge->stopped = false; bool stopped = bridge->stopped = false;
UI_BRIDGE_CALL(b, stop, 1, b); UI_BRIDGE_CALL(b, stop, 1, b);
@ -213,3 +216,8 @@ static void ui_bridge_option_set_event(void **argv)
api_free_object(value); api_free_object(value);
xfree(argv[3]); xfree(argv[3]);
} }
static void ui_bridge_inspect(UI *ui, Dictionary *info)
{
PUT(*info, "chan", INTEGER_OBJ(0));
}

View File

@ -83,7 +83,7 @@ void ui_comp_init(void)
kv_push(layers, &default_grid); kv_push(layers, &default_grid);
curgrid = &default_grid; curgrid = &default_grid;
ui_attach_impl(compositor); ui_attach_impl(compositor, 0);
} }
void ui_comp_syn_init(void) void ui_comp_syn_init(void)

View File

@ -35,3 +35,24 @@ describe('nvim_ui_attach()', function()
pcall_err(request, 'nvim_ui_attach', 40, 10, { rgb=false })) pcall_err(request, 'nvim_ui_attach', 40, 10, { rgb=false }))
end) end)
end) end)
it('autocmds UIEnter/UILeave', function()
clear{
args_rm={'--headless'},
args={
'--cmd', 'let g:evs = []',
'--cmd', 'autocmd UIEnter * :call add(g:evs, "UIEnter") | let g:uienter_ev = deepcopy(v:event)',
'--cmd', 'autocmd UILeave * :call add(g:evs, "UILeave") | let g:uileave_ev = deepcopy(v:event)',
'--cmd', 'autocmd VimEnter * :call add(g:evs, "VimEnter")',
}}
local screen = Screen.new()
screen:attach()
eq({chan=1}, eval('g:uienter_ev'))
screen:detach()
eq({chan=1}, eval('g:uileave_ev'))
eq({
'VimEnter',
'UIEnter',
'UILeave',
}, eval('g:evs'))
end)

View File

@ -721,8 +721,8 @@ describe('TUI', function()
| |
{4:~ }| {4:~ }|
{5: }| {5: }|
[[['height', 6], ['override', v:false], ['rgb', v:| [[['chan', 0], ['height', 6], ['override', v:false|
false], ['width', 50]]] | ], ['rgb', v:false], ['width', 50]]] |
{10:Press ENTER or type command to continue}{1: } | {10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]=]) ]=])
@ -767,11 +767,36 @@ describe('TUI', function()
end) end)
end) end)
describe('TUI UIEnter/UILeave', function()
it('fires exactly once, after VimEnter', function()
clear()
local screen = thelpers.screen_setup(0,
'["'..nvim_prog..'", "-u", "NONE", "-i", "NONE"'
..[[, "--cmd", "set noswapfile noshowcmd noruler"]]
..[[, "--cmd", "let g:evs = []"]]
..[[, "--cmd", "autocmd UIEnter * :call add(g:evs, 'UIEnter')"]]
..[[, "--cmd", "autocmd UILeave * :call add(g:evs, 'UILeave')"]]
..[[, "--cmd", "autocmd VimEnter * :call add(g:evs, 'VimEnter')"]]
..']'
)
feed_data(":echo g:evs\n")
screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
['VimEnter', 'UIEnter'] |
{3:-- TERMINAL --} |
]]}
end)
end)
describe('TUI FocusGained/FocusLost', function() describe('TUI FocusGained/FocusLost', function()
local screen local screen
before_each(function() before_each(function()
helpers.clear() clear()
screen = thelpers.screen_setup(0, '["'..nvim_prog screen = thelpers.screen_setup(0, '["'..nvim_prog
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]')
feed_data(":autocmd FocusGained * echo 'gained'\n") feed_data(":autocmd FocusGained * echo 'gained'\n")