aboutsummaryrefslogtreecommitdiff
path: root/ui/tcell
diff options
context:
space:
mode:
Diffstat (limited to 'ui/tcell')
-rw-r--r--ui/tcell/layout.go32
-rw-r--r--ui/tcell/style.go23
-rw-r--r--ui/tcell/tcell.go101
-rw-r--r--ui/tcell/view.go72
-rw-r--r--ui/tcell/window.go46
5 files changed, 154 insertions, 120 deletions
diff --git a/ui/tcell/layout.go b/ui/tcell/layout.go
index 599fb6a..bc30f8c 100644
--- a/ui/tcell/layout.go
+++ b/ui/tcell/layout.go
@@ -80,7 +80,8 @@ func (wrk *Workspace) Draw() {
// draw vertical lines between cols
for x, y := col.x+col.w+1, wrk.y; y < wrk.y+wrk.h; y++ {
- screen.SetContent(x, y, '|', nil, vertlineStyle)
+ // 2502
+ screen.SetContent(x, y, '\u007c', nil, vertlineStyle)
}
}
}
@@ -101,11 +102,8 @@ func (c *Column) CloseWindow(w *Window) {
}
c.windows = c.windows[:j]
- // If we deleted the current window (probably), select another
if CurWin == w {
- all := AllWindows()
-
- // If we are out of windows in our own column, pick another or exit
+ // If we are not out of windows in our own column, pick another or exit
if len(c.windows) > 0 {
CurWin = c.windows[j-1]
} else {
@@ -115,18 +113,7 @@ func (c *Column) CloseWindow(w *Window) {
// clear clutter
screen.Clear()
- // find another window to focus or exit
- if len(all) > 0 {
- CurWin = AllWindows()[0]
-
- } else {
- ed.Run("Exit")
- }
- }
-
- // if the only win left is the message win, close all
- if len(all) == 1 && CurWin.Name() == FnMessageWin {
- ed.Run("Exit")
+ return
}
}
@@ -141,12 +128,7 @@ func (c *Column) Resize(x, y, w, h int) {
}
func (c *Column) ResizeWindows() {
- var n int
- for _, win := range c.windows {
- if !win.hidden {
- n++
- }
- }
+ n := len(c.windows)
var remainder int
if n > 0 {
@@ -163,8 +145,6 @@ func (c *Column) ResizeWindows() {
func (c *Column) Draw() {
for _, win := range c.windows {
- if !win.hidden {
- win.Draw()
- }
+ win.Draw()
}
}
diff --git a/ui/tcell/style.go b/ui/tcell/style.go
index 0dcb565..a179c1f 100644
--- a/ui/tcell/style.go
+++ b/ui/tcell/style.go
@@ -24,19 +24,24 @@ var (
// initStyles initializes the different styles (colors for background/foreground).
func initStyles() error {
- bodyStyle = tcell.StyleDefault.
- Background(tcell.NewHexColor(0xffffea)).
- Foreground(tcell.ColorBlack)
+ bodyStyle = tcell.StyleDefault
+
+ // bodyStyle = tcell.StyleDefault.
+ // Background(tcell.NewHexColor(0xffffea)).
+ // Foreground(tcell.ColorBlack)
+
bodyCursorStyle = bodyStyle.
Background(tcell.NewHexColor(0xeaea9e))
- bodyHilightStyle = bodyStyle.
- Background(tcell.NewHexColor(0xa6a65a))
+
+ bodyHilightStyle = bodyStyle.Reverse(true)
+ // bodyHilightStyle = bodyStyle.
+ // Background(tcell.NewHexColor(0xa6a65a))
unprintableStyle = bodyStyle.
Foreground(tcell.ColorRed)
- tagStyle = tcell.StyleDefault.
- Background(tcell.NewHexColor(0xeaffff)).
- Foreground(tcell.ColorBlack)
+ tagStyle = tcell.StyleDefault.Reverse(true)
+ //Background(tcell.NewHexColor(0xeaffff)).
+ //Foreground(tcell.ColorBlack)
tagCursorStyle = tagStyle.
Background(tcell.NewHexColor(0x8888cc)).
Foreground(tcell.ColorBlack)
@@ -47,7 +52,7 @@ func initStyles() error {
tagSquareModifiedStyle = tagStyle.
Background(tcell.NewHexColor(0x2222cc))
- vertlineStyle = bodyStyle
+ vertlineStyle = bodyStyle.Reverse(false)
return nil
}
diff --git a/ui/tcell/tcell.go b/ui/tcell/tcell.go
index ff20628..1ebc0cc 100644
--- a/ui/tcell/tcell.go
+++ b/ui/tcell/tcell.go
@@ -3,6 +3,7 @@ package uitcell
import (
"fmt"
"path/filepath"
+ "strings"
"github.com/gdamore/tcell"
"github.com/prodhe/poe/editor"
@@ -17,14 +18,17 @@ const (
var (
screen tcell.Screen
ed editor.Editor
- menu *View
workspace *Workspace
CurWin *Window
+ poecmds map[string]commandFunc
+
quit chan bool
events chan tcell.Event
)
+type commandFunc func()
+
type Tcell struct{}
func (t *Tcell) Init(e editor.Editor) error {
@@ -37,10 +41,6 @@ func (t *Tcell) Init(e editor.Editor) error {
return err
}
- if err := initMenu(); err != nil {
- return err
- }
-
if err := initWorkspace(); err != nil {
return err
}
@@ -49,6 +49,8 @@ func (t *Tcell) Init(e editor.Editor) error {
return err
}
+ initCommands()
+
quit = make(chan bool, 1)
events = make(chan tcell.Event, 100)
@@ -65,14 +67,10 @@ func (t *Tcell) Close() {
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.Name() == poename && CurWin.Dir() == win.Dir() {
- poewin = win
- }
- }
+ poename := CurWin.Dir() + string(filepath.Separator) + FnMessageWin
+ poename = filepath.Clean(poename)
+
+ poewin := FindWindow(poename)
if poewin == nil {
id, buf := ed.NewBuffer()
@@ -110,19 +108,6 @@ func initScreen() error {
return nil
}
-func initMenu() error {
- menu = &View{
- text: &editor.Buffer{},
- what: ViewMenu,
- style: bodyStyle,
- cursorStyle: bodyCursorStyle,
- hilightStyle: bodyHilightStyle,
- tabstop: 4,
- }
- fmt.Fprintf(menu, "Exit New Newcol")
- return nil
-}
-
func initWorkspace() error {
workspace = &Workspace{} // first resize event will set proper dimensions
workspace.AddCol()
@@ -134,12 +119,21 @@ func initWindows() error {
for _, id := range ids {
win := NewWindow(id)
workspace.LastCol().AddWindow(win)
+ CurWin = win
}
return nil
}
+func initCommands() {
+ poecmds = map[string]commandFunc{
+ "New": CmdNew,
+ "Newcol": CmdNewcol,
+ "Del": CmdDel,
+ "Exit": CmdExit,
+ }
+}
+
func (t *Tcell) redraw() {
- menu.Draw()
workspace.Draw()
screen.Show()
}
@@ -168,9 +162,7 @@ outer:
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()
+ workspace.Resize(0, 0, w, h)
screen.Sync()
case *tcell.EventKey: // system wide shortcuts
switch e.Key() {
@@ -178,10 +170,6 @@ outer:
screen.Clear()
screen.Sync()
default: // let the focused view handle event
- if menu.focused {
- menu.HandleEvent(e)
- break
- }
if CurWin != nil {
CurWin.HandleEvent(e)
}
@@ -198,15 +186,8 @@ outer:
}
}
- // check if we are in the menu
- menu.focused = false
- if my < 1 {
- menu.focused = true
- menu.HandleEvent(e)
- break
- }
-
if CurWin != nil {
+ CurWin.Focus()
CurWin.HandleEvent(e)
}
}
@@ -220,6 +201,29 @@ outer:
}
}
+func Cmd(input string) string {
+ if input == "" {
+ return ""
+ }
+
+ input = strings.Trim(input, "\t\n ")
+
+ // check poe default commands
+ cmd := strings.Split(string(input), " ")
+ if fn, ok := poecmds[cmd[0]]; ok {
+ fn()
+ return ""
+ }
+
+ // Edit shortcuts for external commands and piping
+ switch input[0] {
+ case '!', '<', '>', '|':
+ return ed.Edit(CurWin.bufid, input)
+ }
+
+ return ed.Edit(CurWin.bufid, "!"+input)
+}
+
func CmdOpen(fn string) {
screen.Clear()
var win *Window
@@ -233,7 +237,7 @@ func CmdOpen(fn string) {
}
}
-func CmdNew(args string) {
+func CmdNew() {
screen.Clear()
id, _ := ed.NewBuffer()
win := NewWindow(id)
@@ -241,9 +245,18 @@ func CmdNew(args string) {
}
func CmdDel() {
+ if len(AllWindows()) == 1 {
+ CmdExit()
+ return
+ }
CurWin.Close()
}
+func CmdNewcol() {
+ workspace.AddCol()
+ CmdNew()
+}
+
func CmdExit() {
exit := true
wins := AllWindows()
@@ -252,7 +265,7 @@ func CmdExit() {
exit = false
}
}
- if exit || len(wins) == 0 {
+ if exit {
quit <- true
}
}
diff --git a/ui/tcell/view.go b/ui/tcell/view.go
index ef42207..7c0eb64 100644
--- a/ui/tcell/view.go
+++ b/ui/tcell/view.go
@@ -33,7 +33,6 @@ type View struct {
tabstop int
focused bool
what int
- dirty bool // modified since last read/write
mclicktime time.Time // last mouse click in time
mclickpos int // byte offset accounting for runes
mpressed bool
@@ -44,9 +43,6 @@ func (v *View) Write(p []byte) (int, error) {
if err != nil {
return 0, err
}
- if v.what == ViewBody {
- v.dirty = true
- }
v.SetCursor(0, 1) // force scroll if needed
return n, err
}
@@ -62,9 +58,6 @@ func (v *View) Delete() (int, error) {
if err != nil {
return n, err
}
- if v.what == ViewBody {
- v.dirty = true
- }
v.SetCursor(0, 1) // force scroll
return n, nil
}
@@ -79,11 +72,17 @@ func (v *View) Rune() rune {
return r
}
+// Cursor returns start of dot.
func (v *View) Cursor() int {
q0, _ := v.text.Dot()
return q0
}
+// Dirty returns true if the buffer has been written to.
+func (v *View) Dirty() bool {
+ return v.text.Dirty()
+}
+
func (v *View) SetCursor(pos, whence int) {
v.text.SeekDot(pos, whence)
@@ -235,11 +234,15 @@ func (v *View) ScrollTo(offset int) {
}
func (b *View) Draw() {
+ //screen.HideCursor()
+
x, y := b.x, b.y
if b.text.Len() > 0 {
b.opos = b.scrollpos // keep track of last visible char/overflow
b.text.Seek(b.scrollpos, io.SeekStart)
+ q0, q1 := b.text.Dot()
+
for i := b.scrollpos; i < b.text.Len(); { // i gets incremented after reading of the rune, to know how many bytes we need to skip
// line wrap
if x > b.x+b.w {
@@ -255,15 +258,18 @@ func (b *View) Draw() {
// default style
style := b.style
- // highlight cursor
- q0, q1 := b.text.Dot()
+ // highlight cursor if on screen
if (q0 == q1 && i == q0) && b.focused {
- style = b.cursorStyle
+ //style = b.cursorStyle
+ screen.ShowCursor(x, y)
}
- // highlight selection
- if (i >= q0 && i < q1) && b.focused {
+ // highlight selection, even if not focused
+ if i >= q0 && i < q1 {
style = b.hilightStyle
+ if b.focused {
+ screen.HideCursor()
+ }
}
// draw rune from buffer
@@ -334,10 +340,16 @@ func (b *View) Draw() {
}
if y < b.y+b.h {
screen.SetContent(x, y, ' ', nil, b.cursorStyle)
+ screen.ShowCursor(x, y)
x++
}
}
+ // if we are in focus, we are allowed to hide the central cursor if dot is currently off screen
+ if b.focused && (q0 < b.scrollpos || q0 > b.opos) {
+ screen.HideCursor()
+ }
+
// clear the rest and optionally show a special char as empty line
for w := b.x + b.w; w >= x; w-- {
screen.SetContent(w, y, ' ', nil, b.style)
@@ -385,7 +397,10 @@ func (v *View) HandleEvent(ev tcell.Event) {
// if we clicked inside a current selection, run that one
q0, q1 := v.text.Dot()
if pos >= q0 && pos <= q1 && q0 != q1 {
- ed.Run(v.text.ReadDot())
+ output := Cmd(v.text.ReadDot())
+ if output != "" {
+ printMsg(output)
+ }
return
}
@@ -393,9 +408,12 @@ func (v *View) HandleEvent(ev tcell.Event) {
p := pos - v.text.PrevSpace(pos)
n := pos + v.text.NextSpace(pos)
v.text.SetDot(p, n)
- fn := strings.Trim(v.text.ReadDot(), "\n\t ")
+ str := strings.Trim(v.text.ReadDot(), "\n\t ")
v.text.SetDot(q0, q1)
- ed.Run(fn)
+ output := Cmd(str)
+ if output != "" {
+ printMsg(output)
+ }
return
}
@@ -445,7 +463,7 @@ func (v *View) HandleEvent(ev tcell.Event) {
// if we clicked inside a current selection, run that one
q0, q1 := v.text.Dot()
if pos >= q0 && pos <= q1 && q0 != q1 {
- ed.Run(v.text.ReadDot())
+ Cmd(v.text.ReadDot())
return
}
@@ -455,7 +473,7 @@ func (v *View) HandleEvent(ev tcell.Event) {
v.text.SetDot(p, n)
fn := strings.Trim(v.text.ReadDot(), "\n\t ")
v.text.SetDot(q0, q1)
- ed.Run(fn)
+ Cmd(fn)
return
case tcell.Button3: // right click
pos := v.XYToOffset(mx, my)
@@ -562,10 +580,12 @@ func (v *View) HandleEvent(ev tcell.Event) {
v.Delete()
return
case tcell.KeyCtrlG: // file info/statistics
- printMsg("0x%.4x %q len %d\nbasedir: %s\nwindir: %s\nname: %s\n",
+ sw, sh := screen.Size()
+ printMsg("0x%.4x %q len %d\nbasedir: %s\nwindir: %s\nname: %s\nw: %d h: %d sw: %d sh: %d\n",
v.Rune(), v.Rune(),
v.text.Len(),
- ed.WorkDir(), CurWin.Dir(), CurWin.Name())
+ ed.WorkDir(), CurWin.Dir(), CurWin.Name(),
+ CurWin.w, CurWin.h, sh, sw)
return
case tcell.KeyCtrlO: // open file/dir
fn := v.text.ReadDot()
@@ -586,6 +606,9 @@ func (v *View) HandleEvent(ev tcell.Event) {
}
CmdOpen(fn)
return
+ case tcell.KeyCtrlN: // new column
+ CmdNewcol()
+ return
case tcell.KeyCtrlR: // run command in dot
cmd := v.text.ReadDot()
if cmd == "" { // select all non-space characters
@@ -599,7 +622,8 @@ func (v *View) HandleEvent(ev tcell.Event) {
return
}
}
- ed.Run(cmd)
+ res := Cmd(cmd)
+ printMsg("%s\n", res)
return
case tcell.KeyCtrlC: // copy to clipboard
str := v.text.ReadDot()
@@ -618,13 +642,7 @@ func (v *View) HandleEvent(ev tcell.Event) {
}
v.text.Write([]byte(s))
return
- case tcell.KeyCtrlQ:
- // close entire application if we are in the top menu
- if v.what == ViewMenu {
- CmdExit()
- return
- }
- // otherwise, just close this window (CurWin)
+ case tcell.KeyCtrlQ: // close window
CmdDel()
return
default:
diff --git a/ui/tcell/window.go b/ui/tcell/window.go
index fcb146c..b3774d2 100644
--- a/ui/tcell/window.go
+++ b/ui/tcell/window.go
@@ -14,9 +14,8 @@ type Window struct {
body *View
tagline *View
col *Column // reference to the column where in
- hidden bool
- collapsed bool // not implemented
- qcnt int // quit count
+ collapsed bool // not implemented
+ qcnt int // quit count
}
// NewWindow returns a fresh window associated with the given filename. For special case filenames, look at the package constants.
@@ -75,8 +74,13 @@ func (win *Window) Resize(x, y, w, h int) {
win.body.Resize(win.x, win.y+1, win.w, win.h-1)
}
-func (win *Window) UnFocus() {
+func (win *Window) Focus() {
win.body.focused = true
+ //win.tagline.focused = true
+}
+
+func (win *Window) UnFocus() {
+ win.body.focused = false
win.tagline.focused = false
}
@@ -85,7 +89,22 @@ func (win *Window) Name() string {
}
func (win *Window) Dir() string {
- return win.body.text.WorkDir()
+ d := win.body.text.WorkDir()
+ if d == "." {
+ return ed.WorkDir() // base path for program
+ }
+ return d
+}
+
+func (win *Window) Flags() [2]rune {
+ flags := [2]rune{' ', '-'}
+ if win.body.Dirty() {
+ flags[0] = '\''
+ }
+ if win.collapsed {
+ flags[1] = '+'
+ }
+ return flags
}
func (win *Window) HandleEvent(ev tcell.Event) {
@@ -119,13 +138,9 @@ func (win *Window) HandleEvent(ev tcell.Event) {
}
func (win *Window) Draw() {
- // Draw tag square
- boxstyle := tagSquareStyle
- if win.body.dirty {
- boxstyle = tagSquareModifiedStyle
- }
- screen.SetContent(win.x, win.y, ' ', nil, boxstyle)
- screen.SetContent(win.x+1, win.y, ' ', nil, boxstyle)
+ flags := win.Flags()
+ screen.SetContent(win.x, win.y, flags[0], nil, win.tagline.style)
+ screen.SetContent(win.x+1, win.y, flags[1], nil, win.tagline.style)
screen.SetContent(win.x+2, win.y, ' ', nil, win.tagline.style)
// Tagline
@@ -136,11 +151,14 @@ func (win *Window) Draw() {
}
func (win *Window) CanClose() bool {
- ok := !win.body.dirty || win.qcnt > 0
+ if win.body.what == ViewScratch {
+ return true
+ }
+ ok := (!win.body.Dirty() || win.qcnt > 0)
if !ok {
name := win.Name()
if name == FnEmptyWin {
- name = "unnamed file"
+ name = "unnamed buffer"
}
printMsg("%s modified\n", name)
win.qcnt++