win_event_handler.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. // +build windows
  2. package winterm
  3. import (
  4. "bytes"
  5. "log"
  6. "os"
  7. "strconv"
  8. "github.com/Azure/go-ansiterm"
  9. )
  10. type windowsAnsiEventHandler struct {
  11. fd uintptr
  12. file *os.File
  13. infoReset *CONSOLE_SCREEN_BUFFER_INFO
  14. sr scrollRegion
  15. buffer bytes.Buffer
  16. attributes uint16
  17. inverted bool
  18. wrapNext bool
  19. drewMarginByte bool
  20. originMode bool
  21. marginByte byte
  22. curInfo *CONSOLE_SCREEN_BUFFER_INFO
  23. curPos COORD
  24. logf func(string, ...interface{})
  25. }
  26. type Option func(*windowsAnsiEventHandler)
  27. func WithLogf(f func(string, ...interface{})) Option {
  28. return func(w *windowsAnsiEventHandler) {
  29. w.logf = f
  30. }
  31. }
  32. func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
  33. infoReset, err := GetConsoleScreenBufferInfo(fd)
  34. if err != nil {
  35. return nil
  36. }
  37. h := &windowsAnsiEventHandler{
  38. fd: fd,
  39. file: file,
  40. infoReset: infoReset,
  41. attributes: infoReset.Attributes,
  42. }
  43. for _, o := range opts {
  44. o(h)
  45. }
  46. if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
  47. logFile, _ := os.Create("winEventHandler.log")
  48. logger := log.New(logFile, "", log.LstdFlags)
  49. if h.logf != nil {
  50. l := h.logf
  51. h.logf = func(s string, v ...interface{}) {
  52. l(s, v...)
  53. logger.Printf(s, v...)
  54. }
  55. } else {
  56. h.logf = logger.Printf
  57. }
  58. }
  59. if h.logf == nil {
  60. h.logf = func(string, ...interface{}) {}
  61. }
  62. return h
  63. }
  64. type scrollRegion struct {
  65. top int16
  66. bottom int16
  67. }
  68. // simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
  69. // current cursor position and scroll region settings, in which case it returns
  70. // true. If no special handling is necessary, then it does nothing and returns
  71. // false.
  72. //
  73. // In the false case, the caller should ensure that a carriage return
  74. // and line feed are inserted or that the text is otherwise wrapped.
  75. func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
  76. if h.wrapNext {
  77. if err := h.Flush(); err != nil {
  78. return false, err
  79. }
  80. h.clearWrap()
  81. }
  82. pos, info, err := h.getCurrentInfo()
  83. if err != nil {
  84. return false, err
  85. }
  86. sr := h.effectiveSr(info.Window)
  87. if pos.Y == sr.bottom {
  88. // Scrolling is necessary. Let Windows automatically scroll if the scrolling region
  89. // is the full window.
  90. if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
  91. if includeCR {
  92. pos.X = 0
  93. h.updatePos(pos)
  94. }
  95. return false, nil
  96. }
  97. // A custom scroll region is active. Scroll the window manually to simulate
  98. // the LF.
  99. if err := h.Flush(); err != nil {
  100. return false, err
  101. }
  102. h.logf("Simulating LF inside scroll region")
  103. if err := h.scrollUp(1); err != nil {
  104. return false, err
  105. }
  106. if includeCR {
  107. pos.X = 0
  108. if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
  109. return false, err
  110. }
  111. }
  112. return true, nil
  113. } else if pos.Y < info.Window.Bottom {
  114. // Let Windows handle the LF.
  115. pos.Y++
  116. if includeCR {
  117. pos.X = 0
  118. }
  119. h.updatePos(pos)
  120. return false, nil
  121. } else {
  122. // The cursor is at the bottom of the screen but outside the scroll
  123. // region. Skip the LF.
  124. h.logf("Simulating LF outside scroll region")
  125. if includeCR {
  126. if err := h.Flush(); err != nil {
  127. return false, err
  128. }
  129. pos.X = 0
  130. if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
  131. return false, err
  132. }
  133. }
  134. return true, nil
  135. }
  136. }
  137. // executeLF executes a LF without a CR.
  138. func (h *windowsAnsiEventHandler) executeLF() error {
  139. handled, err := h.simulateLF(false)
  140. if err != nil {
  141. return err
  142. }
  143. if !handled {
  144. // Windows LF will reset the cursor column position. Write the LF
  145. // and restore the cursor position.
  146. pos, _, err := h.getCurrentInfo()
  147. if err != nil {
  148. return err
  149. }
  150. h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
  151. if pos.X != 0 {
  152. if err := h.Flush(); err != nil {
  153. return err
  154. }
  155. h.logf("Resetting cursor position for LF without CR")
  156. if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
  157. return err
  158. }
  159. }
  160. }
  161. return nil
  162. }
  163. func (h *windowsAnsiEventHandler) Print(b byte) error {
  164. if h.wrapNext {
  165. h.buffer.WriteByte(h.marginByte)
  166. h.clearWrap()
  167. if _, err := h.simulateLF(true); err != nil {
  168. return err
  169. }
  170. }
  171. pos, info, err := h.getCurrentInfo()
  172. if err != nil {
  173. return err
  174. }
  175. if pos.X == info.Size.X-1 {
  176. h.wrapNext = true
  177. h.marginByte = b
  178. } else {
  179. pos.X++
  180. h.updatePos(pos)
  181. h.buffer.WriteByte(b)
  182. }
  183. return nil
  184. }
  185. func (h *windowsAnsiEventHandler) Execute(b byte) error {
  186. switch b {
  187. case ansiterm.ANSI_TAB:
  188. h.logf("Execute(TAB)")
  189. // Move to the next tab stop, but preserve auto-wrap if already set.
  190. if !h.wrapNext {
  191. pos, info, err := h.getCurrentInfo()
  192. if err != nil {
  193. return err
  194. }
  195. pos.X = (pos.X + 8) - pos.X%8
  196. if pos.X >= info.Size.X {
  197. pos.X = info.Size.X - 1
  198. }
  199. if err := h.Flush(); err != nil {
  200. return err
  201. }
  202. if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
  203. return err
  204. }
  205. }
  206. return nil
  207. case ansiterm.ANSI_BEL:
  208. h.buffer.WriteByte(ansiterm.ANSI_BEL)
  209. return nil
  210. case ansiterm.ANSI_BACKSPACE:
  211. if h.wrapNext {
  212. if err := h.Flush(); err != nil {
  213. return err
  214. }
  215. h.clearWrap()
  216. }
  217. pos, _, err := h.getCurrentInfo()
  218. if err != nil {
  219. return err
  220. }
  221. if pos.X > 0 {
  222. pos.X--
  223. h.updatePos(pos)
  224. h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
  225. }
  226. return nil
  227. case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
  228. // Treat as true LF.
  229. return h.executeLF()
  230. case ansiterm.ANSI_LINE_FEED:
  231. // Simulate a CR and LF for now since there is no way in go-ansiterm
  232. // to tell if the LF should include CR (and more things break when it's
  233. // missing than when it's incorrectly added).
  234. handled, err := h.simulateLF(true)
  235. if handled || err != nil {
  236. return err
  237. }
  238. return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
  239. case ansiterm.ANSI_CARRIAGE_RETURN:
  240. if h.wrapNext {
  241. if err := h.Flush(); err != nil {
  242. return err
  243. }
  244. h.clearWrap()
  245. }
  246. pos, _, err := h.getCurrentInfo()
  247. if err != nil {
  248. return err
  249. }
  250. if pos.X != 0 {
  251. pos.X = 0
  252. h.updatePos(pos)
  253. h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
  254. }
  255. return nil
  256. default:
  257. return nil
  258. }
  259. }
  260. func (h *windowsAnsiEventHandler) CUU(param int) error {
  261. if err := h.Flush(); err != nil {
  262. return err
  263. }
  264. h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
  265. h.clearWrap()
  266. return h.moveCursorVertical(-param)
  267. }
  268. func (h *windowsAnsiEventHandler) CUD(param int) error {
  269. if err := h.Flush(); err != nil {
  270. return err
  271. }
  272. h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
  273. h.clearWrap()
  274. return h.moveCursorVertical(param)
  275. }
  276. func (h *windowsAnsiEventHandler) CUF(param int) error {
  277. if err := h.Flush(); err != nil {
  278. return err
  279. }
  280. h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
  281. h.clearWrap()
  282. return h.moveCursorHorizontal(param)
  283. }
  284. func (h *windowsAnsiEventHandler) CUB(param int) error {
  285. if err := h.Flush(); err != nil {
  286. return err
  287. }
  288. h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
  289. h.clearWrap()
  290. return h.moveCursorHorizontal(-param)
  291. }
  292. func (h *windowsAnsiEventHandler) CNL(param int) error {
  293. if err := h.Flush(); err != nil {
  294. return err
  295. }
  296. h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
  297. h.clearWrap()
  298. return h.moveCursorLine(param)
  299. }
  300. func (h *windowsAnsiEventHandler) CPL(param int) error {
  301. if err := h.Flush(); err != nil {
  302. return err
  303. }
  304. h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
  305. h.clearWrap()
  306. return h.moveCursorLine(-param)
  307. }
  308. func (h *windowsAnsiEventHandler) CHA(param int) error {
  309. if err := h.Flush(); err != nil {
  310. return err
  311. }
  312. h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
  313. h.clearWrap()
  314. return h.moveCursorColumn(param)
  315. }
  316. func (h *windowsAnsiEventHandler) VPA(param int) error {
  317. if err := h.Flush(); err != nil {
  318. return err
  319. }
  320. h.logf("VPA: [[%d]]", param)
  321. h.clearWrap()
  322. info, err := GetConsoleScreenBufferInfo(h.fd)
  323. if err != nil {
  324. return err
  325. }
  326. window := h.getCursorWindow(info)
  327. position := info.CursorPosition
  328. position.Y = window.Top + int16(param) - 1
  329. return h.setCursorPosition(position, window)
  330. }
  331. func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
  332. if err := h.Flush(); err != nil {
  333. return err
  334. }
  335. h.logf("CUP: [[%d %d]]", row, col)
  336. h.clearWrap()
  337. info, err := GetConsoleScreenBufferInfo(h.fd)
  338. if err != nil {
  339. return err
  340. }
  341. window := h.getCursorWindow(info)
  342. position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
  343. return h.setCursorPosition(position, window)
  344. }
  345. func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
  346. if err := h.Flush(); err != nil {
  347. return err
  348. }
  349. h.logf("HVP: [[%d %d]]", row, col)
  350. h.clearWrap()
  351. return h.CUP(row, col)
  352. }
  353. func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
  354. if err := h.Flush(); err != nil {
  355. return err
  356. }
  357. h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
  358. h.clearWrap()
  359. return nil
  360. }
  361. func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
  362. if err := h.Flush(); err != nil {
  363. return err
  364. }
  365. h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
  366. h.clearWrap()
  367. h.originMode = enable
  368. return h.CUP(1, 1)
  369. }
  370. func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
  371. if err := h.Flush(); err != nil {
  372. return err
  373. }
  374. h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
  375. h.clearWrap()
  376. if err := h.ED(2); err != nil {
  377. return err
  378. }
  379. info, err := GetConsoleScreenBufferInfo(h.fd)
  380. if err != nil {
  381. return err
  382. }
  383. targetWidth := int16(80)
  384. if use132 {
  385. targetWidth = 132
  386. }
  387. if info.Size.X < targetWidth {
  388. if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
  389. h.logf("set buffer failed: %v", err)
  390. return err
  391. }
  392. }
  393. window := info.Window
  394. window.Left = 0
  395. window.Right = targetWidth - 1
  396. if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
  397. h.logf("set window failed: %v", err)
  398. return err
  399. }
  400. if info.Size.X > targetWidth {
  401. if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
  402. h.logf("set buffer failed: %v", err)
  403. return err
  404. }
  405. }
  406. return SetConsoleCursorPosition(h.fd, COORD{0, 0})
  407. }
  408. func (h *windowsAnsiEventHandler) ED(param int) error {
  409. if err := h.Flush(); err != nil {
  410. return err
  411. }
  412. h.logf("ED: [%v]", []string{strconv.Itoa(param)})
  413. h.clearWrap()
  414. // [J -- Erases from the cursor to the end of the screen, including the cursor position.
  415. // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
  416. // [2J -- Erases the complete display. The cursor does not move.
  417. // Notes:
  418. // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
  419. info, err := GetConsoleScreenBufferInfo(h.fd)
  420. if err != nil {
  421. return err
  422. }
  423. var start COORD
  424. var end COORD
  425. switch param {
  426. case 0:
  427. start = info.CursorPosition
  428. end = COORD{info.Size.X - 1, info.Size.Y - 1}
  429. case 1:
  430. start = COORD{0, 0}
  431. end = info.CursorPosition
  432. case 2:
  433. start = COORD{0, 0}
  434. end = COORD{info.Size.X - 1, info.Size.Y - 1}
  435. }
  436. err = h.clearRange(h.attributes, start, end)
  437. if err != nil {
  438. return err
  439. }
  440. // If the whole buffer was cleared, move the window to the top while preserving
  441. // the window-relative cursor position.
  442. if param == 2 {
  443. pos := info.CursorPosition
  444. window := info.Window
  445. pos.Y -= window.Top
  446. window.Bottom -= window.Top
  447. window.Top = 0
  448. if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
  449. return err
  450. }
  451. if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
  452. return err
  453. }
  454. }
  455. return nil
  456. }
  457. func (h *windowsAnsiEventHandler) EL(param int) error {
  458. if err := h.Flush(); err != nil {
  459. return err
  460. }
  461. h.logf("EL: [%v]", strconv.Itoa(param))
  462. h.clearWrap()
  463. // [K -- Erases from the cursor to the end of the line, including the cursor position.
  464. // [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
  465. // [2K -- Erases the complete line.
  466. info, err := GetConsoleScreenBufferInfo(h.fd)
  467. if err != nil {
  468. return err
  469. }
  470. var start COORD
  471. var end COORD
  472. switch param {
  473. case 0:
  474. start = info.CursorPosition
  475. end = COORD{info.Size.X, info.CursorPosition.Y}
  476. case 1:
  477. start = COORD{0, info.CursorPosition.Y}
  478. end = info.CursorPosition
  479. case 2:
  480. start = COORD{0, info.CursorPosition.Y}
  481. end = COORD{info.Size.X, info.CursorPosition.Y}
  482. }
  483. err = h.clearRange(h.attributes, start, end)
  484. if err != nil {
  485. return err
  486. }
  487. return nil
  488. }
  489. func (h *windowsAnsiEventHandler) IL(param int) error {
  490. if err := h.Flush(); err != nil {
  491. return err
  492. }
  493. h.logf("IL: [%v]", strconv.Itoa(param))
  494. h.clearWrap()
  495. return h.insertLines(param)
  496. }
  497. func (h *windowsAnsiEventHandler) DL(param int) error {
  498. if err := h.Flush(); err != nil {
  499. return err
  500. }
  501. h.logf("DL: [%v]", strconv.Itoa(param))
  502. h.clearWrap()
  503. return h.deleteLines(param)
  504. }
  505. func (h *windowsAnsiEventHandler) ICH(param int) error {
  506. if err := h.Flush(); err != nil {
  507. return err
  508. }
  509. h.logf("ICH: [%v]", strconv.Itoa(param))
  510. h.clearWrap()
  511. return h.insertCharacters(param)
  512. }
  513. func (h *windowsAnsiEventHandler) DCH(param int) error {
  514. if err := h.Flush(); err != nil {
  515. return err
  516. }
  517. h.logf("DCH: [%v]", strconv.Itoa(param))
  518. h.clearWrap()
  519. return h.deleteCharacters(param)
  520. }
  521. func (h *windowsAnsiEventHandler) SGR(params []int) error {
  522. if err := h.Flush(); err != nil {
  523. return err
  524. }
  525. strings := []string{}
  526. for _, v := range params {
  527. strings = append(strings, strconv.Itoa(v))
  528. }
  529. h.logf("SGR: [%v]", strings)
  530. if len(params) <= 0 {
  531. h.attributes = h.infoReset.Attributes
  532. h.inverted = false
  533. } else {
  534. for _, attr := range params {
  535. if attr == ansiterm.ANSI_SGR_RESET {
  536. h.attributes = h.infoReset.Attributes
  537. h.inverted = false
  538. continue
  539. }
  540. h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
  541. }
  542. }
  543. attributes := h.attributes
  544. if h.inverted {
  545. attributes = invertAttributes(attributes)
  546. }
  547. err := SetConsoleTextAttribute(h.fd, attributes)
  548. if err != nil {
  549. return err
  550. }
  551. return nil
  552. }
  553. func (h *windowsAnsiEventHandler) SU(param int) error {
  554. if err := h.Flush(); err != nil {
  555. return err
  556. }
  557. h.logf("SU: [%v]", []string{strconv.Itoa(param)})
  558. h.clearWrap()
  559. return h.scrollUp(param)
  560. }
  561. func (h *windowsAnsiEventHandler) SD(param int) error {
  562. if err := h.Flush(); err != nil {
  563. return err
  564. }
  565. h.logf("SD: [%v]", []string{strconv.Itoa(param)})
  566. h.clearWrap()
  567. return h.scrollDown(param)
  568. }
  569. func (h *windowsAnsiEventHandler) DA(params []string) error {
  570. h.logf("DA: [%v]", params)
  571. // DA cannot be implemented because it must send data on the VT100 input stream,
  572. // which is not available to go-ansiterm.
  573. return nil
  574. }
  575. func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
  576. if err := h.Flush(); err != nil {
  577. return err
  578. }
  579. h.logf("DECSTBM: [%d, %d]", top, bottom)
  580. // Windows is 0 indexed, Linux is 1 indexed
  581. h.sr.top = int16(top - 1)
  582. h.sr.bottom = int16(bottom - 1)
  583. // This command also moves the cursor to the origin.
  584. h.clearWrap()
  585. return h.CUP(1, 1)
  586. }
  587. func (h *windowsAnsiEventHandler) RI() error {
  588. if err := h.Flush(); err != nil {
  589. return err
  590. }
  591. h.logf("RI: []")
  592. h.clearWrap()
  593. info, err := GetConsoleScreenBufferInfo(h.fd)
  594. if err != nil {
  595. return err
  596. }
  597. sr := h.effectiveSr(info.Window)
  598. if info.CursorPosition.Y == sr.top {
  599. return h.scrollDown(1)
  600. }
  601. return h.moveCursorVertical(-1)
  602. }
  603. func (h *windowsAnsiEventHandler) IND() error {
  604. h.logf("IND: []")
  605. return h.executeLF()
  606. }
  607. func (h *windowsAnsiEventHandler) Flush() error {
  608. h.curInfo = nil
  609. if h.buffer.Len() > 0 {
  610. h.logf("Flush: [%s]", h.buffer.Bytes())
  611. if _, err := h.buffer.WriteTo(h.file); err != nil {
  612. return err
  613. }
  614. }
  615. if h.wrapNext && !h.drewMarginByte {
  616. h.logf("Flush: drawing margin byte '%c'", h.marginByte)
  617. info, err := GetConsoleScreenBufferInfo(h.fd)
  618. if err != nil {
  619. return err
  620. }
  621. charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
  622. size := COORD{1, 1}
  623. position := COORD{0, 0}
  624. region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
  625. if err := WriteConsoleOutput(h.fd, charInfo, size, position, &region); err != nil {
  626. return err
  627. }
  628. h.drewMarginByte = true
  629. }
  630. return nil
  631. }
  632. // cacheConsoleInfo ensures that the current console screen information has been queried
  633. // since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
  634. func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
  635. if h.curInfo == nil {
  636. info, err := GetConsoleScreenBufferInfo(h.fd)
  637. if err != nil {
  638. return COORD{}, nil, err
  639. }
  640. h.curInfo = info
  641. h.curPos = info.CursorPosition
  642. }
  643. return h.curPos, h.curInfo, nil
  644. }
  645. func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
  646. if h.curInfo == nil {
  647. panic("failed to call getCurrentInfo before calling updatePos")
  648. }
  649. h.curPos = pos
  650. }
  651. // clearWrap clears the state where the cursor is in the margin
  652. // waiting for the next character before wrapping the line. This must
  653. // be done before most operations that act on the cursor.
  654. func (h *windowsAnsiEventHandler) clearWrap() {
  655. h.wrapNext = false
  656. h.drewMarginByte = false
  657. }