@@ -2,11 +2,11 @@ package readline
2
2
3
3
import (
4
4
"bufio"
5
+ "bytes"
5
6
"errors"
6
7
"fmt"
7
8
"io"
8
9
"strconv"
9
- "strings"
10
10
"sync"
11
11
"sync/atomic"
12
12
"time"
@@ -276,6 +276,7 @@ func (t *terminal) ioloop() {
276
276
defer t .Close ()
277
277
278
278
buf := bufio .NewReader (t .GetConfig ().Stdin )
279
+ var ansiBuf bytes.Buffer
279
280
280
281
for {
281
282
select {
@@ -293,7 +294,7 @@ func (t *terminal) ioloop() {
293
294
if r == '\x1b' {
294
295
// we're starting an ANSI escape sequence:
295
296
// keep reading until we reach the end of the sequence
296
- result , err = t .consumeANSIEscape (buf )
297
+ result , err = t .consumeANSIEscape (buf , & ansiBuf )
297
298
if err != nil {
298
299
return
299
300
}
@@ -309,7 +310,8 @@ func (t *terminal) ioloop() {
309
310
}
310
311
}
311
312
312
- func (t * terminal ) consumeANSIEscape (buf * bufio.Reader ) (result readResult , err error ) {
313
+ func (t * terminal ) consumeANSIEscape (buf * bufio.Reader , ansiBuf * bytes.Buffer ) (result readResult , err error ) {
314
+ ansiBuf .Reset ()
313
315
// initial character is either [ or O; if we got something else,
314
316
// treat the sequence as terminated and don't interpret it
315
317
initial , _ , err := buf .ReadRune ()
@@ -318,29 +320,27 @@ func (t *terminal) consumeANSIEscape(buf *bufio.Reader) (result readResult, err
318
320
}
319
321
320
322
// data consists of ; and 0-9 , anything else terminates the sequence
321
- var dataBuf strings.Builder
322
323
var type_ rune
323
324
for {
324
325
r , _ , err := buf .ReadRune ()
325
326
if err != nil {
326
327
return result , err
327
328
}
328
329
if r == ';' || ('0' <= r && r <= '9' ) {
329
- dataBuf .WriteRune (r )
330
+ ansiBuf .WriteRune (r )
330
331
} else {
331
332
type_ = r
332
333
break
333
334
}
334
335
}
335
- data := dataBuf .String ()
336
336
337
337
var r rune
338
338
switch type_ {
339
339
case 'R' :
340
340
if initial == '[' {
341
341
// DSR CPR response; if we can't parse it, just ignore it
342
342
// (do not return an error here because that would stop ioloop())
343
- if cpos , err := parseCPRResponse (data ); err == nil {
343
+ if cpos , err := parseCPRResponse (ansiBuf . Bytes () ); err == nil {
344
344
return readResult {r : 0 , ok : false , pos : & cpos }, nil
345
345
}
346
346
}
@@ -357,8 +357,15 @@ func (t *terminal) consumeANSIEscape(buf *bufio.Reader) (result readResult, err
357
357
case 'F' :
358
358
r = CharLineEnd
359
359
case '~' :
360
- if initial == '[' && data == "3" {
361
- r = MetaDeleteKey // this is the key typically labeled "Delete"
360
+ if initial == '[' {
361
+ switch string (ansiBuf .Bytes ()) {
362
+ case "3" :
363
+ r = MetaDeleteKey // this is the key typically labeled "Delete"
364
+ case "7" :
365
+ r = CharLineStart // "Home" key
366
+ case "8" :
367
+ r = CharLineEnd // "End" key
368
+ }
362
369
}
363
370
case 'Z' :
364
371
if initial == '[' {
@@ -372,10 +379,10 @@ func (t *terminal) consumeANSIEscape(buf *bufio.Reader) (result readResult, err
372
379
return // default: no interpretable rune value
373
380
}
374
381
375
- func parseCPRResponse (payload string ) (cursorPosition , error ) {
376
- if parts := strings . Split (payload , ";" ); len ( parts ) == 2 {
377
- if row , err := strconv .Atoi (parts [ 0 ] ); err == nil {
378
- if col , err := strconv .Atoi (parts [ 1 ] ); err == nil {
382
+ func parseCPRResponse (payload [] byte ) (cursorPosition , error ) {
383
+ if semicolonIdx := bytes . IndexByte (payload , ';' ); semicolonIdx != - 1 {
384
+ if row , err := strconv .Atoi (string ( payload [: semicolonIdx ]) ); err == nil {
385
+ if col , err := strconv .Atoi (string ( payload [ semicolonIdx + 1 :]) ); err == nil {
379
386
return cursorPosition {row : row , col : col }, nil
380
387
}
381
388
}
0 commit comments