1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-18 03:01:38 +03:00

GH-292 Make open quickly a bit better..

This commit is contained in:
Tae Won Ha 2016-12-17 09:35:07 +01:00
parent aaf03362fa
commit 7b1ed4d421
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
5 changed files with 45 additions and 73 deletions

View File

@ -1439,13 +1439,14 @@ extension NeoVimView {
} }
public func ipcBecameInvalid(_ reason: String) { public func ipcBecameInvalid(_ reason: String) {
NSLog("ERROR \(#function): force-quitting")
DispatchUtils.gui { DispatchUtils.gui {
if self.agent.neoVimIsQuitting { if self.agent.neoVimIsQuitting {
return return
} }
self.delegate?.ipcBecameInvalid(reason: reason) self.delegate?.ipcBecameInvalid(reason: reason)
NSLog("ERROR \(#function): force-quitting")
self.agent.quit() self.agent.quit()
} }
} }

View File

@ -6,7 +6,7 @@
import Foundation import Foundation
class Matcher { class Matcher {
static let uppercaseCharSet = CharacterSet.uppercaseLetters static let uppercaseCharSet = CharacterSet.uppercaseLetters
enum ExactMatchResult { enum ExactMatchResult {
@ -20,6 +20,7 @@ class Matcher {
static func exactMatchIgnoringCase(_ target: String, pattern: String) -> ExactMatchResult { static func exactMatchIgnoringCase(_ target: String, pattern: String) -> ExactMatchResult {
let ltarget = target.lowercased() let ltarget = target.lowercased()
let lpattern = pattern.lowercased() let lpattern = pattern.lowercased()
if ltarget == lpattern { if ltarget == lpattern {
return .exact return .exact
} }
@ -40,77 +41,49 @@ class Matcher {
} }
static func numberOfUppercaseMatches(_ target: String, pattern: String) -> Int { static func numberOfUppercaseMatches(_ target: String, pattern: String) -> Int {
var tscalars = target.unicodeScalars.filter { uppercaseCharSet.contains(UnicodeScalar($0.value)!) } var tscalars = target.unicodeScalars.filter { self.uppercaseCharSet.contains($0) }
let count = tscalars.count let count = tscalars.count
guard count > 0 else { guard count > 0 else {
return 0 return 0
} }
let pscalars = pattern.uppercased().unicodeScalars let pscalars = pattern.uppercased().unicodeScalars
pscalars.forEach { scalar in pscalars.forEach {
if let idx = tscalars.index(of: scalar) { if let idx = tscalars.index(of: $0) {
tscalars.remove(at: idx) tscalars.remove(at: idx)
} }
} }
return count - tscalars.count return count - tscalars.count
} }
/// Matches `pattern` to `target` in a fuzzy way. /// Matches `pattern` to `target` in a fuzzy way.
/// - returns: `Array` of `Range<String.UnicodeScalarIndex>` /// - returns: number of matched characters where first character match gets a bonus of 5
static func fuzzyIgnoringCase(_ target: String, static func fuzzyIgnoringCase(_ target: String, pattern: String) -> Int {
pattern: String) -> (matches: Int, ranges: [CountableClosedRange<Int>]) {
let tlower = target.lowercased() let tlower = target.lowercased()
let plower = pattern.lowercased() let plower = pattern.lowercased()
let tchars = tlower.unicodeScalars let tchars = tlower.unicodeScalars
let pchars = plower.unicodeScalars let pchars = plower.unicodeScalars
var flags = Array(repeating: false, count: tchars.count) var result = 0
var pidx = pchars.startIndex var pidx = pchars.startIndex
for (i, tchar) in tchars.enumerated() { for tchar in tchars {
if pchars[pidx] == tchar { if pchars[pidx] == tchar {
flags[i] = true result += 1
pidx = pchars.index(after: pidx) pidx = pchars.index(after: pidx)
} }
} }
var ranges: [CountableClosedRange<Int>] = [] if tchars.first == pchars.first {
var matches = 0 result += 5
var lastTrue = -1
var curTrue = -1
for (i, isTrue) in flags.enumerated() {
if isTrue {
matches = matches &+ 1
if lastTrue == -1 {
lastTrue = i
}
curTrue = i
if i == flags.count &- 1 {
if lastTrue > -1 && curTrue > -1 {
ranges.append(lastTrue...curTrue)
lastTrue = -1
curTrue = -1
}
}
} else {
if lastTrue > -1 && curTrue > -1 {
ranges.append(lastTrue...curTrue)
lastTrue = -1
curTrue = -1
}
}
} }
return (matches, ranges) return result
} }
/// Wagner-Fischer algorithm. /// Wagner-Fischer algorithm.
/// We use the 32 bit representation (`String.unicodeScalars`) of both parameters to compare them. /// We use the 32 bit representation (`String.unicodeScalars`) of both parameters to compare them.
/// ///
@ -119,19 +92,19 @@ class Matcher {
static func wagnerFisherDistance(_ target: String, pattern: String) -> Int { static func wagnerFisherDistance(_ target: String, pattern: String) -> Int {
let s = target.unicodeScalars let s = target.unicodeScalars
let t = pattern.unicodeScalars let t = pattern.unicodeScalars
let m = s.count let m = s.count
var prevRow = Array(repeating: 0, count: m &+ 1) var prevRow = Array(repeating: 0, count: m &+ 1)
var curRow = Array(repeating: 0, count: m &+ 1) var curRow = Array(repeating: 0, count: m &+ 1)
for i in 0...m { for i in 0 ... m {
prevRow[i] = i prevRow[i] = i
} }
for (j, tchar) in t.enumerated() { for (j, tchar) in t.enumerated() {
curRow[0] = j &+ 1 curRow[0] = j &+ 1
for (i, schar) in s.enumerated() { for (i, schar) in s.enumerated() {
if schar == tchar { if schar == tchar {
curRow[i &+ 1] = prevRow[i] curRow[i &+ 1] = prevRow[i]
@ -139,10 +112,10 @@ class Matcher {
curRow[i &+ 1] = min(curRow[i] &+ 1, prevRow[i &+ 1] &+ 1, prevRow[i] &+ 1) curRow[i &+ 1] = min(curRow[i] &+ 1, prevRow[i &+ 1] &+ 1, prevRow[i] &+ 1)
} }
} }
prevRow = curRow prevRow = curRow
} }
return curRow[m] return curRow[m]
} }
} }

View File

@ -6,28 +6,26 @@
import Foundation import Foundation
class Scorer { class Scorer {
static func score(_ target: String, pattern: String) -> Int { static func score(_ target: String, pattern: String) -> Int {
let wf = Matcher.wagnerFisherDistance(target, pattern: pattern)
let fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern) let fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern)
let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern) let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern)
let exactMatch = Matcher.exactMatchIgnoringCase(target, pattern: pattern) let exactMatch = Matcher.exactMatchIgnoringCase(target, pattern: pattern)
let wf = Matcher.wagnerFisherDistance(target, pattern: pattern)
let exactScore: Int let exactScore: Int
switch exactMatch { switch exactMatch {
case .none: case .none:
exactScore = 0 exactScore = 0
case .exact: case .exact:
return 100 return 1000
case .prefix, .contains, .suffix: case .prefix, .contains, .suffix:
exactScore = 5 exactScore = 5
} }
let wfScore = 0 - (wf / 10)
return exactScore return exactScore
+ wfScore + 10 * fuzzy
+ fuzzy.matches + 5 * upper
+ 2 * upper - wf
} }
} }

View File

@ -19,7 +19,7 @@ class MatcherTest: XCTestCase {
expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "swIFt")).to(equal(Matcher.ExactMatchResult.suffix)) expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "swIFt")).to(equal(Matcher.ExactMatchResult.suffix))
expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "userdecon")).to(equal(Matcher.ExactMatchResult.none)) expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "userdecon")).to(equal(Matcher.ExactMatchResult.none))
} }
func testUppercaseMatcher() { func testUppercaseMatcher() {
expect(Matcher.numberOfUppercaseMatches("SwiftNeoVimNeoVimView.swift", pattern: "swnvv")).to(equal(4)) expect(Matcher.numberOfUppercaseMatches("SwiftNeoVimNeoVimView.swift", pattern: "swnvv")).to(equal(4))
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "xct")).to(equal(2)) expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "xct")).to(equal(2))
@ -29,12 +29,12 @@ class MatcherTest: XCTestCase {
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "ut")).to(equal(2)) expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "ut")).to(equal(2))
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "de")).to(equal(1)) expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "de")).to(equal(1))
} }
func testFuzzyMatcher() { func testFuzzyMatcher() {
expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "ucotft").matches).to(equal(6)) expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "ucotft")).to(equal(6 + 5))
expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "uco-tft").matches).to(equal(3)) expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "uco-tft")).to(equal(3 + 5))
} }
func testWagerFischerAlgo() { func testWagerFischerAlgo() {
expect(Matcher.wagnerFisherDistance("sitting", pattern: "kitten")).to(equal(3)) expect(Matcher.wagnerFisherDistance("sitting", pattern: "kitten")).to(equal(3))
expect(Matcher.wagnerFisherDistance("saturday", pattern: "sunday")).to(equal(3)) expect(Matcher.wagnerFisherDistance("saturday", pattern: "sunday")).to(equal(3))

View File

@ -24,7 +24,7 @@ class ScorerTest: XCTestCase {
let targets = [ let targets = [
"NeoVimView.swift", "NeoVimView.swift",
"NeoVimViewDelegate.swift", "NeoVimViewDelegate.swift",
"NeoVimServer", "NeoVimAgent",
] ]
expect(Scorer.score(targets[0], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[1], pattern: pattern))) expect(Scorer.score(targets[0], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[1], pattern: pattern)))