1
0
Fork 0
mirror of synced 2024-06-25 18:21:11 -04:00
ultimate-vim/sources_non_forked/coc.nvim/src/sources/source.ts
2022-07-20 13:20:15 +08:00

152 lines
4.7 KiB
TypeScript

'use strict'
import { Neovim } from '@chemzqm/neovim'
import { CancellationToken } from 'vscode-languageserver-protocol'
import { CompleteOption, CompleteResult, ISource, SourceConfig, SourceType, VimCompleteItem } from '../types'
import { byteSlice } from '../util/string'
import workspace from '../workspace'
const logger = require('../util/logger')('sources-source')
export default class Source implements ISource {
public readonly name: string
public readonly filepath: string
public readonly sourceType: SourceType
public readonly isSnippet: boolean
protected readonly nvim: Neovim
private _disabled = false
private defaults: any
constructor(option: SourceConfig) {
this.nvim = workspace.nvim
// readonly properties
this.name = option.name
this.filepath = option.filepath || ''
this.sourceType = option.sourceType || SourceType.Native
this.isSnippet = !!option.isSnippet
this.defaults = option
}
/**
* Priority of source, higher priority makes items lower index.
*/
public get priority(): number {
return this.getConfig('priority', 1)
}
/**
* When triggerOnly is true, not trigger completion on keyword character insert.
*/
public get triggerOnly(): boolean {
let triggerOnly = this.defaults['triggerOnly']
if (typeof triggerOnly == 'boolean') return triggerOnly
if (!this.triggerCharacters && !this.triggerPatterns) return false
return Array.isArray(this.triggerPatterns) && this.triggerPatterns.length != 0
}
public get triggerCharacters(): string[] {
return this.getConfig('triggerCharacters', null)
}
// exists opitonnal function names for remote source
public get optionalFns(): string[] {
return this.defaults['optionalFns'] || []
}
public get triggerPatterns(): RegExp[] | null {
let patterns = this.getConfig<any[]>('triggerPatterns', null)
if (!patterns || patterns.length == 0) return null
return patterns.map(s => (typeof s === 'string') ? new RegExp(s + '$') : s)
}
public get shortcut(): string {
let shortcut = this.getConfig('shortcut', '')
return shortcut ? shortcut : this.name.slice(0, 3)
}
public get enable(): boolean {
if (this._disabled) return false
return this.getConfig('enable', true)
}
public get filetypes(): string[] | null {
return this.getConfig('filetypes', null)
}
public get disableSyntaxes(): string[] {
return this.getConfig('disableSyntaxes', [])
}
public getConfig<T>(key: string, defaultValue?: T): T | null {
let config = workspace.getConfiguration(`coc.source.${this.name}`)
defaultValue = this.defaults.hasOwnProperty(key) ? this.defaults[key] : defaultValue
return config.get(key, defaultValue)
}
public toggle(): void {
this._disabled = !this._disabled
}
public get firstMatch(): boolean {
return this.getConfig('firstMatch', true)
}
public get menu(): string {
let { shortcut } = this
return shortcut ? `[${shortcut}]` : ''
}
/**
* fix start column for new valid characters
*
* @protected
* @param {CompleteOption} opt
* @param {string[]} valids - valid charscters
* @returns {number}
*/
protected fixStartcol(opt: CompleteOption, valids: string[]): number {
let { col, input, line, bufnr } = opt
let start = byteSlice(line, 0, col)
let document = workspace.getDocument(bufnr)
if (!document) return col
let { chars } = document
for (let i = start.length - 1; i >= 0; i--) {
let c = start[i]
if (!chars.isKeywordChar(c) && !valids.includes(c)) {
break
}
input = `${c}${input}`
col = col - 1
}
opt.col = col
opt.input = input
return col
}
public async shouldComplete(opt: CompleteOption): Promise<boolean> {
let { disableSyntaxes } = this
if (opt.synname && disableSyntaxes && disableSyntaxes.length) {
let synname = (opt.synname || '').toLowerCase()
if (disableSyntaxes.findIndex(s => synname.includes(s.toLowerCase())) !== -1) {
return false
}
}
let fn = this.defaults['shouldComplete']
if (typeof fn === 'function') return await Promise.resolve(fn.call(this, opt))
return true
}
public async refresh(): Promise<void> {
let fn = this.defaults['refresh']
if (typeof fn === 'function') await Promise.resolve(fn.call(this))
}
public async onCompleteDone(item: VimCompleteItem, opt: CompleteOption): Promise<void> {
let fn = this.defaults['onCompleteDone']
if (typeof fn === 'function') await Promise.resolve(fn.call(this, item, opt))
}
public async doComplete(opt: CompleteOption, token: CancellationToken): Promise<CompleteResult | null> {
let fn = this.defaults['doComplete']
if (typeof fn === 'function') return await Promise.resolve(fn.call(this, opt, token))
return null
}
}