Johan Rong 1 mesiac pred
rodič
commit
51848544ea
5 zmenil súbory, kde vykonal 250 pridanie a 131 odobranie
  1. 19 0
      internal/buffer/buffer.go
  2. 150 97
      internal/editor/action.go
  3. 18 0
      internal/editor/mode.go
  4. 60 34
      internal/editor/model.go
  5. 3 0
      main.go

+ 19 - 0
internal/buffer/buffer.go

@@ -66,6 +66,12 @@ func (buf *Buffer) Insert(content rune) {
 	}
 }
 
+func (buf *Buffer) Paste(content string) {
+	for _, r := range content {
+		buf.Insert(r)
+	}
+}
+
 func (buf *Buffer) Delete() {
 	buf.ensureRope()
 
@@ -111,6 +117,19 @@ func (buf *Buffer) Delete() {
 	buf.CM.DeduplicateAndSort()
 }
 
+func (buf *Buffer) Clear() {
+	primaryCursor := &Cursor{
+		Offset: 0,
+		Goal:   0,
+	}
+
+	buf.CM.Cursors = buf.CM.Cursors[:0]
+	buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
+	buf.CM.PrimaryIdx = 0
+
+	buf.Rope.Remove(0, buf.Rope.Len())
+}
+
 func (buf *Buffer) MoveHoriz(dir int) {
 	buf.ensureRope()
 

+ 150 - 97
internal/editor/action.go

@@ -1,5 +1,16 @@
 package editor
 
+import(
+	"strings"
+)
+
+type ActionManager = struct {
+	Common  []Action
+	Normal  []Action
+	Insert  []Action
+	Command []Action
+}
+
 type Action = struct {
 	Binding  string
 	Command  string
@@ -7,118 +18,160 @@ type Action = struct {
 	Callback func(*Model, []string)
 }
 
-func DefaultActions() []Action {
-	return []Action{
-		Action{
-			Binding: "left",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().MoveHoriz(-1)	
+func DefaultActionManager() ActionManager {
+	return ActionManager{
+		Common:  []Action{
+			Action{
+				Binding: "f12",
+				Callback: func(m *Model, args []string) {
+					m.Mode = ModeNormal
+				},
 			},
-		},
-		Action{
-			Binding: "right",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().MoveHoriz(1)
+			Action{
+				Binding: "left",
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().MoveHoriz(-1)	
+				},
 			},
-		},
-		Action{
-			Binding: "up",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().MoveVert(-1)
+			Action{
+				Binding: "right",
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().MoveHoriz(1)
+				},
 			},
-		},
-		Action{
-			Binding: "down",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().MoveVert(1)
+			Action{
+				Binding: "shift+ctrl+Rune[v]",
+				Command: "paste",
+				HasArgs: false,
+				Callback: func(m *Model, args []string) {
+					m.Screen.GetClipboard()
+				},
 			},
-		},
-		Action{
-			Binding: "shift+up",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().AddCursorVert(-1)
+			Action{
+				Binding: "ctrl+c",
+				Command: "q",
+				HasArgs: true,
+				Callback: func(m *Model, args []string) {
+					m.Quit()
+				},
 			},
 		},
-		Action{
-			Binding: "shift+down",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().AddCursorVert(1)
+		Normal:  []Action{
+			Action{
+				Binding: "Rune[i]",
+				Callback: func(m *Model, args []string) {
+					m.Mode = ModeInsert
+				},
 			},
-		},
-		Action{
-			Binding: "esc",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().ClearCursors()
+			Action{
+				Binding: "Rune[q]",
+				Callback: func(m *Model, args []string) {
+					m.Mode = ModeCommand
+					m.BM.CommandBuffer.Clear()
+					m.BM.CommandBuffer.Insert('/')
+				},
 			},
 		},
-		Action{
-			Binding: "tab",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				//TODO: implement m.Current().
-				for _ = range 4 {
-					m.Current().Insert(' ')
-				}
+		Insert:  []Action{
+			Action{
+				Binding: "up",
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().MoveVert(-1)
+				},
 			},
-		},
-		Action{
-			Binding: "shift+tab",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				// TODO: implement m.Current().
-				
+			Action{
+				Binding: "down",
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().MoveVert(1)
+				},
 			},
-		},
-		Action{
-			Binding: "backspace",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().Delete()
+			Action{
+				Binding: "shift+up",
+				Command: "TODO:",
+				HasArgs: false,
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().AddCursorVert(-1)
+				},
 			},
-		},
-		Action{
-			Binding: "enter",
-			Command: "TODO:",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Current().Insert('\n')
+			Action{
+				Binding: "shift+down",
+				Command: "TODO:",
+				HasArgs: false,
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().AddCursorVert(1)
+				},
 			},
-		},
-		Action{
-			Binding: "shift+ctrl+Rune[v]",
-			Command: "paste",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Screen.GetClipboard()
-				
-				//for _, r := range m.Screen.GetClipboard() {
-				//	m.Current().Insert(r)
-				//}
+			Action{
+				Binding: "esc",
+				Command: "TODO:",
+				HasArgs: false,
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().ClearCursors()
+				},
+			},
+			Action{
+				Binding: "tab",
+				Command: "TODO:",
+				HasArgs: false,
+				Callback: func(m *Model, args []string) {
+					for _ = range 4 {
+						m.BM.Current().Insert(' ')
+					}
+				},
+			},
+			Action{
+				Binding: "shift+tab",
+				Command: "TODO:",
+				HasArgs: false,
+				Callback: func(m *Model, args []string) {
+					// TODO: implement m.BM.Current().remove...
+					
+				},
+			},
+			Action{
+				Binding: "backspace",
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().Delete()
+				},
+			},
+			Action{
+				Binding: "enter",
+				Callback: func(m *Model, args []string) {
+					m.BM.Current().Insert('\n')
+				},
 			},
 		},
-		Action{
-			Binding: "ctrl+c",
-			Command: "q",
-			HasArgs: false,
-			Callback: func(m *Model, args []string) {
-				m.Quit()
+		Command: []Action{
+			Action{
+				Binding: "backspace",
+				Callback: func(m *Model, args []string) {
+					m.BM.CommandBuffer.Delete()
+				},
+			},
+			Action{
+				Binding: "enter",
+				Callback: func(m *Model, _ []string) {
+					input := m.BM.CommandBuffer.String()
+					args := strings.Split(input, " ")
+
+					if args[0] == "" {
+						m.Mode = ModeNormal
+						return
+					}
+
+					if strings.HasPrefix(args[0], "/") {
+						for _, action := range append(m.AM.Common, append(m.AM.Normal, m.AM.Insert...)...) {
+							if action.Command != "" && string([]rune(args[0])[1:]) == action.Command {
+								m.Mode = ModeNormal
+								action.Callback(m, args[1:])
+								return
+							}
+						}
+					}
+
+					m.Mode = ModeNormal
+					// TODO: Write an error to the commandbuffer 
+				},
 			},
 		},
 	}

+ 18 - 0
internal/editor/mode.go

@@ -0,0 +1,18 @@
+package editor
+
+type Mode int
+const (
+	ModeNormal Mode = iota
+	ModeInsert
+	ModeCommand
+)
+
+func (mode Mode) String() string {
+	switch mode {
+	case ModeNormal:  return "normal"
+	case ModeInsert:  return "insert"
+	case ModeCommand: return "command"
+	}
+
+	return "unknown"
+}

+ 60 - 34
internal/editor/model.go

@@ -7,21 +7,14 @@ import (
 )
 
 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 {
 	model := Model{
 		Screen:	       screen,
@@ -29,59 +22,92 @@ func NewModel(screen tcell.Screen, style tcell.Style) Model {
 		Mode:		   ModeNormal,
 		BM:            buffer.BufferManager{
 			Buffers:       []buffer.Buffer{buffer.NewBuffer()},
-			CurrentIdx:     0,
+			CurrentIdx:    0,
 			CommandBuffer: buffer.NewBuffer(),
 		},
-		Actions:       DefaultActions(),
+		AM:       DefaultActionManager(),
 		ShouldQuit:    false,
 	}
 
 	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() {
-	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 {
 		table := strings.SplitAfter(buf.String(), "\n")
 		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 {
 			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) {
-	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{})
 			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)
+			}
 		}
 	}
 }

+ 3 - 0
main.go

@@ -24,6 +24,7 @@ func main() {
 	m := editor.NewModel(s, style)
 
 	s.EnableMouse()
+	s.DisablePaste()
 	s.Clear()
 
 	quit := func() {
@@ -47,6 +48,8 @@ func main() {
 		switch ev := ev.(type) {
 		case *tcell.EventResize:
 			s.Sync()
+		case *tcell.EventClipboard:
+			m.BM.Current().Paste(string(ev.Data()))
 		case *tcell.EventKey:
 			m.HandleKeyInput(ev)
 		}