Skip to content

Commit

Permalink
Use UTF16 pos and len
Browse files Browse the repository at this point in the history
  • Loading branch information
yury committed Oct 24, 2019
1 parent 55b1dee commit 9e45592
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 28 deletions.
62 changes: 38 additions & 24 deletions Blink/Complete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,30 +210,44 @@ struct Complete {
}

static func _for(cursor: Int, str: String) -> (kind: Kind, result: [String], hint: String) {
let input = _lastCommand(str)
var result:[String] = []

let parts = input.value.split(separator: " ", maxSplits: 1, omittingEmptySubsequences: false)

var kind: Kind = .command
var hint: String = ""
if parts.count <= 1 {
result = _complete(kind: kind, input: input.value)
hint = _hint(kind: kind, candidates: result)
return (kind: kind, result: result.map { input.prefix + $0 }, hint: hint.isEmpty ? "" : input.prefix + hint)
}

let cmd = String(parts[0])
kind = _completionKind(cmd)
result = _complete(kind: kind, input: String(parts[1]))
hint = _hint(kind: kind, candidates: result)

let cmdPrefix = input.prefix + cmd + " "
return (
kind: kind,
result: result.map( { cmdPrefix + $0 } ),
hint: hint.isEmpty ? "" : cmdPrefix + hint
)
return (
kind: .command,
result: [],
hint: ""
)

// let token = CompleteUtils.completeToken(str, cursor: cursor)
//
// guard let cmd = token.cmd else {
// let commands = _complete(kind: .command, input: token.query)
// let filtered = commands.filter({$0.hasPrefix(token.query)})
// let hint = _hint(kind: .command, candidates: filtered)
//
// }
// let input = _lastCommand(str)
// var result:[String] = []
//
// let parts = input.value.split(separator: " ", maxSplits: 1, omittingEmptySubsequences: false)
//
// var kind: Kind = .command
// var hint: String = ""
// if parts.count <= 1 {
// result = _complete(kind: kind, input: input.value)
// hint = _hint(kind: kind, candidates: result)
// return (kind: kind, result: result.map { input.prefix + $0 }, hint: hint.isEmpty ? "" : input.prefix + hint)
// }
//
// let cmd = String(parts[0])
// kind = _completionKind(cmd)
// result = _complete(kind: kind, input: String(parts[1]))
// hint = _hint(kind: kind, candidates: result)
//
// let cmdPrefix = input.prefix + cmd + " "
// return (
// kind: kind,
// result: result.map( { cmdPrefix + $0 } ),
// hint: hint.isEmpty ? "" : cmdPrefix + hint
// )
}

static func _for(request: ForRequest) -> ForResponse {
Expand Down
33 changes: 29 additions & 4 deletions Blink/CompleteUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import Foundation

struct CompleteToken {
var range: Range<String.Index>
var value: String = ""


Expand All @@ -46,13 +45,33 @@ struct CompleteToken {

// if cmd is detected
var cmd: String? = nil

var jsPos: Int = 0
var jsLen: Int = 0
}

struct CompleteUtils {

static func encode(str: String, quote: String.Element? = nil) -> String {
var result = str
result = result.replacingOccurrences(of: "\\", with: "\\\\")
result = result.replacingOccurrences(of: "|", with: "\\|")

guard let quote = quote else {
result = result.replacingOccurrences(of: " ", with: "\\ ")
return result
}

let q = String(quote)

result = result.replacingOccurrences(of: q, with: "\\" + q)
result = "\(q)\(result)\(q)"
return result
}

static func completeToken(_ input: String, cursor: Int) -> CompleteToken {
if input.isEmpty {
return CompleteToken(range: input.startIndex..<input.endIndex)
return CompleteToken()
}

var buf = Array(input)
Expand Down Expand Up @@ -227,8 +246,11 @@ struct CompleteUtils {
}
}

let jsPos = input.index(input.startIndex, offsetBy: pos).utf16Offset(in: input)
let jsEnd = input.index(input.startIndex, offsetBy: end).utf16Offset(in: input)


return CompleteToken(
range: range,
value: String(input[range]),

quote: qch,
Expand All @@ -237,7 +259,10 @@ struct CompleteUtils {
prefix: prefix,
query: query,

cmd: cmd
cmd: cmd,

jsPos: jsPos,
jsLen: jsEnd - jsPos
)
}

Expand Down
62 changes: 62 additions & 0 deletions BlinkTests/CompleteUtilsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,22 @@ extension String {
func token(cursor: Int) -> CompleteToken {
CompleteUtils.completeToken(self, cursor: cursor)
}

func encodeShell(quote: String.Element? = nil) -> String {
CompleteUtils.encode(str: self, quote: quote)
}
}

class CompletionTests: XCTestCase {

func testEncode() {
assert("".encodeShell(quote: nil) == "")
assert(" ".encodeShell(quote: nil) == "\\ ")
assert("''".encodeShell(quote: .init("'")) == "'\\'\\''")
assert("''".encodeShell(quote: .init("\"")) == "\"''\"")
assert("|".encodeShell(quote: .init("\"")) == "\"\\|\"")
}

func testInvalidInput() {
for token in [
" ".token(cursor: -1),
Expand All @@ -51,6 +63,8 @@ class CompletionTests: XCTestCase {
assert(token.prefix == "")
assert(token.query == "")
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 0)
}
}

Expand All @@ -62,6 +76,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 3)

token = "ssh -v".token(cursor: 1)
assert(token.value == "ssh")
Expand All @@ -70,6 +86,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "s")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 3)

token = "ssh -v".token(cursor: 2)
assert(token.value == "ssh")
Expand All @@ -78,6 +96,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "ss")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 3)

token = "ssh -v".token(cursor: 3)
assert(token.value == "ssh")
Expand All @@ -86,6 +106,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "ssh")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 3)

token = "ssh -v".token(cursor: 4)
assert(token.value == "ssh -v")
Expand All @@ -94,6 +116,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 4)
assert(token.jsLen == 2)

token = "ssh -v".token(cursor: 5)
assert(token.value == "ssh -v")
Expand All @@ -102,6 +126,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "-")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 4)
assert(token.jsLen == 2)


token = "ssh -v host".token(cursor: 4)
Expand All @@ -111,6 +137,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 4)
assert(token.jsLen == 2)

token = "ssh -v host".token(cursor: 5)
assert(token.value == "ssh -v")
Expand All @@ -119,6 +147,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "-")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 4)
assert(token.jsLen == 2)

token = "ssh -v host".token(cursor: 6)
assert(token.value == "ssh -v")
Expand All @@ -127,6 +157,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "-v")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 4)
assert(token.jsLen == 2)

token = "ssh -v host".token(cursor: 7)
assert(token.value == "ssh -v host")
Expand All @@ -135,6 +167,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 7)
assert(token.jsLen == 4)

token = "ssh -v host".token(cursor: 8)
assert(token.value == "ssh -v host")
Expand All @@ -143,6 +177,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "h")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 7)
assert(token.jsLen == 4)
}

func testPipe() {
Expand All @@ -154,6 +190,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 12)
assert(token.jsLen == 0)

token = "ssh -v host |".token(cursor: 13)
assert(token.value == "")
Expand All @@ -162,6 +200,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 13)
assert(token.jsLen == 0)

token = "ssh -v host |".token(cursor: 1)
assert(token.value == "ssh")
Expand All @@ -170,6 +210,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "s")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 3)

token = "ssh -v host | grep foo | cat foo".token(cursor: 30)
assert(token.value == "cat foo")
Expand All @@ -178,6 +220,18 @@ class CompletionTests: XCTestCase {
assert(token.query == "f")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 29)
assert(token.jsLen == 3)

token = "ssh -v host | grep foo | cat foo".token(cursor: 7)
assert(token.value == "ssh -v host")
assert(token.prefix == "ssh -v ")
assert(token.cmd == "ssh")
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 7)
assert(token.jsLen == 4)
}

func testEscapes() {
Expand All @@ -188,6 +242,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "c")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 0)
assert(token.jsLen == 2)

token = "cd hello\\ world".token(cursor: 4)
assert(token.value == "cd hello\\ world")
Expand All @@ -196,6 +252,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "h")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 3)
assert(token.jsLen == 12)

token = "cd \"hello\\\" world".token(cursor: 4)
assert(token.value == "cd \"hello\\\" world")
Expand All @@ -220,6 +278,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "")
assert(token.quote == Character("\""))
assert(token.isRedirect == false)
assert(token.jsPos == 3)
assert(token.jsLen == 14)

// `echo "he\"llo, " world |`
// `[ | ^ ] `
Expand All @@ -230,6 +290,8 @@ class CompletionTests: XCTestCase {
assert(token.query == "he\"") // he"
assert(token.quote == Character("\""))
assert(token.isRedirect == false)
assert(token.jsPos == 5)
assert(token.jsLen == 11)
}

func testRedirect() {
Expand Down

0 comments on commit 9e45592

Please sign in to comment.