vim-denops / denops.vim

🐜 An ecosystem of Vim/Neovim which allows developers to write cross-platform plugins in Deno

Home Page:https://vim-denops.github.io/denops-documentation/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Some problems in Vim8/neovim

Shougo opened this issue · comments

  1. The cursor is flickered when use ddc.vim in Vim8. It seems when the popup window is displayed, the cursor will be hidden. I don't know why.

  2. The mode string in the echoarea is redrawn when the popup window is displayed in both Vim8 and neovim.

Minimal vimrc

if &compatible
  set nocompatible
endif

set runtimepath^=~/work/ddc.vim
set runtimepath^=~/work/ddc-around
set runtimepath^=~/work/ddc-matcher_head
set runtimepath^=~/work/ddc-sorter_rank
set runtimepath+=~/src/denops.vim

filetype plugin indent on
syntax enable

call ddc#custom#patch_global('sources', ['around'])
"call ddc#custom#patch_global('completionMode', 'inline')
"call ddc#custom#patch_global('completionMode', 'manual')
call ddc#custom#patch_global('sourceOptions', {
      \ '_': {
      \   'ignoreCase': v:true,
      \   'matchers': ['matcher_head'],
      \   'sorters': ['sorter_rank'],
      \ },
      \ 'around': {'mark': 'A'},
      \ })
call ddc#enable()

Both problems are not occurred in deoplete.

Could you make it without using ddc.vim?

@kuuote can reproduce it without ddc.vim...

It seems from complete() call in ddc.vim.
Without the function call, it is not reporuced.

The cursor problem is reduced by below config.

let &t_SI = "\<Esc>[6 q"
let &t_EI = "\<Esc>[0 q"

Both problems are not occurred in deoplete.

In deoplete, the cursor is not hidden when input.

Could you make it without using ddc.vim?

In Vim8, denops.vim hide the cursor without popup window.
It can be reproduced without ddc.vim.

@Shougo
Sorry, cause of the problem i was recognized was different to this.
Above problem was caused by redrawing in Vim

It's more likely issues on ddc.vim so close. Please feel free to re-open or re-create once the issue can reproduced without using ddc.vim

Really? OK. I will create the minimal example. Please wait.

denops/completion/app.ts

import { Denops } from "https://deno.land/x/denops_std@v1.0.0/mod.ts#^";
import * as autocmd from "https://deno.land/x/denops_std@v1.0.0/autocmd/mod.ts#^";

export async function main(denops: Denops) {
  denops.dispatcher = {
    async onEvent(_arg1: unknown): Promise<void> {
      denops.call("completion#complete");
    },
  };

  await autocmd.group(denops, "completion", (helper: autocmd.GroupHelper) => {
    helper.remove("*");
    for (
      const event of [
        "TextChangedI",
        "TextChangedP",
      ]
    ) {
      helper.define(
        event as autocmd.AutocmdEvent,
        "*",
        `call denops#notify('${denops.name}', 'onEvent', ["${event}"])`,
      );
    }
  });

  console.log(`${denops.name} has loaded`);
}

autoload/completion.vim

let s:root_dir = fnamemodify(expand('<sfile>'), ':h:h')

function! completion#enable() abort
  autocmd User DenopsReady call denops#plugin#register('completion',
        \ denops#util#join_path(s:root_dir, 'denops', 'completion', 'app.ts'))
endfunction

function! completion#complete() abort
  inoremap <silent> <Plug>_ <C-r>=completion#_complete()<CR>

  set completeopt-=longest
  set completeopt+=menuone
  set completeopt-=menu
  set completeopt+=noselect

  call feedkeys("\<Plug>_", 'i')
  return ''
endfunction

function! completion#_complete() abort
  if getline('.') =~ '\w\+$'
    call complete(1, ['foo', 'bar', 'baz'])
  else
    call complete(1, [])
  endif
  return ''
endfunction

Minimal vimrc

if &compatible
  set nocompatible
endif

set runtimepath+=~/src/denops.vim
set runtimepath+=~/src/denops-completion

call completion#enable()

You can reproduce the problems without ddc.vim.

I cloud reproduce 1. but 2. with above. I'll investigate 1. (but I've no idea at least for now)

  1. The cursor is flickered when use ddc.vim in Vim8. It seems when the popup window is displayed, the cursor will be hidden. I don't know why.

  2. The mode string in the echoarea is redrawn when the popup window is displayed in both Vim8 and neovim.

Not sure but the following fix cursor issue on my environment.

diff --git a/denops/completion/app.ts b/denops/completion/app.ts
index 5c106aa..0e0f977 100644
--- a/denops/completion/app.ts
+++ b/denops/completion/app.ts
@@ -4,7 +4,7 @@ import * as autocmd from "https://deno.land/x/denops_std@v1.0.0/autocmd/mod.ts#^
 export async function main(denops: Denops) {
   denops.dispatcher = {
     async onEvent(_arg1: unknown): Promise<void> {
-      denops.call("completion#complete");
+      await denops.call("completion#complete");
     },
   };
 
@@ -19,7 +19,7 @@ export async function main(denops: Denops) {
       helper.define(
         event as autocmd.AutocmdEvent,
         "*",
-        `call denops#notify('${denops.name}', 'onEvent', ["${event}"])`,
+        `call denops#request('${denops.name}', 'onEvent', ["${event}"])`,
       );
     }
   });

Using denops#notify means that you don't wait onEvent thus I guess onEvent calls pollute something?

import { Denops } from "https://deno.land/x/denops_std@v1.0.0/mod.ts#^";
import * as autocmd from "https://deno.land/x/denops_std@v1.0.0/autocmd/mod.ts#^";

const wait = async (ms) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, ms)
  });
}

export async function main(denops: Denops) {
  denops.dispatcher = {
    async onEvent(_arg1: unknown): Promise<void> {
      await wait(1000);
      await denops.call("completion#complete");
    },
  };

  await autocmd.group(denops, "completion", (helper: autocmd.GroupHelper) => {
    helper.remove("*");
    for (
      const event of [
        "TextChangedI",
        "TextChangedP",
      ]
    ) {
      helper.define(
        event as autocmd.AutocmdEvent,
        "*",
        `call denops#notify('${denops.name}', 'onEvent', ["${event}"])`,
      );
    }
  });

  console.log(`${denops.name} has loaded`);
}

Please test it.

let s:root_dir = fnamemodify(expand('<sfile>'), ':h:h')

function! completion#enable() abort
  autocmd User DenopsReady call denops#plugin#register('completion',
        \ denops#util#join_path(s:root_dir, 'denops', 'completion', 'app.ts'))
endfunction

function! completion#complete() abort
  inoremap <silent> <Plug>_ <C-r>=completion#_complete()<CR>

  set completeopt-=longest
  set completeopt+=menuone
  set completeopt-=menu
  set completeopt+=noselect

  call feedkeys("\<Plug>_", 'i')
  return ''
endfunction

function! completion#_complete() abort
  if getline('.') =~ '\w\+$' && getline('.') !~# 'date$'
    call complete(1, map(['foo', 'bar', 'baz'], { _, v -> {'word': v, 'equal': v:true}}))
  else
    call complete(1, [])
  endif
  return ''
endfunction

Please test it and input date date date ... quickly.

I could reproduce the issue on Vim but Neovim

Vim

I could reproduce "statusline flush" issue when I hit <Esc> to escape from insert mode.

Kapture.2021-08-07.at.15.21.40.mp4

Neovim

I could not reproduce "statuslie flush" issue (but Shougo said it might be a performance difference of the terminal).

Kapture.2021-08-07.at.15.20.41.mp4

Using denops#notify means that you don't wait onEvent thus I guess onEvent calls pollute something?

Probably this is the reason but ddc.vim use denops#notify on purpose. Using denops#request blocks thus.

The cursor is flickered when use ddc.vim in Vim8. It seems when the popup window is displayed, the cursor will be hidden. I don't know why.

The problem is fixed when I use denops#request() instead.

But

The mode string in the echoarea is redrawn when the popup window is displayed in both Vim8 and neovim.

Does not fix.

The cursor is flickered when use ddc.vim in Vim8. It seems when the popup window is displayed, the cursor will be hidden. I don't know why.

It is fixed after de-bounce.

The mode string in the echoarea is redrawn when the popup window is displayed in both Vim8 and neovim.

It is also reproduced in deoplete. It is less flicker though.

📝

This is the debounced version I suggested and solved.

let s:root_dir = fnamemodify(expand('<sfile>'), ':h:h')
let s:complete_timer = v:null

function! completion#enable() abort
  autocmd User DenopsReady call denops#plugin#register('completion',
        \ denops#util#join_path(s:root_dir, 'denops', 'completion', 'app.ts'))
endfunction

function! completion#complete() abort
  " デバウンス
  silent! call timer_stop(s:complete_timer)
  let s:complete_timer = timer_start(10, { -> completion#_complete() })
endfunction

function! completion#_complete() abort
  " 入力モードじゃない可能性もあるので...この辺の条件は知らないです
  if mode() !=# 'i'
    return
  endif
  set completeopt-=longest
  set completeopt+=menuone
  set completeopt-=menu
  set completeopt+=noselect
  if getline('.') =~ '\w\+$' && getline('.') !~# 'date$'
    call complete(1, map(['foo', 'bar', 'baz'], { _, v -> {'word': v, 'equal': v:true}}))
  else
    call complete(1, [])
  endif
endfunction