render.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package editor
  2. import (
  3. "strings"
  4. "strconv"
  5. "moose/internal/buffer"
  6. "github.com/gdamore/tcell/v3/color"
  7. )
  8. func (m Model) Render() {
  9. sWidth, sHeight := m.Screen.Size()
  10. maxHeight := sHeight - 2 // TODO: saturating sub?
  11. bLen := len(m.BM.Buffers)
  12. bufWidth := sWidth / bLen
  13. for i := range m.BM.Buffers {
  14. buf := &m.BM.Buffers[i]
  15. primary := buf.CM.Cursors[buf.CM.PrimaryIdx]
  16. curLine, _ := buffer.LineCol(buf, primary.Offset)
  17. buf.ScrollToShow(curLine, maxHeight)
  18. startOffset := buffer.OffsetForLine(buf, buf.TopLine)
  19. endOffset := buf.Rope.Len()
  20. if endLine := buf.TopLine + maxHeight; endLine < buffer.LineCount(buf) {
  21. endOffset = buffer.OffsetForLine(buf, endLine)
  22. }
  23. visible := string(buf.Rope.Slice(startOffset, endOffset))
  24. table := strings.SplitAfter(visible, "\n")
  25. for j, line := range table {
  26. if j + 1 > maxHeight { break }
  27. nums := strconv.Itoa(j + buf.TopLine)
  28. nums = strings.Repeat(" ", 4 - len(nums)) + nums
  29. r := []rune(nums + " " + line)
  30. if len(r) + 1 > bufWidth {
  31. r = r[:bufWidth]
  32. }
  33. m.Screen.PutStrStyled(bufWidth*i, j, string(r), m.Style)
  34. }
  35. if i == m.BM.CurrentIdx {
  36. for _, cur := range buf.CM.Cursors {
  37. line, col := buffer.LineCol(buf, cur.Offset)
  38. screenLine := line - buf.TopLine
  39. if screenLine < 0 || screenLine + 1 > maxHeight { continue }
  40. if col + 1 > bufWidth { continue }
  41. if m.Mode == ModeWrite {
  42. m.Screen.SetContent(bufWidth * i + col + 5, screenLine, ' ', nil, m.Style.Reverse(true))
  43. } else {
  44. m.Screen.SetContent(bufWidth * i + col + 5, screenLine, ' ', nil, m.Style.Reverse(true).Foreground(color.Gray))
  45. }
  46. }
  47. }
  48. }
  49. for col := 0; col < sWidth; col++ {
  50. m.Screen.SetContent(col, maxHeight, ' ', nil, m.Style.Reverse(true))
  51. }
  52. modeStr := m.Mode.String()
  53. if m.Mode == ModePalette {
  54. if strings.HasPrefix(m.BM.PaletteBuffer.String(), "/") {
  55. modeStr = "command"
  56. } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "?") {
  57. modeStr = "find"
  58. } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "=") {
  59. modeStr = "replace"
  60. }
  61. }
  62. m.Screen.PutStrStyled(sWidth - (len(modeStr) + 1), maxHeight, strings.ToUpper(modeStr), m.Style.Reverse(true))
  63. if m.Mode == ModePalette {
  64. m.Screen.PutStrStyled(0, maxHeight + 1, m.BM.PaletteBuffer.String(), m.Style)
  65. for _, cur := range m.BM.PaletteBuffer.CM.Cursors {
  66. line, col := buffer.LineCol(&m.BM.PaletteBuffer, cur.Offset)
  67. if line + maxHeight != maxHeight { continue }
  68. if col + 1 > sWidth { continue }
  69. m.Screen.SetContent(col, maxHeight + 1, ' ', nil, m.Style.Reverse(true))
  70. }
  71. } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "moose.info:") {
  72. m.Screen.PutStrStyled(0, maxHeight + 1, string([]rune(m.BM.PaletteBuffer.String())[11:]), m.Style.Foreground(color.LightGray))
  73. } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "moose.warn:") {
  74. m.Screen.PutStrStyled(0, maxHeight + 1, string([]rune(m.BM.PaletteBuffer.String())[11:]), m.Style.Foreground(color.Orange))
  75. } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "moose.error:") {
  76. m.Screen.PutStrStyled(0, maxHeight + 1, string([]rune(m.BM.PaletteBuffer.String())[12:]), m.Style.Foreground(color.Red))
  77. }
  78. }