               let dirty = info["modified"]?.boolValue,
               let buftype = info["buftype"]?.stringValue,
               let listed = info["buflisted"]?.boolValue
-          else {
-          throw RxNeovimApi.Error.exception(message: "Could not convert values from the dictionary.")
+        else {
+          throw RxNeovimApi.Error
+            .exception(message: "Could not convert values from the dictionary.")
         }
 
         let url = path == "" || buftype != "" ? nil : URL(fileURLWithPath: path)
 
-        return NvimView.Buffer(apiBuffer: buf,
-                               url: url,
-                               type: buftype,
-                               isDirty: dirty,
-                               isCurrent: current,
-                               isListed: listed)
-      }
-      .subscribeOn(self.scheduler)
-  }
-
-  private func `open`(_ url: URL, cmd: String) -> Completable {
-    return self.api
+        return NvimView.Buffer(
+          apiBuffer: buf,
+          url: url,
+          type: buftype,
+          isDirty: dirty,
+          isCurrent: current,
+          isListed: listed
+        )
+      }
+      .subscribeOn(self.scheduler)
+  }
+
+  private func open(_ url: URL, cmd: String) -> Completable {
+    self.api
       .command(command: "\(cmd) \(url.path)")
       .subscribeOn(self.scheduler)
   }
 
-  private func neoVimWindow(for window: RxNeovimApi.Window,
-                            currentWindow: RxNeovimApi.Window?,
-                            currentBuffer: RxNeovimApi.Buffer?) -> Single<NvimView.Window> {
-
-    return self.api
+  private func neoVimWindow(
+    for window: RxNeovimApi.Window,
+    currentWindow: RxNeovimApi.Window?,
+    currentBuffer: RxNeovimApi.Buffer?
+  ) -> Single<NvimView.Window> {
+    self.api
       .winGetBuf(window: window)
       .flatMap { buf in self.neoVimBuffer(for: buf, currentBuffer: currentBuffer) }
-      .map { buffer in NvimView.Window(apiWindow: window, buffer: buffer, isCurrentInTab: window == currentWindow) }
-  }
-
-  private func neoVimTab(for tabpage: RxNeovimApi.Tabpage,
-                         currentTabpage: RxNeovimApi.Tabpage?,
-                         currentBuffer: RxNeovimApi.Buffer?) -> Single<NvimView.Tabpage> {
-
-    return Single.zip(
-        self.api.tabpageGetWin(tabpage: tabpage),
-        self.api.tabpageListWins(tabpage: tabpage)) { (curWin: $0, wins: $1) }
+      .map { buffer in NvimView.Window(
+        apiWindow: window,
+        buffer: buffer,
+        isCurrentInTab: window == currentWindow
+      ) }
+  }
+
+  private func neoVimTab(
+    for tabpage: RxNeovimApi.Tabpage,
+    currentTabpage: RxNeovimApi.Tabpage?,
+    currentBuffer: RxNeovimApi.Buffer?
+  ) -> Single<NvimView.Tabpage> {
+    Single.zip(
+      self.api.tabpageGetWin(tabpage: tabpage),
+      self.api.tabpageListWins(tabpage: tabpage)
+    ) { (curWin: $0, wins: $1) }
       .map { tuple in
         tuple.wins.map { win in
-          return self.neoVimWindow(for: win, currentWindow: tuple.curWin, currentBuffer: currentBuffer)
+          self.neoVimWindow(for: win, currentWindow: tuple.curWin, currentBuffer: currentBuffer)
         }
       }
       .flatMap(Single.fromSinglesToSingleOfArray)
-      .map { wins in NvimView.Tabpage(apiTabpage: tabpage, windows: wins, isCurrent: tabpage == currentTabpage) }
+      .map { wins in
+        NvimView.Tabpage(apiTabpage: tabpage, windows: wins, isCurrent: tabpage == currentTabpage)
+      }
   }
 }

 */

import Cocoa
import RxSwift
import MessagePack
import RxPack

extension NvimView {

  public func isBlocked() -> Single<Bool> {
    return self.api.getMode().map { dict in dict["blocking"]?.boolValue ?? false }
  }

  public func hasDirtyBuffers() -> Single<Bool> {
    return self.api.getDirtyStatus()
  }

  public func waitTillNvimExits() {
    self.nvimExitedCondition.wait(for: 5)
  }

  public func enterResizeMode() {
    self.currentlyResizing = true
    self.markForRenderWholeView()
  }

  public func exitResizeMode() {
    self.currentlyResizing = false
    self.markForRenderWholeView()
    self.resizeNeoVimUi(to: self.bounds.size)
  }

  public func currentBuffer() -> Single<NvimView.Buffer> {
    return self.api
      .getCurrentBuf()
      .flatMap { self.neoVimBuffer(for: $0, currentBuffer: $0) }
      .subscribeOn(self.scheduler)
  }

  public func allBuffers() -> Single<[NvimView.Buffer]> {
    return Single
      .zip(self.api.getCurrentBuf(), self.api.listBufs()) { (curBuf: $0, bufs: $1) }
      .map { tuple in tuple.bufs.map { buf in self.neoVimBuffer(for: buf, currentBuffer: tuple.curBuf) } }
      .flatMap(Single.fromSinglesToSingleOfArray)
      .subscribeOn(self.scheduler)
  }

  public func isCurrentBufferDirty() -> Single<Bool> {
    return self
      .currentBuffer()
      .map { $0.isDirty }
      .subscribeOn(self.scheduler)
  }

  public func allTabs() -> Single<[NvimView.Tabpage]> {
    return Single.zip(self.api.getCurrentBuf(),
                      self.api.getCurrentTabpage(),
                      self.api.listTabpages()) { (curBuf: $0, curTab: $1, tabs: $2) }
      .map { tuple in
        return tuple.tabs.map { tab in
          return self.neoVimTab(for: tab, currentTabpage: tuple.curTab, currentBuffer: tuple.curBuf)
        }
      }
      .flatMap(Single.fromSinglesToSingleOfArray)
      .subscribeOn(self.scheduler)
  }

  public func newTab() -> Completable {
    return self.api
      .command(command: "tabe")
      .subscribeOn(self.scheduler)
  }

  public func `open`(urls: [URL]) -> Completable {
    return self
      .allTabs()
      .flatMapCompletable { tabs -> Completable in
        let buffers = tabs.map { $0.windows }.flatMap { $0 }.map { $0.buffer }
        let currentBufferIsTransient = buffers.first { $0.isCurrent }?.isTransient ?? false

        return Completable.concat(
          urls.map { url -> Completable in
            let bufExists = buffers.contains { $0.url == url }
            let wins = tabs.map({ $0.windows }).flatMap({ $0 })
            if let win = bufExists ? wins.first(where: { win in win.buffer.url == url }) : nil {
              return self.api.setCurrentWin(window: RxNeovimApi.Window(win.handle))
            }

      .subscribeOn(self.scheduler)
  }

  func goTo(line: Int) -> Completable {
    self.api.command(command: "\(line)")
  }

  /// Closes the current window.
  func closeCurrentTab() -> Completable {
    self.api
      .command(command: "q")
      .subscribeOn(self.scheduler)
  }

  func saveCurrentTab() -> Completable {
    self.api
      .command(command: "w")
      .subscribeOn(self.scheduler)
  }

  func saveCurrentTab(url: URL) -> Completable {
    self.api
      .command(command: "w \(url.path)")
      .subscribeOn(self.scheduler)
  }

  func closeCurrentTabWithoutSaving() -> Completable {
    self.api
      .command(command: "q!")
      .subscribeOn(self.scheduler)
  }

  func quitNeoVimWithoutSaving() -> Completable {
    self.api
      .command(command: "qa!")
      .subscribeOn(self.scheduler)
  }

  func vimOutput(of command: String) -> Single<String> {
    self.api
      .exec(src: command, output: true)
      .subscribeOn(self.scheduler)
  }

  func cursorGo(to position: Position) -> Completable {
    self.api
      .getCurrentWin()
      .flatMapCompletable { curWin in
        self.api.winSetCursor(window: curWin, pos: [position.row, position.column])
      }
      .subscribeOn(self.scheduler)
  }

  func didBecomeMain() -> Completable { self.bridge.focusGained(true) }

  func didResignMain() -> Completable { self.bridge.focusGained(false) }

  internal func neoVimBuffer(
    for buf: RxNeovimApi.Buffer,
    currentBuffer: RxNeovimApi.Buffer?
  ) -> Single<NvimView.Buffer> {
    self.api
      .bufGetInfo(buffer: buf)
      .map { info -> NvimView.Buffer in
        let current = buf == currentBuffer
