diff options
author | Petter Rodhelind <petter.rodhelind@gmail.com> | 2018-02-22 23:15:13 +0100 |
---|---|---|
committer | Petter Rodhelind <petter.rodhelind@gmail.com> | 2018-02-22 23:15:13 +0100 |
commit | 4bca49f807544bd948a5f5f78e3787411252650f (patch) | |
tree | 5014acfd25b349488fd8116dccccac714bedb65d /poe.go | |
download | poe-4bca49f807544bd948a5f5f78e3787411252650f.tar.gz poe-4bca49f807544bd948a5f5f78e3787411252650f.tar.bz2 poe-4bca49f807544bd948a5f5f78e3787411252650f.zip |
first commit
Diffstat (limited to 'poe.go')
-rw-r--r-- | poe.go | 255 |
1 files changed, 255 insertions, 0 deletions
@@ -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 + } + } + } +} |