180 lines
3.5 KiB
Go
180 lines
3.5 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
"tildegit.org/sloum/swim/termios"
|
||
)
|
||
|
||
const (
|
||
swimLogo string = "\033[7m swim ▟\033[27m "
|
||
cursorHome string = "\033[0;0H"
|
||
styleOff string = "\033[0m"
|
||
upAndLeft string = "\033[1A\033[500D"
|
||
cursorEnd string = "\033[500;500H"
|
||
)
|
||
|
||
type Board struct {
|
||
Title string
|
||
Body string
|
||
Created time.Time
|
||
Lanes []Lane
|
||
Current int // Index of current lane
|
||
Message string
|
||
MsgErr bool
|
||
Width int
|
||
Height int
|
||
Zoom int
|
||
}
|
||
|
||
func (b *Board) Run() {
|
||
defer termios.Restore()
|
||
termios.SetCharMode()
|
||
|
||
var ch rune
|
||
for {
|
||
b.Draw()
|
||
ch = Getch()
|
||
|
||
switch ch {
|
||
case 'Q':
|
||
termios.Restore()
|
||
os.Exit(0)
|
||
case 'N':
|
||
b.CreateLane()
|
||
case 'n':
|
||
b.CreateStory()
|
||
case '\n':
|
||
// View current story
|
||
case 'h', 'j', 'k', 'l':
|
||
// Move cursor, context dependent
|
||
// If a story is open, will scroll
|
||
// the story, otherwise will select
|
||
// a story
|
||
case 'c':
|
||
// Comment on current story
|
||
case 'a':
|
||
// Archive the current story
|
||
case 'd':
|
||
// Delete current story
|
||
case 'D':
|
||
// Delete current lane
|
||
case 'e':
|
||
// Edit current story
|
||
case ':':
|
||
b.EnterCommand()
|
||
case '+':
|
||
// b.ZoomIn()
|
||
case '-':
|
||
// b.ZoomOut()
|
||
}
|
||
}
|
||
}
|
||
|
||
func (b *Board) ClearMessage() {
|
||
b.Message = ""
|
||
b.MsgErr = false
|
||
}
|
||
|
||
func (b *Board) SetMessage(msg string, isError bool) {
|
||
b.Message = msg
|
||
b.MsgErr = isError
|
||
}
|
||
|
||
func (b *Board) CreateLane() {
|
||
laneTitle, err := GetAndConfirmCommandLine("Lane Title: ")
|
||
if err != nil {
|
||
b.SetMessage(err.Error(), true)
|
||
return
|
||
}
|
||
b.Lanes = append(b.Lanes, MakeLane(laneTitle))
|
||
if b.Current < 0 {
|
||
b.Current = 0
|
||
}
|
||
}
|
||
|
||
func (b *Board) CreateStory() {
|
||
b.Lanes[b.Current].CreateStory(b)
|
||
}
|
||
|
||
func (b Board) PrintHeader() string {
|
||
return fmt.Sprintf("%s%s%-*.*s%s\n", style.Header, swimLogo, b.Width-12, b.Width-12, b.Title, styleOff)
|
||
}
|
||
|
||
func (b Board) PrintInputArea() string {
|
||
return fmt.Sprintf("%s%-*.*s%s\n", style.Input, b.Width, b.Width, " ", styleOff)
|
||
}
|
||
|
||
func (b Board) PrintLanes() string {
|
||
var out strings.Builder
|
||
laneWidth := b.Width / b.Zoom
|
||
|
||
if len(b.Lanes) == 0 {
|
||
for i := 0; i < b.Height - 3; i++ {
|
||
out.WriteString(fmt.Sprintf("%s%*.*s%s\n", style.Lane, b.Width, b.Width, " ", styleOff))
|
||
}
|
||
return out.String()
|
||
}
|
||
laneText := make([][]string, 0, len(b.Lanes))
|
||
maxLen := 0
|
||
for _, l := range b.Lanes {
|
||
s := l.StringSlice(laneWidth)
|
||
laneText = append(laneText, s)
|
||
if len(s) > maxLen {
|
||
maxLen = len(s)
|
||
}
|
||
}
|
||
for i := 0; i < b.Height - 3; i++ {
|
||
for li, l := range laneText {
|
||
// TODO fix this
|
||
if li >= b.Zoom {
|
||
out.WriteRune('\n')
|
||
break
|
||
}
|
||
if i < len(l) {
|
||
out.WriteString(l[i])
|
||
} else {
|
||
out.WriteString(fmt.Sprintf("%s%*.*s%s", style.Lane, laneWidth, laneWidth, " ", styleOff))
|
||
}
|
||
}
|
||
}
|
||
out.WriteString(styleOff)
|
||
return out.String()
|
||
}
|
||
|
||
func (b *Board) EnterCommand() {
|
||
var out strings.Builder
|
||
out.WriteString(upAndLeft) // Move up one and over all
|
||
out.WriteString(style.Input)
|
||
fmt.Print(out.String())
|
||
command, err := GetLine(":")
|
||
if err != nil {
|
||
b.SetMessage(err.Error(), true)
|
||
}
|
||
b.SetMessage(command, false)
|
||
}
|
||
|
||
func (b Board) PrintMessage() string {
|
||
var out strings.Builder
|
||
if b.MsgErr {
|
||
out.WriteString(style.MessageErr)
|
||
} else {
|
||
out.WriteString(style.Message)
|
||
}
|
||
out.WriteString(fmt.Sprintf("%-*.*s%s", b.Width, b.Width, b.Message, styleOff))
|
||
return out.String()
|
||
}
|
||
|
||
func (b Board) Draw() {
|
||
var out strings.Builder
|
||
out.WriteString(cursorHome)
|
||
out.WriteString(b.PrintHeader())
|
||
out.WriteString(b.PrintLanes())
|
||
out.WriteString(b.PrintInputArea())
|
||
out.WriteString(b.PrintMessage())
|
||
fmt.Print(out.String())
|
||
}
|
||
|