| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- package editor
- import (
- "strings"
- "fmt"
- "moose/internal/buffer"
- "github.com/gdamore/tcell/v3/color"
- )
- const tabWidth = 4
- func expandTabs(s string) string {
- var b strings.Builder
- col := 0
- for _, r := range s {
- if r == '\t' {
- spaces := tabWidth - (col % tabWidth)
- b.WriteString(strings.Repeat(" ", spaces))
- col += spaces
- } else {
- b.WriteRune(r)
- col++
- }
- }
- return b.String()
- }
- func visualCol(lineText string, runeCol int) int {
- col := 0
- n := 0
- for _, r := range lineText {
- if n >= runeCol {
- break
- }
- if r == '\t' {
- col += tabWidth - (col % tabWidth)
- } else {
- col++
- }
- n++
- }
- return col
- }
- func (m Model) Render() {
- sWidth, sHeight := m.Screen.Size()
- maxHeight := sHeight - 2 // TODO: saturating sub?
- bLen := len(m.BM.Buffers)
- bufWidth := sWidth / bLen
- for i := range m.BM.Buffers {
- buf := &m.BM.Buffers[i]
- primary := buf.CM.Cursors[buf.CM.PrimaryIdx]
- curLine, _ := buffer.LineCol(buf, primary.Offset)
- buf.ScrollToShow(curLine, maxHeight)
- startOffset := buffer.OffsetForLine(buf, buf.TopLine)
- endOffset := buf.Rope.Len()
- if endLine := buf.TopLine + maxHeight; endLine < buffer.LineCount(buf) {
- endOffset = buffer.OffsetForLine(buf, endLine)
- }
- visible := string(buf.Rope.Slice(startOffset, endOffset))
- table := strings.SplitAfter(visible, "\n")
- for j, line := range table {
- if j + 1 > maxHeight { break }
- nums := fmt.Sprintf("%4d ", j + buf.TopLine)
- r := []rune(nums + expandTabs(line))
- if len(r) + 1 > bufWidth {
- r = r[:bufWidth]
- }
- m.Screen.PutStrStyled(bufWidth*i, j, string(r), m.Style)
- }
- if i == m.BM.CurrentIdx {
- for _, cur := range buf.CM.Cursors {
- line, col := buffer.LineCol(buf, cur.Offset)
- screenLine := line - buf.TopLine
- if screenLine < 0 || screenLine + 1 > maxHeight { continue }
- visCol := visualCol(buffer.LineText(buf, line), col)
- if visCol + 1 > bufWidth { continue }
- ch := buffer.RuneAt(buf, cur.Offset)
- if m.Mode == ModeWrite {
- m.Screen.SetContent(bufWidth * i + visCol + 5, screenLine, ch, nil, m.Style.Reverse(true))
- } else {
- m.Screen.SetContent(bufWidth * i + visCol + 5, screenLine, ch, nil, m.Style.Reverse(true).Foreground(color.Gray))
- }
- }
- }
- }
- for col := 0; col < sWidth; col++ {
- m.Screen.SetContent(col, maxHeight, ' ', nil, m.Style.Background(color.Black))
- }
- modeStr := m.Mode.String()
- if m.Mode == ModePalette {
- if strings.HasPrefix(m.BM.PaletteBuffer.String(), "/") {
- modeStr += " (command)"
- } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "?") {
- modeStr += " (find)"
- } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "=") {
- modeStr += " (replace)"
- }
- }
- m.Screen.PutStrStyled(sWidth - (len(modeStr) + 1), maxHeight, strings.ToUpper(modeStr), m.Style.Background(color.Black))
- if m.Mode == ModePalette {
- m.Screen.PutStrStyled(0, maxHeight + 1, m.BM.PaletteBuffer.String(), m.Style)
- for _, cur := range m.BM.PaletteBuffer.CM.Cursors {
- line, col := buffer.LineCol(&m.BM.PaletteBuffer, cur.Offset)
- if line + maxHeight != maxHeight { continue }
- if col + 1 > sWidth { continue }
- ch := buffer.RuneAt(&m.BM.PaletteBuffer, cur.Offset)
- m.Screen.SetContent(col, maxHeight + 1, ch, nil, m.Style.Reverse(true))
- }
- } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "moose.info:") {
- m.Screen.PutStrStyled(0, maxHeight + 1, string([]rune(m.BM.PaletteBuffer.String())[11:]), m.Style.Foreground(color.LightGray))
- } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "moose.warn:") {
- m.Screen.PutStrStyled(0, maxHeight + 1, string([]rune(m.BM.PaletteBuffer.String())[11:]), m.Style.Foreground(color.Orange))
- } else if strings.HasPrefix(m.BM.PaletteBuffer.String(), "moose.error:") {
- m.Screen.PutStrStyled(0, maxHeight + 1, string([]rune(m.BM.PaletteBuffer.String())[12:]), m.Style.Foreground(color.Red))
- }
- }
|