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

143 lines
4.7 KiB
TypeScript

'use strict'
import { Neovim } from '@chemzqm/neovim'
import { Disposable, Emitter, Event, Range } from 'vscode-languageserver-protocol'
import events from '../events'
import Document from '../model/document'
import Documents from './documents'
import window from '../window'
const logger = require('../util/logger')('core-editors')
interface EditorOption {
bufnr: number
winid: number
tabpagenr: number
winnr: number
visibleRanges: [number, number][]
tabSize: number
insertSpaces: boolean
winids: number[]
}
export interface TextEditorOptions {
tabSize: number
insertSpaces: boolean
}
export interface TextEditor {
readonly tabpagenr: number
readonly winid: number
readonly winnr: number
readonly document: Document
readonly visibleRanges: readonly Range[]
options: TextEditorOptions
}
export default class Editors {
private disposables: Disposable[] = []
private winid: number
private previousId: string
private nvim: Neovim
private editors: Map<number, TextEditor> = new Map()
private readonly _onDidChangeActiveTextEditor = new Emitter<TextEditor | undefined>()
private readonly _onDidChangeVisibleTextEditors = new Emitter<ReadonlyArray<TextEditor>>()
public readonly onDidChangeActiveTextEditor: Event<TextEditor | undefined> = this._onDidChangeActiveTextEditor.event
public readonly onDidChangeVisibleTextEditors: Event<ReadonlyArray<TextEditor>> = this._onDidChangeVisibleTextEditors.event
constructor(private documents: Documents) {
}
public get activeTextEditor(): TextEditor | undefined {
return this.editors.get(this.winid)
}
public get visibleTextEditors(): TextEditor[] {
return Array.from(this.editors.values())
}
private onChange(editor: TextEditor | undefined): void {
let id = `${editor.winid}-${editor.document.bufnr}-${editor.document.uri}`
if (id == this.previousId) return
this.previousId = id
this._onDidChangeActiveTextEditor.fire(editor)
}
public async attach(nvim: Neovim): Promise<void> {
this.nvim = nvim
let { documents } = this
let doc = documents.getDocument(documents.bufnr)
if (doc && doc.winid > 0) {
this.winid = doc.winid
await this.createTextEditor(this.winid)
}
events.on('WinEnter', (winid: number) => {
this.winid = winid
let editor = this.editors.get(winid)
if (editor) this.onChange(editor)
}, null, this.disposables)
events.on('CursorHold', async () => {
let [winid, buftype, isFloat] = await nvim.eval(`[win_getid(),&buftype,coc#window#is_float(win_getid())]`) as [number, string, number]
let changed = false
if (!isFloat && ['', 'acwrite'].includes(buftype) && !this.editors.has(winid)) {
let created = await this.createTextEditor(winid)
if (created) changed = true
}
if (changed) this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors)
}, null, this.disposables)
events.on('WinClosed', (winid: number) => {
if (this.editors.has(winid)) {
this.editors.delete(winid)
this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors)
}
}, null, this.disposables)
events.on('BufWinEnter', async (_: number, winid: number) => {
this.winid = winid
await this.createTextEditor(winid, true)
}, null, this.disposables)
}
private async createTextEditor(winid: number, check = false): Promise<boolean> {
let { documents, nvim } = this
let opts = await nvim.call('coc#util#get_editoroption', [winid]) as EditorOption
if (!opts) return false
let changed = false
if (check) {
for (let winid of this.editors.keys()) {
if (!opts.winids.includes(winid)) {
changed = true
this.editors.delete(winid)
}
}
}
let doc = documents.getDocument(opts.bufnr)
if (doc) {
let editor = this.fromOptions(opts, doc)
this.editors.set(winid, editor)
if (winid == this.winid) this.onChange(editor)
this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors)
logger.debug('editor created winid & bufnr & tabnr: ', winid, opts.bufnr, opts.tabpagenr)
return true
} else if (changed) {
this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors)
}
logger.error(`document not found for window: ${winid}`)
return false
}
private fromOptions(opts: EditorOption, document: Document): TextEditor {
let { visibleRanges } = opts
let tid = window.getTabId(opts.tabpagenr)
return {
get tabpagenr() {
return window.getTabNumber(tid)
},
winid: opts.winid,
winnr: opts.winnr,
document,
visibleRanges: visibleRanges.map(o => Range.create(o[0] - 1, 0, o[1], 0)),
options: {
tabSize: opts.tabSize,
insertSpaces: !!opts.insertSpaces
}
}
}
}