1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-08-16 20:20:28 +03:00

Extract Commons

This commit is contained in:
Tae Won Ha 2020-08-18 23:07:22 +02:00
parent 2cb2fde084
commit ca77228249
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
26 changed files with 457 additions and 549 deletions

5
Commons/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/

24
Commons/Package.swift Normal file
View File

@ -0,0 +1,24 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "Commons",
platforms: [.macOS(.v10_13)],
products: [
.library(
name: "Commons",
targets: ["Commons"]),
],
dependencies: [],
targets: [
.target(
name: "Commons",
dependencies: []
),
.testTarget(
name: "CommonsTests",
dependencies: ["Commons"]
),
]
)

3
Commons/README.md Normal file
View File

@ -0,0 +1,3 @@
# Commons
A description of this package.

View File

@ -0,0 +1,128 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import AppKit
public extension NSColor {
static var random: NSColor {
NSColor(
calibratedRed: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0
)
}
var int: Int {
if let color = self.usingColorSpace(.sRGB) {
let a = Int(color.alphaComponent * 255)
let r = Int(color.redComponent * 255)
let g = Int(color.greenComponent * 255)
let b = Int(color.blueComponent * 255)
return a << 24 | r << 16 | g << 8 | b
} else {
return 0
}
}
var hex: String { String(String(format: "%06X", self.int).suffix(6)) }
convenience init(rgb: Int) {
// @formatter:off
let red = ((rgb >> 16) & 0xFF).cgf / 255.0;
let green = ((rgb >> 8) & 0xFF).cgf / 255.0;
let blue = ((rgb ) & 0xFF).cgf / 255.0;
// @formatter:on
self.init(srgbRed: red, green: green, blue: blue, alpha: 1.0)
}
convenience init?(hex: String) {
var result: UInt32 = 0
guard hex.count == 6, Scanner(string: hex).scanHexInt32(&result) else { return nil }
let r = (result & 0xFF0000) >> 16
let g = (result & 0x00FF00) >> 8
let b = (result & 0x0000FF)
self.init(srgbRed: r.cgf / 255, green: g.cgf / 255, blue: b.cgf / 255, alpha: 1)
}
func brightening(by factor: CGFloat) -> NSColor {
guard let color = self.usingColorSpace(.sRGB) else { return self }
let h = color.hueComponent
let s = color.saturationComponent
let b = color.brightnessComponent
let a = color.alphaComponent
return NSColor(hue: h, saturation: s, brightness: b * factor, alpha: a)
}
}
public extension NSImage {
func tinting(with color: NSColor) -> NSImage {
let result = self.copy() as! NSImage
result.lockFocus()
color.set()
CGRect(origin: .zero, size: self.size).fill(using: .sourceAtop)
result.unlockFocus()
return result
}
}
public extension NSButton {
var boolState: Bool {
get { self.state == .on ? true : false }
set { self.state = newValue ? .on : .off }
}
}
public extension NSMenuItem {
var boolState: Bool {
get { self.state == .on ? true : false }
set { self.state = newValue ? .on : .off }
}
}
public extension NSView {
func removeAllSubviews() { self.subviews.forEach { $0.removeFromSuperview() } }
func removeAllConstraints() { self.removeConstraints(self.constraints) }
func beFirstResponder() { self.window?.makeFirstResponder(self) }
/// - Returns: Rects currently being drawn
/// - Warning: Call only in drawRect()
func rectsBeingDrawn() -> [CGRect] {
var rectsPtr: UnsafePointer<CGRect>? = nil
var count: Int = 0
self.getRectsBeingDrawn(&rectsPtr, count: &count)
return Array(UnsafeBufferPointer(start: rectsPtr, count: count))
}
}
public extension NSEvent.ModifierFlags {
// Values are from https://github.com/SFML/SFML/blob/master/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm
// @formatter:off
static let rightShift = NSEvent.ModifierFlags(rawValue: 0x020004)
static let leftShift = NSEvent.ModifierFlags(rawValue: 0x020002)
static let rightCommand = NSEvent.ModifierFlags(rawValue: 0x100010)
static let leftCommand = NSEvent.ModifierFlags(rawValue: 0x100008)
static let rightOption = NSEvent.ModifierFlags(rawValue: 0x080040)
static let leftOption = NSEvent.ModifierFlags(rawValue: 0x080020)
static let rightControl = NSEvent.ModifierFlags(rawValue: 0x042000)
static let leftControl = NSEvent.ModifierFlags(rawValue: 0x040001)
// @formatter:on
}

View File

@ -5,21 +5,21 @@
import Foundation
extension CFRange {
public extension CFRange {
static let zero = CFRange(location: 0, length: 0)
}
extension CGSize {
public extension CGSize {
func scaling(_ factor: CGFloat) -> CGSize {
return CGSize(width: self.width * factor, height: self.height * factor)
}
}
extension CGRect {
public extension CGRect {
public var hashValue: Int {
var hashValue: Int {
let o = Int(self.origin.x) << 10 ^ Int(self.origin.y)
let s = Int(self.size.width) << 10 ^ Int(self.size.height)
return o + s

View File

@ -0,0 +1,185 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
public extension Array where Element: Hashable {
// From https://stackoverflow.com/a/46354989/9850227
func uniqued() -> [Element] {
var seen = Set<Element>()
return self.filter { seen.insert($0).inserted }
}
}
public extension Array {
func data() -> Data {
return self.withUnsafeBufferPointer(Data.init)
}
}
public extension RandomAccessCollection where Index == Int {
func parallelMap<T>(
chunkSize: Int = 1,
_ transform: @escaping (Element) -> T
) -> [T] {
let count = self.count
guard count > chunkSize else { return self.map(transform) }
var result = Array<T?>(repeating: nil, count: count)
// If we don't use Array.withUnsafeMutableBufferPointer,
// then we get crashes.
result.withUnsafeMutableBufferPointer { pointer in
if chunkSize == 1 {
DispatchQueue.concurrentPerform(iterations: count) { i in
pointer[i] = transform(self[i])
}
} else {
let chunkCount = Int(ceil(Double(self.count) / Double(chunkSize)))
DispatchQueue.concurrentPerform(iterations: chunkCount) { chunkIndex in
let start = Swift.min(chunkIndex * chunkSize, count)
let end = Swift.min(start + chunkSize, count)
(start..<end).forEach { i in pointer[i] = transform(self[i]) }
}
}
}
return result.map { $0! }
}
func groupedRanges<T: Equatable>(
with marker: (Index, Element) -> T
) -> [CountableClosedRange<Index>] {
if self.isEmpty {
return []
}
if self.count == 1 {
return [self.startIndex...self.startIndex]
}
var result = [CountableClosedRange<Index>]()
result.reserveCapacity(self.count / 2)
let inclusiveEndIndex = self.endIndex - 1
var lastStartIndex = self.startIndex
var lastEndIndex = self.startIndex
var lastMarker = marker(0, self.first!) // self is not empty!
for i in self.startIndex..<self.endIndex {
defer { lastEndIndex = i }
let currentMarker = marker(i, self[i])
if lastMarker == currentMarker {
if i == inclusiveEndIndex {
result.append(lastStartIndex...i)
}
} else {
result.append(lastStartIndex...lastEndIndex)
lastMarker = currentMarker
lastStartIndex = i
if i == inclusiveEndIndex {
result.append(i...i)
}
}
}
return result
}
}
public extension NSRange {
static let notFound = NSRange(location: NSNotFound, length: 0)
var inclusiveEndIndex: Int { self.location + self.length - 1 }
}
public extension URL {
func isDirectParent(of url: URL) -> Bool {
guard self.isFileURL && url.isFileURL else { return false }
let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents
guard targetPathComps.count == myPathComps.count + 1 else { return false }
return Array(targetPathComps[0..<myPathComps.count]) == myPathComps
}
func isParent(of url: URL) -> Bool {
guard self.isFileURL && url.isFileURL else { return false }
let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents
guard targetPathComps.count > myPathComps.count else { return false }
return Array(targetPathComps[0..<myPathComps.count]) == myPathComps
}
func isContained(in parentUrl: URL) -> Bool {
if parentUrl == self { return false }
let pathComps = self.pathComponents
let parentPathComps = parentUrl.pathComponents
guard pathComps.count > parentPathComps.count else { return false }
guard Array(pathComps[0..<parentPathComps.endIndex]) == parentPathComps else { return false }
return true
}
var parent: URL {
if self.path == "/" { return self }
return self.deletingLastPathComponent()
}
var isDir: Bool { self.resourceValue(URLResourceKey.isDirectoryKey.rawValue) }
var isHidden: Bool { self.resourceValue(URLResourceKey.isHiddenKey.rawValue) }
var isPackage: Bool { self.resourceValue(URLResourceKey.isPackageKey.rawValue) }
/// Wrapper function for NSURL.getResourceValue for Bool values.
/// Returns also `false` when
/// - there is no value for the given `key` or
/// - the value cannot be converted to `NSNumber`.
///
/// - parameters:
/// - key: The `key`-parameter of `NSURL.getResourceValue`.
private func resourceValue(_ key: String) -> Bool {
var rsrc: AnyObject?
do {
try (self as NSURL).getResourceValue(&rsrc, forKey: URLResourceKey(rawValue: key))
} catch let error as NSError {
// FIXME error handling
log.error("ERROR while getting \(key): \(error)")
return false
}
if let result = rsrc as? NSNumber { return result.boolValue }
return false
}
}
public extension ValueTransformer {
static var keyedUnarchiveFromDataTransformer
= ValueTransformer(forName: .keyedUnarchiveFromDataTransformerName)!
}
private let log = OSLog(subsystem: "com.qvacua.vimr.commons", category: "general")

View File

@ -6,7 +6,7 @@
import Foundation
import os
extension OSLog {
public extension OSLog {
func trace<T>(
file: String = #file,

View File

@ -5,19 +5,19 @@
import Foundation
func identity<T>(_ input: T) -> T { input }
public func identity<T>(_ input: T) -> T { input }
extension BinaryFloatingPoint {
public extension BinaryFloatingPoint {
var cgf: CGFloat { CGFloat(self) }
}
extension FixedWidthInteger {
public extension FixedWidthInteger {
var cgf: CGFloat { CGFloat(self) }
}
extension String {
public extension String {
func without(prefix: String) -> String {
guard self.hasPrefix(prefix) else { return self }
@ -27,7 +27,7 @@ extension String {
}
}
extension Array where Element: Equatable {
public extension Array where Element: Equatable {
func removingDuplicatesPreservingFromBeginning() -> [Element] {
var result = [Element]()
@ -57,7 +57,7 @@ extension Array where Element: Equatable {
}
}
extension Array where Element: Hashable {
public extension Array where Element: Hashable {
func toDict<V>(by mapper: @escaping (Element) -> V) -> Dictionary<Element, V> {
var result = Dictionary<Element, V>(minimumCapacity: self.count)
@ -82,7 +82,7 @@ func tuplesToDict<K: Hashable, V, S: Sequence>(_ sequence: S)
return result
}
extension Dictionary {
public extension Dictionary {
func mapToDict<K, V>(_ transform: ((key: Key, value: Value)) throws -> (K, V)) rethrows
-> Dictionary<K, V> {
@ -97,7 +97,7 @@ extension Dictionary {
}
}
extension Sequence {
public extension Sequence {
@discardableResult
func log() -> Self {

View File

@ -0,0 +1,15 @@
import XCTest
@testable import Commons
final class CommonsTests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(Commons().text, "Hello, World!")
}
static var allTests = [
("testExample", testExample),
]
}

View File

@ -0,0 +1,9 @@
import XCTest
#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(CommonsTests.allTests),
]
}
#endif

View File

@ -0,0 +1,7 @@
import XCTest
import CommonsTests
var tests = [XCTestCaseEntry]()
tests += CommonsTests.allTests()
XCTMain(tests)

View File

@ -13,11 +13,12 @@ let package = Package(
.package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMinor(from: "5.1.1")),
.package(name: "NvimServerTypes", url: "https://github.com/qvacua/neovim", .exact("0.1.0-types")),
.package(name: "RxPack", path: "../RxPack"),
.package(name: "Commons", path: "../Commons"),
],
targets: [
.target(
name: "NvimView",
dependencies: ["RxSwift", "NvimServerTypes", "RxPack", "MessagePack"],
dependencies: ["RxSwift", "NvimServerTypes", "RxPack", "MessagePack", "Commons"],
// com.qvacua.NvimView.vim is copied by the download NvimServer script.
exclude: ["com.qvacua.NvimView.vim"],
resources: [

View File

@ -6,6 +6,7 @@
import Cocoa
import MessagePack
import NvimServerTypes
import Commons
public struct CellAttributes: CustomStringConvertible, Equatable {

View File

@ -1,58 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
extension NSRange {
static let notFound = NSRange(location: NSNotFound, length: 0)
var inclusiveEndIndex: Int { self.location + self.length - 1 }
}
extension NSColor {
var int: Int {
if let color = self.usingColorSpace(.sRGB) {
let a = Int(color.alphaComponent * 255)
let r = Int(color.redComponent * 255)
let g = Int(color.greenComponent * 255)
let b = Int(color.blueComponent * 255)
return a << 24 | r << 16 | g << 8 | b
} else {
return 0
}
}
var hex: String { String(format: "%X", self.int) }
}
extension NSView {
/// - Returns: Rects currently being drawn
/// - Warning: Call only in drawRect()
func rectsBeingDrawn() -> [CGRect] {
var rectsPtr: UnsafePointer<CGRect>? = nil
var count: Int = 0
self.getRectsBeingDrawn(&rectsPtr, count: &count)
return Array(UnsafeBufferPointer(start: rectsPtr, count: count))
}
}
extension NSEvent.ModifierFlags {
// Values are from https://github.com/SFML/SFML/blob/master/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm
// @formatter:off
static let rightShift = NSEvent.ModifierFlags(rawValue: 0x020004)
static let leftShift = NSEvent.ModifierFlags(rawValue: 0x020002)
static let rightCommand = NSEvent.ModifierFlags(rawValue: 0x100010)
static let leftCommand = NSEvent.ModifierFlags(rawValue: 0x100008)
static let rightOption = NSEvent.ModifierFlags(rawValue: 0x080040)
static let leftOption = NSEvent.ModifierFlags(rawValue: 0x080020)
static let rightControl = NSEvent.ModifierFlags(rawValue: 0x042000)
static let leftControl = NSEvent.ModifierFlags(rawValue: 0x040001)
// @formatter:on
}

View File

@ -1,114 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
extension OSLog {
func trace<T>(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: T
) {
#if TRACE
self.log(
type: .debug,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)] [TRACE]"
)
#endif
}
func debug(
file: String = #file,
function: String = #function,
line: Int = #line
) {
#if DEBUG
self.log(
type: .debug,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)]"
)
#endif
}
func debug<T>(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: T
) {
#if DEBUG
self.log(
type: .debug,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
#endif
}
func info<T>(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: T
) {
self.log(
type: .info,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
}
func `default`<T>(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: T
) {
self.log(
type: .default,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
}
func error<T>(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: T
) {
self.log(
type: .error,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
}
func fault<T>(
file: String = #file,
function: String = #function,
line: Int = #line,
_ msg: T
) {
self.log(
type: .fault,
msg: "%{public}@",
"[\((file as NSString).lastPathComponent) - \(function):\(line)] \(msg)"
)
}
private func log(
type: OSLogType,
msg: StaticString,
_ object: CVarArg
) {
os_log(msg, log: self, type: type, object)
}
}

View File

@ -1,111 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
extension BinaryFloatingPoint {
var cgf: CGFloat {
return CGFloat(self)
}
}
extension FixedWidthInteger {
var cgf: CGFloat {
return CGFloat(self)
}
}
extension Array where Element: Hashable {
// From https://stackoverflow.com/a/46354989/9850227
func uniqued() -> [Element] {
var seen = Set<Element>()
return self.filter { seen.insert($0).inserted }
}
}
extension Array {
func data() -> Data {
return self.withUnsafeBufferPointer(Data.init)
}
}
extension RandomAccessCollection where Index == Int {
func parallelMap<T>(
chunkSize: Int = 1,
_ transform: @escaping (Element) -> T
) -> [T] {
let count = self.count
guard count > chunkSize else { return self.map(transform) }
var result = Array<T?>(repeating: nil, count: count)
// If we don't use Array.withUnsafeMutableBufferPointer,
// then we get crashes.
result.withUnsafeMutableBufferPointer { pointer in
if chunkSize == 1 {
DispatchQueue.concurrentPerform(iterations: count) { i in
pointer[i] = transform(self[i])
}
} else {
let chunkCount = Int(ceil(Double(self.count) / Double(chunkSize)))
DispatchQueue.concurrentPerform(iterations: chunkCount) { chunkIndex in
let start = Swift.min(chunkIndex * chunkSize, count)
let end = Swift.min(start + chunkSize, count)
(start..<end).forEach { i in pointer[i] = transform(self[i]) }
}
}
}
return result.map { $0! }
}
func groupedRanges<T: Equatable>(
with marker: (Index, Element) -> T
) -> [CountableClosedRange<Index>] {
if self.isEmpty {
return []
}
if self.count == 1 {
return [self.startIndex...self.startIndex]
}
var result = [CountableClosedRange<Index>]()
result.reserveCapacity(self.count / 2)
let inclusiveEndIndex = self.endIndex - 1
var lastStartIndex = self.startIndex
var lastEndIndex = self.startIndex
var lastMarker = marker(0, self.first!) // self is not empty!
for i in self.startIndex..<self.endIndex {
defer { lastEndIndex = i }
let currentMarker = marker(i, self[i])
if lastMarker == currentMarker {
if i == inclusiveEndIndex {
result.append(lastStartIndex...i)
}
} else {
result.append(lastStartIndex...lastEndIndex)
lastMarker = currentMarker
lastStartIndex = i
if i == inclusiveEndIndex {
result.append(i...i)
}
}
}
return result
}
}

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Commons">
</FileRef>
<FileRef
location = "group:RxPack">
</FileRef>

View File

@ -51,7 +51,7 @@
"repositoryURL": "https://github.com/qvacua/neovim",
"state": {
"branch": null,
"revision": "246da2521cdf3720b11a5045720d2ae1497a9268",
"revision": "13be312e380e7f93878486c8851a605a4e7af0eb",
"version": "0.1.0-types"
}
},

View File

@ -7,7 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
1929B0153C780675EE33F9EC /* AttributedStringMarkdownStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD6439FB8568CD045A41 /* AttributedStringMarkdownStyler.swift */; };
1929B04CE8ECBD75CBBB0991 /* StringCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5D45C9792BBE76B8AFF /* StringCommonsTest.swift */; };
1929B05B9D664052EC2D23EF /* FileOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BCE3E156C06EDF1F2806 /* FileOutlineView.swift */; };
1929B0C7150100A84FBDB8BF /* ShortcutItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF230875DED6CD7AB3EB /* ShortcutItem.swift */; };
@ -31,7 +30,6 @@
1929B4B00D7BB191A9A6532D /* HtmlPreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */; };
1929B4B70926DE113E6BF990 /* MarkdownPreviewReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE37AA2843779CAFA76F /* MarkdownPreviewReducer.swift */; };
1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B67A10E6BB2986B2416E /* BufferListReducer.swift */; };
1929B4E8B916008399CD5D3A /* OSLogCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE867BD8F0ED0246CC94 /* OSLogCommons.swift */; };
1929B4F0612224E594E89B92 /* AppearancePref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0FBFB766042CF06E463 /* AppearancePref.swift */; };
1929B4FEE6EB56EF3F56B805 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B34FC23D805A8B29E8F7 /* Context.swift */; };
1929B50D933A369A86A165DE /* AdvencedPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */; };
@ -96,8 +94,6 @@
4B6423981D8EFDE000FC78C8 /* WorkspaceBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423971D8EFDE000FC78C8 /* WorkspaceBar.swift */; };
4B64239A1D8EFE3000FC78C8 /* WorkspaceTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */; };
4B6A70941D60E04200E12030 /* AppKitCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70931D60E04200E12030 /* AppKitCommons.swift */; };
4B6A70961D6100E300E12030 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70951D6100E300E12030 /* SwiftCommons.swift */; };
4B6DFB3A22366D140066BB43 /* OSLogCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE867BD8F0ED0246CC94 /* OSLogCommons.swift */; };
4B9433DC20B95EC6005807BA /* MacVim-bsh.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4B9433A120B95EC1005807BA /* MacVim-bsh.icns */; };
4B9433DD20B95EC6005807BA /* MacVim-generic.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4B9433A220B95EC1005807BA /* MacVim-generic.icns */; };
4B9433DE20B95EC6005807BA /* MacVim-dylan.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4B9433A320B95EC1005807BA /* MacVim-dylan.icns */; };
@ -160,7 +156,6 @@
4B96FB3C1EBBC56F00E4E164 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
4B96FB3F1EBBC56F00E4E164 /* PrefUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */; };
4B96FB401EBBC56F00E4E164 /* FoundationCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */; };
4B96FB421EBBC56F00E4E164 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70951D6100E300E12030 /* SwiftCommons.swift */; };
4B97E2CC1D33F53D00FC0660 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B97E2CE1D33F53D00FC0660 /* MainWindow.xib */; };
4B9BC41E24EB2E22000209B5 /* MessagePack in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9BC41D24EB2E22000209B5 /* MessagePack */; };
4B9BC42124EB2E45000209B5 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9BC42024EB2E45000209B5 /* RxCocoa */; };
@ -178,6 +173,7 @@
4BD5657824E8443300D52809 /* DictionaryCoding in Frameworks */ = {isa = PBXBuildFile; productRef = 4BD5657724E8443300D52809 /* DictionaryCoding */; };
4BD5657B24E8448300D52809 /* EonilFSEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 4BD5657A24E8448300D52809 /* EonilFSEvents */; };
4BD67C7824EC488200147C51 /* RxPack in Frameworks */ = {isa = PBXBuildFile; productRef = 4BD67C7724EC488200147C51 /* RxPack */; };
4BD67C7B24EC765900147C51 /* Commons in Frameworks */ = {isa = PBXBuildFile; productRef = 4BD67C7A24EC765900147C51 /* Commons */; };
4BDF500C1D760A3500D8FBC3 /* FileUtilsTest in Resources */ = {isa = PBXBuildFile; fileRef = 4BDF500B1D760A3500D8FBC3 /* FileUtilsTest */; };
4BDF50171D77540900D8FBC3 /* OpenQuicklyWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BDF50191D77540900D8FBC3 /* OpenQuicklyWindow.xib */; };
4BEBA5091CFF374B00673FDF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBA5081CFF374B00673FDF /* AppDelegate.swift */; };
@ -311,7 +307,6 @@
1929BCE3E156C06EDF1F2806 /* FileOutlineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileOutlineView.swift; sourceTree = "<group>"; };
1929BD2CA8DD198A6BCDBCB7 /* ThemedTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemedTableSubviews.swift; sourceTree = "<group>"; };
1929BD4149D5A25C82064DD8 /* UiRoot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRoot.swift; sourceTree = "<group>"; };
1929BD6439FB8568CD045A41 /* AttributedStringMarkdownStyler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributedStringMarkdownStyler.swift; sourceTree = "<group>"; };
1929BD83A13BF133741766CC /* MainWindowReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowReducer.swift; sourceTree = "<group>"; };
1929BDC3F82CB4CB4FE56D1B /* ImageAndTextTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAndTextTableCell.swift; sourceTree = "<group>"; };
1929BDC8F5D48578A90236E9 /* FileBrowserReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileBrowserReducer.swift; sourceTree = "<group>"; };
@ -319,7 +314,6 @@
1929BE37AA2843779CAFA76F /* MarkdownPreviewReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownPreviewReducer.swift; sourceTree = "<group>"; };
1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlPreviewToolReducer.swift; sourceTree = "<group>"; };
1929BE6AB18FA655A8A9DA73 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = "../../third-party/libag/include/util.h"; sourceTree = "<group>"; };
1929BE867BD8F0ED0246CC94 /* OSLogCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLogCommons.swift; sourceTree = "<group>"; };
1929BED01F5D94BFCA4CF80F /* AppearancePrefReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppearancePrefReducer.swift; sourceTree = "<group>"; };
1929BF230875DED6CD7AB3EB /* ShortcutItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutItem.swift; sourceTree = "<group>"; };
1929BFB0F294F3714D5E095F /* MarkdownToolReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownToolReducer.swift; sourceTree = "<group>"; };
@ -337,7 +331,6 @@
4B6423971D8EFDE000FC78C8 /* WorkspaceBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WorkspaceBar.swift; path = Workspace/WorkspaceBar.swift; sourceTree = "<group>"; };
4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WorkspaceTool.swift; path = Workspace/WorkspaceTool.swift; sourceTree = "<group>"; };
4B6A70931D60E04200E12030 /* AppKitCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppKitCommons.swift; sourceTree = "<group>"; };
4B6A70951D6100E300E12030 /* SwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftCommons.swift; sourceTree = "<group>"; };
4B8C64CD23F02259008733D8 /* Dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Dev.xcconfig; sourceTree = "<group>"; };
4B8C64CE23F022C2008733D8 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
4B9433A120B95EC1005807BA /* MacVim-bsh.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = "MacVim-bsh.icns"; path = "macvim-file-icons/MacVim-bsh.icns"; sourceTree = "<group>"; };
@ -435,6 +428,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4BD67C7B24EC765900147C51 /* Commons in Frameworks */,
4B9BC42124EB2E45000209B5 /* RxCocoa in Frameworks */,
4BD67C7824EC488200147C51 /* RxPack in Frameworks */,
4B9BC42724EB2E51000209B5 /* NvimView in Frameworks */,
@ -795,9 +789,6 @@
4BF70ED123D1B4AF009E51E9 /* FoundationCommons.m */,
4B6A70931D60E04200E12030 /* AppKitCommons.swift */,
1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */,
4B6A70951D6100E300E12030 /* SwiftCommons.swift */,
1929BE867BD8F0ED0246CC94 /* OSLogCommons.swift */,
1929BD6439FB8568CD045A41 /* AttributedStringMarkdownStyler.swift */,
);
name = Commons;
sourceTree = "<group>";
@ -920,6 +911,7 @@
4B9BC42624EB2E51000209B5 /* NvimView */,
4B9BC42924EB2E6D000209B5 /* ShortcutRecorder */,
4BD67C7724EC488200147C51 /* RxPack */,
4BD67C7A24EC765900147C51 /* Commons */,
);
productName = VimR;
productReference = 4BEBA5051CFF374B00673FDF /* VimR.app */;
@ -1112,7 +1104,6 @@
4B6A70941D60E04200E12030 /* AppKitCommons.swift in Sources */,
4B3965361DEB21300082D3C1 /* InnterToolBar.swift in Sources */,
4B6423981D8EFDE000FC78C8 /* WorkspaceBar.swift in Sources */,
4B6A70961D6100E300E12030 /* SwiftCommons.swift in Sources */,
4BEBA5091CFF374B00673FDF /* AppDelegate.swift in Sources */,
4B64239A1D8EFE3000FC78C8 /* WorkspaceTool.swift in Sources */,
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */,
@ -1179,7 +1170,6 @@
1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */,
1929BF3253594E5B1908C6CE /* RpcAppearanceEpic.swift in Sources */,
4BF70EED23D1B618009E51E9 /* ConditionVariable.swift in Sources */,
1929B4E8B916008399CD5D3A /* OSLogCommons.swift in Sources */,
1929B5A0EDD1119CFF7BB84C /* Defs.swift in Sources */,
1929B376DB09AB5FDBF42BA1 /* MainWindow+Types.swift in Sources */,
1929B443B7AB2176A7818CA1 /* fuzzy_match.cc in Sources */,
@ -1188,7 +1178,6 @@
1929B223C6E97C090474B2C2 /* Resources.swift in Sources */,
1929BC64D3C195A92BE3FD64 /* HtmlPreviewMiddleware.swift in Sources */,
1929B29FF537A339CF4075BD /* CssUtils.swift in Sources */,
1929B0153C780675EE33F9EC /* AttributedStringMarkdownStyler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1196,11 +1185,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B6DFB3A22366D140066BB43 /* OSLogCommons.swift in Sources */,
4B96FB3C1EBBC56F00E4E164 /* FileUtils.swift in Sources */,
4B96FB3F1EBBC56F00E4E164 /* PrefUtils.swift in Sources */,
4B96FB401EBBC56F00E4E164 /* FoundationCommons.swift in Sources */,
4B96FB421EBBC56F00E4E164 /* SwiftCommons.swift in Sources */,
1929B66F795867B8C07FAAD4 /* DictionaryCommonsTest.swift in Sources */,
1929B98F94536E3912AD9F3B /* ArrayCommonsTest.swift in Sources */,
1929BDFDBDA7180D02ACB37E /* RxSwiftCommonsTest.swift in Sources */,
@ -1652,6 +1639,10 @@
isa = XCSwiftPackageProductDependency;
productName = RxPack;
};
4BD67C7A24EC765900147C51 /* Commons */ = {
isa = XCSwiftPackageProductDependency;
productName = Commons;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 4BEBA4FD1CFF374B00673FDF /* Project object */;

View File

@ -10,6 +10,7 @@ import Sparkle
import CocoaFontAwesome
import DictionaryCoding
import os
import Commons
let debugMenuItemIdentifier = NSUserInterfaceItemIdentifier("debug-menu-item")

View File

@ -6,93 +6,12 @@
import Cocoa
import Down
extension NSColor {
static var random: NSColor {
NSColor(
calibratedRed: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0
)
}
var int: Int {
if let color = self.usingColorSpace(.sRGB) {
let a = Int(color.alphaComponent * 255)
let r = Int(color.redComponent * 255)
let g = Int(color.greenComponent * 255)
let b = Int(color.blueComponent * 255)
return a << 24 | r << 16 | g << 8 | b
} else {
return 0
}
}
var hex: String { String(String(format: "%06X", self.int).suffix(6)) }
convenience init(rgb: Int) {
// @formatter:off
let red = ((rgb >> 16) & 0xFF).cgf / 255.0;
let green = ((rgb >> 8) & 0xFF).cgf / 255.0;
let blue = ((rgb ) & 0xFF).cgf / 255.0;
// @formatter:on
self.init(srgbRed: red, green: green, blue: blue, alpha: 1.0)
}
convenience init?(hex: String) {
var result: UInt32 = 0
guard hex.count == 6, Scanner(string: hex).scanHexInt32(&result) else { return nil }
let r = (result & 0xFF0000) >> 16
let g = (result & 0x00FF00) >> 8
let b = (result & 0x0000FF)
self.init(srgbRed: r.cgf / 255, green: g.cgf / 255, blue: b.cgf / 255, alpha: 1)
}
func brightening(by factor: CGFloat) -> NSColor {
guard let color = self.usingColorSpace(.sRGB) else { return self }
let h = color.hueComponent
let s = color.saturationComponent
let b = color.brightnessComponent
let a = color.alphaComponent
return NSColor(hue: h, saturation: s, brightness: b * factor, alpha: a)
}
extension NSView {
@objc var isFirstResponder: Bool { self.window?.firstResponder == self }
}
extension NSImage {
func tinting(with color: NSColor) -> NSImage {
let result = self.copy() as! NSImage
result.lockFocus()
color.set()
CGRect(origin: .zero, size: self.size).fill(using: .sourceAtop)
result.unlockFocus()
return result
}
}
extension NSButton {
var boolState: Bool {
get { self.state == .on ? true : false }
set { self.state = newValue ? .on : .off }
}
}
extension NSMenuItem {
var boolState: Bool {
get { self.state == .on ? true : false }
set { self.state = newValue ? .on : .off }
}
}
extension NSAttributedString {
@ -128,17 +47,6 @@ extension NSAttributedString {
}
}
extension NSView {
func removeAllSubviews() { self.subviews.forEach { $0.removeFromSuperview() } }
func removeAllConstraints() { self.removeConstraints(self.constraints) }
@objc var isFirstResponder: Bool { self.window?.firstResponder == self }
func beFirstResponder() { self.window?.makeFirstResponder(self) }
}
extension NSTableView {
static func standardTableView() -> NSTableView {
@ -238,6 +146,54 @@ extension NSScrollView {
}
}
private class AttributedStringMarkdownStyler {
static func new() -> Styler {
let fonts = StaticFontCollection(
body: NSFont.systemFont(ofSize: NSFont.smallSystemFontSize),
code: NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize)!
)
let style = DownStylerConfiguration(fonts: fonts, paragraphStyles: ParagraphStyles())
return DownStyler(configuration: style)
}
}
private struct ParagraphStyles: ParagraphStyleCollection {
let heading1: NSParagraphStyle
let heading2: NSParagraphStyle
let heading3: NSParagraphStyle
let heading4: NSParagraphStyle
let heading5: NSParagraphStyle
let heading6: NSParagraphStyle
let body: NSParagraphStyle
let code: NSParagraphStyle
public init() {
let headingStyle = NSParagraphStyle()
let bodyStyle = NSMutableParagraphStyle()
bodyStyle.paragraphSpacingBefore = 2
bodyStyle.paragraphSpacing = 2
bodyStyle.lineSpacing = 2
let codeStyle = NSMutableParagraphStyle()
codeStyle.paragraphSpacingBefore = 2
codeStyle.paragraphSpacing = 2
self.heading1 = headingStyle
self.heading2 = headingStyle
self.heading3 = headingStyle
self.heading4 = headingStyle
self.heading5 = headingStyle
self.heading6 = headingStyle
self.body = bodyStyle
self.code = codeStyle
}
}
private let fontCollection = StaticFontCollection(
body: NSFont.systemFont(ofSize: NSFont.smallSystemFontSize),
code: NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize)!

View File

@ -1,54 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import Down
class AttributedStringMarkdownStyler {
static func new() -> Styler {
let fonts = StaticFontCollection(
body: NSFont.systemFont(ofSize: NSFont.smallSystemFontSize),
code: NSFont.userFixedPitchFont(ofSize: NSFont.smallSystemFontSize)!
)
let style = DownStylerConfiguration(fonts: fonts, paragraphStyles: ParagraphStyles())
return DownStyler(configuration: style)
}
}
private struct ParagraphStyles: ParagraphStyleCollection {
let heading1: NSParagraphStyle
let heading2: NSParagraphStyle
let heading3: NSParagraphStyle
let heading4: NSParagraphStyle
let heading5: NSParagraphStyle
let heading6: NSParagraphStyle
let body: NSParagraphStyle
let code: NSParagraphStyle
public init() {
let headingStyle = NSParagraphStyle()
let bodyStyle = NSMutableParagraphStyle()
bodyStyle.paragraphSpacingBefore = 2
bodyStyle.paragraphSpacing = 2
bodyStyle.lineSpacing = 2
let codeStyle = NSMutableParagraphStyle()
codeStyle.paragraphSpacingBefore = 2
codeStyle.paragraphSpacing = 2
self.heading1 = headingStyle
self.heading2 = headingStyle
self.heading3 = headingStyle
self.heading4 = headingStyle
self.heading5 = headingStyle
self.heading6 = headingStyle
self.body = bodyStyle
self.code = codeStyle
}
}

View File

@ -7,6 +7,7 @@ import Cocoa
import RxSwift
import PureLayout
import CocoaFontAwesome
import Commons
class FileBrowser: NSView,
UiComponent {

View File

@ -9,82 +9,4 @@ import os
extension URL {
var direntType: UInt8 { (self as NSURL).direntType() }
func isDirectParent(of url: URL) -> Bool {
guard self.isFileURL && url.isFileURL else { return false }
let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents
guard targetPathComps.count == myPathComps.count + 1 else { return false }
return Array(targetPathComps[0..<myPathComps.count]) == myPathComps
}
func isParent(of url: URL) -> Bool {
guard self.isFileURL && url.isFileURL else { return false }
let myPathComps = self.pathComponents
let targetPathComps = url.pathComponents
guard targetPathComps.count > myPathComps.count else { return false }
return Array(targetPathComps[0..<myPathComps.count]) == myPathComps
}
func isContained(in parentUrl: URL) -> Bool {
if parentUrl == self { return false }
let pathComps = self.pathComponents
let parentPathComps = parentUrl.pathComponents
guard pathComps.count > parentPathComps.count else { return false }
guard Array(pathComps[0..<parentPathComps.endIndex]) == parentPathComps else { return false }
return true
}
var parent: URL {
if self.path == "/" { return self }
return self.deletingLastPathComponent()
}
var isDir: Bool { self.resourceValue(URLResourceKey.isDirectoryKey.rawValue) }
var isHidden: Bool { self.resourceValue(URLResourceKey.isHiddenKey.rawValue) }
var isPackage: Bool { self.resourceValue(URLResourceKey.isPackageKey.rawValue) }
/// Wrapper function for NSURL.getResourceValue for Bool values.
/// Returns also `false` when
/// - there is no value for the given `key` or
/// - the value cannot be converted to `NSNumber`.
///
/// - parameters:
/// - key: The `key`-parameter of `NSURL.getResourceValue`.
private func resourceValue(_ key: String) -> Bool {
var rsrc: AnyObject?
do {
try (self as NSURL).getResourceValue(&rsrc, forKey: URLResourceKey(rawValue: key))
} catch let error as NSError {
// FIXME error handling
log.error("ERROR while getting \(key): \(error)")
return false
}
if let result = rsrc as? NSNumber { return result.boolValue }
return false
}
}
extension ValueTransformer {
static var keyedUnarchiveFromDataTransformer
= ValueTransformer(forName: .keyedUnarchiveFromDataTransformerName)!
}
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.general)

View File

@ -16,12 +16,4 @@ class OpenQuicklyFileViewRow: NSTableRowView {
self.rectsBeingDrawn().forEach { NSIntersectionRect($0, dirtyRect).fill(using: .sourceOver) }
}
private func rectsBeingDrawn() -> [CGRect] {
var rectsPtr: UnsafePointer<CGRect>? = nil
var count: Int = 0
self.getRectsBeingDrawn(&rectsPtr, count: &count)
return Array(UnsafeBufferPointer(start: rectsPtr, count: count))
}
}

View File

@ -5,6 +5,7 @@
import Cocoa
import NvimView
import Commons
func changeTheme(themePrefChanged: Bool, themeChanged: Bool, usesTheme: Bool,
forTheme: () -> Void, forDefaultTheme: () -> Void) -> Bool {