Skip to content

Commit

Permalink
Tab completion
Browse files Browse the repository at this point in the history
  • Loading branch information
yury committed Oct 24, 2019
1 parent 9e45592 commit b484540
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 88 deletions.
4 changes: 2 additions & 2 deletions Blink.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2167,7 +2167,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 151;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = HV2S48975V;
Expand Down Expand Up @@ -2212,7 +2212,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 151;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = HV2S48975V;
ENABLE_BITCODE = NO;
Expand Down
147 changes: 68 additions & 79 deletions Blink/Complete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,18 @@ struct Complete {
let id: Int
let cursor: Int
let input: String
let n: Int
}

struct ForResponse: Codable {
let requestId: Int
let input: String
let result: [String]
let result: String
let hint: String
let kind: String
let start: Int
let pos: Int
let len: Int
}

enum Kind: String {
Expand Down Expand Up @@ -201,63 +205,86 @@ struct Complete {
case .command:
if let hint = _commandHints()[first] {
result = "\(first) - \(hint)"
} else {
result = first
}
default:
result = candidates.prefix(5).joined(separator: ", ")
}

return result;
}

static func _loopIndex(arr: [String], n: Int) -> String {
let count = arr.count
if count == 0 {
return ""
}
if n >= 0 {
return arr[n % count]
}

return arr[count - 1 - (abs(n) % count)]
}

static func _for(cursor: Int, str: String, n: Int) -> (kind: Kind, start: Int, pos: Int, len: Int, result: String, hint: String) {

static func _for(cursor: Int, str: String) -> (kind: Kind, result: [String], hint: String) {
return (
kind: .command,
result: [],
hint: ""
)
let token = CompleteUtils.completeToken(str, cursor: cursor)

// 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
// )
guard let cmd = token.cmd else {
let kind: Kind = token.isRedirect ? .file : .command
let commands = _complete(kind: kind, input: token.query)
let filtered = commands.filter({$0.hasPrefix(token.query)}).sorted().map { CompleteUtils.encode(str: $0, quote: token.quote) }
let hint = token.canShowHint ? _hint(kind: kind, candidates: filtered) : ""

return (
kind: .command,
start: token.jsStart,
pos: token.jsPos,
len: token.jsLen,
result: _loopIndex(arr: filtered, n: n),
hint: hint
)
}

if token.query.first == "-" {
let opts = getoptString(cmd) ?? ""
return (
kind: .no,
start: token.jsStart,
pos: token.jsPos,
len: token.jsLen,
result: "",
hint: (!token.canShowHint || opts.isEmpty) ? "" : "\(token.value) [\(opts)]"
)
}

let kind = _completionKind(cmd)
let result = _complete(kind: kind, input: token.query).sorted().map { CompleteUtils.encode(str: $0, quote: token.quote) }
let hint = !token.canShowHint ? "" : _hint(kind: kind, candidates: Array(result.prefix(5)))

return (
kind: kind,
start: token.jsStart,
pos: token.jsPos,
len: token.jsLen,
result: _loopIndex(arr: result, n: n),
hint: hint.isEmpty ? "" : token.prefix + hint
)
}

static func _for(request: ForRequest) -> ForResponse {
let res = _for(cursor: request.cursor, str: request.input)
let res = _for(cursor: request.cursor, str: request.input, n: request.n)
return ForResponse(
requestId: request.id,
input: request.input,
result: res.result,
hint: res.hint,
kind: res.kind.rawValue)
kind: res.kind.rawValue,
start: res.start,
pos: res.pos,
len: res.len
)
}

static func _forAPI(session: MCPSession, json: String) -> String? {
Expand Down Expand Up @@ -354,43 +381,5 @@ struct Complete {
}
return result;
}



private static func _lastCommand(_ str: String) -> (prefix: String, idx: Int, value: String) {
var buf = Array(str)
var len = buf.count
var bp = 0;
var i = 0;
while i < len {
defer { i += 1 }

let ch = buf[i]

let quotes = "\"'"

for quote in quotes {
if ch == quote {
i += 1
while i < len && buf[i] != quote {
i += 1
}
}
}

if ch == "|" {
bp = i
}
}

while bp < len {
if buf[bp] == " " || buf[bp] == "|" {
bp += 1
} else {
break
}
}

return (prefix: String(buf.prefix(bp)), idx: bp, value: String(buf.suffix(from: bp)))
}
}
13 changes: 10 additions & 3 deletions Blink/CompleteUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ struct CompleteToken {
// if cmd is detected
var cmd: String? = nil

var jsStart: Int = 0
var jsPos: Int = 0
var jsLen: Int = 0
var canShowHint: Bool = false
}

struct CompleteUtils {
Expand Down Expand Up @@ -99,8 +101,9 @@ struct CompleteUtils {
bs = 0
}

if ch.isWhitespace {
if ch.isWhitespace && bs % 2 == 0 {
pos = i
continue
}

if ch == "|" && bs % 2 == 0 {
Expand Down Expand Up @@ -196,6 +199,7 @@ struct CompleteUtils {

let range = input.index(input.startIndex, offsetBy: start)..<input.index(input.startIndex, offsetBy: end)

var canShowHint = range.upperBound == input.endIndex
// if pos >= len {
// pos = len - 1
// }
Expand Down Expand Up @@ -236,7 +240,7 @@ struct CompleteUtils {
}
}

if pos == start || pos >= len {
if pos == start || pos > len {
cmd = nil
prefix = ""
} else {
Expand All @@ -246,6 +250,7 @@ struct CompleteUtils {
}
}

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

Expand All @@ -261,8 +266,10 @@ struct CompleteUtils {

cmd: cmd,

jsStart: jsStart,
jsPos: jsPos,
jsLen: jsEnd - jsPos
jsLen: jsEnd - jsPos,
canShowHint: canShowHint
)
}

Expand Down
25 changes: 23 additions & 2 deletions BlinkTests/CompleteUtilsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,18 @@ class CompletionTests: XCTestCase {
}

func testSimpleCmd() {
var token = "ssh ".token(cursor: 0)
var token = "mosh ".token(cursor: 5)

assert(token.value == "mosh ")
assert(token.prefix == "mosh ")
assert(token.cmd == "mosh")
assert(token.query == "")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 5)
assert(token.jsLen == 0)

token = "ssh ".token(cursor: 0)
assert(token.value == "ssh")
assert(token.prefix == "")
assert(token.cmd == nil)
Expand Down Expand Up @@ -235,7 +246,17 @@ class CompletionTests: XCTestCase {
}

func testEscapes() {
var token = "cd hello\\ world".token(cursor: 1)
var token = "cat foo\\ ".token(cursor: 9)
assert(token.value == "cat foo\\ ")
assert(token.prefix == "cat ")
assert(token.cmd == "cat")
assert(token.query == "foo ")
assert(token.quote == nil)
assert(token.isRedirect == false)
assert(token.jsPos == 4)
assert(token.jsLen == 5)

token = "cd hello\\ world".token(cursor: 1)
assert(token.value == "cd")
assert(token.prefix == "")
assert(token.cmd == nil)
Expand Down
4 changes: 2 additions & 2 deletions Resources/hterm_all.min.js

Large diffs are not rendered by default.

0 comments on commit b484540

Please sign in to comment.