Adds init command
This commit is contained in:
parent
18ee12f21c
commit
4379ef12de
25
README.md
25
README.md
|
@ -86,6 +86,31 @@ This tree style listing shows commands and their sub-commands. Anything inside o
|
|||
- `task` - Always refers to the currently selected story
|
||||
- `{task number}`
|
||||
- `quit`
|
||||
- `regex` - Uses golang style regular expressions
|
||||
- `board`
|
||||
- `title`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `lane`
|
||||
- `title`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `lanes` - Applies the expression to all lanes, abbreviating `lanes` is not allowed
|
||||
- `title`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `story`
|
||||
- `title`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `description`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `stories` - Applies the expression to all stories in the current lane, abbreviating `stories` is not allowed
|
||||
- `title`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `description`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `stories!` - Applies the expression to all stories on the board (use with care), abbreviating `stories!` is not allowed
|
||||
- `title`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `description`
|
||||
- Expression in the form: `/[match expression]/[replacement]/`
|
||||
- `set`
|
||||
- `board`
|
||||
- `title`
|
||||
|
|
111
board.go
111
board.go
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"tildegit.org/sloum/swim/termios"
|
||||
"time"
|
||||
|
@ -223,6 +224,12 @@ func (b *Board) EnterCommand() {
|
|||
if mainCom == "wq" {
|
||||
Quit()
|
||||
}
|
||||
case "regex", "re", "regexp":
|
||||
if len(f) < 4 {
|
||||
b.SetMessage("Not enough arguments: regex [target] [location] [/pattern/replacement/]", true)
|
||||
return
|
||||
}
|
||||
b.Regex(f[1:])
|
||||
case "q", "quit":
|
||||
Quit()
|
||||
case "c", "create":
|
||||
|
@ -497,6 +504,110 @@ func (b *Board) ViewStory() {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *Board) Regex(args []string) {
|
||||
target := strings.ToLower(args[0])
|
||||
location := strings.ToLower(args[1])
|
||||
exp := strings.Join(args[2:], " ")
|
||||
if !strings.HasPrefix(exp, "/") {
|
||||
b.SetMessage("Invalid expression, must start with \"/\"", true)
|
||||
return
|
||||
}
|
||||
if len(exp) < 5 {
|
||||
b.SetMessage("Invalid expression", true)
|
||||
return
|
||||
}
|
||||
exp = strings.Replace(exp, "\\/", "~@!", -1)
|
||||
findReplaceFlag := strings.Split(exp[1:], "/")
|
||||
if len(findReplaceFlag) < 2 {
|
||||
b.SetMessage("Invalid expression, no replacement value", true)
|
||||
return
|
||||
}
|
||||
for i := range findReplaceFlag {
|
||||
findReplaceFlag[i] = strings.Replace(findReplaceFlag[i], "~@!", "\\/", -1)
|
||||
}
|
||||
re, err := regexp.Compile(findReplaceFlag[0])
|
||||
if err != nil {
|
||||
b.SetMessage(err.Error(), true)
|
||||
return
|
||||
}
|
||||
var src string
|
||||
switch target {
|
||||
case "board", "b", "bo", "boa", "boar":
|
||||
if !strings.HasPrefix(location, "t") {
|
||||
b.SetMessage(fmt.Sprintf("Invalid location, %q, for %s", location, target), true)
|
||||
return
|
||||
}
|
||||
src = b.Title
|
||||
b.Title = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
case "lanes":
|
||||
if !strings.HasPrefix(location, "t") {
|
||||
b.SetMessage(fmt.Sprintf("Invalid location, %q, for %s", location, target), true)
|
||||
return
|
||||
}
|
||||
for i := range b.Lanes {
|
||||
src = b.Lanes[i].Title
|
||||
b.Lanes[i].Title = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
}
|
||||
case "lane", "l", "la", "lan":
|
||||
if !strings.HasPrefix(location, "t") {
|
||||
b.SetMessage(fmt.Sprintf("Invalid location, %q, for %s", location, target), true)
|
||||
return
|
||||
}
|
||||
src = b.Lanes[b.Current].Title
|
||||
b.Lanes[b.Current].Title = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
case "stories!":
|
||||
for l := range b.Lanes {
|
||||
for i := range b.Lanes[l].Stories {
|
||||
switch location {
|
||||
case "title", "t", "ti", "tit", "titl":
|
||||
src = b.Lanes[l].Stories[i].Title
|
||||
b.Lanes[l].Stories[i].Title = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
case "description", "desc", "d", "de":
|
||||
src = b.Lanes[l].Stories[i].Body
|
||||
b.Lanes[l].Stories[i].Body = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
default:
|
||||
b.SetMessage(fmt.Sprintf("Invalid location, %q, for %s", location, target), true)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
case "stories":
|
||||
for i := range b.Lanes[b.Current].Stories {
|
||||
switch location {
|
||||
case "title", "t", "ti", "tit", "titl":
|
||||
src = b.Lanes[b.Current].Stories[i].Title
|
||||
b.Lanes[b.Current].Stories[i].Title = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
case "description", "desc", "d", "de":
|
||||
src = b.Lanes[b.Current].Stories[i].Body
|
||||
b.Lanes[b.Current].Stories[i].Body = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
default:
|
||||
b.SetMessage(fmt.Sprintf("Invalid location, %q, for %s", location, target), true)
|
||||
return
|
||||
}
|
||||
}
|
||||
case "story", "s", "st", "sto", "stor":
|
||||
switch location {
|
||||
case "title", "t", "ti", "tit", "titl":
|
||||
src = b.Lanes[b.Current].Stories[b.Lanes[b.Current].Current].Title
|
||||
b.Lanes[b.Current].Stories[b.Lanes[b.Current].Current].Title = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
case "description", "desc", "d", "de":
|
||||
src = b.Lanes[b.Current].Stories[b.Lanes[b.Current].Current].Body
|
||||
b.Lanes[b.Current].Stories[b.Lanes[b.Current].Current].Body = re.ReplaceAllLiteralString(src, findReplaceFlag[1])
|
||||
default:
|
||||
b.SetMessage(fmt.Sprintf("Invalid location, %q, for %s", location, target), true)
|
||||
return
|
||||
}
|
||||
default:
|
||||
b.SetMessage(fmt.Sprintf("Invalid target %q", target), true)
|
||||
return
|
||||
}
|
||||
if b.StoryOpen && strings.HasPrefix(target, "s") {
|
||||
b.Lanes[b.Current].Stories[b.Lanes[b.Current].Current].BuildStorySlice(b.width)
|
||||
b.Lanes[b.Current].Stories[b.Lanes[b.Current].Current].Draw(b)
|
||||
}
|
||||
b.SetMessage("Regular expression applied", false)
|
||||
}
|
||||
|
||||
func (b Board) Draw() {
|
||||
var out strings.Builder
|
||||
out.WriteString(cursorHome)
|
||||
|
|
25
main.go
25
main.go
|
@ -153,7 +153,7 @@ func WrapText(text string, lineWidth int) string {
|
|||
func Quit() {
|
||||
termios.Restore()
|
||||
fmt.Print(cursorEnd)
|
||||
fmt.Print("\033[0m\n\033[?25h")
|
||||
fmt.Print("\033[0m\033[?25h")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
|
@ -206,6 +206,23 @@ func handleSignals(c <-chan os.Signal) {
|
|||
}
|
||||
}
|
||||
|
||||
func InitNewBoard() {
|
||||
b := DefaultBoard(80,30)
|
||||
b.CreateLane("Backlog")
|
||||
b.CreateLane("Active")
|
||||
b.CreateLane("Complete")
|
||||
b.message = "Welcome to SWIM"
|
||||
workingPath, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
filename := filepath.Base(workingPath) + ".swim"
|
||||
filename = strings.Replace(filename, " ", "_", -1)
|
||||
savepath := filepath.Join(workingPath, filename)
|
||||
b.Write([]string{"write", savepath})
|
||||
Quit()
|
||||
}
|
||||
|
||||
func DefaultBoard(cols, rows int) Board {
|
||||
return Board{
|
||||
Title: "",
|
||||
|
@ -243,7 +260,11 @@ func main() {
|
|||
style.Init(SetColorFromFlag(*colors))
|
||||
cols, rows := termios.GetWindowSize()
|
||||
if len(args) > 0 {
|
||||
LoadFile(args[0], cols, rows)
|
||||
if strings.ToLower(args[0]) == "init" {
|
||||
InitNewBoard()
|
||||
} else {
|
||||
LoadFile(args[0], cols, rows)
|
||||
}
|
||||
} else {
|
||||
fp = ""
|
||||
board = DefaultBoard(cols, rows)
|
||||
|
|
4
swim.1
4
swim.1
|
@ -153,6 +153,10 @@ quit
|
|||
Quits the program immediately. To save and quit use \fIwq\fP.
|
||||
.TP
|
||||
.B
|
||||
regexp
|
||||
Accepts three required arguments: target (\fIbaord\fP, \fIlane\fP, \fIlanes\fP, \fIstory\fP, \fIstories\fP, and \fIstories!\fP), location (\fItitle\fP, and for story: \fIdescription\fP), and an expression representing a substitution in the form of \fI/[match expresion]/[substitution]/\fP. Matching is done with golang style regular expressions and flags can be added inline as a part of the expression. Example: \fIregexp story title /^My/Your/\fP. \fIlanes\fP and \fIstories\fP will apply the regex to all lanes or to all stories in the current lane. To target all stories on the whole board use \fIstories!\fP. Standard command abbreviation rules apply for all targets and locations with the exception of \fIlanes\fP, \fIstories\fP, and \fIstories!\fP, which must be written out fully.
|
||||
.TP
|
||||
.B
|
||||
set
|
||||
Sets a value for a particular target and location. Available targets are \fIboard\fP, \fIlane\fP, and \fIstory\fP. All three have a \fItitle\fP location. \fIstory\fP also has \fIdescription\fP, \fIpoints\fP, and \fIuser\fP. All commands accept an optional fourth argument representing the new value to set the location to. If no fourth argument, which can be many space separated words, is not passed the user will be queried for input. Many of the story locations can be modified via a key command but exist here to allow for user workflow preference. Example: \fIset lane title My Cool Lane\fP.
|
||||
.TP
|
||||
|
|
Loading…
Reference in New Issue