Skip to content

Commit

Permalink
Merge pull request xi-editor#171 from cmyr/fix-open-behaviour
Browse files Browse the repository at this point in the history
Reuse empty views when opening a new document
  • Loading branch information
raphlinus committed Mar 2, 2017
2 parents e8f6f55 + d318747 commit dedd956
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
5 changes: 4 additions & 1 deletion XiEditor/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var dispatcher: Dispatcher?
var styleMap: StyleMap = StyleMap()

/// used internally to force open to an existing empty document when present.
var _documentForNextOpenCall: Document?

func applicationWillFinishLaunching(_ aNotification: Notification) {

guard let corePath = Bundle.main.path(forResource: "xi-core", ofType: "")
Expand All @@ -46,7 +49,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
return nil
}

func handleCoreCmd(_ json: Any) {
guard let obj = json as? [String : Any],
let method = obj["method"] as? String,
Expand Down
44 changes: 34 additions & 10 deletions XiEditor/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class Document: NSDocument {
var pendingNotifications: [PendingNotification] = [];
var editViewController: EditViewController?

/// used to keep track of whether we're in the process of reusing an empty window
fileprivate var _skipShowingWindow = false

override init() {
dispatcher = (NSApplication.shared().delegate as? AppDelegate)?.dispatcher
super.init()
Expand All @@ -44,25 +47,46 @@ class Document: NSDocument {
}

override func makeWindowControllers() {
// Returns the Storyboard that contains your Document window.
let storyboard = NSStoryboard(name: "Main", bundle: nil)
let windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as! NSWindowController
var windowController: NSWindowController!
// check to see if we should reuse another document's window
if let delegate = (NSApplication.shared().delegate as? AppDelegate), let existing = delegate._documentForNextOpenCall {
assert(existing.windowControllers.count == 1, "each document should only and always own a single windowController")
windowController = existing.windowControllers[0]
delegate._documentForNextOpenCall = nil
// if we're reusing an existing window, we want to noop on the `showWindows()` call we receive from the DocumentController
_skipShowingWindow = true
} else {
// if we aren't reusing, create a new window as normal:
let storyboard = NSStoryboard(name: "Main", bundle: nil)
windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as! NSWindowController

//FIXME: some saner way of positioning new windows. maybe based on current window size, with some checks to not completely obscure an existing window?
// also awareness of multiple screens (prefer to open on currently active screen)
let screenHeight = windowController.window?.screen?.frame.height ?? 800
let windowHeight: CGFloat = 800
windowController.window?.setFrame(NSRect(x: 200, y: screenHeight - windowHeight - 200, width: 700, height: 800), display: true)
}

self.editViewController = windowController.contentViewController as? EditViewController
editViewController?.document = self
windowController.window?.delegate = editViewController

self.addWindowController(windowController)

Events.NewTab().dispatchWithCallback(dispatcher!) { (tabName) in
DispatchQueue.main.async {
self.tabName = tabName
}
}
//FIXME: some saner way of positioning new windows. maybe based on current window size, with some checks to not completely obscure an existing window?
// also awareness of multiple screens (prefer to open on currently active screen)
let screenHeight = windowController.window?.screen?.frame.height ?? 800
let windowHeight: CGFloat = 800
windowController.window?.setFrame(NSRect(x: 200, y: screenHeight - windowHeight - 200, width: 700, height: 800), display: true)
}

self.addWindowController(windowController)
override func showWindows() {
// part of our code to reuse existing windows when opening documents
assert(windowControllers.count == 1, "documents should have a single window controller")
if !(_skipShowingWindow) {
super.showWindows()
} else {
_skipShowingWindow = false
}
}

override func read(from url: URL, ofType typeName: String) throws {
Expand Down
8 changes: 8 additions & 0 deletions XiEditor/EditViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ class EditViewController: NSViewController {
document?.sendRpcAsync("insert", params: insertedStringToJson(insertString as! NSString))
}

// we override this to see if our view is empty, and should be reused for this open call
func openDocument(_ sender: Any?) {
if editView?.lines.isEmpty ?? false {
(NSApplication.shared().delegate as? AppDelegate)?._documentForNextOpenCall = self.document
}
NSDocumentController.shared().openDocument(sender)
}

// MARK: - Menu Items
fileprivate func cutCopy(_ method: String) {
let text = document?.sendRpc(method, params: [])
Expand Down
7 changes: 7 additions & 0 deletions XiEditor/LineCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ class LineCache {
return nInvalidBefore + lines.count + nInvalidAfter
}
}

/// A boolean value indicating whether or not the linecache contains any text.
/// - Note: An empty line cache will still contain a single empty line, this
/// is sent as an update from the core after a new document is created.
var isEmpty: Bool {
return lines.count == 0 || (lines.count == 1 && lines[0]?.text == "")
}

func get(_ ix: Int) -> Line? {
if ix < nInvalidBefore { return nil }
Expand Down

0 comments on commit dedd956

Please sign in to comment.