aboutsummaryrefslogtreecommitdiff
path: root/poe.go
diff options
context:
space:
mode:
authorPetter Rodhelind <petter.rodhelind@gmail.com>2018-02-22 23:15:13 +0100
committerPetter Rodhelind <petter.rodhelind@gmail.com>2018-02-22 23:15:13 +0100
commit4bca49f807544bd948a5f5f78e3787411252650f (patch)
tree5014acfd25b349488fd8116dccccac714bedb65d /poe.go
downloadpoe-4bca49f807544bd948a5f5f78e3787411252650f.tar.gz
poe-4bca49f807544bd948a5f5f78e3787411252650f.tar.bz2
poe-4bca49f807544bd948a5f5f78e3787411252650f.zip
first commit
Diffstat (limited to 'poe.go')
-rw-r--r--poe.go255
1 files changed, 255 insertions, 0 deletions
diff --git a/poe.go b/poe.go
new file mode 100644
index 0000000..996e3dc
--- /dev/null
+++ b/poe.go
@@ -0,0 +1,255 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+
+ "github.com/gdamore/tcell"
+ "github.com/prodhe/poe/gapbuffer"
+)
+
+const (
+ FnMessageWin = "+poe"
+ FnEmptyWin = ""
+ RuneWidthZero = '?'
+)
+
+var (
+ // Main screen terminal
+ screen tcell.Screen
+
+ // menu is the main tagline above everything else
+ menu *View
+
+ // workspace contains windows.
+ workspace *Workspace
+
+ // CurWin is a pointer to the currently focused window.
+ CurWin *Window
+
+ // Channels
+ events chan tcell.Event
+ quit chan bool
+
+ // baseDir stores the dir from which the program started in
+ baseDir string
+)
+
+// InitScreen initializes the tcell terminal.
+func InitScreen() {
+ var err error
+ screen, err = tcell.NewScreen()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ os.Exit(1)
+ }
+ if err = screen.Init(); err != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ os.Exit(1)
+ }
+ screen.SetStyle(bodyStyle)
+ screen.EnableMouse()
+ screen.Clear()
+ screen.Sync()
+}
+
+func InitMenu() {
+ menu = &View{
+ text: &Text{buf: gapbuffer.New()},
+ what: ViewMenu,
+ style: bodyStyle,
+ cursorStyle: bodyCursorStyle,
+ hilightStyle: bodyHilightStyle,
+ tabstop: 4,
+ }
+ fmt.Fprintf(menu, "Exit New Newcol")
+}
+
+func InitWorkspace() {
+ workspace = &Workspace{} // first resize event will set proper dimensions
+ workspace.AddCol()
+ //workspace.AddCol()
+ //workspace.LastCol().AddWindow(NewWindow(FnEmptyWin))
+}
+
+// LoadBuffers reads files from disk and loads them into windows. Screen need to be initialized.
+func LoadBuffers(fns []string) {
+ if len(fns) < 1 {
+ fns = append(fns, FnEmptyWin)
+ }
+
+ // setup windows
+ for i, fn := range fns {
+ win := NewWindow(fn)
+ win.LoadBuffer()
+ if i == 0 { // first window gets focus
+ CurWin = win
+ }
+ workspace.Col(0).AddWindow(win)
+ }
+
+ // add a base directory listing in new col
+ workspace.AddCol()
+ CmdOpen(baseDir)
+}
+
+func printMsg(format string, a ...interface{}) {
+ // get output window
+ var poewin *Window
+ for _, win := range AllWindows() {
+ poename := win.Dir() + string(filepath.Separator) + FnMessageWin
+ poename = filepath.Clean(poename)
+ if win.NameAbs() == poename && CurWin.Dir() == win.Dir() {
+ poewin = win
+ }
+ }
+
+ if poewin == nil {
+ poewin = NewWindow(CurWin.Dir() + string(filepath.Separator) + FnMessageWin)
+ poewin.body.what = ViewScratch
+
+ if len(workspace.cols) < 2 {
+ workspace.AddCol()
+ }
+ workspace.LastCol().AddWindow(poewin)
+ }
+
+ poewin.body.SetCursor(poewin.body.text.buf.Len(), 0)
+
+ if a == nil {
+ fmt.Fprintf(poewin.body, format)
+ return
+ }
+ fmt.Fprintf(poewin.body, format, a...)
+
+}
+
+func Redraw() {
+ menu.Draw()
+ workspace.Draw()
+ screen.Show()
+}
+
+func main() {
+ flag.Parse()
+
+ // store current working dir
+ var err error
+ baseDir, err = filepath.Abs(".")
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ //baseDir += string(filepath.Separator)
+
+ // Init
+ InitStyles()
+ InitScreen()
+
+ // proper closing and terminal cleanup on exit and error message on a possible panic
+ defer func() {
+ if screen != nil {
+ screen.Clear()
+ screen.Fini()
+ }
+ if err := recover(); err != nil {
+ buf := make([]byte, 1<<16)
+ n := runtime.Stack(buf, true)
+ fmt.Println("poe error:", err)
+ fmt.Printf("%s", buf[:n+1])
+ os.Exit(1)
+ }
+ }()
+
+ // Setup top menu
+ InitMenu()
+
+ // Create initial workspace
+ InitWorkspace()
+
+ InitCommands()
+
+ // This loads all buffers reading file names from command line and populates the workspace.
+ LoadBuffers(flag.Args())
+
+ events = make(chan tcell.Event, 100)
+ quit = make(chan bool, 1)
+
+ go func() {
+ for {
+ if screen != nil {
+ events <- screen.PollEvent()
+ }
+ }
+ }()
+
+ // main loop
+loop:
+ for {
+ Redraw()
+
+ // Check for events
+ var event tcell.Event
+ select {
+ case <-quit:
+ break loop
+ case event = <-events:
+ }
+
+ for event != nil {
+ switch e := event.(type) {
+ case *tcell.EventResize:
+ w, h := screen.Size()
+ menu.Resize(0, 0, w, 1)
+ workspace.Resize(0, 1, w, h-1)
+ screen.Clear()
+ screen.Sync()
+ case *tcell.EventKey: // system wide shortcuts
+ switch e.Key() {
+ case tcell.KeyCtrlL: // refresh terminal
+ screen.Clear()
+ screen.Sync()
+ default: // let the focused view handle event
+ if menu.focused {
+ menu.HandleEvent(e)
+ break
+ }
+ CurWin.HandleEvent(e)
+ }
+ case *tcell.EventMouse:
+ mx, my := e.Position()
+
+ // find which window to send the event to
+ for _, win := range AllWindows() {
+ win.UnFocus()
+ if mx >= win.x && mx < win.x+win.w &&
+ my >= win.y && my < win.y+win.h {
+ CurWin = win
+ }
+ }
+
+ // check if we are in the menu
+ menu.focused = false
+ if my < 1 {
+ menu.focused = true
+ menu.HandleEvent(e)
+ break
+ }
+
+ CurWin.HandleEvent(e)
+ }
+
+ event = nil
+
+ // check tcell event queue before returning to main event check
+ select {
+ case event = <-events:
+ default:
+ event = nil
+ }
+ }
+ }
+}