|
@@ -7,21 +7,14 @@ import (
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
type Model struct {
|
|
type Model struct {
|
|
|
- Screen tcell.Screen
|
|
|
|
|
- Style tcell.Style
|
|
|
|
|
- Mode Mode
|
|
|
|
|
- BM buffer.BufferManager
|
|
|
|
|
- Actions []Action
|
|
|
|
|
- ShouldQuit bool
|
|
|
|
|
|
|
+ Screen tcell.Screen
|
|
|
|
|
+ Style tcell.Style
|
|
|
|
|
+ Mode Mode
|
|
|
|
|
+ BM buffer.BufferManager
|
|
|
|
|
+ AM ActionManager
|
|
|
|
|
+ ShouldQuit bool
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-type Mode int
|
|
|
|
|
-const (
|
|
|
|
|
- ModeNormal Mode = iota
|
|
|
|
|
- ModeInsert
|
|
|
|
|
- ModeCommand
|
|
|
|
|
-)
|
|
|
|
|
-
|
|
|
|
|
func NewModel(screen tcell.Screen, style tcell.Style) Model {
|
|
func NewModel(screen tcell.Screen, style tcell.Style) Model {
|
|
|
model := Model{
|
|
model := Model{
|
|
|
Screen: screen,
|
|
Screen: screen,
|
|
@@ -29,59 +22,92 @@ func NewModel(screen tcell.Screen, style tcell.Style) Model {
|
|
|
Mode: ModeNormal,
|
|
Mode: ModeNormal,
|
|
|
BM: buffer.BufferManager{
|
|
BM: buffer.BufferManager{
|
|
|
Buffers: []buffer.Buffer{buffer.NewBuffer()},
|
|
Buffers: []buffer.Buffer{buffer.NewBuffer()},
|
|
|
- CurrentIdx: 0,
|
|
|
|
|
|
|
+ CurrentIdx: 0,
|
|
|
CommandBuffer: buffer.NewBuffer(),
|
|
CommandBuffer: buffer.NewBuffer(),
|
|
|
},
|
|
},
|
|
|
- Actions: DefaultActions(),
|
|
|
|
|
|
|
+ AM: DefaultActionManager(),
|
|
|
ShouldQuit: false,
|
|
ShouldQuit: false,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return model
|
|
return model
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (m *Model) Quit() {
|
|
|
|
|
- m.ShouldQuit = true
|
|
|
|
|
|
|
+func (m *Model) CurrentActionSet() []Action {
|
|
|
|
|
+ switch m.Mode {
|
|
|
|
|
+ case ModeNormal: return m.AM.Normal
|
|
|
|
|
+ case ModeInsert: return m.AM.Insert
|
|
|
|
|
+ case ModeCommand: return m.AM.Command
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (m *Model) Current() *buffer.Buffer {
|
|
|
|
|
- if m.Mode == ModeCommand {
|
|
|
|
|
- return &m.BM.CommandBuffer
|
|
|
|
|
- } else {
|
|
|
|
|
- return m.BM.Current()
|
|
|
|
|
- }
|
|
|
|
|
|
|
+func (m *Model) Quit() {
|
|
|
|
|
+ m.ShouldQuit = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (m Model) Render() {
|
|
func (m Model) Render() {
|
|
|
- len := len(m.BM.Buffers)
|
|
|
|
|
- sWidth, _ := m.Screen.Size()
|
|
|
|
|
- width := sWidth / len
|
|
|
|
|
|
|
+ sWidth, sHeight := m.Screen.Size()
|
|
|
|
|
+
|
|
|
|
|
+ maxHeight := sHeight - 2 // TODO: saturating sub?
|
|
|
|
|
+
|
|
|
|
|
+ bLen := len(m.BM.Buffers)
|
|
|
|
|
+ bufWidth := sWidth / bLen
|
|
|
|
|
|
|
|
for i, buf := range m.BM.Buffers {
|
|
for i, buf := range m.BM.Buffers {
|
|
|
table := strings.SplitAfter(buf.String(), "\n")
|
|
table := strings.SplitAfter(buf.String(), "\n")
|
|
|
for j, line := range table {
|
|
for j, line := range table {
|
|
|
- m.Screen.PutStrStyled(width * i, j, line, m.Style)
|
|
|
|
|
|
|
+ m.Screen.PutStrStyled(bufWidth * i, j, line, m.Style)
|
|
|
|
|
+
|
|
|
|
|
+ if j + 1 > maxHeight { break }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for _, cur := range buf.CM.Cursors {
|
|
for _, cur := range buf.CM.Cursors {
|
|
|
line, col := buffer.LineCol(buf.Rope, cur.Offset)
|
|
line, col := buffer.LineCol(buf.Rope, cur.Offset)
|
|
|
- m.Screen.SetContent(width * i + col, line, ' ', nil, m.Style.Reverse(true))
|
|
|
|
|
|
|
+ if line + 1 > maxHeight { continue }
|
|
|
|
|
+
|
|
|
|
|
+ m.Screen.SetContent(bufWidth * i + col, line, ' ', nil, m.Style.Reverse(true))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ for col := 0; col < sWidth; col++ {
|
|
|
|
|
+ m.Screen.SetContent(col, maxHeight, ' ', nil, m.Style.Reverse(true))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ modeStr := m.Mode.String()
|
|
|
|
|
+ m.Screen.PutStrStyled(sWidth - (len(modeStr) + 1), maxHeight, strings.ToUpper(modeStr), m.Style.Reverse(true))
|
|
|
|
|
+
|
|
|
|
|
+ if m.Mode == ModeCommand {
|
|
|
|
|
+ m.Screen.PutStrStyled(0, maxHeight + 1, m.BM.CommandBuffer.String(), m.Style)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (m *Model) HandleKeyInput(ev *tcell.EventKey) {
|
|
func (m *Model) HandleKeyInput(ev *tcell.EventKey) {
|
|
|
- for i := range m.Actions {
|
|
|
|
|
- action := m.Actions[i]
|
|
|
|
|
|
|
+ for _, action := range append(m.AM.Common, m.CurrentActionSet()...) {
|
|
|
|
|
+ if action.Binding != "" && strings.ToLower(ev.Name()) == strings.ToLower(action.Binding) {
|
|
|
|
|
+ if action.Command != "" && action.HasArgs == true {
|
|
|
|
|
+ m.Mode = ModeCommand
|
|
|
|
|
+ m.BM.CommandBuffer.Paste(action.Command)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if strings.ToLower(ev.Name()) == strings.ToLower(action.Binding) {
|
|
|
|
|
action.Callback(m, []string{})
|
|
action.Callback(m, []string{})
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ev.Key() == tcell.KeyRune {
|
|
|
|
|
- for _, r := range ev.Str() {
|
|
|
|
|
- m.Current().Insert(r)
|
|
|
|
|
|
|
+ if m.Mode == ModeInsert {
|
|
|
|
|
+ if ev.Key() == tcell.KeyRune {
|
|
|
|
|
+ for _, r := range ev.Str() {
|
|
|
|
|
+ m.BM.Current().Insert(r)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if m.Mode == ModeCommand {
|
|
|
|
|
+ if ev.Key() == tcell.KeyRune {
|
|
|
|
|
+ for _, r := range ev.Str() {
|
|
|
|
|
+ m.BM.CommandBuffer.Insert(r)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|