main.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package show_error
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "os"
  8. "kitty/tools/cli"
  9. "kitty/tools/cli/markup"
  10. "kitty/tools/tty"
  11. "kitty/tools/tui"
  12. "kitty/tools/tui/loop"
  13. )
  14. var _ = fmt.Print
  15. type Options struct {
  16. Title string
  17. }
  18. type Message struct {
  19. Msg string `json:"msg"`
  20. Traceback string `json:"tb"`
  21. }
  22. func main(args []string, opts *Options) (rc int, err error) {
  23. if tty.IsTerminal(os.Stdin.Fd()) {
  24. return 1, fmt.Errorf("Input data for this kitten must be piped as JSON to STDIN")
  25. }
  26. data, err := io.ReadAll(os.Stdin)
  27. if err != nil {
  28. return 1, err
  29. }
  30. m := Message{}
  31. err = json.Unmarshal(data, &m)
  32. if err != nil {
  33. return 1, err
  34. }
  35. f := markup.New(true)
  36. if opts.Title != "" {
  37. fmt.Println(f.Err(opts.Title))
  38. fmt.Println(loop.EscapeCodeToSetWindowTitle(opts.Title))
  39. fmt.Println()
  40. }
  41. fmt.Println(m.Msg)
  42. show_traceback := false
  43. if m.Traceback != "" {
  44. lp, err := loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.NoMouseTracking)
  45. if err != nil {
  46. return 1, err
  47. }
  48. lp.OnInitialize = func() (string, error) {
  49. lp.SetCursorVisible(false)
  50. lp.QueueWriteString("\n\r\x1b[1;32mPress e to see detailed traceback or any other key to exit\x1b[m\r\n")
  51. return "", nil
  52. }
  53. lp.OnFinalize = func() string {
  54. lp.SetCursorVisible(true)
  55. return ""
  56. }
  57. lp.OnKeyEvent = func(event *loop.KeyEvent) error {
  58. if event.Type == loop.PRESS || event.Type == loop.REPEAT {
  59. if event.MatchesPressOrRepeat("e") || event.MatchesPressOrRepeat("shift+e") || event.MatchesPressOrRepeat("E") {
  60. show_traceback = true
  61. lp.Quit(0)
  62. } else {
  63. lp.Quit(1)
  64. }
  65. }
  66. if event.MatchesPressOrRepeat("enter") || event.MatchesPressOrRepeat("kp_enter") || event.MatchesPressOrRepeat("esc") || event.MatchesPressOrRepeat("ctrl+c") || event.MatchesPressOrRepeat("ctrl+d") {
  67. event.Handled = true
  68. lp.Quit(0)
  69. }
  70. return nil
  71. }
  72. lp.Run()
  73. if lp.ExitCode() == 1 {
  74. return 0, nil
  75. }
  76. }
  77. if show_traceback {
  78. fmt.Println(m.Traceback)
  79. fmt.Println()
  80. }
  81. tui.HoldTillEnter(true)
  82. return
  83. }
  84. func EntryPoint(root *cli.Command) *cli.Command {
  85. sc := root.AddSubCommand(&cli.Command{
  86. Name: "__show_error__",
  87. Hidden: true,
  88. Usage: "[options]",
  89. ShortDescription: "Show an error message. Internal use.",
  90. HelpText: "Show an error message. Used internally by kitty.",
  91. Run: func(cmd *cli.Command, args []string) (ret int, err error) {
  92. opts := &Options{}
  93. err = cmd.GetOptionValues(opts)
  94. if err != nil {
  95. return 1, err
  96. }
  97. return main(args, opts)
  98. },
  99. })
  100. sc.Add(cli.OptionSpec{
  101. Name: "--title",
  102. Default: "ERROR",
  103. Help: "The title for the error message",
  104. })
  105. return sc
  106. }