Browse Source

Support aliases (strictly).

It's porting of
591cb8fa11 in https://github.com/Shougo/ddc-nvim-lsp/pull/19.

If you alias this source to two or more names, the global environment
variable are conflicted.

Lua evaluation is exclusive, but `async` function in TypeScript may be
interrupted by other operations at right after the `await` statement.

`escapeVimAutoloadName` is for escaping Unicode sequences into vim
variable compatible names. eg:
  - `012abcABC` -> `012abcABC`
    - `lsp/ts` -> `lsp_47_ts`
      - `a-b_c` -> `a_45_b_95_c`

      Converting with escaping `_` to make this injective (=reversible).

And invocations of members of the source (eg: gatherCandidates) may be
shuffled after calling `ddc#refresh_candidates` because ddc.vim uses
`await` before calling them.
pull/9/head
Luma 3 years ago
parent
commit
3843ee9f94
  1. 12
      autoload/ddc_vim_lsp.vim
  2. 93
      denops/@ddc-sources/vim-lsp.ts

12
autoload/ddc_vim_lsp.vim

@ -1,4 +1,4 @@
function! ddc_vim_lsp#_callback(server, position, data) abort
function! ddc_vim_lsp#_callback(server, position, alias, data) abort
if lsp#client#is_error(a:data) || !has_key(a:data, 'response') || !has_key(a:data['response'], 'result')
return
endif
@ -9,16 +9,16 @@ function! ddc_vim_lsp#_callback(server, position, data) abort
\ 'response': a:data['response'],
\ }
let lspitems = lsp#omni#get_vim_completion_items(l:options)['items']
if len(lspitems) > 0
let g:ddc#source#ddc_vim_lsp#_results = lspitems
let g:ddc#source#ddc_vim_lsp#_requested = v:true
let g:ddc#source#ddc_vim_lsp#{a:alias}#_results = lspitems
let g:ddc#source#ddc_vim_lsp#{a:alias}#_requested = v:true
call ddc#refresh_candidates()
endif
endfunction
function! ddc_vim_lsp#request(server_name) abort
function! ddc_vim_lsp#request(server_name, alias) abort
let l:server = lsp#get_server_info(a:server_name)
let l:position = lsp#get_position()
@ -28,6 +28,6 @@ function! ddc_vim_lsp#request(server_name) abort
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'position': l:position,
\ },
\ 'on_notification': function('ddc_vim_lsp#_callback', [l:server, l:position]),
\ 'on_notification': function('ddc_vim_lsp#_callback', [l:server, l:position, a:alias]),
\ })
endfunction

93
denops/@ddc-sources/vim-lsp.ts

@ -3,58 +3,103 @@ import {
Candidate,
} from "https://deno.land/x/ddc_vim@v0.13.0/types.ts#^";
import { batch, vars } from "https://deno.land/x/ddc_vim@v0.13.0/deps.ts#^";
import {
batch,
Denops,
vars,
} from "https://deno.land/x/ddc_vim@v0.13.0/deps.ts#^";
GatherCandidatesArguments,
OnInitArguments,
} from "https://deno.land/x/ddc_vim@v0.13.0/base/source.ts#^";
// Vim funcname constraints can be found at :help E124.
// Leading numbers are allowed in autoload name.
const escapeVimAutoloadName = (name: string) => {
let escaped = "";
for (let i = 0; i < name.length; i++) {
if (name.charAt(i).match(/[a-zA-Z0-9]/)) escaped += name.charAt(i);
else escaped += `_${name.charCodeAt(i)}_`;
}
return escaped;
};
const escapeVimAutoloadNameCache = new Map<string, string>();
const escapeVimAutoloadNameCached = (name: string) => {
if (!escapeVimAutoloadNameCache.has(name)) {
escapeVimAutoloadNameCache.set(name, escapeVimAutoloadName(name));
}
return escapeVimAutoloadNameCache.get(name);
};
// deno-lint-ignore ban-types
type Params = {};
export class Source extends BaseSource {
async onInit(args: {
denops: Denops;
}): Promise<void> {
export class Source extends BaseSource<Params> {
async onInit(args: OnInitArguments<Params>): Promise<void> {
const escaped = escapeVimAutoloadNameCached(this.name);
await batch(args.denops, async (denops) => {
await vars.g.set(denops, "ddc#source#ddc_vim_lsp#_results", []);
await vars.g.set(denops, "ddc#source#ddc_vim_lsp#_requested", false);
await vars.g.set(denops, "ddc#source#ddc_vim_lsp#_prev_input", "");
await vars.g.set(
denops,
`ddc#source#ddc_vim_lsp#${escaped}#_results`,
[],
);
await vars.g.set(
denops,
`ddc#source#ddc_vim_lsp#${escaped}#_requested`,
false,
);
await vars.g.set(
denops,
`ddc#source#ddc_vim_lsp#${escaped}#_prev_input`,
"",
);
});
}
async gatherCandidates(args: {
denops: Denops;
context: Context;
completeStr: string;
}): Promise<Candidate[]> {
async gatherCandidates(
args: GatherCandidatesArguments<Params>,
): Promise<Candidate[]> {
const escaped = escapeVimAutoloadNameCached(this.name);
const prevInput = await vars.g.get(
args.denops,
"ddc#source#ddc_vim_lsp#_prev_input",
`ddc#source#ddc_vim_lsp#${escaped}#_prev_input`,
);
const requested = await vars.g.get(
args.denops,
"ddc#source#ddc_vim_lsp#_requested",
`ddc#source#ddc_vim_lsp#${escaped}#_requested`,
);
if (args.context.input == prevInput && requested) {
return await vars.g.get(args.denops, "ddc#source#ddc_vim_lsp#_results");
return await vars.g.get(
args.denops,
`ddc#source#ddc_vim_lsp#${escaped}#_results`,
// deno-lint-ignore no-explicit-any
) as any;
}
const lspservers = await args.denops.call("lsp#get_allowed_servers");
const lspservers: string[] = await args.denops.call(
"lsp#get_allowed_servers",
// deno-lint-ignore no-explicit-any
) as any;
if (lspservers.length === 0) {
return [];
}
await batch(args.denops, async (denops) => {
await vars.g.set(denops, "ddc#source#ddc_vim_lsp#_results", []);
await vars.g.set(denops, "ddc#source#ddc_vim_lsp#_requested", false);
await vars.g.set(
denops,
"ddc#source#ddc_vim_lsp#_prev_input",
`ddc#source#ddc_vim_lsp#${escaped}#_results`,
[],
);
await vars.g.set(
denops,
`ddc#source#ddc_vim_lsp#${escaped}#_requested`,
false,
);
await vars.g.set(
denops,
`ddc#source#ddc_vim_lsp#${escaped}#_prev_input`,
args.context.input,
);
// NOTE: choose first lsp server
await denops.call("ddc_vim_lsp#request", lspservers[0]);
await denops.call("ddc_vim_lsp#request", lspservers[0], escaped);
});
return [];

Loading…
Cancel
Save