mirror of
https://github.com/qvacua/vimr.git
synced 2024-11-24 11:37:32 +03:00
GH-339 React to opening
This commit is contained in:
parent
738635ca51
commit
1ce679da9d
1
Cartfile
1
Cartfile
@ -4,3 +4,4 @@ github "eonil/FileSystemEvents" "master"
|
||||
github "sparkle-project/Sparkle" == 1.14.0
|
||||
github "qvacua/CocoaFontAwesome" "master"
|
||||
github "qvacua/CocoaMarkdown" "master"
|
||||
github "sindresorhus/github-markdown-css" == 2.4.1
|
||||
|
@ -5,3 +5,4 @@ github "Quick/Nimble" "v5.1.0"
|
||||
github "PureLayout/PureLayout" "v3.0.2"
|
||||
github "ReactiveX/RxSwift" "3.0.1"
|
||||
github "sparkle-project/Sparkle" "1.14.0"
|
||||
github "sindresorhus/github-markdown-css" "v2.4.1"
|
||||
|
@ -37,6 +37,7 @@
|
||||
4B183E161E07C1420079E8A8 /* preview in Resources */ = {isa = PBXBuildFile; fileRef = 4B183E151E07C1420079E8A8 /* preview */; };
|
||||
4B183E1B1E08748B0079E8A8 /* NeoVimAutoCommandEvent.generated.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B183E1A1E08748B0079E8A8 /* NeoVimAutoCommandEvent.generated.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4B183E1E1E09931E0079E8A8 /* MarkdownRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B183E1D1E09931E0079E8A8 /* MarkdownRenderer.swift */; };
|
||||
4B19164C1E0B1D53007EA025 /* github-markdown.css in Resources */ = {isa = PBXBuildFile; fileRef = 4B19164B1E0B1D53007EA025 /* github-markdown.css */; };
|
||||
4B22F7F01D7C029400929B0E /* ScorerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B22F7EF1D7C029400929B0E /* ScorerTest.swift */; };
|
||||
4B22F7F21D7C6B9000929B0E /* ImageAndTextTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B22F7F11D7C6B9000929B0E /* ImageAndTextTableCell.swift */; };
|
||||
4B238BE11D3BF24200CBDD98 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B238BE01D3BF24200CBDD98 /* Application.swift */; };
|
||||
@ -305,6 +306,7 @@
|
||||
4B183E151E07C1420079E8A8 /* preview */ = {isa = PBXFileReference; lastKnownFileType = folder; path = preview; sourceTree = "<group>"; };
|
||||
4B183E1A1E08748B0079E8A8 /* NeoVimAutoCommandEvent.generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NeoVimAutoCommandEvent.generated.h; sourceTree = "<group>"; };
|
||||
4B183E1D1E09931E0079E8A8 /* MarkdownRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownRenderer.swift; sourceTree = "<group>"; };
|
||||
4B19164B1E0B1D53007EA025 /* github-markdown.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = "github-markdown.css"; path = "Carthage/Checkouts/github-markdown-css/github-markdown.css"; sourceTree = SOURCE_ROOT; };
|
||||
4B1BB3521D16C5E500CA4FEF /* InputTestView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputTestView.swift; sourceTree = "<group>"; };
|
||||
4B22F7EF1D7C029400929B0E /* ScorerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScorerTest.swift; sourceTree = "<group>"; };
|
||||
4B22F7F11D7C6B9000929B0E /* ImageAndTextTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAndTextTableCell.swift; sourceTree = "<group>"; };
|
||||
@ -685,6 +687,7 @@
|
||||
4B97E2CF1D33F92200FC0660 /* resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B19164B1E0B1D53007EA025 /* github-markdown.css */,
|
||||
4B183E151E07C1420079E8A8 /* preview */,
|
||||
4BEBA50C1CFF374B00673FDF /* MainMenu.xib */,
|
||||
4B97E2CE1D33F53D00FC0660 /* MainWindow.xib */,
|
||||
@ -1102,6 +1105,7 @@
|
||||
4BDF50171D77540900D8FBC3 /* OpenQuicklyWindow.xib in Resources */,
|
||||
4B37ADB91D6E471B00970D55 /* vimr in Resources */,
|
||||
4BB409E51DD68CCC005F39A2 /* FileBrowserMenu.xib in Resources */,
|
||||
4B19164C1E0B1D53007EA025 /* github-markdown.css in Resources */,
|
||||
4BEBA50E1CFF374B00673FDF /* MainMenu.xib in Resources */,
|
||||
4B97E2CC1D33F53D00FC0660 /* MainWindow.xib in Resources */,
|
||||
4B029F1A1D45E349004EE0D3 /* PrefWindow.xib in Resources */,
|
||||
|
@ -16,6 +16,7 @@ enum MainWindowAction {
|
||||
case changeFileBrowserSelection(mainWindow: MainWindowComponent, url: URL)
|
||||
case close(mainWindow: MainWindowComponent, mainWindowPrefData: MainWindowPrefData)
|
||||
|
||||
case toggleTool(tool: WorkspaceTool)
|
||||
case currentBufferChanged(mainWindow: MainWindowComponent, buffer: NeoVimBuffer)
|
||||
}
|
||||
|
||||
@ -339,6 +340,10 @@ extension MainWindowComponent {
|
||||
func resizeDidEnd(workspace: Workspace) {
|
||||
self.neoVimView.exitResizeMode()
|
||||
}
|
||||
|
||||
func toggled(tool: WorkspaceTool) {
|
||||
self.publish(event: MainWindowAction.toggleTool(tool: tool))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - File Menu Item Actions
|
||||
|
@ -8,25 +8,36 @@ import RxSwift
|
||||
import PureLayout
|
||||
import CocoaMarkdown
|
||||
|
||||
enum PreviewRendererAction {
|
||||
protocol PreviewRenderer: class {
|
||||
|
||||
case htmlString(html: String)
|
||||
case error
|
||||
}
|
||||
|
||||
class MarkdownRenderer: StandardFlow {
|
||||
enum PreviewRendererAction {
|
||||
|
||||
case htmlString(renderer: PreviewRenderer, html: String)
|
||||
case error(renderer: PreviewRenderer)
|
||||
}
|
||||
|
||||
class MarkdownRenderer: StandardFlow, PreviewRenderer {
|
||||
|
||||
fileprivate let extensions = Set([ "md", "markdown", ])
|
||||
|
||||
fileprivate func canRender(fileExtension: String) -> Bool {
|
||||
return extensions.contains(fileExtension)
|
||||
}
|
||||
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PreviewAction }
|
||||
.map { $0 as! PreviewAction }
|
||||
.subscribe(onNext: { action in
|
||||
.map { action in
|
||||
switch action {
|
||||
case let .refresh(url):
|
||||
self.render(from: url)
|
||||
|
||||
case let .automaticRefresh(url):
|
||||
return url
|
||||
}
|
||||
})
|
||||
}
|
||||
.filter { self.canRender(fileExtension: $0.pathExtension) }
|
||||
.subscribe(onNext: { [unowned self] url in self.render(from: url) })
|
||||
}
|
||||
|
||||
fileprivate func render(from url: URL) {
|
||||
@ -38,6 +49,6 @@ class MarkdownRenderer: StandardFlow {
|
||||
return
|
||||
}
|
||||
|
||||
self.publish(event: PreviewRendererAction.htmlString(html: html))
|
||||
self.publish(event: PreviewRendererAction.htmlString(renderer: self, html: html))
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import WebKit
|
||||
|
||||
enum PreviewAction {
|
||||
|
||||
case refresh(url: URL)
|
||||
case automaticRefresh(url: URL)
|
||||
}
|
||||
|
||||
struct PreviewPrefData: StandardPrefData {
|
||||
@ -38,6 +38,12 @@ class PreviewComponent: NSView, ViewComponent {
|
||||
|
||||
fileprivate let webview = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
|
||||
|
||||
fileprivate var currentRenderer: PreviewRenderer?
|
||||
|
||||
fileprivate let renderers: [PreviewRenderer]
|
||||
|
||||
fileprivate var isOpen = false
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
@ -54,13 +60,16 @@ class PreviewComponent: NSView, ViewComponent {
|
||||
self.flow = EmbeddableComponent(source: source)
|
||||
self.markdownRenderer = MarkdownRenderer(source: self.flow.sink)
|
||||
|
||||
self.renderers = [
|
||||
self.markdownRenderer,
|
||||
]
|
||||
|
||||
super.init(frame: .zero)
|
||||
self.configureForAutoLayout()
|
||||
|
||||
self.flow.set(subscription: self.subscription)
|
||||
|
||||
|
||||
self.webview.loadHTMLString(self.previewService.emptyPreview(), baseURL: nil)
|
||||
self.webview.loadHTMLString(self.previewService.emptyHtml(), baseURL: nil)
|
||||
|
||||
self.addViews()
|
||||
self.addReactions()
|
||||
@ -82,12 +91,18 @@ class PreviewComponent: NSView, ViewComponent {
|
||||
.subscribe(onNext: { action in
|
||||
switch action {
|
||||
|
||||
case let .currentBufferChanged(mainWindow, currentBuffer):
|
||||
case let .currentBufferChanged(_, currentBuffer):
|
||||
guard let url = currentBuffer.url else {
|
||||
return
|
||||
}
|
||||
|
||||
self.flow.publish(event: PreviewAction.refresh(url: url))
|
||||
self.flow.publish(event: PreviewAction.automaticRefresh(url: url))
|
||||
|
||||
case let .toggleTool(tool):
|
||||
guard tool.view == self else {
|
||||
return
|
||||
}
|
||||
self.isOpen = tool.isSelected
|
||||
|
||||
default:
|
||||
return
|
||||
@ -100,14 +115,18 @@ class PreviewComponent: NSView, ViewComponent {
|
||||
self.markdownRenderer.sink
|
||||
.filter { $0 is PreviewRendererAction }
|
||||
.map { $0 as! PreviewRendererAction }
|
||||
.subscribe(onNext: { action in
|
||||
.subscribe(onNext: { [unowned self] action in
|
||||
guard self.isOpen else {
|
||||
return
|
||||
}
|
||||
|
||||
switch action {
|
||||
|
||||
case let .htmlString(html):
|
||||
case let .htmlString(_, html):
|
||||
self.webview.loadHTMLString(html, baseURL: nil)
|
||||
|
||||
case .error:
|
||||
self.webview.loadHTMLString(self.previewService.emptyPreview(), baseURL: nil)
|
||||
self.webview.loadHTMLString(self.previewService.errorHtml(), baseURL: nil)
|
||||
|
||||
}
|
||||
})
|
||||
|
@ -7,25 +7,52 @@ import Foundation
|
||||
|
||||
class PreviewService {
|
||||
|
||||
fileprivate let emptyPreviewHtml: String
|
||||
fileprivate let empty: String
|
||||
fileprivate let error: String
|
||||
fileprivate let saveFirst: String
|
||||
|
||||
init() {
|
||||
guard let emptyUrl = Bundle.main.url(forResource: "empty", withExtension: "html", subdirectory: "preview") else {
|
||||
preconditionFailure("No empty.html!")
|
||||
}
|
||||
|
||||
guard let emptyUrl = Bundle.main.url(forResource: "empty-preview",
|
||||
withExtension: "html",
|
||||
subdirectory: "preview")
|
||||
guard let errorUrl = Bundle.main.url(forResource: "error", withExtension: "html", subdirectory: "preview") else {
|
||||
preconditionFailure("No error.html!")
|
||||
}
|
||||
|
||||
guard let saveFirstUrl = Bundle.main.url(forResource: "error",
|
||||
withExtension: "html",
|
||||
subdirectory: "preview")
|
||||
else {
|
||||
preconditionFailure("No empty-preview.html!")
|
||||
preconditionFailure("No save-first.html!")
|
||||
}
|
||||
|
||||
guard let emptyHtml = try? String(contentsOf: emptyUrl) else {
|
||||
preconditionFailure("Error getting empty-preview.html!")
|
||||
preconditionFailure("Error getting empty.html!")
|
||||
}
|
||||
|
||||
self.emptyPreviewHtml = emptyHtml
|
||||
guard let errorHtml = try? String(contentsOf: errorUrl) else {
|
||||
preconditionFailure("Error getting error.html!")
|
||||
}
|
||||
|
||||
guard let saveFirstHtml = try? String(contentsOf: saveFirstUrl) else {
|
||||
preconditionFailure("Error getting save-first.html!")
|
||||
}
|
||||
|
||||
self.empty = emptyHtml
|
||||
self.error = errorHtml
|
||||
self.saveFirst = saveFirstHtml
|
||||
}
|
||||
|
||||
func emptyPreview() -> String {
|
||||
return self.emptyPreviewHtml
|
||||
func emptyHtml() -> String {
|
||||
return self.empty
|
||||
}
|
||||
|
||||
func errorHtml() -> String {
|
||||
return self.error
|
||||
}
|
||||
|
||||
func saveFirstHtml() -> String {
|
||||
return self.saveFirst
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ protocol WorkspaceDelegate: class {
|
||||
|
||||
func resizeWillStart(workspace: Workspace)
|
||||
func resizeDidEnd(workspace: Workspace)
|
||||
|
||||
func toggled(tool: WorkspaceTool)
|
||||
}
|
||||
|
||||
class Workspace: NSView, WorkspaceBarDelegate {
|
||||
@ -196,6 +198,10 @@ extension Workspace {
|
||||
func resizeDidEnd(workspaceBar: WorkspaceBar) {
|
||||
self.delegate?.resizeDidEnd(workspace: self)
|
||||
}
|
||||
|
||||
func toggle(tool: WorkspaceTool) {
|
||||
self.delegate?.toggled(tool: tool)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Layout
|
||||
|
@ -10,6 +10,8 @@ protocol WorkspaceBarDelegate: class {
|
||||
|
||||
func resizeWillStart(workspaceBar: WorkspaceBar)
|
||||
func resizeDidEnd(workspaceBar: WorkspaceBar)
|
||||
|
||||
func toggle(tool: WorkspaceTool)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -835,5 +837,6 @@ extension WorkspaceBar {
|
||||
self.relayout()
|
||||
|
||||
self.delegate?.resizeDidEnd(workspaceBar: self)
|
||||
self.delegate?.toggle(tool: tool)
|
||||
}
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ class WorkspaceTool: NSView {
|
||||
}
|
||||
|
||||
func toggle() {
|
||||
self.delegate?.toggle(self)
|
||||
self.isSelected = !self.isSelected
|
||||
self.delegate?.toggle(self)
|
||||
}
|
||||
|
||||
fileprivate func addViews() {
|
||||
|
62
VimR/preview/base.css
Normal file
62
VimR/preview/base.css
Normal file
@ -0,0 +1,62 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
#message {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: small;
|
||||
color: gray;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Empty</title>
|
||||
</head>
|
||||
<body style="font-family: -apple-system; background-color: white;">
|
||||
<div style="text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
||||
<span style="font-size: x-large;">😶</span><br>
|
||||
<span style="font-size: small; color: gray;">no preview...</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
VimR/preview/empty.html
Normal file
14
VimR/preview/empty.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="base.css">
|
||||
<title>Empty</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message">
|
||||
<h1>😶</h1>
|
||||
<span class="info-text">no preview...</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
VimR/preview/error.html
Normal file
14
VimR/preview/error.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="base.css">
|
||||
<title>Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message">
|
||||
<h1>😱</h1>
|
||||
<span class="info-text">There was an error...</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Empty</title>
|
||||
</head>
|
||||
<body style="font-family: -apple-system; background-color: white;">
|
||||
<div style="text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
||||
<span style="font-size: x-large;">😌</span><br>
|
||||
<span style="font-size: small; color: gray;">save the file first for preview...</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
VimR/preview/save-first.html
Normal file
14
VimR/preview/save-first.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="base.css">
|
||||
<title>Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message">
|
||||
<h1>😶</h1>
|
||||
<span class="info-text">Save first for preview</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
2
neovim
2
neovim
@ -1 +1 @@
|
||||
Subproject commit 3fa28dc5807196447f1da8ca793fd0b048fedea1
|
||||
Subproject commit 157d037a7c1f28c3e6a518f34608f68682535ed3
|
Loading…
Reference in New Issue
Block a user