package main import ( "fmt" "os" tcellterm "git.sr.ht/~rockorager/tcell-term" "github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2/views" ) type model struct { term *tcellterm.VT s tcell.Screen termView views.View title *views.TextBar titleView views.View result *views.TextArea resultView views.View } func newModel() *model { var err error m := &model{} m.s, err = tcell.NewScreen() if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } if err = m.s.Init(); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } m.s.EnablePaste() w, _ := m.s.Size() m.title = views.NewTextBar() m.title.SetCenter( "nixpl", tcell.StyleDefault.Foreground(tcell.ColorBlue). Bold(true). Underline(true), ) m.titleView = views.NewViewPort(m.s, 0, 0, -1, 2) m.title.SetView(m.titleView) m.termView = views.NewViewPort(m.s, 0, 2, w/2, -1) m.term = tcellterm.New() m.term.SetSurface(m.termView) m.term.Attach(m.HandleEvent) m.resultView = views.NewViewPort(m.s, w/2, 2, w/2, -1) m.result = views.NewTextArea() m.result.SetView(m.resultView) m.s.EnableMouse() return m } // Update is the main event handler. It should only be called by the main thread func (m *model) Update(ev tcell.Event) { switch ev := ev.(type) { case *tcell.EventKey: switch ev.Key() { case tcell.KeyCtrlC: m.term.Close() m.s.Fini() return } if m.term != nil { m.term.HandleEvent(ev) } m.term.Draw() m.result.Draw() m.s.Show() case *tcell.EventResize: w, _ := m.s.Size() if m.term != nil { m.termView.Resize(0, 2, w/2, -1) m.term.Resize(m.termView.Size()) } m.titleView.Resize(0, 0, -1, 2) m.title.Resize() m.resultView.Resize(w/2, 2, w/2, -1) m.result.Resize() m.title.Draw() m.term.Draw() m.result.Draw() m.s.Sync() return case *tcellterm.EventRedraw: m.term.Draw() m.title.Draw() m.result.Draw() row, col, style, vis := m.term.Cursor() if vis { m.s.SetCursorStyle(style) m.s.ShowCursor(col, row+2) } else { m.s.HideCursor() } m.s.Show() return case *tcellterm.EventClosed: m.s.Clear() m.s.Fini() return case *tcell.EventPaste: m.term.HandleEvent(ev) return case *tcell.EventMouse: // Translate the coordinates to our global coordinates (y-2) x, y := ev.Position() if y-2 < 0 { // Event is outside our view return } e := tcell.NewEventMouse(x, y-2, ev.Buttons(), ev.Modifiers()) m.term.HandleEvent(e) return case *tcellterm.EventMouseMode: m.s.EnableMouse(ev.Flags()...) case *tcellterm.EventPanic: m.s.Clear() m.s.Fini() fmt.Println(ev.Error) } return } // HandleEvent is used to handle events from underlying widgets. Any events // which redraw must be executed in the main goroutine by posting the event back // to tcell func (m *model) HandleEvent(ev tcell.Event) { m.s.PostEvent(ev) } func (m *model) UpdateResult(result string) { m.result.SetContent(result) m.result.Draw() m.s.Sync() }