1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-24 22:33:52 +03:00

GH-227 It compiles, it compiles

This commit is contained in:
Tae Won Ha 2016-09-25 17:50:33 +02:00
parent d29c67064e
commit 0f7b564667
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
50 changed files with 1005 additions and 1007 deletions

View File

@ -1,3 +1,3 @@
github "ReactiveX/RxSwift" == 2.6.0 github "ReactiveX/RxSwift" "3.0.0-beta.1"
github "PureLayout/PureLayout" == 3.0.2 github "PureLayout/PureLayout" == 3.0.2
github "eonil/FileSystemEvents" "master" github "eonil/FileSystemEvents" "master"

View File

@ -1 +1 @@
github "Quick/Nimble" == 4.1.0 github "Quick/Nimble" == 5.0.0

View File

@ -1,4 +1,4 @@
github "eonil/FileSystemEvents" "01f622d3b446612d573b1035b46afb7a6eee0240" github "eonil/FileSystemEvents" "aa5c6af1fd35939f9aca3b9eba3b672bfa549b3a"
github "Quick/Nimble" "v4.1.0" github "Quick/Nimble" "v5.0.0"
github "PureLayout/PureLayout" "v3.0.2" github "PureLayout/PureLayout" "v3.0.2"
github "ReactiveX/RxSwift" "2.6.0" github "ReactiveX/RxSwift" "3.0.0-beta.1"

View File

@ -30,7 +30,7 @@ extension NSView {
/// - Returns: Rects currently being drawn /// - Returns: Rects currently being drawn
/// - Warning: Call only in drawRect() /// - Warning: Call only in drawRect()
func rectsBeingDrawn() -> [CGRect] { func rectsBeingDrawn() -> [CGRect] {
var rectsPtr: UnsafePointer<CGRect> = nil var rectsPtr: UnsafePointer<CGRect>? = nil
var count: Int = 0 var count: Int = 0
self.getRectsBeingDrawn(&rectsPtr, count: &count) self.getRectsBeingDrawn(&rectsPtr, count: &count)

View File

@ -7,11 +7,11 @@ import Cocoa
class ColorUtils { class ColorUtils {
static func colorIgnoringAlpha(rgb: UInt32) -> NSColor { static func colorIgnoringAlpha(_ rgb: UInt32) -> NSColor {
let red = (CGFloat((rgb >> 16) & 0xFF)) / 255.0; let red = (CGFloat((rgb >> 16) & 0xFF)) / 255.0;
let green = (CGFloat((rgb >> 8) & 0xFF)) / 255.0; let green = (CGFloat((rgb >> 8) & 0xFF)) / 255.0;
let blue = (CGFloat((rgb ) & 0xFF)) / 255.0; let blue = (CGFloat((rgb ) & 0xFF)) / 255.0;
return NSColor(SRGBRed: red, green: green, blue: blue, alpha: 1.0) return NSColor(srgbRed: red, green: green, blue: blue, alpha: 1.0)
} }
} }

View File

@ -5,11 +5,11 @@
import Cocoa import Cocoa
public class DispatchUtils { open class DispatchUtils {
private static let qDispatchMainQueue = dispatch_get_main_queue() fileprivate static let qDispatchMainQueue = DispatchQueue.main
public static func gui(call: () -> Void) { open static func gui(_ call: @escaping () -> Void) {
dispatch_async(DispatchUtils.qDispatchMainQueue, call) DispatchUtils.qDispatchMainQueue.async(execute: call)
} }
} }

View File

@ -6,7 +6,7 @@
import Cocoa import Cocoa
struct Cell: CustomStringConvertible { struct Cell: CustomStringConvertible {
private let attributes: CellAttributes fileprivate let attributes: CellAttributes
let string: String let string: String
var marked: Bool var marked: Bool
@ -72,11 +72,11 @@ struct Region: CustomStringConvertible {
return "Region<\(self.top)...\(self.bottom):\(self.left)...\(self.right)>" return "Region<\(self.top)...\(self.bottom):\(self.left)...\(self.right)>"
} }
var rowRange: Range<Int> { var rowRange: CountableClosedRange<Int> {
return self.top...self.bottom return self.top...self.bottom
} }
var columnRange: Range<Int> { var columnRange: CountableClosedRange<Int> {
return self.left...self.right return self.left...self.right
} }
} }
@ -84,10 +84,10 @@ struct Region: CustomStringConvertible {
/// Almost a verbatim copy of ugrid.c of NeoVim /// Almost a verbatim copy of ugrid.c of NeoVim
class Grid: CustomStringConvertible { class Grid: CustomStringConvertible {
private(set) var region = Region.zero fileprivate(set) var region = Region.zero
private(set) var size = Size.zero fileprivate(set) var size = Size.zero
private(set) var putPosition = Position.zero fileprivate(set) var putPosition = Position.zero
private(set) var screenCursor = Position.zero fileprivate(set) var screenCursor = Position.zero
var foreground = qDefaultForeground var foreground = qDefaultForeground
var background = qDefaultBackground var background = qDefaultBackground
@ -95,11 +95,11 @@ class Grid: CustomStringConvertible {
var dark = false var dark = false
var attrs: CellAttributes = CellAttributes( var attrs: CellAttributes = CellAttributes(
fontTrait: .None, fontTrait: .none,
foreground: qDefaultForeground, background: qDefaultBackground, special: qDefaultSpecial foreground: qDefaultForeground, background: qDefaultBackground, special: qDefaultSpecial
) )
private(set) var cells: [[Cell]] = [] fileprivate(set) var cells: [[Cell]] = []
var hasData: Bool { var hasData: Bool {
return !self.cells.isEmpty return !self.cells.isEmpty
@ -109,16 +109,16 @@ class Grid: CustomStringConvertible {
return self.cells.reduce("<<< Grid\n") { $1.reduce($0) { $0 + $1.description } + "\n" } + ">>>" return self.cells.reduce("<<< Grid\n") { $1.reduce($0) { $0 + $1.description } + "\n" } + ">>>"
} }
func resize(size: Size) { func resize(_ size: Size) {
self.region = Region(top: 0, bottom: size.height - 1, left: 0, right: size.width - 1) self.region = Region(top: 0, bottom: size.height - 1, left: 0, right: size.width - 1)
self.size = size self.size = size
self.putPosition = Position.zero self.putPosition = Position.zero
let emptyCellAttrs = CellAttributes(fontTrait: .None, let emptyCellAttrs = CellAttributes(fontTrait: .none,
foreground: self.foreground, background: self.background, special: self.special) foreground: self.foreground, background: self.background, special: self.special)
let emptyRow = Array(count: size.width, repeatedValue: Cell(string: " ", attrs: emptyCellAttrs)) let emptyRow = Array(repeating: Cell(string: " ", attrs: emptyCellAttrs), count: size.width)
self.cells = Array(count: size.height, repeatedValue: emptyRow) self.cells = Array(repeating: emptyRow, count: size.height)
} }
func clear() { func clear() {
@ -132,11 +132,11 @@ class Grid: CustomStringConvertible {
) )
} }
func setScrollRegion(region: Region) { func setScrollRegion(_ region: Region) {
self.region = region self.region = region
} }
func scroll(count: Int) { func scroll(_ count: Int) {
var start, stop, step : Int var start, stop, step : Int
if count > 0 { if count > 0 {
start = self.region.top; start = self.region.top;
@ -150,8 +150,8 @@ class Grid: CustomStringConvertible {
// copy cell data // copy cell data
let rangeWithinRow = self.region.left...self.region.right let rangeWithinRow = self.region.left...self.region.right
for i in start.stride(to: stop, by: step) { for i in stride(from: start, to: stop, by: step) {
self.cells[i].replaceRange(rangeWithinRow, with: self.cells[i + count][rangeWithinRow]) self.cells[i].replaceSubrange(rangeWithinRow, with: self.cells[i + count][rangeWithinRow])
} }
// clear cells in the emptied region, // clear cells in the emptied region,
@ -166,15 +166,15 @@ class Grid: CustomStringConvertible {
self.clearRegion(Region(top: clearTop, bottom: clearBottom, left: self.region.left, right: self.region.right)) self.clearRegion(Region(top: clearTop, bottom: clearBottom, left: self.region.left, right: self.region.right))
} }
func goto(position: Position) { func goto(_ position: Position) {
self.putPosition = position self.putPosition = position
} }
func moveCursor(position: Position) { func moveCursor(_ position: Position) {
self.screenCursor = position self.screenCursor = position
} }
func put(string: String) { func put(_ string: String) {
// FIXME: handle the following situation: // FIXME: handle the following situation:
// |abcde | <- type // |abcde | <- type
// => // =>
@ -187,18 +187,18 @@ class Grid: CustomStringConvertible {
self.putPosition.column += 1 self.putPosition.column += 1
} }
func putMarkedText(string: String) { func putMarkedText(_ string: String) {
// NOTE: Maybe there's a better way to indicate marked text than inverting... // NOTE: Maybe there's a better way to indicate marked text than inverting...
self.cells[self.putPosition.row][self.putPosition.column] = Cell(string: string, attrs: self.attrs, marked: true) self.cells[self.putPosition.row][self.putPosition.column] = Cell(string: string, attrs: self.attrs, marked: true)
self.putPosition.column += 1 self.putPosition.column += 1
} }
func unmarkCell(position: Position) { func unmarkCell(_ position: Position) {
// NSLog("\(#function): \(position)") // NSLog("\(#function): \(position)")
self.cells[position.row][position.column].marked = false self.cells[position.row][position.column].marked = false
} }
func singleIndexFrom(position: Position) -> Int { func singleIndexFrom(_ position: Position) -> Int {
return position.row * self.size.width + position.column return position.row * self.size.width + position.column
} }
@ -215,7 +215,7 @@ class Grid: CustomStringConvertible {
} }
var left = 0 var left = 0
for idx in (0..<column).reverse() { for idx in (0..<column).reversed() {
let cell = self.cells[row][idx] let cell = self.cells[row][idx]
if cell.string == " " { if cell.string == " " {
left = idx + 1 left = idx + 1
@ -235,14 +235,14 @@ class Grid: CustomStringConvertible {
return Region(top: row, bottom: row, left: left, right: right) return Region(top: row, bottom: row, left: left, right: right)
} }
func positionFromSingleIndex(idx: Int) -> Position { func positionFromSingleIndex(_ idx: Int) -> Position {
let row = Int(floor(Double(idx) / Double(self.size.width))) let row = Int(floor(Double(idx) / Double(self.size.width)))
let column = idx - row * self.size.width let column = idx - row * self.size.width
return Position(row: row, column: column) return Position(row: row, column: column)
} }
func isCellEmpty(position: Position) -> Bool { func isCellEmpty(_ position: Position) -> Bool {
guard self.isSane(position: position) else { guard self.isSane(position: position) else {
return false return false
} }
@ -254,44 +254,44 @@ class Grid: CustomStringConvertible {
return false return false
} }
func isPreviousCellEmpty(position: Position) -> Bool { func isPreviousCellEmpty(_ position: Position) -> Bool {
return self.isCellEmpty(self.previousCellPosition(position)) return self.isCellEmpty(self.previousCellPosition(position))
} }
func isNextCellEmpty(position: Position) -> Bool { func isNextCellEmpty(_ position: Position) -> Bool {
return self.isCellEmpty(self.nextCellPosition(position)) return self.isCellEmpty(self.nextCellPosition(position))
} }
func previousCellPosition(position: Position) -> Position { func previousCellPosition(_ position: Position) -> Position {
return Position(row: position.row, column: max(position.column - 1, 0)) return Position(row: position.row, column: max(position.column - 1, 0))
} }
func nextCellPosition(position: Position) -> Position { func nextCellPosition(_ position: Position) -> Position {
return Position(row: position.row, column: min(position.column + 1, self.size.width - 1)) return Position(row: position.row, column: min(position.column + 1, self.size.width - 1))
} }
func cellForSingleIndex(idx: Int) -> Cell { func cellForSingleIndex(_ idx: Int) -> Cell {
let position = self.positionFromSingleIndex(idx) let position = self.positionFromSingleIndex(idx)
return self.cells[position.row][position.column] return self.cells[position.row][position.column]
} }
private func clearRegion(region: Region) { fileprivate func clearRegion(_ region: Region) {
// FIXME: sometimes clearRegion gets called without first resizing the Grid. Should we handle this? // FIXME: sometimes clearRegion gets called without first resizing the Grid. Should we handle this?
guard self.hasData else { guard self.hasData else {
return return
} }
let clearedAttrs = CellAttributes(fontTrait: .None, let clearedAttrs = CellAttributes(fontTrait: .none,
foreground: self.foreground, background: self.background, special: self.special) foreground: self.foreground, background: self.background, special: self.special)
let clearedCell = Cell(string: " ", attrs: clearedAttrs) let clearedCell = Cell(string: " ", attrs: clearedAttrs)
let clearedRow = Array(count: region.right - region.left + 1, repeatedValue: clearedCell) let clearedRow = Array(repeating: clearedCell, count: region.right - region.left + 1)
for i in region.top...region.bottom { for i in region.top...region.bottom {
self.cells[i].replaceRange(region.left...region.right, with: clearedRow) self.cells[i].replaceSubrange(region.left...region.right, with: clearedRow)
} }
} }
private func isSane(position position: Position) -> Bool { fileprivate func isSane(position: Position) -> Bool {
guard position.row < self.size.height && position.column < self.size.width else { guard position.row < self.size.height && position.column < self.size.width else {
return false return false
} }

View File

@ -58,7 +58,7 @@ class KeyUtils {
NSF35FunctionKey: "F35", NSF35FunctionKey: "F35",
] ]
static func isSpecial(key key: String) -> Bool { static func isSpecial(key: String) -> Bool {
guard key.characters.count == 1 else { guard key.characters.count == 1 else {
return false return false
} }
@ -70,7 +70,7 @@ class KeyUtils {
return false return false
} }
static func namedKeyFrom(key key: String) -> String { static func namedKeyFrom(key: String) -> String {
if let firstChar = key.utf16.first { if let firstChar = key.utf16.first {
if KeyUtils.specialKeys.keys.contains(Int(firstChar)) { if KeyUtils.specialKeys.keys.contains(Int(firstChar)) {
return KeyUtils.specialKeys[Int(firstChar)]! return KeyUtils.specialKeys[Int(firstChar)]!

View File

@ -9,7 +9,7 @@ import Cocoa
private struct RowRun: CustomStringConvertible { private struct RowRun: CustomStringConvertible {
let row: Int let row: Int
let range: Range<Int> let range: CountableClosedRange<Int>
let attrs: CellAttributes let attrs: CellAttributes
var description: String { var description: String {
@ -17,7 +17,7 @@ private struct RowRun: CustomStringConvertible {
} }
} }
public class NeoVimView: NSView, NSUserInterfaceValidations { open class NeoVimView: NSView, NSUserInterfaceValidations {
public struct Config { public struct Config {
let useInteractiveZsh: Bool let useInteractiveZsh: Bool
@ -27,29 +27,29 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
} }
} }
public static let minFontSize = CGFloat(4) open static let minFontSize = CGFloat(4)
public static let maxFontSize = CGFloat(128) open static let maxFontSize = CGFloat(128)
public static let defaultFont = NSFont.userFixedPitchFontOfSize(13)! open static let defaultFont = NSFont.userFixedPitchFont(ofSize: 13)!
public let uuid = NSUUID().UUIDString open let uuid = UUID().uuidString
public weak var delegate: NeoVimViewDelegate? open weak var delegate: NeoVimViewDelegate?
public private(set) var mode = Mode.Normal open fileprivate(set) var mode = Mode.Normal
public var usesLigatures = false { open var usesLigatures = false {
didSet { didSet {
self.drawer.usesLigatures = self.usesLigatures self.drawer.usesLigatures = self.usesLigatures
self.needsDisplay = true self.needsDisplay = true
} }
} }
public var font: NSFont { open var font: NSFont {
get { get {
return self._font return self._font
} }
set { set {
guard newValue.fixedPitch else { guard newValue.isFixedPitch else {
return return
} }
@ -68,59 +68,56 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
} }
} }
public var cwd: NSURL { open var cwd: URL {
get { get {
return NSURL(fileURLWithPath: self.agent.vimCommandOutput("silent pwd")) return URL(fileURLWithPath: self.agent.vimCommandOutput("silent pwd"))
} }
set { set {
guard let path = newValue.path else { let path = newValue.path
return
}
let escapedCwd = self.agent.escapedFileName(path) let escapedCwd = self.agent.escapedFileName(path)
self.agent.vimCommand("silent cd \(escapedCwd)") self.agent.vimCommand("silent cd \(escapedCwd)")
} }
} }
private var _font = NeoVimView.defaultFont fileprivate var _font = NeoVimView.defaultFont
private let agent: NeoVimAgent fileprivate let agent: NeoVimAgent
private let drawer: TextDrawer fileprivate let drawer: TextDrawer
private let fontManager = NSFontManager.sharedFontManager() fileprivate let fontManager = NSFontManager.shared()
private let pasteboard = NSPasteboard.generalPasteboard() fileprivate let pasteboard = NSPasteboard.general()
private let grid = Grid() fileprivate let grid = Grid()
private var markedText: String? fileprivate var markedText: String?
/// We store the last marked text because Cocoa's text input system does the following: /// We store the last marked text because Cocoa's text input system does the following:
/// -> hanja popup -> insertText() -> attributedSubstring...() -> setMarkedText() -> ... /// -> hanja popup -> insertText() -> attributedSubstring...() -> setMarkedText() -> ...
/// We want to return "" in attributedSubstring...() /// We want to return "" in attributedSubstring...()
private var lastMarkedText: String? fileprivate var lastMarkedText: String?
private var markedPosition = Position.null fileprivate var markedPosition = Position.null
private var keyDownDone = true fileprivate var keyDownDone = true
private var lastClickedCellPosition = Position.null fileprivate var lastClickedCellPosition = Position.null
private var xOffset = CGFloat(0) fileprivate var xOffset = CGFloat(0)
private var yOffset = CGFloat(0) fileprivate var yOffset = CGFloat(0)
private var cellSize = CGSize.zero fileprivate var cellSize = CGSize.zero
private var descent = CGFloat(0) fileprivate var descent = CGFloat(0)
private var leading = CGFloat(0) fileprivate var leading = CGFloat(0)
private let maxScrollDeltaX = 30 fileprivate let maxScrollDeltaX = 30
private let maxScrollDeltaY = 30 fileprivate let maxScrollDeltaY = 30
private let scrollLimiterX = CGFloat(20) fileprivate let scrollLimiterX = CGFloat(20)
private let scrollLimiterY = CGFloat(20) fileprivate let scrollLimiterY = CGFloat(20)
private var scrollGuardCounterX = 5 fileprivate var scrollGuardCounterX = 5
private var scrollGuardCounterY = 5 fileprivate var scrollGuardCounterY = 5
private let scrollGuardYield = 5 fileprivate let scrollGuardYield = 5
private var isCurrentlyPinching = false fileprivate var isCurrentlyPinching = false
private var pinchTargetScale = CGFloat(1) fileprivate var pinchTargetScale = CGFloat(1)
private var pinchImage = NSImage() fileprivate var pinchImage = NSImage()
public init(frame rect: NSRect, config: Config) { public init(frame rect: NSRect, config: Config) {
self.drawer = TextDrawer(font: self._font, useLigatures: false) self.drawer = TextDrawer(font: self._font, useLigatures: false)
@ -142,7 +139,7 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
DispatchUtils.gui { DispatchUtils.gui {
if noErrorDuringInitialization == false { if noErrorDuringInitialization == false {
let alert = NSAlert() let alert = NSAlert()
alert.alertStyle = .WarningAlertStyle alert.alertStyle = .warning
alert.messageText = "Error during initialization" alert.messageText = "Error during initialization"
alert.informativeText = "There was an error during the initialization of NeoVim. " alert.informativeText = "There was an error during the initialization of NeoVim. "
+ "Use :messages to view the error messages." + "Use :messages to view the error messages."
@ -161,7 +158,7 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@IBAction public func debug1(sender: AnyObject!) { @IBAction open func debug1(_ sender: AnyObject!) {
NSLog("DEBUG 1 - Start") NSLog("DEBUG 1 - Start")
NSLog("\(self.agent.vimCommandOutput("silent echo $PATH"))") NSLog("\(self.agent.vimCommandOutput("silent echo $PATH"))")
NSLog("\(self.agent.vimCommandOutput("silent pwd"))") NSLog("\(self.agent.vimCommandOutput("silent pwd"))")
@ -188,10 +185,10 @@ extension NeoVimView {
self.exec(command: "tabe") self.exec(command: "tabe")
} }
public func open(urls urls: [NSURL]) { public func open(urls: [URL]) {
let currentBufferIsTransient = self.agent.buffers().filter { $0.current }.first?.transient ?? false let currentBufferIsTransient = self.agent.buffers().filter { $0.current }.first?.transient ?? false
urls.enumerate().forEach { (idx, url) in urls.enumerated().forEach { (idx, url) in
if idx == 0 && currentBufferIsTransient { if idx == 0 && currentBufferIsTransient {
self.open(url, cmd: "e") self.open(url, cmd: "e")
} else { } else {
@ -200,11 +197,11 @@ extension NeoVimView {
} }
} }
public func openInNewTab(urls urls: [NSURL]) { public func openInNewTab(urls: [URL]) {
urls.forEach { self.open($0, cmd: "tabe") } urls.forEach { self.open($0, cmd: "tabe") }
} }
public func openInCurrentTab(url url: NSURL) { public func openInCurrentTab(url: URL) {
self.open(url, cmd: "e") self.open(url, cmd: "e")
} }
@ -216,11 +213,8 @@ extension NeoVimView {
self.exec(command: "w") self.exec(command: "w")
} }
public func saveCurrentTab(url url: NSURL) { public func saveCurrentTab(url: URL) {
guard let path = url.path else { let path = url.path
return
}
let escapedFileName = self.agent.escapedFileName(path) let escapedFileName = self.agent.escapedFileName(path)
self.exec(command: "w \(escapedFileName)") self.exec(command: "w \(escapedFileName)")
} }
@ -240,7 +234,7 @@ extension NeoVimView {
/// Does the following /// Does the following
/// - `Mode.Normal`: `:command<CR>` /// - `Mode.Normal`: `:command<CR>`
/// - else: `:<Esc>:command<CR>` /// - else: `:<Esc>:command<CR>`
private func exec(command cmd: String) { fileprivate func exec(command cmd: String) {
switch self.mode { switch self.mode {
case .Normal: case .Normal:
self.agent.vimInput(":\(cmd)<CR>") self.agent.vimInput(":\(cmd)<CR>")
@ -249,11 +243,8 @@ extension NeoVimView {
} }
} }
private func open(url: NSURL, cmd: String) { fileprivate func open(_ url: URL, cmd: String) {
guard let path = url.path else { let path = url.path
return
}
let escapedFileName = self.agent.escapedFileName(path) let escapedFileName = self.agent.escapedFileName(path)
self.exec(command: "\(cmd) \(escapedFileName)") self.exec(command: "\(cmd) \(escapedFileName)")
} }
@ -262,7 +253,7 @@ extension NeoVimView {
// MARK: - Resizing // MARK: - Resizing
extension NeoVimView { extension NeoVimView {
override public func setFrameSize(newSize: NSSize) { override open func setFrameSize(_ newSize: NSSize) {
super.setFrameSize(newSize) super.setFrameSize(newSize)
// initial resizing is done when grid has data // initial resizing is done when grid has data
@ -281,22 +272,22 @@ extension NeoVimView {
self.resizeNeoVimUiTo(size: newSize) self.resizeNeoVimUiTo(size: newSize)
} }
override public func viewDidEndLiveResize() { override open func viewDidEndLiveResize() {
super.viewDidEndLiveResize() super.viewDidEndLiveResize()
self.resizeNeoVimUiTo(size: self.bounds.size) self.resizeNeoVimUiTo(size: self.bounds.size)
} }
private func resizeNeoVimUiTo(size size: CGSize) { fileprivate func resizeNeoVimUiTo(size: CGSize) {
// NSLog("\(#function): \(size)") // NSLog("\(#function): \(size)")
let discreteSize = self.discreteSize(size: size) let discreteSize = self.discreteSize(size: size)
self.xOffset = floor((size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2) self.xOffset = floor((size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2)
self.yOffset = floor((size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2) self.yOffset = floor((size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2)
self.agent.resizeToWidth(Int32(discreteSize.width), height: Int32(discreteSize.height)) self.agent.resize(toWidth: Int32(discreteSize.width), height: Int32(discreteSize.height))
} }
private func discreteSize(size size: CGSize) -> Size { fileprivate func discreteSize(size: CGSize) -> Size {
return Size(width: Int(floor(size.width / self.cellSize.width)), return Size(width: Int(floor(size.width / self.cellSize.width)),
height: Int(floor(size.height / self.cellSize.height))) height: Int(floor(size.height / self.cellSize.height)))
} }
@ -305,42 +296,42 @@ extension NeoVimView {
// MARK: - Drawing // MARK: - Drawing
extension NeoVimView { extension NeoVimView {
override public func drawRect(dirtyUnionRect: NSRect) { override open func draw(_ dirtyUnionRect: NSRect) {
guard self.grid.hasData else { guard self.grid.hasData else {
return return
} }
if self.inLiveResize { if self.inLiveResize {
NSColor.windowBackgroundColor().set() NSColor.windowBackgroundColor.set()
dirtyUnionRect.fill() dirtyUnionRect.fill()
let boundsSize = self.bounds.size let boundsSize = self.bounds.size
let discreteSize = self.discreteSize(size: boundsSize) let discreteSize = self.discreteSize(size: boundsSize)
let displayStr = "\(discreteSize.width) × \(discreteSize.height)" let displayStr = "\(discreteSize.width) × \(discreteSize.height)"
let attrs = [ NSFontAttributeName: NSFont.systemFontOfSize(24) ] let attrs = [ NSFontAttributeName: NSFont.systemFont(ofSize: 24) ]
let size = displayStr.sizeWithAttributes(attrs) let size = displayStr.size(withAttributes: attrs)
let x = (boundsSize.width - size.width) / 2 let x = (boundsSize.width - size.width) / 2
let y = (boundsSize.height - size.height) / 2 let y = (boundsSize.height - size.height) / 2
displayStr.drawAtPoint(CGPoint(x: x, y: y), withAttributes: attrs) displayStr.draw(at: CGPoint(x: x, y: y), withAttributes: attrs)
return return
} }
// NSLog("\(#function): \(dirtyUnionRect)") // NSLog("\(#function): \(dirtyUnionRect)")
let context = NSGraphicsContext.currentContext()!.CGContext let context = NSGraphicsContext.current()!.cgContext
if self.isCurrentlyPinching { if self.isCurrentlyPinching {
let boundsSize = self.bounds.size let boundsSize = self.bounds.size
let targetSize = CGSize(width: boundsSize.width * self.pinchTargetScale, let targetSize = CGSize(width: boundsSize.width * self.pinchTargetScale,
height: boundsSize.height * self.pinchTargetScale) height: boundsSize.height * self.pinchTargetScale)
self.pinchImage.drawInRect(CGRect(origin: self.bounds.origin, size: targetSize)) self.pinchImage.draw(in: CGRect(origin: self.bounds.origin, size: targetSize))
return return
} }
CGContextSetTextMatrix(context, CGAffineTransformIdentity); context.textMatrix = CGAffineTransform.identity;
CGContextSetTextDrawingMode(context, .Fill); context.setTextDrawingMode(.fill);
let dirtyRects = self.rectsBeingDrawn() let dirtyRects = self.rectsBeingDrawn()
// NSLog("\(dirtyRects)") // NSLog("\(dirtyRects)")
@ -349,7 +340,7 @@ extension NeoVimView {
self.drawCursor(context: context) self.drawCursor(context: context)
} }
private func draw(rowRun rowFrag: RowRun, context: CGContext) { fileprivate func draw(rowRun rowFrag: RowRun, context: CGContext) {
// For background drawing we don't filter out the put(0, 0)s: in some cases only the put(0, 0)-cells should be // For background drawing we don't filter out the put(0, 0)s: in some cases only the put(0, 0)-cells should be
// redrawn. => FIXME: probably we have to consider this also when drawing further down, ie when the range starts // redrawn. => FIXME: probably we have to consider this also when drawing further down, ie when the range starts
// with '0'... // with '0'...
@ -368,13 +359,13 @@ extension NeoVimView {
let string = self.grid.cells[rowFrag.row][rowFrag.range].reduce("") { $0 + $1.string } let string = self.grid.cells[rowFrag.row][rowFrag.range].reduce("") { $0 + $1.string }
let glyphPositions = positions.map { CGPoint(x: $0.x, y: $0.y + self.descent + self.leading) } let glyphPositions = positions.map { CGPoint(x: $0.x, y: $0.y + self.descent + self.leading) }
self.drawer.drawString(string, self.drawer.draw(string,
positions: UnsafeMutablePointer(glyphPositions), positionsCount: positions.count, positions: UnsafeMutablePointer(mutating: glyphPositions), positionsCount: positions.count,
highlightAttrs: rowFrag.attrs, highlightAttrs: rowFrag.attrs,
context: context) context: context)
} }
private func cursorRegion() -> Region { fileprivate func cursorRegion() -> Region {
let cursorPosition = self.mode == .Cmdline ? self.grid.putPosition : self.grid.screenCursor let cursorPosition = self.mode == .Cmdline ? self.grid.putPosition : self.grid.screenCursor
// NSLog("\(#function): \(cursorPosition)") // NSLog("\(#function): \(cursorPosition)")
@ -393,7 +384,7 @@ extension NeoVimView {
return cursorRegion return cursorRegion
} }
private func drawCursor(context context: CGContext) { fileprivate func drawCursor(context: CGContext) {
// FIXME: for now do some rudimentary cursor drawing // FIXME: for now do some rudimentary cursor drawing
let cursorRegion = self.cursorRegion() let cursorRegion = self.cursorRegion()
let cursorRow = cursorRegion.top let cursorRow = cursorRegion.top
@ -409,7 +400,7 @@ extension NeoVimView {
self.draw(rowRun: rowRun, context: context) self.draw(rowRun: rowRun, context: context)
} }
private func drawBackground(positions positions: [CGPoint], background: UInt32) { fileprivate func drawBackground(positions: [CGPoint], background: UInt32) {
ColorUtils.colorIgnoringAlpha(background).set() ColorUtils.colorIgnoringAlpha(background).set()
// NSColor(calibratedRed: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0).set() // NSColor(calibratedRed: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0).set()
let backgroundRect = CGRect( let backgroundRect = CGRect(
@ -419,9 +410,9 @@ extension NeoVimView {
backgroundRect.fill() backgroundRect.fill()
} }
private func rowRunIntersecting(rects rects: [CGRect]) -> [RowRun] { fileprivate func rowRunIntersecting(rects: [CGRect]) -> [RowRun] {
return rects return rects
.map { rect -> (Range<Int>, Range<Int>) in .map { rect -> (CountableClosedRange<Int>, CountableClosedRange<Int>) in
// Get all Regions that intersects with the given rects. There can be overlaps between the Regions, but for the // Get all Regions that intersects with the given rects. There can be overlaps between the Regions, but for the
// time being we ignore them; probably not necessary to optimize them away. // time being we ignore them; probably not necessary to optimize them away.
let region = self.regionFor(rect: rect) let region = self.regionFor(rect: rect)
@ -431,17 +422,17 @@ extension NeoVimView {
.flatMap { $0 } // Flattened RowRuns for all Regions. .flatMap { $0 } // Flattened RowRuns for all Regions.
} }
private func rowRunsFor(rowRange rowRange: Range<Int>, columnRange: Range<Int>) -> [RowRun] { fileprivate func rowRunsFor(rowRange: CountableClosedRange<Int>, columnRange: CountableClosedRange<Int>) -> [RowRun] {
return rowRange return rowRange
.map { (row) -> [RowRun] in .map { (row) -> [RowRun] in
let rowCells = self.grid.cells[row] let rowCells = self.grid.cells[row]
let startIdx = columnRange.startIndex let startIdx = columnRange.lowerBound
var result = [ RowRun(row: row, range: startIdx...startIdx, attrs: rowCells[startIdx].attrs) ] var result = [ RowRun(row: row, range: startIdx...startIdx, attrs: rowCells[startIdx].attrs) ]
columnRange.forEach { idx in columnRange.forEach { idx in
if rowCells[idx].attrs == result.last!.attrs { if rowCells[idx].attrs == result.last!.attrs {
let last = result.popLast()! let last = result.popLast()!
result.append(RowRun(row: row, range: last.range.startIndex...idx, attrs: last.attrs)) result.append(RowRun(row: row, range: last.range.lowerBound...idx, attrs: last.attrs))
} else { } else {
result.append(RowRun(row: row, range: idx...idx, attrs: rowCells[idx].attrs)) result.append(RowRun(row: row, range: idx...idx, attrs: rowCells[idx].attrs))
} }
@ -452,7 +443,7 @@ extension NeoVimView {
.flatMap { $0 } // Flattened RowRuns for a Region. .flatMap { $0 } // Flattened RowRuns for a Region.
} }
private func regionFor(rect rect: CGRect) -> Region { fileprivate func regionFor(rect: CGRect) -> Region {
let cellWidth = self.cellSize.width let cellWidth = self.cellSize.width
let cellHeight = self.cellSize.height let cellHeight = self.cellSize.height
@ -472,22 +463,22 @@ extension NeoVimView {
return Region(top: rowStart, bottom: rowEnd, left: columnStart, right: columnEnd) return Region(top: rowStart, bottom: rowEnd, left: columnStart, right: columnEnd)
} }
private func pointInViewFor(position position: Position) -> CGPoint { fileprivate func pointInViewFor(position: Position) -> CGPoint {
return self.pointInViewFor(row: position.row, column: position.column) return self.pointInViewFor(row: position.row, column: position.column)
} }
private func pointInViewFor(row row: Int, column: Int) -> CGPoint { fileprivate func pointInViewFor(row: Int, column: Int) -> CGPoint {
return CGPoint( return CGPoint(
x: self.xOffset + CGFloat(column) * self.cellSize.width, x: self.xOffset + CGFloat(column) * self.cellSize.width,
y: self.bounds.size.height - self.yOffset - CGFloat(row) * self.cellSize.height - self.cellSize.height y: self.bounds.size.height - self.yOffset - CGFloat(row) * self.cellSize.height - self.cellSize.height
) )
} }
private func cellRectFor(row row: Int, column: Int) -> CGRect { fileprivate func cellRectFor(row: Int, column: Int) -> CGRect {
return CGRect(origin: self.pointInViewFor(row: row, column: column), size: self.cellSize) return CGRect(origin: self.pointInViewFor(row: row, column: column), size: self.cellSize)
} }
private func regionRectFor(region region: Region) -> CGRect { fileprivate func regionRectFor(region: Region) -> CGRect {
let top = CGFloat(region.top) let top = CGFloat(region.top)
let bottom = CGFloat(region.bottom) let bottom = CGFloat(region.bottom)
let left = CGFloat(region.left) let left = CGFloat(region.left)
@ -507,35 +498,39 @@ extension NeoVimView {
) )
} }
private func wrapNamedKeys(string: String) -> String { fileprivate func wrapNamedKeys(_ string: String) -> String {
return "<\(string)>" return "<\(string)>"
} }
private func vimPlainString(string: String) -> String { fileprivate func vimPlainString(_ string: String) -> String {
return string.stringByReplacingOccurrencesOfString("<", withString: self.wrapNamedKeys("lt")) return string.replacingOccurrences(of: "<", with: self.wrapNamedKeys("lt"))
} }
} }
// MARK: - NSUserInterfaceValidationsProtocol // MARK: - NSUserInterfaceValidationsProtocol
extension NeoVimView { extension NeoVimView {
public func validateUserInterfaceItem(item: NSValidatedUserInterfaceItem) -> Bool { public func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
let canUndoOrRedo = self.mode == .Insert || self.mode == .Replace || self.mode == .Normal || self.mode == .Visual let canUndoOrRedo = self.mode == .Insert || self.mode == .Replace || self.mode == .Normal || self.mode == .Visual
let canCopyOrCut = self.mode == .Normal || self.mode == .Visual let canCopyOrCut = self.mode == .Normal || self.mode == .Visual
let canPaste = self.pasteboard.stringForType(NSPasteboardTypeString) != nil let canPaste = self.pasteboard.string(forType: NSPasteboardTypeString) != nil
let canDelete = self.mode == .Visual || self.mode == .Normal let canDelete = self.mode == .Visual || self.mode == .Normal
let canSelectAll = self.mode == .Insert || self.mode == .Replace || self.mode == .Normal || self.mode == .Visual let canSelectAll = self.mode == .Insert || self.mode == .Replace || self.mode == .Normal || self.mode == .Visual
switch item.action() { guard let action = item.action else {
case NSSelectorFromString("undo:"), NSSelectorFromString("redo:"): return true
}
switch action {
case Selector("undo:"), Selector("redo:"):
return canUndoOrRedo return canUndoOrRedo
case NSSelectorFromString("copy:"), NSSelectorFromString("cut:"): case Selector("copy:"), Selector("cut:"):
return canCopyOrCut return canCopyOrCut
case NSSelectorFromString("paste:"): case Selector("paste:"):
return canPaste return canPaste
case NSSelectorFromString("delete:"): case Selector("delete:"):
return canDelete return canDelete
case NSSelectorFromString("selectAll:"): case Selector("selectAll:"):
return canSelectAll return canSelectAll
default: default:
return true return true
@ -546,7 +541,7 @@ extension NeoVimView {
// MARK: - Edit Menu Items // MARK: - Edit Menu Items
extension NeoVimView { extension NeoVimView {
@IBAction func undo(sender: AnyObject!) { @IBAction func undo(_ sender: AnyObject!) {
switch self.mode { switch self.mode {
case .Insert, .Replace: case .Insert, .Replace:
self.agent.vimInput("<Esc>ui") self.agent.vimInput("<Esc>ui")
@ -557,7 +552,7 @@ extension NeoVimView {
} }
} }
@IBAction func redo(sender: AnyObject!) { @IBAction func redo(_ sender: AnyObject!) {
switch self.mode { switch self.mode {
case .Insert, .Replace: case .Insert, .Replace:
self.agent.vimInput("<Esc><C-r>i") self.agent.vimInput("<Esc><C-r>i")
@ -568,7 +563,7 @@ extension NeoVimView {
} }
} }
@IBAction func cut(sender: AnyObject!) { @IBAction func cut(_ sender: AnyObject!) {
switch self.mode { switch self.mode {
case .Visual, .Normal: case .Visual, .Normal:
self.agent.vimInput("\"+d") self.agent.vimInput("\"+d")
@ -577,7 +572,7 @@ extension NeoVimView {
} }
} }
@IBAction func copy(sender: AnyObject!) { @IBAction func copy(_ sender: AnyObject!) {
switch self.mode { switch self.mode {
case .Visual, .Normal: case .Visual, .Normal:
self.agent.vimInput("\"+y") self.agent.vimInput("\"+y")
@ -586,8 +581,8 @@ extension NeoVimView {
} }
} }
@IBAction func paste(sender: AnyObject!) { @IBAction func paste(_ sender: AnyObject!) {
guard let content = self.pasteboard.stringForType(NSPasteboardTypeString) else { guard let content = self.pasteboard.string(forType: NSPasteboardTypeString) else {
return return
} }
@ -599,7 +594,7 @@ extension NeoVimView {
} }
} }
@IBAction func delete(sender: AnyObject!) { @IBAction func delete(_ sender: AnyObject!) {
switch self.mode { switch self.mode {
case .Normal, .Visual: case .Normal, .Visual:
self.agent.vimInput("x") self.agent.vimInput("x")
@ -608,7 +603,7 @@ extension NeoVimView {
} }
} }
@IBAction public override func selectAll(sender: AnyObject?) { @IBAction open override func selectAll(_ sender: Any?) {
switch self.mode { switch self.mode {
case .Insert, .Visual: case .Insert, .Visual:
self.agent.vimInput("<Esc>ggVG") self.agent.vimInput("<Esc>ggVG")
@ -621,10 +616,10 @@ extension NeoVimView {
// MARK: - Key Events // MARK: - Key Events
extension NeoVimView: NSTextInputClient { extension NeoVimView: NSTextInputClient {
override public func keyDown(event: NSEvent) { override open func keyDown(with event: NSEvent) {
self.keyDownDone = false self.keyDownDone = false
let context = NSTextInputContext.currentInputContext()! let context = NSTextInputContext.current()!
let cocoaHandledEvent = context.handleEvent(event) let cocoaHandledEvent = context.handleEvent(event)
if self.keyDownDone && cocoaHandledEvent { if self.keyDownDone && cocoaHandledEvent {
return return
@ -633,10 +628,10 @@ extension NeoVimView: NSTextInputClient {
// NSLog("\(#function): \(event)") // NSLog("\(#function): \(event)")
let modifierFlags = event.modifierFlags let modifierFlags = event.modifierFlags
let capslock = modifierFlags.contains(.AlphaShiftKeyMask) let capslock = modifierFlags.contains(.capsLock)
let shift = modifierFlags.contains(.ShiftKeyMask) let shift = modifierFlags.contains(.shift)
let chars = event.characters! let chars = event.characters!
let charsIgnoringModifiers = shift || capslock ? event.charactersIgnoringModifiers!.lowercaseString let charsIgnoringModifiers = shift || capslock ? event.charactersIgnoringModifiers!.lowercased()
: event.charactersIgnoringModifiers! : event.charactersIgnoringModifiers!
if KeyUtils.isSpecial(key: charsIgnoringModifiers) { if KeyUtils.isSpecial(key: charsIgnoringModifiers) {
@ -656,7 +651,7 @@ extension NeoVimView: NSTextInputClient {
self.keyDownDone = true self.keyDownDone = true
} }
public func insertText(aString: AnyObject, replacementRange: NSRange) { public func insertText(_ aString: Any, replacementRange: NSRange) {
// NSLog("\(#function): \(replacementRange): '\(aString)'") // NSLog("\(#function): \(replacementRange): '\(aString)'")
switch aString { switch aString {
@ -675,14 +670,14 @@ extension NeoVimView: NSTextInputClient {
self.keyDownDone = true self.keyDownDone = true
} }
public override func doCommandBySelector(aSelector: Selector) { open override func doCommand(by aSelector: Selector) {
// NSLog("\(#function): \(aSelector)"); // NSLog("\(#function): \(aSelector)");
// FIXME: handle when -> delete // FIXME: handle when -> delete
if self.respondsToSelector(aSelector) { if self.responds(to: aSelector) {
Swift.print("\(#function): calling \(aSelector)") Swift.print("\(#function): calling \(aSelector)")
self.performSelector(aSelector, withObject: self) self.perform(aSelector, with: self)
self.keyDownDone = true self.keyDownDone = true
return return
} }
@ -691,7 +686,7 @@ extension NeoVimView: NSTextInputClient {
self.keyDownDone = false self.keyDownDone = false
} }
public func setMarkedText(aString: AnyObject, selectedRange: NSRange, replacementRange: NSRange) { public func setMarkedText(_ aString: Any, selectedRange: NSRange, replacementRange: NSRange) {
if self.markedText == nil { if self.markedText == nil {
self.markedPosition = self.grid.putPosition self.markedPosition = self.grid.putPosition
} }
@ -707,7 +702,7 @@ extension NeoVimView: NSTextInputClient {
case let attributedString as NSAttributedString: case let attributedString as NSAttributedString:
self.markedText = attributedString.string self.markedText = attributedString.string
default: default:
self.markedText = String(aString) // should not occur self.markedText = String(describing: aString) // should not occur
} }
// NSLog("\(#function): \(self.markedText), \(selectedRange), \(replacementRange)") // NSLog("\(#function): \(self.markedText), \(selectedRange), \(replacementRange)")
@ -723,7 +718,7 @@ extension NeoVimView: NSTextInputClient {
self.keyDownDone = true self.keyDownDone = true
// TODO: necessary? // TODO: necessary?
self.setNeedsDisplayInRect(self.cellRectFor(row: self.grid.putPosition.row, column: self.grid.putPosition.column)) self.setNeedsDisplay(self.cellRectFor(row: self.grid.putPosition.row, column: self.grid.putPosition.column))
} }
/// Return the current selection (or the position of the cursor with empty-length range). For example when you enter /// Return the current selection (or the position of the cursor with empty-length range). For example when you enter
@ -761,7 +756,7 @@ extension NeoVimView: NSTextInputClient {
// FIXME: take into account the "return nil"-case // FIXME: take into account the "return nil"-case
// FIXME: just fix me, PLEASE... // FIXME: just fix me, PLEASE...
public func attributedSubstringForProposedRange(aRange: NSRange, actualRange: NSRangePointer) -> NSAttributedString? { public func attributedSubstring(forProposedRange aRange: NSRange, actualRange: NSRangePointer?) -> NSAttributedString? {
// NSLog("\(#function): \(aRange), \(actualRange[0])") // NSLog("\(#function): \(aRange), \(actualRange[0])")
if aRange.location == NSNotFound { if aRange.location == NSNotFound {
// NSLog("\(#function): range not found: returning nil") // NSLog("\(#function): range not found: returning nil")
@ -789,28 +784,28 @@ extension NeoVimView: NSTextInputClient {
return [] return []
} }
public func firstRectForCharacterRange(aRange: NSRange, actualRange: NSRangePointer) -> NSRect { public func firstRect(forCharacterRange aRange: NSRange, actualRange: NSRangePointer?) -> NSRect {
let position = self.grid.positionFromSingleIndex(aRange.location) let position = self.grid.positionFromSingleIndex(aRange.location)
// NSLog("\(#function): \(aRange),\(actualRange[0]) -> \(position.row):\(position.column)") // NSLog("\(#function): \(aRange),\(actualRange[0]) -> \(position.row):\(position.column)")
let resultInSelf = self.cellRectFor(row: position.row, column: position.column) let resultInSelf = self.cellRectFor(row: position.row, column: position.column)
let result = self.window?.convertRectToScreen(self.convertRect(resultInSelf, toView: nil)) let result = self.window?.convertToScreen(self.convert(resultInSelf, to: nil))
return result! return result!
} }
public func characterIndexForPoint(aPoint: NSPoint) -> Int { public func characterIndex(for aPoint: NSPoint) -> Int {
// NSLog("\(#function): \(aPoint)") // NSLog("\(#function): \(aPoint)")
return 1 return 1
} }
private func vimModifierFlags(modifierFlags: NSEventModifierFlags) -> String? { fileprivate func vimModifierFlags(_ modifierFlags: NSEventModifierFlags) -> String? {
var result = "" var result = ""
let control = modifierFlags.contains(.ControlKeyMask) let control = modifierFlags.contains(.control)
let option = modifierFlags.contains(.AlternateKeyMask) let option = modifierFlags.contains(.option)
let command = modifierFlags.contains(.CommandKeyMask) let command = modifierFlags.contains(.command)
if control { if control {
result += "C-" result += "C-"
@ -835,7 +830,7 @@ extension NeoVimView: NSTextInputClient {
// MARK: - Gesture Events // MARK: - Gesture Events
extension NeoVimView { extension NeoVimView {
override public func magnifyWithEvent(event: NSEvent) { override open func magnify(with event: NSEvent) {
let factor = 1 + event.magnification let factor = 1 + event.magnification
let pinchTargetScale = self.pinchTargetScale * factor let pinchTargetScale = self.pinchTargetScale * factor
let resultingFontSize = round(pinchTargetScale * self._font.pointSize) let resultingFontSize = round(pinchTargetScale * self._font.pointSize)
@ -844,18 +839,18 @@ extension NeoVimView {
} }
switch event.phase { switch event.phase {
case NSEventPhase.Began: case NSEventPhase.began:
let pinchImageRep = self.bitmapImageRepForCachingDisplayInRect(self.bounds)! let pinchImageRep = self.bitmapImageRepForCachingDisplay(in: self.bounds)!
self.cacheDisplayInRect(self.bounds, toBitmapImageRep: pinchImageRep) self.cacheDisplay(in: self.bounds, to: pinchImageRep)
self.pinchImage = NSImage() self.pinchImage = NSImage()
self.pinchImage.addRepresentation(pinchImageRep) self.pinchImage.addRepresentation(pinchImageRep)
self.isCurrentlyPinching = true self.isCurrentlyPinching = true
self.needsDisplay = true self.needsDisplay = true
case NSEventPhase.Ended, NSEventPhase.Cancelled: case NSEventPhase.ended, NSEventPhase.cancelled:
self.isCurrentlyPinching = false self.isCurrentlyPinching = false
self.font = self.fontManager.convertFont(self._font, toSize: resultingFontSize) self.font = self.fontManager.convert(self._font, toSize: resultingFontSize)
self.pinchTargetScale = 1 self.pinchTargetScale = 1
default: default:
@ -867,19 +862,19 @@ extension NeoVimView {
// MARK: - Mouse Events // MARK: - Mouse Events
extension NeoVimView { extension NeoVimView {
override public func mouseDown(event: NSEvent) { override open func mouseDown(with event: NSEvent) {
self.mouse(event: event, vimName:"LeftMouse") self.mouse(event: event, vimName:"LeftMouse")
} }
override public func mouseUp(event: NSEvent) { override open func mouseUp(with event: NSEvent) {
self.mouse(event: event, vimName:"LeftRelease") self.mouse(event: event, vimName:"LeftRelease")
} }
override public func mouseDragged(event: NSEvent) { override open func mouseDragged(with event: NSEvent) {
self.mouse(event: event, vimName:"LeftDrag") self.mouse(event: event, vimName:"LeftDrag")
} }
override public func scrollWheel(event: NSEvent) { override open func scrollWheel(with event: NSEvent) {
let (deltaX, deltaY) = (event.scrollingDeltaX, event.scrollingDeltaY) let (deltaX, deltaY) = (event.scrollingDeltaX, event.scrollingDeltaY)
if deltaX == 0 && deltaY == 0 { if deltaX == 0 && deltaY == 0 {
return return
@ -908,8 +903,8 @@ extension NeoVimView {
} }
} }
private func cellPositionFor(event event: NSEvent) -> Position { fileprivate func cellPositionFor(event: NSEvent) -> Position {
let location = self.convertPoint(event.locationInWindow, fromView: nil) let location = self.convert(event.locationInWindow, from: nil)
let row = Int((location.x - self.xOffset) / self.cellSize.width) let row = Int((location.x - self.xOffset) / self.cellSize.width)
let column = Int((self.bounds.size.height - location.y - self.yOffset) / self.cellSize.height) let column = Int((self.bounds.size.height - location.y - self.yOffset) / self.cellSize.height)
@ -918,7 +913,7 @@ extension NeoVimView {
return cellPosition return cellPosition
} }
private func mouse(event event: NSEvent, vimName: String) { fileprivate func mouse(event: NSEvent, vimName: String) {
let cellPosition = self.cellPositionFor(event: event) let cellPosition = self.cellPositionFor(event: event)
guard self.shouldFireVimInputFor(event: event, newCellPosition: cellPosition) else { guard self.shouldFireVimInputFor(event: event, newCellPosition: cellPosition) else {
return return
@ -938,9 +933,9 @@ extension NeoVimView {
self.agent.vimInput(result) self.agent.vimInput(result)
} }
private func shouldFireVimInputFor(event event:NSEvent, newCellPosition: Position) -> Bool { fileprivate func shouldFireVimInputFor(event:NSEvent, newCellPosition: Position) -> Bool {
let type = event.type let type = event.type
guard type == .LeftMouseDragged || type == .RightMouseDragged || type == .OtherMouseDragged else { guard type == .leftMouseDragged || type == .rightMouseDragged || type == .otherMouseDragged else {
self.lastClickedCellPosition = newCellPosition self.lastClickedCellPosition = newCellPosition
return true return true
} }
@ -953,7 +948,7 @@ extension NeoVimView {
return true return true
} }
private func vimClickCountFrom(event event: NSEvent) -> String { fileprivate func vimClickCountFrom(event: NSEvent) -> String {
let clickCount = event.clickCount let clickCount = event.clickCount
guard 2 <= clickCount && clickCount <= 4 else { guard 2 <= clickCount && clickCount <= 4 else {
@ -961,14 +956,14 @@ extension NeoVimView {
} }
switch event.type { switch event.type {
case .LeftMouseDown, .LeftMouseUp, .RightMouseDown, .RightMouseUp: case .leftMouseDown, .leftMouseUp, .rightMouseDown, .rightMouseUp:
return "\(clickCount)-" return "\(clickCount)-"
default: default:
return "" return ""
} }
} }
private func vimScrollEventNamesFor(deltaX deltaX: CGFloat, deltaY: CGFloat) -> (String, String) { fileprivate func vimScrollEventNamesFor(deltaX: CGFloat, deltaY: CGFloat) -> (String, String) {
let typeY: String let typeY: String
if deltaY > 0 { if deltaY > 0 {
typeY = "ScrollWheelUp" typeY = "ScrollWheelUp"
@ -986,7 +981,7 @@ extension NeoVimView {
return (typeX, typeY) return (typeX, typeY)
} }
private func vimScrollInputFor(deltaX deltaX: CGFloat, deltaY: CGFloat, fileprivate func vimScrollInputFor(deltaX: CGFloat, deltaY: CGFloat,
modifierFlags: NSEventModifierFlags, modifierFlags: NSEventModifierFlags,
cellPosition: Position) -> (String, String) cellPosition: Position) -> (String, String)
{ {
@ -1006,7 +1001,7 @@ extension NeoVimView {
return (resultX, resultY) return (resultX, resultY)
} }
private func throttleScrollX(absDelta absDeltaX: CGFloat, vimInput: String) { fileprivate func throttleScrollX(absDelta absDeltaX: CGFloat, vimInput: String) {
if absDeltaX == 0 { if absDeltaX == 0 {
self.scrollGuardCounterX = self.scrollGuardYield - 1 self.scrollGuardCounterX = self.scrollGuardYield - 1
} else if absDeltaX <= 2 { } else if absDeltaX <= 2 {
@ -1022,7 +1017,7 @@ extension NeoVimView {
} }
} }
private func throttleScrollY(absDelta absDeltaY: CGFloat, vimInput: String) { fileprivate func throttleScrollY(absDelta absDeltaY: CGFloat, vimInput: String) {
if absDeltaY == 0 { if absDeltaY == 0 {
self.scrollGuardCounterY = self.scrollGuardYield - 1 self.scrollGuardCounterY = self.scrollGuardYield - 1
} else if absDeltaY <= 2 { } else if absDeltaY <= 2 {
@ -1042,7 +1037,7 @@ extension NeoVimView {
// MARK: - NeoVimUiBridgeProtocol // MARK: - NeoVimUiBridgeProtocol
extension NeoVimView: NeoVimUiBridgeProtocol { extension NeoVimView: NeoVimUiBridgeProtocol {
public func resizeToWidth(width: Int32, height: Int32) { public func resize(toWidth width: Int32, height: Int32) {
DispatchUtils.gui { DispatchUtils.gui {
// NSLog("\(#function): \(width):\(height)") // NSLog("\(#function): \(width):\(height)")
self.grid.resize(Size(width: Int(width), height: Int(height))) self.grid.resize(Size(width: Int(width), height: Int(height)))
@ -1067,11 +1062,11 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
height: self.cellSize.height height: self.cellSize.height
) )
let rect = CGRect(origin: origin, size: size) let rect = CGRect(origin: origin, size: size)
self.setNeedsDisplayInRect(rect) self.setNeedsDisplay(rect)
} }
} }
public func gotoPosition(position: Position, screenCursor: Position) { public func gotoPosition(_ position: Position, screenCursor: Position) {
DispatchUtils.gui { DispatchUtils.gui {
// NSLog("\(#function): \(position), \(screenCursor)") // NSLog("\(#function): \(position), \(screenCursor)")
@ -1118,12 +1113,12 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func mouseOff() { public func mouseOff() {
} }
public func modeChange(mode: Mode) { public func modeChange(_ mode: Mode) {
// NSLog("mode changed to: %02x", mode.rawValue) // NSLog("mode changed to: %02x", mode.rawValue)
self.mode = mode self.mode = mode
} }
public func setScrollRegionToTop(top: Int32, bottom: Int32, left: Int32, right: Int32) { public func setScrollRegionToTop(_ top: Int32, bottom: Int32, left: Int32, right: Int32) {
DispatchUtils.gui { DispatchUtils.gui {
let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right)) let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right))
self.grid.setScrollRegion(region) self.grid.setScrollRegion(region)
@ -1131,20 +1126,20 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
} }
public func scroll(count: Int32) { public func scroll(_ count: Int32) {
DispatchUtils.gui { DispatchUtils.gui {
self.grid.scroll(Int(count)) self.grid.scroll(Int(count))
self.setNeedsDisplay(region: self.grid.region) self.setNeedsDisplay(region: self.grid.region)
} }
} }
public func highlightSet(attrs: CellAttributes) { public func highlightSet(_ attrs: CellAttributes) {
DispatchUtils.gui { DispatchUtils.gui {
self.grid.attrs = attrs self.grid.attrs = attrs
} }
} }
public func put(string: String, screenCursor: Position) { public func put(_ string: String, screenCursor: Position) {
DispatchUtils.gui { DispatchUtils.gui {
let curPos = self.grid.putPosition let curPos = self.grid.putPosition
// NSLog("\(#function): \(curPos) -> \(string)") // NSLog("\(#function): \(curPos) -> \(string)")
@ -1164,7 +1159,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
} }
public func putMarkedText(markedText: String, screenCursor: Position) { public func putMarkedText(_ markedText: String, screenCursor: Position) {
DispatchUtils.gui { DispatchUtils.gui {
NSLog("\(#function): '\(markedText)' -> \(screenCursor)") NSLog("\(#function): '\(markedText)' -> \(screenCursor)")
@ -1182,7 +1177,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
} }
public func unmarkRow(row: Int32, column: Int32) { public func unmarkRow(_ row: Int32, column: Int32) {
DispatchUtils.gui { DispatchUtils.gui {
let position = Position(row: Int(row), column: Int(column)) let position = Position(row: Int(row), column: Int(column))
@ -1208,7 +1203,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
// NSLog("\(#function)") // NSLog("\(#function)")
} }
public func updateForeground(fg: Int32, dark: Bool) { public func updateForeground(_ fg: Int32, dark: Bool) {
DispatchUtils.gui { DispatchUtils.gui {
self.grid.dark = dark self.grid.dark = dark
self.grid.foreground = UInt32(bitPattern: fg) self.grid.foreground = UInt32(bitPattern: fg)
@ -1216,16 +1211,16 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
} }
public func updateBackground(bg: Int32, dark: Bool) { public func updateBackground(_ bg: Int32, dark: Bool) {
DispatchUtils.gui { DispatchUtils.gui {
self.grid.dark = dark self.grid.dark = dark
self.grid.background = UInt32(bitPattern: bg) self.grid.background = UInt32(bitPattern: bg)
self.layer?.backgroundColor = ColorUtils.colorIgnoringAlpha(self.grid.background).CGColor self.layer?.backgroundColor = ColorUtils.colorIgnoringAlpha(self.grid.background).cgColor
// NSLog("\(ColorUtils.colorIgnoringAlpha(UInt32(bg)))") // NSLog("\(ColorUtils.colorIgnoringAlpha(UInt32(bg)))")
} }
} }
public func updateSpecial(sp: Int32, dark: Bool) { public func updateSpecial(_ sp: Int32, dark: Bool) {
DispatchUtils.gui { DispatchUtils.gui {
self.grid.dark = dark self.grid.dark = dark
self.grid.special = UInt32(bitPattern: sp) self.grid.special = UInt32(bitPattern: sp)
@ -1235,16 +1230,16 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
public func suspend() { public func suspend() {
} }
public func setTitle(title: String) { public func setTitle(_ title: String) {
DispatchUtils.gui { DispatchUtils.gui {
self.delegate?.setTitle(title) self.delegate?.setTitle(title)
} }
} }
public func setIcon(icon: String) { public func setIcon(_ icon: String) {
} }
public func setDirtyStatus(dirty: Bool) { public func setDirtyStatus(_ dirty: Bool) {
DispatchUtils.gui { DispatchUtils.gui {
self.delegate?.setDirtyStatus(dirty) self.delegate?.setDirtyStatus(dirty)
} }
@ -1263,7 +1258,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
} }
private func updateCursorWhenPutting(currentPosition curPos: Position, screenCursor: Position) { fileprivate func updateCursorWhenPutting(currentPosition curPos: Position, screenCursor: Position) {
if self.mode == .Cmdline { if self.mode == .Cmdline {
// When the cursor is in the command line, then we need this... // When the cursor is in the command line, then we need this...
self.setNeedsDisplay(cellPosition: self.grid.previousCellPosition(curPos)) self.setNeedsDisplay(cellPosition: self.grid.previousCellPosition(curPos))
@ -1276,11 +1271,11 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
self.grid.moveCursor(screenCursor) self.grid.moveCursor(screenCursor)
} }
private func setNeedsDisplay(region region: Region) { fileprivate func setNeedsDisplay(region: Region) {
self.setNeedsDisplayInRect(self.regionRectFor(region: region)) self.setNeedsDisplay(self.regionRectFor(region: region))
} }
private func setNeedsDisplay(cellPosition position: Position) { fileprivate func setNeedsDisplay(cellPosition position: Position) {
self.setNeedsDisplay(position: position) self.setNeedsDisplay(position: position)
if self.grid.isCellEmpty(position) { if self.grid.isCellEmpty(position) {
@ -1292,16 +1287,16 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
} }
} }
private func setNeedsDisplay(position position: Position) { fileprivate func setNeedsDisplay(position: Position) {
self.setNeedsDisplay(row: position.row, column: position.column) self.setNeedsDisplay(row: position.row, column: position.column)
} }
private func setNeedsDisplay(row row: Int, column: Int) { fileprivate func setNeedsDisplay(row: Int, column: Int) {
// Swift.print("\(#function): \(row):\(column)") // Swift.print("\(#function): \(row):\(column)")
self.setNeedsDisplayInRect(self.cellRectFor(row: row, column: column)) self.setNeedsDisplay(self.cellRectFor(row: row, column: column))
} }
private func setNeedsDisplay(screenCursor position: Position) { fileprivate func setNeedsDisplay(screenCursor position: Position) {
self.setNeedsDisplay(position: position) self.setNeedsDisplay(position: position)
if self.grid.isNextCellEmpty(position) { if self.grid.isNextCellEmpty(position) {
self.setNeedsDisplay(position: self.grid.nextCellPosition(position)) self.setNeedsDisplay(position: self.grid.nextCellPosition(position))

View File

@ -8,8 +8,8 @@ import Cocoa
// See http://stackoverflow.com/a/24104371 for class // See http://stackoverflow.com/a/24104371 for class
public protocol NeoVimViewDelegate: class { public protocol NeoVimViewDelegate: class {
func setTitle(title: String) func setTitle(_ title: String)
func setDirtyStatus(dirty: Bool) func setDirtyStatus(_ dirty: Bool)
func cwdChanged() func cwdChanged()
func neoVimStopped() func neoVimStopped()
} }

View File

@ -11,38 +11,38 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow! @IBOutlet weak var window: NSWindow!
private var workspace: Workspace = Workspace(mainView: NSView()) fileprivate var workspace: Workspace = Workspace(mainView: NSView())
@IBAction func toggleBars(sender: AnyObject!) { @IBAction func toggleBars(_ sender: AnyObject!) {
workspace.toggleAllTools() workspace.toggleAllTools()
} }
@IBAction func toggleButtons(sender: AnyObject!) { @IBAction func toggleButtons(_ sender: AnyObject!) {
workspace.toggleToolButtons() workspace.toggleToolButtons()
} }
func applicationDidFinishLaunching(aNotification: NSNotification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentView = self.window.contentView! let contentView = self.window.contentView!
let workspace = Workspace(mainView: self.view(NSColor.yellowColor())) let workspace = Workspace(mainView: self.view(NSColor.yellow))
self.workspace = workspace self.workspace = workspace
contentView.addSubview(workspace) contentView.addSubview(workspace)
workspace.autoPinEdgesToSuperviewEdges() workspace.autoPinEdgesToSuperviewEdges()
workspace.append(tool: WorkspaceTool(title: "Top-1", view: self.view(NSColor.whiteColor())), location: .top) workspace.append(tool: WorkspaceTool(title: "Top-1", view: self.view(NSColor.white)), location: .top)
workspace.append(tool: WorkspaceTool(title: "Right-1", view: self.view(NSColor.whiteColor())), location: .right) workspace.append(tool: WorkspaceTool(title: "Right-1", view: self.view(NSColor.white)), location: .right)
workspace.append(tool: WorkspaceTool(title: "Right-2", view: self.view(NSColor.greenColor())), location: .right) workspace.append(tool: WorkspaceTool(title: "Right-2", view: self.view(NSColor.green)), location: .right)
workspace.append(tool: WorkspaceTool(title: "Left-1", view: self.view(NSColor.whiteColor())), location: .left) workspace.append(tool: WorkspaceTool(title: "Left-1", view: self.view(NSColor.white)), location: .left)
workspace.append(tool: WorkspaceTool(title: "Left-2", view: self.view(NSColor.greenColor())), location: .left) workspace.append(tool: WorkspaceTool(title: "Left-2", view: self.view(NSColor.green)), location: .left)
workspace.append(tool: WorkspaceTool(title: "Left-3", view: self.view(NSColor.magentaColor())), location: .left) workspace.append(tool: WorkspaceTool(title: "Left-3", view: self.view(NSColor.magenta)), location: .left)
workspace.append(tool: WorkspaceTool(title: "Bottom-1", view: self.view(NSColor.whiteColor())), location: .bottom) workspace.append(tool: WorkspaceTool(title: "Bottom-1", view: self.view(NSColor.white)), location: .bottom)
workspace.append(tool: WorkspaceTool(title: "Bottom-2", view: self.view(NSColor.greenColor())), location: .bottom) workspace.append(tool: WorkspaceTool(title: "Bottom-2", view: self.view(NSColor.green)), location: .bottom)
} }
private func view(color: NSColor) -> NSView { fileprivate func view(_ color: NSColor) -> NSView {
let view = NSView(forAutoLayout: ()) let view = NSView(forAutoLayout: ())
view.wantsLayer = true view.wantsLayer = true
view.layer?.backgroundColor = color.CGColor view.layer?.backgroundColor = color.cgColor
return view return view
} }
} }

View File

@ -819,18 +819,20 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0730; LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0730; LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "Tae Won Ha"; ORGANIZATIONNAME = "Tae Won Ha";
TargetAttributes = { TargetAttributes = {
4B2A2BF61D0351810074CE9A = { 4B2A2BF61D0351810074CE9A = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = H96Q2NKTQH; DevelopmentTeam = H96Q2NKTQH;
LastSwiftMigration = 0800;
}; };
4B56F28F1D29903F00C1F92E = { 4B56F28F1D29903F00C1F92E = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
}; };
4B64239E1D8EFE7500FC78C8 = { 4B64239E1D8EFE7500FC78C8 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
4B854A191D31447C00E08DE1 = { 4B854A191D31447C00E08DE1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
@ -838,9 +840,11 @@
4BEBA5041CFF374B00673FDF = { 4BEBA5041CFF374B00673FDF = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = H96Q2NKTQH; DevelopmentTeam = H96Q2NKTQH;
LastSwiftMigration = 0800;
}; };
4BEBA5131CFF374B00673FDF = { 4BEBA5131CFF374B00673FDF = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
}; };
}; };
@ -1143,6 +1147,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -1166,6 +1171,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR.SwiftNeoVim; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR.SwiftNeoVim;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -1212,6 +1218,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo"; PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -1228,6 +1235,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo"; PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -1295,8 +1303,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
@ -1342,8 +1352,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
@ -1370,10 +1382,10 @@
4BEBA51E1CFF374B00673FDF /* Debug */ = { 4BEBA51E1CFF374B00673FDF /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac", "$(PROJECT_DIR)/Carthage/Build/Mac",
@ -1383,16 +1395,17 @@
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR;
PRODUCT_NAME = VimR; PRODUCT_NAME = VimR;
SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h; SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h;
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
4BEBA51F1CFF374B00673FDF /* Release */ = { 4BEBA51F1CFF374B00673FDF /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac", "$(PROJECT_DIR)/Carthage/Build/Mac",
@ -1402,6 +1415,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR;
PRODUCT_NAME = VimR; PRODUCT_NAME = VimR;
SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h; SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h;
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -1417,6 +1431,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimRTests; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimRTests;
PRODUCT_NAME = VimRTests; PRODUCT_NAME = VimRTests;
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -1432,6 +1447,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimRTests; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimRTests;
PRODUCT_NAME = VimRTests; PRODUCT_NAME = VimRTests;
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0730" LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0730" LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0730" LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0730" LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0800"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -25,9 +25,9 @@ class AdvancedPrefPane: PrefPane {
return true return true
} }
private var data: AdvancedPrefData fileprivate var data: AdvancedPrefData
private let useInteractiveZshCheckbox = NSButton(forAutoLayout: ()) fileprivate let useInteractiveZshCheckbox = NSButton(forAutoLayout: ())
init(source: Observable<Any>, initialData: AdvancedPrefData) { init(source: Observable<Any>, initialData: AdvancedPrefData) {
self.data = initialData self.data = initialData
@ -59,20 +59,20 @@ class AdvancedPrefPane: PrefPane {
self.addSubview(useInteractiveZsh) self.addSubview(useInteractiveZsh)
self.addSubview(useInteractiveZshInfo) self.addSubview(useInteractiveZshInfo)
paneTitle.autoPinEdgeToSuperviewEdge(.Top, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
paneTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
paneTitle.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual) paneTitle.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
useInteractiveZsh.autoPinEdge(.Top, toEdge: .Bottom, ofView: paneTitle, withOffset: 18) useInteractiveZsh.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
useInteractiveZsh.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) useInteractiveZsh.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
useInteractiveZshInfo.autoPinEdge(.Top, toEdge: .Bottom, ofView: useInteractiveZsh, withOffset: 5) useInteractiveZshInfo.autoPinEdge(.top, to: .bottom, of: useInteractiveZsh, withOffset: 5)
useInteractiveZshInfo.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) useInteractiveZshInfo.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
useInteractiveZsh.boolState = self.data.useInteractiveZsh useInteractiveZsh.boolState = self.data.useInteractiveZsh
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return source return source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { ($0 as! PrefData).advanced } .map { ($0 as! PrefData).advanced }
@ -83,12 +83,12 @@ class AdvancedPrefPane: PrefPane {
} }
} }
private func set(data data: AdvancedPrefData) { fileprivate func set(data: AdvancedPrefData) {
self.data = data self.data = data
self.publish(event: data) self.publish(event: data)
} }
private func updateViews(newData newData: AdvancedPrefData) { fileprivate func updateViews(newData: AdvancedPrefData) {
self.useInteractiveZshCheckbox.boolState = newData.useInteractiveZsh self.useInteractiveZshCheckbox.boolState = newData.useInteractiveZsh
} }
} }
@ -96,7 +96,7 @@ class AdvancedPrefPane: PrefPane {
// MARK: - Actions // MARK: - Actions
extension AdvancedPrefPane { extension AdvancedPrefPane {
func useInteractiveZshAction(sender: NSButton) { func useInteractiveZshAction(_ sender: NSButton) {
self.set(data: AdvancedPrefData(useInteractiveZsh: self.useInteractiveZshCheckbox.boolState)) self.set(data: AdvancedPrefData(useInteractiveZsh: self.useInteractiveZshCheckbox.boolState))
} }
} }

View File

@ -23,24 +23,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet var debugMenu: NSMenuItem! @IBOutlet var debugMenu: NSMenuItem!
private let disposeBag = DisposeBag() fileprivate let disposeBag = DisposeBag()
private let changeSubject = PublishSubject<Any>() fileprivate let changeSubject = PublishSubject<Any>()
private let changeSink: Observable<Any> fileprivate let changeSink: Observable<Any>
private let actionSubject = PublishSubject<Any>() fileprivate let actionSubject = PublishSubject<Any>()
private let actionSink: Observable<Any> fileprivate let actionSink: Observable<Any>
private let prefStore: PrefStore fileprivate let prefStore: PrefStore
private let mainWindowManager: MainWindowManager fileprivate let mainWindowManager: MainWindowManager
private let openQuicklyWindowManager: OpenQuicklyWindowManager fileprivate let openQuicklyWindowManager: OpenQuicklyWindowManager
private let prefWindowComponent: PrefWindowComponent fileprivate let prefWindowComponent: PrefWindowComponent
private let fileItemService = FileItemService() fileprivate let fileItemService = FileItemService()
private var quitWhenAllWindowsAreClosed = false fileprivate var quitWhenAllWindowsAreClosed = false
private var launching = true fileprivate var launching = true
override init() { override init() {
self.actionSink = self.actionSubject.asObservable() self.actionSink = self.actionSubject.asObservable()
@ -103,17 +103,17 @@ class AppDelegate: NSObject, NSApplicationDelegate {
// MARK: - NSApplicationDelegate // MARK: - NSApplicationDelegate
extension AppDelegate { extension AppDelegate {
func applicationWillFinishLaunching(_: NSNotification) { func applicationWillFinishLaunching(_: Notification) {
self.launching = true self.launching = true
let appleEventManager = NSAppleEventManager.sharedAppleEventManager() let appleEventManager = NSAppleEventManager.shared()
appleEventManager.setEventHandler(self, appleEventManager.setEventHandler(self,
andSelector: #selector(AppDelegate.handleGetUrlEvent(_:withReplyEvent:)), andSelector: #selector(AppDelegate.handleGetUrlEvent(_:withReplyEvent:)),
forEventClass: UInt32(kInternetEventClass), forEventClass: UInt32(kInternetEventClass),
andEventID: UInt32(kAEGetURL)) andEventID: UInt32(kAEGetURL))
} }
func applicationDidFinishLaunching(_: NSNotification) { func applicationDidFinishLaunching(_: Notification) {
// let testView = InputTestView(frame: CGRect(x: 0, y: 0, width: 300, height: 300)) // let testView = InputTestView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
// self.window.contentView?.addSubview(testView) // self.window.contentView?.addSubview(testView)
// self.window.makeFirstResponder(testView) // self.window.makeFirstResponder(testView)
@ -121,11 +121,11 @@ extension AppDelegate {
self.launching = false self.launching = false
#if DEBUG #if DEBUG
self.debugMenu.hidden = false self.debugMenu.isHidden = false
#endif #endif
} }
func applicationOpenUntitledFile(sender: NSApplication) -> Bool { func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool {
if self.launching { if self.launching {
if self.prefStore.data.general.openNewWindowWhenLaunching { if self.prefStore.data.general.openNewWindowWhenLaunching {
self.newDocument(self) self.newDocument(self)
@ -141,50 +141,50 @@ extension AppDelegate {
return false return false
} }
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply { func applicationShouldTerminate(_ sender: NSApplication) -> NSApplicationTerminateReply {
if self.mainWindowManager.hasDirtyWindows() { if self.mainWindowManager.hasDirtyWindows() {
let alert = NSAlert() let alert = NSAlert()
alert.addButtonWithTitle("Cancel") alert.addButton(withTitle: "Cancel")
alert.addButtonWithTitle("Discard and Quit") alert.addButton(withTitle: "Discard and Quit")
alert.messageText = "There are windows with unsaved buffers!" alert.messageText = "There are windows with unsaved buffers!"
alert.alertStyle = .WarningAlertStyle alert.alertStyle = .warning
if alert.runModal() == NSAlertSecondButtonReturn { if alert.runModal() == NSAlertSecondButtonReturn {
self.quitWhenAllWindowsAreClosed = true self.quitWhenAllWindowsAreClosed = true
self.mainWindowManager.closeAllWindowsWithoutSaving() self.mainWindowManager.closeAllWindowsWithoutSaving()
} }
return .TerminateCancel return .terminateCancel
} }
if self.mainWindowManager.hasMainWindow() { if self.mainWindowManager.hasMainWindow() {
self.quitWhenAllWindowsAreClosed = true self.quitWhenAllWindowsAreClosed = true
self.mainWindowManager.closeAllWindows() self.mainWindowManager.closeAllWindows()
return .TerminateCancel return .terminateCancel
} }
// There are no open main window, then just quit. // There are no open main window, then just quit.
return .TerminateNow return .terminateNow
} }
// For drag & dropping files on the App icon. // For drag & dropping files on the App icon.
func application(sender: NSApplication, openFiles filenames: [String]) { func application(_ sender: NSApplication, openFiles filenames: [String]) {
let urls = filenames.map { NSURL(fileURLWithPath: $0) } let urls = filenames.map { URL(fileURLWithPath: $0) }
self.mainWindowManager.newMainWindow(urls: urls) self.mainWindowManager.newMainWindow(urls: urls)
sender.replyToOpenOrPrint(.Success) sender.reply(toOpenOrPrint: .success)
} }
} }
// MARK: - AppleScript // MARK: - AppleScript
extension AppDelegate { extension AppDelegate {
func handleGetUrlEvent(event: NSAppleEventDescriptor, withReplyEvent: NSAppleEventDescriptor) { func handleGetUrlEvent(_ event: NSAppleEventDescriptor, withReplyEvent: NSAppleEventDescriptor) {
guard let urlString = event.paramDescriptorForKeyword(UInt32(keyDirectObject))?.stringValue else { guard let urlString = event.paramDescriptor(forKeyword: UInt32(keyDirectObject))?.stringValue else {
return return
} }
guard let url = NSURL(string: urlString) else { guard let url = URL(string: urlString) else {
return return
} }
@ -200,16 +200,16 @@ extension AppDelegate {
return return
} }
let queryParams = url.query?.componentsSeparatedByString("&") let queryParams = url.query?.components(separatedBy: "&")
let urls = queryParams? let urls = queryParams?
.filter { $0.hasPrefix(filePrefix) } .filter { $0.hasPrefix(filePrefix) }
.flatMap { $0.without(prefix: filePrefix).stringByRemovingPercentEncoding } .flatMap { $0.without(prefix: filePrefix).removingPercentEncoding }
.map { NSURL(fileURLWithPath: $0) } ?? [] .map { URL(fileURLWithPath: $0) } ?? []
let cwd = queryParams? let cwd = queryParams?
.filter { $0.hasPrefix(cwdPrefix) } .filter { $0.hasPrefix(cwdPrefix) }
.flatMap { $0.without(prefix: cwdPrefix).stringByRemovingPercentEncoding } .flatMap { $0.without(prefix: cwdPrefix).removingPercentEncoding }
.map { NSURL(fileURLWithPath: $0) } .map { URL(fileURLWithPath: $0) }
.first ?? NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) .first ?? URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
switch action { switch action {
case .activate, .newWindow: case .activate, .newWindow:
@ -228,24 +228,24 @@ extension AppDelegate {
// MARK: - IBActions // MARK: - IBActions
extension AppDelegate { extension AppDelegate {
@IBAction func showPrefWindow(sender: AnyObject!) { @IBAction func showPrefWindow(_ sender: AnyObject!) {
self.prefWindowComponent.show() self.prefWindowComponent.show()
} }
@IBAction func newDocument(sender: AnyObject!) { @IBAction func newDocument(_ sender: AnyObject!) {
self.mainWindowManager.newMainWindow() self.mainWindowManager.newMainWindow()
} }
// Invoked when no main window is open. // Invoked when no main window is open.
@IBAction func openDocument(sender: AnyObject!) { @IBAction func openDocument(_ sender: AnyObject!) {
let panel = NSOpenPanel() let panel = NSOpenPanel()
panel.canChooseDirectories = true panel.canChooseDirectories = true
panel.beginWithCompletionHandler { result in panel.begin { result in
guard result == NSFileHandlingPanelOKButton else { guard result == NSFileHandlingPanelOKButton else {
return return
} }
self.mainWindowManager.newMainWindow(urls: panel.URLs) self.mainWindowManager.newMainWindow(urls: panel.urls)
} }
} }
} }

View File

@ -21,26 +21,26 @@ extension NSButton {
extension NSAttributedString { extension NSAttributedString {
func draw(at point: CGPoint, angle: CGFloat) { func draw(at point: CGPoint, angle: CGFloat) {
let translation = NSAffineTransform() var translation = AffineTransform.identity
let rotation = NSAffineTransform() var rotation = AffineTransform.identity
translation.translateXBy(point.x, yBy: point.y) translation.translate(x: point.x, y: point.y)
rotation.rotateByRadians(angle) rotation.rotate(byRadians: angle)
translation.concat() (translation as NSAffineTransform).concat()
rotation.concat() (rotation as NSAffineTransform).concat()
self.drawAtPoint(CGPoint.zero) self.draw(at: CGPoint.zero)
rotation.invert() rotation.invert()
translation.invert() translation.invert()
rotation.concat() (rotation as NSAffineTransform).concat()
translation.concat() (translation as NSAffineTransform).concat()
} }
// From https://developer.apple.com/library/mac/qa/qa1487/_index.html // From https://developer.apple.com/library/mac/qa/qa1487/_index.html
static func link(withUrl url: NSURL, text: String, font: NSFont? = nil) -> NSAttributedString { static func link(withUrl url: URL, text: String, font: NSFont? = nil) -> NSAttributedString {
let attrString = NSMutableAttributedString(string: text) let attrString = NSMutableAttributedString(string: text)
let range = NSRange(location: 0, length: attrString.length) let range = NSRange(location: 0, length: attrString.length)
@ -49,9 +49,9 @@ extension NSAttributedString {
attrString.addAttribute(NSFontAttributeName, value: font!, range: range) attrString.addAttribute(NSFontAttributeName, value: font!, range: range)
} }
attrString.addAttribute(NSLinkAttributeName, value: url.absoluteString, range: range) attrString.addAttribute(NSLinkAttributeName, value: url.absoluteString, range: range)
attrString.addAttribute(NSForegroundColorAttributeName, value: NSColor.blueColor(), range: range) attrString.addAttribute(NSForegroundColorAttributeName, value: NSColor.blue, range: range)
attrString.addAttribute(NSUnderlineStyleAttributeName, attrString.addAttribute(NSUnderlineStyleAttributeName,
value: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), range: range) value: NSNumber(value: NSUnderlineStyle.styleSingle.rawValue as Int), range: range)
attrString.endEditing() attrString.endEditing()
return attrString return attrString
@ -79,22 +79,22 @@ extension NSTableView {
let tableView = NSTableView(frame: CGRect.zero) let tableView = NSTableView(frame: CGRect.zero)
let column = NSTableColumn(identifier: "name") let column = NSTableColumn(identifier: "name")
column.editable = false column.isEditable = false
tableView.addTableColumn(column) tableView.addTableColumn(column)
tableView.rowSizeStyle = .Default tableView.rowSizeStyle = .default
tableView.sizeLastColumnToFit() tableView.sizeLastColumnToFit()
tableView.allowsEmptySelection = false tableView.allowsEmptySelection = false
tableView.allowsMultipleSelection = false tableView.allowsMultipleSelection = false
tableView.headerView = nil tableView.headerView = nil
tableView.focusRingType = .None tableView.focusRingType = .none
return tableView return tableView
} }
static func standardSourceListTableView() -> NSTableView { static func standardSourceListTableView() -> NSTableView {
let tableView = self.standardTableView() let tableView = self.standardTableView()
tableView.selectionHighlightStyle = .SourceList tableView.selectionHighlightStyle = .sourceList
return tableView return tableView
} }
@ -109,7 +109,7 @@ extension NSScrollView {
scrollView.hasVerticalScroller = true scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true scrollView.hasHorizontalScroller = true
scrollView.autohidesScrollers = true scrollView.autohidesScrollers = true
scrollView.borderType = .BezelBorder scrollView.borderType = .bezelBorder
return scrollView return scrollView
} }

View File

@ -13,7 +13,7 @@ struct AppearancePrefData: Equatable {
} }
func == (left: AppearancePrefData, right: AppearancePrefData) -> Bool { func == (left: AppearancePrefData, right: AppearancePrefData) -> Bool {
return left.editorUsesLigatures == right.editorUsesLigatures && left.editorFont.isEqualTo(right.editorFont) return left.editorUsesLigatures == right.editorUsesLigatures && left.editorFont.isEqual(to: right.editorFont)
} }
class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDelegate { class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDelegate {
@ -26,21 +26,21 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
return true return true
} }
private var data: AppearancePrefData { fileprivate var data: AppearancePrefData {
didSet { didSet {
self.updateViews(newData: self.data) self.updateViews(newData: self.data)
} }
} }
private let fontManager = NSFontManager.sharedFontManager() fileprivate let fontManager = NSFontManager.shared()
private let sizes = [9, 10, 11, 12, 13, 14, 16, 18, 24, 36, 48, 64] fileprivate let sizes = [9, 10, 11, 12, 13, 14, 16, 18, 24, 36, 48, 64]
private let sizeCombo = NSComboBox(forAutoLayout: ()) fileprivate let sizeCombo = NSComboBox(forAutoLayout: ())
private let fontPopup = NSPopUpButton(frame: CGRect.zero, pullsDown: false) fileprivate let fontPopup = NSPopUpButton(frame: CGRect.zero, pullsDown: false)
private let ligatureCheckbox = NSButton(forAutoLayout: ()) fileprivate let ligatureCheckbox = NSButton(forAutoLayout: ())
private let previewArea = NSTextView(frame: CGRect.zero) fileprivate let previewArea = NSTextView(frame: CGRect.zero)
private let exampleText = fileprivate let exampleText =
"abcdefghijklmnopqrstuvwxyz\n" + "abcdefghijklmnopqrstuvwxyz\n" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" +
"0123456789\n" + "0123456789\n" +
@ -59,12 +59,12 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
private func set(data data: AppearancePrefData) { fileprivate func set(data: AppearancePrefData) {
self.data = data self.data = data
self.publish(event: data) self.publish(event: data)
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return source return source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { ($0 as! PrefData).appearance } .map { ($0 as! PrefData).appearance }
@ -83,14 +83,14 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
fontPopup.translatesAutoresizingMaskIntoConstraints = false fontPopup.translatesAutoresizingMaskIntoConstraints = false
fontPopup.target = self fontPopup.target = self
fontPopup.action = #selector(AppearancePrefPane.fontPopupAction) fontPopup.action = #selector(AppearancePrefPane.fontPopupAction)
fontPopup.addItemsWithTitles(self.fontManager.availableFontNamesWithTraits(.FixedPitchFontMask)!) fontPopup.addItems(withTitles: self.fontManager.availableFontNames(with: .fixedPitchFontMask)!)
let sizeCombo = self.sizeCombo let sizeCombo = self.sizeCombo
sizeCombo.setDelegate(self) sizeCombo.delegate = self
sizeCombo.target = self sizeCombo.target = self
sizeCombo.action = #selector(AppearancePrefPane.sizeComboBoxDidEnter(_:)) sizeCombo.action = #selector(AppearancePrefPane.sizeComboBoxDidEnter(_:))
self.sizes.forEach { string in self.sizes.forEach { string in
sizeCombo.addItemWithObjectValue(string) sizeCombo.addItem(withObjectValue: string)
} }
let ligatureCheckbox = self.ligatureCheckbox let ligatureCheckbox = self.ligatureCheckbox
@ -99,23 +99,23 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
action: #selector(AppearancePrefPane.usesLigaturesAction(_:))) action: #selector(AppearancePrefPane.usesLigaturesAction(_:)))
let previewArea = self.previewArea let previewArea = self.previewArea
previewArea.editable = true previewArea.isEditable = true
previewArea.maxSize = CGSize(width: CGFloat.max, height: CGFloat.max) previewArea.maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
previewArea.verticallyResizable = true previewArea.isVerticallyResizable = true
previewArea.horizontallyResizable = true previewArea.isHorizontallyResizable = true
previewArea.textContainer?.heightTracksTextView = false previewArea.textContainer?.heightTracksTextView = false
previewArea.textContainer?.widthTracksTextView = false previewArea.textContainer?.widthTracksTextView = false
previewArea.autoresizingMask = [ .ViewWidthSizable, .ViewHeightSizable] previewArea.autoresizingMask = [ .viewWidthSizable, .viewHeightSizable]
previewArea.textContainer?.containerSize = CGSize.init(width: CGFloat.max, height: CGFloat.max) previewArea.textContainer?.containerSize = CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
previewArea.layoutManager?.replaceTextStorage(NSTextStorage(string: self.exampleText)) previewArea.layoutManager?.replaceTextStorage(NSTextStorage(string: self.exampleText))
previewArea.richText = false previewArea.isRichText = false
previewArea.turnOffLigatures(self) previewArea.turnOffLigatures(self)
let previewScrollView = NSScrollView(forAutoLayout: ()) let previewScrollView = NSScrollView(forAutoLayout: ())
previewScrollView.hasVerticalScroller = true previewScrollView.hasVerticalScroller = true
previewScrollView.hasHorizontalScroller = true previewScrollView.hasHorizontalScroller = true
previewScrollView.autohidesScrollers = true previewScrollView.autohidesScrollers = true
previewScrollView.borderType = .BezelBorder previewScrollView.borderType = .bezelBorder
previewScrollView.documentView = previewArea previewScrollView.documentView = previewArea
self.addSubview(paneTitle) self.addSubview(paneTitle)
@ -126,31 +126,31 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
self.addSubview(ligatureCheckbox) self.addSubview(ligatureCheckbox)
self.addSubview(previewScrollView) self.addSubview(previewScrollView)
paneTitle.autoPinEdgeToSuperviewEdge(.Top, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
paneTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
fontTitle.autoPinEdge(.Left, toEdge: .Left, ofView: paneTitle) fontTitle.autoPinEdge(.left, to: .left, of: paneTitle)
fontTitle.autoAlignAxis(.Baseline, toSameAxisOfView: fontPopup) fontTitle.autoAlignAxis(.baseline, toSameAxisOf: fontPopup)
fontPopup.autoPinEdge(.Top, toEdge: .Bottom, ofView: paneTitle, withOffset: 18) fontPopup.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
fontPopup.autoPinEdge(.Left, toEdge: .Right, ofView: fontTitle, withOffset: 5) fontPopup.autoPinEdge(.left, to: .right, of: fontTitle, withOffset: 5)
fontPopup.autoSetDimension(.Width, toSize: 240) fontPopup.autoSetDimension(.width, toSize: 240)
sizeCombo.autoSetDimension(.Width, toSize: 60) sizeCombo.autoSetDimension(.width, toSize: 60)
// If we use .Baseline the combo box is placed one pixel off... // If we use .Baseline the combo box is placed one pixel off...
sizeCombo.autoAlignAxis(.Horizontal, toSameAxisOfView: fontPopup) sizeCombo.autoAlignAxis(.horizontal, toSameAxisOf: fontPopup)
sizeCombo.autoPinEdge(.Left, toEdge: .Right, ofView: fontPopup, withOffset: 5) sizeCombo.autoPinEdge(.left, to: .right, of: fontPopup, withOffset: 5)
ligatureCheckbox.autoPinEdge(.Top, toEdge: .Bottom, ofView: sizeCombo, withOffset: 18) ligatureCheckbox.autoPinEdge(.top, to: .bottom, of: sizeCombo, withOffset: 18)
ligatureCheckbox.autoPinEdge(.Left, toEdge: .Right, ofView: fontTitle, withOffset: 5) ligatureCheckbox.autoPinEdge(.left, to: .right, of: fontTitle, withOffset: 5)
previewScrollView.autoSetDimension(.Height, toSize: 200, relation: .GreaterThanOrEqual) previewScrollView.autoSetDimension(.height, toSize: 200, relation: .greaterThanOrEqual)
previewScrollView.autoPinEdge(.Top, toEdge: .Bottom, ofView: ligatureCheckbox, withOffset: 18) previewScrollView.autoPinEdge(.top, to: .bottom, of: ligatureCheckbox, withOffset: 18)
previewScrollView.autoPinEdgeToSuperviewEdge(.Right, withInset: 18) previewScrollView.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
previewScrollView.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 18) previewScrollView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 18)
previewScrollView.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) previewScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
self.fontPopup.selectItemWithTitle(self.data.editorFont.fontName) self.fontPopup.selectItem(withTitle: self.data.editorFont.fontName)
self.sizeCombo.stringValue = String(Int(self.data.editorFont.pointSize)) self.sizeCombo.stringValue = String(Int(self.data.editorFont.pointSize))
self.ligatureCheckbox.state = self.data.editorUsesLigatures ? NSOnState : NSOffState self.ligatureCheckbox.state = self.data.editorUsesLigatures ? NSOnState : NSOffState
self.previewArea.font = self.data.editorFont self.previewArea.font = self.data.editorFont
@ -161,10 +161,10 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
} }
} }
private func updateViews(newData newData: AppearancePrefData) { fileprivate func updateViews(newData: AppearancePrefData) {
let newFont = newData.editorFont let newFont = newData.editorFont
self.fontPopup.selectItemWithTitle(newFont.fontName) self.fontPopup.selectItem(withTitle: newFont.fontName)
self.sizeCombo.stringValue = String(Int(newFont.pointSize)) self.sizeCombo.stringValue = String(Int(newFont.pointSize))
self.ligatureCheckbox.boolState = newData.editorUsesLigatures self.ligatureCheckbox.boolState = newData.editorUsesLigatures
self.previewArea.font = newData.editorFont self.previewArea.font = newData.editorFont
@ -180,16 +180,16 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
// MARK: - Actions // MARK: - Actions
extension AppearancePrefPane { extension AppearancePrefPane {
func usesLigaturesAction(sender: NSButton) { func usesLigaturesAction(_ sender: NSButton) {
self.set(data: AppearancePrefData(editorFont: self.data.editorFont, editorUsesLigatures: sender.boolState)) self.set(data: AppearancePrefData(editorFont: self.data.editorFont, editorUsesLigatures: sender.boolState))
} }
func fontPopupAction(sender: NSPopUpButton) { func fontPopupAction(_ sender: NSPopUpButton) {
guard let selectedItem = self.fontPopup.selectedItem else { guard let selectedItem = self.fontPopup.selectedItem else {
return return
} }
guard selectedItem != self.data.editorFont.fontName else { guard selectedItem.title != self.data.editorFont.fontName else {
return return
} }
@ -200,25 +200,25 @@ extension AppearancePrefPane {
self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures)) self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures))
} }
func comboBoxSelectionDidChange(notification: NSNotification) { func comboBoxSelectionDidChange(_ notification: Notification) {
guard notification.object! === self.sizeCombo else { guard (notification.object as! NSComboBox) === self.sizeCombo else {
return return
} }
let newFontSize = self.cappedFontSize(Int(self.sizes[self.sizeCombo.indexOfSelectedItem])) let newFontSize = self.cappedFontSize(Int(self.sizes[self.sizeCombo.indexOfSelectedItem]))
let newFont = self.fontManager.convertFont(self.data.editorFont, toSize: newFontSize) let newFont = self.fontManager.convert(self.data.editorFont, toSize: newFontSize)
self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures)) self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures))
} }
func sizeComboBoxDidEnter(sender: AnyObject!) { func sizeComboBoxDidEnter(_ sender: AnyObject!) {
let newFontSize = self.cappedFontSize(self.sizeCombo.integerValue) let newFontSize = self.cappedFontSize(self.sizeCombo.integerValue)
let newFont = self.fontManager.convertFont(self.data.editorFont, toSize: newFontSize) let newFont = self.fontManager.convert(self.data.editorFont, toSize: newFontSize)
self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures)) self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures))
} }
private func cappedFontSize(size: Int) -> CGFloat { fileprivate func cappedFontSize(_ size: Int) -> CGFloat {
guard size >= 4 else { guard size >= 4 else {
return 13 return 13
} }

View File

@ -24,7 +24,7 @@ class Application: NSApplication {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@IBAction override func showHelp(sender: AnyObject!) { @IBAction override func showHelp(_ sender: Any!) {
NSWorkspace.sharedWorkspace().openURL(NSURL(string: "https://github.com/qvacua/vimr/wiki")!) NSWorkspace.shared().open(URL(string: "https://github.com/qvacua/vimr/wiki")!)
} }
} }

View File

@ -34,11 +34,11 @@ class StandardFlow: Flow {
self.subject.onCompleted() self.subject.onCompleted()
} }
func subscription(source source: Observable<Any>) -> Disposable { func subscription(source: Observable<Any>) -> Disposable {
preconditionFailure("Please override") preconditionFailure("Please override")
} }
func publish(event event: Any) { func publish(event: Any) {
self.subject.onNext(event) self.subject.onNext(event)
} }
} }
@ -69,11 +69,11 @@ class StandardComponent: NSObject, Component {
preconditionFailure("Please override") preconditionFailure("Please override")
} }
func subscription(source source: Observable<Any>) -> Disposable { func subscription(source: Observable<Any>) -> Disposable {
preconditionFailure("Please override") preconditionFailure("Please override")
} }
func publish(event event: Any) { func publish(event: Any) {
self.subject.onNext(event) self.subject.onNext(event)
} }
} }

View File

@ -7,7 +7,7 @@ import Foundation
class FileItem : CustomStringConvertible { class FileItem : CustomStringConvertible {
let url: NSURL let url: URL
let dir: Bool let dir: Bool
let hidden: Bool let hidden: Bool
let package: Bool let package: Bool
@ -28,18 +28,18 @@ class FileItem : CustomStringConvertible {
+ "children=\(self.children.count)>" + "children=\(self.children.count)>"
} }
init(_ url: NSURL) { init(_ url: URL) {
self.url = url self.url = url
self.dir = url.dir self.dir = url.dir
self.hidden = url.hidden self.hidden = url.hidden
self.package = url.package self.package = url.package
} }
func removeChild(withUrl url: NSURL) { func removeChild(withUrl url: URL) {
guard let idx = self.children.indexOf({ $0.url == url }) else { guard let idx = self.children.index(where: { $0.url == url }) else {
return return
} }
self.children.removeAtIndex(idx) self.children.remove(at: idx)
} }
} }

View File

@ -22,7 +22,7 @@ class FileItemIgnorePattern: Hashable, CustomStringConvertible {
let folderPattern: Bool let folderPattern: Bool
let pattern: String let pattern: String
private let patternAsFileSysRep: UnsafeMutablePointer<Int8> fileprivate let patternAsFileSysRep: UnsafeMutablePointer<Int8>
init(pattern: String) { init(pattern: String) {
self.pattern = pattern self.pattern = pattern
@ -31,14 +31,14 @@ class FileItemIgnorePattern: Hashable, CustomStringConvertible {
let fileSysRep = (pattern as NSString).fileSystemRepresentation let fileSysRep = (pattern as NSString).fileSystemRepresentation
let len = Int(strlen(fileSysRep)) let len = Int(strlen(fileSysRep))
self.patternAsFileSysRep = UnsafeMutablePointer<Int8>.alloc(len + 1) self.patternAsFileSysRep = UnsafeMutablePointer<Int8>.allocate(capacity: len + 1)
memcpy(self.patternAsFileSysRep, fileSysRep, len) memcpy(self.patternAsFileSysRep, fileSysRep, len)
self.patternAsFileSysRep[len] = 0 self.patternAsFileSysRep[len] = 0
} }
deinit { deinit {
let len = Int(strlen(self.patternAsFileSysRep)) let len = Int(strlen(self.patternAsFileSysRep))
self.patternAsFileSysRep.dealloc(len + 1) self.patternAsFileSysRep.deallocate(capacity: len + 1)
} }
func match(absolutePath path: String) -> Bool { func match(absolutePath path: String) -> Bool {
@ -57,4 +57,4 @@ class FileItemIgnorePattern: Hashable, CustomStringConvertible {
return matches != FNM_NOMATCH return matches != FNM_NOMATCH
} }
} }

View File

@ -15,31 +15,31 @@ class Token: Equatable {}
class FileItemService { class FileItemService {
private(set) var ignorePatterns: Set<FileItemIgnorePattern> = [] { fileprivate(set) var ignorePatterns: Set<FileItemIgnorePattern> = [] {
didSet { didSet {
self.ignoreToken = Token() self.ignoreToken = Token()
} }
} }
/// Used to cache fnmatch calls in `FileItem`. /// Used to cache fnmatch calls in `FileItem`.
private var ignoreToken = Token() fileprivate var ignoreToken = Token()
/// When at least this much of non-directory and visible files are scanned, they are emitted. /// When at least this much of non-directory and visible files are scanned, they are emitted.
private let emitChunkSize = 1000 fileprivate let emitChunkSize = 1000
private let scanDispatchQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0) fileprivate let scanDispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)
private let monitorDispatchQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0) fileprivate let monitorDispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)
private let root = FileItem(NSURL(fileURLWithPath: "/", isDirectory: true)) fileprivate let root = FileItem(URL(fileURLWithPath: "/", isDirectory: true))
private let fileSystemEventsLatency = Double(2) fileprivate let fileSystemEventsLatency = Double(2)
private var monitors = [NSURL: FileSystemEventMonitor]() fileprivate var monitors = [URL: FileSystemEventMonitor]()
private var monitorCounter = [NSURL: Int]() fileprivate var monitorCounter = [URL: Int]()
private let workspace = NSWorkspace.sharedWorkspace() fileprivate let workspace = NSWorkspace.shared()
private let iconsCache = NSCache() fileprivate let iconsCache = NSCache<NSURL, NSImage>()
private var spinLock = OS_SPINLOCK_INIT fileprivate var spinLock = OS_SPINLOCK_INIT
init() { init() {
self.iconsCache.countLimit = 2000 self.iconsCache.countLimit = 2000
@ -50,22 +50,17 @@ class FileItemService {
self.ignorePatterns = patterns self.ignorePatterns = patterns
} }
func icon(forUrl url: NSURL) -> NSImage? { func icon(forUrl url: URL) -> NSImage? {
guard let path = url.path else { let path = url.path
return nil let icon = workspace.icon(forFile: path)
}
let icon = workspace.iconForFile(path)
icon.size = CGSize(width: 16, height: 16) icon.size = CGSize(width: 16, height: 16)
self.iconsCache.setObject(icon, forKey: url) self.iconsCache.setObject(icon, forKey: url as NSURL)
return icon return icon
} }
func monitor(url url: NSURL) { func monitor(url: URL) {
guard let path = url.path else { let path = url.path
return
}
// FIXME: Handle EonilFileSystemEventFlag.RootChanged, ie watchRoot: true // FIXME: Handle EonilFileSystemEventFlag.RootChanged, ie watchRoot: true
let monitor = FileSystemEventMonitor(pathsToWatch: [path], let monitor = FileSystemEventMonitor(pathsToWatch: [path],
@ -73,7 +68,7 @@ class FileItemService {
watchRoot: false, watchRoot: false,
queue: self.monitorDispatchQueue) queue: self.monitorDispatchQueue)
{ [unowned self] events in { [unowned self] events in
let urls = events.map { NSURL(fileURLWithPath: $0.path) } let urls = events.map { URL(fileURLWithPath: $0.path) }
let parent = FileUtils.commonParent(ofUrls: urls) let parent = FileUtils.commonParent(ofUrls: urls)
self.fileItem(forUrl: parent)?.needsScanChildren = true self.fileItem(forUrl: parent)?.needsScanChildren = true
} }
@ -86,7 +81,7 @@ class FileItemService {
} }
} }
func unmonitor(url url: NSURL) { func unmonitor(url: URL) {
guard let counter = self.monitorCounter[url] else { guard let counter = self.monitorCounter[url] else {
return return
} }
@ -95,8 +90,8 @@ class FileItemService {
if newCounter > 0 { if newCounter > 0 {
self.monitorCounter[url] = newCounter self.monitorCounter[url] = newCounter
} else { } else {
self.monitorCounter.removeValueForKey(url) self.monitorCounter.removeValue(forKey: url)
self.monitors.removeValueForKey(url) self.monitors.removeValue(forKey: url)
// TODO Remove cached items more aggressively? // TODO Remove cached items more aggressively?
let hasRelations = self.monitors.keys.reduce(false) { (result, monitoredUrl) in let hasRelations = self.monitors.keys.reduce(false) { (result, monitoredUrl) in
@ -111,12 +106,12 @@ class FileItemService {
} }
} }
private func parentFileItem(ofUrl url: NSURL) -> FileItem { fileprivate func parentFileItem(ofUrl url: URL) -> FileItem {
return self.fileItem(forPathComponents: Array(url.pathComponents!.dropLast()))! return self.fileItem(forPathComponents: Array(url.pathComponents.dropLast()))!
} }
func flatFileItems(ofUrl url: NSURL) -> Observable<[FileItem]> { func flatFileItems(ofUrl url: URL) -> Observable<[FileItem]> {
guard url.fileURL else { guard url.isFileURL else {
return Observable.empty() return Observable.empty()
} }
@ -124,16 +119,13 @@ class FileItemService {
return Observable.empty() return Observable.empty()
} }
guard let pathComponents = url.pathComponents else { let pathComponents = url.pathComponents
return Observable.empty()
}
return Observable.create { [unowned self] observer in return Observable.create { [unowned self] observer in
let cancel = AnonymousDisposable { let cancel = AnonymousDisposable {
// noop // noop
} }
dispatch_async(self.scanDispatchQueue) { [unowned self] in self.scanDispatchQueue.async { [unowned self] in
guard let targetItem = self.fileItem(forPathComponents: pathComponents) else { guard let targetItem = self.fileItem(forPathComponents: pathComponents) else {
observer.onCompleted() observer.onCompleted()
return return
@ -166,7 +158,7 @@ class FileItemService {
item.ignoreToken = self.ignoreToken item.ignoreToken = self.ignoreToken
item.ignore = false item.ignore = false
let path = item.url.path! let path = item.url.path
for pattern in self.ignorePatterns { for pattern in self.ignorePatterns {
// We don't use `String.FnMatchOption.leadingDir` (`FNM_LEADING_DIR`) for directories since we do not // We don't use `String.FnMatchOption.leadingDir` (`FNM_LEADING_DIR`) for directories since we do not
// scan ignored directories at all when filtering. For example "*/.git" would create a `FileItem` // scan ignored directories at all when filtering. For example "*/.git" would create a `FileItem`
@ -197,11 +189,8 @@ class FileItemService {
} }
} }
private func fileItem(forUrl url: NSURL) -> FileItem? { fileprivate func fileItem(forUrl url: URL) -> FileItem? {
guard let pathComponents = url.pathComponents else { let pathComponents = url.pathComponents
return nil
}
return self.fileItem(forPathComponents: pathComponents) return self.fileItem(forPathComponents: pathComponents)
} }
@ -209,7 +198,7 @@ class FileItemService {
/// instantiates the intermediate `FileItem`s. /// instantiates the intermediate `FileItem`s.
/// ///
/// - returns: `FileItem` corresponding to `pathComponents`. `nil` if the file does not exist. /// - returns: `FileItem` corresponding to `pathComponents`. `nil` if the file does not exist.
private func fileItem(forPathComponents pathComponents: [String]) -> FileItem? { fileprivate func fileItem(forPathComponents pathComponents: [String]) -> FileItem? {
let result = pathComponents.dropFirst().reduce(self.root) { (resultItem, childName) -> FileItem? in let result = pathComponents.dropFirst().reduce(self.root) { (resultItem, childName) -> FileItem? in
guard let parent = resultItem else { guard let parent = resultItem else {
return nil return nil
@ -230,11 +219,11 @@ class FileItemService {
/// - parent: parent of the child. /// - parent: parent of the child.
/// - create: whether to create the child `FileItem` if it's not scanned yet. /// - create: whether to create the child `FileItem` if it's not scanned yet.
/// - returns: child `FileItem` or nil. /// - returns: child `FileItem` or nil.
private func child(withName name: String, ofParent parent: FileItem, create: Bool = false) -> FileItem? { fileprivate func child(withName name: String, ofParent parent: FileItem, create: Bool = false) -> FileItem? {
let filteredChildren = parent.children.filter { $0.url.lastPathComponent == name } let filteredChildren = parent.children.filter { $0.url.lastPathComponent == name }
if filteredChildren.isEmpty && create { if filteredChildren.isEmpty && create {
let childUrl = parent.url.URLByAppendingPathComponent(name) let childUrl = parent.url.appendingPathComponent(name)
guard FileUtils.fileExistsAtUrl(childUrl) else { guard FileUtils.fileExistsAtUrl(childUrl) else {
return nil return nil
@ -249,7 +238,7 @@ class FileItemService {
return filteredChildren.first return filteredChildren.first
} }
private func scanChildren(item: FileItem) { fileprivate func scanChildren(_ item: FileItem) {
let children = FileUtils.directDescendants(item.url).map(FileItem.init) let children = FileUtils.directDescendants(item.url).map(FileItem.init)
self.syncAddChildren { item.children = children } self.syncAddChildren { item.children = children }
@ -257,7 +246,7 @@ class FileItemService {
item.needsScanChildren = false item.needsScanChildren = false
} }
private func syncAddChildren(@noescape fn: () -> Void) { fileprivate func syncAddChildren(_ fn: () -> Void) {
OSSpinLockLock(&self.spinLock) OSSpinLockLock(&self.spinLock)
fn() fn()
OSSpinLockUnlock(&self.spinLock) OSSpinLockUnlock(&self.spinLock)

View File

@ -7,23 +7,23 @@ import Foundation
class FileUtils { class FileUtils {
private static let keysToGet = [ fileprivate static let keysToGet = [
NSURLIsDirectoryKey, URLResourceKey.isDirectoryKey,
NSURLIsHiddenKey, URLResourceKey.isHiddenKey,
NSURLIsAliasFileKey, URLResourceKey.isAliasFileKey,
NSURLIsSymbolicLinkKey URLResourceKey.isSymbolicLinkKey
] ]
private static let scanOptions: NSDirectoryEnumerationOptions = [ fileprivate static let scanOptions: FileManager.DirectoryEnumerationOptions = [
NSDirectoryEnumerationOptions.SkipsSubdirectoryDescendants, FileManager.DirectoryEnumerationOptions.skipsSubdirectoryDescendants,
NSDirectoryEnumerationOptions.SkipsPackageDescendants FileManager.DirectoryEnumerationOptions.skipsPackageDescendants
] ]
private static let fileManager = NSFileManager.defaultManager() fileprivate static let fileManager = FileManager.default
static func directDescendants(url: NSURL) -> [NSURL] { static func directDescendants(_ url: URL) -> [URL] {
guard let childUrls = try? self.fileManager.contentsOfDirectoryAtURL( guard let childUrls = try? self.fileManager.contentsOfDirectory(
url, includingPropertiesForKeys: self.keysToGet, options: self.scanOptions at: url, includingPropertiesForKeys: self.keysToGet, options: self.scanOptions
) else { ) else {
// FIXME error handling // FIXME error handling
return [] return []
@ -32,33 +32,30 @@ class FileUtils {
return childUrls return childUrls
} }
static func fileExistsAtUrl(url: NSURL) -> Bool { static func fileExistsAtUrl(_ url: URL) -> Bool {
guard url.fileURL else { guard url.isFileURL else {
return false return false
} }
guard let path = url.path else { let path = url.path
return false return self.fileManager.fileExists(atPath: path)
}
return self.fileManager.fileExistsAtPath(path)
} }
static func commonParent(ofUrls urls: [NSURL]) -> NSURL { static func commonParent(ofUrls urls: [URL]) -> URL {
guard urls.count > 0 else { guard urls.count > 0 else {
return NSURL(fileURLWithPath: "/", isDirectory: true) return URL(fileURLWithPath: "/", isDirectory: true)
} }
let pathComps = urls.map { $0.pathComponents! } let pathComps = urls.map { $0.pathComponents }
let min = pathComps.reduce(pathComps[0].count) { (result, comps) in result < comps.count ? result : comps.count } let min = pathComps.reduce(pathComps[0].count) { (result, comps) in result < comps.count ? result : comps.count }
let pathCompsWithMinCount = pathComps.filter { $0.count == min } let pathCompsWithMinCount = pathComps.filter { $0.count == min }
let possibleParent = NSURL.fileURLWithPathComponents(pathCompsWithMinCount[0])! let possibleParent = NSURL.fileURL(withPathComponents: pathCompsWithMinCount[0])!
let minPathComponents = Set(pathComps.map { $0[min - 1] }) let minPathComponents = Set(pathComps.map { $0[min - 1] })
if minPathComponents.count == 1 { if minPathComponents.count == 1 {
return possibleParent.dir ? possibleParent : possibleParent.URLByDeletingLastPathComponent! return possibleParent.dir ? possibleParent : possibleParent.deletingLastPathComponent()
} }
return possibleParent.URLByDeletingLastPathComponent! return possibleParent.deletingLastPathComponent()
} }
} }

View File

@ -5,15 +5,15 @@
import Foundation import Foundation
extension NSURL { extension URL {
func parent(ofUrl url: NSURL) -> Bool { func parent(ofUrl url: URL) -> Bool {
guard self.fileURL && url.fileURL else { guard self.isFileURL && url.isFileURL else {
return false return false
} }
let myPathComps = self.pathComponents! let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents! let targetPathComps = url.pathComponents
guard targetPathComps.count > myPathComps.count else { guard targetPathComps.count > myPathComps.count else {
return false return false
@ -29,11 +29,11 @@ extension NSURL {
/// ///
/// - parameters: /// - parameters:
/// - key: The `key`-parameter of `NSURL.getResourceValue`. /// - key: The `key`-parameter of `NSURL.getResourceValue`.
func resourceValue(key: String) -> Bool { func resourceValue(_ key: String) -> Bool {
var rsrc: AnyObject? var rsrc: AnyObject?
do { do {
try self.getResourceValue(&rsrc, forKey: key) try (self as NSURL).getResourceValue(&rsrc, forKey: URLResourceKey(rawValue: key))
} catch { } catch {
// FIXME error handling // FIXME error handling
print("\(#function): \(self) -> ERROR while getting \(key)") print("\(#function): \(self) -> ERROR while getting \(key)")
@ -48,14 +48,14 @@ extension NSURL {
} }
var dir: Bool { var dir: Bool {
return self.resourceValue(NSURLIsDirectoryKey) return self.resourceValue(URLResourceKey.isDirectoryKey.rawValue)
} }
var hidden: Bool { var hidden: Bool {
return self.resourceValue(NSURLIsHiddenKey) return self.resourceValue(URLResourceKey.isHiddenKey.rawValue)
} }
var package: Bool { var package: Bool {
return self.resourceValue(NSURLIsPackageKey) return self.resourceValue(URLResourceKey.isPackageKey.rawValue)
} }
} }

View File

@ -30,11 +30,11 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
return true return true
} }
private var data: GeneralPrefData fileprivate var data: GeneralPrefData
private let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ()) fileprivate let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ())
private let openOnReactivationCheckbox = NSButton(forAutoLayout: ()) fileprivate let openOnReactivationCheckbox = NSButton(forAutoLayout: ())
private let ignoreField = NSTextField(forAutoLayout: ()) fileprivate let ignoreField = NSTextField(forAutoLayout: ())
init(source: Observable<Any>, initialData: GeneralPrefData) { init(source: Observable<Any>, initialData: GeneralPrefData) {
self.data = initialData self.data = initialData
@ -63,8 +63,8 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
let ignoreListTitle = self.titleTextField(title: "Files To Ignore:") let ignoreListTitle = self.titleTextField(title: "Files To Ignore:")
let ignoreField = self.ignoreField let ignoreField = self.ignoreField
NSNotificationCenter.defaultCenter() NotificationCenter.default
.addObserverForName(NSControlTextDidEndEditingNotification, object: ignoreField, queue: nil) { [unowned self] _ in .addObserver(forName: NSNotification.Name.NSControlTextDidEndEditing, object: ignoreField, queue: nil) { [unowned self] _ in
self.ignorePatternsAction() self.ignorePatternsAction()
} }
let ignoreInfo = self.infoTextField(text: "") let ignoreInfo = self.infoTextField(text: "")
@ -73,9 +73,9 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
let cliToolTitle = self.titleTextField(title: "CLI Tool:") let cliToolTitle = self.titleTextField(title: "CLI Tool:")
let cliToolButton = NSButton(forAutoLayout: ()) let cliToolButton = NSButton(forAutoLayout: ())
cliToolButton.title = "Copy 'vimr' CLI Tool..." cliToolButton.title = "Copy 'vimr' CLI Tool..."
cliToolButton.bezelStyle = .RoundedBezelStyle cliToolButton.bezelStyle = .rounded
cliToolButton.bordered = true cliToolButton.isBordered = true
cliToolButton.setButtonType(.MomentaryPushInButton) cliToolButton.setButtonType(.momentaryPushIn)
cliToolButton.target = self cliToolButton.target = self
cliToolButton.action = #selector(GeneralPrefPane.copyCliTool(_:)) cliToolButton.action = #selector(GeneralPrefPane.copyCliTool(_:))
let cliToolInfo = self.infoTextField( let cliToolInfo = self.infoTextField(
@ -95,50 +95,50 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
self.addSubview(cliToolButton) self.addSubview(cliToolButton)
self.addSubview(cliToolInfo) self.addSubview(cliToolInfo)
paneTitle.autoPinEdgeToSuperviewEdge(.Top, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
paneTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
paneTitle.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual) paneTitle.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
openUntitledWindowTitle.autoAlignAxis(.Baseline, toSameAxisOfView: whenLaunching, withOffset: 0) openUntitledWindowTitle.autoAlignAxis(.baseline, toSameAxisOf: whenLaunching, withOffset: 0)
openUntitledWindowTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18) openUntitledWindowTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
whenLaunching.autoPinEdge(.Top, toEdge: .Bottom, ofView: paneTitle, withOffset: 18) whenLaunching.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
whenLaunching.autoPinEdge(.Left, toEdge: .Right, ofView: openUntitledWindowTitle, withOffset: 5) whenLaunching.autoPinEdge(.left, to: .right, of: openUntitledWindowTitle, withOffset: 5)
whenLaunching.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual) whenLaunching.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
onReactivation.autoPinEdge(.Top, toEdge: .Bottom, ofView: whenLaunching, withOffset: 5) onReactivation.autoPinEdge(.top, to: .bottom, of: whenLaunching, withOffset: 5)
onReactivation.autoPinEdge(.Left, toEdge: .Left, ofView: whenLaunching) onReactivation.autoPinEdge(.left, to: .left, of: whenLaunching)
onReactivation.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual) onReactivation.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
ignoreListTitle.autoAlignAxis(.Baseline, toSameAxisOfView: ignoreField) ignoreListTitle.autoAlignAxis(.baseline, toSameAxisOf: ignoreField)
ignoreListTitle.autoPinEdge(.Right, toEdge: .Right, ofView: openUntitledWindowTitle) ignoreListTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
ignoreListTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18, relation: .GreaterThanOrEqual) ignoreListTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
ignoreField.autoPinEdge(.Top, toEdge: .Bottom, ofView: onReactivation, withOffset: 18) ignoreField.autoPinEdge(.top, to: .bottom, of: onReactivation, withOffset: 18)
ignoreField.autoPinEdgeToSuperviewEdge(.Right, withInset: 18) ignoreField.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
ignoreField.autoPinEdge(.Left, toEdge: .Right, ofView: ignoreListTitle, withOffset: 5) ignoreField.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
ignoreInfo.autoPinEdge(.Top, toEdge: .Bottom, ofView: ignoreField, withOffset: 5) ignoreInfo.autoPinEdge(.top, to: .bottom, of: ignoreField, withOffset: 5)
ignoreInfo.autoPinEdgeToSuperviewEdge(.Right, withInset: 18) ignoreInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
ignoreInfo.autoPinEdge(.Left, toEdge: .Right, ofView: ignoreListTitle, withOffset: 5) ignoreInfo.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
cliToolTitle.autoAlignAxis(.Baseline, toSameAxisOfView: cliToolButton) cliToolTitle.autoAlignAxis(.baseline, toSameAxisOf: cliToolButton)
cliToolTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18, relation: .GreaterThanOrEqual) cliToolTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
cliToolTitle.autoPinEdge(.Right, toEdge: .Right, ofView: openUntitledWindowTitle) cliToolTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
cliToolButton.autoPinEdge(.Top, toEdge: .Bottom, ofView: ignoreInfo, withOffset: 18) cliToolButton.autoPinEdge(.top, to: .bottom, of: ignoreInfo, withOffset: 18)
cliToolButton.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual) cliToolButton.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
cliToolButton.autoPinEdge(.Left, toEdge: .Right, ofView: cliToolTitle, withOffset: 5) cliToolButton.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
cliToolInfo.autoPinEdge(.Top, toEdge: .Bottom, ofView: cliToolButton, withOffset: 5) cliToolInfo.autoPinEdge(.top, to: .bottom, of: cliToolButton, withOffset: 5)
cliToolInfo.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual) cliToolInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
cliToolInfo.autoPinEdge(.Left, toEdge: .Right, ofView: cliToolTitle, withOffset: 5) cliToolInfo.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
self.openWhenLaunchingCheckbox.boolState = self.data.openNewWindowWhenLaunching self.openWhenLaunchingCheckbox.boolState = self.data.openNewWindowWhenLaunching
self.openOnReactivationCheckbox.boolState = self.data.openNewWindowOnReactivation self.openOnReactivationCheckbox.boolState = self.data.openNewWindowOnReactivation
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return source return source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { ($0 as! PrefData).general } .map { ($0 as! PrefData).general }
@ -153,19 +153,19 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
self.ignorePatternsAction() self.ignorePatternsAction()
} }
private func set(data data: GeneralPrefData) { fileprivate func set(data: GeneralPrefData) {
self.data = data self.data = data
self.publish(event: data) self.publish(event: data)
} }
private func ignoreInfoText() -> NSAttributedString { fileprivate func ignoreInfoText() -> NSAttributedString {
let font = NSFont.systemFontOfSize(NSFont.smallSystemFontSize()) let font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
let attrs = [ let attrs = [
NSFontAttributeName: font, NSFontAttributeName: font,
NSForegroundColorAttributeName: NSColor.grayColor() NSForegroundColorAttributeName: NSColor.gray
] ]
let wikiUrl = NSURL(string: "https://github.com/qvacua/vimr/wiki")! let wikiUrl = URL(string: "https://github.com/qvacua/vimr/wiki")!
let linkStr = NSAttributedString.link(withUrl: wikiUrl, text: "VimR Wiki", font: font) let linkStr = NSAttributedString.link(withUrl: wikiUrl, text: "VimR Wiki", font: font)
let str = "Comma-separated list of ignore patterns\n" let str = "Comma-separated list of ignore patterns\n"
+ "Matching files will be ignored in \"Open Quickly\".\n" + "Matching files will be ignored in \"Open Quickly\".\n"
@ -173,13 +173,13 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
+ "For detailed information see " + "For detailed information see "
let ignoreInfoStr = NSMutableAttributedString(string:str, attributes:attrs) let ignoreInfoStr = NSMutableAttributedString(string:str, attributes:attrs)
ignoreInfoStr.appendAttributedString(linkStr) ignoreInfoStr.append(linkStr)
ignoreInfoStr.appendAttributedString(NSAttributedString(string: ".", attributes: attrs)) ignoreInfoStr.append(NSAttributedString(string: ".", attributes: attrs))
return ignoreInfoStr return ignoreInfoStr
} }
private func updateViews(newData newData: GeneralPrefData) { fileprivate func updateViews(newData: GeneralPrefData) {
self.openWhenLaunchingCheckbox.boolState = newData.openNewWindowWhenLaunching self.openWhenLaunchingCheckbox.boolState = newData.openNewWindowWhenLaunching
self.openOnReactivationCheckbox.boolState = newData.openNewWindowOnReactivation self.openOnReactivationCheckbox.boolState = newData.openNewWindowOnReactivation
self.ignoreField.stringValue = PrefUtils.ignorePatternString(fromSet: newData.ignorePatterns) self.ignoreField.stringValue = PrefUtils.ignorePatternString(fromSet: newData.ignorePatterns)
@ -189,37 +189,37 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
// MARK: - Actions // MARK: - Actions
extension GeneralPrefPane { extension GeneralPrefPane {
func copyCliTool(sender: NSButton) { func copyCliTool(_ sender: NSButton) {
let panel = NSOpenPanel() let panel = NSOpenPanel()
panel.canChooseFiles = false panel.canChooseFiles = false
panel.canChooseDirectories = true panel.canChooseDirectories = true
panel.beginSheetModalForWindow(self.window!) { result in panel.beginSheetModal(for: self.window!) { result in
guard result == NSFileHandlingPanelOKButton else { guard result == NSFileHandlingPanelOKButton else {
return return
} }
guard let vimrUrl = NSBundle.mainBundle().URLForResource("vimr", withExtension: nil) else { guard let vimrUrl = Bundle.main.url(forResource: "vimr", withExtension: nil) else {
self.alert(title: "Something Went Wrong.", self.alert(title: "Something Went Wrong.",
info: "The CLI tool 'vimr' could not be found. Please re-download VimR and try again.") info: "The CLI tool 'vimr' could not be found. Please re-download VimR and try again.")
return return
} }
guard let targetUrl = panel.URL?.URLByAppendingPathComponent("vimr") else { guard let targetUrl = panel.url?.appendingPathComponent("vimr") else {
self.alert(title: "Something Went Wrong.", self.alert(title: "Something Went Wrong.",
info: "The target directory could not be determined. Please try again with a different directory.") info: "The target directory could not be determined. Please try again with a different directory.")
return return
} }
do { do {
try NSFileManager.defaultManager().copyItemAtURL(vimrUrl, toURL: targetUrl) try FileManager.default.copyItem(at: vimrUrl, to: targetUrl)
} catch let err as NSError { } catch let err as NSError {
self.alert(title: "Error copying 'vimr'", info: err.localizedDescription) self.alert(title: "Error copying 'vimr'", info: err.localizedDescription)
} }
} }
} }
func openUntitledWindowWhenLaunchingAction(sender: NSButton) { func openUntitledWindowWhenLaunchingAction(_ sender: NSButton) {
self.set(data: GeneralPrefData( self.set(data: GeneralPrefData(
openNewWindowWhenLaunching: self.openWhenLaunchingCheckbox.boolState, openNewWindowWhenLaunching: self.openWhenLaunchingCheckbox.boolState,
openNewWindowOnReactivation: self.data.openNewWindowOnReactivation, openNewWindowOnReactivation: self.data.openNewWindowOnReactivation,
@ -227,7 +227,7 @@ extension GeneralPrefPane {
) )
} }
func openUntitledWindowOnReactivationAction(sender: NSButton) { func openUntitledWindowOnReactivationAction(_ sender: NSButton) {
self.set(data: GeneralPrefData( self.set(data: GeneralPrefData(
openNewWindowWhenLaunching: self.data.openNewWindowWhenLaunching, openNewWindowWhenLaunching: self.data.openNewWindowWhenLaunching,
openNewWindowOnReactivation: self.openOnReactivationCheckbox.boolState, openNewWindowOnReactivation: self.openOnReactivationCheckbox.boolState,
@ -235,7 +235,7 @@ extension GeneralPrefPane {
) )
} }
private func ignorePatternsAction() { fileprivate func ignorePatternsAction() {
let patterns = PrefUtils.ignorePatterns(fromString: self.ignoreField.stringValue) let patterns = PrefUtils.ignorePatterns(fromString: self.ignoreField.stringValue)
if patterns == self.data.ignorePatterns { if patterns == self.data.ignorePatterns {
return return
@ -248,9 +248,9 @@ extension GeneralPrefPane {
) )
} }
private func alert(title title: String, info: String) { fileprivate func alert(title: String, info: String) {
let alert = NSAlert() let alert = NSAlert()
alert.alertStyle = .WarningAlertStyle alert.alertStyle = .warning
alert.messageText = title alert.messageText = title
alert.informativeText = info alert.informativeText = info
alert.runModal() alert.runModal()

View File

@ -28,8 +28,8 @@ class ImageAndTextTableCell: NSView {
} }
} }
private let textField: NSTextField = NSTextField(forAutoLayout: ()) fileprivate let textField: NSTextField = NSTextField(forAutoLayout: ())
private let imageView: NSImageView = NSImageView(forAutoLayout: ()) fileprivate let imageView: NSImageView = NSImageView(forAutoLayout: ())
init(withIdentifier identifier: String) { init(withIdentifier identifier: String) {
super.init(frame: CGRect.zero) super.init(frame: CGRect.zero)
@ -37,9 +37,9 @@ class ImageAndTextTableCell: NSView {
self.identifier = identifier self.identifier = identifier
let textField = self.textField let textField = self.textField
textField.bordered = false textField.isBordered = false
textField.editable = false textField.isEditable = false
textField.lineBreakMode = .ByTruncatingTail textField.lineBreakMode = .byTruncatingTail
textField.drawsBackground = false textField.drawsBackground = false
let imageView = self.imageView let imageView = self.imageView
@ -47,18 +47,18 @@ class ImageAndTextTableCell: NSView {
self.addSubview(textField) self.addSubview(textField)
self.addSubview(imageView) self.addSubview(imageView)
imageView.autoPinEdgeToSuperviewEdge(.Top, withInset: 2) imageView.autoPinEdge(toSuperviewEdge: .top, withInset: 2)
imageView.autoPinEdgeToSuperviewEdge(.Left, withInset: 2) imageView.autoPinEdge(toSuperviewEdge: .left, withInset: 2)
imageView.autoSetDimension(.Width, toSize: 16) imageView.autoSetDimension(.width, toSize: 16)
imageView.autoSetDimension(.Height, toSize: 16) imageView.autoSetDimension(.height, toSize: 16)
textField.autoPinEdgeToSuperviewEdge(.Top, withInset: 2) textField.autoPinEdge(toSuperviewEdge: .top, withInset: 2)
textField.autoPinEdgeToSuperviewEdge(.Right, withInset: 2) textField.autoPinEdge(toSuperviewEdge: .right, withInset: 2)
textField.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 2) textField.autoPinEdge(toSuperviewEdge: .bottom, withInset: 2)
textField.autoPinEdge(.Left, toEdge: .Right, ofView: imageView, withOffset: 4) textField.autoPinEdge(.left, to: .right, of: imageView, withOffset: 4)
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
} }

View File

@ -15,17 +15,17 @@ enum MainWindowAction {
class MainWindowComponent: WindowComponent, NSWindowDelegate { class MainWindowComponent: WindowComponent, NSWindowDelegate {
private let fontManager = NSFontManager.sharedFontManager() fileprivate let fontManager = NSFontManager.shared()
private var defaultEditorFont: NSFont fileprivate var defaultEditorFont: NSFont
private var usesLigatures: Bool fileprivate var usesLigatures: Bool
var uuid: String { var uuid: String {
return self.neoVimView.uuid return self.neoVimView.uuid
} }
private var _cwd: NSURL = NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) fileprivate var _cwd: URL = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
var cwd: NSURL { var cwd: URL {
get { get {
self._cwd = self.neoVimView.cwd self._cwd = self.neoVimView.cwd
return self._cwd return self._cwd
@ -43,16 +43,16 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
self.fileItemService.monitor(url: newValue) self.fileItemService.monitor(url: newValue)
} }
} }
private let fileItemService: FileItemService fileprivate let fileItemService: FileItemService
private let workspace: Workspace fileprivate let workspace: Workspace
private let neoVimView: NeoVimView fileprivate let neoVimView: NeoVimView
// TODO: Consider an option object for cwd, urls, etc... // TODO: Consider an option object for cwd, urls, etc...
init(source: Observable<Any>, init(source: Observable<Any>,
fileItemService: FileItemService, fileItemService: FileItemService,
cwd: NSURL, cwd: URL,
urls: [NSURL] = [], urls: [URL] = [],
initialData: PrefData) initialData: PrefData)
{ {
self.neoVimView = NeoVimView(frame: CGRect.zero, self.neoVimView = NeoVimView(frame: CGRect.zero,
@ -83,7 +83,7 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
self.show() self.show()
} }
func open(urls urls: [NSURL]) { func open(urls: [URL]) {
self.neoVimView.open(urls: urls) self.neoVimView.open(urls: urls)
} }
@ -104,12 +104,12 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
self.workspace.autoPinEdgesToSuperviewEdges() self.workspace.autoPinEdgesToSuperviewEdges()
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return source return source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { ($0 as! PrefData).appearance } .map { ($0 as! PrefData).appearance }
.filter { [unowned self] appearanceData in .filter { [unowned self] appearanceData in
!appearanceData.editorFont.isEqualTo(self.neoVimView.font) !appearanceData.editorFont.isEqual(to: self.neoVimView.font)
|| appearanceData.editorUsesLigatures != self.neoVimView.usesLigatures || appearanceData.editorUsesLigatures != self.neoVimView.usesLigatures
} }
.subscribeNext { [unowned self] appearance in .subscribeNext { [unowned self] appearance in
@ -122,28 +122,28 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
// MARK: - File Menu Items // MARK: - File Menu Items
extension MainWindowComponent { extension MainWindowComponent {
@IBAction func newTab(sender: AnyObject!) { @IBAction func newTab(_ sender: AnyObject!) {
self.neoVimView.newTab() self.neoVimView.newTab()
} }
@IBAction func openDocument(sender: AnyObject!) { @IBAction func openDocument(_ sender: AnyObject!) {
let panel = NSOpenPanel() let panel = NSOpenPanel()
panel.canChooseDirectories = true panel.canChooseDirectories = true
panel.beginSheetModalForWindow(self.window) { result in panel.beginSheetModal(for: self.window) { result in
guard result == NSFileHandlingPanelOKButton else { guard result == NSFileHandlingPanelOKButton else {
return return
} }
// The open panel can choose only one file. // The open panel can choose only one file.
self.neoVimView.open(urls: panel.URLs) self.neoVimView.open(urls: panel.urls)
} }
} }
@IBAction func openQuickly(sender: AnyObject!) { @IBAction func openQuickly(_ sender: AnyObject!) {
self.publish(event: MainWindowAction.openQuickly(mainWindow: self)) self.publish(event: MainWindowAction.openQuickly(mainWindow: self))
} }
@IBAction func saveDocument(sender: AnyObject!) { @IBAction func saveDocument(_ sender: AnyObject!) {
let curBuf = self.neoVimView.currentBuffer() let curBuf = self.neoVimView.currentBuffer()
if curBuf.fileName == nil { if curBuf.fileName == nil {
@ -154,7 +154,7 @@ extension MainWindowComponent {
self.neoVimView.saveCurrentTab() self.neoVimView.saveCurrentTab()
} }
@IBAction func saveDocumentAs(sender: AnyObject!) { @IBAction func saveDocumentAs(_ sender: AnyObject!) {
self.savePanelSheet { url in self.savePanelSheet { url in
self.neoVimView.saveCurrentTab(url: url) self.neoVimView.saveCurrentTab(url: url)
@ -166,24 +166,24 @@ extension MainWindowComponent {
} }
} }
private func savePanelSheet(action action: (NSURL) -> Void) { fileprivate func savePanelSheet(action: @escaping (URL) -> Void) {
let panel = NSSavePanel() let panel = NSSavePanel()
panel.beginSheetModalForWindow(self.window) { result in panel.beginSheetModal(for: self.window) { result in
guard result == NSFileHandlingPanelOKButton else { guard result == NSFileHandlingPanelOKButton else {
return return
} }
let showAlert: () -> Void = { let showAlert: () -> Void = {
let alert = NSAlert() let alert = NSAlert()
alert.addButtonWithTitle("OK") alert.addButton(withTitle: "OK")
alert.messageText = "Invalid File Name" alert.messageText = "Invalid File Name"
alert.informativeText = "The file name you have entered cannot be used. Please use a different name." alert.informativeText = "The file name you have entered cannot be used. Please use a different name."
alert.alertStyle = .WarningAlertStyle alert.alertStyle = .warning
alert.runModal() alert.runModal()
} }
guard let url = panel.URL else { guard let url = panel.url else {
showAlert() showAlert()
return return
} }
@ -201,20 +201,20 @@ extension MainWindowComponent {
// MARK: - Font Menu Items // MARK: - Font Menu Items
extension MainWindowComponent { extension MainWindowComponent {
@IBAction func resetFontSize(sender: AnyObject!) { @IBAction func resetFontSize(_ sender: AnyObject!) {
self.neoVimView.font = self.defaultEditorFont self.neoVimView.font = self.defaultEditorFont
} }
@IBAction func makeFontBigger(sender: AnyObject!) { @IBAction func makeFontBigger(_ sender: AnyObject!) {
let curFont = self.neoVimView.font let curFont = self.neoVimView.font
let font = self.fontManager.convertFont(curFont, let font = self.fontManager.convert(curFont,
toSize: min(curFont.pointSize + 1, PrefStore.maximumEditorFontSize)) toSize: min(curFont.pointSize + 1, PrefStore.maximumEditorFontSize))
self.neoVimView.font = font self.neoVimView.font = font
} }
@IBAction func makeFontSmaller(sender: AnyObject!) { @IBAction func makeFontSmaller(_ sender: AnyObject!) {
let curFont = self.neoVimView.font let curFont = self.neoVimView.font
let font = self.fontManager.convertFont(curFont, let font = self.fontManager.convert(curFont,
toSize: max(curFont.pointSize - 1, PrefStore.minimumEditorFontSize)) toSize: max(curFont.pointSize - 1, PrefStore.minimumEditorFontSize))
self.neoVimView.font = font self.neoVimView.font = font
} }
@ -223,11 +223,11 @@ extension MainWindowComponent {
// MARK: - NeoVimViewDelegate // MARK: - NeoVimViewDelegate
extension MainWindowComponent: NeoVimViewDelegate { extension MainWindowComponent: NeoVimViewDelegate {
func setTitle(title: String) { func setTitle(_ title: String) {
self.window.title = title self.window.title = title
} }
func setDirtyStatus(dirty: Bool) { func setDirtyStatus(_ dirty: Bool) {
self.windowController.setDocumentEdited(dirty) self.windowController.setDocumentEdited(dirty)
} }
@ -246,27 +246,27 @@ extension MainWindowComponent: NeoVimViewDelegate {
// MARK: - NSWindowDelegate // MARK: - NSWindowDelegate
extension MainWindowComponent { extension MainWindowComponent {
func windowDidBecomeKey(_: NSNotification) { func windowDidBecomeKey(_: Notification) {
self.publish(event: MainWindowAction.becomeKey(mainWindow: self)) self.publish(event: MainWindowAction.becomeKey(mainWindow: self))
} }
func windowWillClose(notification: NSNotification) { func windowWillClose(_ notification: Notification) {
self.fileItemService.unmonitor(url: self._cwd) self.fileItemService.unmonitor(url: self._cwd)
self.publish(event: MainWindowAction.close(mainWindow: self)) self.publish(event: MainWindowAction.close(mainWindow: self))
} }
func windowShouldClose(sender: AnyObject) -> Bool { func windowShouldClose(_ sender: Any) -> Bool {
if self.neoVimView.isCurrentBufferDirty() { if self.neoVimView.isCurrentBufferDirty() {
let alert = NSAlert() let alert = NSAlert()
alert.addButtonWithTitle("Cancel") alert.addButton(withTitle: "Cancel")
alert.addButtonWithTitle("Discard and Close") alert.addButton(withTitle: "Discard and Close")
alert.messageText = "The current buffer has unsaved changes!" alert.messageText = "The current buffer has unsaved changes!"
alert.alertStyle = .WarningAlertStyle alert.alertStyle = .warning
alert.beginSheetModalForWindow(self.window) { response in alert.beginSheetModal(for: self.window, completionHandler: { response in
if response == NSAlertSecondButtonReturn { if response == NSAlertSecondButtonReturn {
self.neoVimView.closeCurrentTabWithoutSaving() self.neoVimView.closeCurrentTabWithoutSaving()
} }
} })
return false return false
} }

View File

@ -12,13 +12,13 @@ enum MainWindowEvent {
class MainWindowManager: StandardFlow { class MainWindowManager: StandardFlow {
static private let userHomeUrl = NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) static fileprivate let userHomeUrl = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
private var mainWindowComponents = [String:MainWindowComponent]() fileprivate var mainWindowComponents = [String:MainWindowComponent]()
private weak var keyMainWindow: MainWindowComponent? fileprivate weak var keyMainWindow: MainWindowComponent?
private let fileItemService: FileItemService fileprivate let fileItemService: FileItemService
private var data: PrefData fileprivate var data: PrefData
init(source: Observable<Any>, fileItemService: FileItemService, initialData: PrefData) { init(source: Observable<Any>, fileItemService: FileItemService, initialData: PrefData) {
self.fileItemService = fileItemService self.fileItemService = fileItemService
@ -27,7 +27,7 @@ class MainWindowManager: StandardFlow {
super.init(source: source) super.init(source: source)
} }
func newMainWindow(urls urls: [NSURL] = [], cwd: NSURL = MainWindowManager.userHomeUrl) -> MainWindowComponent { func newMainWindow(urls: [URL] = [], cwd: URL = MainWindowManager.userHomeUrl) -> MainWindowComponent {
let mainWindowComponent = MainWindowComponent( let mainWindowComponent = MainWindowComponent(
source: self.source, fileItemService: self.fileItemService, cwd: cwd, urls: urls, initialData: self.data source: self.source, fileItemService: self.fileItemService, cwd: cwd, urls: urls, initialData: self.data
) )
@ -53,12 +53,12 @@ class MainWindowManager: StandardFlow {
return mainWindowComponent return mainWindowComponent
} }
func closeMainWindow(mainWindowComponent: MainWindowComponent) { func closeMainWindow(_ mainWindowComponent: MainWindowComponent) {
if self.keyMainWindow === mainWindowComponent { if self.keyMainWindow === mainWindowComponent {
self.keyMainWindow = nil self.keyMainWindow = nil
} }
self.mainWindowComponents.removeValueForKey(mainWindowComponent.uuid) self.mainWindowComponents.removeValue(forKey: mainWindowComponent.uuid)
if self.mainWindowComponents.isEmpty { if self.mainWindowComponents.isEmpty {
self.publish(event: MainWindowEvent.allWindowsClosed) self.publish(event: MainWindowEvent.allWindowsClosed)
@ -69,7 +69,7 @@ class MainWindowManager: StandardFlow {
return self.mainWindowComponents.values.reduce(false) { $0 ? true : $1.isDirty() } return self.mainWindowComponents.values.reduce(false) { $0 ? true : $1.isDirty() }
} }
func openInKeyMainWindow(urls urls:[NSURL] = [], cwd: NSURL = MainWindowManager.userHomeUrl) { func openInKeyMainWindow(urls:[URL] = [], cwd: URL = MainWindowManager.userHomeUrl) {
guard !self.mainWindowComponents.isEmpty else { guard !self.mainWindowComponents.isEmpty else {
self.newMainWindow(urls: urls, cwd: cwd) self.newMainWindow(urls: urls, cwd: cwd)
return return
@ -84,7 +84,7 @@ class MainWindowManager: StandardFlow {
keyMainWindow.open(urls: urls) keyMainWindow.open(urls: urls)
} }
private func set(keyMainWindow mainWindow: MainWindowComponent?) { fileprivate func set(keyMainWindow mainWindow: MainWindowComponent?) {
self.keyMainWindow = mainWindow self.keyMainWindow = mainWindow
} }
@ -101,7 +101,7 @@ class MainWindowManager: StandardFlow {
return !self.mainWindowComponents.isEmpty return !self.mainWindowComponents.isEmpty
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return source return source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { $0 as! PrefData } .map { $0 as! PrefData }

View File

@ -7,7 +7,7 @@ import Foundation
class Matcher { class Matcher {
static let uppercaseCharSet = NSCharacterSet.uppercaseLetterCharacterSet() static let uppercaseCharSet = CharacterSet.uppercaseLetters
enum ExactMatchResult { enum ExactMatchResult {
case none case none
@ -17,9 +17,9 @@ class Matcher {
case contains case contains
} }
static func exactMatchIgnoringCase(target: String, pattern: String) -> ExactMatchResult { static func exactMatchIgnoringCase(_ target: String, pattern: String) -> ExactMatchResult {
let ltarget = target.lowercaseString let ltarget = target.lowercased()
let lpattern = pattern.lowercaseString let lpattern = pattern.lowercased()
if ltarget == lpattern { if ltarget == lpattern {
return .exact return .exact
} }
@ -32,26 +32,26 @@ class Matcher {
return .suffix return .suffix
} }
if ltarget.containsString(lpattern) { if ltarget.contains(lpattern) {
return .contains return .contains
} }
return .none return .none
} }
static func numberOfUppercaseMatches(target: String, pattern: String) -> Int { static func numberOfUppercaseMatches(_ target: String, pattern: String) -> Int {
var tscalars = target.unicodeScalars.filter { uppercaseCharSet.longCharacterIsMember($0.value) } var tscalars = target.unicodeScalars.filter { uppercaseCharSet.contains(UnicodeScalar($0.value)!) }
let count = tscalars.count let count = tscalars.count
guard count > 0 else { guard count > 0 else {
return 0 return 0
} }
let pscalars = pattern.uppercaseString.unicodeScalars let pscalars = pattern.uppercased().unicodeScalars
pscalars.forEach { scalar in pscalars.forEach { scalar in
if let idx = tscalars.indexOf(scalar) { if let idx = tscalars.index(of: scalar) {
tscalars.removeAtIndex(idx) tscalars.remove(at: idx)
} }
} }
@ -60,30 +60,30 @@ class Matcher {
/// Matches `pattern` to `target` in a fuzzy way. /// Matches `pattern` to `target` in a fuzzy way.
/// - returns: `Array` of `Range<String.UnicodeScalarIndex>` /// - returns: `Array` of `Range<String.UnicodeScalarIndex>`
static func fuzzyIgnoringCase(target: String, pattern: String) -> (matches: Int, ranges: [Range<Int>]) { static func fuzzyIgnoringCase(_ target: String, pattern: String) -> (matches: Int, ranges: [CountableRange<Int>]) {
let tlower = target.lowercaseString let tlower = target.lowercased()
let plower = pattern.lowercaseString let plower = pattern.lowercased()
let tchars = tlower.unicodeScalars let tchars = tlower.unicodeScalars
let pchars = plower.unicodeScalars let pchars = plower.unicodeScalars
var flags = Array(count: tchars.count, repeatedValue: false) var flags = Array(repeating: false, count: tchars.count)
var pidx = pchars.startIndex var pidx = pchars.startIndex
for (i, tchar) in tchars.enumerate() { for (i, tchar) in tchars.enumerated() {
if pchars[pidx] == tchar { if pchars[pidx] == tchar {
flags[i] = true flags[i] = true
pidx = pidx.successor() pidx = pchars.index(after: pidx)
} }
} }
var ranges: [Range<Int>] = [] var ranges: [CountableRange<Int>] = []
var matches = 0 var matches = 0
var lastTrue = -1 var lastTrue = -1
var curTrue = -1 var curTrue = -1
for (i, isTrue) in flags.enumerate() { for (i, isTrue) in flags.enumerated() {
if isTrue { if isTrue {
matches = matches &+ 1 matches = matches &+ 1
if lastTrue == -1 { if lastTrue == -1 {
@ -93,14 +93,14 @@ class Matcher {
if i == flags.count &- 1 { if i == flags.count &- 1 {
if lastTrue > -1 && curTrue > -1 { if lastTrue > -1 && curTrue > -1 {
ranges.append(lastTrue...curTrue) ranges.append(CountableRange(lastTrue...curTrue))
lastTrue = -1 lastTrue = -1
curTrue = -1 curTrue = -1
} }
} }
} else { } else {
if lastTrue > -1 && curTrue > -1 { if lastTrue > -1 && curTrue > -1 {
ranges.append(lastTrue...curTrue) ranges.append(CountableRange(lastTrue...curTrue))
lastTrue = -1 lastTrue = -1
curTrue = -1 curTrue = -1
} }
@ -115,23 +115,23 @@ class Matcher {
/// ///
/// - returns: the distance of pattern from target /// - returns: the distance of pattern from target
/// - seealso: https://en.wikipedia.org/wiki/WagnerFischer_algorithm /// - seealso: https://en.wikipedia.org/wiki/WagnerFischer_algorithm
static func wagnerFisherDistance(target: String, pattern: String) -> Int { static func wagnerFisherDistance(_ target: String, pattern: String) -> Int {
let s = target.unicodeScalars let s = target.unicodeScalars
let t = pattern.unicodeScalars let t = pattern.unicodeScalars
let m = s.count let m = s.count
var prevRow = Array(count: m &+ 1, repeatedValue: 0) var prevRow = Array(repeating: 0, count: m &+ 1)
var curRow = Array(count: m &+ 1, repeatedValue: 0) var curRow = Array(repeating: 0, count: m &+ 1)
for i in 0...m { for i in 0...m {
prevRow[i] = i prevRow[i] = i
} }
for (j, tchar) in t.enumerate() { for (j, tchar) in t.enumerated() {
curRow[0] = j &+ 1 curRow[0] = j &+ 1
for (i, schar) in s.enumerate() { for (i, schar) in s.enumerated() {
if schar == tchar { if schar == tchar {
curRow[i &+ 1] = prevRow[i] curRow[i &+ 1] = prevRow[i]
} else { } else {

View File

@ -7,18 +7,18 @@ import Cocoa
class OpenQuicklyFileViewRow: NSTableRowView { class OpenQuicklyFileViewRow: NSTableRowView {
override func drawSelectionInRect(dirtyRect: NSRect) { override func drawSelection(in dirtyRect: NSRect) {
if self.selected { if self.isSelected {
NSColor.selectedControlColor().set() NSColor.selectedControlColor.set()
} else { } else {
NSColor.clearColor().set() NSColor.clear.set()
} }
self.rectsBeingDrawn().forEach { NSRectFillUsingOperation(NSIntersectionRect($0, dirtyRect), .CompositeSourceOver) } self.rectsBeingDrawn().forEach { NSRectFillUsingOperation(NSIntersectionRect($0, dirtyRect), .sourceOver) }
} }
private func rectsBeingDrawn() -> [CGRect] { fileprivate func rectsBeingDrawn() -> [CGRect] {
var rectsPtr: UnsafePointer<CGRect> = nil var rectsPtr: UnsafePointer<CGRect>? = nil
var count: Int = 0 var count: Int = 0
self.getRectsBeingDrawn(&rectsPtr, count: &count) self.getRectsBeingDrawn(&rectsPtr, count: &count)

View File

@ -5,20 +5,20 @@
import Cocoa import Cocoa
class OpenQuicklyFilterOperation: NSOperation { class OpenQuicklyFilterOperation: Operation {
private let chunkSize = 100 fileprivate let chunkSize = 100
private let maxResultCount = 500 fileprivate let maxResultCount = 500
private unowned let openQuicklyWindow: OpenQuicklyWindowComponent fileprivate unowned let openQuicklyWindow: OpenQuicklyWindowComponent
private let pattern: String fileprivate let pattern: String
private let flatFileItems: [FileItem] fileprivate let flatFileItems: [FileItem]
private let cwd: NSURL fileprivate let cwd: URL
init(forOpenQuicklyWindow openQuicklyWindow: OpenQuicklyWindowComponent) { init(forOpenQuicklyWindow openQuicklyWindow: OpenQuicklyWindowComponent) {
self.openQuicklyWindow = openQuicklyWindow self.openQuicklyWindow = openQuicklyWindow
self.pattern = openQuicklyWindow.pattern self.pattern = openQuicklyWindow.pattern
self.cwd = openQuicklyWindow.cwd self.cwd = openQuicklyWindow.cwd as URL
self.flatFileItems = openQuicklyWindow.flatFileItems self.flatFileItems = openQuicklyWindow.flatFileItems
super.init() super.init()
@ -33,7 +33,7 @@ class OpenQuicklyFilterOperation: NSOperation {
self.openQuicklyWindow.scanCondition.unlock() self.openQuicklyWindow.scanCondition.unlock()
} }
if self.cancelled { if self.isCancelled {
return return
} }
@ -47,17 +47,17 @@ class OpenQuicklyFilterOperation: NSOperation {
let count = self.flatFileItems.count let count = self.flatFileItems.count
let chunksCount = Int(ceil(Float(count) / Float(self.chunkSize))) let chunksCount = Int(ceil(Float(count) / Float(self.chunkSize)))
let useFullPath = pattern.containsString("/") let useFullPath = pattern.contains("/")
let cwdPath = self.cwd.path! + "/" let cwdPath = self.cwd.path + "/"
var result = [ScoredFileItem]() var result = [ScoredFileItem]()
var spinLock = OS_SPINLOCK_INIT var spinLock = OS_SPINLOCK_INIT
let cleanedPattern = useFullPath ? self.pattern.stringByReplacingOccurrencesOfString("/", withString: "") let cleanedPattern = useFullPath ? self.pattern.replacingOccurrences(of: "/", with: "")
: self.pattern : self.pattern
dispatch_apply(chunksCount, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { [unowned self] idx in DispatchQueue.concurrentPerform(iterations: chunksCount) { [unowned self] idx in
if self.cancelled { if self.isCancelled {
return return
} }
@ -66,39 +66,39 @@ class OpenQuicklyFilterOperation: NSOperation {
let chunkedItems = self.flatFileItems[startIndex..<endIndex] let chunkedItems = self.flatFileItems[startIndex..<endIndex]
let chunkedResult: [ScoredFileItem] = chunkedItems.flatMap { let chunkedResult: [ScoredFileItem] = chunkedItems.flatMap {
if self.cancelled { if self.isCancelled {
return nil return nil
} }
let url = $0.url let url = $0.url
if useFullPath { if useFullPath {
let target = url.path!.stringByReplacingOccurrencesOfString(cwdPath, withString: "") let target = url.path.replacingOccurrences(of: cwdPath, with: "")
.stringByReplacingOccurrencesOfString("/", withString: "") .replacingOccurrences(of: "/", with: "")
return ScoredFileItem(score: Scorer.score(target, pattern: cleanedPattern), url: url) return ScoredFileItem(score: Scorer.score(target, pattern: cleanedPattern), url: url)
} }
return ScoredFileItem(score: Scorer.score(url.lastPathComponent!, pattern: cleanedPattern), url: url) return ScoredFileItem(score: Scorer.score(url.lastPathComponent, pattern: cleanedPattern), url: url)
} }
if self.cancelled { if self.isCancelled {
return return
} }
OSSpinLockLock(&spinLock) OSSpinLockLock(&spinLock)
result.appendContentsOf(chunkedResult) result.append(contentsOf: chunkedResult)
OSSpinLockUnlock(&spinLock) OSSpinLockUnlock(&spinLock)
} }
if self.cancelled { if self.isCancelled {
return return
} }
sorted = result.sort(>) sorted = result.sorted(by: >)
} }
if self.cancelled { if self.isCancelled {
return return
} }
@ -107,4 +107,4 @@ class OpenQuicklyFilterOperation: NSOperation {
self.openQuicklyWindow.reloadFileView(withScoredItems: result) self.openQuicklyWindow.reloadFileView(withScoredItems: result)
} }
} }
} }

View File

@ -16,80 +16,80 @@ class OpenQuicklyWindowComponent: WindowComponent,
let scanCondition = NSCondition() let scanCondition = NSCondition()
var pauseScan = false var pauseScan = false
private(set) var pattern = "" fileprivate(set) var pattern = ""
private(set) var cwd = NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) { fileprivate(set) var cwd = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) {
didSet { didSet {
self.cwdPathCompsCount = self.cwd.pathComponents!.count self.cwdPathCompsCount = self.cwd.pathComponents.count
self.cwdControl.URL = self.cwd self.cwdControl.url = self.cwd
} }
} }
private(set) var flatFileItems = [FileItem]() fileprivate(set) var flatFileItems = [FileItem]()
private(set) var fileViewItems = [ScoredFileItem]() fileprivate(set) var fileViewItems = [ScoredFileItem]()
private let userInitiatedScheduler = ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .UserInitiated) fileprivate let userInitiatedScheduler = ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .userInitiated)
private let searchField = NSTextField(forAutoLayout: ()) fileprivate let searchField = NSTextField(forAutoLayout: ())
private let progressIndicator = NSProgressIndicator(forAutoLayout: ()) fileprivate let progressIndicator = NSProgressIndicator(forAutoLayout: ())
private let cwdControl = NSPathControl(forAutoLayout: ()) fileprivate let cwdControl = NSPathControl(forAutoLayout: ())
private let countField = NSTextField(forAutoLayout: ()) fileprivate let countField = NSTextField(forAutoLayout: ())
private let fileView = NSTableView.standardTableView() fileprivate let fileView = NSTableView.standardTableView()
private let fileItemService: FileItemService fileprivate let fileItemService: FileItemService
private var count = 0 fileprivate var count = 0
private var perSessionDisposeBag = DisposeBag() fileprivate var perSessionDisposeBag = DisposeBag()
private var cwdPathCompsCount = 0 fileprivate var cwdPathCompsCount = 0
private let searchStream: Observable<String> fileprivate let searchStream: Observable<String>
private let filterOpQueue = NSOperationQueue() fileprivate let filterOpQueue = OperationQueue()
weak private var mainWindow: MainWindowComponent? weak fileprivate var mainWindow: MainWindowComponent?
init(source: Observable<Any>, fileItemService: FileItemService) { init(source: Observable<Any>, fileItemService: FileItemService) {
self.fileItemService = fileItemService self.fileItemService = fileItemService
self.searchStream = self.searchField.rx_text self.searchStream = self.searchField.rx.textInput.text
.throttle(0.2, scheduler: MainScheduler.instance) .throttle(0.2, scheduler: MainScheduler.instance)
.distinctUntilChanged() .distinctUntilChanged()
super.init(source: source, nibName: "OpenQuicklyWindow") super.init(source: source, nibName: "OpenQuicklyWindow")
self.window.delegate = self self.window.delegate = self
self.filterOpQueue.qualityOfService = .UserInitiated self.filterOpQueue.qualityOfService = .userInitiated
self.filterOpQueue.name = "open-quickly-filter-operation-queue" self.filterOpQueue.name = "open-quickly-filter-operation-queue"
} }
override func addViews() { override func addViews() {
let searchField = self.searchField let searchField = self.searchField
searchField.rx_delegate.setForwardToDelegate(self, retainDelegate: false) searchField.rx.delegate.setForwardToDelegate(self, retainDelegate: false)
let progressIndicator = self.progressIndicator let progressIndicator = self.progressIndicator
progressIndicator.indeterminate = true progressIndicator.isIndeterminate = true
progressIndicator.displayedWhenStopped = false progressIndicator.isDisplayedWhenStopped = false
progressIndicator.style = .SpinningStyle progressIndicator.style = .spinningStyle
progressIndicator.controlSize = .SmallControlSize progressIndicator.controlSize = .small
let fileView = self.fileView let fileView = self.fileView
fileView.intercellSpacing = CGSize(width: 4, height: 4) fileView.intercellSpacing = CGSize(width: 4, height: 4)
fileView.setDataSource(self) fileView.dataSource = self
fileView.setDelegate(self) fileView.delegate = self
let fileScrollView = NSScrollView.standardScrollView() let fileScrollView = NSScrollView.standardScrollView()
fileScrollView.autoresizesSubviews = true fileScrollView.autoresizesSubviews = true
fileScrollView.documentView = fileView fileScrollView.documentView = fileView
let cwdControl = self.cwdControl let cwdControl = self.cwdControl
cwdControl.pathStyle = .Standard cwdControl.pathStyle = .standard
cwdControl.backgroundColor = NSColor.clearColor() cwdControl.backgroundColor = NSColor.clear
cwdControl.refusesFirstResponder = true cwdControl.refusesFirstResponder = true
cwdControl.cell?.controlSize = .SmallControlSize cwdControl.cell?.controlSize = .small
cwdControl.cell?.font = NSFont.systemFontOfSize(NSFont.smallSystemFontSize()) cwdControl.cell?.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
cwdControl.setContentCompressionResistancePriority(NSLayoutPriorityDefaultLow, forOrientation:.Horizontal) cwdControl.setContentCompressionResistancePriority(NSLayoutPriorityDefaultLow, for:.horizontal)
let countField = self.countField let countField = self.countField
countField.editable = false countField.isEditable = false
countField.bordered = false countField.isBordered = false
countField.alignment = .Right countField.alignment = .right
countField.backgroundColor = NSColor.clearColor() countField.backgroundColor = NSColor.clear
countField.stringValue = "0 items" countField.stringValue = "0 items"
let contentView = self.window.contentView! let contentView = self.window.contentView!
@ -99,28 +99,28 @@ class OpenQuicklyWindowComponent: WindowComponent,
contentView.addSubview(cwdControl) contentView.addSubview(cwdControl)
contentView.addSubview(countField) contentView.addSubview(countField)
searchField.autoPinEdgeToSuperviewEdge(.Top, withInset: 8) searchField.autoPinEdge(toSuperviewEdge: .top, withInset: 8)
searchField.autoPinEdgeToSuperviewEdge(.Right, withInset: 8) searchField.autoPinEdge(toSuperviewEdge: .right, withInset: 8)
searchField.autoPinEdgeToSuperviewEdge(.Left, withInset: 8) searchField.autoPinEdge(toSuperviewEdge: .left, withInset: 8)
progressIndicator.autoAlignAxis(.Horizontal, toSameAxisOfView: searchField) progressIndicator.autoAlignAxis(.horizontal, toSameAxisOf: searchField)
progressIndicator.autoPinEdge(.Right, toEdge: .Right, ofView: searchField, withOffset: -4) progressIndicator.autoPinEdge(.right, to: .right, of: searchField, withOffset: -4)
fileScrollView.autoPinEdge(.Top, toEdge: .Bottom, ofView: searchField, withOffset: 8) fileScrollView.autoPinEdge(.top, to: .bottom, of: searchField, withOffset: 8)
fileScrollView.autoPinEdgeToSuperviewEdge(.Left, withInset: -1) fileScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: -1)
fileScrollView.autoPinEdgeToSuperviewEdge(.Right, withInset: -1) fileScrollView.autoPinEdge(toSuperviewEdge: .right, withInset: -1)
fileScrollView.autoSetDimension(.Height, toSize: 200, relation: .GreaterThanOrEqual) fileScrollView.autoSetDimension(.height, toSize: 200, relation: .greaterThanOrEqual)
cwdControl.autoPinEdge(.Top, toEdge: .Bottom, ofView: fileScrollView, withOffset: 4) cwdControl.autoPinEdge(.top, to: .bottom, of: fileScrollView, withOffset: 4)
cwdControl.autoPinEdgeToSuperviewEdge(.Left, withInset: 2) cwdControl.autoPinEdge(toSuperviewEdge: .left, withInset: 2)
cwdControl.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 4) cwdControl.autoPinEdge(toSuperviewEdge: .bottom, withInset: 4)
countField.autoPinEdge(.Top, toEdge: .Bottom, ofView: fileScrollView, withOffset: 4) countField.autoPinEdge(.top, to: .bottom, of: fileScrollView, withOffset: 4)
countField.autoPinEdgeToSuperviewEdge(.Right, withInset: 2) countField.autoPinEdge(toSuperviewEdge: .right, withInset: 2)
countField.autoPinEdge(.Left, toEdge: .Right, ofView: cwdControl, withOffset: 4) countField.autoPinEdge(.left, to: .right, of: cwdControl, withOffset: 4)
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return NopDisposable.instance return NopDisposable.instance
} }
@ -154,7 +154,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
} }
.addDisposableTo(self.perSessionDisposeBag) .addDisposableTo(self.perSessionDisposeBag)
self.cwd = mainWindow.cwd self.cwd = mainWindow.cwd as URL
let flatFiles = self.fileItemService.flatFileItems(ofUrl: self.cwd) let flatFiles = self.fileItemService.flatFileItems(ofUrl: self.cwd)
.subscribeOn(self.userInitiatedScheduler) .subscribeOn(self.userInitiatedScheduler)
@ -174,7 +174,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
} }
self.scanCondition.unlock() self.scanCondition.unlock()
self.flatFileItems.appendContentsOf(items) self.flatFileItems.append(contentsOf: items)
self.resetAndAddFilterOperation() self.resetAndAddFilterOperation()
} }
.observeOn(MainScheduler.instance) .observeOn(MainScheduler.instance)
@ -188,7 +188,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
self.searchField.becomeFirstResponder() self.searchField.becomeFirstResponder()
} }
private func resetAndAddFilterOperation() { fileprivate func resetAndAddFilterOperation() {
self.filterOpQueue.cancelAllOperations() self.filterOpQueue.cancelAllOperations()
let op = OpenQuicklyFilterOperation(forOpenQuicklyWindow: self) let op = OpenQuicklyFilterOperation(forOpenQuicklyWindow: self)
self.filterOpQueue.addOperation(op) self.filterOpQueue.addOperation(op)
@ -198,7 +198,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
// MARK: - NSTableViewDataSource // MARK: - NSTableViewDataSource
extension OpenQuicklyWindowComponent { extension OpenQuicklyWindowComponent {
func numberOfRowsInTableView(_: NSTableView) -> Int { @objc(numberOfRowsInTableView:) func numberOfRows(in _: NSTableView) -> Int {
return self.fileViewItems.count return self.fileViewItems.count
} }
} }
@ -206,27 +206,27 @@ extension OpenQuicklyWindowComponent {
// MARK: - NSTableViewDelegate // MARK: - NSTableViewDelegate
extension OpenQuicklyWindowComponent { extension OpenQuicklyWindowComponent {
func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
return OpenQuicklyFileViewRow() return OpenQuicklyFileViewRow()
} }
func tableView(tableView: NSTableView, viewForTableColumn _: NSTableColumn?, row: Int) -> NSView? { @objc(tableView:viewForTableColumn:row:) func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {
let cachedCell = tableView.makeViewWithIdentifier("file-view-row", owner: self) let cachedCell = tableView.make(withIdentifier: "file-view-row", owner: self)
let cell = cachedCell as? ImageAndTextTableCell ?? ImageAndTextTableCell(withIdentifier: "file-view-row") let cell = cachedCell as? ImageAndTextTableCell ?? ImageAndTextTableCell(withIdentifier: "file-view-row")
let url = self.fileViewItems[row].url let url = self.fileViewItems[row].url
cell.text = self.rowText(forUrl: url) cell.text = self.rowText(forUrl: url as URL)
cell.image = self.fileItemService.icon(forUrl: url) cell.image = self.fileItemService.icon(forUrl: url)
return cell return cell
} }
func tableViewSelectionDidChange(_: NSNotification) { func tableViewSelectionDidChange(_: Notification) {
// NSLog("\(#function): selection changed") // NSLog("\(#function): selection changed")
} }
private func rowText(forUrl url: NSURL) -> NSAttributedString { fileprivate func rowText(forUrl url: URL) -> NSAttributedString {
let pathComps = url.pathComponents! let pathComps = url.pathComponents
let truncatedPathComps = pathComps[self.cwdPathCompsCount..<pathComps.count] let truncatedPathComps = pathComps[self.cwdPathCompsCount..<pathComps.count]
let name = truncatedPathComps.last! let name = truncatedPathComps.last!
@ -235,10 +235,10 @@ extension OpenQuicklyWindowComponent {
} }
let rowText: NSMutableAttributedString let rowText: NSMutableAttributedString
let pathInfo = truncatedPathComps.dropLast().reverse().joinWithSeparator(" / ") let pathInfo = truncatedPathComps.dropLast().reversed().joined(separator: " / ")
rowText = NSMutableAttributedString(string: "\(name)\(pathInfo)") rowText = NSMutableAttributedString(string: "\(name)\(pathInfo)")
rowText.addAttribute(NSForegroundColorAttributeName, rowText.addAttribute(NSForegroundColorAttributeName,
value: NSColor.lightGrayColor(), value: NSColor.lightGray,
range: NSRange(location:name.characters.count, range: NSRange(location:name.characters.count,
length: pathInfo.characters.count + 3)) length: pathInfo.characters.count + 3))
@ -249,7 +249,7 @@ extension OpenQuicklyWindowComponent {
// MARK: - NSTextFieldDelegate // MARK: - NSTextFieldDelegate
extension OpenQuicklyWindowComponent { extension OpenQuicklyWindowComponent {
func control(control: NSControl, textView: NSTextView, doCommandBySelector commandSelector: Selector) -> Bool { @objc(control:textView:doCommandBySelector:) func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
switch commandSelector { switch commandSelector {
case NSSelectorFromString("cancelOperation:"): case NSSelectorFromString("cancelOperation:"):
self.window.performClose(self) self.window.performClose(self)
@ -273,7 +273,7 @@ extension OpenQuicklyWindowComponent {
} }
} }
private func moveSelection(ofTableView tableView: NSTableView, byDelta delta: Int) { fileprivate func moveSelection(ofTableView tableView: NSTableView, byDelta delta: Int) {
let selectedRow = tableView.selectedRow let selectedRow = tableView.selectedRow
let lastIdx = tableView.numberOfRows - 1 let lastIdx = tableView.numberOfRows - 1
let targetIdx: Int let targetIdx: Int
@ -286,7 +286,7 @@ extension OpenQuicklyWindowComponent {
targetIdx = selectedRow + delta targetIdx = selectedRow + delta
} }
tableView.selectRowIndexes(NSIndexSet(index: targetIdx), byExtendingSelection: false) tableView.selectRowIndexes(IndexSet(integer: targetIdx), byExtendingSelection: false)
tableView.scrollRowToVisible(targetIdx) tableView.scrollRowToVisible(targetIdx)
} }
} }
@ -294,7 +294,7 @@ extension OpenQuicklyWindowComponent {
// MARK: - NSWindowDelegate // MARK: - NSWindowDelegate
extension OpenQuicklyWindowComponent { extension OpenQuicklyWindowComponent {
func windowWillClose(notification: NSNotification) { func windowWillClose(_ notification: Notification) {
self.endProgress() self.endProgress()
self.mainWindow = nil self.mainWindow = nil
@ -314,7 +314,7 @@ extension OpenQuicklyWindowComponent {
self.countField.stringValue = "0 items" self.countField.stringValue = "0 items"
} }
func windowDidResignKey(notification: NSNotification) { func windowDidResignKey(_ notification: Notification) {
self.window.performClose(self) self.window.performClose(self)
} }
} }

View File

@ -8,8 +8,8 @@ import RxSwift
class OpenQuicklyWindowManager: StandardFlow { class OpenQuicklyWindowManager: StandardFlow {
private let openQuicklyWindow: OpenQuicklyWindowComponent fileprivate let openQuicklyWindow: OpenQuicklyWindowComponent
private let fileItemService: FileItemService fileprivate let fileItemService: FileItemService
init(source: Observable<Any>, fileItemService: FileItemService) { init(source: Observable<Any>, fileItemService: FileItemService) {
self.fileItemService = fileItemService self.fileItemService = fileItemService
@ -22,7 +22,7 @@ class OpenQuicklyWindowManager: StandardFlow {
self.openQuicklyWindow.show(forMainWindow: mainWindow) self.openQuicklyWindow.show(forMainWindow: mainWindow)
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return NopDisposable.instance return NopDisposable.instance
} }
} }

View File

@ -10,15 +10,15 @@ class PrefPane: NSView, Component {
let disposeBag = DisposeBag() let disposeBag = DisposeBag()
private let source: Observable<Any> fileprivate let source: Observable<Any>
private let subject = PublishSubject<Any>() fileprivate let subject = PublishSubject<Any>()
var sink: Observable<Any> { var sink: Observable<Any> {
return self.subject.asObservable() return self.subject.asObservable()
} }
// Return true to place this to the upper left corner when the scroll view is bigger than this view. // Return true to place this to the upper left corner when the scroll view is bigger than this view.
override var flipped: Bool { override var isFlipped: Bool {
return true return true
} }
@ -52,11 +52,11 @@ class PrefPane: NSView, Component {
preconditionFailure("Please override") preconditionFailure("Please override")
} }
func subscription(source source: Observable<Any>) -> Disposable { func subscription(source: Observable<Any>) -> Disposable {
preconditionFailure("Please override") preconditionFailure("Please override")
} }
func publish(event event: Any) { func publish(event: Any) {
self.subject.onNext(event) self.subject.onNext(event)
} }
@ -68,31 +68,31 @@ class PrefPane: NSView, Component {
// MARK: - Control Utils // MARK: - Control Utils
extension PrefPane { extension PrefPane {
func paneTitleTextField(title title: String) -> NSTextField { func paneTitleTextField(title: String) -> NSTextField {
let field = defaultTitleTextField() let field = defaultTitleTextField()
field.font = NSFont.boldSystemFontOfSize(16) field.font = NSFont.boldSystemFont(ofSize: 16)
field.alignment = .Left; field.alignment = .left;
field.stringValue = title field.stringValue = title
return field return field
} }
func titleTextField(title title: String) -> NSTextField { func titleTextField(title: String) -> NSTextField {
let field = defaultTitleTextField() let field = defaultTitleTextField()
field.alignment = .Right; field.alignment = .right;
field.stringValue = title field.stringValue = title
return field return field
} }
func infoTextField(text text: String) -> NSTextField { func infoTextField(text: String) -> NSTextField {
let field = NSTextField(forAutoLayout: ()) let field = NSTextField(forAutoLayout: ())
field.font = NSFont.systemFontOfSize(NSFont.smallSystemFontSize()) field.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
field.textColor = NSColor.grayColor() field.textColor = NSColor.gray
field.backgroundColor = NSColor.clearColor() field.backgroundColor = NSColor.clear
field.editable = false field.isEditable = false
field.bordered = false field.isBordered = false
// both are needed, otherwise hyperlink won't accept mousedown // both are needed, otherwise hyperlink won't accept mousedown
field.selectable = true field.isSelectable = true
field.allowsEditingTextAttributes = true field.allowsEditingTextAttributes = true
field.stringValue = text field.stringValue = text
@ -100,19 +100,19 @@ extension PrefPane {
return field return field
} }
func configureCheckbox(button button: NSButton, title: String, action: Selector) { func configureCheckbox(button: NSButton, title: String, action: Selector) {
button.title = title button.title = title
button.setButtonType(.SwitchButton) button.setButtonType(.switch)
button.bezelStyle = .ThickSquareBezelStyle // button.bezelStyle = .ThickSquareBezelStyle
button.target = self button.target = self
button.action = action button.action = action
} }
private func defaultTitleTextField() -> NSTextField { fileprivate func defaultTitleTextField() -> NSTextField {
let field = NSTextField(forAutoLayout: ()) let field = NSTextField(forAutoLayout: ())
field.backgroundColor = NSColor.clearColor(); field.backgroundColor = NSColor.clear;
field.editable = false; field.isEditable = false;
field.bordered = false; field.isBordered = false;
return field return field
} }
} }

View File

@ -21,21 +21,21 @@ private class PrefKeys {
class PrefStore: Store { class PrefStore: Store {
private static let compatibleVersion = "38" fileprivate static let compatibleVersion = "38"
private static let defaultEditorFont = NeoVimView.defaultFont fileprivate static let defaultEditorFont = NeoVimView.defaultFont
static let minimumEditorFontSize = NeoVimView.minFontSize static let minimumEditorFontSize = NeoVimView.minFontSize
static let maximumEditorFontSize = NeoVimView.maxFontSize static let maximumEditorFontSize = NeoVimView.maxFontSize
private let source: Observable<Any> fileprivate let source: Observable<Any>
private let disposeBag = DisposeBag() fileprivate let disposeBag = DisposeBag()
private let subject = PublishSubject<Any>() fileprivate let subject = PublishSubject<Any>()
var sink: Observable<Any> { var sink: Observable<Any> {
return self.subject.asObservable() return self.subject.asObservable()
} }
private let userDefaults = NSUserDefaults.standardUserDefaults() fileprivate let userDefaults = UserDefaults.standard
private let fontManager = NSFontManager.sharedFontManager() fileprivate let fontManager = NSFontManager.shared()
var data = PrefData( var data = PrefData(
general: GeneralPrefData(openNewWindowWhenLaunching: true, general: GeneralPrefData(openNewWindowWhenLaunching: true,
@ -48,7 +48,7 @@ class PrefStore: Store {
init(source: Observable<Any>) { init(source: Observable<Any>) {
self.source = source self.source = source
if let prefs = self.userDefaults.dictionaryForKey(PrefStore.compatibleVersion) { if let prefs = self.userDefaults.dictionary(forKey: PrefStore.compatibleVersion) {
self.data = self.prefDataFromDict(prefs) self.data = self.prefDataFromDict(prefs)
} else { } else {
self.userDefaults.setValue(self.prefsDict(self.data), forKey: PrefStore.compatibleVersion) self.userDefaults.setValue(self.prefsDict(self.data), forKey: PrefStore.compatibleVersion)
@ -61,7 +61,7 @@ class PrefStore: Store {
self.subject.onCompleted() self.subject.onCompleted()
} }
private func prefDataFromDict(prefs: [String: AnyObject]) -> PrefData { fileprivate func prefDataFromDict(_ prefs: [String: Any]) -> PrefData {
let editorFontName = prefs[PrefKeys.editorFontName] as? String ?? PrefStore.defaultEditorFont.fontName let editorFontName = prefs[PrefKeys.editorFontName] as? String ?? PrefStore.defaultEditorFont.fontName
let editorFontSize = CGFloat( let editorFontSize = CGFloat(
@ -89,43 +89,43 @@ class PrefStore: Store {
) )
} }
private func saneFont(fontName: String, fontSize: CGFloat) -> NSFont { fileprivate func saneFont(_ fontName: String, fontSize: CGFloat) -> NSFont {
var editorFont = NSFont(name: fontName, size: fontSize) ?? PrefStore.defaultEditorFont var editorFont = NSFont(name: fontName, size: fontSize) ?? PrefStore.defaultEditorFont
if !editorFont.fixedPitch { if !editorFont.isFixedPitch {
editorFont = fontManager.convertFont(PrefStore.defaultEditorFont, toSize: editorFont.pointSize) editorFont = fontManager.convert(PrefStore.defaultEditorFont, toSize: editorFont.pointSize)
} }
if editorFont.pointSize < PrefStore.minimumEditorFontSize if editorFont.pointSize < PrefStore.minimumEditorFontSize
|| editorFont.pointSize > PrefStore.maximumEditorFontSize { || editorFont.pointSize > PrefStore.maximumEditorFontSize {
editorFont = fontManager.convertFont(editorFont, toSize: PrefStore.defaultEditorFont.pointSize) editorFont = fontManager.convert(editorFont, toSize: PrefStore.defaultEditorFont.pointSize)
} }
return editorFont return editorFont
} }
private func prefsDict(prefData: PrefData) -> [String: AnyObject] { fileprivate func prefsDict(_ prefData: PrefData) -> [String: AnyObject] {
let generalData = prefData.general let generalData = prefData.general
let appearanceData = prefData.appearance let appearanceData = prefData.appearance
let advancedData = prefData.advanced let advancedData = prefData.advanced
let prefs: [String: AnyObject] = [ let prefs: [String: AnyObject] = [
// General // General
PrefKeys.openNewWindowWhenLaunching: generalData.openNewWindowWhenLaunching, PrefKeys.openNewWindowWhenLaunching: generalData.openNewWindowWhenLaunching as AnyObject,
PrefKeys.openNewWindowOnReactivation: generalData.openNewWindowOnReactivation, PrefKeys.openNewWindowOnReactivation: generalData.openNewWindowOnReactivation as AnyObject,
PrefKeys.openQuicklyIgnorePatterns: PrefUtils.ignorePatternString(fromSet: generalData.ignorePatterns), PrefKeys.openQuicklyIgnorePatterns: PrefUtils.ignorePatternString(fromSet: generalData.ignorePatterns) as AnyObject,
// Appearance // Appearance
PrefKeys.editorFontName: appearanceData.editorFont.fontName, PrefKeys.editorFontName: appearanceData.editorFont.fontName as AnyObject,
PrefKeys.editorFontSize: appearanceData.editorFont.pointSize, PrefKeys.editorFontSize: appearanceData.editorFont.pointSize as AnyObject,
PrefKeys.editorUsesLigatures: appearanceData.editorUsesLigatures, PrefKeys.editorUsesLigatures: appearanceData.editorUsesLigatures as AnyObject,
// Advanced // Advanced
PrefKeys.useInteractiveZsh: advancedData.useInteractiveZsh, PrefKeys.useInteractiveZsh: advancedData.useInteractiveZsh as AnyObject,
] ]
return prefs return prefs
} }
private func addReactions() { fileprivate func addReactions() {
self.source self.source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { $0 as! PrefData } .map { $0 as! PrefData }

View File

@ -7,17 +7,17 @@ import Foundation
class PrefUtils { class PrefUtils {
private static let whitespaceCharSet = NSCharacterSet.whitespaceCharacterSet() fileprivate static let whitespaceCharSet = CharacterSet.whitespaces
static func ignorePatterns(fromString str: String) -> Set<FileItemIgnorePattern> { static func ignorePatterns(fromString str: String) -> Set<FileItemIgnorePattern> {
if str.stringByTrimmingCharactersInSet(self.whitespaceCharSet).characters.count == 0 { if str.trimmingCharacters(in: self.whitespaceCharSet).characters.count == 0 {
return Set() return Set()
} }
let patterns: [FileItemIgnorePattern] = str let patterns: [FileItemIgnorePattern] = str
.componentsSeparatedByString(",") .components(separatedBy: ",")
.flatMap { .flatMap {
let trimmed = $0.stringByTrimmingCharactersInSet(self.whitespaceCharSet) let trimmed = $0.trimmingCharacters(in: self.whitespaceCharSet)
if trimmed.characters.count == 0 { if trimmed.characters.count == 0 {
return nil return nil
} }
@ -31,7 +31,7 @@ class PrefUtils {
static func ignorePatternString(fromSet set: Set<FileItemIgnorePattern>) -> String { static func ignorePatternString(fromSet set: Set<FileItemIgnorePattern>) -> String {
return Array(set) return Array(set)
.map { $0.pattern } .map { $0.pattern }
.sort() .sorted()
.joinWithSeparator(", ") .joined(separator: ", ")
} }
} }

View File

@ -15,14 +15,14 @@ struct PrefData {
class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate { class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate {
private var data: PrefData fileprivate var data: PrefData
private let categoryView = NSTableView.standardSourceListTableView() fileprivate let categoryView = NSTableView.standardSourceListTableView()
private let categoryScrollView = NSScrollView.standardScrollView() fileprivate let categoryScrollView = NSScrollView.standardScrollView()
private let paneContainer = NSScrollView(forAutoLayout: ()) fileprivate let paneContainer = NSScrollView(forAutoLayout: ())
private let panes: [PrefPane] fileprivate let panes: [PrefPane]
private var currentPane: PrefPane { fileprivate var currentPane: PrefPane {
get { get {
return self.paneContainer.documentView as! PrefPane return self.paneContainer.documentView as! PrefPane
} }
@ -53,7 +53,7 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
self.addReactions() self.addReactions()
} }
override func subscription(source source: Observable<Any>) -> Disposable { override func subscription(source: Observable<Any>) -> Disposable {
return source return source
.filter { $0 is PrefData } .filter { $0 is PrefData }
.map { $0 as! PrefData } .map { $0 as! PrefData }
@ -69,8 +69,8 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
override func addViews() { override func addViews() {
let categoryView = self.categoryView let categoryView = self.categoryView
categoryView.setDataSource(self) categoryView.dataSource = self
categoryView.setDelegate(self) categoryView.delegate = self
let categoryScrollView = self.categoryScrollView let categoryScrollView = self.categoryScrollView
categoryScrollView.documentView = categoryView categoryScrollView.documentView = categoryView
@ -79,28 +79,28 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
paneContainer.hasVerticalScroller = true paneContainer.hasVerticalScroller = true
paneContainer.hasHorizontalScroller = true paneContainer.hasHorizontalScroller = true
paneContainer.autohidesScrollers = true paneContainer.autohidesScrollers = true
paneContainer.borderType = .NoBorder paneContainer.borderType = .noBorder
paneContainer.autoresizesSubviews = false paneContainer.autoresizesSubviews = false
paneContainer.backgroundColor = NSColor.windowBackgroundColor() paneContainer.backgroundColor = NSColor.windowBackgroundColor
self.window.contentView?.addSubview(categoryScrollView) self.window.contentView?.addSubview(categoryScrollView)
self.window.contentView?.addSubview(paneContainer) self.window.contentView?.addSubview(paneContainer)
categoryScrollView.autoSetDimension(.Width, toSize: 150) categoryScrollView.autoSetDimension(.width, toSize: 150)
categoryScrollView.autoPinEdgeToSuperviewEdge(.Top, withInset: -1) categoryScrollView.autoPinEdge(toSuperviewEdge: .top, withInset: -1)
categoryScrollView.autoPinEdgeToSuperviewEdge(.Bottom, withInset: -1) categoryScrollView.autoPinEdge(toSuperviewEdge: .bottom, withInset: -1)
categoryScrollView.autoPinEdgeToSuperviewEdge(.Left, withInset: -1) categoryScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: -1)
paneContainer.autoSetDimension(.Width, toSize: 200, relation: .GreaterThanOrEqual) paneContainer.autoSetDimension(.width, toSize: 200, relation: .greaterThanOrEqual)
paneContainer.autoPinEdgeToSuperviewEdge(.Top) paneContainer.autoPinEdge(toSuperviewEdge: .top)
paneContainer.autoPinEdgeToSuperviewEdge(.Right) paneContainer.autoPinEdge(toSuperviewEdge: .right)
paneContainer.autoPinEdgeToSuperviewEdge(.Bottom) paneContainer.autoPinEdge(toSuperviewEdge: .bottom)
paneContainer.autoPinEdge(.Left, toEdge: .Right, ofView: categoryScrollView) paneContainer.autoPinEdge(.left, to: .right, of: categoryScrollView)
self.currentPane = self.panes[0] self.currentPane = self.panes[0]
} }
private func addReactions() { fileprivate func addReactions() {
self.panes self.panes
.map { $0.sink } .map { $0.sink }
.toMergedObservables() .toMergedObservables()
@ -122,7 +122,7 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
.addDisposableTo(self.disposeBag) .addDisposableTo(self.disposeBag)
} }
func windowWillClose(notification: NSNotification) { func windowWillClose(_ notification: Notification) {
self.panes.forEach { $0.windowWillClose() } self.panes.forEach { $0.windowWillClose() }
} }
} }
@ -130,11 +130,11 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
// MARK: - NSTableViewDataSource // MARK: - NSTableViewDataSource
extension PrefWindowComponent { extension PrefWindowComponent {
func numberOfRowsInTableView(_: NSTableView) -> Int { @objc(numberOfRowsInTableView:) func numberOfRows(in _: NSTableView) -> Int {
return self.panes.count return self.panes.count
} }
func tableView(_: NSTableView, objectValueForTableColumn _: NSTableColumn?, row: Int) -> AnyObject? { @objc(tableView:objectValueForTableColumn:row:) func tableView(_: NSTableView, objectValueFor _: NSTableColumn?, row: Int) -> Any? {
return self.panes[row].displayName return self.panes[row].displayName
} }
} }
@ -142,7 +142,7 @@ extension PrefWindowComponent {
// MARK: - NSTableViewDelegate // MARK: - NSTableViewDelegate
extension PrefWindowComponent { extension PrefWindowComponent {
func tableViewSelectionDidChange(_: NSNotification) { func tableViewSelectionDidChange(_: Notification) {
let idx = self.categoryView.selectedRow let idx = self.categoryView.selectedRow
self.currentPane = self.panes[idx] self.currentPane = self.panes[idx]
} }

View File

@ -8,9 +8,9 @@ import RxSwift
class ScoredFileItem: Comparable { class ScoredFileItem: Comparable {
let score: Int let score: Int
unowned let url: NSURL let url: URL
init(score: Int, url: NSURL) { init(score: Int, url: URL) {
self.score = score self.score = score
self.url = url self.url = url
} }

View File

@ -7,7 +7,7 @@ import Foundation
class Scorer { class Scorer {
static func score(target: String, pattern: String) -> Int { static func score(_ target: String, pattern: String) -> Int {
let wf = Matcher.wagnerFisherDistance(target, pattern: pattern) let wf = Matcher.wagnerFisherDistance(target, pattern: pattern)
let fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern) let fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern)
let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern) let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern)

View File

@ -5,17 +5,17 @@
import Foundation import Foundation
func call(@autoclosure closure: () -> Void, when condition: Bool) { if condition { closure() } } func call(_ closure: @autoclosure () -> Void, when condition: Bool) { if condition { closure() } }
func call(@autoclosure closure: () -> Void, whenNot condition: Bool) { if !condition { closure() } } func call(_ closure: @autoclosure () -> Void, whenNot condition: Bool) { if !condition { closure() } }
extension String { extension String {
func without(prefix prefix: String) -> String { func without(prefix: String) -> String {
guard self.hasPrefix(prefix) else { guard self.hasPrefix(prefix) else {
return self return self
} }
let idx = self.startIndex.advancedBy(prefix.characters.count) let idx = self.characters.index(self.startIndex, offsetBy: prefix.characters.count)
return self[idx..<self.endIndex] return self[idx..<self.endIndex]
} }
} }
@ -30,8 +30,8 @@ extension Array {
/// - transform: The transform function. /// - transform: The transform function.
/// - returns: Transformed array of `self`. /// - returns: Transformed array of `self`.
func concurrentChunkMap<R>( func concurrentChunkMap<R>(
chunk: Int = 100, _ chunk: Int = 100,
queue: dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), queue: DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated),
transform: (Element) -> R) -> [R] transform: (Element) -> R) -> [R]
{ {
let count = self.count let count = self.count
@ -41,9 +41,9 @@ extension Array {
var spinLock = OS_SPINLOCK_INIT var spinLock = OS_SPINLOCK_INIT
dispatch_apply(chunkedCount, queue) { idx in DispatchQueue.concurrentPerform(iterations: chunkedCount) { idx in
let startIndex = min(idx * chunk, count) let startIndex = Swift.min(idx * chunk, count)
let endIndex = min(startIndex + chunk, count) let endIndex = Swift.min(startIndex + chunk, count)
let mappedChunk = self[startIndex..<endIndex].map(transform) let mappedChunk = self[startIndex..<endIndex].map(transform)
@ -54,4 +54,4 @@ extension Array {
return result.flatMap { $0 } return result.flatMap { $0 }
} }
} }

View File

@ -19,13 +19,13 @@ class Workspace: NSView {
let mainViewMinimumSize: CGSize let mainViewMinimumSize: CGSize
} }
private(set) var isBarVisible = true { fileprivate(set) var isBarVisible = true {
didSet { didSet {
self.relayout() self.relayout()
} }
} }
private let bars: [WorkspaceBarLocation: WorkspaceBar] fileprivate let bars: [WorkspaceBarLocation: WorkspaceBar]
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
@ -52,7 +52,7 @@ class Workspace: NSView {
self.relayout() self.relayout()
} }
func append(tool tool: WorkspaceTool, location: WorkspaceBarLocation) { func append(tool: WorkspaceTool, location: WorkspaceBarLocation) {
self.bars[location]?.append(tool: tool) self.bars[location]?.append(tool: tool)
} }
@ -68,7 +68,7 @@ class Workspace: NSView {
// MARK: - Layout // MARK: - Layout
extension Workspace { extension Workspace {
private func relayout() { fileprivate func relayout() {
// FIXME: I did not investigate why toggleButtons does not work correctly if we store all constraints in an array // FIXME: I did not investigate why toggleButtons does not work correctly if we store all constraints in an array
// and remove them here by self.removeConstraints(${all constraints). The following seems to work... // and remove them here by self.removeConstraints(${all constraints). The following seems to work...
self.subviews.forEach { $0.removeAllConstraints() } self.subviews.forEach { $0.removeAllConstraints() }
@ -77,8 +77,8 @@ extension Workspace {
let mainView = self.mainView let mainView = self.mainView
self.addSubview(mainView) self.addSubview(mainView)
mainView.autoSetDimension(.Width, toSize: self.config.mainViewMinimumSize.width, relation: .GreaterThanOrEqual) mainView.autoSetDimension(.width, toSize: self.config.mainViewMinimumSize.width, relation: .greaterThanOrEqual)
mainView.autoSetDimension(.Height, toSize: self.config.mainViewMinimumSize.height, relation: .GreaterThanOrEqual) mainView.autoSetDimension(.height, toSize: self.config.mainViewMinimumSize.height, relation: .greaterThanOrEqual)
guard self.isBarVisible else { guard self.isBarVisible else {
mainView.autoPinEdgesToSuperviewEdges() mainView.autoPinEdgesToSuperviewEdges()
@ -95,35 +95,35 @@ extension Workspace {
self.addSubview(bottomBar) self.addSubview(bottomBar)
self.addSubview(leftBar) self.addSubview(leftBar)
topBar.autoPinEdgeToSuperviewEdge(.Top) topBar.autoPinEdge(toSuperviewEdge: .top)
topBar.autoPinEdgeToSuperviewEdge(.Right) topBar.autoPinEdge(toSuperviewEdge: .right)
topBar.autoPinEdgeToSuperviewEdge(.Left) topBar.autoPinEdge(toSuperviewEdge: .left)
rightBar.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar) rightBar.autoPinEdge(.top, to: .bottom, of: topBar)
rightBar.autoPinEdgeToSuperviewEdge(.Right) rightBar.autoPinEdge(toSuperviewEdge: .right)
rightBar.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar) rightBar.autoPinEdge(.bottom, to: .top, of: bottomBar)
bottomBar.autoPinEdgeToSuperviewEdge(.Right) bottomBar.autoPinEdge(toSuperviewEdge: .right)
bottomBar.autoPinEdgeToSuperviewEdge(.Bottom) bottomBar.autoPinEdge(toSuperviewEdge: .bottom)
bottomBar.autoPinEdgeToSuperviewEdge(.Left) bottomBar.autoPinEdge(toSuperviewEdge: .left)
leftBar.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar) leftBar.autoPinEdge(.top, to: .bottom, of: topBar)
leftBar.autoPinEdgeToSuperviewEdge(.Left) leftBar.autoPinEdge(toSuperviewEdge: .left)
leftBar.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar) leftBar.autoPinEdge(.bottom, to: .top, of: bottomBar)
NSLayoutConstraint.autoSetPriority(NSLayoutPriorityDragThatCannotResizeWindow) { NSLayoutConstraint.autoSetPriority(NSLayoutPriorityDragThatCannotResizeWindow) {
topBar.dimensionConstraint = topBar.autoSetDimension(.Height, toSize: 50) topBar.dimensionConstraint = topBar.autoSetDimension(.height, toSize: 50)
rightBar.dimensionConstraint = rightBar.autoSetDimension(.Width, toSize: 50) rightBar.dimensionConstraint = rightBar.autoSetDimension(.width, toSize: 50)
bottomBar.dimensionConstraint = bottomBar.autoSetDimension(.Height, toSize: 50) bottomBar.dimensionConstraint = bottomBar.autoSetDimension(.height, toSize: 50)
leftBar.dimensionConstraint = leftBar.autoSetDimension(.Width, toSize: 50) leftBar.dimensionConstraint = leftBar.autoSetDimension(.width, toSize: 50)
} }
self.bars.values.forEach { $0.relayout() } self.bars.values.forEach { $0.relayout() }
mainView.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar) mainView.autoPinEdge(.top, to: .bottom, of: topBar)
mainView.autoPinEdge(.Right, toEdge: .Left, ofView: rightBar) mainView.autoPinEdge(.right, to: .left, of: rightBar)
mainView.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar) mainView.autoPinEdge(.bottom, to: .top, of: bottomBar)
mainView.autoPinEdge(.Left, toEdge: .Right, ofView: leftBar) mainView.autoPinEdge(.left, to: .right, of: leftBar)
self.needsDisplay = true self.needsDisplay = true
} }

View File

@ -8,16 +8,16 @@ import PureLayout
class WorkspaceBar: NSView, WorkspaceToolDelegate { class WorkspaceBar: NSView, WorkspaceToolDelegate {
static private let separatorColor = NSColor.controlShadowColor() static fileprivate let separatorColor = NSColor.controlShadowColor
static private let separatorThickness = CGFloat(1) static fileprivate let separatorThickness = CGFloat(1)
private var tools = [WorkspaceTool]() fileprivate var tools = [WorkspaceTool]()
private weak var selectedTool: WorkspaceTool? fileprivate weak var selectedTool: WorkspaceTool?
private var isMouseDownOngoing = false fileprivate var isMouseDownOngoing = false
private var dragIncrement = CGFloat(1) fileprivate var dragIncrement = CGFloat(1)
private var layoutConstraints = [NSLayoutConstraint]() fileprivate var layoutConstraints = [NSLayoutConstraint]()
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
@ -39,7 +39,7 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
super.translatesAutoresizingMaskIntoConstraints = false super.translatesAutoresizingMaskIntoConstraints = false
self.wantsLayer = true self.wantsLayer = true
self.layer!.backgroundColor = NSColor.windowBackgroundColor().CGColor self.layer!.backgroundColor = NSColor.windowBackgroundColor.cgColor
} }
func relayout() { func relayout() {
@ -47,7 +47,7 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
self.removeAllSubviews() self.removeAllSubviews()
if self.isEmpty() { if self.isEmpty() {
self.set(dimension: 0) self.set(0)
return return
} }
@ -57,31 +57,31 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
if self.isOpen() { if self.isOpen() {
let curTool = self.selectedTool! let curTool = self.selectedTool!
self.layout(tool: curTool) self.layout(curTool)
let newDimension = self.barDimension(withToolDimension: curTool.dimension) let newDimension = self.barDimension(withToolDimension: curTool.dimension)
self.set(dimension: newDimension) self.set(newDimension)
} else { } else {
self.set(dimension: self.barDimensionWithButtonsWithoutTool()) self.set(self.barDimensionWithButtonsWithoutTool())
} }
} else { } else {
if self.isOpen() { if self.isOpen() {
let curTool = self.selectedTool! let curTool = self.selectedTool!
self.layoutWithoutButtons(tool: curTool) self.layoutWithoutButtons(curTool)
let newDimension = self.barDimensionWithoutButtons(withToolDimension: curTool.dimension) let newDimension = self.barDimensionWithoutButtons(withToolDimension: curTool.dimension)
self.set(dimension: newDimension) self.set(newDimension)
} else { } else {
self.set(dimension: 0) self.set(0)
} }
} }
self.needsDisplay = true self.needsDisplay = true
} }
func append(tool tool: WorkspaceTool) { func append(tool: WorkspaceTool) {
tool.delegate = self tool.delegate = self
tool.location = self.location tool.location = self.location
tools.append(tool) tools.append(tool)
@ -98,8 +98,8 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
// MARK: - NSView // MARK: - NSView
extension WorkspaceBar { extension WorkspaceBar {
override func drawRect(dirtyRect: NSRect) { override func draw(_ dirtyRect: NSRect) {
super.drawRect(dirtyRect) super.draw(dirtyRect)
if self.isButtonVisible { if self.isButtonVisible {
self.drawInnerSeparator(dirtyRect) self.drawInnerSeparator(dirtyRect)
@ -110,7 +110,7 @@ extension WorkspaceBar {
} }
} }
override func mouseDown(event: NSEvent) { override func mouseDown(with event: NSEvent) {
guard self.isOpen() else { guard self.isOpen() else {
return return
} }
@ -119,11 +119,11 @@ extension WorkspaceBar {
return return
} }
let initialMouseLoc = self.convertPoint(event.locationInWindow, fromView: nil) let initialMouseLoc = self.convert(event.locationInWindow, from: nil)
let mouseInResizeRect = NSMouseInRect(initialMouseLoc, self.resizeRect(), self.flipped) let mouseInResizeRect = NSMouseInRect(initialMouseLoc, self.resizeRect(), self.isFlipped)
guard mouseInResizeRect && event.type == .LeftMouseDown else { guard mouseInResizeRect && event.type == .leftMouseDown else {
super.mouseDown(event) super.mouseDown(with: event)
return return
} }
@ -133,14 +133,14 @@ extension WorkspaceBar {
var dragged = false var dragged = false
var curEvent = event var curEvent = event
let nextEventMask: NSEventMask = [ let nextEventMask: NSEventMask = [
NSEventMask.LeftMouseDraggedMask, NSEventMask.leftMouseDragged,
NSEventMask.LeftMouseDownMask, NSEventMask.leftMouseDown,
NSEventMask.LeftMouseUpMask NSEventMask.leftMouseUp
] ]
while curEvent.type != .LeftMouseUp { while curEvent.type != .leftMouseUp {
let nextEvent = NSApp.nextEventMatchingMask(Int(nextEventMask.rawValue), let nextEvent = NSApp.nextEvent(matching: NSEventMask(rawValue: UInt64(Int(nextEventMask.rawValue))),
untilDate: NSDate.distantFuture(), until: Date.distantFuture,
inMode: NSEventTrackingRunLoopMode, inMode: RunLoopMode.eventTrackingRunLoopMode,
dequeue: true) dequeue: true)
guard nextEvent != nil else { guard nextEvent != nil else {
break break
@ -148,23 +148,23 @@ extension WorkspaceBar {
curEvent = nextEvent! curEvent = nextEvent!
guard curEvent.type == .LeftMouseDragged else { guard curEvent.type == .leftMouseDragged else {
break break
} }
let curMouseLoc = self.convertPoint(curEvent.locationInWindow, fromView: nil) let curMouseLoc = self.convert(curEvent.locationInWindow, from: nil)
let distance = sq(initialMouseLoc.x - curMouseLoc.x) + sq(initialMouseLoc.y - curMouseLoc.y) let distance = sq(initialMouseLoc.x - curMouseLoc.x) + sq(initialMouseLoc.y - curMouseLoc.y)
guard dragged || distance >= 1 else { guard dragged || distance >= 1 else {
continue continue
} }
let locInSuperview = self.superview!.convertPoint(curEvent.locationInWindow, fromView: nil) let locInSuperview = self.superview!.convert(curEvent.locationInWindow, from: nil)
let newDimension = self.newDimension(forLocationInSuperview: locInSuperview) let newDimension = self.newDimension(forLocationInSuperview: locInSuperview)
self.set(dimension: newDimension) self.set(newDimension)
self.window?.invalidateCursorRectsForView(self) self.window?.invalidateCursorRects(for: self)
dragged = true dragged = true
} }
@ -180,13 +180,13 @@ extension WorkspaceBar {
switch self.location { switch self.location {
case .top, .bottom: case .top, .bottom:
self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeUpDownCursor()) self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeUpDown())
case .right, .left: case .right, .left:
self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeLeftRightCursor()) self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeLeftRight())
} }
} }
private func drawInnerSeparator(dirtyRect: NSRect) { fileprivate func drawInnerSeparator(_ dirtyRect: NSRect) {
WorkspaceBar.separatorColor.set() WorkspaceBar.separatorColor.set()
let innerLineRect = self.innerSeparatorRect() let innerLineRect = self.innerSeparatorRect()
@ -195,7 +195,7 @@ extension WorkspaceBar {
} }
} }
private func drawOuterSeparator(dirtyRect: NSRect) { fileprivate func drawOuterSeparator(_ dirtyRect: NSRect) {
WorkspaceBar.separatorColor.set() WorkspaceBar.separatorColor.set()
let outerLineRect = self.outerSeparatorRect() let outerLineRect = self.outerSeparatorRect()
@ -204,7 +204,7 @@ extension WorkspaceBar {
} }
} }
private func buttonSize() -> CGSize { fileprivate func buttonSize() -> CGSize {
if self.isEmpty() { if self.isEmpty() {
return CGSize.zero return CGSize.zero
} }
@ -212,7 +212,7 @@ extension WorkspaceBar {
return self.tools.first!.button.intrinsicContentSize return self.tools.first!.button.intrinsicContentSize
} }
private func innerSeparatorRect() -> CGRect { fileprivate func innerSeparatorRect() -> CGRect {
let bounds = self.bounds let bounds = self.bounds
let thickness = WorkspaceBar.separatorThickness let thickness = WorkspaceBar.separatorThickness
let bar = self.buttonSize() let bar = self.buttonSize()
@ -229,12 +229,12 @@ extension WorkspaceBar {
} }
} }
private func newDimension(forLocationInSuperview locInSuperview: CGPoint) -> CGFloat { fileprivate func newDimension(forLocationInSuperview locInSuperview: CGPoint) -> CGFloat {
let dimension = self.dimension(forLocationInSuperview: locInSuperview) let dimension = self.dimension(forLocationInSuperview: locInSuperview)
return self.dragIncrement * floor(dimension / self.dragIncrement) return self.dragIncrement * floor(dimension / self.dragIncrement)
} }
private func dimension(forLocationInSuperview locInSuperview: CGPoint) -> CGFloat { fileprivate func dimension(forLocationInSuperview locInSuperview: CGPoint) -> CGFloat {
let superviewBounds = self.superview!.bounds let superviewBounds = self.superview!.bounds
switch self.location { switch self.location {
@ -249,11 +249,11 @@ extension WorkspaceBar {
} }
} }
private func sq(number: CGFloat) -> CGFloat { fileprivate func sq(_ number: CGFloat) -> CGFloat {
return number * number return number * number
} }
private func outerSeparatorRect() -> CGRect { fileprivate func outerSeparatorRect() -> CGRect {
let thickness = WorkspaceBar.separatorThickness let thickness = WorkspaceBar.separatorThickness
switch self.location { switch self.location {
@ -268,7 +268,7 @@ extension WorkspaceBar {
} }
} }
private func resizeRect() -> CGRect { fileprivate func resizeRect() -> CGRect {
let separatorRect = self.outerSeparatorRect() let separatorRect = self.outerSeparatorRect()
let clickDimension = CGFloat(4) let clickDimension = CGFloat(4)
@ -284,7 +284,7 @@ extension WorkspaceBar {
} }
} }
private func set(dimension dimension: CGFloat) { fileprivate func set(_ dimension: CGFloat) {
self.dimensionConstraint.constant = dimension self.dimensionConstraint.constant = dimension
let toolDimension = self.toolDimension(fromBarDimension: dimension) let toolDimension = self.toolDimension(fromBarDimension: dimension)
@ -297,64 +297,64 @@ extension WorkspaceBar {
// MARK: - Layout // MARK: - Layout
extension WorkspaceBar { extension WorkspaceBar {
private func isEmpty() -> Bool { fileprivate func isEmpty() -> Bool {
return self.tools.isEmpty return self.tools.isEmpty
} }
private func hasTools() -> Bool { fileprivate func hasTools() -> Bool {
return !self.isEmpty() return !self.isEmpty()
} }
private func isOpen() -> Bool { fileprivate func isOpen() -> Bool {
return self.selectedTool != nil return self.selectedTool != nil
} }
private func layoutWithoutButtons(tool tool: WorkspaceTool) { fileprivate func layoutWithoutButtons(_ tool: WorkspaceTool) {
let view = tool.view let view = tool.view
let thickness = WorkspaceBar.separatorThickness let thickness = WorkspaceBar.separatorThickness
self.addSubview(view) self.addSubview(view)
switch self.location { switch self.location {
case .top: case .top:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top), view.autoPinEdge(toSuperviewEdge: .top),
view.autoPinEdgeToSuperviewEdge(.Right), view.autoPinEdge(toSuperviewEdge: .right),
view.autoPinEdgeToSuperviewEdge(.Bottom, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .bottom, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Left), view.autoPinEdge(toSuperviewEdge: .left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
case .right: case .right:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top), view.autoPinEdge(toSuperviewEdge: .top),
view.autoPinEdgeToSuperviewEdge(.Right), view.autoPinEdge(toSuperviewEdge: .right),
view.autoPinEdgeToSuperviewEdge(.Bottom), view.autoPinEdge(toSuperviewEdge: .bottom),
view.autoPinEdgeToSuperviewEdge(.Left, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .left, withInset: thickness),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.width, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
case .bottom: case .bottom:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .top, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Right), view.autoPinEdge(toSuperviewEdge: .right),
view.autoPinEdgeToSuperviewEdge(.Bottom), view.autoPinEdge(toSuperviewEdge: .bottom),
view.autoPinEdgeToSuperviewEdge(.Left), view.autoPinEdge(toSuperviewEdge: .left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
case .left: case .left:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top), view.autoPinEdge(toSuperviewEdge: .top),
view.autoPinEdgeToSuperviewEdge(.Right, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .right, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Bottom), view.autoPinEdge(toSuperviewEdge: .bottom),
view.autoPinEdgeToSuperviewEdge(.Left), view.autoPinEdge(toSuperviewEdge: .left),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.width, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
} }
} }
private func layout(tool tool: WorkspaceTool) { fileprivate func layout(_ tool: WorkspaceTool) {
let view = tool.view let view = tool.view
let button = tool.button let button = tool.button
let thickness = WorkspaceBar.separatorThickness let thickness = WorkspaceBar.separatorThickness
@ -363,45 +363,45 @@ extension WorkspaceBar {
switch self.location { switch self.location {
case .top: case .top:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdge(.Top, toEdge: .Bottom, ofView: button, withOffset: thickness), view.autoPinEdge(.top, to: .bottom, of: button, withOffset: thickness),
view.autoPinEdgeToSuperviewEdge(.Right), view.autoPinEdge(toSuperviewEdge: .right),
view.autoPinEdgeToSuperviewEdge(.Bottom, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .bottom, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Left), view.autoPinEdge(toSuperviewEdge: .left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
case .right: case .right:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top), view.autoPinEdge(toSuperviewEdge: .top),
view.autoPinEdge(.Right, toEdge: .Left, ofView: button, withOffset: -thickness), // Offset is count l -> r, view.autoPinEdge(.right, to: .left, of: button, withOffset: -thickness), // Offset is count l -> r,
view.autoPinEdgeToSuperviewEdge(.Bottom), view.autoPinEdge(toSuperviewEdge: .bottom),
view.autoPinEdgeToSuperviewEdge(.Left, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .left, withInset: thickness),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.width, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
case .bottom: case .bottom:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .top, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Right), view.autoPinEdge(toSuperviewEdge: .right),
view.autoPinEdge(.Bottom, toEdge: .Top, ofView: button, withOffset: -thickness), // Offset is count t -> b, view.autoPinEdge(.bottom, to: .top, of: button, withOffset: -thickness), // Offset is count t -> b,
view.autoPinEdgeToSuperviewEdge(.Left), view.autoPinEdge(toSuperviewEdge: .left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
case .left: case .left:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
view.autoPinEdgeToSuperviewEdge(.Top), view.autoPinEdge(toSuperviewEdge: .top),
view.autoPinEdgeToSuperviewEdge(.Right, withInset: thickness), view.autoPinEdge(toSuperviewEdge: .right, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Bottom), view.autoPinEdge(toSuperviewEdge: .bottom),
view.autoPinEdge(.Left, toEdge: .Right, ofView: button, withOffset: thickness), view.autoPinEdge(.left, to: .right, of: button, withOffset: thickness),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual) view.autoSetDimension(.width, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
]) ])
} }
} }
private func layoutButtons() { fileprivate func layoutButtons() {
guard let firstTool = self.tools.first else { guard let firstTool = self.tools.first else {
return return
} }
@ -413,24 +413,24 @@ extension WorkspaceBar {
let firstButton = firstTool.button let firstButton = firstTool.button
switch self.location { switch self.location {
case .top: case .top:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
firstButton.autoPinEdgeToSuperviewEdge(.Top), firstButton.autoPinEdge(toSuperviewEdge: .top),
firstButton.autoPinEdgeToSuperviewEdge(.Left), firstButton.autoPinEdge(toSuperviewEdge: .left),
]) ])
case .right: case .right:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
firstButton.autoPinEdgeToSuperviewEdge(.Top), firstButton.autoPinEdge(toSuperviewEdge: .top),
firstButton.autoPinEdgeToSuperviewEdge(.Right), firstButton.autoPinEdge(toSuperviewEdge: .right),
]) ])
case .bottom: case .bottom:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
firstButton.autoPinEdgeToSuperviewEdge(.Left), firstButton.autoPinEdge(toSuperviewEdge: .left),
firstButton.autoPinEdgeToSuperviewEdge(.Bottom), firstButton.autoPinEdge(toSuperviewEdge: .bottom),
]) ])
case .left: case .left:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
firstButton.autoPinEdgeToSuperviewEdge(.Top), firstButton.autoPinEdge(toSuperviewEdge: .top),
firstButton.autoPinEdgeToSuperviewEdge(.Left), firstButton.autoPinEdge(toSuperviewEdge: .left),
]) ])
} }
@ -438,24 +438,24 @@ extension WorkspaceBar {
for button in self.tools[1..<self.tools.count].map({ $0.button }) { for button in self.tools[1..<self.tools.count].map({ $0.button }) {
switch self.location { switch self.location {
case .top: case .top:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
button.autoPinEdgeToSuperviewEdge(.Top), button.autoPinEdge(toSuperviewEdge: .top),
button.autoPinEdge(.Left, toEdge: .Right, ofView: lastButton), button.autoPinEdge(.left, to: .right, of: lastButton),
]) ])
case .right: case .right:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: lastButton), button.autoPinEdge(.top, to: .bottom, of: lastButton),
button.autoPinEdgeToSuperviewEdge(.Right), button.autoPinEdge(toSuperviewEdge: .right),
]) ])
case .bottom: case .bottom:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
button.autoPinEdge(.Left, toEdge: .Right, ofView: lastButton), button.autoPinEdge(.left, to: .right, of: lastButton),
button.autoPinEdgeToSuperviewEdge(.Bottom), button.autoPinEdge(toSuperviewEdge: .bottom),
]) ])
case .left: case .left:
self.layoutConstraints.appendContentsOf([ self.layoutConstraints.append(contentsOf: [
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: lastButton), button.autoPinEdge(.top, to: .bottom, of: lastButton),
button.autoPinEdgeToSuperviewEdge(.Left), button.autoPinEdge(toSuperviewEdge: .left),
]) ])
} }
@ -463,7 +463,7 @@ extension WorkspaceBar {
} }
} }
private func barDimensionWithButtonsWithoutTool() -> CGFloat { fileprivate func barDimensionWithButtonsWithoutTool() -> CGFloat {
switch self.location { switch self.location {
case .top, .bottom: case .top, .bottom:
return self.buttonSize().height + WorkspaceBar.separatorThickness return self.buttonSize().height + WorkspaceBar.separatorThickness
@ -472,15 +472,15 @@ extension WorkspaceBar {
} }
} }
private func barDimensionWithoutButtons(withToolDimension toolDimension: CGFloat) -> CGFloat { fileprivate func barDimensionWithoutButtons(withToolDimension toolDimension: CGFloat) -> CGFloat {
return toolDimension + WorkspaceBar.separatorThickness return toolDimension + WorkspaceBar.separatorThickness
} }
private func barDimension(withToolDimension toolDimension: CGFloat) -> CGFloat { fileprivate func barDimension(withToolDimension toolDimension: CGFloat) -> CGFloat {
return self.barDimensionWithButtonsWithoutTool() + toolDimension + WorkspaceBar.separatorThickness return self.barDimensionWithButtonsWithoutTool() + toolDimension + WorkspaceBar.separatorThickness
} }
private func toolDimension(fromBarDimension barDimension: CGFloat) -> CGFloat { fileprivate func toolDimension(fromBarDimension barDimension: CGFloat) -> CGFloat {
if self.isButtonVisible { if self.isButtonVisible {
return barDimension - WorkspaceBar.separatorThickness - barDimensionWithButtonsWithoutTool() return barDimension - WorkspaceBar.separatorThickness - barDimensionWithButtonsWithoutTool()
} }
@ -492,7 +492,7 @@ extension WorkspaceBar {
// MARK: - WorkspaceToolDelegate // MARK: - WorkspaceToolDelegate
extension WorkspaceBar { extension WorkspaceBar {
func toggle(tool tool: WorkspaceTool) { func toggle(_ tool: WorkspaceTool) {
if self.isOpen() { if self.isOpen() {
let curTool = self.selectedTool! let curTool = self.selectedTool!
if curTool === tool { if curTool === tool {

View File

@ -7,7 +7,7 @@ import Cocoa
protocol WorkspaceToolDelegate: class { protocol WorkspaceToolDelegate: class {
func toggle(tool tool: WorkspaceTool) func toggle(_ tool: WorkspaceTool)
} }
class WorkspaceTool { class WorkspaceTool {
@ -46,7 +46,7 @@ class WorkspaceTool {
} }
func toggle() { func toggle() {
self.delegate?.toggle(tool: self) self.delegate?.toggle(self)
self.isSelected = !self.isSelected self.isSelected = !self.isSelected
} }
} }

View File

@ -7,10 +7,10 @@ import Cocoa
class WorkspaceToolButton: NSView { class WorkspaceToolButton: NSView {
static private let titlePadding = CGSize(width: 8, height: 2) static fileprivate let titlePadding = CGSize(width: 8, height: 2)
private let title: NSAttributedString fileprivate let title: NSAttributedString
private var trackingArea = NSTrackingArea() fileprivate var trackingArea = NSTrackingArea()
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
@ -26,7 +26,7 @@ class WorkspaceToolButton: NSView {
init(title: String) { init(title: String) {
self.title = NSAttributedString(string: title, attributes: [ self.title = NSAttributedString(string: title, attributes: [
NSFontAttributeName: NSFont.systemFontOfSize(11) NSFontAttributeName: NSFont.systemFont(ofSize: 11)
]) ])
super.init(frame: CGRect.zero) super.init(frame: CGRect.zero)
@ -36,11 +36,11 @@ class WorkspaceToolButton: NSView {
} }
func highlight() { func highlight() {
self.layer?.backgroundColor = NSColor.controlShadowColor().CGColor self.layer?.backgroundColor = NSColor.controlShadowColor.cgColor
} }
func dehighlight() { func dehighlight() {
self.layer?.backgroundColor = NSColor.clearColor().CGColor self.layer?.backgroundColor = NSColor.clear.cgColor
} }
} }
@ -59,13 +59,13 @@ extension WorkspaceToolButton {
} }
} }
override func drawRect(dirtyRect: NSRect) { override func draw(_ dirtyRect: NSRect) {
super.drawRect(dirtyRect) super.draw(dirtyRect)
let padding = WorkspaceToolButton.titlePadding let padding = WorkspaceToolButton.titlePadding
switch self.location { switch self.location {
case .top, .bottom: case .top, .bottom:
self.title.drawAtPoint(CGPoint(x: padding.width, y: padding.height)) self.title.draw(at: CGPoint(x: padding.width, y: padding.height))
case .right: case .right:
self.title.draw(at: CGPoint(x: padding.height, y: self.bounds.height - padding.width), angle: -CGFloat(M_PI_2)) self.title.draw(at: CGPoint(x: padding.height, y: self.bounds.height - padding.width), angle: -CGFloat(M_PI_2))
case .left: case .left:
@ -77,7 +77,7 @@ extension WorkspaceToolButton {
self.removeTrackingArea(self.trackingArea) self.removeTrackingArea(self.trackingArea)
self.trackingArea = NSTrackingArea(rect: self.bounds, self.trackingArea = NSTrackingArea(rect: self.bounds,
options: [.MouseEnteredAndExited, .ActiveInActiveApp], options: [.mouseEnteredAndExited, .activeInActiveApp],
owner: self, owner: self,
userInfo: nil) userInfo: nil)
self.addTrackingArea(self.trackingArea) self.addTrackingArea(self.trackingArea)
@ -85,11 +85,11 @@ extension WorkspaceToolButton {
super.updateTrackingAreas() super.updateTrackingAreas()
} }
override func mouseDown(event: NSEvent) { override func mouseDown(with event: NSEvent) {
self.tool?.toggle() self.tool?.toggle()
} }
override func mouseEntered(_: NSEvent) { override func mouseEntered(with _: NSEvent) {
if self.isSelected { if self.isSelected {
return return
} }
@ -97,7 +97,7 @@ extension WorkspaceToolButton {
self.highlight() self.highlight()
} }
override func mouseExited(_: NSEvent) { override func mouseExited(with _: NSEvent) {
if self.isSelected { if self.isSelected {
return return
} }

View File

@ -8,17 +8,17 @@ import Nimble
class FileUtilsTest: XCTestCase { class FileUtilsTest: XCTestCase {
var fileUtilsRsrcUrl = NSURL() var fileUtilsRsrcUrl = URL()
var a1Dir = NSURL() var a1Dir = URL()
override func setUp() { override func setUp() {
fileUtilsRsrcUrl = NSBundle.init(forClass: self.dynamicType).URLForResource("FileUtilsTest", withExtension: "")! fileUtilsRsrcUrl = Bundle.init(for: type(of: self)).url(forResource: "FileUtilsTest", withExtension: "")!
a1Dir = fileUtilsRsrcUrl.URLByAppendingPathComponent("a1") a1Dir = fileUtilsRsrcUrl.appendingPathComponent("a1")
} }
func testCommonParentOneDirUrl() { func testCommonParentOneDirUrl() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"), fileUtilsRsrcUrl.appendingPathComponent("a1"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
@ -26,20 +26,20 @@ class FileUtilsTest: XCTestCase {
func testCommonParentOneFileUrl() { func testCommonParentOneFileUrl() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
} }
func testCommonParentEmptyParams() { func testCommonParentEmptyParams() {
expect(FileUtils.commonParent(ofUrls: [])).to(equal(NSURL(fileURLWithPath: "/", isDirectory: true))) expect(FileUtils.commonParent(ofUrls: []) as URL).to(equal(URL(fileURLWithPath: "/", isDirectory: true)))
} }
func testCommonParent1() { func testCommonParent1() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"), fileUtilsRsrcUrl.appendingPathComponent("a1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
@ -47,9 +47,9 @@ class FileUtilsTest: XCTestCase {
func testCommonParent2() { func testCommonParent2() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"), fileUtilsRsrcUrl.appendingPathComponent("a1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
@ -57,10 +57,10 @@ class FileUtilsTest: XCTestCase {
func testCommonParent3() { func testCommonParent3() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"), fileUtilsRsrcUrl.appendingPathComponent("a1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("b1/b1-file1"), fileUtilsRsrcUrl.appendingPathComponent("b1/b1-file1"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl))
@ -68,10 +68,10 @@ class FileUtilsTest: XCTestCase {
func testCommonParent4() { func testCommonParent4() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"), fileUtilsRsrcUrl.appendingPathComponent("a1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("b1"), fileUtilsRsrcUrl.appendingPathComponent("b1"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl))
@ -79,9 +79,9 @@ class FileUtilsTest: XCTestCase {
func testCommonParent5() { func testCommonParent5() {
let urls = [ let urls = [
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"), fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2"), fileUtilsRsrcUrl.appendingPathComponent("a1/a2"),
] ]
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir)) expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))

View File

@ -9,11 +9,11 @@ import Nimble
class ScorerTest: XCTestCase { class ScorerTest: XCTestCase {
func testScore1() { func testScore1() {
let pattern = "sw/nvv".stringByReplacingOccurrencesOfString("/", withString: "") let pattern = "sw/nvv".replacingOccurrences(of: "/", with: "")
let targets = [ let targets = [
"SwiftNeoVim/NeoVimView.swift", "SwiftNeoVim/NeoVimView.swift",
"build/Release/NeoVimServer.dSYM/Contents/Resources/DWARF/NeoVimServer", "build/Release/NeoVimServer.dSYM/Contents/Resources/DWARF/NeoVimServer",
].map { $0.stringByReplacingOccurrencesOfString("/", withString: "") } ].map { $0.replacingOccurrences(of: "/", with: "") }
expect(Scorer.score(targets[0], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[1], pattern: pattern))) expect(Scorer.score(targets[0], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[1], pattern: pattern)))
} }