mirror of
1
0
Fork 0
ultimate-vim/sources_non_forked/coc.nvim/src/__tests__/completion/language.test.ts

318 lines
12 KiB
TypeScript

import { Neovim } from '@chemzqm/neovim'
import { Disposable } from 'vscode-languageserver-protocol'
import { CompletionItem, CompletionList, InsertTextFormat, Position, Range, TextEdit } from 'vscode-languageserver-types'
import languages from '../../languages'
import { CompletionItemProvider } from '../../provider'
import snippetManager from '../../snippets/manager'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('language source', () => {
describe('additionalTextEdits', () => {
it('should fix cursor position with plain text on additionalTextEdits', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'foo',
filterText: 'foo',
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'a\nbar')]
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('if')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.waitFor('getline', ['.'], 'barfoo')
})
it('should fix cursor position with snippet on additionalTextEdits', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'if',
insertTextFormat: InsertTextFormat.Snippet,
textEdit: { range: Range.create(0, 0, 0, 1), newText: 'if($1)' },
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('ii')
await helper.waitPopup()
let res = await helper.getItems()
let idx = res.findIndex(o => o.menu == '[edit]')
await helper.selectCompleteItem(idx)
await helper.waitFor('col', ['.'], 8)
})
it('should fix cursor position with plain text snippet on additionalTextEdits', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'if',
insertTextFormat: InsertTextFormat.Snippet,
textEdit: { range: Range.create(0, 0, 0, 2), newText: 'do$0' },
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('iif')
await helper.waitPopup()
let items = await helper.getItems()
let idx = items.findIndex(o => o.word == 'do' && o.menu == '[edit]')
await helper.selectCompleteItem(idx)
await helper.waitFor('getline', ['.'], 'bar do')
await helper.waitFor('col', ['.'], 7)
})
it('should fix cursor position with nested snippet on additionalTextEdits', async () => {
let res = await snippetManager.insertSnippet('func($1)$0')
expect(res).toBe(true)
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'if',
insertTextFormat: InsertTextFormat.Snippet,
insertText: 'do$0',
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('if')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.waitFor('getline', ['.'], 'bar func(do)')
let [, lnum, col] = await nvim.call('getcurpos')
expect(lnum).toBe(1)
expect(col).toBe(12)
})
it('should fix cursor position and keep placeholder with snippet on additionalTextEdits', async () => {
let text = 'foo0bar1'
await nvim.setLine(text)
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'var',
insertTextFormat: InsertTextFormat.Snippet,
textEdit: { range: Range.create(0, text.length + 1, 0, text.length + 1), newText: '${1:foo} = foo0bar1' },
additionalTextEdits: [TextEdit.del(Range.create(0, 0, 0, text.length + 1))],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.']))
await nvim.input('A.')
await helper.waitPopup()
let res = await helper.getItems()
let idx = res.findIndex(o => o.menu == '[edit]')
await helper.selectCompleteItem(idx)
await helper.waitFor('getline', ['.'], 'foo = foo0bar1')
await helper.wait(50)
expect(snippetManager.session).toBeDefined()
let [, lnum, col] = await nvim.call('getcurpos')
expect(lnum).toBe(1)
expect(col).toBe(3)
})
it('should cancel current snippet session when additionalTextEdits inside snippet', async () => {
await nvim.input('i')
await snippetManager.insertSnippet('foo($1, $2)$0', true)
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'bar',
insertTextFormat: InsertTextFormat.Snippet,
textEdit: { range: Range.create(0, 4, 0, 5), newText: 'bar($1)' },
additionalTextEdits: [TextEdit.del(Range.create(0, 0, 0, 3))]
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.']))
await nvim.input('b')
await helper.waitPopup()
let res = await helper.getItems()
let idx = res.findIndex(o => o.menu == '[edit]')
await helper.selectCompleteItem(idx)
await helper.waitFor('getline', ['.'], '(bar(), )')
let col = await nvim.call('col', ['.'])
expect(col).toBe(6)
})
})
describe('filterText', () => {
it('should fix input for snippet item', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'foo',
filterText: 'foo',
insertText: '${1:foo}($2)',
insertTextFormat: InsertTextFormat.Snippet,
}]
}
disposables.push(languages.registerCompletionItemProvider('snippets-test', 'st', null, provider))
await nvim.input('if')
await helper.waitPopup()
await nvim.input('<C-n>')
await helper.waitFor('getline', ['.'], 'foo')
})
it('should fix filterText of complete item', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'name',
sortText: '11',
textEdit: {
range: Range.create(0, 1, 0, 2),
newText: '?.name'
}
}]
}
disposables.push(languages.registerCompletionItemProvider('name', 'N', null, provider, ['.']))
await nvim.setLine('t')
await nvim.input('A.')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.waitFor('getline', ['.'], 't?.name')
})
})
describe('inComplete result', () => {
it('should filter in complete request', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (doc, pos, token, context): Promise<CompletionList> => {
let option = (context as any).option
if (context.triggerCharacter == '.') {
return {
isIncomplete: true,
items: [
{
label: 'foo'
}, {
label: 'bar'
}
]
}
}
if (option.input == 'f') {
if (token.isCancellationRequested) return
return {
isIncomplete: true,
items: [
{
label: 'foo'
}
]
}
}
if (option.input == 'fo') {
if (token.isCancellationRequested) return
return {
isIncomplete: false,
items: [
{
label: 'foo'
}
]
}
}
}
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.']))
await nvim.input('i.')
await helper.waitPopup()
await nvim.input('fo')
await helper.wait(50)
let res = await helper.getItems()
expect(res.length).toBe(1)
})
})
describe('textEdit', () => {
it('should fix bad range', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'foo',
filterText: 'foo',
textEdit: { range: Range.create(0, 0, 0, 0), newText: 'foo' },
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('if')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.waitFor('getline', ['.'], 'foo')
})
it('should applyEdits for empty word', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: '',
filterText: '!',
textEdit: { range: Range.create(0, 0, 0, 1), newText: 'foo' },
data: { word: '' }
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['!']))
await nvim.input('i!')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.waitFor('getline', ['.'], 'foo')
})
it('should provide word when textEdit after startcol', async () => {
// some LS would send textEdit after first character,
// need fix the word from newText
let provider: CompletionItemProvider = {
provideCompletionItems: async (_, position): Promise<CompletionItem[]> => {
if (position.line != 0) return null
return [{
label: 'bar',
filterText: 'ar',
textEdit: {
range: Range.create(0, 1, 0, 1),
newText: 'ar'
}
}]
}
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('ib')
await helper.waitPopup()
let context = await nvim.getVar('coc#_context') as any
expect(context.start).toBe(1)
expect(context.candidates[0].word).toBe('ar')
})
it('should adjust completion position by textEdit start position', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (_document, _position, _token, context): Promise<CompletionItem[]> => {
if (!context.triggerCharacter) return
return [{
label: 'foo',
textEdit: {
range: Range.create(0, 0, 0, 1),
newText: '?foo'
}
}]
}
}
disposables.push(languages.registerCompletionItemProvider('fix', 'f', null, provider, ['?']))
await nvim.input('i?')
await helper.waitPopup()
await nvim.eval('feedkeys("\\<C-n>", "in")')
await helper.waitFor('getline', ['.'], '?foo')
})
})
})