mirror of https://github.com/jetkvm/kvm.git
Minor serial helper improvements
This commit is contained in:
parent
2ce5623712
commit
e55653068c
|
|
@ -355,14 +355,45 @@ func (b *ConsoleBroker) handleRX(data []byte) {
|
||||||
if b.sink == nil || len(data) == 0 {
|
if b.sink == nil || len(data) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
text := normalize(data, b.norm)
|
|
||||||
if text != "" {
|
// If we’re mid TX line, end it before RX
|
||||||
scopedLogger.Info().Msg("Emitting RX data to sink")
|
if b.txLineActive {
|
||||||
b.emitToTerminal(fmt.Sprintf("%s: %s", b.labelRX, text))
|
b.emitToTerminal(b.lineSep())
|
||||||
|
b.txLineActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
last := data[len(data)-1]
|
text := normalize(data, b.norm)
|
||||||
b.rxAtLineEnd = (last == '\r' || last == '\n')
|
if text == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scopedLogger.Info().Msg("Emitting RX data to sink (with per-line prefixes)")
|
||||||
|
|
||||||
|
// Prefix every line, regardless of how the EOLs look
|
||||||
|
lines := splitAfterAnyEOL(text, b.norm.CRLF)
|
||||||
|
|
||||||
|
// Start from the broker's current RX line state
|
||||||
|
atLineEnd := b.rxAtLineEnd
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if atLineEnd {
|
||||||
|
// New physical line -> prefix with RX:
|
||||||
|
b.emitToTerminal(fmt.Sprintf("%s: %s", b.labelRX, line))
|
||||||
|
} else {
|
||||||
|
// Continuation of previous RX line -> no extra RX: prefix
|
||||||
|
b.emitToTerminal(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update line-end state based on this piece
|
||||||
|
atLineEnd = endsWithEOL(line, b.norm.CRLF)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist state for next RX chunk
|
||||||
|
b.rxAtLineEnd = atLineEnd
|
||||||
|
|
||||||
if b.pendingTX != nil && b.rxAtLineEnd {
|
if b.pendingTX != nil && b.rxAtLineEnd {
|
||||||
b.flushPendingTX()
|
b.flushPendingTX()
|
||||||
|
|
@ -427,6 +458,8 @@ func (b *ConsoleBroker) lineSep() string {
|
||||||
switch b.norm.CRLF {
|
switch b.norm.CRLF {
|
||||||
case CRLF_CRLF:
|
case CRLF_CRLF:
|
||||||
return "\r\n"
|
return "\r\n"
|
||||||
|
case CRLF_LFCR:
|
||||||
|
return "\n\r"
|
||||||
case CRLF_CR:
|
case CRLF_CR:
|
||||||
return "\r"
|
return "\r"
|
||||||
case CRLF_LF:
|
case CRLF_LF:
|
||||||
|
|
@ -436,6 +469,69 @@ func (b *ConsoleBroker) lineSep() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// splitAfterAnyEOL splits text into lines keeping the EOL with each piece.
|
||||||
|
// For CRLFAsIs it treats \r, \n, \r\n, and \n\r as EOLs.
|
||||||
|
// For other modes it uses the normalized separator.
|
||||||
|
func splitAfterAnyEOL(text string, mode CRLFMode) []string {
|
||||||
|
if text == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast path for normalized modes
|
||||||
|
switch mode {
|
||||||
|
case CRLF_LF:
|
||||||
|
return strings.SplitAfter(text, "\n")
|
||||||
|
case CRLF_CR:
|
||||||
|
return strings.SplitAfter(text, "\r")
|
||||||
|
case CRLF_CRLF:
|
||||||
|
return strings.SplitAfter(text, "\r\n")
|
||||||
|
case CRLF_LFCR:
|
||||||
|
return strings.SplitAfter(text, "\n\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRLFAsIs: scan bytes and treat \r, \n, \r\n, \n\r as one boundary
|
||||||
|
b := []byte(text)
|
||||||
|
var parts []string
|
||||||
|
start := 0
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
if b[i] == '\r' || b[i] == '\n' {
|
||||||
|
j := i + 1
|
||||||
|
// coalesce pair if the next is the "other" newline
|
||||||
|
if j < len(b) && ((b[i] == '\r' && b[j] == '\n') || (b[i] == '\n' && b[j] == '\r')) {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
parts = append(parts, string(b[start:j]))
|
||||||
|
start = j
|
||||||
|
i = j - 1 // advance past the EOL (or pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if start < len(b) {
|
||||||
|
parts = append(parts, string(b[start:]))
|
||||||
|
}
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
|
func endsWithEOL(s string, mode CRLFMode) bool {
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch mode {
|
||||||
|
case CRLF_CRLF:
|
||||||
|
return strings.HasSuffix(s, "\r\n")
|
||||||
|
case CRLF_LFCR:
|
||||||
|
return strings.HasSuffix(s, "\n\r")
|
||||||
|
case CRLF_LF:
|
||||||
|
return strings.HasSuffix(s, "\n")
|
||||||
|
case CRLF_CR:
|
||||||
|
return strings.HasSuffix(s, "\r")
|
||||||
|
default: // AsIs: any of \r, \n, \r\n, \n\r
|
||||||
|
return strings.HasSuffix(s, "\r\n") ||
|
||||||
|
strings.HasSuffix(s, "\n\r") ||
|
||||||
|
strings.HasSuffix(s, "\n") ||
|
||||||
|
strings.HasSuffix(s, "\r")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *ConsoleBroker) emitToTerminal(s string) {
|
func (b *ConsoleBroker) emitToTerminal(s string) {
|
||||||
if b.sink == nil || s == "" {
|
if b.sink == nil || s == "" {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue