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:
parent
aaf03362fa
commit
7b1ed4d421
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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)))
|
||||||
|
Loading…
Reference in New Issue
Block a user