diff --git a/NvimView/NvimView/AttributesRunDrawer.swift b/NvimView/NvimView/AttributesRunDrawer.swift index 46908acd..93caceae 100644 --- a/NvimView/NvimView/AttributesRunDrawer.swift +++ b/NvimView/NvimView/AttributesRunDrawer.swift @@ -219,7 +219,7 @@ final class AttributesRunDrawer { private func updateFontMetrics() { self.cellSize = FontUtils.cellSize( - of: self.font, linespacing: linespacing + of: self.font, linespacing: self.linespacing ) self.baselineOffset = self.cellSize.height - CTFontGetAscent(self.font) self.descent = CTFontGetDescent(font) diff --git a/NvimView/NvimView/FontUtils.swift b/NvimView/NvimView/FontUtils.swift index 4e21b33b..bc1497e8 100644 --- a/NvimView/NvimView/FontUtils.swift +++ b/NvimView/NvimView/FontUtils.swift @@ -32,8 +32,11 @@ extension FontTrait: Hashable { final class FontUtils { static func cellSize(of font: NSFont, linespacing: CGFloat) -> CGSize { - if let cached = cellSizeCache.object(forKey: font) { - return cached + if let cached = cellSizeWithDefaultLinespacingCache.object(forKey: font) { + return CGSize( + width: cached.width, + height: ceil(linespacing * cached.height) + ) } let capitalM = [UniChar(0x004D)] @@ -46,11 +49,18 @@ final class FontUtils { let descent = CTFontGetDescent(font) let leading = CTFontGetLeading(font) + let cellSizeToCache = CGSize( + width: advancement.width, + height: ceil(ascent + descent + leading) + ) + cellSizeWithDefaultLinespacingCache.set( + object: cellSizeToCache, forKey: font + ) + let cellSize = CGSize( width: advancement.width, - height: ceil(linespacing * (ascent + descent + leading)) + height: ceil(linespacing * cellSizeToCache.height) ) - cellSizeCache.set(object: cellSize, forKey: font) return cellSize } @@ -87,4 +97,4 @@ final class FontUtils { } private let fontCache = SimpleCache(countLimit: 100) -private let cellSizeCache = SimpleCache(countLimit: 100) +private let cellSizeWithDefaultLinespacingCache = SimpleCache(countLimit: 100) diff --git a/NvimView/NvimView/com.qvacua.NvimView.vim b/NvimView/NvimView/com.qvacua.NvimView.vim index 1f1b847e..69002294 100644 --- a/NvimView/NvimView/com.qvacua.NvimView.vim +++ b/NvimView/NvimView/com.qvacua.NvimView.vim @@ -1,45 +1,3 @@ set termguicolors set mouse=a set title - -"function! s:VimRMakeSessionTemporary() abort -" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.make-session-temporary') -"endfunction -"command! -nargs=0 VimRMakeSessionTemporary call s:VimRMakeSessionTemporary() -" -"function! s:VimRMaximizeWindow() abort -" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.maximize-window') -"endfunction -"command! -nargs=0 VimRMaximizeWindow call s:VimRMaximizeWindow() -" -"" -1: hide, 0: toggle, 1: show -"function! s:VimRToggleTools(value) abort -" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tools', a:value) -"endfunction -"command! -nargs=0 VimRHideTools call s:VimRToggleTools(-1) -"command! -nargs=0 VimRToggleTools call s:VimRToggleTools(0) -"command! -nargs=0 VimRShowTools call s:VimRToggleTools(1) -" -"" -1: hide, 0: toggle, 1: show -"function! s:VimRToggleToolButtons(value) abort -" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tool-buttons', a:value) -"endfunction -"command! -nargs=0 VimRHideToolButtons call s:VimRToggleToolButtons(-1) -"command! -nargs=0 VimRToggleToolButtons call s:VimRToggleToolButtons(0) -"command! -nargs=0 VimRShowToolButtons call s:VimRToggleToolButtons(1) -" -"function! s:VimRToggleFullscreen() abort -" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-fullscreen') -"endfunction -"command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen() -" -"function! s:VimRTest() abort -" VimRMakeSessionTemporary -" VimRHideTools -" VimRMaximizeWindow -" normal o -"endfunction -"command! -nargs=0 VimRTest call s:VimRTest() -" -""au VimEnter * echo "hello" -""au GuiEnter * echo "world" diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index 97f8d051..55062a01 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -80,12 +80,14 @@ 1929BDC69A5F9D1661423488 /* ShortcutItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF230875DED6CD7AB3EB /* ShortcutItem.swift */; }; 1929BDFDBDA7180D02ACB37E /* RxSwiftCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6C215ACCBE12672A8D7 /* RxSwiftCommonsTest.swift */; }; 1929BE0DAEE9664C5BCFA211 /* States.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB6608B4F0E037CA0F4C /* States.swift */; }; + 1929BE0EB11D6BBC46D448D2 /* RpcAppearanceEpic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */; }; 1929BE0F64A6CE5BCE2A5092 /* MainWindow+Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B714EB137AE448CE8ABD /* MainWindow+Delegates.swift */; }; 1929BE2F3E0182CC51F2763A /* ThemedTableSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD2CA8DD198A6BCDBCB7 /* ThemedTableSubviews.swift */; }; 1929BEAE0592096BC1191B67 /* PrefPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B07A4A9209C88380E015 /* PrefPane.swift */; }; 1929BEDE1BE950EDA9497363 /* GeneralPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB55946DAEBF55D24048 /* GeneralPref.swift */; }; 1929BEFEABA0448306CDB6D4 /* FileItemIgnorePatternTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */; }; 1929BF03FD6465F289AA80B2 /* ToolsPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB2AD21A10A0ECA66A5E /* ToolsPref.swift */; }; + 1929BF3253594E5B1908C6CE /* RpcAppearanceEpic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */; }; 1929BF4FF30D9A9DE82C3052 /* FileUtilsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8042AC566CDF6C998A3 /* FileUtilsTest.swift */; }; 1929BFC70581084B5CE04A5B /* MatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFE179BCA3C75A13D71B /* MatcherTests.swift */; }; 1929BFDE22D155F7C4B19E96 /* HtmlPreviewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B85023B042C485409CE1 /* HtmlPreviewTool.swift */; }; @@ -312,6 +314,7 @@ 1929B14A5949FB64C4B2646F /* KeysPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeysPref.swift; sourceTree = ""; }; 1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyFileViewRow.swift; sourceTree = ""; }; 1929B1DC584C89C477E83FA2 /* HttpServerMiddleware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpServerMiddleware.swift; sourceTree = ""; }; + 1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RpcAppearanceEpic.swift; sourceTree = ""; }; 1929B34FC23D805A8B29E8F7 /* Context.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = ""; }; 1929B364460D86F17E80943C /* PrefMiddleware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefMiddleware.swift; sourceTree = ""; }; 1929B365A6434354B568B04F /* FileMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileMonitor.swift; sourceTree = ""; }; @@ -627,6 +630,7 @@ 1929B5E773BDB3B4EE9D00C1 /* Reducers */, 1929BFA93DC859DD76C46192 /* Middlewares */, 1929BFC0A5A9C6DB09BE1368 /* Types.swift */, + 1929BE4A67D96BD8BD8168C3 /* Epics */, ); name = UI; sourceTree = ""; @@ -681,6 +685,14 @@ name = "Open Quickly"; sourceTree = ""; }; + 1929BE4A67D96BD8BD8168C3 /* Epics */ = { + isa = PBXGroup; + children = ( + 1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */, + ); + name = Epics; + sourceTree = ""; + }; 1929BFA93DC859DD76C46192 /* Middlewares */ = { isa = PBXGroup; children = ( @@ -1191,6 +1203,7 @@ 1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */, 1929B0C7150100A84FBDB8BF /* ShortcutItem.swift in Sources */, 1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */, + 1929BF3253594E5B1908C6CE /* RpcAppearanceEpic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1226,6 +1239,7 @@ 1929B0244BD7111E168726CF /* DefaultShortcuts.swift in Sources */, 1929BDC69A5F9D1661423488 /* ShortcutItem.swift in Sources */, 1929B489A51FD5B13888A00C /* RpcEvents.swift in Sources */, + 1929BE0EB11D6BBC46D448D2 /* RpcAppearanceEpic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/VimR/VimR/Context.swift b/VimR/VimR/Context.swift index 6b4a3888..5138cb0e 100644 --- a/VimR/VimR/Context.swift +++ b/VimR/VimR/Context.swift @@ -28,6 +28,7 @@ class Context: ReduxContext { let httpMiddleware: HttpServerMiddleware = HttpServerMiddleware(port: baseServerUrl.port!) let uiRootReducer = UiRootReducer() let openQuicklyReducer = OpenQuicklyReducer() + let rpcEpic = RpcAppearanceEpic(emitter: self.actionEmitter) // AppState self.actionEmitter.observable @@ -52,6 +53,7 @@ class Context: ReduxContext { middlewares: [ self.prefMiddleware.mainWindow.apply, self.prefMiddleware.apply, + rpcEpic.apply, ]) .filter { $0.modified } .subscribe(onNext: self.emitAppState) diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index 8a7c68b8..275b494a 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -31,7 +31,7 @@ extension MainWindow { self.window.setFrame(screen.frame, display: true) case .toggleTools: - if params.count == 0 { return } + guard params.count == 1 else { return } let param = params[0].integerValue @@ -44,7 +44,7 @@ extension MainWindow { } case .toggleToolButtons: - if params.count == 0 { return } + guard params.count == 1 else { return } let param = params[0].integerValue @@ -59,6 +59,23 @@ extension MainWindow { case .toggleFullScreen: self.window.toggleFullScreen(self) + case .setFont: + guard params.count == 2 else { return } + guard let fontName = params[0].stringValue, + let fontSize = params[1].integerValue, + let font = NSFont(name: fontName, size: CGFloat(fontSize)) + else { + return + } + + self.emit(self.uuidAction(for: .setFont(font))) + + case .setLinespacing: + guard params.count == 1 else { return } + guard let linespacing = params[0].floatValue else { return } + + self.emit(self.uuidAction(for: .setLinespacing(CGFloat(linespacing)))) + } } diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index eacc8c93..ec6deeaa 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -45,6 +45,10 @@ class MainWindow: NSObject, case setTheme(Theme) case close + + // RPC actions + case setFont(NSFont) + case setLinespacing(CGFloat) } enum FocusableView { diff --git a/VimR/VimR/MainWindowReducer.swift b/VimR/VimR/MainWindowReducer.swift index 9216638e..b5d1a948 100644 --- a/VimR/VimR/MainWindowReducer.swift +++ b/VimR/VimR/MainWindowReducer.swift @@ -81,6 +81,10 @@ class MainWindowReducer: ReducerType { case .makeSessionTemporary: state.isTemporarySession = true + // RPC actions + case .setFont(let font): + stdoutLog.debug(font) + default: return tuple diff --git a/VimR/VimR/RpcAppearanceEpic.swift b/VimR/VimR/RpcAppearanceEpic.swift new file mode 100644 index 00000000..c402c92f --- /dev/null +++ b/VimR/VimR/RpcAppearanceEpic.swift @@ -0,0 +1,42 @@ +/** + * Tae Won Ha - http://taewon.de - @hataewon + * See LICENSE + */ + +import Foundation + +class RpcAppearanceEpic: EpicType { + + typealias StateType = AppState + typealias ActionType = UuidAction + typealias EmitActionType = AppearancePref.Action + + required init(emitter: ActionEmitter) { + self.emit = emitter.typedEmit() + } + + func typedApply( + _ reduce: @escaping TypedActionReduceFunction + ) -> TypedActionReduceFunction { + return { tuple in + let result = reduce(tuple) + + switch tuple.action.payload { + + case .setFont(let font): + self.emit(.setFont(font)) + + case .setLinespacing(let linespacing): + self.emit(.setLinespacing(linespacing)) + + default: + break + + } + + return result + } + } + + private let emit: (EmitActionType) -> Void +} diff --git a/VimR/VimR/RpcEvents.swift b/VimR/VimR/RpcEvents.swift index 020415fd..237f250b 100644 --- a/VimR/VimR/RpcEvents.swift +++ b/VimR/VimR/RpcEvents.swift @@ -14,4 +14,7 @@ enum RpcEvent: String, CaseIterable { case toggleTools = "com.qvacua.vimr.rpc-events.toggle-tools" case toggleToolButtons = "com.qvacua.vimr.rpc-events.toggle-tool-buttons" case toggleFullScreen = "com.qvacua.vimr.rpc-events.toggle-fullscreen" + + case setFont = "com.qvacua.vimr.rpc-events.set-font" + case setLinespacing = "com.qvacua.vimr.rpc-events.set-linespacing" } diff --git a/VimR/VimR/RxRedux.swift b/VimR/VimR/RxRedux.swift index fd524384..e8be9ab6 100644 --- a/VimR/VimR/RxRedux.swift +++ b/VimR/VimR/RxRedux.swift @@ -95,6 +95,13 @@ extension MiddlewareType { } } +protocol EpicType: MiddlewareType { + + associatedtype EmitActionType + + init(emitter: ActionEmitter) +} + protocol UiComponent { associatedtype StateType diff --git a/VimR/VimR/com.qvacua.VimR.vim b/VimR/VimR/com.qvacua.VimR.vim index eed681df..aa3a001d 100644 --- a/VimR/VimR/com.qvacua.VimR.vim +++ b/VimR/VimR/com.qvacua.VimR.vim @@ -28,3 +28,13 @@ function! s:VimRToggleFullscreen() abort call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-fullscreen') endfunction command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen() + +function! s:VimRSetFontAndSize(font, size) abort + call rpcnotify(0, 'com.qvacua.NvimView', 'set-font', a:font, a:size) +endfunction +command! -nargs=* VimRSetFontAndSize call s:VimRSetFontAndSize() + +function! s:VimRSetLinespacing(linespacing) abort + call rpcnotify(0, 'com.qvacua.NvimView', 'set-linespacing', a:linespacing) +endfunction +command! -nargs=1 VimRSetLinespacing call s:VimRSetLinespacing() diff --git a/resources/release-notes.md b/resources/release-notes.md index 448068b0..e17752b1 100644 --- a/resources/release-notes.md +++ b/resources/release-notes.md @@ -3,6 +3,7 @@ * GH-314: You can customize the key shortcut for all menu items in the *Shortcut* preferences pane. * GH-501: Add key shortcuts to toggle the Buffer List, Markdown Preview, and HTML Preview tools. * GH-649: Add commands that can control some of GUI elements. +* GH-506: Set font, size and linespacing via `~/.config/nvim/ginig.vim`. * Draw the disclosure triangle in appropriate color of the current color scheme (and improve handling of changes of `cwd` in the file browser). * ...