forked from evanmiller/hecate
/
hecate.go
139 lines (114 loc) · 2.83 KB
/
hecate.go
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
package main
import (
"fmt"
"os"
"path"
"errors"
mmap "github.com/edsrzf/mmap-go"
"github.com/nsf/termbox-go"
)
const PROGRAM_NAME = "hecate"
type FileInfo struct {
filename string
bytes []byte
}
func mainLoop(files []FileInfo, style Style) {
screens := defaultScreensForFiles(files)
active_idx := DATA_SCREEN_INDEX
var screen_key_channels []chan termbox.Event
var screen_quit_channels []chan bool
switch_channel := make(chan int)
main_key_channel := make(chan termbox.Event, 10)
layoutAndDrawScreen(screens[active_idx], style)
for _ = range screens {
key_channel := make(chan termbox.Event, 10)
screen_key_channels = append(screen_key_channels, key_channel)
quit_channel := make(chan bool, 10)
screen_quit_channels = append(screen_quit_channels, quit_channel)
}
for i, s := range screens {
go func(index int, screen Screen) {
screen.receiveEvents(screen_key_channels[index], switch_channel,
screen_quit_channels[index])
}(i, s)
}
go func() {
for {
event := termbox.PollEvent()
if event.Type == termbox.EventInterrupt {
break
} else {
main_key_channel <- event
}
}
}()
for {
do_quit := false
select {
case event := <-main_key_channel:
if event.Type == termbox.EventKey {
handleSpecialKeys(event.Key)
screen_key_channels[active_idx] <- event
}
if event.Type == termbox.EventResize {
layoutAndDrawScreen(screens[active_idx], style)
}
case new_screen_index := <-switch_channel:
if new_screen_index < len(screens) {
active_idx = new_screen_index
layoutAndDrawScreen(screens[active_idx], style)
} else {
do_quit = true
}
}
if do_quit {
for _, c := range screen_quit_channels {
c <- true
}
termbox.Interrupt()
break
}
}
}
func openFile (filename string) (*FileInfo, error) {
file, err := os.Open(filename)
if err != nil {
return nil, errors.New(fmt.Sprintf("Error opening file: %q\n", err.Error()))
}
fi, err := file.Stat()
if err != nil {
return nil, errors.New(fmt.Sprintf("Error stat'ing file: %q\n", err.Error()))
}
if fi.Size() < 8 {
return nil, errors.New(fmt.Sprintf("File %s is too short to be edited\n", filename))
}
mm, err := mmap.Map(file, mmap.RDONLY, 0)
if err != nil {
return nil, errors.New(fmt.Sprintf("Error mmap'ing file: %q\n", err.Error()))
}
return &FileInfo{filename: path.Base(filename), bytes: mm}, nil
}
func main() {
var err error
if len(os.Args) < 2 {
fmt.Printf("Usage: %s <filename> [...]\n", PROGRAM_NAME)
os.Exit(1)
}
var files []FileInfo
for i := 1; i < len(os.Args); i++ {
file_info, err := openFile(os.Args[i])
if err != nil {
fmt.Print(err)
os.Exit(1)
}
files = append(files, *file_info)
}
err = termbox.Init()
if err != nil {
panic(err)
}
defer termbox.Close()
style := defaultStyle()
termbox.SetOutputMode(outputMode)
mainLoop(files, style)
}