1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-11-24 11:37:32 +03:00

Merge pull request #830 from Shirk/remote_options_and_guifont

Implement support for 'set guifont' via optionSet. (fixes #779)
This commit is contained in:
Tae Won Ha 2020-12-20 15:23:55 +01:00 committed by GitHub
commit a42a6d87cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 154 additions and 1 deletions

View File

@ -69,6 +69,37 @@ enum FontUtils {
fontCache.set(ctFont, forKey: sizedFontTrait)
return ctFont
}
static func font(fromVimFontSpec fontSpec: String) -> NSFont? {
let fontParams = fontSpec.components(separatedBy: ":")
guard fontParams.count == 2 else {
return nil
}
let fontName = fontParams[0].components(separatedBy: "_").joined(separator: " ")
var fontSize = NvimView.defaultFont.pointSize // use a sane fallback
if fontParams[1].hasPrefix("h"), fontParams[1].count >= 2 {
let sizeSpec = fontParams[1].dropFirst()
if let parsed = Float(sizeSpec)?.rounded() {
fontSize = CGFloat(parsed)
if fontSize < NvimView.minFontSize || fontSize > NvimView.maxFontSize {
fontSize = NvimView.defaultFont.pointSize
}
}
}
return NSFont(name: fontName, size: CGFloat(fontSize))
}
static func vimFontSpec(forFont font: NSFont) -> String {
if let escapedName = font.displayName?.components(separatedBy: " ").joined(separator: "_") {
return "\(escapedName):h\(Int(font.pointSize))"
}
// fontName always returns a valid result and works for font(name:, size:) as well
return "\(font.fontName):h\(Int(font.pointSize))"
}
}
private let fontCache = FifoCache<SizedFontTrait, NSFont>(count: 100, queueQos: .userInteractive)

View File

@ -0,0 +1,106 @@
/**
* Renee Koecher - @shirk
* See LICENSE
*/
import Cocoa
import MessagePack
import RxSwift
extension NvimView {
enum RemoteOption {
// list of currently handled remote options
case guifont(fontSpec: String)
case guifontWide(fontSpec: String)
static func fromValuePair(_ option: (key: MessagePackValue, value: MessagePackValue))
-> RemoteOption?
{
guard let key = option.key.stringValue,
let val = option.value.stringValue else {
return nil
}
switch key {
case "guifont": return RemoteOption.guifont(fontSpec: val)
case "guifontwide": return RemoteOption.guifontWide(fontSpec: val)
default: return nil
}
}
// convenience methods
static func fromFont(_ font: NSFont, forWideFont isWide: Bool = false) -> RemoteOption {
let fontSpec = FontUtils.vimFontSpec(forFont: font)
if isWide {
return RemoteOption.guifontWide(fontSpec: fontSpec)
}
return RemoteOption.guifont(fontSpec: fontSpec)
}
}
final func handleRemoteOptions(_ options: [MessagePackValue: MessagePackValue]) {
for kvPair in options {
guard let option = RemoteOption.fromValuePair(kvPair) else {
self.bridgeLogger.debug("Could not handle RemoteOption \(kvPair)")
continue
}
switch option {
// FIXME: currently this treats gft and gfw the as the same
case let .guifont(fontSpec): self.handleGuifontSet(fontSpec)
case let .guifontWide(fontSpec): self.handleGuifontSet(fontSpec, forWideFont: true)
}
}
}
final func signalRemoteOptionChange(_ option: RemoteOption) {
let command: Completable?
switch option {
case let .guifont(fontSpec):
command = self.api.setOption(name: "guifont", value: .string(fontSpec))
case let .guifontWide(fontSpec):
command = self.api.setOption(name: "guifontwide", value: .string(fontSpec))
}
command?.subscribe().disposed(by: self.disposeBag)
}
public final func signalError(code: Int, message: String) {
self.api.errWriteln(str: "E\(code): \(message)")
.subscribe()
.disposed(by: self.disposeBag)
}
private func handleGuifontSet(_ fontSpec: String, forWideFont wideFlag: Bool = false) {
if fontSpec.isEmpty {
// this happens on connect - signal the current value
self.signalRemoteOptionChange(RemoteOption.fromFont(self.font, forWideFont: wideFlag))
return
}
// stop if we would set the same font again
let currentSpec = FontUtils.vimFontSpec(forFont: font)
if currentSpec == fontSpec.components(separatedBy: " ").joined(separator: "_") {
return
}
guard let newFont = FontUtils.font(fromVimFontSpec: fontSpec) else {
self.bridgeLogger.debug("Invalid specification for guifont '\(fontSpec)'")
self.signalError(code: 596, message: "Invalid font(s): gufont=\(fontSpec)")
self.signalRemoteOptionChange(RemoteOption.fromFont(self.font, forWideFont: wideFlag))
return
}
gui.async {
self.font = newFont
self.markForRenderWholeView()
self.eventsSubject.onNext(.guifontChanged(newFont))
}
}
}
private let gui = DispatchQueue.main

View File

@ -61,6 +61,7 @@ public extension NvimView {
case bufferWritten(NvimView.Buffer)
case colorschemeChanged(NvimView.Theme)
case guifontChanged(NSFont)
case ipcBecameInvalid(String)

View File

@ -14,7 +14,14 @@ extension NvimView {
self.eventsSubject.onNext(.initVimError)
}
final func optionSet(_: MessagePackValue) {}
final func optionSet(_ value: MessagePackValue) {
guard let options = value.dictionaryValue else {
self.bridgeLogger.error("Could not convert \(value)")
return
}
handleRemoteOptions(options);
}
final func resize(_ value: MessagePackValue) {
guard let array = MessagePackUtils.array(

View File

@ -95,6 +95,8 @@ public class NvimView: NSView,
self._font = newValue
self.updateFontMetaData(newValue)
signalRemoteOptionChange(RemoteOption.fromFont(newValue));
}
}

View File

@ -103,6 +103,10 @@ extension MainWindow {
.disposed(by: self.disposeBag)
}
func guifontChanged(to font: NSFont) {
self.emit(self.uuidAction(for: .setFont(font)))
}
func ipcBecameInvalid(reason: String) {
let alert = NSAlert()
alert.addButton(withTitle: "Close")

View File

@ -296,6 +296,8 @@ class MainWindow: NSObject,
case let .colorschemeChanged(theme): self?.colorschemeChanged(to: theme)
case let .guifontChanged(font): self?.guifontChanged(to: font)
case let .ipcBecameInvalid(reason):
self?.ipcBecameInvalid(reason: reason)