Skip to content

Commit 771d48d

Browse files
committed
Merge branch 'main' into wcspec
2 parents 8e86d95 + fa9e3cb commit 771d48d

18 files changed

Lines changed: 3989 additions & 176 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ DerivedData
99
.deriveddata
1010
.build
1111
.DS_Store
12+
*~

Sources/SwiftTerm/Apple/AppleTerminalView.swift

Lines changed: 374 additions & 45 deletions
Large diffs are not rendered by default.

Sources/SwiftTerm/BufferLine.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public final class BufferLine: CustomDebugStringConvertible {
4242
{
4343
fillCharacter = other.fillCharacter
4444
isWrapped = other.isWrapped
45+
renderMode = other.renderMode
46+
images = other.images
4547
data = Array(other.data)
4648
dataSize = other.dataSize
4749
}
@@ -90,6 +92,7 @@ public final class BufferLine: CustomDebugStringConvertible {
9092
let dataSize = dataSize
9193
let empty = CharData(attribute: attribute)
9294
data.replaceSubrange(0..<dataSize, with: repeatElement(empty, count: dataSize))
95+
images = nil
9396
}
9497
/// Test whether contains any chars.
9598
public func hasContent (index: Int) -> Bool {
@@ -286,6 +289,7 @@ public final class BufferLine: CustomDebugStringConvertible {
286289
public func attach (image: TerminalImage) {
287290
if var imageArray = self.images {
288291
imageArray.append (image)
292+
images = imageArray
289293
} else {
290294
images = [image]
291295
}

Sources/SwiftTerm/CharData.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,18 @@ public struct Attribute: Equatable, Hashable {
100100
public private(set) var fg, bg: Color
101101
// The cell attributes
102102
public private(set) var style: CharacterStyle
103+
/// Optional underline color
104+
public private(set) var underlineColor: Color? = nil
103105

104106
public static func ==(lhs: Attribute, rhs: Attribute) -> Bool
105107
{
106-
lhs.style == rhs.style && lhs.fg == rhs.fg && lhs.bg == rhs.bg
108+
lhs.style == rhs.style && lhs.fg == rhs.fg && lhs.bg == rhs.bg && lhs.underlineColor == rhs.underlineColor
107109
}
108110

109111
// Returns an attribute with just the colors
110112
func justColor () -> Attribute
111113
{
112-
Attribute (fg: fg, bg: bg, style: .none)
114+
Attribute (fg: fg, bg: bg, style: .none, underlineColor: underlineColor)
113115
}
114116

115117
// Temporary, longer term in Attribute we will add a proper encoding

Sources/SwiftTerm/EscapeSequenceParser.swift

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ enum ParserState : UInt8 {
2626
case csiIgnore
2727
case sosPmApcString
2828
case oscString
29+
case apcString
2930
case dcsEntry
3031
case dcsParam
3132
case dcsIgnore
@@ -42,6 +43,7 @@ class ParsingState {
4243
var print: Int
4344
var dcs: Int
4445
var osc: cstring
46+
var apc: cstring
4547
var collect: cstring
4648
var parameters: [Int32]
4749
var abort: Bool
@@ -54,6 +56,7 @@ class ParsingState {
5456
print = 0
5557
dcs = 0
5658
osc = []
59+
apc = []
5760
collect = []
5861
parameters = []
5962
abort = false
@@ -170,7 +173,8 @@ public class EscapeSequenceParser {
170173
table.add (code: 0x9c, state: state, action: .ignore, next: .ground) // ST as terminator
171174
table.add (code: 0x1b, state: state, action: .clear, next: .escape) // ESC
172175
table.add (code: 0x9d, state: state, action: .oscStart, next: .oscString) // OSC
173-
table.add (codes: [0x98, 0x9e, 0x9f], state: state, action: .ignore, next: .sosPmApcString)
176+
table.add (codes: [0x98, 0x9e], state: state, action: .ignore, next: .sosPmApcString)
177+
table.add (code: 0x9f, state: state, action: .oscStart, next: .apcString)
174178
table.add (code: 0x9b, state: state, action: .clear, next: .csiEntry) // CSI
175179
table.add (code: 0x90, state: state, action: .clear, next: .dcsEntry) // DCS
176180
}
@@ -179,6 +183,7 @@ public class EscapeSequenceParser {
179183
table.add (codes: executables, state: .escape, action: .execute, next: .escape)
180184
table.add (code: 0x7f, state: .escape, action: .ignore, next: .escape)
181185
table.add (codes: executables, state: .oscString, action: .ignore, next: .oscString)
186+
table.add (codes: executables, state: .apcString, action: .ignore, next: .apcString)
182187
table.add (codes: executables, state: .csiEntry, action: .execute, next: .csiEntry)
183188
table.add (code: 0x7f, state: .csiEntry, action: .ignore, next: .csiEntry)
184189
table.add (codes: executables, state: .csiParam, action: .execute, next: .csiParam)
@@ -194,8 +199,14 @@ public class EscapeSequenceParser {
194199
table.add (code: 0x7f, state: .oscString, action: .oscPut, next: .oscString)
195200
table.add (codes: [0x9c, 0x1b, 0x18, 0x1a, 0x07], state: .oscString, action: .oscEnd, next: .ground)
196201
table.add (codes: r (low: 0x1c, high: 0x20), state: .oscString, action: .ignore, next: .oscString)
197-
// sos/pm/apc does nothing
198-
table.add (codes: [0x58, 0x5e, 0x5f], state: .escape, action: .ignore, next: .sosPmApcString)
202+
// apc
203+
table.add (code: 0x5f, state: .escape, action: .oscStart, next: .apcString)
204+
table.add (codes: printables, state: .apcString, action: .oscPut, next: .apcString)
205+
table.add (code: 0x7f, state: .apcString, action: .oscPut, next: .apcString)
206+
table.add (codes: [0x9c, 0x1b, 0x18, 0x1a, 0x07], state: .apcString, action: .oscEnd, next: .ground)
207+
table.add (codes: r (low: 0x1c, high: 0x20), state: .apcString, action: .ignore, next: .apcString)
208+
// sos/pm does nothing
209+
table.add (codes: [0x58, 0x5e], state: .escape, action: .ignore, next: .sosPmApcString)
199210
table.add (codes: printables, state: .sosPmApcString, action: .ignore, next: .sosPmApcString)
200211
table.add (codes: executables, state: .sosPmApcString, action: .ignore, next: .sosPmApcString)
201212
table.add (code: 0x9c, state: .sosPmApcString, action: .ignore, next: .ground)
@@ -263,6 +274,7 @@ public class EscapeSequenceParser {
263274
table.add (code: 0x7f, state: .dcsPassthrough, action: .ignore, next: .dcsPassthrough)
264275
table.add (codes: [0x1b, 0x9c], state: .dcsPassthrough, action: .dcsUnhook, next: .ground)
265276
table.add (code: NonAsciiPrintable, state: .oscString, action: .oscPut, next: .oscString)
277+
table.add (code: NonAsciiPrintable, state: .apcString, action: .oscPut, next: .apcString)
266278
return table
267279
}
268280

@@ -277,6 +289,10 @@ public class EscapeSequenceParser {
277289
/// receive both the OSC code as the first parameter, along with a byte array containing
278290
/// the payload for the OSC message.
279291
public typealias OscHandlerFallback = (Int, ArraySlice<UInt8>) -> ()
292+
293+
/// Signature for an APC handler, it will receive the byte array containing the data to this APC sequence
294+
public typealias ApcHandler = (ArraySlice<UInt8>) -> ()
295+
public typealias ApcHandlerFallback = (UInt8, ArraySlice<UInt8>) -> ()
280296

281297
typealias DscHandlerFallback = (UInt8, [Int]) -> ()
282298

@@ -301,6 +317,7 @@ public class EscapeSequenceParser {
301317
/// }
302318
/// ```
303319
public var oscHandlers: [Int:OscHandler] = [:]
320+
public var apcHandlers: [UInt8:ApcHandler] = [:]
304321
var executeHandlers: [UInt8:ExecuteHandler] = [:]
305322
var escHandlers: [cstring:EscHandler] = [:]
306323
var dcsHandlers: [cstring:DcsHandler] = [:]
@@ -313,6 +330,7 @@ public class EscapeSequenceParser {
313330

314331
// buffers over several calls
315332
var _osc: cstring
333+
var _apc: cstring
316334
var _pars: [Int]
317335
var _parsTxt: [UInt8]
318336
var _collect: cstring
@@ -325,6 +343,7 @@ public class EscapeSequenceParser {
325343
{
326344
table = EscapeSequenceParser.buildVt500TransitionTable()
327345
_osc = []
346+
_apc = []
328347
_pars = [0]
329348
_parsTxt = []
330349
_collect = []
@@ -340,6 +359,11 @@ public class EscapeSequenceParser {
340359
escHandlers [Array (flag.utf8)] = callback
341360
}
342361

362+
func setApcHandler (_ flag: String, _ callback: @escaping ApcHandler)
363+
{
364+
apcHandlers [flag.first!.asciiValue!] = callback
365+
}
366+
343367
func setCsiHandler (_ flag: String, _ callback: @escaping CsiHandler)
344368
{
345369
csiHandlers [flag.first!.asciiValue!] = callback
@@ -361,12 +385,16 @@ public class EscapeSequenceParser {
361385

362386
var oscHandlerFallback: OscHandlerFallback = { code, data -> () in
363387

388+
}
389+
var apcHandlerFallback: ApcHandlerFallback = { code, data -> () in
390+
364391
}
365392

366393
func reset ()
367394
{
368395
currentState = initialState
369396
_osc = []
397+
_apc = []
370398
_pars = [0]
371399
_collect = []
372400
activeDcsHandler = nil
@@ -397,6 +425,7 @@ public class EscapeSequenceParser {
397425
var print = -1
398426
var dcs = -1
399427
var osc = self._osc
428+
var apc = self._apc
400429
var collect = self._collect
401430
var pars = self._pars
402431
var parsTxt = self._parsTxt
@@ -493,6 +522,7 @@ public class EscapeSequenceParser {
493522
state.print = print
494523
state.dcs = dcs
495524
state.osc = osc
525+
state.apc = apc
496526
state.collect = collect
497527
let inject = errorHandler (state)
498528
if inject.abort {
@@ -533,6 +563,7 @@ public class EscapeSequenceParser {
533563
print = -1
534564
}
535565
osc = []
566+
apc = []
536567
pars = [0]
537568
parsTxt = []
538569
collect = []
@@ -559,6 +590,7 @@ public class EscapeSequenceParser {
559590
transition |= ParserState.escape.rawValue
560591
}
561592
osc = []
593+
apc = []
562594
pars = [0]
563595
parsTxt = []
564596
collect = []
@@ -569,44 +601,66 @@ public class EscapeSequenceParser {
569601
printHandler (data[print..<i])
570602
print = -1
571603
}
572-
osc = []
604+
let nextState = ParserState (rawValue: transition & 15)!
605+
if nextState == .apcString {
606+
apc = []
607+
} else {
608+
osc = []
609+
}
573610
case .oscPut:
574611
var j = i
575612
while j < end {
576613
let c = data [j]
577614
if c == ControlCodes.BEL || c == ControlCodes.CAN || c == ControlCodes.ESC {
578615
break
579616
} else if c >= 0x20 {
580-
osc.append (c)
617+
if currentState == .apcString {
618+
apc.append (c)
619+
} else {
620+
osc.append (c)
621+
}
581622
}
582623
j += 1
583624
}
584625
i = j - 1
585626
case .oscEnd:
586-
if osc.count != 0 && code != ControlCodes.CAN && code != ControlCodes.SUB {
587-
// NOTE: OSC subparsing is not part of the original parser
588-
// we do basic identifier parsing here to offer a jump table for OSC as well
589-
var oscCode : Int
590-
var content : ArraySlice<UInt8>
591-
let semiColonAscii = 59 // ';'
592-
593-
if let idx = osc.firstIndex (of: UInt8(semiColonAscii)){
594-
oscCode = EscapeSequenceParser.parseInt (osc [0..<idx])
595-
content = osc [(idx+1)...]
596-
} else {
597-
oscCode = EscapeSequenceParser.parseInt (osc[0...])
598-
content = []
627+
if currentState == .apcString {
628+
if apc.count != 0 && code != ControlCodes.CAN && code != ControlCodes.SUB {
629+
let command = apc [apc.startIndex]
630+
let content = apc.count > 1 ? apc[(apc.startIndex+1)...] : ArraySlice<UInt8>()
631+
if let handler = apcHandlers [command] {
632+
handler (content)
633+
} else {
634+
apcHandlerFallback (command, content)
635+
}
599636
}
600-
if let handler = oscHandlers [oscCode] {
601-
handler (content)
602-
} else {
603-
oscHandlerFallback (oscCode, content)
637+
} else {
638+
if osc.count != 0 && code != ControlCodes.CAN && code != ControlCodes.SUB {
639+
// NOTE: OSC subparsing is not part of the original parser
640+
// we do basic identifier parsing here to offer a jump table for OSC as well
641+
var oscCode : Int
642+
var content : ArraySlice<UInt8>
643+
let semiColonAscii = 59 // ';'
644+
645+
if let idx = osc.firstIndex (of: UInt8(semiColonAscii)){
646+
oscCode = EscapeSequenceParser.parseInt (osc [0..<idx])
647+
content = osc [(idx+1)...]
648+
} else {
649+
oscCode = EscapeSequenceParser.parseInt (osc[0...])
650+
content = []
651+
}
652+
if let handler = oscHandlers [oscCode] {
653+
handler (content)
654+
} else {
655+
oscHandlerFallback (oscCode, content)
656+
}
604657
}
605658
}
606659
if code == 0x1b {
607660
transition |= ParserState.escape.rawValue
608661
}
609662
osc = []
663+
apc = []
610664
pars = [0]
611665
parsTxt = []
612666
collect = []
@@ -624,6 +678,7 @@ public class EscapeSequenceParser {
624678
}
625679
// save non pushable buffers
626680
_osc = osc
681+
_apc = apc
627682
_collect = collect
628683
_pars = pars
629684
_parsTxt = parsTxt

0 commit comments

Comments
 (0)