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:
parent
d29c67064e
commit
0f7b564667
2
Cartfile
2
Cartfile
@ -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 "eonil/FileSystemEvents" "master"
|
||||
|
@ -1 +1 @@
|
||||
github "Quick/Nimble" == 4.1.0
|
||||
github "Quick/Nimble" == 5.0.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
github "eonil/FileSystemEvents" "01f622d3b446612d573b1035b46afb7a6eee0240"
|
||||
github "Quick/Nimble" "v4.1.0"
|
||||
github "eonil/FileSystemEvents" "aa5c6af1fd35939f9aca3b9eba3b672bfa549b3a"
|
||||
github "Quick/Nimble" "v5.0.0"
|
||||
github "PureLayout/PureLayout" "v3.0.2"
|
||||
github "ReactiveX/RxSwift" "2.6.0"
|
||||
github "ReactiveX/RxSwift" "3.0.0-beta.1"
|
||||
|
@ -30,7 +30,7 @@ extension NSView {
|
||||
/// - Returns: Rects currently being drawn
|
||||
/// - Warning: Call only in drawRect()
|
||||
func rectsBeingDrawn() -> [CGRect] {
|
||||
var rectsPtr: UnsafePointer<CGRect> = nil
|
||||
var rectsPtr: UnsafePointer<CGRect>? = nil
|
||||
var count: Int = 0
|
||||
self.getRectsBeingDrawn(&rectsPtr, count: &count)
|
||||
|
||||
|
@ -7,11 +7,11 @@ import Cocoa
|
||||
|
||||
class ColorUtils {
|
||||
|
||||
static func colorIgnoringAlpha(rgb: UInt32) -> NSColor {
|
||||
static func colorIgnoringAlpha(_ rgb: UInt32) -> NSColor {
|
||||
let red = (CGFloat((rgb >> 16) & 0xFF)) / 255.0;
|
||||
let green = (CGFloat((rgb >> 8) & 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)
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@
|
||||
|
||||
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) {
|
||||
dispatch_async(DispatchUtils.qDispatchMainQueue, call)
|
||||
open static func gui(_ call: @escaping () -> Void) {
|
||||
DispatchUtils.qDispatchMainQueue.async(execute: call)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
import Cocoa
|
||||
|
||||
struct Cell: CustomStringConvertible {
|
||||
private let attributes: CellAttributes
|
||||
fileprivate let attributes: CellAttributes
|
||||
|
||||
let string: String
|
||||
var marked: Bool
|
||||
@ -72,11 +72,11 @@ struct Region: CustomStringConvertible {
|
||||
return "Region<\(self.top)...\(self.bottom):\(self.left)...\(self.right)>"
|
||||
}
|
||||
|
||||
var rowRange: Range<Int> {
|
||||
var rowRange: CountableClosedRange<Int> {
|
||||
return self.top...self.bottom
|
||||
}
|
||||
|
||||
var columnRange: Range<Int> {
|
||||
var columnRange: CountableClosedRange<Int> {
|
||||
return self.left...self.right
|
||||
}
|
||||
}
|
||||
@ -84,10 +84,10 @@ struct Region: CustomStringConvertible {
|
||||
/// Almost a verbatim copy of ugrid.c of NeoVim
|
||||
class Grid: CustomStringConvertible {
|
||||
|
||||
private(set) var region = Region.zero
|
||||
private(set) var size = Size.zero
|
||||
private(set) var putPosition = Position.zero
|
||||
private(set) var screenCursor = Position.zero
|
||||
fileprivate(set) var region = Region.zero
|
||||
fileprivate(set) var size = Size.zero
|
||||
fileprivate(set) var putPosition = Position.zero
|
||||
fileprivate(set) var screenCursor = Position.zero
|
||||
|
||||
var foreground = qDefaultForeground
|
||||
var background = qDefaultBackground
|
||||
@ -95,11 +95,11 @@ class Grid: CustomStringConvertible {
|
||||
var dark = false
|
||||
|
||||
var attrs: CellAttributes = CellAttributes(
|
||||
fontTrait: .None,
|
||||
fontTrait: .none,
|
||||
foreground: qDefaultForeground, background: qDefaultBackground, special: qDefaultSpecial
|
||||
)
|
||||
|
||||
private(set) var cells: [[Cell]] = []
|
||||
fileprivate(set) var cells: [[Cell]] = []
|
||||
|
||||
var hasData: Bool {
|
||||
return !self.cells.isEmpty
|
||||
@ -109,16 +109,16 @@ class Grid: CustomStringConvertible {
|
||||
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.size = size
|
||||
self.putPosition = Position.zero
|
||||
|
||||
let emptyCellAttrs = CellAttributes(fontTrait: .None,
|
||||
let emptyCellAttrs = CellAttributes(fontTrait: .none,
|
||||
foreground: self.foreground, background: self.background, special: self.special)
|
||||
|
||||
let emptyRow = Array(count: size.width, repeatedValue: Cell(string: " ", attrs: emptyCellAttrs))
|
||||
self.cells = Array(count: size.height, repeatedValue: emptyRow)
|
||||
let emptyRow = Array(repeating: Cell(string: " ", attrs: emptyCellAttrs), count: size.width)
|
||||
self.cells = Array(repeating: emptyRow, count: size.height)
|
||||
}
|
||||
|
||||
func clear() {
|
||||
@ -132,11 +132,11 @@ class Grid: CustomStringConvertible {
|
||||
)
|
||||
}
|
||||
|
||||
func setScrollRegion(region: Region) {
|
||||
func setScrollRegion(_ region: Region) {
|
||||
self.region = region
|
||||
}
|
||||
|
||||
func scroll(count: Int) {
|
||||
func scroll(_ count: Int) {
|
||||
var start, stop, step : Int
|
||||
if count > 0 {
|
||||
start = self.region.top;
|
||||
@ -150,8 +150,8 @@ class Grid: CustomStringConvertible {
|
||||
|
||||
// copy cell data
|
||||
let rangeWithinRow = self.region.left...self.region.right
|
||||
for i in start.stride(to: stop, by: step) {
|
||||
self.cells[i].replaceRange(rangeWithinRow, with: self.cells[i + count][rangeWithinRow])
|
||||
for i in stride(from: start, to: stop, by: step) {
|
||||
self.cells[i].replaceSubrange(rangeWithinRow, with: self.cells[i + count][rangeWithinRow])
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
func goto(position: Position) {
|
||||
func goto(_ position: Position) {
|
||||
self.putPosition = position
|
||||
}
|
||||
|
||||
func moveCursor(position: Position) {
|
||||
func moveCursor(_ position: Position) {
|
||||
self.screenCursor = position
|
||||
}
|
||||
|
||||
func put(string: String) {
|
||||
func put(_ string: String) {
|
||||
// FIXME: handle the following situation:
|
||||
// |abcde | <- type ㅎ
|
||||
// =>
|
||||
@ -187,18 +187,18 @@ class Grid: CustomStringConvertible {
|
||||
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...
|
||||
self.cells[self.putPosition.row][self.putPosition.column] = Cell(string: string, attrs: self.attrs, marked: true)
|
||||
self.putPosition.column += 1
|
||||
}
|
||||
|
||||
func unmarkCell(position: Position) {
|
||||
func unmarkCell(_ position: Position) {
|
||||
// NSLog("\(#function): \(position)")
|
||||
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
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ class Grid: CustomStringConvertible {
|
||||
}
|
||||
|
||||
var left = 0
|
||||
for idx in (0..<column).reverse() {
|
||||
for idx in (0..<column).reversed() {
|
||||
let cell = self.cells[row][idx]
|
||||
if cell.string == " " {
|
||||
left = idx + 1
|
||||
@ -235,14 +235,14 @@ class Grid: CustomStringConvertible {
|
||||
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 column = idx - row * self.size.width
|
||||
|
||||
return Position(row: row, column: column)
|
||||
}
|
||||
|
||||
func isCellEmpty(position: Position) -> Bool {
|
||||
func isCellEmpty(_ position: Position) -> Bool {
|
||||
guard self.isSane(position: position) else {
|
||||
return false
|
||||
}
|
||||
@ -254,44 +254,44 @@ class Grid: CustomStringConvertible {
|
||||
return false
|
||||
}
|
||||
|
||||
func isPreviousCellEmpty(position: Position) -> Bool {
|
||||
func isPreviousCellEmpty(_ position: Position) -> Bool {
|
||||
return self.isCellEmpty(self.previousCellPosition(position))
|
||||
}
|
||||
|
||||
func isNextCellEmpty(position: Position) -> Bool {
|
||||
func isNextCellEmpty(_ position: Position) -> Bool {
|
||||
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))
|
||||
}
|
||||
|
||||
func nextCellPosition(position: Position) -> Position {
|
||||
func nextCellPosition(_ position: Position) -> Position {
|
||||
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)
|
||||
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?
|
||||
guard self.hasData else {
|
||||
return
|
||||
}
|
||||
|
||||
let clearedAttrs = CellAttributes(fontTrait: .None,
|
||||
let clearedAttrs = CellAttributes(fontTrait: .none,
|
||||
foreground: self.foreground, background: self.background, special: self.special)
|
||||
|
||||
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 {
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class KeyUtils {
|
||||
NSF35FunctionKey: "F35",
|
||||
]
|
||||
|
||||
static func isSpecial(key key: String) -> Bool {
|
||||
static func isSpecial(key: String) -> Bool {
|
||||
guard key.characters.count == 1 else {
|
||||
return false
|
||||
}
|
||||
@ -70,7 +70,7 @@ class KeyUtils {
|
||||
return false
|
||||
}
|
||||
|
||||
static func namedKeyFrom(key key: String) -> String {
|
||||
static func namedKeyFrom(key: String) -> String {
|
||||
if let firstChar = key.utf16.first {
|
||||
if KeyUtils.specialKeys.keys.contains(Int(firstChar)) {
|
||||
return KeyUtils.specialKeys[Int(firstChar)]!
|
||||
|
@ -9,7 +9,7 @@ import Cocoa
|
||||
private struct RowRun: CustomStringConvertible {
|
||||
|
||||
let row: Int
|
||||
let range: Range<Int>
|
||||
let range: CountableClosedRange<Int>
|
||||
let attrs: CellAttributes
|
||||
|
||||
var description: String {
|
||||
@ -17,7 +17,7 @@ private struct RowRun: CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
public class NeoVimView: NSView, NSUserInterfaceValidations {
|
||||
open class NeoVimView: NSView, NSUserInterfaceValidations {
|
||||
|
||||
public struct Config {
|
||||
let useInteractiveZsh: Bool
|
||||
@ -27,29 +27,29 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
|
||||
}
|
||||
}
|
||||
|
||||
public static let minFontSize = CGFloat(4)
|
||||
public static let maxFontSize = CGFloat(128)
|
||||
public static let defaultFont = NSFont.userFixedPitchFontOfSize(13)!
|
||||
open static let minFontSize = CGFloat(4)
|
||||
open static let maxFontSize = CGFloat(128)
|
||||
open static let defaultFont = NSFont.userFixedPitchFont(ofSize: 13)!
|
||||
|
||||
public let uuid = NSUUID().UUIDString
|
||||
public weak var delegate: NeoVimViewDelegate?
|
||||
open let uuid = UUID().uuidString
|
||||
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 {
|
||||
self.drawer.usesLigatures = self.usesLigatures
|
||||
self.needsDisplay = true
|
||||
}
|
||||
}
|
||||
|
||||
public var font: NSFont {
|
||||
open var font: NSFont {
|
||||
get {
|
||||
return self._font
|
||||
}
|
||||
|
||||
set {
|
||||
guard newValue.fixedPitch else {
|
||||
guard newValue.isFixedPitch else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -68,59 +68,56 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
|
||||
}
|
||||
}
|
||||
|
||||
public var cwd: NSURL {
|
||||
open var cwd: URL {
|
||||
get {
|
||||
return NSURL(fileURLWithPath: self.agent.vimCommandOutput("silent pwd"))
|
||||
return URL(fileURLWithPath: self.agent.vimCommandOutput("silent pwd"))
|
||||
}
|
||||
|
||||
set {
|
||||
guard let path = newValue.path else {
|
||||
return
|
||||
}
|
||||
|
||||
let path = newValue.path
|
||||
let escapedCwd = self.agent.escapedFileName(path)
|
||||
self.agent.vimCommand("silent cd \(escapedCwd)")
|
||||
}
|
||||
}
|
||||
|
||||
private var _font = NeoVimView.defaultFont
|
||||
fileprivate var _font = NeoVimView.defaultFont
|
||||
|
||||
private let agent: NeoVimAgent
|
||||
private let drawer: TextDrawer
|
||||
private let fontManager = NSFontManager.sharedFontManager()
|
||||
private let pasteboard = NSPasteboard.generalPasteboard()
|
||||
fileprivate let agent: NeoVimAgent
|
||||
fileprivate let drawer: TextDrawer
|
||||
fileprivate let fontManager = NSFontManager.shared()
|
||||
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:
|
||||
/// 하 -> hanja popup -> insertText(하) -> attributedSubstring...() -> setMarkedText(下) -> ...
|
||||
/// We want to return "하" in attributedSubstring...()
|
||||
private var lastMarkedText: String?
|
||||
fileprivate var lastMarkedText: String?
|
||||
|
||||
private var markedPosition = Position.null
|
||||
private var keyDownDone = true
|
||||
fileprivate var markedPosition = Position.null
|
||||
fileprivate var keyDownDone = true
|
||||
|
||||
private var lastClickedCellPosition = Position.null
|
||||
fileprivate var lastClickedCellPosition = Position.null
|
||||
|
||||
private var xOffset = CGFloat(0)
|
||||
private var yOffset = CGFloat(0)
|
||||
private var cellSize = CGSize.zero
|
||||
private var descent = CGFloat(0)
|
||||
private var leading = CGFloat(0)
|
||||
fileprivate var xOffset = CGFloat(0)
|
||||
fileprivate var yOffset = CGFloat(0)
|
||||
fileprivate var cellSize = CGSize.zero
|
||||
fileprivate var descent = CGFloat(0)
|
||||
fileprivate var leading = CGFloat(0)
|
||||
|
||||
private let maxScrollDeltaX = 30
|
||||
private let maxScrollDeltaY = 30
|
||||
private let scrollLimiterX = CGFloat(20)
|
||||
private let scrollLimiterY = CGFloat(20)
|
||||
private var scrollGuardCounterX = 5
|
||||
private var scrollGuardCounterY = 5
|
||||
private let scrollGuardYield = 5
|
||||
fileprivate let maxScrollDeltaX = 30
|
||||
fileprivate let maxScrollDeltaY = 30
|
||||
fileprivate let scrollLimiterX = CGFloat(20)
|
||||
fileprivate let scrollLimiterY = CGFloat(20)
|
||||
fileprivate var scrollGuardCounterX = 5
|
||||
fileprivate var scrollGuardCounterY = 5
|
||||
fileprivate let scrollGuardYield = 5
|
||||
|
||||
private var isCurrentlyPinching = false
|
||||
private var pinchTargetScale = CGFloat(1)
|
||||
private var pinchImage = NSImage()
|
||||
fileprivate var isCurrentlyPinching = false
|
||||
fileprivate var pinchTargetScale = CGFloat(1)
|
||||
fileprivate var pinchImage = NSImage()
|
||||
|
||||
public init(frame rect: NSRect, config: Config) {
|
||||
self.drawer = TextDrawer(font: self._font, useLigatures: false)
|
||||
@ -142,7 +139,7 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
|
||||
DispatchUtils.gui {
|
||||
if noErrorDuringInitialization == false {
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .WarningAlertStyle
|
||||
alert.alertStyle = .warning
|
||||
alert.messageText = "Error during initialization"
|
||||
alert.informativeText = "There was an error during the initialization of NeoVim. "
|
||||
+ "Use :messages to view the error messages."
|
||||
@ -161,7 +158,7 @@ public class NeoVimView: NSView, NSUserInterfaceValidations {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@IBAction public func debug1(sender: AnyObject!) {
|
||||
@IBAction open func debug1(_ sender: AnyObject!) {
|
||||
NSLog("DEBUG 1 - Start")
|
||||
NSLog("\(self.agent.vimCommandOutput("silent echo $PATH"))")
|
||||
NSLog("\(self.agent.vimCommandOutput("silent pwd"))")
|
||||
@ -188,10 +185,10 @@ extension NeoVimView {
|
||||
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
|
||||
|
||||
urls.enumerate().forEach { (idx, url) in
|
||||
urls.enumerated().forEach { (idx, url) in
|
||||
if idx == 0 && currentBufferIsTransient {
|
||||
self.open(url, cmd: "e")
|
||||
} 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") }
|
||||
}
|
||||
|
||||
public func openInCurrentTab(url url: NSURL) {
|
||||
public func openInCurrentTab(url: URL) {
|
||||
self.open(url, cmd: "e")
|
||||
}
|
||||
|
||||
@ -216,11 +213,8 @@ extension NeoVimView {
|
||||
self.exec(command: "w")
|
||||
}
|
||||
|
||||
public func saveCurrentTab(url url: NSURL) {
|
||||
guard let path = url.path else {
|
||||
return
|
||||
}
|
||||
|
||||
public func saveCurrentTab(url: URL) {
|
||||
let path = url.path
|
||||
let escapedFileName = self.agent.escapedFileName(path)
|
||||
self.exec(command: "w \(escapedFileName)")
|
||||
}
|
||||
@ -240,7 +234,7 @@ extension NeoVimView {
|
||||
/// Does the following
|
||||
/// - `Mode.Normal`: `:command<CR>`
|
||||
/// - else: `:<Esc>:command<CR>`
|
||||
private func exec(command cmd: String) {
|
||||
fileprivate func exec(command cmd: String) {
|
||||
switch self.mode {
|
||||
case .Normal:
|
||||
self.agent.vimInput(":\(cmd)<CR>")
|
||||
@ -249,11 +243,8 @@ extension NeoVimView {
|
||||
}
|
||||
}
|
||||
|
||||
private func open(url: NSURL, cmd: String) {
|
||||
guard let path = url.path else {
|
||||
return
|
||||
}
|
||||
|
||||
fileprivate func open(_ url: URL, cmd: String) {
|
||||
let path = url.path
|
||||
let escapedFileName = self.agent.escapedFileName(path)
|
||||
self.exec(command: "\(cmd) \(escapedFileName)")
|
||||
}
|
||||
@ -262,7 +253,7 @@ extension NeoVimView {
|
||||
// MARK: - Resizing
|
||||
extension NeoVimView {
|
||||
|
||||
override public func setFrameSize(newSize: NSSize) {
|
||||
override open func setFrameSize(_ newSize: NSSize) {
|
||||
super.setFrameSize(newSize)
|
||||
|
||||
// initial resizing is done when grid has data
|
||||
@ -281,22 +272,22 @@ extension NeoVimView {
|
||||
self.resizeNeoVimUiTo(size: newSize)
|
||||
}
|
||||
|
||||
override public func viewDidEndLiveResize() {
|
||||
override open func viewDidEndLiveResize() {
|
||||
super.viewDidEndLiveResize()
|
||||
self.resizeNeoVimUiTo(size: self.bounds.size)
|
||||
}
|
||||
|
||||
private func resizeNeoVimUiTo(size size: CGSize) {
|
||||
fileprivate func resizeNeoVimUiTo(size: CGSize) {
|
||||
// NSLog("\(#function): \(size)")
|
||||
let discreteSize = self.discreteSize(size: size)
|
||||
|
||||
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.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)),
|
||||
height: Int(floor(size.height / self.cellSize.height)))
|
||||
}
|
||||
@ -305,42 +296,42 @@ extension NeoVimView {
|
||||
// MARK: - Drawing
|
||||
extension NeoVimView {
|
||||
|
||||
override public func drawRect(dirtyUnionRect: NSRect) {
|
||||
override open func draw(_ dirtyUnionRect: NSRect) {
|
||||
guard self.grid.hasData else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.inLiveResize {
|
||||
NSColor.windowBackgroundColor().set()
|
||||
NSColor.windowBackgroundColor.set()
|
||||
dirtyUnionRect.fill()
|
||||
|
||||
let boundsSize = self.bounds.size
|
||||
let discreteSize = self.discreteSize(size: boundsSize)
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
// NSLog("\(#function): \(dirtyUnionRect)")
|
||||
let context = NSGraphicsContext.currentContext()!.CGContext
|
||||
let context = NSGraphicsContext.current()!.cgContext
|
||||
|
||||
if self.isCurrentlyPinching {
|
||||
let boundsSize = self.bounds.size
|
||||
let targetSize = CGSize(width: boundsSize.width * 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
|
||||
}
|
||||
|
||||
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
|
||||
CGContextSetTextDrawingMode(context, .Fill);
|
||||
context.textMatrix = CGAffineTransform.identity;
|
||||
context.setTextDrawingMode(.fill);
|
||||
|
||||
let dirtyRects = self.rectsBeingDrawn()
|
||||
// NSLog("\(dirtyRects)")
|
||||
@ -349,7 +340,7 @@ extension NeoVimView {
|
||||
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
|
||||
// redrawn. => FIXME: probably we have to consider this also when drawing further down, ie when the range starts
|
||||
// with '0'...
|
||||
@ -368,13 +359,13 @@ extension NeoVimView {
|
||||
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) }
|
||||
|
||||
self.drawer.drawString(string,
|
||||
positions: UnsafeMutablePointer(glyphPositions), positionsCount: positions.count,
|
||||
self.drawer.draw(string,
|
||||
positions: UnsafeMutablePointer(mutating: glyphPositions), positionsCount: positions.count,
|
||||
highlightAttrs: rowFrag.attrs,
|
||||
context: context)
|
||||
}
|
||||
|
||||
private func cursorRegion() -> Region {
|
||||
fileprivate func cursorRegion() -> Region {
|
||||
let cursorPosition = self.mode == .Cmdline ? self.grid.putPosition : self.grid.screenCursor
|
||||
// NSLog("\(#function): \(cursorPosition)")
|
||||
|
||||
@ -393,7 +384,7 @@ extension NeoVimView {
|
||||
return cursorRegion
|
||||
}
|
||||
|
||||
private func drawCursor(context context: CGContext) {
|
||||
fileprivate func drawCursor(context: CGContext) {
|
||||
// FIXME: for now do some rudimentary cursor drawing
|
||||
let cursorRegion = self.cursorRegion()
|
||||
let cursorRow = cursorRegion.top
|
||||
@ -409,7 +400,7 @@ extension NeoVimView {
|
||||
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()
|
||||
// NSColor(calibratedRed: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0).set()
|
||||
let backgroundRect = CGRect(
|
||||
@ -419,9 +410,9 @@ extension NeoVimView {
|
||||
backgroundRect.fill()
|
||||
}
|
||||
|
||||
private func rowRunIntersecting(rects rects: [CGRect]) -> [RowRun] {
|
||||
fileprivate func rowRunIntersecting(rects: [CGRect]) -> [RowRun] {
|
||||
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
|
||||
// time being we ignore them; probably not necessary to optimize them away.
|
||||
let region = self.regionFor(rect: rect)
|
||||
@ -431,17 +422,17 @@ extension NeoVimView {
|
||||
.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
|
||||
.map { (row) -> [RowRun] in
|
||||
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) ]
|
||||
columnRange.forEach { idx in
|
||||
if rowCells[idx].attrs == result.last!.attrs {
|
||||
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 {
|
||||
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.
|
||||
}
|
||||
|
||||
private func regionFor(rect rect: CGRect) -> Region {
|
||||
fileprivate func regionFor(rect: CGRect) -> Region {
|
||||
let cellWidth = self.cellSize.width
|
||||
let cellHeight = self.cellSize.height
|
||||
|
||||
@ -472,22 +463,22 @@ extension NeoVimView {
|
||||
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)
|
||||
}
|
||||
|
||||
private func pointInViewFor(row row: Int, column: Int) -> CGPoint {
|
||||
fileprivate func pointInViewFor(row: Int, column: Int) -> CGPoint {
|
||||
return CGPoint(
|
||||
x: self.xOffset + CGFloat(column) * self.cellSize.width,
|
||||
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)
|
||||
}
|
||||
|
||||
private func regionRectFor(region region: Region) -> CGRect {
|
||||
fileprivate func regionRectFor(region: Region) -> CGRect {
|
||||
let top = CGFloat(region.top)
|
||||
let bottom = CGFloat(region.bottom)
|
||||
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)>"
|
||||
}
|
||||
|
||||
private func vimPlainString(string: String) -> String {
|
||||
return string.stringByReplacingOccurrencesOfString("<", withString: self.wrapNamedKeys("lt"))
|
||||
fileprivate func vimPlainString(_ string: String) -> String {
|
||||
return string.replacingOccurrences(of: "<", with: self.wrapNamedKeys("lt"))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - NSUserInterfaceValidationsProtocol
|
||||
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 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 canSelectAll = self.mode == .Insert || self.mode == .Replace || self.mode == .Normal || self.mode == .Visual
|
||||
|
||||
switch item.action() {
|
||||
case NSSelectorFromString("undo:"), NSSelectorFromString("redo:"):
|
||||
guard let action = item.action else {
|
||||
return true
|
||||
}
|
||||
|
||||
switch action {
|
||||
case Selector("undo:"), Selector("redo:"):
|
||||
return canUndoOrRedo
|
||||
case NSSelectorFromString("copy:"), NSSelectorFromString("cut:"):
|
||||
case Selector("copy:"), Selector("cut:"):
|
||||
return canCopyOrCut
|
||||
case NSSelectorFromString("paste:"):
|
||||
case Selector("paste:"):
|
||||
return canPaste
|
||||
case NSSelectorFromString("delete:"):
|
||||
case Selector("delete:"):
|
||||
return canDelete
|
||||
case NSSelectorFromString("selectAll:"):
|
||||
case Selector("selectAll:"):
|
||||
return canSelectAll
|
||||
default:
|
||||
return true
|
||||
@ -546,7 +541,7 @@ extension NeoVimView {
|
||||
// MARK: - Edit Menu Items
|
||||
extension NeoVimView {
|
||||
|
||||
@IBAction func undo(sender: AnyObject!) {
|
||||
@IBAction func undo(_ sender: AnyObject!) {
|
||||
switch self.mode {
|
||||
case .Insert, .Replace:
|
||||
self.agent.vimInput("<Esc>ui")
|
||||
@ -557,7 +552,7 @@ extension NeoVimView {
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func redo(sender: AnyObject!) {
|
||||
@IBAction func redo(_ sender: AnyObject!) {
|
||||
switch self.mode {
|
||||
case .Insert, .Replace:
|
||||
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 {
|
||||
case .Visual, .Normal:
|
||||
self.agent.vimInput("\"+d")
|
||||
@ -577,7 +572,7 @@ extension NeoVimView {
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func copy(sender: AnyObject!) {
|
||||
@IBAction func copy(_ sender: AnyObject!) {
|
||||
switch self.mode {
|
||||
case .Visual, .Normal:
|
||||
self.agent.vimInput("\"+y")
|
||||
@ -586,8 +581,8 @@ extension NeoVimView {
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func paste(sender: AnyObject!) {
|
||||
guard let content = self.pasteboard.stringForType(NSPasteboardTypeString) else {
|
||||
@IBAction func paste(_ sender: AnyObject!) {
|
||||
guard let content = self.pasteboard.string(forType: NSPasteboardTypeString) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -599,7 +594,7 @@ extension NeoVimView {
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func delete(sender: AnyObject!) {
|
||||
@IBAction func delete(_ sender: AnyObject!) {
|
||||
switch self.mode {
|
||||
case .Normal, .Visual:
|
||||
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 {
|
||||
case .Insert, .Visual:
|
||||
self.agent.vimInput("<Esc>ggVG")
|
||||
@ -621,10 +616,10 @@ extension NeoVimView {
|
||||
// MARK: - Key Events
|
||||
extension NeoVimView: NSTextInputClient {
|
||||
|
||||
override public func keyDown(event: NSEvent) {
|
||||
override open func keyDown(with event: NSEvent) {
|
||||
self.keyDownDone = false
|
||||
|
||||
let context = NSTextInputContext.currentInputContext()!
|
||||
let context = NSTextInputContext.current()!
|
||||
let cocoaHandledEvent = context.handleEvent(event)
|
||||
if self.keyDownDone && cocoaHandledEvent {
|
||||
return
|
||||
@ -633,10 +628,10 @@ extension NeoVimView: NSTextInputClient {
|
||||
// NSLog("\(#function): \(event)")
|
||||
|
||||
let modifierFlags = event.modifierFlags
|
||||
let capslock = modifierFlags.contains(.AlphaShiftKeyMask)
|
||||
let shift = modifierFlags.contains(.ShiftKeyMask)
|
||||
let capslock = modifierFlags.contains(.capsLock)
|
||||
let shift = modifierFlags.contains(.shift)
|
||||
let chars = event.characters!
|
||||
let charsIgnoringModifiers = shift || capslock ? event.charactersIgnoringModifiers!.lowercaseString
|
||||
let charsIgnoringModifiers = shift || capslock ? event.charactersIgnoringModifiers!.lowercased()
|
||||
: event.charactersIgnoringModifiers!
|
||||
|
||||
if KeyUtils.isSpecial(key: charsIgnoringModifiers) {
|
||||
@ -656,7 +651,7 @@ extension NeoVimView: NSTextInputClient {
|
||||
self.keyDownDone = true
|
||||
}
|
||||
|
||||
public func insertText(aString: AnyObject, replacementRange: NSRange) {
|
||||
public func insertText(_ aString: Any, replacementRange: NSRange) {
|
||||
// NSLog("\(#function): \(replacementRange): '\(aString)'")
|
||||
|
||||
switch aString {
|
||||
@ -675,14 +670,14 @@ extension NeoVimView: NSTextInputClient {
|
||||
self.keyDownDone = true
|
||||
}
|
||||
|
||||
public override func doCommandBySelector(aSelector: Selector) {
|
||||
open override func doCommand(by aSelector: Selector) {
|
||||
// NSLog("\(#function): \(aSelector)");
|
||||
|
||||
// FIXME: handle when ㅎ -> delete
|
||||
|
||||
if self.respondsToSelector(aSelector) {
|
||||
if self.responds(to: aSelector) {
|
||||
Swift.print("\(#function): calling \(aSelector)")
|
||||
self.performSelector(aSelector, withObject: self)
|
||||
self.perform(aSelector, with: self)
|
||||
self.keyDownDone = true
|
||||
return
|
||||
}
|
||||
@ -691,7 +686,7 @@ extension NeoVimView: NSTextInputClient {
|
||||
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 {
|
||||
self.markedPosition = self.grid.putPosition
|
||||
}
|
||||
@ -707,7 +702,7 @@ extension NeoVimView: NSTextInputClient {
|
||||
case let attributedString as NSAttributedString:
|
||||
self.markedText = attributedString.string
|
||||
default:
|
||||
self.markedText = String(aString) // should not occur
|
||||
self.markedText = String(describing: aString) // should not occur
|
||||
}
|
||||
|
||||
// NSLog("\(#function): \(self.markedText), \(selectedRange), \(replacementRange)")
|
||||
@ -723,7 +718,7 @@ extension NeoVimView: NSTextInputClient {
|
||||
self.keyDownDone = true
|
||||
|
||||
// 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
|
||||
@ -761,7 +756,7 @@ extension NeoVimView: NSTextInputClient {
|
||||
|
||||
// FIXME: take into account the "return nil"-case
|
||||
// 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])")
|
||||
if aRange.location == NSNotFound {
|
||||
// NSLog("\(#function): range not found: returning nil")
|
||||
@ -789,28 +784,28 @@ extension NeoVimView: NSTextInputClient {
|
||||
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)
|
||||
|
||||
// NSLog("\(#function): \(aRange),\(actualRange[0]) -> \(position.row):\(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!
|
||||
}
|
||||
|
||||
public func characterIndexForPoint(aPoint: NSPoint) -> Int {
|
||||
public func characterIndex(for aPoint: NSPoint) -> Int {
|
||||
// NSLog("\(#function): \(aPoint)")
|
||||
return 1
|
||||
}
|
||||
|
||||
private func vimModifierFlags(modifierFlags: NSEventModifierFlags) -> String? {
|
||||
fileprivate func vimModifierFlags(_ modifierFlags: NSEventModifierFlags) -> String? {
|
||||
var result = ""
|
||||
|
||||
let control = modifierFlags.contains(.ControlKeyMask)
|
||||
let option = modifierFlags.contains(.AlternateKeyMask)
|
||||
let command = modifierFlags.contains(.CommandKeyMask)
|
||||
let control = modifierFlags.contains(.control)
|
||||
let option = modifierFlags.contains(.option)
|
||||
let command = modifierFlags.contains(.command)
|
||||
|
||||
if control {
|
||||
result += "C-"
|
||||
@ -835,7 +830,7 @@ extension NeoVimView: NSTextInputClient {
|
||||
// MARK: - Gesture Events
|
||||
extension NeoVimView {
|
||||
|
||||
override public func magnifyWithEvent(event: NSEvent) {
|
||||
override open func magnify(with event: NSEvent) {
|
||||
let factor = 1 + event.magnification
|
||||
let pinchTargetScale = self.pinchTargetScale * factor
|
||||
let resultingFontSize = round(pinchTargetScale * self._font.pointSize)
|
||||
@ -844,18 +839,18 @@ extension NeoVimView {
|
||||
}
|
||||
|
||||
switch event.phase {
|
||||
case NSEventPhase.Began:
|
||||
let pinchImageRep = self.bitmapImageRepForCachingDisplayInRect(self.bounds)!
|
||||
self.cacheDisplayInRect(self.bounds, toBitmapImageRep: pinchImageRep)
|
||||
case NSEventPhase.began:
|
||||
let pinchImageRep = self.bitmapImageRepForCachingDisplay(in: self.bounds)!
|
||||
self.cacheDisplay(in: self.bounds, to: pinchImageRep)
|
||||
self.pinchImage = NSImage()
|
||||
self.pinchImage.addRepresentation(pinchImageRep)
|
||||
|
||||
self.isCurrentlyPinching = true
|
||||
self.needsDisplay = true
|
||||
|
||||
case NSEventPhase.Ended, NSEventPhase.Cancelled:
|
||||
case NSEventPhase.ended, NSEventPhase.cancelled:
|
||||
self.isCurrentlyPinching = false
|
||||
self.font = self.fontManager.convertFont(self._font, toSize: resultingFontSize)
|
||||
self.font = self.fontManager.convert(self._font, toSize: resultingFontSize)
|
||||
self.pinchTargetScale = 1
|
||||
|
||||
default:
|
||||
@ -867,19 +862,19 @@ extension NeoVimView {
|
||||
// MARK: - Mouse Events
|
||||
extension NeoVimView {
|
||||
|
||||
override public func mouseDown(event: NSEvent) {
|
||||
override open func mouseDown(with event: NSEvent) {
|
||||
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")
|
||||
}
|
||||
|
||||
override public func mouseDragged(event: NSEvent) {
|
||||
override open func mouseDragged(with event: NSEvent) {
|
||||
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)
|
||||
if deltaX == 0 && deltaY == 0 {
|
||||
return
|
||||
@ -908,8 +903,8 @@ extension NeoVimView {
|
||||
}
|
||||
}
|
||||
|
||||
private func cellPositionFor(event event: NSEvent) -> Position {
|
||||
let location = self.convertPoint(event.locationInWindow, fromView: nil)
|
||||
fileprivate func cellPositionFor(event: NSEvent) -> Position {
|
||||
let location = self.convert(event.locationInWindow, from: nil)
|
||||
let row = Int((location.x - self.xOffset) / self.cellSize.width)
|
||||
let column = Int((self.bounds.size.height - location.y - self.yOffset) / self.cellSize.height)
|
||||
|
||||
@ -918,7 +913,7 @@ extension NeoVimView {
|
||||
return cellPosition
|
||||
}
|
||||
|
||||
private func mouse(event event: NSEvent, vimName: String) {
|
||||
fileprivate func mouse(event: NSEvent, vimName: String) {
|
||||
let cellPosition = self.cellPositionFor(event: event)
|
||||
guard self.shouldFireVimInputFor(event: event, newCellPosition: cellPosition) else {
|
||||
return
|
||||
@ -938,9 +933,9 @@ extension NeoVimView {
|
||||
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
|
||||
guard type == .LeftMouseDragged || type == .RightMouseDragged || type == .OtherMouseDragged else {
|
||||
guard type == .leftMouseDragged || type == .rightMouseDragged || type == .otherMouseDragged else {
|
||||
self.lastClickedCellPosition = newCellPosition
|
||||
return true
|
||||
}
|
||||
@ -953,7 +948,7 @@ extension NeoVimView {
|
||||
return true
|
||||
}
|
||||
|
||||
private func vimClickCountFrom(event event: NSEvent) -> String {
|
||||
fileprivate func vimClickCountFrom(event: NSEvent) -> String {
|
||||
let clickCount = event.clickCount
|
||||
|
||||
guard 2 <= clickCount && clickCount <= 4 else {
|
||||
@ -961,14 +956,14 @@ extension NeoVimView {
|
||||
}
|
||||
|
||||
switch event.type {
|
||||
case .LeftMouseDown, .LeftMouseUp, .RightMouseDown, .RightMouseUp:
|
||||
case .leftMouseDown, .leftMouseUp, .rightMouseDown, .rightMouseUp:
|
||||
return "\(clickCount)-"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
private func vimScrollEventNamesFor(deltaX deltaX: CGFloat, deltaY: CGFloat) -> (String, String) {
|
||||
fileprivate func vimScrollEventNamesFor(deltaX: CGFloat, deltaY: CGFloat) -> (String, String) {
|
||||
let typeY: String
|
||||
if deltaY > 0 {
|
||||
typeY = "ScrollWheelUp"
|
||||
@ -986,7 +981,7 @@ extension NeoVimView {
|
||||
return (typeX, typeY)
|
||||
}
|
||||
|
||||
private func vimScrollInputFor(deltaX deltaX: CGFloat, deltaY: CGFloat,
|
||||
fileprivate func vimScrollInputFor(deltaX: CGFloat, deltaY: CGFloat,
|
||||
modifierFlags: NSEventModifierFlags,
|
||||
cellPosition: Position) -> (String, String)
|
||||
{
|
||||
@ -1006,7 +1001,7 @@ extension NeoVimView {
|
||||
return (resultX, resultY)
|
||||
}
|
||||
|
||||
private func throttleScrollX(absDelta absDeltaX: CGFloat, vimInput: String) {
|
||||
fileprivate func throttleScrollX(absDelta absDeltaX: CGFloat, vimInput: String) {
|
||||
if absDeltaX == 0 {
|
||||
self.scrollGuardCounterX = self.scrollGuardYield - 1
|
||||
} 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 {
|
||||
self.scrollGuardCounterY = self.scrollGuardYield - 1
|
||||
} else if absDeltaY <= 2 {
|
||||
@ -1042,7 +1037,7 @@ extension NeoVimView {
|
||||
// MARK: - NeoVimUiBridgeProtocol
|
||||
extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
|
||||
public func resizeToWidth(width: Int32, height: Int32) {
|
||||
public func resize(toWidth width: Int32, height: Int32) {
|
||||
DispatchUtils.gui {
|
||||
// NSLog("\(#function): \(width):\(height)")
|
||||
self.grid.resize(Size(width: Int(width), height: Int(height)))
|
||||
@ -1067,11 +1062,11 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
height: self.cellSize.height
|
||||
)
|
||||
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 {
|
||||
// NSLog("\(#function): \(position), \(screenCursor)")
|
||||
|
||||
@ -1118,12 +1113,12 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
public func mouseOff() {
|
||||
}
|
||||
|
||||
public func modeChange(mode: Mode) {
|
||||
public func modeChange(_ mode: Mode) {
|
||||
// NSLog("mode changed to: %02x", mode.rawValue)
|
||||
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 {
|
||||
let region = Region(top: Int(top), bottom: Int(bottom), left: Int(left), right: Int(right))
|
||||
self.grid.setScrollRegion(region)
|
||||
@ -1131,20 +1126,20 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public func scroll(count: Int32) {
|
||||
public func scroll(_ count: Int32) {
|
||||
DispatchUtils.gui {
|
||||
self.grid.scroll(Int(count))
|
||||
self.setNeedsDisplay(region: self.grid.region)
|
||||
}
|
||||
}
|
||||
|
||||
public func highlightSet(attrs: CellAttributes) {
|
||||
public func highlightSet(_ attrs: CellAttributes) {
|
||||
DispatchUtils.gui {
|
||||
self.grid.attrs = attrs
|
||||
}
|
||||
}
|
||||
|
||||
public func put(string: String, screenCursor: Position) {
|
||||
public func put(_ string: String, screenCursor: Position) {
|
||||
DispatchUtils.gui {
|
||||
let curPos = self.grid.putPosition
|
||||
// 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 {
|
||||
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 {
|
||||
let position = Position(row: Int(row), column: Int(column))
|
||||
|
||||
@ -1208,7 +1203,7 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
// NSLog("\(#function)")
|
||||
}
|
||||
|
||||
public func updateForeground(fg: Int32, dark: Bool) {
|
||||
public func updateForeground(_ fg: Int32, dark: Bool) {
|
||||
DispatchUtils.gui {
|
||||
self.grid.dark = dark
|
||||
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 {
|
||||
self.grid.dark = dark
|
||||
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)))")
|
||||
}
|
||||
}
|
||||
|
||||
public func updateSpecial(sp: Int32, dark: Bool) {
|
||||
public func updateSpecial(_ sp: Int32, dark: Bool) {
|
||||
DispatchUtils.gui {
|
||||
self.grid.dark = dark
|
||||
self.grid.special = UInt32(bitPattern: sp)
|
||||
@ -1235,16 +1230,16 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
public func suspend() {
|
||||
}
|
||||
|
||||
public func setTitle(title: String) {
|
||||
public func setTitle(_ title: String) {
|
||||
DispatchUtils.gui {
|
||||
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 {
|
||||
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 {
|
||||
// When the cursor is in the command line, then we need this...
|
||||
self.setNeedsDisplay(cellPosition: self.grid.previousCellPosition(curPos))
|
||||
@ -1276,11 +1271,11 @@ extension NeoVimView: NeoVimUiBridgeProtocol {
|
||||
self.grid.moveCursor(screenCursor)
|
||||
}
|
||||
|
||||
private func setNeedsDisplay(region region: Region) {
|
||||
self.setNeedsDisplayInRect(self.regionRectFor(region: region))
|
||||
fileprivate func setNeedsDisplay(region: Region) {
|
||||
self.setNeedsDisplay(self.regionRectFor(region: region))
|
||||
}
|
||||
|
||||
private func setNeedsDisplay(cellPosition position: Position) {
|
||||
fileprivate func setNeedsDisplay(cellPosition position: Position) {
|
||||
self.setNeedsDisplay(position: 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)
|
||||
}
|
||||
|
||||
private func setNeedsDisplay(row row: Int, column: Int) {
|
||||
fileprivate func setNeedsDisplay(row: Int, column: Int) {
|
||||
// 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)
|
||||
if self.grid.isNextCellEmpty(position) {
|
||||
self.setNeedsDisplay(position: self.grid.nextCellPosition(position))
|
||||
|
@ -8,8 +8,8 @@ import Cocoa
|
||||
// See http://stackoverflow.com/a/24104371 for class
|
||||
public protocol NeoVimViewDelegate: class {
|
||||
|
||||
func setTitle(title: String)
|
||||
func setDirtyStatus(dirty: Bool)
|
||||
func setTitle(_ title: String)
|
||||
func setDirtyStatus(_ dirty: Bool)
|
||||
func cwdChanged()
|
||||
func neoVimStopped()
|
||||
}
|
||||
|
@ -11,38 +11,38 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
@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()
|
||||
}
|
||||
|
||||
@IBAction func toggleButtons(sender: AnyObject!) {
|
||||
@IBAction func toggleButtons(_ sender: AnyObject!) {
|
||||
workspace.toggleToolButtons()
|
||||
}
|
||||
|
||||
func applicationDidFinishLaunching(aNotification: NSNotification) {
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
let contentView = self.window.contentView!
|
||||
let workspace = Workspace(mainView: self.view(NSColor.yellowColor()))
|
||||
let workspace = Workspace(mainView: self.view(NSColor.yellow))
|
||||
self.workspace = workspace
|
||||
|
||||
contentView.addSubview(workspace)
|
||||
workspace.autoPinEdgesToSuperviewEdges()
|
||||
|
||||
workspace.append(tool: WorkspaceTool(title: "Top-1", view: self.view(NSColor.whiteColor())), location: .top)
|
||||
workspace.append(tool: WorkspaceTool(title: "Right-1", view: self.view(NSColor.whiteColor())), location: .right)
|
||||
workspace.append(tool: WorkspaceTool(title: "Right-2", view: self.view(NSColor.greenColor())), location: .right)
|
||||
workspace.append(tool: WorkspaceTool(title: "Left-1", view: self.view(NSColor.whiteColor())), location: .left)
|
||||
workspace.append(tool: WorkspaceTool(title: "Left-2", view: self.view(NSColor.greenColor())), location: .left)
|
||||
workspace.append(tool: WorkspaceTool(title: "Left-3", view: self.view(NSColor.magentaColor())), location: .left)
|
||||
workspace.append(tool: WorkspaceTool(title: "Bottom-1", view: self.view(NSColor.whiteColor())), location: .bottom)
|
||||
workspace.append(tool: WorkspaceTool(title: "Bottom-2", view: self.view(NSColor.greenColor())), location: .bottom)
|
||||
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.white)), 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.white)), 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.magenta)), location: .left)
|
||||
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.green)), location: .bottom)
|
||||
}
|
||||
|
||||
private func view(color: NSColor) -> NSView {
|
||||
fileprivate func view(_ color: NSColor) -> NSView {
|
||||
let view = NSView(forAutoLayout: ())
|
||||
view.wantsLayer = true
|
||||
view.layer?.backgroundColor = color.CGColor
|
||||
view.layer?.backgroundColor = color.cgColor
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
@ -819,18 +819,20 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0730;
|
||||
LastUpgradeCheck = 0800;
|
||||
ORGANIZATIONNAME = "Tae Won Ha";
|
||||
TargetAttributes = {
|
||||
4B2A2BF61D0351810074CE9A = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = H96Q2NKTQH;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
4B56F28F1D29903F00C1F92E = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
};
|
||||
4B64239E1D8EFE7500FC78C8 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
4B854A191D31447C00E08DE1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
@ -838,9 +840,11 @@
|
||||
4BEBA5041CFF374B00673FDF = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = H96Q2NKTQH;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
4BEBA5131CFF374B00673FDF = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -1143,6 +1147,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1166,6 +1171,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR.SwiftNeoVim;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -1212,6 +1218,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1228,6 +1235,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -1295,8 +1303,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
@ -1342,8 +1352,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
@ -1370,10 +1382,10 @@
|
||||
4BEBA51E1CFF374B00673FDF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/Mac",
|
||||
@ -1383,16 +1395,17 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR;
|
||||
PRODUCT_NAME = VimR;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
4BEBA51F1CFF374B00673FDF /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/Mac",
|
||||
@ -1402,6 +1415,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR;
|
||||
PRODUCT_NAME = VimR;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -1417,6 +1431,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimRTests;
|
||||
PRODUCT_NAME = VimRTests;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1432,6 +1447,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimRTests;
|
||||
PRODUCT_NAME = VimRTests;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -25,9 +25,9 @@ class AdvancedPrefPane: PrefPane {
|
||||
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) {
|
||||
self.data = initialData
|
||||
@ -59,20 +59,20 @@ class AdvancedPrefPane: PrefPane {
|
||||
self.addSubview(useInteractiveZsh)
|
||||
self.addSubview(useInteractiveZshInfo)
|
||||
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Top, withInset: 18)
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
useInteractiveZsh.autoPinEdge(.Top, toEdge: .Bottom, ofView: paneTitle, withOffset: 18)
|
||||
useInteractiveZsh.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
useInteractiveZsh.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
|
||||
useInteractiveZsh.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
|
||||
useInteractiveZshInfo.autoPinEdge(.Top, toEdge: .Bottom, ofView: useInteractiveZsh, withOffset: 5)
|
||||
useInteractiveZshInfo.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
useInteractiveZshInfo.autoPinEdge(.top, to: .bottom, of: useInteractiveZsh, withOffset: 5)
|
||||
useInteractiveZshInfo.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
|
||||
useInteractiveZsh.boolState = self.data.useInteractiveZsh
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PrefData }
|
||||
.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.publish(event: data)
|
||||
}
|
||||
|
||||
private func updateViews(newData newData: AdvancedPrefData) {
|
||||
fileprivate func updateViews(newData: AdvancedPrefData) {
|
||||
self.useInteractiveZshCheckbox.boolState = newData.useInteractiveZsh
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ class AdvancedPrefPane: PrefPane {
|
||||
// MARK: - Actions
|
||||
extension AdvancedPrefPane {
|
||||
|
||||
func useInteractiveZshAction(sender: NSButton) {
|
||||
func useInteractiveZshAction(_ sender: NSButton) {
|
||||
self.set(data: AdvancedPrefData(useInteractiveZsh: self.useInteractiveZshCheckbox.boolState))
|
||||
}
|
||||
}
|
||||
|
@ -23,24 +23,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
@IBOutlet var debugMenu: NSMenuItem!
|
||||
|
||||
private let disposeBag = DisposeBag()
|
||||
fileprivate let disposeBag = DisposeBag()
|
||||
|
||||
private let changeSubject = PublishSubject<Any>()
|
||||
private let changeSink: Observable<Any>
|
||||
fileprivate let changeSubject = PublishSubject<Any>()
|
||||
fileprivate let changeSink: Observable<Any>
|
||||
|
||||
private let actionSubject = PublishSubject<Any>()
|
||||
private let actionSink: Observable<Any>
|
||||
fileprivate let actionSubject = PublishSubject<Any>()
|
||||
fileprivate let actionSink: Observable<Any>
|
||||
|
||||
private let prefStore: PrefStore
|
||||
fileprivate let prefStore: PrefStore
|
||||
|
||||
private let mainWindowManager: MainWindowManager
|
||||
private let openQuicklyWindowManager: OpenQuicklyWindowManager
|
||||
private let prefWindowComponent: PrefWindowComponent
|
||||
fileprivate let mainWindowManager: MainWindowManager
|
||||
fileprivate let openQuicklyWindowManager: OpenQuicklyWindowManager
|
||||
fileprivate let prefWindowComponent: PrefWindowComponent
|
||||
|
||||
private let fileItemService = FileItemService()
|
||||
fileprivate let fileItemService = FileItemService()
|
||||
|
||||
private var quitWhenAllWindowsAreClosed = false
|
||||
private var launching = true
|
||||
fileprivate var quitWhenAllWindowsAreClosed = false
|
||||
fileprivate var launching = true
|
||||
|
||||
override init() {
|
||||
self.actionSink = self.actionSubject.asObservable()
|
||||
@ -103,17 +103,17 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
// MARK: - NSApplicationDelegate
|
||||
extension AppDelegate {
|
||||
|
||||
func applicationWillFinishLaunching(_: NSNotification) {
|
||||
func applicationWillFinishLaunching(_: Notification) {
|
||||
self.launching = true
|
||||
|
||||
let appleEventManager = NSAppleEventManager.sharedAppleEventManager()
|
||||
let appleEventManager = NSAppleEventManager.shared()
|
||||
appleEventManager.setEventHandler(self,
|
||||
andSelector: #selector(AppDelegate.handleGetUrlEvent(_:withReplyEvent:)),
|
||||
forEventClass: UInt32(kInternetEventClass),
|
||||
andEventID: UInt32(kAEGetURL))
|
||||
}
|
||||
|
||||
func applicationDidFinishLaunching(_: NSNotification) {
|
||||
func applicationDidFinishLaunching(_: Notification) {
|
||||
// let testView = InputTestView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
|
||||
// self.window.contentView?.addSubview(testView)
|
||||
// self.window.makeFirstResponder(testView)
|
||||
@ -121,11 +121,11 @@ extension AppDelegate {
|
||||
self.launching = false
|
||||
|
||||
#if DEBUG
|
||||
self.debugMenu.hidden = false
|
||||
self.debugMenu.isHidden = false
|
||||
#endif
|
||||
}
|
||||
|
||||
func applicationOpenUntitledFile(sender: NSApplication) -> Bool {
|
||||
func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool {
|
||||
if self.launching {
|
||||
if self.prefStore.data.general.openNewWindowWhenLaunching {
|
||||
self.newDocument(self)
|
||||
@ -141,50 +141,50 @@ extension AppDelegate {
|
||||
return false
|
||||
}
|
||||
|
||||
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
|
||||
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplicationTerminateReply {
|
||||
if self.mainWindowManager.hasDirtyWindows() {
|
||||
let alert = NSAlert()
|
||||
alert.addButtonWithTitle("Cancel")
|
||||
alert.addButtonWithTitle("Discard and Quit")
|
||||
alert.addButton(withTitle: "Cancel")
|
||||
alert.addButton(withTitle: "Discard and Quit")
|
||||
alert.messageText = "There are windows with unsaved buffers!"
|
||||
alert.alertStyle = .WarningAlertStyle
|
||||
alert.alertStyle = .warning
|
||||
|
||||
if alert.runModal() == NSAlertSecondButtonReturn {
|
||||
self.quitWhenAllWindowsAreClosed = true
|
||||
self.mainWindowManager.closeAllWindowsWithoutSaving()
|
||||
}
|
||||
|
||||
return .TerminateCancel
|
||||
return .terminateCancel
|
||||
}
|
||||
|
||||
if self.mainWindowManager.hasMainWindow() {
|
||||
self.quitWhenAllWindowsAreClosed = true
|
||||
self.mainWindowManager.closeAllWindows()
|
||||
|
||||
return .TerminateCancel
|
||||
return .terminateCancel
|
||||
}
|
||||
|
||||
// There are no open main window, then just quit.
|
||||
return .TerminateNow
|
||||
return .terminateNow
|
||||
}
|
||||
|
||||
// For drag & dropping files on the App icon.
|
||||
func application(sender: NSApplication, openFiles filenames: [String]) {
|
||||
let urls = filenames.map { NSURL(fileURLWithPath: $0) }
|
||||
func application(_ sender: NSApplication, openFiles filenames: [String]) {
|
||||
let urls = filenames.map { URL(fileURLWithPath: $0) }
|
||||
self.mainWindowManager.newMainWindow(urls: urls)
|
||||
sender.replyToOpenOrPrint(.Success)
|
||||
sender.reply(toOpenOrPrint: .success)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - AppleScript
|
||||
extension AppDelegate {
|
||||
|
||||
func handleGetUrlEvent(event: NSAppleEventDescriptor, withReplyEvent: NSAppleEventDescriptor) {
|
||||
guard let urlString = event.paramDescriptorForKeyword(UInt32(keyDirectObject))?.stringValue else {
|
||||
func handleGetUrlEvent(_ event: NSAppleEventDescriptor, withReplyEvent: NSAppleEventDescriptor) {
|
||||
guard let urlString = event.paramDescriptor(forKeyword: UInt32(keyDirectObject))?.stringValue else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = NSURL(string: urlString) else {
|
||||
guard let url = URL(string: urlString) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -200,16 +200,16 @@ extension AppDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
let queryParams = url.query?.componentsSeparatedByString("&")
|
||||
let queryParams = url.query?.components(separatedBy: "&")
|
||||
let urls = queryParams?
|
||||
.filter { $0.hasPrefix(filePrefix) }
|
||||
.flatMap { $0.without(prefix: filePrefix).stringByRemovingPercentEncoding }
|
||||
.map { NSURL(fileURLWithPath: $0) } ?? []
|
||||
.flatMap { $0.without(prefix: filePrefix).removingPercentEncoding }
|
||||
.map { URL(fileURLWithPath: $0) } ?? []
|
||||
let cwd = queryParams?
|
||||
.filter { $0.hasPrefix(cwdPrefix) }
|
||||
.flatMap { $0.without(prefix: cwdPrefix).stringByRemovingPercentEncoding }
|
||||
.map { NSURL(fileURLWithPath: $0) }
|
||||
.first ?? NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
|
||||
.flatMap { $0.without(prefix: cwdPrefix).removingPercentEncoding }
|
||||
.map { URL(fileURLWithPath: $0) }
|
||||
.first ?? URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
|
||||
|
||||
switch action {
|
||||
case .activate, .newWindow:
|
||||
@ -228,24 +228,24 @@ extension AppDelegate {
|
||||
// MARK: - IBActions
|
||||
extension AppDelegate {
|
||||
|
||||
@IBAction func showPrefWindow(sender: AnyObject!) {
|
||||
@IBAction func showPrefWindow(_ sender: AnyObject!) {
|
||||
self.prefWindowComponent.show()
|
||||
}
|
||||
|
||||
@IBAction func newDocument(sender: AnyObject!) {
|
||||
@IBAction func newDocument(_ sender: AnyObject!) {
|
||||
self.mainWindowManager.newMainWindow()
|
||||
}
|
||||
|
||||
// Invoked when no main window is open.
|
||||
@IBAction func openDocument(sender: AnyObject!) {
|
||||
@IBAction func openDocument(_ sender: AnyObject!) {
|
||||
let panel = NSOpenPanel()
|
||||
panel.canChooseDirectories = true
|
||||
panel.beginWithCompletionHandler { result in
|
||||
panel.begin { result in
|
||||
guard result == NSFileHandlingPanelOKButton else {
|
||||
return
|
||||
}
|
||||
|
||||
self.mainWindowManager.newMainWindow(urls: panel.URLs)
|
||||
self.mainWindowManager.newMainWindow(urls: panel.urls)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,26 +21,26 @@ extension NSButton {
|
||||
extension NSAttributedString {
|
||||
|
||||
func draw(at point: CGPoint, angle: CGFloat) {
|
||||
let translation = NSAffineTransform()
|
||||
let rotation = NSAffineTransform()
|
||||
var translation = AffineTransform.identity
|
||||
var rotation = AffineTransform.identity
|
||||
|
||||
translation.translateXBy(point.x, yBy: point.y)
|
||||
rotation.rotateByRadians(angle)
|
||||
translation.translate(x: point.x, y: point.y)
|
||||
rotation.rotate(byRadians: angle)
|
||||
|
||||
translation.concat()
|
||||
rotation.concat()
|
||||
(translation as NSAffineTransform).concat()
|
||||
(rotation as NSAffineTransform).concat()
|
||||
|
||||
self.drawAtPoint(CGPoint.zero)
|
||||
self.draw(at: CGPoint.zero)
|
||||
|
||||
rotation.invert()
|
||||
translation.invert()
|
||||
|
||||
rotation.concat()
|
||||
translation.concat()
|
||||
(rotation as NSAffineTransform).concat()
|
||||
(translation as NSAffineTransform).concat()
|
||||
}
|
||||
|
||||
// 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 range = NSRange(location: 0, length: attrString.length)
|
||||
|
||||
@ -49,9 +49,9 @@ extension NSAttributedString {
|
||||
attrString.addAttribute(NSFontAttributeName, value: font!, 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,
|
||||
value: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), range: range)
|
||||
value: NSNumber(value: NSUnderlineStyle.styleSingle.rawValue as Int), range: range)
|
||||
attrString.endEditing()
|
||||
|
||||
return attrString
|
||||
@ -79,22 +79,22 @@ extension NSTableView {
|
||||
let tableView = NSTableView(frame: CGRect.zero)
|
||||
|
||||
let column = NSTableColumn(identifier: "name")
|
||||
column.editable = false
|
||||
column.isEditable = false
|
||||
|
||||
tableView.addTableColumn(column)
|
||||
tableView.rowSizeStyle = .Default
|
||||
tableView.rowSizeStyle = .default
|
||||
tableView.sizeLastColumnToFit()
|
||||
tableView.allowsEmptySelection = false
|
||||
tableView.allowsMultipleSelection = false
|
||||
tableView.headerView = nil
|
||||
tableView.focusRingType = .None
|
||||
tableView.focusRingType = .none
|
||||
|
||||
return tableView
|
||||
}
|
||||
|
||||
static func standardSourceListTableView() -> NSTableView {
|
||||
let tableView = self.standardTableView()
|
||||
tableView.selectionHighlightStyle = .SourceList
|
||||
tableView.selectionHighlightStyle = .sourceList
|
||||
|
||||
return tableView
|
||||
}
|
||||
@ -109,7 +109,7 @@ extension NSScrollView {
|
||||
scrollView.hasVerticalScroller = true
|
||||
scrollView.hasHorizontalScroller = true
|
||||
scrollView.autohidesScrollers = true
|
||||
scrollView.borderType = .BezelBorder
|
||||
scrollView.borderType = .bezelBorder
|
||||
|
||||
return scrollView
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ struct AppearancePrefData: Equatable {
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -26,21 +26,21 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
|
||||
return true
|
||||
}
|
||||
|
||||
private var data: AppearancePrefData {
|
||||
fileprivate var data: AppearancePrefData {
|
||||
didSet {
|
||||
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]
|
||||
private let sizeCombo = NSComboBox(forAutoLayout: ())
|
||||
private let fontPopup = NSPopUpButton(frame: CGRect.zero, pullsDown: false)
|
||||
private let ligatureCheckbox = NSButton(forAutoLayout: ())
|
||||
private let previewArea = NSTextView(frame: CGRect.zero)
|
||||
fileprivate let sizes = [9, 10, 11, 12, 13, 14, 16, 18, 24, 36, 48, 64]
|
||||
fileprivate let sizeCombo = NSComboBox(forAutoLayout: ())
|
||||
fileprivate let fontPopup = NSPopUpButton(frame: CGRect.zero, pullsDown: false)
|
||||
fileprivate let ligatureCheckbox = NSButton(forAutoLayout: ())
|
||||
fileprivate let previewArea = NSTextView(frame: CGRect.zero)
|
||||
|
||||
private let exampleText =
|
||||
fileprivate let exampleText =
|
||||
"abcdefghijklmnopqrstuvwxyz\n" +
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" +
|
||||
"0123456789\n" +
|
||||
@ -59,12 +59,12 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func set(data data: AppearancePrefData) {
|
||||
fileprivate func set(data: AppearancePrefData) {
|
||||
self.data = data
|
||||
self.publish(event: data)
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PrefData }
|
||||
.map { ($0 as! PrefData).appearance }
|
||||
@ -83,14 +83,14 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
|
||||
fontPopup.translatesAutoresizingMaskIntoConstraints = false
|
||||
fontPopup.target = self
|
||||
fontPopup.action = #selector(AppearancePrefPane.fontPopupAction)
|
||||
fontPopup.addItemsWithTitles(self.fontManager.availableFontNamesWithTraits(.FixedPitchFontMask)!)
|
||||
fontPopup.addItems(withTitles: self.fontManager.availableFontNames(with: .fixedPitchFontMask)!)
|
||||
|
||||
let sizeCombo = self.sizeCombo
|
||||
sizeCombo.setDelegate(self)
|
||||
sizeCombo.delegate = self
|
||||
sizeCombo.target = self
|
||||
sizeCombo.action = #selector(AppearancePrefPane.sizeComboBoxDidEnter(_:))
|
||||
self.sizes.forEach { string in
|
||||
sizeCombo.addItemWithObjectValue(string)
|
||||
sizeCombo.addItem(withObjectValue: string)
|
||||
}
|
||||
|
||||
let ligatureCheckbox = self.ligatureCheckbox
|
||||
@ -99,23 +99,23 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
|
||||
action: #selector(AppearancePrefPane.usesLigaturesAction(_:)))
|
||||
|
||||
let previewArea = self.previewArea
|
||||
previewArea.editable = true
|
||||
previewArea.maxSize = CGSize(width: CGFloat.max, height: CGFloat.max)
|
||||
previewArea.verticallyResizable = true
|
||||
previewArea.horizontallyResizable = true
|
||||
previewArea.isEditable = true
|
||||
previewArea.maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
|
||||
previewArea.isVerticallyResizable = true
|
||||
previewArea.isHorizontallyResizable = true
|
||||
previewArea.textContainer?.heightTracksTextView = false
|
||||
previewArea.textContainer?.widthTracksTextView = false
|
||||
previewArea.autoresizingMask = [ .ViewWidthSizable, .ViewHeightSizable]
|
||||
previewArea.textContainer?.containerSize = CGSize.init(width: CGFloat.max, height: CGFloat.max)
|
||||
previewArea.autoresizingMask = [ .viewWidthSizable, .viewHeightSizable]
|
||||
previewArea.textContainer?.containerSize = CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
|
||||
previewArea.layoutManager?.replaceTextStorage(NSTextStorage(string: self.exampleText))
|
||||
previewArea.richText = false
|
||||
previewArea.isRichText = false
|
||||
previewArea.turnOffLigatures(self)
|
||||
|
||||
let previewScrollView = NSScrollView(forAutoLayout: ())
|
||||
previewScrollView.hasVerticalScroller = true
|
||||
previewScrollView.hasHorizontalScroller = true
|
||||
previewScrollView.autohidesScrollers = true
|
||||
previewScrollView.borderType = .BezelBorder
|
||||
previewScrollView.borderType = .bezelBorder
|
||||
previewScrollView.documentView = previewArea
|
||||
|
||||
self.addSubview(paneTitle)
|
||||
@ -126,31 +126,31 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
|
||||
self.addSubview(ligatureCheckbox)
|
||||
self.addSubview(previewScrollView)
|
||||
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Top, withInset: 18)
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
|
||||
fontTitle.autoPinEdge(.Left, toEdge: .Left, ofView: paneTitle)
|
||||
fontTitle.autoAlignAxis(.Baseline, toSameAxisOfView: fontPopup)
|
||||
fontTitle.autoPinEdge(.left, to: .left, of: paneTitle)
|
||||
fontTitle.autoAlignAxis(.baseline, toSameAxisOf: fontPopup)
|
||||
|
||||
fontPopup.autoPinEdge(.Top, toEdge: .Bottom, ofView: paneTitle, withOffset: 18)
|
||||
fontPopup.autoPinEdge(.Left, toEdge: .Right, ofView: fontTitle, withOffset: 5)
|
||||
fontPopup.autoSetDimension(.Width, toSize: 240)
|
||||
fontPopup.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
|
||||
fontPopup.autoPinEdge(.left, to: .right, of: fontTitle, withOffset: 5)
|
||||
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...
|
||||
sizeCombo.autoAlignAxis(.Horizontal, toSameAxisOfView: fontPopup)
|
||||
sizeCombo.autoPinEdge(.Left, toEdge: .Right, ofView: fontPopup, withOffset: 5)
|
||||
sizeCombo.autoAlignAxis(.horizontal, toSameAxisOf: fontPopup)
|
||||
sizeCombo.autoPinEdge(.left, to: .right, of: fontPopup, withOffset: 5)
|
||||
|
||||
ligatureCheckbox.autoPinEdge(.Top, toEdge: .Bottom, ofView: sizeCombo, withOffset: 18)
|
||||
ligatureCheckbox.autoPinEdge(.Left, toEdge: .Right, ofView: fontTitle, withOffset: 5)
|
||||
ligatureCheckbox.autoPinEdge(.top, to: .bottom, of: sizeCombo, withOffset: 18)
|
||||
ligatureCheckbox.autoPinEdge(.left, to: .right, of: fontTitle, withOffset: 5)
|
||||
|
||||
previewScrollView.autoSetDimension(.Height, toSize: 200, relation: .GreaterThanOrEqual)
|
||||
previewScrollView.autoPinEdge(.Top, toEdge: .Bottom, ofView: ligatureCheckbox, withOffset: 18)
|
||||
previewScrollView.autoPinEdgeToSuperviewEdge(.Right, withInset: 18)
|
||||
previewScrollView.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 18)
|
||||
previewScrollView.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
previewScrollView.autoSetDimension(.height, toSize: 200, relation: .greaterThanOrEqual)
|
||||
previewScrollView.autoPinEdge(.top, to: .bottom, of: ligatureCheckbox, withOffset: 18)
|
||||
previewScrollView.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
|
||||
previewScrollView.autoPinEdge(toSuperviewEdge: .bottom, 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.ligatureCheckbox.state = self.data.editorUsesLigatures ? NSOnState : NSOffState
|
||||
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
|
||||
|
||||
self.fontPopup.selectItemWithTitle(newFont.fontName)
|
||||
self.fontPopup.selectItem(withTitle: newFont.fontName)
|
||||
self.sizeCombo.stringValue = String(Int(newFont.pointSize))
|
||||
self.ligatureCheckbox.boolState = newData.editorUsesLigatures
|
||||
self.previewArea.font = newData.editorFont
|
||||
@ -180,16 +180,16 @@ class AppearancePrefPane: PrefPane, NSComboBoxDelegate, NSControlTextEditingDele
|
||||
// MARK: - Actions
|
||||
extension AppearancePrefPane {
|
||||
|
||||
func usesLigaturesAction(sender: NSButton) {
|
||||
func usesLigaturesAction(_ sender: NSButton) {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
guard selectedItem != self.data.editorFont.fontName else {
|
||||
guard selectedItem.title != self.data.editorFont.fontName else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -200,25 +200,25 @@ extension AppearancePrefPane {
|
||||
self.set(data: AppearancePrefData(editorFont: newFont, editorUsesLigatures: self.data.editorUsesLigatures))
|
||||
}
|
||||
|
||||
func comboBoxSelectionDidChange(notification: NSNotification) {
|
||||
guard notification.object! === self.sizeCombo else {
|
||||
func comboBoxSelectionDidChange(_ notification: Notification) {
|
||||
guard (notification.object as! NSComboBox) === self.sizeCombo else {
|
||||
return
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
func sizeComboBoxDidEnter(sender: AnyObject!) {
|
||||
func sizeComboBoxDidEnter(_ sender: AnyObject!) {
|
||||
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))
|
||||
}
|
||||
|
||||
private func cappedFontSize(size: Int) -> CGFloat {
|
||||
fileprivate func cappedFontSize(_ size: Int) -> CGFloat {
|
||||
guard size >= 4 else {
|
||||
return 13
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class Application: NSApplication {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@IBAction override func showHelp(sender: AnyObject!) {
|
||||
NSWorkspace.sharedWorkspace().openURL(NSURL(string: "https://github.com/qvacua/vimr/wiki")!)
|
||||
@IBAction override func showHelp(_ sender: Any!) {
|
||||
NSWorkspace.shared().open(URL(string: "https://github.com/qvacua/vimr/wiki")!)
|
||||
}
|
||||
}
|
||||
|
@ -34,11 +34,11 @@ class StandardFlow: Flow {
|
||||
self.subject.onCompleted()
|
||||
}
|
||||
|
||||
func subscription(source source: Observable<Any>) -> Disposable {
|
||||
func subscription(source: Observable<Any>) -> Disposable {
|
||||
preconditionFailure("Please override")
|
||||
}
|
||||
|
||||
func publish(event event: Any) {
|
||||
func publish(event: Any) {
|
||||
self.subject.onNext(event)
|
||||
}
|
||||
}
|
||||
@ -69,11 +69,11 @@ class StandardComponent: NSObject, Component {
|
||||
preconditionFailure("Please override")
|
||||
}
|
||||
|
||||
func subscription(source source: Observable<Any>) -> Disposable {
|
||||
func subscription(source: Observable<Any>) -> Disposable {
|
||||
preconditionFailure("Please override")
|
||||
}
|
||||
|
||||
func publish(event event: Any) {
|
||||
func publish(event: Any) {
|
||||
self.subject.onNext(event)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import Foundation
|
||||
|
||||
class FileItem : CustomStringConvertible {
|
||||
|
||||
let url: NSURL
|
||||
let url: URL
|
||||
let dir: Bool
|
||||
let hidden: Bool
|
||||
let package: Bool
|
||||
@ -28,18 +28,18 @@ class FileItem : CustomStringConvertible {
|
||||
+ "children=\(self.children.count)>"
|
||||
}
|
||||
|
||||
init(_ url: NSURL) {
|
||||
init(_ url: URL) {
|
||||
self.url = url
|
||||
self.dir = url.dir
|
||||
self.hidden = url.hidden
|
||||
self.package = url.package
|
||||
}
|
||||
|
||||
func removeChild(withUrl url: NSURL) {
|
||||
guard let idx = self.children.indexOf({ $0.url == url }) else {
|
||||
func removeChild(withUrl url: URL) {
|
||||
guard let idx = self.children.index(where: { $0.url == url }) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.children.removeAtIndex(idx)
|
||||
self.children.remove(at: idx)
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class FileItemIgnorePattern: Hashable, CustomStringConvertible {
|
||||
let folderPattern: Bool
|
||||
let pattern: String
|
||||
|
||||
private let patternAsFileSysRep: UnsafeMutablePointer<Int8>
|
||||
fileprivate let patternAsFileSysRep: UnsafeMutablePointer<Int8>
|
||||
|
||||
init(pattern: String) {
|
||||
self.pattern = pattern
|
||||
@ -31,14 +31,14 @@ class FileItemIgnorePattern: Hashable, CustomStringConvertible {
|
||||
let fileSysRep = (pattern as NSString).fileSystemRepresentation
|
||||
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)
|
||||
self.patternAsFileSysRep[len] = 0
|
||||
}
|
||||
|
||||
deinit {
|
||||
let len = Int(strlen(self.patternAsFileSysRep))
|
||||
self.patternAsFileSysRep.dealloc(len + 1)
|
||||
self.patternAsFileSysRep.deallocate(capacity: len + 1)
|
||||
}
|
||||
|
||||
func match(absolutePath path: String) -> Bool {
|
||||
|
@ -15,31 +15,31 @@ class Token: Equatable {}
|
||||
|
||||
class FileItemService {
|
||||
|
||||
private(set) var ignorePatterns: Set<FileItemIgnorePattern> = [] {
|
||||
fileprivate(set) var ignorePatterns: Set<FileItemIgnorePattern> = [] {
|
||||
didSet {
|
||||
self.ignoreToken = Token()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
private let emitChunkSize = 1000
|
||||
fileprivate let emitChunkSize = 1000
|
||||
|
||||
private let scanDispatchQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
|
||||
private let monitorDispatchQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
|
||||
fileprivate let scanDispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)
|
||||
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)
|
||||
private var monitors = [NSURL: FileSystemEventMonitor]()
|
||||
private var monitorCounter = [NSURL: Int]()
|
||||
fileprivate let fileSystemEventsLatency = Double(2)
|
||||
fileprivate var monitors = [URL: FileSystemEventMonitor]()
|
||||
fileprivate var monitorCounter = [URL: Int]()
|
||||
|
||||
private let workspace = NSWorkspace.sharedWorkspace()
|
||||
private let iconsCache = NSCache()
|
||||
fileprivate let workspace = NSWorkspace.shared()
|
||||
fileprivate let iconsCache = NSCache<NSURL, NSImage>()
|
||||
|
||||
private var spinLock = OS_SPINLOCK_INIT
|
||||
fileprivate var spinLock = OS_SPINLOCK_INIT
|
||||
|
||||
init() {
|
||||
self.iconsCache.countLimit = 2000
|
||||
@ -50,22 +50,17 @@ class FileItemService {
|
||||
self.ignorePatterns = patterns
|
||||
}
|
||||
|
||||
func icon(forUrl url: NSURL) -> NSImage? {
|
||||
guard let path = url.path else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let icon = workspace.iconForFile(path)
|
||||
func icon(forUrl url: URL) -> NSImage? {
|
||||
let path = url.path
|
||||
let icon = workspace.icon(forFile: path)
|
||||
icon.size = CGSize(width: 16, height: 16)
|
||||
self.iconsCache.setObject(icon, forKey: url)
|
||||
self.iconsCache.setObject(icon, forKey: url as NSURL)
|
||||
|
||||
return icon
|
||||
}
|
||||
|
||||
func monitor(url url: NSURL) {
|
||||
guard let path = url.path else {
|
||||
return
|
||||
}
|
||||
func monitor(url: URL) {
|
||||
let path = url.path
|
||||
|
||||
// FIXME: Handle EonilFileSystemEventFlag.RootChanged, ie watchRoot: true
|
||||
let monitor = FileSystemEventMonitor(pathsToWatch: [path],
|
||||
@ -73,7 +68,7 @@ class FileItemService {
|
||||
watchRoot: false,
|
||||
queue: self.monitorDispatchQueue)
|
||||
{ [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)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -95,8 +90,8 @@ class FileItemService {
|
||||
if newCounter > 0 {
|
||||
self.monitorCounter[url] = newCounter
|
||||
} else {
|
||||
self.monitorCounter.removeValueForKey(url)
|
||||
self.monitors.removeValueForKey(url)
|
||||
self.monitorCounter.removeValue(forKey: url)
|
||||
self.monitors.removeValue(forKey: url)
|
||||
|
||||
// TODO Remove cached items more aggressively?
|
||||
let hasRelations = self.monitors.keys.reduce(false) { (result, monitoredUrl) in
|
||||
@ -111,12 +106,12 @@ class FileItemService {
|
||||
}
|
||||
}
|
||||
|
||||
private func parentFileItem(ofUrl url: NSURL) -> FileItem {
|
||||
return self.fileItem(forPathComponents: Array(url.pathComponents!.dropLast()))!
|
||||
fileprivate func parentFileItem(ofUrl url: URL) -> FileItem {
|
||||
return self.fileItem(forPathComponents: Array(url.pathComponents.dropLast()))!
|
||||
}
|
||||
|
||||
func flatFileItems(ofUrl url: NSURL) -> Observable<[FileItem]> {
|
||||
guard url.fileURL else {
|
||||
func flatFileItems(ofUrl url: URL) -> Observable<[FileItem]> {
|
||||
guard url.isFileURL else {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
@ -124,16 +119,13 @@ class FileItemService {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
guard let pathComponents = url.pathComponents else {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
let pathComponents = url.pathComponents
|
||||
return Observable.create { [unowned self] observer in
|
||||
let cancel = AnonymousDisposable {
|
||||
// noop
|
||||
}
|
||||
|
||||
dispatch_async(self.scanDispatchQueue) { [unowned self] in
|
||||
self.scanDispatchQueue.async { [unowned self] in
|
||||
guard let targetItem = self.fileItem(forPathComponents: pathComponents) else {
|
||||
observer.onCompleted()
|
||||
return
|
||||
@ -166,7 +158,7 @@ class FileItemService {
|
||||
item.ignoreToken = self.ignoreToken
|
||||
item.ignore = false
|
||||
|
||||
let path = item.url.path!
|
||||
let path = item.url.path
|
||||
for pattern in self.ignorePatterns {
|
||||
// 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`
|
||||
@ -197,11 +189,8 @@ class FileItemService {
|
||||
}
|
||||
}
|
||||
|
||||
private func fileItem(forUrl url: NSURL) -> FileItem? {
|
||||
guard let pathComponents = url.pathComponents else {
|
||||
return nil
|
||||
}
|
||||
|
||||
fileprivate func fileItem(forUrl url: URL) -> FileItem? {
|
||||
let pathComponents = url.pathComponents
|
||||
return self.fileItem(forPathComponents: pathComponents)
|
||||
}
|
||||
|
||||
@ -209,7 +198,7 @@ class FileItemService {
|
||||
/// instantiates the intermediate `FileItem`s.
|
||||
///
|
||||
/// - 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
|
||||
guard let parent = resultItem else {
|
||||
return nil
|
||||
@ -230,11 +219,11 @@ class FileItemService {
|
||||
/// - parent: parent of the child.
|
||||
/// - create: whether to create the child `FileItem` if it's not scanned yet.
|
||||
/// - 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 }
|
||||
|
||||
if filteredChildren.isEmpty && create {
|
||||
let childUrl = parent.url.URLByAppendingPathComponent(name)
|
||||
let childUrl = parent.url.appendingPathComponent(name)
|
||||
|
||||
guard FileUtils.fileExistsAtUrl(childUrl) else {
|
||||
return nil
|
||||
@ -249,7 +238,7 @@ class FileItemService {
|
||||
return filteredChildren.first
|
||||
}
|
||||
|
||||
private func scanChildren(item: FileItem) {
|
||||
fileprivate func scanChildren(_ item: FileItem) {
|
||||
let children = FileUtils.directDescendants(item.url).map(FileItem.init)
|
||||
self.syncAddChildren { item.children = children }
|
||||
|
||||
@ -257,7 +246,7 @@ class FileItemService {
|
||||
item.needsScanChildren = false
|
||||
}
|
||||
|
||||
private func syncAddChildren(@noescape fn: () -> Void) {
|
||||
fileprivate func syncAddChildren(_ fn: () -> Void) {
|
||||
OSSpinLockLock(&self.spinLock)
|
||||
fn()
|
||||
OSSpinLockUnlock(&self.spinLock)
|
||||
|
@ -7,23 +7,23 @@ import Foundation
|
||||
|
||||
class FileUtils {
|
||||
|
||||
private static let keysToGet = [
|
||||
NSURLIsDirectoryKey,
|
||||
NSURLIsHiddenKey,
|
||||
NSURLIsAliasFileKey,
|
||||
NSURLIsSymbolicLinkKey
|
||||
fileprivate static let keysToGet = [
|
||||
URLResourceKey.isDirectoryKey,
|
||||
URLResourceKey.isHiddenKey,
|
||||
URLResourceKey.isAliasFileKey,
|
||||
URLResourceKey.isSymbolicLinkKey
|
||||
]
|
||||
|
||||
private static let scanOptions: NSDirectoryEnumerationOptions = [
|
||||
NSDirectoryEnumerationOptions.SkipsSubdirectoryDescendants,
|
||||
NSDirectoryEnumerationOptions.SkipsPackageDescendants
|
||||
fileprivate static let scanOptions: FileManager.DirectoryEnumerationOptions = [
|
||||
FileManager.DirectoryEnumerationOptions.skipsSubdirectoryDescendants,
|
||||
FileManager.DirectoryEnumerationOptions.skipsPackageDescendants
|
||||
]
|
||||
|
||||
private static let fileManager = NSFileManager.defaultManager()
|
||||
fileprivate static let fileManager = FileManager.default
|
||||
|
||||
static func directDescendants(url: NSURL) -> [NSURL] {
|
||||
guard let childUrls = try? self.fileManager.contentsOfDirectoryAtURL(
|
||||
url, includingPropertiesForKeys: self.keysToGet, options: self.scanOptions
|
||||
static func directDescendants(_ url: URL) -> [URL] {
|
||||
guard let childUrls = try? self.fileManager.contentsOfDirectory(
|
||||
at: url, includingPropertiesForKeys: self.keysToGet, options: self.scanOptions
|
||||
) else {
|
||||
// FIXME error handling
|
||||
return []
|
||||
@ -32,33 +32,30 @@ class FileUtils {
|
||||
return childUrls
|
||||
}
|
||||
|
||||
static func fileExistsAtUrl(url: NSURL) -> Bool {
|
||||
guard url.fileURL else {
|
||||
static func fileExistsAtUrl(_ url: URL) -> Bool {
|
||||
guard url.isFileURL else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let path = url.path else {
|
||||
return false
|
||||
let path = url.path
|
||||
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 {
|
||||
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 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] })
|
||||
if minPathComponents.count == 1 {
|
||||
return possibleParent.dir ? possibleParent : possibleParent.URLByDeletingLastPathComponent!
|
||||
return possibleParent.dir ? possibleParent : possibleParent.deletingLastPathComponent()
|
||||
}
|
||||
|
||||
return possibleParent.URLByDeletingLastPathComponent!
|
||||
return possibleParent.deletingLastPathComponent()
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,15 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NSURL {
|
||||
extension URL {
|
||||
|
||||
func parent(ofUrl url: NSURL) -> Bool {
|
||||
guard self.fileURL && url.fileURL else {
|
||||
func parent(ofUrl url: URL) -> Bool {
|
||||
guard self.isFileURL && url.isFileURL else {
|
||||
return false
|
||||
}
|
||||
|
||||
let myPathComps = self.pathComponents!
|
||||
let targetPathComps = url.pathComponents!
|
||||
let myPathComps = self.pathComponents
|
||||
let targetPathComps = url.pathComponents
|
||||
|
||||
guard targetPathComps.count > myPathComps.count else {
|
||||
return false
|
||||
@ -29,11 +29,11 @@ extension NSURL {
|
||||
///
|
||||
/// - parameters:
|
||||
/// - key: The `key`-parameter of `NSURL.getResourceValue`.
|
||||
func resourceValue(key: String) -> Bool {
|
||||
func resourceValue(_ key: String) -> Bool {
|
||||
var rsrc: AnyObject?
|
||||
|
||||
do {
|
||||
try self.getResourceValue(&rsrc, forKey: key)
|
||||
try (self as NSURL).getResourceValue(&rsrc, forKey: URLResourceKey(rawValue: key))
|
||||
} catch {
|
||||
// FIXME error handling
|
||||
print("\(#function): \(self) -> ERROR while getting \(key)")
|
||||
@ -48,14 +48,14 @@ extension NSURL {
|
||||
}
|
||||
|
||||
var dir: Bool {
|
||||
return self.resourceValue(NSURLIsDirectoryKey)
|
||||
return self.resourceValue(URLResourceKey.isDirectoryKey.rawValue)
|
||||
}
|
||||
|
||||
var hidden: Bool {
|
||||
return self.resourceValue(NSURLIsHiddenKey)
|
||||
return self.resourceValue(URLResourceKey.isHiddenKey.rawValue)
|
||||
}
|
||||
|
||||
var package: Bool {
|
||||
return self.resourceValue(NSURLIsPackageKey)
|
||||
return self.resourceValue(URLResourceKey.isPackageKey.rawValue)
|
||||
}
|
||||
}
|
||||
|
@ -30,11 +30,11 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
return true
|
||||
}
|
||||
|
||||
private var data: GeneralPrefData
|
||||
fileprivate var data: GeneralPrefData
|
||||
|
||||
private let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ())
|
||||
private let openOnReactivationCheckbox = NSButton(forAutoLayout: ())
|
||||
private let ignoreField = NSTextField(forAutoLayout: ())
|
||||
fileprivate let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ())
|
||||
fileprivate let openOnReactivationCheckbox = NSButton(forAutoLayout: ())
|
||||
fileprivate let ignoreField = NSTextField(forAutoLayout: ())
|
||||
|
||||
init(source: Observable<Any>, initialData: GeneralPrefData) {
|
||||
self.data = initialData
|
||||
@ -63,8 +63,8 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
|
||||
let ignoreListTitle = self.titleTextField(title: "Files To Ignore:")
|
||||
let ignoreField = self.ignoreField
|
||||
NSNotificationCenter.defaultCenter()
|
||||
.addObserverForName(NSControlTextDidEndEditingNotification, object: ignoreField, queue: nil) { [unowned self] _ in
|
||||
NotificationCenter.default
|
||||
.addObserver(forName: NSNotification.Name.NSControlTextDidEndEditing, object: ignoreField, queue: nil) { [unowned self] _ in
|
||||
self.ignorePatternsAction()
|
||||
}
|
||||
let ignoreInfo = self.infoTextField(text: "")
|
||||
@ -73,9 +73,9 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
let cliToolTitle = self.titleTextField(title: "CLI Tool:")
|
||||
let cliToolButton = NSButton(forAutoLayout: ())
|
||||
cliToolButton.title = "Copy 'vimr' CLI Tool..."
|
||||
cliToolButton.bezelStyle = .RoundedBezelStyle
|
||||
cliToolButton.bordered = true
|
||||
cliToolButton.setButtonType(.MomentaryPushInButton)
|
||||
cliToolButton.bezelStyle = .rounded
|
||||
cliToolButton.isBordered = true
|
||||
cliToolButton.setButtonType(.momentaryPushIn)
|
||||
cliToolButton.target = self
|
||||
cliToolButton.action = #selector(GeneralPrefPane.copyCliTool(_:))
|
||||
let cliToolInfo = self.infoTextField(
|
||||
@ -95,50 +95,50 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
self.addSubview(cliToolButton)
|
||||
self.addSubview(cliToolInfo)
|
||||
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Top, withInset: 18)
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
paneTitle.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
openUntitledWindowTitle.autoAlignAxis(.Baseline, toSameAxisOfView: whenLaunching, withOffset: 0)
|
||||
openUntitledWindowTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18)
|
||||
openUntitledWindowTitle.autoAlignAxis(.baseline, toSameAxisOf: whenLaunching, withOffset: 0)
|
||||
openUntitledWindowTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
|
||||
whenLaunching.autoPinEdge(.Top, toEdge: .Bottom, ofView: paneTitle, withOffset: 18)
|
||||
whenLaunching.autoPinEdge(.Left, toEdge: .Right, ofView: openUntitledWindowTitle, withOffset: 5)
|
||||
whenLaunching.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
whenLaunching.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
|
||||
whenLaunching.autoPinEdge(.left, to: .right, of: openUntitledWindowTitle, withOffset: 5)
|
||||
whenLaunching.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
onReactivation.autoPinEdge(.Top, toEdge: .Bottom, ofView: whenLaunching, withOffset: 5)
|
||||
onReactivation.autoPinEdge(.Left, toEdge: .Left, ofView: whenLaunching)
|
||||
onReactivation.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
onReactivation.autoPinEdge(.top, to: .bottom, of: whenLaunching, withOffset: 5)
|
||||
onReactivation.autoPinEdge(.left, to: .left, of: whenLaunching)
|
||||
onReactivation.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
ignoreListTitle.autoAlignAxis(.Baseline, toSameAxisOfView: ignoreField)
|
||||
ignoreListTitle.autoPinEdge(.Right, toEdge: .Right, ofView: openUntitledWindowTitle)
|
||||
ignoreListTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
ignoreListTitle.autoAlignAxis(.baseline, toSameAxisOf: ignoreField)
|
||||
ignoreListTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
|
||||
ignoreListTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
ignoreField.autoPinEdge(.Top, toEdge: .Bottom, ofView: onReactivation, withOffset: 18)
|
||||
ignoreField.autoPinEdgeToSuperviewEdge(.Right, withInset: 18)
|
||||
ignoreField.autoPinEdge(.Left, toEdge: .Right, ofView: ignoreListTitle, withOffset: 5)
|
||||
ignoreField.autoPinEdge(.top, to: .bottom, of: onReactivation, withOffset: 18)
|
||||
ignoreField.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
|
||||
ignoreField.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
|
||||
|
||||
ignoreInfo.autoPinEdge(.Top, toEdge: .Bottom, ofView: ignoreField, withOffset: 5)
|
||||
ignoreInfo.autoPinEdgeToSuperviewEdge(.Right, withInset: 18)
|
||||
ignoreInfo.autoPinEdge(.Left, toEdge: .Right, ofView: ignoreListTitle, withOffset: 5)
|
||||
ignoreInfo.autoPinEdge(.top, to: .bottom, of: ignoreField, withOffset: 5)
|
||||
ignoreInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
|
||||
ignoreInfo.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
|
||||
|
||||
cliToolTitle.autoAlignAxis(.Baseline, toSameAxisOfView: cliToolButton)
|
||||
cliToolTitle.autoPinEdgeToSuperviewEdge(.Left, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
cliToolTitle.autoPinEdge(.Right, toEdge: .Right, ofView: openUntitledWindowTitle)
|
||||
cliToolTitle.autoAlignAxis(.baseline, toSameAxisOf: cliToolButton)
|
||||
cliToolTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
|
||||
cliToolTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
|
||||
|
||||
cliToolButton.autoPinEdge(.Top, toEdge: .Bottom, ofView: ignoreInfo, withOffset: 18)
|
||||
cliToolButton.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
cliToolButton.autoPinEdge(.Left, toEdge: .Right, ofView: cliToolTitle, withOffset: 5)
|
||||
cliToolButton.autoPinEdge(.top, to: .bottom, of: ignoreInfo, withOffset: 18)
|
||||
cliToolButton.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
cliToolButton.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
|
||||
|
||||
cliToolInfo.autoPinEdge(.Top, toEdge: .Bottom, ofView: cliToolButton, withOffset: 5)
|
||||
cliToolInfo.autoPinEdgeToSuperviewEdge(.Right, withInset: 18, relation: .GreaterThanOrEqual)
|
||||
cliToolInfo.autoPinEdge(.Left, toEdge: .Right, ofView: cliToolTitle, withOffset: 5)
|
||||
cliToolInfo.autoPinEdge(.top, to: .bottom, of: cliToolButton, withOffset: 5)
|
||||
cliToolInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
cliToolInfo.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
|
||||
|
||||
self.openWhenLaunchingCheckbox.boolState = self.data.openNewWindowWhenLaunching
|
||||
self.openOnReactivationCheckbox.boolState = self.data.openNewWindowOnReactivation
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PrefData }
|
||||
.map { ($0 as! PrefData).general }
|
||||
@ -153,19 +153,19 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
self.ignorePatternsAction()
|
||||
}
|
||||
|
||||
private func set(data data: GeneralPrefData) {
|
||||
fileprivate func set(data: GeneralPrefData) {
|
||||
self.data = data
|
||||
self.publish(event: data)
|
||||
}
|
||||
|
||||
private func ignoreInfoText() -> NSAttributedString {
|
||||
let font = NSFont.systemFontOfSize(NSFont.smallSystemFontSize())
|
||||
fileprivate func ignoreInfoText() -> NSAttributedString {
|
||||
let font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
|
||||
let attrs = [
|
||||
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 str = "Comma-separated list of ignore patterns\n"
|
||||
+ "Matching files will be ignored in \"Open Quickly\".\n"
|
||||
@ -173,13 +173,13 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
+ "For detailed information see "
|
||||
|
||||
let ignoreInfoStr = NSMutableAttributedString(string:str, attributes:attrs)
|
||||
ignoreInfoStr.appendAttributedString(linkStr)
|
||||
ignoreInfoStr.appendAttributedString(NSAttributedString(string: ".", attributes: attrs))
|
||||
ignoreInfoStr.append(linkStr)
|
||||
ignoreInfoStr.append(NSAttributedString(string: ".", attributes: attrs))
|
||||
|
||||
return ignoreInfoStr
|
||||
}
|
||||
|
||||
private func updateViews(newData newData: GeneralPrefData) {
|
||||
fileprivate func updateViews(newData: GeneralPrefData) {
|
||||
self.openWhenLaunchingCheckbox.boolState = newData.openNewWindowWhenLaunching
|
||||
self.openOnReactivationCheckbox.boolState = newData.openNewWindowOnReactivation
|
||||
self.ignoreField.stringValue = PrefUtils.ignorePatternString(fromSet: newData.ignorePatterns)
|
||||
@ -189,37 +189,37 @@ class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
|
||||
// MARK: - Actions
|
||||
extension GeneralPrefPane {
|
||||
|
||||
func copyCliTool(sender: NSButton) {
|
||||
func copyCliTool(_ sender: NSButton) {
|
||||
let panel = NSOpenPanel()
|
||||
panel.canChooseFiles = false
|
||||
panel.canChooseDirectories = true
|
||||
|
||||
panel.beginSheetModalForWindow(self.window!) { result in
|
||||
panel.beginSheetModal(for: self.window!) { result in
|
||||
guard result == NSFileHandlingPanelOKButton else {
|
||||
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.",
|
||||
info: "The CLI tool 'vimr' could not be found. Please re-download VimR and try again.")
|
||||
return
|
||||
}
|
||||
|
||||
guard let targetUrl = panel.URL?.URLByAppendingPathComponent("vimr") else {
|
||||
guard let targetUrl = panel.url?.appendingPathComponent("vimr") else {
|
||||
self.alert(title: "Something Went Wrong.",
|
||||
info: "The target directory could not be determined. Please try again with a different directory.")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
try NSFileManager.defaultManager().copyItemAtURL(vimrUrl, toURL: targetUrl)
|
||||
try FileManager.default.copyItem(at: vimrUrl, to: targetUrl)
|
||||
} catch let err as NSError {
|
||||
self.alert(title: "Error copying 'vimr'", info: err.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func openUntitledWindowWhenLaunchingAction(sender: NSButton) {
|
||||
func openUntitledWindowWhenLaunchingAction(_ sender: NSButton) {
|
||||
self.set(data: GeneralPrefData(
|
||||
openNewWindowWhenLaunching: self.openWhenLaunchingCheckbox.boolState,
|
||||
openNewWindowOnReactivation: self.data.openNewWindowOnReactivation,
|
||||
@ -227,7 +227,7 @@ extension GeneralPrefPane {
|
||||
)
|
||||
}
|
||||
|
||||
func openUntitledWindowOnReactivationAction(sender: NSButton) {
|
||||
func openUntitledWindowOnReactivationAction(_ sender: NSButton) {
|
||||
self.set(data: GeneralPrefData(
|
||||
openNewWindowWhenLaunching: self.data.openNewWindowWhenLaunching,
|
||||
openNewWindowOnReactivation: self.openOnReactivationCheckbox.boolState,
|
||||
@ -235,7 +235,7 @@ extension GeneralPrefPane {
|
||||
)
|
||||
}
|
||||
|
||||
private func ignorePatternsAction() {
|
||||
fileprivate func ignorePatternsAction() {
|
||||
let patterns = PrefUtils.ignorePatterns(fromString: self.ignoreField.stringValue)
|
||||
if patterns == self.data.ignorePatterns {
|
||||
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()
|
||||
alert.alertStyle = .WarningAlertStyle
|
||||
alert.alertStyle = .warning
|
||||
alert.messageText = title
|
||||
alert.informativeText = info
|
||||
alert.runModal()
|
||||
|
@ -28,8 +28,8 @@ class ImageAndTextTableCell: NSView {
|
||||
}
|
||||
}
|
||||
|
||||
private let textField: NSTextField = NSTextField(forAutoLayout: ())
|
||||
private let imageView: NSImageView = NSImageView(forAutoLayout: ())
|
||||
fileprivate let textField: NSTextField = NSTextField(forAutoLayout: ())
|
||||
fileprivate let imageView: NSImageView = NSImageView(forAutoLayout: ())
|
||||
|
||||
init(withIdentifier identifier: String) {
|
||||
super.init(frame: CGRect.zero)
|
||||
@ -37,9 +37,9 @@ class ImageAndTextTableCell: NSView {
|
||||
self.identifier = identifier
|
||||
|
||||
let textField = self.textField
|
||||
textField.bordered = false
|
||||
textField.editable = false
|
||||
textField.lineBreakMode = .ByTruncatingTail
|
||||
textField.isBordered = false
|
||||
textField.isEditable = false
|
||||
textField.lineBreakMode = .byTruncatingTail
|
||||
textField.drawsBackground = false
|
||||
|
||||
let imageView = self.imageView
|
||||
@ -47,15 +47,15 @@ class ImageAndTextTableCell: NSView {
|
||||
self.addSubview(textField)
|
||||
self.addSubview(imageView)
|
||||
|
||||
imageView.autoPinEdgeToSuperviewEdge(.Top, withInset: 2)
|
||||
imageView.autoPinEdgeToSuperviewEdge(.Left, withInset: 2)
|
||||
imageView.autoSetDimension(.Width, toSize: 16)
|
||||
imageView.autoSetDimension(.Height, toSize: 16)
|
||||
imageView.autoPinEdge(toSuperviewEdge: .top, withInset: 2)
|
||||
imageView.autoPinEdge(toSuperviewEdge: .left, withInset: 2)
|
||||
imageView.autoSetDimension(.width, toSize: 16)
|
||||
imageView.autoSetDimension(.height, toSize: 16)
|
||||
|
||||
textField.autoPinEdgeToSuperviewEdge(.Top, withInset: 2)
|
||||
textField.autoPinEdgeToSuperviewEdge(.Right, withInset: 2)
|
||||
textField.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 2)
|
||||
textField.autoPinEdge(.Left, toEdge: .Right, ofView: imageView, withOffset: 4)
|
||||
textField.autoPinEdge(toSuperviewEdge: .top, withInset: 2)
|
||||
textField.autoPinEdge(toSuperviewEdge: .right, withInset: 2)
|
||||
textField.autoPinEdge(toSuperviewEdge: .bottom, withInset: 2)
|
||||
textField.autoPinEdge(.left, to: .right, of: imageView, withOffset: 4)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
@ -15,17 +15,17 @@ enum MainWindowAction {
|
||||
|
||||
class MainWindowComponent: WindowComponent, NSWindowDelegate {
|
||||
|
||||
private let fontManager = NSFontManager.sharedFontManager()
|
||||
fileprivate let fontManager = NSFontManager.shared()
|
||||
|
||||
private var defaultEditorFont: NSFont
|
||||
private var usesLigatures: Bool
|
||||
fileprivate var defaultEditorFont: NSFont
|
||||
fileprivate var usesLigatures: Bool
|
||||
|
||||
var uuid: String {
|
||||
return self.neoVimView.uuid
|
||||
}
|
||||
|
||||
private var _cwd: NSURL = NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
|
||||
var cwd: NSURL {
|
||||
fileprivate var _cwd: URL = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true)
|
||||
var cwd: URL {
|
||||
get {
|
||||
self._cwd = self.neoVimView.cwd
|
||||
return self._cwd
|
||||
@ -43,16 +43,16 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
|
||||
self.fileItemService.monitor(url: newValue)
|
||||
}
|
||||
}
|
||||
private let fileItemService: FileItemService
|
||||
fileprivate let fileItemService: FileItemService
|
||||
|
||||
private let workspace: Workspace
|
||||
private let neoVimView: NeoVimView
|
||||
fileprivate let workspace: Workspace
|
||||
fileprivate let neoVimView: NeoVimView
|
||||
|
||||
// TODO: Consider an option object for cwd, urls, etc...
|
||||
init(source: Observable<Any>,
|
||||
fileItemService: FileItemService,
|
||||
cwd: NSURL,
|
||||
urls: [NSURL] = [],
|
||||
cwd: URL,
|
||||
urls: [URL] = [],
|
||||
initialData: PrefData)
|
||||
{
|
||||
self.neoVimView = NeoVimView(frame: CGRect.zero,
|
||||
@ -83,7 +83,7 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
|
||||
self.show()
|
||||
}
|
||||
|
||||
func open(urls urls: [NSURL]) {
|
||||
func open(urls: [URL]) {
|
||||
self.neoVimView.open(urls: urls)
|
||||
}
|
||||
|
||||
@ -104,12 +104,12 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
|
||||
self.workspace.autoPinEdgesToSuperviewEdges()
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PrefData }
|
||||
.map { ($0 as! PrefData).appearance }
|
||||
.filter { [unowned self] appearanceData in
|
||||
!appearanceData.editorFont.isEqualTo(self.neoVimView.font)
|
||||
!appearanceData.editorFont.isEqual(to: self.neoVimView.font)
|
||||
|| appearanceData.editorUsesLigatures != self.neoVimView.usesLigatures
|
||||
}
|
||||
.subscribeNext { [unowned self] appearance in
|
||||
@ -122,28 +122,28 @@ class MainWindowComponent: WindowComponent, NSWindowDelegate {
|
||||
// MARK: - File Menu Items
|
||||
extension MainWindowComponent {
|
||||
|
||||
@IBAction func newTab(sender: AnyObject!) {
|
||||
@IBAction func newTab(_ sender: AnyObject!) {
|
||||
self.neoVimView.newTab()
|
||||
}
|
||||
|
||||
@IBAction func openDocument(sender: AnyObject!) {
|
||||
@IBAction func openDocument(_ sender: AnyObject!) {
|
||||
let panel = NSOpenPanel()
|
||||
panel.canChooseDirectories = true
|
||||
panel.beginSheetModalForWindow(self.window) { result in
|
||||
panel.beginSheetModal(for: self.window) { result in
|
||||
guard result == NSFileHandlingPanelOKButton else {
|
||||
return
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
@IBAction func saveDocument(sender: AnyObject!) {
|
||||
@IBAction func saveDocument(_ sender: AnyObject!) {
|
||||
let curBuf = self.neoVimView.currentBuffer()
|
||||
|
||||
if curBuf.fileName == nil {
|
||||
@ -154,7 +154,7 @@ extension MainWindowComponent {
|
||||
self.neoVimView.saveCurrentTab()
|
||||
}
|
||||
|
||||
@IBAction func saveDocumentAs(sender: AnyObject!) {
|
||||
@IBAction func saveDocumentAs(_ sender: AnyObject!) {
|
||||
self.savePanelSheet { url in
|
||||
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()
|
||||
panel.beginSheetModalForWindow(self.window) { result in
|
||||
panel.beginSheetModal(for: self.window) { result in
|
||||
guard result == NSFileHandlingPanelOKButton else {
|
||||
return
|
||||
}
|
||||
|
||||
let showAlert: () -> Void = {
|
||||
let alert = NSAlert()
|
||||
alert.addButtonWithTitle("OK")
|
||||
alert.addButton(withTitle: "OK")
|
||||
alert.messageText = "Invalid File 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()
|
||||
}
|
||||
|
||||
guard let url = panel.URL else {
|
||||
guard let url = panel.url else {
|
||||
showAlert()
|
||||
return
|
||||
}
|
||||
@ -201,20 +201,20 @@ extension MainWindowComponent {
|
||||
// MARK: - Font Menu Items
|
||||
extension MainWindowComponent {
|
||||
|
||||
@IBAction func resetFontSize(sender: AnyObject!) {
|
||||
@IBAction func resetFontSize(_ sender: AnyObject!) {
|
||||
self.neoVimView.font = self.defaultEditorFont
|
||||
}
|
||||
|
||||
@IBAction func makeFontBigger(sender: AnyObject!) {
|
||||
@IBAction func makeFontBigger(_ sender: AnyObject!) {
|
||||
let curFont = self.neoVimView.font
|
||||
let font = self.fontManager.convertFont(curFont,
|
||||
let font = self.fontManager.convert(curFont,
|
||||
toSize: min(curFont.pointSize + 1, PrefStore.maximumEditorFontSize))
|
||||
self.neoVimView.font = font
|
||||
}
|
||||
|
||||
@IBAction func makeFontSmaller(sender: AnyObject!) {
|
||||
@IBAction func makeFontSmaller(_ sender: AnyObject!) {
|
||||
let curFont = self.neoVimView.font
|
||||
let font = self.fontManager.convertFont(curFont,
|
||||
let font = self.fontManager.convert(curFont,
|
||||
toSize: max(curFont.pointSize - 1, PrefStore.minimumEditorFontSize))
|
||||
self.neoVimView.font = font
|
||||
}
|
||||
@ -223,11 +223,11 @@ extension MainWindowComponent {
|
||||
// MARK: - NeoVimViewDelegate
|
||||
extension MainWindowComponent: NeoVimViewDelegate {
|
||||
|
||||
func setTitle(title: String) {
|
||||
func setTitle(_ title: String) {
|
||||
self.window.title = title
|
||||
}
|
||||
|
||||
func setDirtyStatus(dirty: Bool) {
|
||||
func setDirtyStatus(_ dirty: Bool) {
|
||||
self.windowController.setDocumentEdited(dirty)
|
||||
}
|
||||
|
||||
@ -246,27 +246,27 @@ extension MainWindowComponent: NeoVimViewDelegate {
|
||||
// MARK: - NSWindowDelegate
|
||||
extension MainWindowComponent {
|
||||
|
||||
func windowDidBecomeKey(_: NSNotification) {
|
||||
func windowDidBecomeKey(_: Notification) {
|
||||
self.publish(event: MainWindowAction.becomeKey(mainWindow: self))
|
||||
}
|
||||
|
||||
func windowWillClose(notification: NSNotification) {
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
self.fileItemService.unmonitor(url: self._cwd)
|
||||
self.publish(event: MainWindowAction.close(mainWindow: self))
|
||||
}
|
||||
|
||||
func windowShouldClose(sender: AnyObject) -> Bool {
|
||||
func windowShouldClose(_ sender: Any) -> Bool {
|
||||
if self.neoVimView.isCurrentBufferDirty() {
|
||||
let alert = NSAlert()
|
||||
alert.addButtonWithTitle("Cancel")
|
||||
alert.addButtonWithTitle("Discard and Close")
|
||||
alert.addButton(withTitle: "Cancel")
|
||||
alert.addButton(withTitle: "Discard and Close")
|
||||
alert.messageText = "The current buffer has unsaved changes!"
|
||||
alert.alertStyle = .WarningAlertStyle
|
||||
alert.beginSheetModalForWindow(self.window) { response in
|
||||
alert.alertStyle = .warning
|
||||
alert.beginSheetModal(for: self.window, completionHandler: { response in
|
||||
if response == NSAlertSecondButtonReturn {
|
||||
self.neoVimView.closeCurrentTabWithoutSaving()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ enum MainWindowEvent {
|
||||
|
||||
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]()
|
||||
private weak var keyMainWindow: MainWindowComponent?
|
||||
fileprivate var mainWindowComponents = [String:MainWindowComponent]()
|
||||
fileprivate weak var keyMainWindow: MainWindowComponent?
|
||||
|
||||
private let fileItemService: FileItemService
|
||||
private var data: PrefData
|
||||
fileprivate let fileItemService: FileItemService
|
||||
fileprivate var data: PrefData
|
||||
|
||||
init(source: Observable<Any>, fileItemService: FileItemService, initialData: PrefData) {
|
||||
self.fileItemService = fileItemService
|
||||
@ -27,7 +27,7 @@ class MainWindowManager: StandardFlow {
|
||||
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(
|
||||
source: self.source, fileItemService: self.fileItemService, cwd: cwd, urls: urls, initialData: self.data
|
||||
)
|
||||
@ -53,12 +53,12 @@ class MainWindowManager: StandardFlow {
|
||||
return mainWindowComponent
|
||||
}
|
||||
|
||||
func closeMainWindow(mainWindowComponent: MainWindowComponent) {
|
||||
func closeMainWindow(_ mainWindowComponent: MainWindowComponent) {
|
||||
if self.keyMainWindow === mainWindowComponent {
|
||||
self.keyMainWindow = nil
|
||||
}
|
||||
|
||||
self.mainWindowComponents.removeValueForKey(mainWindowComponent.uuid)
|
||||
self.mainWindowComponents.removeValue(forKey: mainWindowComponent.uuid)
|
||||
|
||||
if self.mainWindowComponents.isEmpty {
|
||||
self.publish(event: MainWindowEvent.allWindowsClosed)
|
||||
@ -69,7 +69,7 @@ class MainWindowManager: StandardFlow {
|
||||
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 {
|
||||
self.newMainWindow(urls: urls, cwd: cwd)
|
||||
return
|
||||
@ -84,7 +84,7 @@ class MainWindowManager: StandardFlow {
|
||||
keyMainWindow.open(urls: urls)
|
||||
}
|
||||
|
||||
private func set(keyMainWindow mainWindow: MainWindowComponent?) {
|
||||
fileprivate func set(keyMainWindow mainWindow: MainWindowComponent?) {
|
||||
self.keyMainWindow = mainWindow
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ class MainWindowManager: StandardFlow {
|
||||
return !self.mainWindowComponents.isEmpty
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PrefData }
|
||||
.map { $0 as! PrefData }
|
||||
|
@ -7,7 +7,7 @@ import Foundation
|
||||
|
||||
class Matcher {
|
||||
|
||||
static let uppercaseCharSet = NSCharacterSet.uppercaseLetterCharacterSet()
|
||||
static let uppercaseCharSet = CharacterSet.uppercaseLetters
|
||||
|
||||
enum ExactMatchResult {
|
||||
case none
|
||||
@ -17,9 +17,9 @@ class Matcher {
|
||||
case contains
|
||||
}
|
||||
|
||||
static func exactMatchIgnoringCase(target: String, pattern: String) -> ExactMatchResult {
|
||||
let ltarget = target.lowercaseString
|
||||
let lpattern = pattern.lowercaseString
|
||||
static func exactMatchIgnoringCase(_ target: String, pattern: String) -> ExactMatchResult {
|
||||
let ltarget = target.lowercased()
|
||||
let lpattern = pattern.lowercased()
|
||||
if ltarget == lpattern {
|
||||
return .exact
|
||||
}
|
||||
@ -32,26 +32,26 @@ class Matcher {
|
||||
return .suffix
|
||||
}
|
||||
|
||||
if ltarget.containsString(lpattern) {
|
||||
if ltarget.contains(lpattern) {
|
||||
return .contains
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
static func numberOfUppercaseMatches(target: String, pattern: String) -> Int {
|
||||
var tscalars = target.unicodeScalars.filter { uppercaseCharSet.longCharacterIsMember($0.value) }
|
||||
static func numberOfUppercaseMatches(_ target: String, pattern: String) -> Int {
|
||||
var tscalars = target.unicodeScalars.filter { uppercaseCharSet.contains(UnicodeScalar($0.value)!) }
|
||||
|
||||
let count = tscalars.count
|
||||
guard count > 0 else {
|
||||
return 0
|
||||
}
|
||||
|
||||
let pscalars = pattern.uppercaseString.unicodeScalars
|
||||
let pscalars = pattern.uppercased().unicodeScalars
|
||||
|
||||
pscalars.forEach { scalar in
|
||||
if let idx = tscalars.indexOf(scalar) {
|
||||
tscalars.removeAtIndex(idx)
|
||||
if let idx = tscalars.index(of: scalar) {
|
||||
tscalars.remove(at: idx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,30 +60,30 @@ class Matcher {
|
||||
|
||||
/// Matches `pattern` to `target` in a fuzzy way.
|
||||
/// - returns: `Array` of `Range<String.UnicodeScalarIndex>`
|
||||
static func fuzzyIgnoringCase(target: String, pattern: String) -> (matches: Int, ranges: [Range<Int>]) {
|
||||
let tlower = target.lowercaseString
|
||||
let plower = pattern.lowercaseString
|
||||
static func fuzzyIgnoringCase(_ target: String, pattern: String) -> (matches: Int, ranges: [CountableRange<Int>]) {
|
||||
let tlower = target.lowercased()
|
||||
let plower = pattern.lowercased()
|
||||
|
||||
let tchars = tlower.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
|
||||
for (i, tchar) in tchars.enumerate() {
|
||||
for (i, tchar) in tchars.enumerated() {
|
||||
if pchars[pidx] == tchar {
|
||||
flags[i] = true
|
||||
pidx = pidx.successor()
|
||||
pidx = pchars.index(after: pidx)
|
||||
}
|
||||
}
|
||||
|
||||
var ranges: [Range<Int>] = []
|
||||
var ranges: [CountableRange<Int>] = []
|
||||
var matches = 0
|
||||
|
||||
var lastTrue = -1
|
||||
var curTrue = -1
|
||||
|
||||
for (i, isTrue) in flags.enumerate() {
|
||||
for (i, isTrue) in flags.enumerated() {
|
||||
if isTrue {
|
||||
matches = matches &+ 1
|
||||
if lastTrue == -1 {
|
||||
@ -93,14 +93,14 @@ class Matcher {
|
||||
|
||||
if i == flags.count &- 1 {
|
||||
if lastTrue > -1 && curTrue > -1 {
|
||||
ranges.append(lastTrue...curTrue)
|
||||
ranges.append(CountableRange(lastTrue...curTrue))
|
||||
lastTrue = -1
|
||||
curTrue = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if lastTrue > -1 && curTrue > -1 {
|
||||
ranges.append(lastTrue...curTrue)
|
||||
ranges.append(CountableRange(lastTrue...curTrue))
|
||||
lastTrue = -1
|
||||
curTrue = -1
|
||||
}
|
||||
@ -115,23 +115,23 @@ class Matcher {
|
||||
///
|
||||
/// - returns: the distance of pattern from target
|
||||
/// - seealso: https://en.wikipedia.org/wiki/Wagner–Fischer_algorithm
|
||||
static func wagnerFisherDistance(target: String, pattern: String) -> Int {
|
||||
static func wagnerFisherDistance(_ target: String, pattern: String) -> Int {
|
||||
let s = target.unicodeScalars
|
||||
let t = pattern.unicodeScalars
|
||||
|
||||
let m = s.count
|
||||
|
||||
var prevRow = Array(count: m &+ 1, repeatedValue: 0)
|
||||
var curRow = Array(count: m &+ 1, repeatedValue: 0)
|
||||
var prevRow = Array(repeating: 0, count: m &+ 1)
|
||||
var curRow = Array(repeating: 0, count: m &+ 1)
|
||||
|
||||
for i in 0...m {
|
||||
prevRow[i] = i
|
||||
}
|
||||
|
||||
for (j, tchar) in t.enumerate() {
|
||||
for (j, tchar) in t.enumerated() {
|
||||
curRow[0] = j &+ 1
|
||||
|
||||
for (i, schar) in s.enumerate() {
|
||||
for (i, schar) in s.enumerated() {
|
||||
if schar == tchar {
|
||||
curRow[i &+ 1] = prevRow[i]
|
||||
} else {
|
||||
|
@ -7,18 +7,18 @@ import Cocoa
|
||||
|
||||
class OpenQuicklyFileViewRow: NSTableRowView {
|
||||
|
||||
override func drawSelectionInRect(dirtyRect: NSRect) {
|
||||
if self.selected {
|
||||
NSColor.selectedControlColor().set()
|
||||
override func drawSelection(in dirtyRect: NSRect) {
|
||||
if self.isSelected {
|
||||
NSColor.selectedControlColor.set()
|
||||
} 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] {
|
||||
var rectsPtr: UnsafePointer<CGRect> = nil
|
||||
fileprivate func rectsBeingDrawn() -> [CGRect] {
|
||||
var rectsPtr: UnsafePointer<CGRect>? = nil
|
||||
var count: Int = 0
|
||||
self.getRectsBeingDrawn(&rectsPtr, count: &count)
|
||||
|
||||
|
@ -5,20 +5,20 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class OpenQuicklyFilterOperation: NSOperation {
|
||||
class OpenQuicklyFilterOperation: Operation {
|
||||
|
||||
private let chunkSize = 100
|
||||
private let maxResultCount = 500
|
||||
fileprivate let chunkSize = 100
|
||||
fileprivate let maxResultCount = 500
|
||||
|
||||
private unowned let openQuicklyWindow: OpenQuicklyWindowComponent
|
||||
private let pattern: String
|
||||
private let flatFileItems: [FileItem]
|
||||
private let cwd: NSURL
|
||||
fileprivate unowned let openQuicklyWindow: OpenQuicklyWindowComponent
|
||||
fileprivate let pattern: String
|
||||
fileprivate let flatFileItems: [FileItem]
|
||||
fileprivate let cwd: URL
|
||||
|
||||
init(forOpenQuicklyWindow openQuicklyWindow: OpenQuicklyWindowComponent) {
|
||||
self.openQuicklyWindow = openQuicklyWindow
|
||||
self.pattern = openQuicklyWindow.pattern
|
||||
self.cwd = openQuicklyWindow.cwd
|
||||
self.cwd = openQuicklyWindow.cwd as URL
|
||||
self.flatFileItems = openQuicklyWindow.flatFileItems
|
||||
|
||||
super.init()
|
||||
@ -33,7 +33,7 @@ class OpenQuicklyFilterOperation: NSOperation {
|
||||
self.openQuicklyWindow.scanCondition.unlock()
|
||||
}
|
||||
|
||||
if self.cancelled {
|
||||
if self.isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
@ -47,17 +47,17 @@ class OpenQuicklyFilterOperation: NSOperation {
|
||||
|
||||
let count = self.flatFileItems.count
|
||||
let chunksCount = Int(ceil(Float(count) / Float(self.chunkSize)))
|
||||
let useFullPath = pattern.containsString("/")
|
||||
let cwdPath = self.cwd.path! + "/"
|
||||
let useFullPath = pattern.contains("/")
|
||||
let cwdPath = self.cwd.path + "/"
|
||||
|
||||
var result = [ScoredFileItem]()
|
||||
var spinLock = OS_SPINLOCK_INIT
|
||||
|
||||
let cleanedPattern = useFullPath ? self.pattern.stringByReplacingOccurrencesOfString("/", withString: "")
|
||||
let cleanedPattern = useFullPath ? self.pattern.replacingOccurrences(of: "/", with: "")
|
||||
: self.pattern
|
||||
|
||||
dispatch_apply(chunksCount, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { [unowned self] idx in
|
||||
if self.cancelled {
|
||||
DispatchQueue.concurrentPerform(iterations: chunksCount) { [unowned self] idx in
|
||||
if self.isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
@ -66,39 +66,39 @@ class OpenQuicklyFilterOperation: NSOperation {
|
||||
|
||||
let chunkedItems = self.flatFileItems[startIndex..<endIndex]
|
||||
let chunkedResult: [ScoredFileItem] = chunkedItems.flatMap {
|
||||
if self.cancelled {
|
||||
if self.isCancelled {
|
||||
return nil
|
||||
}
|
||||
|
||||
let url = $0.url
|
||||
|
||||
if useFullPath {
|
||||
let target = url.path!.stringByReplacingOccurrencesOfString(cwdPath, withString: "")
|
||||
.stringByReplacingOccurrencesOfString("/", withString: "")
|
||||
let target = url.path.replacingOccurrences(of: cwdPath, with: "")
|
||||
.replacingOccurrences(of: "/", with: "")
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
OSSpinLockLock(&spinLock)
|
||||
result.appendContentsOf(chunkedResult)
|
||||
result.append(contentsOf: chunkedResult)
|
||||
OSSpinLockUnlock(&spinLock)
|
||||
}
|
||||
|
||||
if self.cancelled {
|
||||
if self.isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
sorted = result.sort(>)
|
||||
sorted = result.sorted(by: >)
|
||||
}
|
||||
|
||||
if self.cancelled {
|
||||
if self.isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -16,80 +16,80 @@ class OpenQuicklyWindowComponent: WindowComponent,
|
||||
let scanCondition = NSCondition()
|
||||
var pauseScan = false
|
||||
|
||||
private(set) var pattern = ""
|
||||
private(set) var cwd = NSURL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) {
|
||||
fileprivate(set) var pattern = ""
|
||||
fileprivate(set) var cwd = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) {
|
||||
didSet {
|
||||
self.cwdPathCompsCount = self.cwd.pathComponents!.count
|
||||
self.cwdControl.URL = self.cwd
|
||||
self.cwdPathCompsCount = self.cwd.pathComponents.count
|
||||
self.cwdControl.url = self.cwd
|
||||
}
|
||||
}
|
||||
private(set) var flatFileItems = [FileItem]()
|
||||
private(set) var fileViewItems = [ScoredFileItem]()
|
||||
fileprivate(set) var flatFileItems = [FileItem]()
|
||||
fileprivate(set) var fileViewItems = [ScoredFileItem]()
|
||||
|
||||
private let userInitiatedScheduler = ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .UserInitiated)
|
||||
fileprivate let userInitiatedScheduler = ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .userInitiated)
|
||||
|
||||
private let searchField = NSTextField(forAutoLayout: ())
|
||||
private let progressIndicator = NSProgressIndicator(forAutoLayout: ())
|
||||
private let cwdControl = NSPathControl(forAutoLayout: ())
|
||||
private let countField = NSTextField(forAutoLayout: ())
|
||||
private let fileView = NSTableView.standardTableView()
|
||||
fileprivate let searchField = NSTextField(forAutoLayout: ())
|
||||
fileprivate let progressIndicator = NSProgressIndicator(forAutoLayout: ())
|
||||
fileprivate let cwdControl = NSPathControl(forAutoLayout: ())
|
||||
fileprivate let countField = NSTextField(forAutoLayout: ())
|
||||
fileprivate let fileView = NSTableView.standardTableView()
|
||||
|
||||
private let fileItemService: FileItemService
|
||||
fileprivate let fileItemService: FileItemService
|
||||
|
||||
private var count = 0
|
||||
private var perSessionDisposeBag = DisposeBag()
|
||||
fileprivate var count = 0
|
||||
fileprivate var perSessionDisposeBag = DisposeBag()
|
||||
|
||||
private var cwdPathCompsCount = 0
|
||||
private let searchStream: Observable<String>
|
||||
private let filterOpQueue = NSOperationQueue()
|
||||
fileprivate var cwdPathCompsCount = 0
|
||||
fileprivate let searchStream: Observable<String>
|
||||
fileprivate let filterOpQueue = OperationQueue()
|
||||
|
||||
weak private var mainWindow: MainWindowComponent?
|
||||
weak fileprivate var mainWindow: MainWindowComponent?
|
||||
|
||||
init(source: Observable<Any>, fileItemService: FileItemService) {
|
||||
self.fileItemService = fileItemService
|
||||
self.searchStream = self.searchField.rx_text
|
||||
self.searchStream = self.searchField.rx.textInput.text
|
||||
.throttle(0.2, scheduler: MainScheduler.instance)
|
||||
.distinctUntilChanged()
|
||||
|
||||
super.init(source: source, nibName: "OpenQuicklyWindow")
|
||||
|
||||
self.window.delegate = self
|
||||
self.filterOpQueue.qualityOfService = .UserInitiated
|
||||
self.filterOpQueue.qualityOfService = .userInitiated
|
||||
self.filterOpQueue.name = "open-quickly-filter-operation-queue"
|
||||
}
|
||||
|
||||
override func addViews() {
|
||||
let searchField = self.searchField
|
||||
searchField.rx_delegate.setForwardToDelegate(self, retainDelegate: false)
|
||||
searchField.rx.delegate.setForwardToDelegate(self, retainDelegate: false)
|
||||
|
||||
let progressIndicator = self.progressIndicator
|
||||
progressIndicator.indeterminate = true
|
||||
progressIndicator.displayedWhenStopped = false
|
||||
progressIndicator.style = .SpinningStyle
|
||||
progressIndicator.controlSize = .SmallControlSize
|
||||
progressIndicator.isIndeterminate = true
|
||||
progressIndicator.isDisplayedWhenStopped = false
|
||||
progressIndicator.style = .spinningStyle
|
||||
progressIndicator.controlSize = .small
|
||||
|
||||
let fileView = self.fileView
|
||||
fileView.intercellSpacing = CGSize(width: 4, height: 4)
|
||||
fileView.setDataSource(self)
|
||||
fileView.setDelegate(self)
|
||||
fileView.dataSource = self
|
||||
fileView.delegate = self
|
||||
|
||||
let fileScrollView = NSScrollView.standardScrollView()
|
||||
fileScrollView.autoresizesSubviews = true
|
||||
fileScrollView.documentView = fileView
|
||||
|
||||
let cwdControl = self.cwdControl
|
||||
cwdControl.pathStyle = .Standard
|
||||
cwdControl.backgroundColor = NSColor.clearColor()
|
||||
cwdControl.pathStyle = .standard
|
||||
cwdControl.backgroundColor = NSColor.clear
|
||||
cwdControl.refusesFirstResponder = true
|
||||
cwdControl.cell?.controlSize = .SmallControlSize
|
||||
cwdControl.cell?.font = NSFont.systemFontOfSize(NSFont.smallSystemFontSize())
|
||||
cwdControl.setContentCompressionResistancePriority(NSLayoutPriorityDefaultLow, forOrientation:.Horizontal)
|
||||
cwdControl.cell?.controlSize = .small
|
||||
cwdControl.cell?.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
|
||||
cwdControl.setContentCompressionResistancePriority(NSLayoutPriorityDefaultLow, for:.horizontal)
|
||||
|
||||
let countField = self.countField
|
||||
countField.editable = false
|
||||
countField.bordered = false
|
||||
countField.alignment = .Right
|
||||
countField.backgroundColor = NSColor.clearColor()
|
||||
countField.isEditable = false
|
||||
countField.isBordered = false
|
||||
countField.alignment = .right
|
||||
countField.backgroundColor = NSColor.clear
|
||||
countField.stringValue = "0 items"
|
||||
|
||||
let contentView = self.window.contentView!
|
||||
@ -99,28 +99,28 @@ class OpenQuicklyWindowComponent: WindowComponent,
|
||||
contentView.addSubview(cwdControl)
|
||||
contentView.addSubview(countField)
|
||||
|
||||
searchField.autoPinEdgeToSuperviewEdge(.Top, withInset: 8)
|
||||
searchField.autoPinEdgeToSuperviewEdge(.Right, withInset: 8)
|
||||
searchField.autoPinEdgeToSuperviewEdge(.Left, withInset: 8)
|
||||
searchField.autoPinEdge(toSuperviewEdge: .top, withInset: 8)
|
||||
searchField.autoPinEdge(toSuperviewEdge: .right, withInset: 8)
|
||||
searchField.autoPinEdge(toSuperviewEdge: .left, withInset: 8)
|
||||
|
||||
progressIndicator.autoAlignAxis(.Horizontal, toSameAxisOfView: searchField)
|
||||
progressIndicator.autoPinEdge(.Right, toEdge: .Right, ofView: searchField, withOffset: -4)
|
||||
progressIndicator.autoAlignAxis(.horizontal, toSameAxisOf: searchField)
|
||||
progressIndicator.autoPinEdge(.right, to: .right, of: searchField, withOffset: -4)
|
||||
|
||||
fileScrollView.autoPinEdge(.Top, toEdge: .Bottom, ofView: searchField, withOffset: 8)
|
||||
fileScrollView.autoPinEdgeToSuperviewEdge(.Left, withInset: -1)
|
||||
fileScrollView.autoPinEdgeToSuperviewEdge(.Right, withInset: -1)
|
||||
fileScrollView.autoSetDimension(.Height, toSize: 200, relation: .GreaterThanOrEqual)
|
||||
fileScrollView.autoPinEdge(.top, to: .bottom, of: searchField, withOffset: 8)
|
||||
fileScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: -1)
|
||||
fileScrollView.autoPinEdge(toSuperviewEdge: .right, withInset: -1)
|
||||
fileScrollView.autoSetDimension(.height, toSize: 200, relation: .greaterThanOrEqual)
|
||||
|
||||
cwdControl.autoPinEdge(.Top, toEdge: .Bottom, ofView: fileScrollView, withOffset: 4)
|
||||
cwdControl.autoPinEdgeToSuperviewEdge(.Left, withInset: 2)
|
||||
cwdControl.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 4)
|
||||
cwdControl.autoPinEdge(.top, to: .bottom, of: fileScrollView, withOffset: 4)
|
||||
cwdControl.autoPinEdge(toSuperviewEdge: .left, withInset: 2)
|
||||
cwdControl.autoPinEdge(toSuperviewEdge: .bottom, withInset: 4)
|
||||
|
||||
countField.autoPinEdge(.Top, toEdge: .Bottom, ofView: fileScrollView, withOffset: 4)
|
||||
countField.autoPinEdgeToSuperviewEdge(.Right, withInset: 2)
|
||||
countField.autoPinEdge(.Left, toEdge: .Right, ofView: cwdControl, withOffset: 4)
|
||||
countField.autoPinEdge(.top, to: .bottom, of: fileScrollView, withOffset: 4)
|
||||
countField.autoPinEdge(toSuperviewEdge: .right, withInset: 2)
|
||||
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
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
|
||||
}
|
||||
.addDisposableTo(self.perSessionDisposeBag)
|
||||
|
||||
self.cwd = mainWindow.cwd
|
||||
self.cwd = mainWindow.cwd as URL
|
||||
let flatFiles = self.fileItemService.flatFileItems(ofUrl: self.cwd)
|
||||
.subscribeOn(self.userInitiatedScheduler)
|
||||
|
||||
@ -174,7 +174,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
|
||||
}
|
||||
self.scanCondition.unlock()
|
||||
|
||||
self.flatFileItems.appendContentsOf(items)
|
||||
self.flatFileItems.append(contentsOf: items)
|
||||
self.resetAndAddFilterOperation()
|
||||
}
|
||||
.observeOn(MainScheduler.instance)
|
||||
@ -188,7 +188,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
|
||||
self.searchField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
private func resetAndAddFilterOperation() {
|
||||
fileprivate func resetAndAddFilterOperation() {
|
||||
self.filterOpQueue.cancelAllOperations()
|
||||
let op = OpenQuicklyFilterOperation(forOpenQuicklyWindow: self)
|
||||
self.filterOpQueue.addOperation(op)
|
||||
@ -198,7 +198,7 @@ class OpenQuicklyWindowComponent: WindowComponent,
|
||||
// MARK: - NSTableViewDataSource
|
||||
extension OpenQuicklyWindowComponent {
|
||||
|
||||
func numberOfRowsInTableView(_: NSTableView) -> Int {
|
||||
@objc(numberOfRowsInTableView:) func numberOfRows(in _: NSTableView) -> Int {
|
||||
return self.fileViewItems.count
|
||||
}
|
||||
}
|
||||
@ -206,27 +206,27 @@ extension OpenQuicklyWindowComponent {
|
||||
// MARK: - NSTableViewDelegate
|
||||
extension OpenQuicklyWindowComponent {
|
||||
|
||||
func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
|
||||
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
|
||||
return OpenQuicklyFileViewRow()
|
||||
}
|
||||
|
||||
func tableView(tableView: NSTableView, viewForTableColumn _: NSTableColumn?, row: Int) -> NSView? {
|
||||
let cachedCell = tableView.makeViewWithIdentifier("file-view-row", owner: self)
|
||||
@objc(tableView:viewForTableColumn:row:) func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {
|
||||
let cachedCell = tableView.make(withIdentifier: "file-view-row", owner: self)
|
||||
let cell = cachedCell as? ImageAndTextTableCell ?? ImageAndTextTableCell(withIdentifier: "file-view-row")
|
||||
|
||||
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)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableViewSelectionDidChange(_: NSNotification) {
|
||||
func tableViewSelectionDidChange(_: Notification) {
|
||||
// NSLog("\(#function): selection changed")
|
||||
}
|
||||
|
||||
private func rowText(forUrl url: NSURL) -> NSAttributedString {
|
||||
let pathComps = url.pathComponents!
|
||||
fileprivate func rowText(forUrl url: URL) -> NSAttributedString {
|
||||
let pathComps = url.pathComponents
|
||||
let truncatedPathComps = pathComps[self.cwdPathCompsCount..<pathComps.count]
|
||||
let name = truncatedPathComps.last!
|
||||
|
||||
@ -235,10 +235,10 @@ extension OpenQuicklyWindowComponent {
|
||||
}
|
||||
|
||||
let rowText: NSMutableAttributedString
|
||||
let pathInfo = truncatedPathComps.dropLast().reverse().joinWithSeparator(" / ")
|
||||
let pathInfo = truncatedPathComps.dropLast().reversed().joined(separator: " / ")
|
||||
rowText = NSMutableAttributedString(string: "\(name) — \(pathInfo)")
|
||||
rowText.addAttribute(NSForegroundColorAttributeName,
|
||||
value: NSColor.lightGrayColor(),
|
||||
value: NSColor.lightGray,
|
||||
range: NSRange(location:name.characters.count,
|
||||
length: pathInfo.characters.count + 3))
|
||||
|
||||
@ -249,7 +249,7 @@ extension OpenQuicklyWindowComponent {
|
||||
// MARK: - NSTextFieldDelegate
|
||||
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 {
|
||||
case NSSelectorFromString("cancelOperation:"):
|
||||
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 lastIdx = tableView.numberOfRows - 1
|
||||
let targetIdx: Int
|
||||
@ -286,7 +286,7 @@ extension OpenQuicklyWindowComponent {
|
||||
targetIdx = selectedRow + delta
|
||||
}
|
||||
|
||||
tableView.selectRowIndexes(NSIndexSet(index: targetIdx), byExtendingSelection: false)
|
||||
tableView.selectRowIndexes(IndexSet(integer: targetIdx), byExtendingSelection: false)
|
||||
tableView.scrollRowToVisible(targetIdx)
|
||||
}
|
||||
}
|
||||
@ -294,7 +294,7 @@ extension OpenQuicklyWindowComponent {
|
||||
// MARK: - NSWindowDelegate
|
||||
extension OpenQuicklyWindowComponent {
|
||||
|
||||
func windowWillClose(notification: NSNotification) {
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
self.endProgress()
|
||||
|
||||
self.mainWindow = nil
|
||||
@ -314,7 +314,7 @@ extension OpenQuicklyWindowComponent {
|
||||
self.countField.stringValue = "0 items"
|
||||
}
|
||||
|
||||
func windowDidResignKey(notification: NSNotification) {
|
||||
func windowDidResignKey(_ notification: Notification) {
|
||||
self.window.performClose(self)
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ import RxSwift
|
||||
|
||||
class OpenQuicklyWindowManager: StandardFlow {
|
||||
|
||||
private let openQuicklyWindow: OpenQuicklyWindowComponent
|
||||
private let fileItemService: FileItemService
|
||||
fileprivate let openQuicklyWindow: OpenQuicklyWindowComponent
|
||||
fileprivate let fileItemService: FileItemService
|
||||
|
||||
init(source: Observable<Any>, fileItemService: FileItemService) {
|
||||
self.fileItemService = fileItemService
|
||||
@ -22,7 +22,7 @@ class OpenQuicklyWindowManager: StandardFlow {
|
||||
self.openQuicklyWindow.show(forMainWindow: mainWindow)
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return NopDisposable.instance
|
||||
}
|
||||
}
|
||||
|
@ -10,15 +10,15 @@ class PrefPane: NSView, Component {
|
||||
|
||||
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> {
|
||||
return self.subject.asObservable()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -52,11 +52,11 @@ class PrefPane: NSView, Component {
|
||||
preconditionFailure("Please override")
|
||||
}
|
||||
|
||||
func subscription(source source: Observable<Any>) -> Disposable {
|
||||
func subscription(source: Observable<Any>) -> Disposable {
|
||||
preconditionFailure("Please override")
|
||||
}
|
||||
|
||||
func publish(event event: Any) {
|
||||
func publish(event: Any) {
|
||||
self.subject.onNext(event)
|
||||
}
|
||||
|
||||
@ -68,31 +68,31 @@ class PrefPane: NSView, Component {
|
||||
// MARK: - Control Utils
|
||||
extension PrefPane {
|
||||
|
||||
func paneTitleTextField(title title: String) -> NSTextField {
|
||||
func paneTitleTextField(title: String) -> NSTextField {
|
||||
let field = defaultTitleTextField()
|
||||
field.font = NSFont.boldSystemFontOfSize(16)
|
||||
field.alignment = .Left;
|
||||
field.font = NSFont.boldSystemFont(ofSize: 16)
|
||||
field.alignment = .left;
|
||||
field.stringValue = title
|
||||
return field
|
||||
}
|
||||
|
||||
func titleTextField(title title: String) -> NSTextField {
|
||||
func titleTextField(title: String) -> NSTextField {
|
||||
let field = defaultTitleTextField()
|
||||
field.alignment = .Right;
|
||||
field.alignment = .right;
|
||||
field.stringValue = title
|
||||
return field
|
||||
}
|
||||
|
||||
func infoTextField(text text: String) -> NSTextField {
|
||||
func infoTextField(text: String) -> NSTextField {
|
||||
let field = NSTextField(forAutoLayout: ())
|
||||
field.font = NSFont.systemFontOfSize(NSFont.smallSystemFontSize())
|
||||
field.textColor = NSColor.grayColor()
|
||||
field.backgroundColor = NSColor.clearColor()
|
||||
field.editable = false
|
||||
field.bordered = false
|
||||
field.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
|
||||
field.textColor = NSColor.gray
|
||||
field.backgroundColor = NSColor.clear
|
||||
field.isEditable = false
|
||||
field.isBordered = false
|
||||
|
||||
// both are needed, otherwise hyperlink won't accept mousedown
|
||||
field.selectable = true
|
||||
field.isSelectable = true
|
||||
field.allowsEditingTextAttributes = true
|
||||
|
||||
field.stringValue = text
|
||||
@ -100,19 +100,19 @@ extension PrefPane {
|
||||
return field
|
||||
}
|
||||
|
||||
func configureCheckbox(button button: NSButton, title: String, action: Selector) {
|
||||
func configureCheckbox(button: NSButton, title: String, action: Selector) {
|
||||
button.title = title
|
||||
button.setButtonType(.SwitchButton)
|
||||
button.bezelStyle = .ThickSquareBezelStyle
|
||||
button.setButtonType(.switch)
|
||||
// button.bezelStyle = .ThickSquareBezelStyle
|
||||
button.target = self
|
||||
button.action = action
|
||||
}
|
||||
|
||||
private func defaultTitleTextField() -> NSTextField {
|
||||
fileprivate func defaultTitleTextField() -> NSTextField {
|
||||
let field = NSTextField(forAutoLayout: ())
|
||||
field.backgroundColor = NSColor.clearColor();
|
||||
field.editable = false;
|
||||
field.bordered = false;
|
||||
field.backgroundColor = NSColor.clear;
|
||||
field.isEditable = false;
|
||||
field.isBordered = false;
|
||||
return field
|
||||
}
|
||||
}
|
||||
|
@ -21,21 +21,21 @@ private class PrefKeys {
|
||||
|
||||
class PrefStore: Store {
|
||||
|
||||
private static let compatibleVersion = "38"
|
||||
private static let defaultEditorFont = NeoVimView.defaultFont
|
||||
fileprivate static let compatibleVersion = "38"
|
||||
fileprivate static let defaultEditorFont = NeoVimView.defaultFont
|
||||
static let minimumEditorFontSize = NeoVimView.minFontSize
|
||||
static let maximumEditorFontSize = NeoVimView.maxFontSize
|
||||
|
||||
private let source: Observable<Any>
|
||||
private let disposeBag = DisposeBag()
|
||||
fileprivate let source: Observable<Any>
|
||||
fileprivate let disposeBag = DisposeBag()
|
||||
|
||||
private let subject = PublishSubject<Any>()
|
||||
fileprivate let subject = PublishSubject<Any>()
|
||||
var sink: Observable<Any> {
|
||||
return self.subject.asObservable()
|
||||
}
|
||||
|
||||
private let userDefaults = NSUserDefaults.standardUserDefaults()
|
||||
private let fontManager = NSFontManager.sharedFontManager()
|
||||
fileprivate let userDefaults = UserDefaults.standard
|
||||
fileprivate let fontManager = NSFontManager.shared()
|
||||
|
||||
var data = PrefData(
|
||||
general: GeneralPrefData(openNewWindowWhenLaunching: true,
|
||||
@ -48,7 +48,7 @@ class PrefStore: Store {
|
||||
init(source: Observable<Any>) {
|
||||
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)
|
||||
} else {
|
||||
self.userDefaults.setValue(self.prefsDict(self.data), forKey: PrefStore.compatibleVersion)
|
||||
@ -61,7 +61,7 @@ class PrefStore: Store {
|
||||
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 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
|
||||
if !editorFont.fixedPitch {
|
||||
editorFont = fontManager.convertFont(PrefStore.defaultEditorFont, toSize: editorFont.pointSize)
|
||||
if !editorFont.isFixedPitch {
|
||||
editorFont = fontManager.convert(PrefStore.defaultEditorFont, toSize: editorFont.pointSize)
|
||||
}
|
||||
if editorFont.pointSize < PrefStore.minimumEditorFontSize
|
||||
|| editorFont.pointSize > PrefStore.maximumEditorFontSize {
|
||||
editorFont = fontManager.convertFont(editorFont, toSize: PrefStore.defaultEditorFont.pointSize)
|
||||
editorFont = fontManager.convert(editorFont, toSize: PrefStore.defaultEditorFont.pointSize)
|
||||
}
|
||||
|
||||
return editorFont
|
||||
}
|
||||
|
||||
private func prefsDict(prefData: PrefData) -> [String: AnyObject] {
|
||||
fileprivate func prefsDict(_ prefData: PrefData) -> [String: AnyObject] {
|
||||
let generalData = prefData.general
|
||||
let appearanceData = prefData.appearance
|
||||
let advancedData = prefData.advanced
|
||||
|
||||
let prefs: [String: AnyObject] = [
|
||||
// General
|
||||
PrefKeys.openNewWindowWhenLaunching: generalData.openNewWindowWhenLaunching,
|
||||
PrefKeys.openNewWindowOnReactivation: generalData.openNewWindowOnReactivation,
|
||||
PrefKeys.openQuicklyIgnorePatterns: PrefUtils.ignorePatternString(fromSet: generalData.ignorePatterns),
|
||||
PrefKeys.openNewWindowWhenLaunching: generalData.openNewWindowWhenLaunching as AnyObject,
|
||||
PrefKeys.openNewWindowOnReactivation: generalData.openNewWindowOnReactivation as AnyObject,
|
||||
PrefKeys.openQuicklyIgnorePatterns: PrefUtils.ignorePatternString(fromSet: generalData.ignorePatterns) as AnyObject,
|
||||
|
||||
// Appearance
|
||||
PrefKeys.editorFontName: appearanceData.editorFont.fontName,
|
||||
PrefKeys.editorFontSize: appearanceData.editorFont.pointSize,
|
||||
PrefKeys.editorUsesLigatures: appearanceData.editorUsesLigatures,
|
||||
PrefKeys.editorFontName: appearanceData.editorFont.fontName as AnyObject,
|
||||
PrefKeys.editorFontSize: appearanceData.editorFont.pointSize as AnyObject,
|
||||
PrefKeys.editorUsesLigatures: appearanceData.editorUsesLigatures as AnyObject,
|
||||
|
||||
// Advanced
|
||||
PrefKeys.useInteractiveZsh: advancedData.useInteractiveZsh,
|
||||
PrefKeys.useInteractiveZsh: advancedData.useInteractiveZsh as AnyObject,
|
||||
]
|
||||
|
||||
return prefs
|
||||
}
|
||||
|
||||
private func addReactions() {
|
||||
fileprivate func addReactions() {
|
||||
self.source
|
||||
.filter { $0 is PrefData }
|
||||
.map { $0 as! PrefData }
|
||||
|
@ -7,17 +7,17 @@ import Foundation
|
||||
|
||||
class PrefUtils {
|
||||
|
||||
private static let whitespaceCharSet = NSCharacterSet.whitespaceCharacterSet()
|
||||
fileprivate static let whitespaceCharSet = CharacterSet.whitespaces
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
let patterns: [FileItemIgnorePattern] = str
|
||||
.componentsSeparatedByString(",")
|
||||
.components(separatedBy: ",")
|
||||
.flatMap {
|
||||
let trimmed = $0.stringByTrimmingCharactersInSet(self.whitespaceCharSet)
|
||||
let trimmed = $0.trimmingCharacters(in: self.whitespaceCharSet)
|
||||
if trimmed.characters.count == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -31,7 +31,7 @@ class PrefUtils {
|
||||
static func ignorePatternString(fromSet set: Set<FileItemIgnorePattern>) -> String {
|
||||
return Array(set)
|
||||
.map { $0.pattern }
|
||||
.sort()
|
||||
.joinWithSeparator(", ")
|
||||
.sorted()
|
||||
.joined(separator: ", ")
|
||||
}
|
||||
}
|
@ -15,14 +15,14 @@ struct PrefData {
|
||||
|
||||
class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate {
|
||||
|
||||
private var data: PrefData
|
||||
fileprivate var data: PrefData
|
||||
|
||||
private let categoryView = NSTableView.standardSourceListTableView()
|
||||
private let categoryScrollView = NSScrollView.standardScrollView()
|
||||
private let paneContainer = NSScrollView(forAutoLayout: ())
|
||||
fileprivate let categoryView = NSTableView.standardSourceListTableView()
|
||||
fileprivate let categoryScrollView = NSScrollView.standardScrollView()
|
||||
fileprivate let paneContainer = NSScrollView(forAutoLayout: ())
|
||||
|
||||
private let panes: [PrefPane]
|
||||
private var currentPane: PrefPane {
|
||||
fileprivate let panes: [PrefPane]
|
||||
fileprivate var currentPane: PrefPane {
|
||||
get {
|
||||
return self.paneContainer.documentView as! PrefPane
|
||||
}
|
||||
@ -53,7 +53,7 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
|
||||
self.addReactions()
|
||||
}
|
||||
|
||||
override func subscription(source source: Observable<Any>) -> Disposable {
|
||||
override func subscription(source: Observable<Any>) -> Disposable {
|
||||
return source
|
||||
.filter { $0 is PrefData }
|
||||
.map { $0 as! PrefData }
|
||||
@ -69,8 +69,8 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
|
||||
|
||||
override func addViews() {
|
||||
let categoryView = self.categoryView
|
||||
categoryView.setDataSource(self)
|
||||
categoryView.setDelegate(self)
|
||||
categoryView.dataSource = self
|
||||
categoryView.delegate = self
|
||||
|
||||
let categoryScrollView = self.categoryScrollView
|
||||
categoryScrollView.documentView = categoryView
|
||||
@ -79,28 +79,28 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
|
||||
paneContainer.hasVerticalScroller = true
|
||||
paneContainer.hasHorizontalScroller = true
|
||||
paneContainer.autohidesScrollers = true
|
||||
paneContainer.borderType = .NoBorder
|
||||
paneContainer.borderType = .noBorder
|
||||
paneContainer.autoresizesSubviews = false
|
||||
paneContainer.backgroundColor = NSColor.windowBackgroundColor()
|
||||
paneContainer.backgroundColor = NSColor.windowBackgroundColor
|
||||
|
||||
self.window.contentView?.addSubview(categoryScrollView)
|
||||
self.window.contentView?.addSubview(paneContainer)
|
||||
|
||||
categoryScrollView.autoSetDimension(.Width, toSize: 150)
|
||||
categoryScrollView.autoPinEdgeToSuperviewEdge(.Top, withInset: -1)
|
||||
categoryScrollView.autoPinEdgeToSuperviewEdge(.Bottom, withInset: -1)
|
||||
categoryScrollView.autoPinEdgeToSuperviewEdge(.Left, withInset: -1)
|
||||
categoryScrollView.autoSetDimension(.width, toSize: 150)
|
||||
categoryScrollView.autoPinEdge(toSuperviewEdge: .top, withInset: -1)
|
||||
categoryScrollView.autoPinEdge(toSuperviewEdge: .bottom, withInset: -1)
|
||||
categoryScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: -1)
|
||||
|
||||
paneContainer.autoSetDimension(.Width, toSize: 200, relation: .GreaterThanOrEqual)
|
||||
paneContainer.autoPinEdgeToSuperviewEdge(.Top)
|
||||
paneContainer.autoPinEdgeToSuperviewEdge(.Right)
|
||||
paneContainer.autoPinEdgeToSuperviewEdge(.Bottom)
|
||||
paneContainer.autoPinEdge(.Left, toEdge: .Right, ofView: categoryScrollView)
|
||||
paneContainer.autoSetDimension(.width, toSize: 200, relation: .greaterThanOrEqual)
|
||||
paneContainer.autoPinEdge(toSuperviewEdge: .top)
|
||||
paneContainer.autoPinEdge(toSuperviewEdge: .right)
|
||||
paneContainer.autoPinEdge(toSuperviewEdge: .bottom)
|
||||
paneContainer.autoPinEdge(.left, to: .right, of: categoryScrollView)
|
||||
|
||||
self.currentPane = self.panes[0]
|
||||
}
|
||||
|
||||
private func addReactions() {
|
||||
fileprivate func addReactions() {
|
||||
self.panes
|
||||
.map { $0.sink }
|
||||
.toMergedObservables()
|
||||
@ -122,7 +122,7 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
|
||||
.addDisposableTo(self.disposeBag)
|
||||
}
|
||||
|
||||
func windowWillClose(notification: NSNotification) {
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
self.panes.forEach { $0.windowWillClose() }
|
||||
}
|
||||
}
|
||||
@ -130,11 +130,11 @@ class PrefWindowComponent: WindowComponent, NSWindowDelegate, NSTableViewDataSou
|
||||
// MARK: - NSTableViewDataSource
|
||||
extension PrefWindowComponent {
|
||||
|
||||
func numberOfRowsInTableView(_: NSTableView) -> Int {
|
||||
@objc(numberOfRowsInTableView:) func numberOfRows(in _: NSTableView) -> Int {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -142,7 +142,7 @@ extension PrefWindowComponent {
|
||||
// MARK: - NSTableViewDelegate
|
||||
extension PrefWindowComponent {
|
||||
|
||||
func tableViewSelectionDidChange(_: NSNotification) {
|
||||
func tableViewSelectionDidChange(_: Notification) {
|
||||
let idx = self.categoryView.selectedRow
|
||||
self.currentPane = self.panes[idx]
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import RxSwift
|
||||
|
||||
class ScoredFileItem: Comparable {
|
||||
let score: Int
|
||||
unowned let url: NSURL
|
||||
let url: URL
|
||||
|
||||
init(score: Int, url: NSURL) {
|
||||
init(score: Int, url: URL) {
|
||||
self.score = score
|
||||
self.url = url
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import Foundation
|
||||
|
||||
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 fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern)
|
||||
let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern)
|
||||
|
@ -5,17 +5,17 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
func call(@autoclosure closure: () -> Void, when condition: Bool) { if condition { closure() } }
|
||||
func call(@autoclosure closure: () -> Void, whenNot condition: Bool) { if !condition { closure() } }
|
||||
func call(_ closure: @autoclosure () -> Void, when condition: Bool) { if condition { closure() } }
|
||||
func call(_ closure: @autoclosure () -> Void, whenNot condition: Bool) { if !condition { closure() } }
|
||||
|
||||
extension String {
|
||||
|
||||
func without(prefix prefix: String) -> String {
|
||||
func without(prefix: String) -> String {
|
||||
guard self.hasPrefix(prefix) else {
|
||||
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]
|
||||
}
|
||||
}
|
||||
@ -30,8 +30,8 @@ extension Array {
|
||||
/// - transform: The transform function.
|
||||
/// - returns: Transformed array of `self`.
|
||||
func concurrentChunkMap<R>(
|
||||
chunk: Int = 100,
|
||||
queue: dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
|
||||
_ chunk: Int = 100,
|
||||
queue: DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated),
|
||||
transform: (Element) -> R) -> [R]
|
||||
{
|
||||
let count = self.count
|
||||
@ -41,9 +41,9 @@ extension Array {
|
||||
|
||||
var spinLock = OS_SPINLOCK_INIT
|
||||
|
||||
dispatch_apply(chunkedCount, queue) { idx in
|
||||
let startIndex = min(idx * chunk, count)
|
||||
let endIndex = min(startIndex + chunk, count)
|
||||
DispatchQueue.concurrentPerform(iterations: chunkedCount) { idx in
|
||||
let startIndex = Swift.min(idx * chunk, count)
|
||||
let endIndex = Swift.min(startIndex + chunk, count)
|
||||
|
||||
let mappedChunk = self[startIndex..<endIndex].map(transform)
|
||||
|
||||
|
@ -19,13 +19,13 @@ class Workspace: NSView {
|
||||
let mainViewMinimumSize: CGSize
|
||||
}
|
||||
|
||||
private(set) var isBarVisible = true {
|
||||
fileprivate(set) var isBarVisible = true {
|
||||
didSet {
|
||||
self.relayout()
|
||||
}
|
||||
}
|
||||
|
||||
private let bars: [WorkspaceBarLocation: WorkspaceBar]
|
||||
fileprivate let bars: [WorkspaceBarLocation: WorkspaceBar]
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
@ -52,7 +52,7 @@ class Workspace: NSView {
|
||||
self.relayout()
|
||||
}
|
||||
|
||||
func append(tool tool: WorkspaceTool, location: WorkspaceBarLocation) {
|
||||
func append(tool: WorkspaceTool, location: WorkspaceBarLocation) {
|
||||
self.bars[location]?.append(tool: tool)
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ class Workspace: NSView {
|
||||
// MARK: - Layout
|
||||
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
|
||||
// and remove them here by self.removeConstraints(${all constraints). The following seems to work...
|
||||
self.subviews.forEach { $0.removeAllConstraints() }
|
||||
@ -77,8 +77,8 @@ extension Workspace {
|
||||
let mainView = self.mainView
|
||||
self.addSubview(mainView)
|
||||
|
||||
mainView.autoSetDimension(.Width, toSize: self.config.mainViewMinimumSize.width, relation: .GreaterThanOrEqual)
|
||||
mainView.autoSetDimension(.Height, toSize: self.config.mainViewMinimumSize.height, relation: .GreaterThanOrEqual)
|
||||
mainView.autoSetDimension(.width, toSize: self.config.mainViewMinimumSize.width, relation: .greaterThanOrEqual)
|
||||
mainView.autoSetDimension(.height, toSize: self.config.mainViewMinimumSize.height, relation: .greaterThanOrEqual)
|
||||
|
||||
guard self.isBarVisible else {
|
||||
mainView.autoPinEdgesToSuperviewEdges()
|
||||
@ -95,35 +95,35 @@ extension Workspace {
|
||||
self.addSubview(bottomBar)
|
||||
self.addSubview(leftBar)
|
||||
|
||||
topBar.autoPinEdgeToSuperviewEdge(.Top)
|
||||
topBar.autoPinEdgeToSuperviewEdge(.Right)
|
||||
topBar.autoPinEdgeToSuperviewEdge(.Left)
|
||||
topBar.autoPinEdge(toSuperviewEdge: .top)
|
||||
topBar.autoPinEdge(toSuperviewEdge: .right)
|
||||
topBar.autoPinEdge(toSuperviewEdge: .left)
|
||||
|
||||
rightBar.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar)
|
||||
rightBar.autoPinEdgeToSuperviewEdge(.Right)
|
||||
rightBar.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar)
|
||||
rightBar.autoPinEdge(.top, to: .bottom, of: topBar)
|
||||
rightBar.autoPinEdge(toSuperviewEdge: .right)
|
||||
rightBar.autoPinEdge(.bottom, to: .top, of: bottomBar)
|
||||
|
||||
bottomBar.autoPinEdgeToSuperviewEdge(.Right)
|
||||
bottomBar.autoPinEdgeToSuperviewEdge(.Bottom)
|
||||
bottomBar.autoPinEdgeToSuperviewEdge(.Left)
|
||||
bottomBar.autoPinEdge(toSuperviewEdge: .right)
|
||||
bottomBar.autoPinEdge(toSuperviewEdge: .bottom)
|
||||
bottomBar.autoPinEdge(toSuperviewEdge: .left)
|
||||
|
||||
leftBar.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar)
|
||||
leftBar.autoPinEdgeToSuperviewEdge(.Left)
|
||||
leftBar.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar)
|
||||
leftBar.autoPinEdge(.top, to: .bottom, of: topBar)
|
||||
leftBar.autoPinEdge(toSuperviewEdge: .left)
|
||||
leftBar.autoPinEdge(.bottom, to: .top, of: bottomBar)
|
||||
|
||||
NSLayoutConstraint.autoSetPriority(NSLayoutPriorityDragThatCannotResizeWindow) {
|
||||
topBar.dimensionConstraint = topBar.autoSetDimension(.Height, toSize: 50)
|
||||
rightBar.dimensionConstraint = rightBar.autoSetDimension(.Width, toSize: 50)
|
||||
bottomBar.dimensionConstraint = bottomBar.autoSetDimension(.Height, toSize: 50)
|
||||
leftBar.dimensionConstraint = leftBar.autoSetDimension(.Width, toSize: 50)
|
||||
topBar.dimensionConstraint = topBar.autoSetDimension(.height, toSize: 50)
|
||||
rightBar.dimensionConstraint = rightBar.autoSetDimension(.width, toSize: 50)
|
||||
bottomBar.dimensionConstraint = bottomBar.autoSetDimension(.height, toSize: 50)
|
||||
leftBar.dimensionConstraint = leftBar.autoSetDimension(.width, toSize: 50)
|
||||
}
|
||||
|
||||
self.bars.values.forEach { $0.relayout() }
|
||||
|
||||
mainView.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar)
|
||||
mainView.autoPinEdge(.Right, toEdge: .Left, ofView: rightBar)
|
||||
mainView.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar)
|
||||
mainView.autoPinEdge(.Left, toEdge: .Right, ofView: leftBar)
|
||||
mainView.autoPinEdge(.top, to: .bottom, of: topBar)
|
||||
mainView.autoPinEdge(.right, to: .left, of: rightBar)
|
||||
mainView.autoPinEdge(.bottom, to: .top, of: bottomBar)
|
||||
mainView.autoPinEdge(.left, to: .right, of: leftBar)
|
||||
|
||||
self.needsDisplay = true
|
||||
}
|
||||
|
@ -8,16 +8,16 @@ import PureLayout
|
||||
|
||||
class WorkspaceBar: NSView, WorkspaceToolDelegate {
|
||||
|
||||
static private let separatorColor = NSColor.controlShadowColor()
|
||||
static private let separatorThickness = CGFloat(1)
|
||||
static fileprivate let separatorColor = NSColor.controlShadowColor
|
||||
static fileprivate let separatorThickness = CGFloat(1)
|
||||
|
||||
private var tools = [WorkspaceTool]()
|
||||
private weak var selectedTool: WorkspaceTool?
|
||||
fileprivate var tools = [WorkspaceTool]()
|
||||
fileprivate weak var selectedTool: WorkspaceTool?
|
||||
|
||||
private var isMouseDownOngoing = false
|
||||
private var dragIncrement = CGFloat(1)
|
||||
fileprivate var isMouseDownOngoing = false
|
||||
fileprivate var dragIncrement = CGFloat(1)
|
||||
|
||||
private var layoutConstraints = [NSLayoutConstraint]()
|
||||
fileprivate var layoutConstraints = [NSLayoutConstraint]()
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
@ -39,7 +39,7 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
|
||||
super.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
self.wantsLayer = true
|
||||
self.layer!.backgroundColor = NSColor.windowBackgroundColor().CGColor
|
||||
self.layer!.backgroundColor = NSColor.windowBackgroundColor.cgColor
|
||||
}
|
||||
|
||||
func relayout() {
|
||||
@ -47,7 +47,7 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
|
||||
self.removeAllSubviews()
|
||||
|
||||
if self.isEmpty() {
|
||||
self.set(dimension: 0)
|
||||
self.set(0)
|
||||
return
|
||||
}
|
||||
|
||||
@ -57,31 +57,31 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
|
||||
if self.isOpen() {
|
||||
let curTool = self.selectedTool!
|
||||
|
||||
self.layout(tool: curTool)
|
||||
self.layout(curTool)
|
||||
|
||||
let newDimension = self.barDimension(withToolDimension: curTool.dimension)
|
||||
self.set(dimension: newDimension)
|
||||
self.set(newDimension)
|
||||
} else {
|
||||
self.set(dimension: self.barDimensionWithButtonsWithoutTool())
|
||||
self.set(self.barDimensionWithButtonsWithoutTool())
|
||||
}
|
||||
|
||||
} else {
|
||||
if self.isOpen() {
|
||||
let curTool = self.selectedTool!
|
||||
|
||||
self.layoutWithoutButtons(tool: curTool)
|
||||
self.layoutWithoutButtons(curTool)
|
||||
|
||||
let newDimension = self.barDimensionWithoutButtons(withToolDimension: curTool.dimension)
|
||||
self.set(dimension: newDimension)
|
||||
self.set(newDimension)
|
||||
} else {
|
||||
self.set(dimension: 0)
|
||||
self.set(0)
|
||||
}
|
||||
}
|
||||
|
||||
self.needsDisplay = true
|
||||
}
|
||||
|
||||
func append(tool tool: WorkspaceTool) {
|
||||
func append(tool: WorkspaceTool) {
|
||||
tool.delegate = self
|
||||
tool.location = self.location
|
||||
tools.append(tool)
|
||||
@ -98,8 +98,8 @@ class WorkspaceBar: NSView, WorkspaceToolDelegate {
|
||||
// MARK: - NSView
|
||||
extension WorkspaceBar {
|
||||
|
||||
override func drawRect(dirtyRect: NSRect) {
|
||||
super.drawRect(dirtyRect)
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
|
||||
if self.isButtonVisible {
|
||||
self.drawInnerSeparator(dirtyRect)
|
||||
@ -110,7 +110,7 @@ extension WorkspaceBar {
|
||||
}
|
||||
}
|
||||
|
||||
override func mouseDown(event: NSEvent) {
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
guard self.isOpen() else {
|
||||
return
|
||||
}
|
||||
@ -119,11 +119,11 @@ extension WorkspaceBar {
|
||||
return
|
||||
}
|
||||
|
||||
let initialMouseLoc = self.convertPoint(event.locationInWindow, fromView: nil)
|
||||
let mouseInResizeRect = NSMouseInRect(initialMouseLoc, self.resizeRect(), self.flipped)
|
||||
let initialMouseLoc = self.convert(event.locationInWindow, from: nil)
|
||||
let mouseInResizeRect = NSMouseInRect(initialMouseLoc, self.resizeRect(), self.isFlipped)
|
||||
|
||||
guard mouseInResizeRect && event.type == .LeftMouseDown else {
|
||||
super.mouseDown(event)
|
||||
guard mouseInResizeRect && event.type == .leftMouseDown else {
|
||||
super.mouseDown(with: event)
|
||||
return
|
||||
}
|
||||
|
||||
@ -133,14 +133,14 @@ extension WorkspaceBar {
|
||||
var dragged = false
|
||||
var curEvent = event
|
||||
let nextEventMask: NSEventMask = [
|
||||
NSEventMask.LeftMouseDraggedMask,
|
||||
NSEventMask.LeftMouseDownMask,
|
||||
NSEventMask.LeftMouseUpMask
|
||||
NSEventMask.leftMouseDragged,
|
||||
NSEventMask.leftMouseDown,
|
||||
NSEventMask.leftMouseUp
|
||||
]
|
||||
while curEvent.type != .LeftMouseUp {
|
||||
let nextEvent = NSApp.nextEventMatchingMask(Int(nextEventMask.rawValue),
|
||||
untilDate: NSDate.distantFuture(),
|
||||
inMode: NSEventTrackingRunLoopMode,
|
||||
while curEvent.type != .leftMouseUp {
|
||||
let nextEvent = NSApp.nextEvent(matching: NSEventMask(rawValue: UInt64(Int(nextEventMask.rawValue))),
|
||||
until: Date.distantFuture,
|
||||
inMode: RunLoopMode.eventTrackingRunLoopMode,
|
||||
dequeue: true)
|
||||
guard nextEvent != nil else {
|
||||
break
|
||||
@ -148,23 +148,23 @@ extension WorkspaceBar {
|
||||
|
||||
curEvent = nextEvent!
|
||||
|
||||
guard curEvent.type == .LeftMouseDragged else {
|
||||
guard curEvent.type == .leftMouseDragged else {
|
||||
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)
|
||||
|
||||
guard dragged || distance >= 1 else {
|
||||
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)
|
||||
|
||||
self.set(dimension: newDimension)
|
||||
self.set(newDimension)
|
||||
|
||||
self.window?.invalidateCursorRectsForView(self)
|
||||
self.window?.invalidateCursorRects(for: self)
|
||||
|
||||
dragged = true
|
||||
}
|
||||
@ -180,13 +180,13 @@ extension WorkspaceBar {
|
||||
|
||||
switch self.location {
|
||||
case .top, .bottom:
|
||||
self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeUpDownCursor())
|
||||
self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeUpDown())
|
||||
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()
|
||||
|
||||
let innerLineRect = self.innerSeparatorRect()
|
||||
@ -195,7 +195,7 @@ extension WorkspaceBar {
|
||||
}
|
||||
}
|
||||
|
||||
private func drawOuterSeparator(dirtyRect: NSRect) {
|
||||
fileprivate func drawOuterSeparator(_ dirtyRect: NSRect) {
|
||||
WorkspaceBar.separatorColor.set()
|
||||
|
||||
let outerLineRect = self.outerSeparatorRect()
|
||||
@ -204,7 +204,7 @@ extension WorkspaceBar {
|
||||
}
|
||||
}
|
||||
|
||||
private func buttonSize() -> CGSize {
|
||||
fileprivate func buttonSize() -> CGSize {
|
||||
if self.isEmpty() {
|
||||
return CGSize.zero
|
||||
}
|
||||
@ -212,7 +212,7 @@ extension WorkspaceBar {
|
||||
return self.tools.first!.button.intrinsicContentSize
|
||||
}
|
||||
|
||||
private func innerSeparatorRect() -> CGRect {
|
||||
fileprivate func innerSeparatorRect() -> CGRect {
|
||||
let bounds = self.bounds
|
||||
let thickness = WorkspaceBar.separatorThickness
|
||||
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)
|
||||
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
|
||||
|
||||
switch self.location {
|
||||
@ -249,11 +249,11 @@ extension WorkspaceBar {
|
||||
}
|
||||
}
|
||||
|
||||
private func sq(number: CGFloat) -> CGFloat {
|
||||
fileprivate func sq(_ number: CGFloat) -> CGFloat {
|
||||
return number * number
|
||||
}
|
||||
|
||||
private func outerSeparatorRect() -> CGRect {
|
||||
fileprivate func outerSeparatorRect() -> CGRect {
|
||||
let thickness = WorkspaceBar.separatorThickness
|
||||
|
||||
switch self.location {
|
||||
@ -268,7 +268,7 @@ extension WorkspaceBar {
|
||||
}
|
||||
}
|
||||
|
||||
private func resizeRect() -> CGRect {
|
||||
fileprivate func resizeRect() -> CGRect {
|
||||
let separatorRect = self.outerSeparatorRect()
|
||||
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
|
||||
|
||||
let toolDimension = self.toolDimension(fromBarDimension: dimension)
|
||||
@ -297,64 +297,64 @@ extension WorkspaceBar {
|
||||
// MARK: - Layout
|
||||
extension WorkspaceBar {
|
||||
|
||||
private func isEmpty() -> Bool {
|
||||
fileprivate func isEmpty() -> Bool {
|
||||
return self.tools.isEmpty
|
||||
}
|
||||
|
||||
private func hasTools() -> Bool {
|
||||
fileprivate func hasTools() -> Bool {
|
||||
return !self.isEmpty()
|
||||
}
|
||||
|
||||
private func isOpen() -> Bool {
|
||||
fileprivate func isOpen() -> Bool {
|
||||
return self.selectedTool != nil
|
||||
}
|
||||
|
||||
private func layoutWithoutButtons(tool tool: WorkspaceTool) {
|
||||
fileprivate func layoutWithoutButtons(_ tool: WorkspaceTool) {
|
||||
let view = tool.view
|
||||
let thickness = WorkspaceBar.separatorThickness
|
||||
|
||||
self.addSubview(view)
|
||||
switch self.location {
|
||||
case .top:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right),
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom, withInset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top),
|
||||
view.autoPinEdge(toSuperviewEdge: .right),
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom, withInset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .left),
|
||||
|
||||
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
|
||||
view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
|
||||
])
|
||||
case .right:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right),
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
view.autoPinEdgeToSuperviewEdge(.Left, withInset: thickness),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top),
|
||||
view.autoPinEdge(toSuperviewEdge: .right),
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
view.autoPinEdge(toSuperviewEdge: .left, withInset: thickness),
|
||||
|
||||
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
|
||||
view.autoSetDimension(.width, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
|
||||
])
|
||||
case .bottom:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top, withInset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right),
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
view.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top, withInset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .right),
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
view.autoPinEdge(toSuperviewEdge: .left),
|
||||
|
||||
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
|
||||
view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
|
||||
])
|
||||
case .left:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right, withInset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
view.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top),
|
||||
view.autoPinEdge(toSuperviewEdge: .right, withInset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
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 button = tool.button
|
||||
let thickness = WorkspaceBar.separatorThickness
|
||||
@ -363,45 +363,45 @@ extension WorkspaceBar {
|
||||
|
||||
switch self.location {
|
||||
case .top:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdge(.Top, toEdge: .Bottom, ofView: button, withOffset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right),
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom, withInset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(.top, to: .bottom, of: button, withOffset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .right),
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom, withInset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .left),
|
||||
|
||||
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
|
||||
view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
|
||||
])
|
||||
case .right:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top),
|
||||
view.autoPinEdge(.Right, toEdge: .Left, ofView: button, withOffset: -thickness), // Offset is count l -> r,
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
view.autoPinEdgeToSuperviewEdge(.Left, withInset: thickness),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top),
|
||||
view.autoPinEdge(.right, to: .left, of: button, withOffset: -thickness), // Offset is count l -> r,
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
view.autoPinEdge(toSuperviewEdge: .left, withInset: thickness),
|
||||
|
||||
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
|
||||
view.autoSetDimension(.width, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
|
||||
])
|
||||
case .bottom:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top, withInset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right),
|
||||
view.autoPinEdge(.Bottom, toEdge: .Top, ofView: button, withOffset: -thickness), // Offset is count t -> b,
|
||||
view.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top, withInset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .right),
|
||||
view.autoPinEdge(.bottom, to: .top, of: button, withOffset: -thickness), // Offset is count t -> b,
|
||||
view.autoPinEdge(toSuperviewEdge: .left),
|
||||
|
||||
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
|
||||
view.autoSetDimension(.height, toSize: tool.minimumDimension, relation: .greaterThanOrEqual)
|
||||
])
|
||||
case .left:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
view.autoPinEdgeToSuperviewEdge(.Top),
|
||||
view.autoPinEdgeToSuperviewEdge(.Right, withInset: thickness),
|
||||
view.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
view.autoPinEdge(.Left, toEdge: .Right, ofView: button, withOffset: thickness),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
view.autoPinEdge(toSuperviewEdge: .top),
|
||||
view.autoPinEdge(toSuperviewEdge: .right, withInset: thickness),
|
||||
view.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -413,24 +413,24 @@ extension WorkspaceBar {
|
||||
let firstButton = firstTool.button
|
||||
switch self.location {
|
||||
case .top:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Top),
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .top),
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .left),
|
||||
])
|
||||
case .right:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Top),
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Right),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .top),
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .right),
|
||||
])
|
||||
case .bottom:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Left),
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .left),
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
])
|
||||
case .left:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Top),
|
||||
firstButton.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .top),
|
||||
firstButton.autoPinEdge(toSuperviewEdge: .left),
|
||||
])
|
||||
}
|
||||
|
||||
@ -438,24 +438,24 @@ extension WorkspaceBar {
|
||||
for button in self.tools[1..<self.tools.count].map({ $0.button }) {
|
||||
switch self.location {
|
||||
case .top:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
button.autoPinEdgeToSuperviewEdge(.Top),
|
||||
button.autoPinEdge(.Left, toEdge: .Right, ofView: lastButton),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
button.autoPinEdge(toSuperviewEdge: .top),
|
||||
button.autoPinEdge(.left, to: .right, of: lastButton),
|
||||
])
|
||||
case .right:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: lastButton),
|
||||
button.autoPinEdgeToSuperviewEdge(.Right),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
button.autoPinEdge(.top, to: .bottom, of: lastButton),
|
||||
button.autoPinEdge(toSuperviewEdge: .right),
|
||||
])
|
||||
case .bottom:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
button.autoPinEdge(.Left, toEdge: .Right, ofView: lastButton),
|
||||
button.autoPinEdgeToSuperviewEdge(.Bottom),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
button.autoPinEdge(.left, to: .right, of: lastButton),
|
||||
button.autoPinEdge(toSuperviewEdge: .bottom),
|
||||
])
|
||||
case .left:
|
||||
self.layoutConstraints.appendContentsOf([
|
||||
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: lastButton),
|
||||
button.autoPinEdgeToSuperviewEdge(.Left),
|
||||
self.layoutConstraints.append(contentsOf: [
|
||||
button.autoPinEdge(.top, to: .bottom, of: lastButton),
|
||||
button.autoPinEdge(toSuperviewEdge: .left),
|
||||
])
|
||||
}
|
||||
|
||||
@ -463,7 +463,7 @@ extension WorkspaceBar {
|
||||
}
|
||||
}
|
||||
|
||||
private func barDimensionWithButtonsWithoutTool() -> CGFloat {
|
||||
fileprivate func barDimensionWithButtonsWithoutTool() -> CGFloat {
|
||||
switch self.location {
|
||||
case .top, .bottom:
|
||||
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
|
||||
}
|
||||
|
||||
private func barDimension(withToolDimension toolDimension: CGFloat) -> CGFloat {
|
||||
fileprivate func barDimension(withToolDimension toolDimension: CGFloat) -> CGFloat {
|
||||
return self.barDimensionWithButtonsWithoutTool() + toolDimension + WorkspaceBar.separatorThickness
|
||||
}
|
||||
|
||||
private func toolDimension(fromBarDimension barDimension: CGFloat) -> CGFloat {
|
||||
fileprivate func toolDimension(fromBarDimension barDimension: CGFloat) -> CGFloat {
|
||||
if self.isButtonVisible {
|
||||
return barDimension - WorkspaceBar.separatorThickness - barDimensionWithButtonsWithoutTool()
|
||||
}
|
||||
@ -492,7 +492,7 @@ extension WorkspaceBar {
|
||||
// MARK: - WorkspaceToolDelegate
|
||||
extension WorkspaceBar {
|
||||
|
||||
func toggle(tool tool: WorkspaceTool) {
|
||||
func toggle(_ tool: WorkspaceTool) {
|
||||
if self.isOpen() {
|
||||
let curTool = self.selectedTool!
|
||||
if curTool === tool {
|
||||
|
@ -7,7 +7,7 @@ import Cocoa
|
||||
|
||||
protocol WorkspaceToolDelegate: class {
|
||||
|
||||
func toggle(tool tool: WorkspaceTool)
|
||||
func toggle(_ tool: WorkspaceTool)
|
||||
}
|
||||
|
||||
class WorkspaceTool {
|
||||
@ -46,7 +46,7 @@ class WorkspaceTool {
|
||||
}
|
||||
|
||||
func toggle() {
|
||||
self.delegate?.toggle(tool: self)
|
||||
self.delegate?.toggle(self)
|
||||
self.isSelected = !self.isSelected
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import Cocoa
|
||||
|
||||
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
|
||||
private var trackingArea = NSTrackingArea()
|
||||
fileprivate let title: NSAttributedString
|
||||
fileprivate var trackingArea = NSTrackingArea()
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
@ -26,7 +26,7 @@ class WorkspaceToolButton: NSView {
|
||||
|
||||
init(title: String) {
|
||||
self.title = NSAttributedString(string: title, attributes: [
|
||||
NSFontAttributeName: NSFont.systemFontOfSize(11)
|
||||
NSFontAttributeName: NSFont.systemFont(ofSize: 11)
|
||||
])
|
||||
|
||||
super.init(frame: CGRect.zero)
|
||||
@ -36,11 +36,11 @@ class WorkspaceToolButton: NSView {
|
||||
}
|
||||
|
||||
func highlight() {
|
||||
self.layer?.backgroundColor = NSColor.controlShadowColor().CGColor
|
||||
self.layer?.backgroundColor = NSColor.controlShadowColor.cgColor
|
||||
}
|
||||
|
||||
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) {
|
||||
super.drawRect(dirtyRect)
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
|
||||
let padding = WorkspaceToolButton.titlePadding
|
||||
switch self.location {
|
||||
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:
|
||||
self.title.draw(at: CGPoint(x: padding.height, y: self.bounds.height - padding.width), angle: -CGFloat(M_PI_2))
|
||||
case .left:
|
||||
@ -77,7 +77,7 @@ extension WorkspaceToolButton {
|
||||
self.removeTrackingArea(self.trackingArea)
|
||||
|
||||
self.trackingArea = NSTrackingArea(rect: self.bounds,
|
||||
options: [.MouseEnteredAndExited, .ActiveInActiveApp],
|
||||
options: [.mouseEnteredAndExited, .activeInActiveApp],
|
||||
owner: self,
|
||||
userInfo: nil)
|
||||
self.addTrackingArea(self.trackingArea)
|
||||
@ -85,11 +85,11 @@ extension WorkspaceToolButton {
|
||||
super.updateTrackingAreas()
|
||||
}
|
||||
|
||||
override func mouseDown(event: NSEvent) {
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
self.tool?.toggle()
|
||||
}
|
||||
|
||||
override func mouseEntered(_: NSEvent) {
|
||||
override func mouseEntered(with _: NSEvent) {
|
||||
if self.isSelected {
|
||||
return
|
||||
}
|
||||
@ -97,7 +97,7 @@ extension WorkspaceToolButton {
|
||||
self.highlight()
|
||||
}
|
||||
|
||||
override func mouseExited(_: NSEvent) {
|
||||
override func mouseExited(with _: NSEvent) {
|
||||
if self.isSelected {
|
||||
return
|
||||
}
|
||||
|
@ -8,17 +8,17 @@ import Nimble
|
||||
|
||||
class FileUtilsTest: XCTestCase {
|
||||
|
||||
var fileUtilsRsrcUrl = NSURL()
|
||||
var a1Dir = NSURL()
|
||||
var fileUtilsRsrcUrl = URL()
|
||||
var a1Dir = URL()
|
||||
|
||||
override func setUp() {
|
||||
fileUtilsRsrcUrl = NSBundle.init(forClass: self.dynamicType).URLForResource("FileUtilsTest", withExtension: "")!
|
||||
a1Dir = fileUtilsRsrcUrl.URLByAppendingPathComponent("a1")
|
||||
fileUtilsRsrcUrl = Bundle.init(for: type(of: self)).url(forResource: "FileUtilsTest", withExtension: "")!
|
||||
a1Dir = fileUtilsRsrcUrl.appendingPathComponent("a1")
|
||||
}
|
||||
|
||||
func testCommonParentOneDirUrl() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
@ -26,20 +26,20 @@ class FileUtilsTest: XCTestCase {
|
||||
|
||||
func testCommonParentOneFileUrl() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
}
|
||||
|
||||
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() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
@ -47,9 +47,9 @@ class FileUtilsTest: XCTestCase {
|
||||
|
||||
func testCommonParent2() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
@ -57,10 +57,10 @@ class FileUtilsTest: XCTestCase {
|
||||
|
||||
func testCommonParent3() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("b1/b1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("b1/b1-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl))
|
||||
@ -68,10 +68,10 @@ class FileUtilsTest: XCTestCase {
|
||||
|
||||
func testCommonParent4() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("b1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("b1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl))
|
||||
@ -79,9 +79,9 @@ class FileUtilsTest: XCTestCase {
|
||||
|
||||
func testCommonParent5() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.appendingPathComponent("a1/a2"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
|
@ -9,11 +9,11 @@ import Nimble
|
||||
class ScorerTest: XCTestCase {
|
||||
|
||||
func testScore1() {
|
||||
let pattern = "sw/nvv".stringByReplacingOccurrencesOfString("/", withString: "")
|
||||
let pattern = "sw/nvv".replacingOccurrences(of: "/", with: "")
|
||||
let targets = [
|
||||
"SwiftNeoVim/NeoVimView.swift",
|
||||
"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)))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user