diff --git a/Sources/XiEditor/Client.swift b/Sources/XiEditor/Client.swift index 6c164225..c6511e63 100644 --- a/Sources/XiEditor/Client.swift +++ b/Sources/XiEditor/Client.swift @@ -86,4 +86,7 @@ protocol XiClient: AnyObject { /// A notification containing the current replace status. func replaceStatus(viewIdentifier: String, status: ReplaceStatus) + + /// A notification telling whether tail was enabled/disabled. + func enableTailing(viewIdentifier: String, isTailEnabled: Bool) } diff --git a/Sources/XiEditor/ClientImplementation.swift b/Sources/XiEditor/ClientImplementation.swift index 02cfa0c9..b514390d 100644 --- a/Sources/XiEditor/ClientImplementation.swift +++ b/Sources/XiEditor/ClientImplementation.swift @@ -176,6 +176,14 @@ class ClientImplementation: XiClient, DocumentsProviding, ConfigCacheProviding, } } } + + func enableTailing(viewIdentifier: String, isTailEnabled: Bool) { + let document = documentForViewIdentifier(viewIdentifier: viewIdentifier) + DispatchQueue.main.async { + document?.editViewController?.enableTailing(isTailEnabled) + } + } + // Stores the config dict so new windows don't have to wait for core to send it. // The main purpose of this is ensuring that `unified_titlebar` applies immediately. diff --git a/Sources/XiEditor/Core/CoreNotification.swift b/Sources/XiEditor/Core/CoreNotification.swift index d7422565..e42e3971 100644 --- a/Sources/XiEditor/Core/CoreNotification.swift +++ b/Sources/XiEditor/Core/CoreNotification.swift @@ -71,6 +71,7 @@ enum CoreNotification { case findStatus(viewIdentifier: ViewIdentifier, status: [FindStatus]) case replaceStatus(viewIdentifier: ViewIdentifier, status: ReplaceStatus) + case enableTailing(viewIdentifier: ViewIdentifier, isTailEnabled: Bool) static func fromJson(_ json: [String: Any]) -> CoreNotification? { guard @@ -228,6 +229,11 @@ enum CoreNotification { { return .replaceStatus(viewIdentifier: viewIdentifier!, status: replaceStatus) } + case "enable_tailing": + if let isTailEnabled = jsonParams["is_tail_enabled"] as? Bool + { + return .enableTailing(viewIdentifier: viewIdentifier!, isTailEnabled: isTailEnabled) + } default: assertionFailure("Unsupported notification method from core: \(jsonMethod)") diff --git a/Sources/XiEditor/EditViewController.swift b/Sources/XiEditor/EditViewController.swift index d4db2b66..695e86e3 100644 --- a/Sources/XiEditor/EditViewController.swift +++ b/Sources/XiEditor/EditViewController.swift @@ -152,6 +152,11 @@ class EditViewController: NSViewController, EditViewDataSource, FindDelegate, Sc updateLanguageMenu() } } + + /// Flag to determine if current file is being tailed. + var isTailEnabled: Bool = false + + var isExistingFile: Bool = false // used to calculate the gutter width. Initial -1 so that a new document // still triggers update of gutter width. @@ -329,6 +334,12 @@ class EditViewController: NSViewController, EditViewDataSource, FindDelegate, Sc _previousViewportSize = CGSize.zero redrawEverything() } + + func enableTailMenu() { + let toggleTailSubMenu = NSApplication.shared.mainMenu!.item(withTitle: "Debug")!.submenu!.item(withTitle: "Tail File") + toggleTailSubMenu!.isEnabled = true + self.isExistingFile = true + } /// If font size or theme changes, we invalidate all views. func redrawEverything() { @@ -711,6 +722,10 @@ class EditViewController: NSViewController, EditViewDataSource, FindDelegate, Sc document.xiCore.setTheme(themeName: sender.title) } + @IBAction func debugToggleTail(_ sender: NSMenuItem) { + document.xiCore.toggleTailConfig(identifier: document.coreViewIdentifier!, enabled: !self.isTailEnabled) + } + @IBAction func debugSetLanguage(_ sender: NSMenuItem) { guard sender.state != NSControl.StateValue.on else { print("language already active"); return } document.xiCore.setLanguage(identifier: document.coreViewIdentifier!, languageName: sender.title) @@ -840,11 +855,28 @@ class EditViewController: NSViewController, EditViewDataSource, FindDelegate, Sc item.state = findViewController.showMultipleSearchQueries ? .on : .off } + func updateTailMenu() { + let toggleTailSubMenu = NSApplication.shared.mainMenu!.item(withTitle: "Debug")!.submenu!.item(withTitle: "Tail File") + if self.isExistingFile { + toggleTailSubMenu!.isEnabled = true + if self.isTailEnabled { + toggleTailSubMenu!.state = NSControl.StateValue.on + } else { + toggleTailSubMenu!.state = NSControl.StateValue.off + } + } else { + toggleTailSubMenu!.isEnabled = false + toggleTailSubMenu!.state = NSControl.StateValue.off + self.isTailEnabled = false + } + } + // Gets called when active window changes func updateMenuState() { updatePluginMenu() updateLanguageMenu() updateFindMenu() + updateTailMenu() } @objc func handleCommand(_ sender: NSMenuItem) { @@ -919,6 +951,11 @@ class EditViewController: NSViewController, EditViewDataSource, FindDelegate, Sc languagesMenu.addItem(item) } } + + public func enableTailing(_ isTailEnabled: Bool) { + self.isTailEnabled = isTailEnabled + self.updateTailMenu() + } @IBAction func gotoLine(_ sender: AnyObject) { guard let window = self.view.window else { return } diff --git a/Sources/XiEditor/Main.storyboard b/Sources/XiEditor/Main.storyboard index 1dfe620d..c802a991 100644 --- a/Sources/XiEditor/Main.storyboard +++ b/Sources/XiEditor/Main.storyboard @@ -1111,7 +1111,7 @@ Gw - + @@ -1209,6 +1209,12 @@ Gw + + + + + + @@ -1238,6 +1244,7 @@ Gw + diff --git a/Sources/XiEditor/RPCSending.swift b/Sources/XiEditor/RPCSending.swift index 7dcc44bb..88d6331b 100644 --- a/Sources/XiEditor/RPCSending.swift +++ b/Sources/XiEditor/RPCSending.swift @@ -309,6 +309,8 @@ class StdoutRPCSender: RPCSending { self.client?.findStatus(viewIdentifier: viewIdentifier, status: status) case let .replaceStatus(viewIdentifier, status): self.client?.replaceStatus(viewIdentifier: viewIdentifier, status: status) + case let .enableTailing(viewIdentifier, isTailEnabled): + self.client?.enableTailing(viewIdentifier: viewIdentifier, isTailEnabled: isTailEnabled) } } diff --git a/Sources/XiEditor/XiCore.swift b/Sources/XiEditor/XiCore.swift index dd120d58..02dbbb4f 100644 --- a/Sources/XiEditor/XiCore.swift +++ b/Sources/XiEditor/XiCore.swift @@ -48,6 +48,9 @@ protocol XiCore: class { /// `Document` calls are migrated to it's own protocol. func sendRpcAsync(_ method: String, params: Any, callback: RpcCallback?) func sendRpc(_ method: String, params: Any) -> RpcResult + /// Will tail opened file if enabled. + /// If toggle succeeds the client will receive a `toggle_tail_config_changed` notification. + func toggleTailConfig(identifier: ViewIdentifier, enabled: Bool) } final class CoreConnection: XiCore { @@ -109,6 +112,10 @@ final class CoreConnection: XiCore { let params = ["destination": destination, "frontend_samples": frontendSamples] as AnyObject sendRpcAsync("save_trace", params: params) } + + func toggleTailConfig(identifier: ViewIdentifier, enabled: Bool) { + sendRpcAsync("toggle_tail", params: ["view_id": identifier, "enabled": enabled]) + } func sendRpcAsync(_ method: String, params: Any, callback: RpcCallback? = nil) { rpcSender.sendRpcAsync(method, params: params, callback: callback) diff --git a/Sources/XiEditor/XiDocumentController.swift b/Sources/XiEditor/XiDocumentController.swift index 6a5a2a97..c7d875f4 100644 --- a/Sources/XiEditor/XiDocumentController.swift +++ b/Sources/XiEditor/XiDocumentController.swift @@ -133,6 +133,7 @@ class XiDocumentController: NSDocumentController, AlertPresenting { currentDocument.fileURL = url self.setIdentifier(result, forDocument: currentDocument) currentDocument.editViewController!.prepareForReuse() + currentDocument.editViewController!.enableTailMenu() completionHandler(currentDocument, false, nil) case .error(let error): @@ -182,6 +183,10 @@ class XiDocumentController: NSDocumentController, AlertPresenting { let viewIdentifier = result as! String self.setIdentifier(viewIdentifier, forDocument: document) document.coreViewIdentifier = viewIdentifier + if url != nil { + document.editViewController?.isExistingFile = true + } + document.editViewController?.updateTailMenu() case .error(let error): document.close() self.showAlert(with: error.message) diff --git a/Tests/IntegrationTests/TestClientImplementation.swift b/Tests/IntegrationTests/TestClientImplementation.swift index 4cde8f95..de395594 100644 --- a/Tests/IntegrationTests/TestClientImplementation.swift +++ b/Tests/IntegrationTests/TestClientImplementation.swift @@ -86,4 +86,7 @@ class TestClientImplementation: XiClient { func replaceStatus(viewIdentifier: String, status: ReplaceStatus) { } + + func enableTailing(viewIdentifier: String, isTailEnabled: Bool) { + } }