renderer.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package core
  2. import (
  3. "fmt"
  4. "strings"
  5. "gopkg.in/AlecAivazis/survey.v1/terminal"
  6. )
  7. type Renderer struct {
  8. stdio terminal.Stdio
  9. lineCount int
  10. errorLineCount int
  11. }
  12. var ErrorTemplate = `{{color "red"}}{{ ErrorIcon }} Sorry, your reply was invalid: {{.Error}}{{color "reset"}}
  13. `
  14. func (r *Renderer) WithStdio(stdio terminal.Stdio) {
  15. r.stdio = stdio
  16. }
  17. func (r *Renderer) Stdio() terminal.Stdio {
  18. return r.stdio
  19. }
  20. func (r *Renderer) NewRuneReader() *terminal.RuneReader {
  21. return terminal.NewRuneReader(r.stdio)
  22. }
  23. func (r *Renderer) NewCursor() *terminal.Cursor {
  24. return &terminal.Cursor{
  25. In: r.stdio.In,
  26. Out: r.stdio.Out,
  27. }
  28. }
  29. func (r *Renderer) Error(invalid error) error {
  30. // since errors are printed on top we need to reset the prompt
  31. // as well as any previous error print
  32. r.resetPrompt(r.lineCount + r.errorLineCount)
  33. // we just cleared the prompt lines
  34. r.lineCount = 0
  35. out, err := RunTemplate(ErrorTemplate, invalid)
  36. if err != nil {
  37. return err
  38. }
  39. // keep track of how many lines are printed so we can clean up later
  40. r.errorLineCount = strings.Count(out, "\n")
  41. // send the message to the user
  42. fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), out)
  43. return nil
  44. }
  45. func (r *Renderer) resetPrompt(lines int) {
  46. // clean out current line in case tmpl didnt end in newline
  47. cursor := r.NewCursor()
  48. cursor.HorizontalAbsolute(0)
  49. terminal.EraseLine(r.stdio.Out, terminal.ERASE_LINE_ALL)
  50. // clean up what we left behind last time
  51. for i := 0; i < lines; i++ {
  52. cursor.PreviousLine(1)
  53. terminal.EraseLine(r.stdio.Out, terminal.ERASE_LINE_ALL)
  54. }
  55. }
  56. func (r *Renderer) Render(tmpl string, data interface{}) error {
  57. r.resetPrompt(r.lineCount)
  58. // render the template summarizing the current state
  59. out, err := RunTemplate(tmpl, data)
  60. if err != nil {
  61. return err
  62. }
  63. // keep track of how many lines are printed so we can clean up later
  64. r.lineCount = strings.Count(out, "\n")
  65. // print the summary
  66. fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), out)
  67. // nothing went wrong
  68. return nil
  69. }