aboutsummaryrefslogtreecommitdiff
path: root/editor/editor.go
blob: 87b3effd8299402b7f35182b68a7df68ca23022c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package editor

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/prodhe/poe/gapbuffer"
)

// Editor is the edit component that holds text buffers. A UI of some sort operates on the editor to manipulate buffers.
type Editor interface {
	NewBuffer() (id int64, buf *Buffer)
	Buffer(id int64) *Buffer
	Buffers() ([]int64, []*Buffer)
	LoadBuffers(filenames []string)
	CloseBuffer(id int64)
	WorkDir() string
	Len() int
	Edit(bufid int64, cmd string) string
}

// New returns an empty editor with no buffers loaded.
func New() Editor {
	e := &ed{}
	e.buffers = map[int64]*Buffer{}
	e.workdir, _ = filepath.Abs(".")
	return e
}

// ed implements Editor.
type ed struct {
	buffers map[int64]*Buffer
	workdir string
}

// NewBuffer creates an empty buffer and appends it to the editor. Returns the new id and the new buffer.
func (e *ed) NewBuffer() (id int64, buf *Buffer) {
	buf = &Buffer{buf: &gapbuffer.Buffer{}}
	id = e.genBufferID()
	e.buffers[id] = buf
	return id, buf
}

// Buffer returns the buffer with given index. Nil if id not found.
func (e *ed) Buffer(id int64) *Buffer {
	if _, ok := e.buffers[id]; ok {
		return e.buffers[id]
	}
	return nil
}

// Buffers returns a slice of IDs and a slice of buffers.
func (e *ed) Buffers() ([]int64, []*Buffer) {
	ids := make([]int64, 0, len(e.buffers))
	bs := make([]*Buffer, 0, len(e.buffers))
	for i, b := range e.buffers {
		ids = append(ids, i)
		bs = append(bs, b)
	}
	return ids, bs
}

// CloseBuffer deletes the given buffer from memory. No warnings. Here be dragons.
func (e *ed) CloseBuffer(id int64) {
	delete(e.buffers, id)
}

// Len returns number of buffers currently in the editor.
func (e *ed) Len() int {
	return len(e.buffers)
}

// WorkDir returns the base working directory of the editor.
func (e *ed) WorkDir() string {
	if e.workdir == "" {
		d, _ := filepath.Abs(".")
		return d
	}
	return e.workdir
}

// LoadBuffers reads files from disk and loads them into windows. Screen need to be initialized.
func (e *ed) LoadBuffers(fns []string) {
	// load given filenames and append to buffer list
	for _, fn := range fns {
		_, buf := e.NewBuffer()
		buf.NewFile(fn)
		buf.ReadFile()
	}

	if len(fns) == 0 {
		e.NewBuffer()
	}
}

func (e *ed) genBufferID() int64 {
	return time.Now().UnixNano()
}

func (e *ed) Edit(bufid int64, args string) string {
	if len(args) < 1 {
		return ""
	}

	if _, ok := e.buffers[bufid]; !ok {
		// no such bufid
		return ""
	}

	switch args[0] {
	case 'f':
		var names []string
		for _, buf := range e.buffers {
			names = append(names, fmt.Sprintf("%s", buf.Name()))
		}
		return fmt.Sprintf("buffers:\n%s", strings.Join(names, "\n"))
	case '!':
		os.Chdir(e.buffers[bufid].WorkDir())
		cmd := strings.Split(string(args[1:]), " ")
		path, err := exec.LookPath(cmd[0])
		if err != nil { // path not found or not executable
			//return fmt.Sprintf("cannot execute: %s", cmd[0])
			return ""
		}
		out, err := exec.Command(path, cmd[1:]...).Output()
		if err != nil {
			return fmt.Sprintf("error: %s", err)
			break
		}
		outstr := string(out)
		return outstr
	}

	// no match
	return "?"
}