mirror of
https://github.com/github/semantic.git
synced 2024-12-26 00:12:29 +03:00
Merge remote-tracking branch 'origin/master' into show-empty-space
This commit is contained in:
commit
5f43e526c2
@ -36,6 +36,8 @@
|
||||
D4413FEF1BB06D4C00E3C3C1 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */; };
|
||||
D4413FF11BB08FDC00E3C3C1 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4413FF01BB08FDC00E3C3C1 /* JSON.swift */; };
|
||||
D45A36C91BBC667D00BE3DDE /* Categorizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45A36C81BBC667D00BE3DDE /* Categorizable.swift */; };
|
||||
D46452C71BE7C6C800D7D26E /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46452C61BE7C6C800D7D26E /* Argument.swift */; };
|
||||
D46452C91BE7EB2500D7D26E /* Unified.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46452C81BE7EB2500D7D26E /* Unified.swift */; };
|
||||
D49FCBC41BBEF98E00C5E9C3 /* Free.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49FCBC31BBEF98E00C5E9C3 /* Free.swift */; };
|
||||
D49FCBC61BBF214300C5E9C3 /* Patch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49FCBC51BBF214300C5E9C3 /* Patch.swift */; };
|
||||
D49FCBC81BBF2C4300C5E9C3 /* Algorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49FCBC71BBF2C4300C5E9C3 /* Algorithm.swift */; };
|
||||
@ -104,6 +106,8 @@
|
||||
D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
|
||||
D4413FF01BB08FDC00E3C3C1 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
|
||||
D45A36C81BBC667D00BE3DDE /* Categorizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Categorizable.swift; sourceTree = "<group>"; };
|
||||
D46452C61BE7C6C800D7D26E /* Argument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Argument.swift; sourceTree = "<group>"; };
|
||||
D46452C81BE7EB2500D7D26E /* Unified.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unified.swift; sourceTree = "<group>"; };
|
||||
D49FCBC31BBEF98E00C5E9C3 /* Free.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Free.swift; sourceTree = "<group>"; };
|
||||
D49FCBC51BBF214300C5E9C3 /* Patch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Patch.swift; sourceTree = "<group>"; };
|
||||
D49FCBC71BBF2C4300C5E9C3 /* Algorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Algorithm.swift; sourceTree = "<group>"; };
|
||||
@ -257,6 +261,8 @@
|
||||
D4FB2CDB1BDEBCCD00B3CCE0 /* main.swift */,
|
||||
D4FB2D011BE2943A00B3CCE0 /* Info.swift */,
|
||||
D4FB2CF71BE1560400B3CCE0 /* TSNode.swift */,
|
||||
D46452C61BE7C6C800D7D26E /* Argument.swift */,
|
||||
D46452C81BE7EB2500D7D26E /* Unified.swift */,
|
||||
D4FB2CE51BDEBE7900B3CCE0 /* doubt-difftool-Bridging-Header.h */,
|
||||
D4FB2D001BE2936800B3CCE0 /* Parsers */,
|
||||
D4FB2CDE1BDEBD1C00B3CCE0 /* libruntime.a */,
|
||||
@ -481,10 +487,12 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D46452C71BE7C6C800D7D26E /* Argument.swift in Sources */,
|
||||
D4FB2CF81BE1560400B3CCE0 /* TSNode.swift in Sources */,
|
||||
D4FB2CFA1BE28F6D00B3CCE0 /* parser.c in Sources */,
|
||||
D4FB2CFC1BE292BB00B3CCE0 /* parser.c in Sources */,
|
||||
D4FB2D021BE2943A00B3CCE0 /* Info.swift in Sources */,
|
||||
D46452C91BE7EB2500D7D26E /* Unified.swift in Sources */,
|
||||
D4FB2CDC1BDEBCCD00B3CCE0 /* main.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -48,7 +48,7 @@
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugDocumentVersioning = "NO"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
@ -62,6 +62,10 @@
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "--unified"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "https://raw.githubusercontent.com/jquery/jquery/2.1.0/src/effects.js"
|
||||
isEnabled = "YES">
|
||||
|
@ -1,105 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D4DF96FA1BC5DF050040F41F"
|
||||
BuildableName = "doubt-json.app"
|
||||
BlueprintName = "doubt-json"
|
||||
ReferencedContainer = "container:Doubt.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D4DF96FA1BC5DF050040F41F"
|
||||
BuildableName = "doubt-json.app"
|
||||
BlueprintName = "doubt-json"
|
||||
ReferencedContainer = "container:Doubt.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D4DF96FA1BC5DF050040F41F"
|
||||
BuildableName = "doubt-json.app"
|
||||
BlueprintName = "doubt-json"
|
||||
ReferencedContainer = "container:Doubt.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "$(SRCROOT)/doubt-json/Fixtures/a.json"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "$(SRCROOT)/doubt-json/Fixtures/b.json"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "$(SRCROOT)/UI/diff.json"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D4DF96FA1BC5DF050040F41F"
|
||||
BuildableName = "doubt-json.app"
|
||||
BlueprintName = "doubt-json"
|
||||
ReferencedContainer = "container:Doubt.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -120,6 +120,15 @@ extension CofreeType {
|
||||
return (term.extract, term.unwrap)
|
||||
}
|
||||
|
||||
|
||||
/// Catamorphism over `TermType`s.
|
||||
///
|
||||
/// Folds the tree encoded by the receiver into a single value by recurring top-down through the tree, applying `transform` to leaves, then to branches, and so forth.
|
||||
public func cata<Result>(transform: (Annotation, Syntax<Result, Leaf>) -> Result) -> Result {
|
||||
return self |> (Self.eliminate >>> { ($0, $1.map { $0.cata(transform) }) } >>> transform)
|
||||
}
|
||||
|
||||
|
||||
/// Constructs a cofree by coiteration.
|
||||
///
|
||||
/// This is an _anamorphism_ (from the Greek “ana,” “upwards”; compare “anabolism”), a generalization of unfolds over regular trees (and datatypes isomorphic to them). The initial seed is used as the annotation of the returned value. The continuation of the structure is unpacked by applying `annotate` to the seed and mapping the resulting syntax’s values recursively. In this manner, the structure is unfolded bottom-up, starting with `seed` and ending at the leaves.
|
||||
|
@ -56,17 +56,17 @@ public enum Free<Leaf, Annotation, Value>: CustomDebugStringConvertible {
|
||||
/// While not every function on a given `Free` can be computed using `cata`, these guarantees of termination and complexity, as well as the brevity and focus on the operation being performed n times, make it a desirable scaffolding for any function which can.
|
||||
///
|
||||
/// For a lucid, in-depth tutorial on recursion schemes, I recommend [Patrick Thomson](https://twitter.com/importantshock)’s _[An Introduction to Recursion Schemes](http://patrickthomson.ghost.io/an-introduction-to-recursion-schemes/)_ and _[Recursion Schemes, Part 2: A Mob of Morphisms](http://patrickthomson.ghost.io/recursion-schemes-part-2/)_.
|
||||
public func cata(@noescape transform: Syntax<Value, Leaf> throws -> Value) rethrows -> Value {
|
||||
public func cata(@noescape transform: (Annotation, Syntax<Value, Leaf>) throws -> Value) rethrows -> Value {
|
||||
return try analysis(
|
||||
ifPure: id,
|
||||
ifRoll: { try transform($1.map { try $0.cata(transform) }) })
|
||||
ifRoll: { try transform($0, $1.map { try $0.cata(transform) }) })
|
||||
}
|
||||
|
||||
|
||||
/// Reduces the receiver top-down, left-to-right, starting from an `initial` value, and applying `combine` to successive values.
|
||||
public func reduce(initial: Value, @noescape combine: (Value, Value) -> Value) -> Value {
|
||||
return cata {
|
||||
switch $0 {
|
||||
switch $1 {
|
||||
case .Leaf:
|
||||
return initial
|
||||
case let .Indexed(a):
|
||||
@ -132,11 +132,11 @@ extension Free where Value: PatchType, Value.Element == Cofree<Leaf, ()> {
|
||||
public typealias Term = Value.Element
|
||||
|
||||
public func merge(@noescape transform: Value -> Term) -> Term {
|
||||
return map(transform).cata { Cofree((), $0) }
|
||||
return map(transform).cata { Cofree((), $1) }
|
||||
}
|
||||
|
||||
public func merge(@noescape transform: Value -> Term?) -> Term? {
|
||||
return map(transform).cata(Free.discardNullTerms)
|
||||
return map(transform).cata { Free.discardNullTerms($1) }
|
||||
}
|
||||
|
||||
private static func discardNullTerms(syntax: Syntax<Term?, Leaf>) -> Term? {
|
||||
|
@ -11,7 +11,7 @@ struct UnannotatedTerm {
|
||||
let keyed = UnannotatedTerm.keyed
|
||||
let fixed = UnannotatedTerm.fixed
|
||||
return term.cata {
|
||||
switch $0 {
|
||||
switch $1 {
|
||||
case let .Leaf(s):
|
||||
return s
|
||||
case let .Indexed(s):
|
||||
@ -30,7 +30,7 @@ struct UnannotatedTerm {
|
||||
let fixed = UnannotatedTerm.fixed
|
||||
|
||||
return term.cata {
|
||||
switch $0 {
|
||||
switch $1 {
|
||||
case let .Leaf(s):
|
||||
return Cofree(0..<s.characters.count, .Leaf(s))
|
||||
case let .Indexed(i):
|
||||
|
2
prototype/External/Stream
vendored
2
prototype/External/Stream
vendored
@ -1 +1 @@
|
||||
Subproject commit fe6f1b69296bd2cfff734f7dda786fc6743b5665
|
||||
Subproject commit 434e07a3861698516c438e631d0545c1e1c4ab06
|
43
prototype/doubt-difftool/Argument.swift
Normal file
43
prototype/doubt-difftool/Argument.swift
Normal file
@ -0,0 +1,43 @@
|
||||
/// A list of arguments for the difftool.
|
||||
enum Argument {
|
||||
indirect case OutputFlag(Output, Argument)
|
||||
case Sources(Source, Source)
|
||||
|
||||
var sources: (Source, Source) {
|
||||
switch self {
|
||||
case let .Sources(a, b):
|
||||
return (a, b)
|
||||
case let .OutputFlag(_, rest):
|
||||
return rest.sources
|
||||
}
|
||||
}
|
||||
|
||||
var output: Output {
|
||||
switch self {
|
||||
case let .OutputFlag(output, _):
|
||||
return output
|
||||
default:
|
||||
return .Split
|
||||
}
|
||||
}
|
||||
|
||||
enum Output {
|
||||
case Unified
|
||||
case Split
|
||||
}
|
||||
}
|
||||
|
||||
private let flag: Madness.Parser<[String], Argument.Output>.Function =
|
||||
const(Argument.Output.Unified) <^> satisfy { $0 == "--unified" }
|
||||
<|> const(Argument.Output.Split) <^> satisfy { $0 == "--split" }
|
||||
<|> pure(Argument.Output.Split)
|
||||
|
||||
private let source: Madness.Parser<[String], Source>.Function =
|
||||
{ try! Source($0) } <^> satisfy { !$0.hasPrefix("--") }
|
||||
|
||||
let argumentsParser: Madness.Parser<[String], Argument>.Function = any // skip the path to the difftool
|
||||
*> (curry(Argument.OutputFlag) <^> flag)
|
||||
<*> (curry(Argument.Sources) <^> source <*> source)
|
||||
|
||||
import Madness
|
||||
import Prelude
|
93
prototype/doubt-difftool/Unified.swift
Normal file
93
prototype/doubt-difftool/Unified.swift
Normal file
@ -0,0 +1,93 @@
|
||||
private func unified(term: Term, source: String) -> String {
|
||||
return term.cata { info, syntax -> (String, Range<Int>?) in
|
||||
switch syntax {
|
||||
case .Leaf:
|
||||
return (String(source.utf16[info.range]), info.range)
|
||||
case let .Indexed(i):
|
||||
return (unified(info.range, children: i, source: source), info.range)
|
||||
case let .Fixed(f):
|
||||
return (unified(info.range, children: f, source: source), info.range)
|
||||
case let .Keyed(k):
|
||||
return (unified(info.range, children: k.values.sort(isOrderedBefore), source: source), info.range)
|
||||
}
|
||||
}.0
|
||||
}
|
||||
|
||||
private func isOrderedBefore(a: (String, Range<Int>?), _ b: (String, Range<Int>?)) -> Bool {
|
||||
if let a = a.1, b = b.1 {
|
||||
return a.startIndex < b.startIndex
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private var isTTY = isatty(STDOUT_FILENO) != 0
|
||||
private var isDumb = String.fromCString(getenv("TERM")).map { $0.hasPrefix("dumb") } ?? true
|
||||
private var shouldFormat = isTTY && !isDumb
|
||||
|
||||
private struct Attribute {
|
||||
let colour: Colour
|
||||
let style: Style
|
||||
|
||||
enum Colour: Int {
|
||||
case Black = 30
|
||||
case Red
|
||||
case Green
|
||||
case Yellow
|
||||
case Blue
|
||||
case Purple
|
||||
case Cyan
|
||||
case White
|
||||
}
|
||||
|
||||
enum Style: Int {
|
||||
case Normal = 0
|
||||
case Bold = 1
|
||||
case Underline = 4
|
||||
}
|
||||
|
||||
func wrap(string: String) -> String {
|
||||
return shouldFormat
|
||||
? "\u{001B}[\(style.rawValue);\(colour.rawValue)m\(string)\u{001B}[0m"
|
||||
: string
|
||||
}
|
||||
}
|
||||
|
||||
private func unified(patch: Patch<Term>, before: String, after: String) -> String {
|
||||
return (patch.state.before.map { Attribute(colour: .Red, style: .Bold).wrap("{-\(unified($0, source: before))-}") } ?? "")
|
||||
+ (patch.state.after.map { Attribute(colour: .Green, style: .Bold).wrap("{+\(unified($0, source: after))+}") } ?? "")
|
||||
}
|
||||
|
||||
private func range(patch: Patch<Term>) -> Range<Int>? {
|
||||
return patch.state.after?.extract.range
|
||||
}
|
||||
|
||||
private func unified(range: Range<Int>, children: [(String, Range<Int>?)], source: String) -> String {
|
||||
var previous = range.startIndex
|
||||
var out: String = ""
|
||||
for (string, range) in children {
|
||||
if let range = range {
|
||||
out += String(source.utf16[previous..<range.startIndex])
|
||||
previous = range.endIndex
|
||||
}
|
||||
out += string
|
||||
}
|
||||
return out + String(source.utf16[previous..<range.endIndex])
|
||||
}
|
||||
|
||||
func unified(diff: Diff, before: String, after: String) -> String {
|
||||
return diff.map { (unified($0, before: before, after: after), range($0)) }.cata { info, syntax in
|
||||
switch syntax {
|
||||
case .Leaf:
|
||||
return (String(after.utf16[info.1.range]), info.1.range)
|
||||
case let .Indexed(i):
|
||||
return (unified(info.1.range, children: i, source: after), info.1.range)
|
||||
case let .Fixed(f):
|
||||
return (unified(info.1.range, children: f, source: after), info.1.range)
|
||||
case let .Keyed(k):
|
||||
return (unified(info.1.range, children: k.values.sort(isOrderedBefore), source: after), info.1.range)
|
||||
}
|
||||
}.0
|
||||
}
|
||||
|
||||
|
||||
import Doubt
|
@ -14,6 +14,7 @@ func benchmark<T>(label: String? = nil, _ f: () -> T) -> T {
|
||||
extension String: ErrorType {}
|
||||
|
||||
typealias Term = Cofree<String, Info>
|
||||
typealias Diff = Free<Term.Leaf, (Term.Annotation, Term.Annotation), Patch<Term>>
|
||||
typealias Parser = String throws -> Term
|
||||
|
||||
struct Source {
|
||||
@ -143,9 +144,9 @@ func parserForType(type: String) -> String throws -> Term {
|
||||
}
|
||||
}
|
||||
|
||||
let arguments = BoundsCheckedArray(array: Process.arguments)
|
||||
guard let aSource = try arguments[1].map(Source.init) else { throw "need source A" }
|
||||
guard let bSource = try arguments[2].map(Source.init) else { throw "need source B" }
|
||||
let parsed = parse(argumentsParser, input: Process.arguments)
|
||||
let arguments: Argument = try parsed.either(ifLeft: { throw "\($0)" }, ifRight: { $0 })
|
||||
let (aSource, bSource) = arguments.sources
|
||||
let jsonURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).URLByAppendingPathComponent("diff.json")
|
||||
guard let uiPath = NSBundle.mainBundle().infoDictionary?["PathToUISource"] as? String else { throw "need ui path" }
|
||||
guard aSource.type == bSource.type else { throw "can’t compare files of different types" }
|
||||
@ -154,7 +155,9 @@ let parser = parserForType(aSource.type)
|
||||
let a = try parser(aSource.contents)
|
||||
let b = try parser(bSource.contents)
|
||||
let diff = Interpreter<Term>(equal: Term.equals(annotation: const(true), leaf: ==), comparable: Interpreter<Term>.comparable { $0.extract.categories }, cost: Free.sum(Patch.sum)).run(a, b)
|
||||
let JSON: Doubt.JSON = [
|
||||
switch arguments.output {
|
||||
case .Split:
|
||||
let JSON: Doubt.JSON = [
|
||||
"before": .String(aSource.contents),
|
||||
"after": .String(bSource.contents),
|
||||
"diff": diff.JSON(pure: { $0.JSON { $0.JSON(annotation: { $0.range.JSON }, leaf: Doubt.JSON.String) } }, leaf: Doubt.JSON.String, annotation: {
|
||||
@ -163,14 +166,17 @@ let JSON: Doubt.JSON = [
|
||||
"after": $1.range.JSON,
|
||||
]
|
||||
}),
|
||||
]
|
||||
let data = JSON.serialize()
|
||||
try data.writeToURL(jsonURL, options: .DataWritingAtomic)
|
||||
]
|
||||
let data = JSON.serialize()
|
||||
try data.writeToURL(jsonURL, options: .DataWritingAtomic)
|
||||
|
||||
let components = NSURLComponents()
|
||||
components.scheme = "file"
|
||||
components.path = uiPath
|
||||
components.query = jsonURL.absoluteString
|
||||
if let URL = components.URL {
|
||||
let components = NSURLComponents()
|
||||
components.scheme = "file"
|
||||
components.path = uiPath
|
||||
components.query = jsonURL.absoluteString
|
||||
if let URL = components.URL {
|
||||
NSWorkspace.sharedWorkspace().openURL(URL)
|
||||
}
|
||||
case .Unified:
|
||||
print(benchmark { unified(diff, before: aSource.contents, after: bSource.contents) })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user