import { Neovim } from '@chemzqm/neovim' import path from 'path' import manager from '../../list/manager' import events from '../../events' import { QuickfixItem, IList, ListItem } from '../../types' import helper from '../helper' let nvim: Neovim const locations: ReadonlyArray = [{ filename: __filename, col: 2, lnum: 1, text: 'foo' }, { filename: __filename, col: 1, lnum: 2, text: 'Bar' }, { filename: __filename, col: 1, lnum: 3, text: 'option' }] beforeAll(async () => { await helper.setup() nvim = helper.nvim await nvim.setVar('coc_jump_locations', locations) }) afterEach(async () => { manager.reset() await helper.reset() }) afterAll(async () => { await helper.shutdown() }) describe('list', () => { describe('events', () => { it('should cancel and enable prompt', async () => { let winid = await nvim.call('win_getid') await manager.start(['location']) await manager.session.ui.ready await nvim.call('win_gotoid', [winid]) await helper.wait(50) let res = await nvim.call('coc#prompt#activated') expect(res).toBe(0) await nvim.command('wincmd p') await helper.wait(50) res = await nvim.call('coc#prompt#activated') expect(res).toBe(1) }) }) describe('list commands', () => { it('should be activated', async () => { await manager.start(['location']) await manager.session.ui.ready await helper.wait(50) expect(manager.isActivated).toBe(true) let line = await nvim.getLine() expect(line).toMatch(/manager.test.ts/) }) it('should get list names', () => { let names = manager.names expect(names.length > 0).toBe(true) }) it('should resume list', async () => { await manager.start(['--normal', 'location']) await manager.session.ui.ready await helper.wait(30) await nvim.eval('feedkeys("j", "in")') await helper.wait(30) let line = await nvim.call('line', '.') expect(line).toBe(2) await manager.cancel() await helper.wait(30) await manager.resume() await helper.wait(30) line = await nvim.call('line', '.') expect(line).toBe(2) }) it('should not quit list with --no-quit', async () => { await manager.start(['--normal', '--no-quit', 'location']) await manager.session.ui.ready let winnr = await nvim.eval('win_getid()') as number await manager.doAction() await helper.wait(100) let wins = await nvim.windows let ids = wins.map(o => o.id) expect(ids).toContain(winnr) }) it('should do default action for first item', async () => { await manager.start(['--normal', '--first', 'location']) await helper.wait(300) let name = await nvim.eval('bufname("%")') as string let filename = path.basename(__filename) expect(name.includes(filename)).toBe(true) let pos = await nvim.eval('getcurpos()') expect(pos[1]).toBe(1) expect(pos[2]).toBe(2) }) it('should goto next & previous', async () => { await manager.start(['location']) await manager.session?.ui.ready await helper.wait(60) await manager.doAction() await manager.cancel() let bufname = await nvim.eval('expand("%:p")') expect(bufname).toMatch('manager.test.ts') await manager.next() let line = await nvim.call('line', '.') expect(line).toBe(2) await helper.wait(60) await manager.previous() line = await nvim.call('line', '.') expect(line).toBe(1) }) it('should parse arguments', async () => { await manager.start(['--input=test', '--reverse', '--normal', '--no-sort', '--ignore-case', '--top', '--number-select', '--auto-preview', '--strict', 'location']) await helper.wait(30) let opts = manager.session?.listOptions expect(opts).toEqual({ reverse: true, numberSelect: true, autoPreview: true, first: false, input: 'test', interactive: false, matcher: 'strict', ignorecase: true, position: 'top', mode: 'normal', noQuit: false, sort: false }) }) }) describe('list configuration', () => { it('should change indicator', async () => { helper.updateConfiguration('list.indicator', '>>') await manager.start(['location']) await manager.session.ui.ready await helper.wait(200) let line = await helper.getCmdline() expect(line).toMatch('>>') }) it('should split right for preview window', async () => { helper.updateConfiguration('list.previewSplitRight', true) let win = await nvim.window await manager.start(['location']) await helper.wait(100) await manager.doAction('preview') await helper.wait(100) manager.prompt.cancel() await helper.wait(10) await nvim.call('win_gotoid', [win.id]) await nvim.command('wincmd l') let curr = await nvim.window let isPreview = await curr.getVar('previewwindow') expect(isPreview).toBe(1) }) it('should toggle selection mode', async () => { await manager.start(['--normal', 'location']) await manager.session?.ui.ready await nvim.input('V') await helper.wait(30) await nvim.input('1') await helper.wait(30) await nvim.input('j') await helper.wait(100) await manager.session?.ui.toggleSelection() let items = await manager.session?.ui.getItems() expect(items.length).toBe(2) }) it('should change next/previous keymap', async () => { helper.updateConfiguration('list.nextKeymap', '') helper.updateConfiguration('list.previousKeymap', '') await manager.start(['location']) await manager.session.ui.ready await helper.wait(100) await nvim.eval('feedkeys("\\", "in")') await helper.wait(100) let line = await nvim.line expect(line).toMatch('Bar') await nvim.eval('feedkeys("\\", "in")') await helper.wait(100) line = await nvim.line expect(line).toMatch('foo') }) it('should respect mouse events', async () => { async function setMouseEvent(line: number): Promise { let winid = manager.session?.ui.winid await nvim.command(`let v:mouse_winid = ${winid}`) await nvim.command(`let v:mouse_lnum = ${line}`) await nvim.command(`let v:mouse_col = 1`) } await manager.start(['--normal', 'location']) await manager.session.ui.ready await helper.wait(100) await setMouseEvent(1) await manager.onNormalInput('') await setMouseEvent(2) await manager.onNormalInput('') await setMouseEvent(3) await manager.onNormalInput('') await helper.wait(100) let items = await manager.session?.ui.getItems() expect(items.length).toBe(3) }) it('should toggle preview', async () => { await manager.start(['--normal', '--auto-preview', 'location']) await manager.session.ui.ready await helper.wait(100) await manager.togglePreview() await helper.wait(100) await manager.togglePreview() await helper.wait(100) let has = await nvim.call('coc#list#has_preview') expect(has).toBeGreaterThan(0) }) it('should show help of current list', async () => { await manager.start(['--normal', '--auto-preview', 'location']) await helper.wait(200) await manager.session?.showHelp() let bufname = await nvim.call('bufname', '%') expect(bufname).toBe('[LIST HELP]') }) it('should resolve list item', async () => { let list: IList = { name: 'test', actions: [{ name: 'open', execute: _item => { // noop } }], defaultAction: 'open', loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]), resolveItem: item => { item.label = item.label.slice(0, 1) return Promise.resolve(item) } } let disposable = manager.registerList(list) await manager.start(['--normal', 'test']) await manager.session.ui.ready await helper.wait(50) let line = await nvim.line expect(line).toBe('f') disposable.dispose() }) }) describe('descriptions', () => { it('should get descriptions', async () => { let res = manager.descriptions expect(res).toBeDefined() expect(res.location).toBeDefined() }) }) describe('loadItems()', () => { it('should load items for list', async () => { let res = await manager.loadItems('location') expect(res.length).toBeGreaterThan(0) ; (manager as any).lastSession = undefined manager.toggleMode() manager.stop() }) }) describe('onInsertInput()', () => { it('should handle insert input', async () => { await manager.onInsertInput('k') await manager.onInsertInput('') await manager.start(['--number-select', 'location']) await manager.session.ui.ready await manager.onInsertInput('1') await helper.wait(300) let bufname = await nvim.call('expand', ['%:p']) expect(bufname).toMatch('manager.test.ts') }) it('should ignore invalid input', async () => { await manager.start(['location']) await manager.session.ui.ready await manager.onInsertInput('') await manager.onInsertInput(String.fromCharCode(65533)) await manager.onInsertInput(String.fromCharCode(30)) expect(manager.isActivated).toBe(true) }) it('should ignore insert', async () => { await manager.start(['location']) await manager.session.ui.ready await nvim.eval('feedkeys("\\x", "in")') await helper.wait(50) expect(manager.isActivated).toBe(true) }) }) describe('parseArgs()', () => { it('should show error for bad option', async () => { manager.parseArgs(['$x', 'location']) let msg = await helper.getCmdline() expect(msg).toMatch('Invalid list option') }) it('should show error for option that does not exist', async () => { manager.parseArgs(['-xyz', 'location']) let msg = await helper.getCmdline() expect(msg).toMatch('Invalid option') }) it('should show error for interactive with list not support interactive', async () => { manager.parseArgs(['--interactive', 'location']) let msg = await helper.getCmdline() expect(msg).toMatch('not supported') }) }) describe('resume()', () => { it('should resume by name', async () => { await events.fire('FocusGained', []) await manager.start(['location']) await manager.session.ui.ready await manager.session.hide() await helper.wait(100) await manager.resume('location') expect(manager.isActivated).toBe(true) }) }) describe('first(), last()', () => { it('should get session by name', async () => { let last: string let list: IList = { name: 'test', actions: [{ name: 'open', execute: (item: ListItem) => { last = item.label } }], defaultAction: 'open', loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]) } manager.registerList(list) await manager.start(['test']) await manager.session.ui.ready await manager.first('a') await manager.last('a') await manager.first('test') expect(last).toBe('foo') await manager.last('test') expect(last).toBe('bar') }) }) describe('registerList()', () => { it('should recreat list', async () => { let list: IList = { name: 'test', actions: [{ name: 'open', execute: _item => { // noop } }], defaultAction: 'open', loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]) } manager.registerList(list) helper.updateConfiguration('list.source.test.defaultAction', 'open') let disposable = manager.registerList(list) disposable.dispose() await helper.wait(30) let msg = await helper.getCmdline() expect(msg).toMatch('recreated') }) }) describe('start()', () => { it('should show error when loadItems throws', async () => { let list: IList = { name: 'test', actions: [{ name: 'open', execute: (_item: ListItem) => { } }], defaultAction: 'open', loadItems: () => { throw new Error('test error') } } manager.registerList(list) await manager.start(['test']) await helper.wait(100) }) }) describe('list options', () => { it('should respect auto preview option', async () => { await manager.start(['--auto-preview', 'location']) await manager.session.ui.ready await helper.waitFor('winnr', ['$'], 3) let previewWinnr = await nvim.call('coc#list#has_preview') expect(previewWinnr).toBe(2) let bufnr = await nvim.call('winbufnr', previewWinnr) let buf = nvim.createBuffer(bufnr) let name = await buf.name expect(name).toMatch('manager.test.ts') await nvim.eval('feedkeys("j", "in")') await helper.wait(100) let winnr = await nvim.call('coc#list#has_preview') expect(winnr).toBe(previewWinnr) }) it('should respect input option', async () => { await manager.start(['--input=foo', 'location']) await manager.session.ui.ready await helper.wait(30) let line = await helper.getCmdline() expect(line).toMatch('foo') expect(manager.isActivated).toBe(true) }) it('should respect regex filter', async () => { await manager.start(['--input=f.o', '--regex', 'location']) await helper.wait(200) let item = await manager.session?.ui.item expect(item.label).toMatch('foo') }) it('should respect normal option', async () => { await manager.start(['--normal', 'location']) await manager.session.ui.ready let line = await helper.getCmdline() expect(line).toBe('') }) it('should respect nosort option', async () => { await manager.start(['--ignore-case', '--no-sort', 'location']) await manager.session.ui.ready expect(manager.isActivated).toBe(true) await nvim.input('oo') await helper.wait(100) let line = await nvim.call('getline', ['.']) expect(line).toMatch('foo') }) it('should respect ignorecase option', async () => { await manager.start(['--ignore-case', '--strict', 'location']) await manager.session.ui.ready expect(manager.isActivated).toBe(true) await nvim.input('bar') await helper.wait(100) let n = manager.session?.ui.length expect(n).toBe(1) let line = await nvim.line expect(line).toMatch('Bar') }) it('should respect top option', async () => { await manager.start(['--top', 'location']) await manager.session.ui.ready let nr = await nvim.call('winnr') expect(nr).toBe(1) }) it('should respect number select option', async () => { await manager.start(['--number-select', 'location']) await manager.session.ui.ready await helper.wait(100) await nvim.eval('feedkeys("2", "in")') await helper.wait(100) let lnum = locations[1].lnum let curr = await nvim.call('line', '.') expect(lnum).toBe(curr) }) it('should respect tab option', async () => { await manager.start(['--tab', '--auto-preview', 'location']) await manager.session.ui.ready await helper.wait(100) await nvim.command('wincmd l') let previewwindow = await nvim.eval('w:previewwindow') expect(previewwindow).toBe(1) }) }) })