1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-01 18:39:52 +03:00
vimr/SwiftNeoVim/NeoVimView+UiBridge.swift
Tae Won Ha f524a3ff0c
GH-302, GH-421 Call agent.quit() in main thread
- this avoids the strange delay which occurs sometimes when we call it in the mach port server thread
2017-06-13 22:56:50 +02:00

374 lines
8.1 KiB
Swift

/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
extension NeoVimView {
public func resize(toWidth width: Int, height: Int) {
gui.async {
self.bridgeLogger.debug("\(width) x \(height)")
self.grid.resize(Size(width: width, height: height))
self.markForRenderWholeView()
}
}
public func clear() {
gui.async {
self.bridgeLogger.mark()
self.grid.clear()
self.markForRenderWholeView()
}
}
public func eolClear() {
gui.async {
self.bridgeLogger.mark()
self.grid.eolClear()
let putPosition = self.grid.position
let region = Region(top: putPosition.row,
bottom: putPosition.row,
left: putPosition.column,
right: self.grid.region.right)
self.markForRender(region: region)
}
}
public func gotoPosition(_ position: Position, textPosition: Position) {
gui.async {
self.bridgeLogger.debug(position)
self.markForRender(cellPosition: self.grid.position)
self.grid.goto(position)
self.delegate?.cursor(to: textPosition)
}
}
public func modeChange(_ mode: CursorModeShape) {
gui.async {
self.bridgeLogger.debug(cursorModeShapeName(mode))
self.mode = mode
}
}
public func setScrollRegionToTop(_ top: Int, bottom: Int, left: Int, right: Int) {
gui.async {
self.bridgeLogger.debug("\(top):\(bottom):\(left):\(right)")
let region = Region(top: top, bottom: bottom, left: left, right: right)
self.grid.setScrollRegion(region)
}
}
public func scroll(_ count: Int) {
gui.async {
self.bridgeLogger.debug(count)
self.grid.scroll(count)
self.markForRender(region: self.grid.region)
// Do not send msgs to agent -> neovim in the delegate method. It causes spinning
// when you're opening a file with existing swap file.
self.delegate?.scroll()
}
}
public func highlightSet(_ attrs: CellAttributes) {
gui.async {
self.bridgeLogger.debug(attrs)
self.grid.attrs = attrs
}
}
public func put(_ string: String) {
gui.async {
let curPos = self.grid.position
// self.bridgeLogger.debug("\(curPos) -> \(string)")
self.grid.put(string)
if self.usesLigatures {
if string == " " {
self.markForRender(cellPosition: curPos)
} else {
self.markForRender(region: self.grid.regionOfWord(at: curPos))
}
} else {
self.markForRender(cellPosition: curPos)
}
}
}
public func putMarkedText(_ markedText: String) {
gui.async {
let curPos = self.grid.position
// self.bridgeLogger.debug("\(curPos) -> '\(markedText)'")
self.grid.putMarkedText(markedText)
self.markForRender(position: curPos)
// When the cursor is in the command line, then we need this...
self.markForRender(cellPosition: self.grid.nextCellPosition(curPos))
if markedText.characters.count == 0 {
self.markForRender(position: self.grid.previousCellPosition(curPos))
}
}
}
public func unmarkRow(_ row: Int, column: Int) {
gui.async {
self.bridgeLogger.debug("\(row):\(column)")
let position = Position(row: row, column: column)
self.grid.unmarkCell(position)
self.markForRender(position: position)
}
}
public func flush() {
gui.async {
self.bridgeLogger.hr()
self.shouldDrawCursor = true
if self.usesLigatures {
self.markForRender(region: self.grid.regionOfWord(at: self.grid.position))
} else {
self.markForRender(cellPosition: self.grid.position)
}
}
}
public func updateForeground(_ fg: Int) {
gui.async {
self.bridgeLogger.debug(ColorUtils.colorIgnoringAlpha(fg))
self.grid.foreground = fg
}
}
public func updateBackground(_ bg: Int) {
gui.async {
self.bridgeLogger.debug(ColorUtils.colorIgnoringAlpha(bg))
self.grid.background = bg
self.layer?.backgroundColor = ColorUtils.colorIgnoringAlpha(self.grid.background).cgColor
}
}
public func updateSpecial(_ sp: Int) {
gui.async {
self.bridgeLogger.debug(ColorUtils.colorIgnoringAlpha(sp))
self.grid.special = sp
}
}
public func setTitle(_ title: String) {
gui.async {
self.bridgeLogger.debug(title)
self.delegate?.set(title: title)
}
}
public func stop() {
self.bridgeLogger.hr()
self.quitNeoVimCondition.lock()
self.isNeoVimQuitSuccessful = true
self.quitNeoVimCondition.signal()
self.quitNeoVimCondition.unlock()
gui.async {
self.agent.quit()
self.delegate?.neoVimStopped()
}
}
public func autoCommandEvent(_ event: NeoVimAutoCommandEvent, bufferHandle: Int) {
gui.async {
// self.bridgeLogger.debug("\(neoVimAutoCommandEventName(event)) -> \(bufferHandle)")
if event == .BUFWINENTER || event == .BUFWINLEAVE {
self.bufferListChanged()
}
if event == .TABENTER {
self.tabChanged()
}
if event == .BUFREADPOST || event == .BUFWRITEPOST {
self.currentBufferChanged(bufferHandle)
}
}
}
public func ipcBecameInvalid(_ reason: String) {
gui.async {
self.bridgeLogger.debug(reason)
if self.agent.neoVimIsQuitting {
return
}
self.delegate?.ipcBecameInvalid(reason: reason)
self.bridgeLogger.fault("force-quitting")
self.agent.quit()
}
}
}
// MARK: - Simple
extension NeoVimView {
public func bell() {
gui.async {
self.bridgeLogger.mark()
NSBeep()
}
}
public func cwdChanged(_ cwd: String) {
gui.async {
self.bridgeLogger.debug(cwd)
self._cwd = URL(fileURLWithPath: cwd)
self.cwdChanged()
}
}
public func setDirtyStatus(_ dirty: Bool) {
gui.async {
self.bridgeLogger.debug(dirty)
self.delegate?.set(dirtyStatus: dirty)
}
}
public func updateMenu() {
gui.async {
self.bridgeLogger.mark()
}
}
public func busyStart() {
gui.async {
self.bridgeLogger.mark()
}
}
public func busyStop() {
gui.async {
self.bridgeLogger.mark()
}
}
public func mouseOn() {
gui.async {
self.bridgeLogger.mark()
}
}
public func mouseOff() {
gui.async {
self.bridgeLogger.mark()
}
}
public func visualBell() {
gui.async {
self.bridgeLogger.mark()
}
}
public func suspend() {
gui.async {
self.bridgeLogger.mark()
}
}
public func setIcon(_ icon: String) {
gui.async {
self.bridgeLogger.debug(icon)
}
}
}
extension NeoVimView {
func markForRender(cellPosition position: Position) {
self.markForRender(position: position)
if self.grid.isCellEmpty(position) {
self.markForRender(position: self.grid.previousCellPosition(position))
}
if self.grid.isNextCellEmpty(position) {
self.markForRender(position: self.grid.nextCellPosition(position))
}
}
func markForRender(position: Position) {
self.markForRender(row: position.row, column: position.column)
}
func markForRender(screenCursor position: Position) {
self.markForRender(position: position)
if self.grid.isNextCellEmpty(position) {
self.markForRender(position: self.grid.nextCellPosition(position))
}
}
func markForRenderWholeView() {
self.needsDisplay = true
}
func markForRender(region: Region) {
self.setNeedsDisplay(self.rect(for: region))
}
func markForRender(row: Int, column: Int) {
self.setNeedsDisplay(self.rect(forRow: row, column: column))
}
}
extension NeoVimView {
fileprivate func currentBufferChanged(_ handle: Int) {
guard let currentBuffer = self.currentBuffer() else {
return
}
guard currentBuffer.handle == handle else {
return
}
self.delegate?.currentBufferChanged(currentBuffer)
}
fileprivate func tabChanged() {
self.delegate?.tabChanged()
}
fileprivate func cwdChanged() {
self.delegate?.cwdChanged()
}
fileprivate func bufferListChanged() {
self.delegate?.bufferListChanged()
}
}
fileprivate let gui = DispatchQueue.main