adding nested header support (mostly in summary); gofmt

This commit is contained in:
Dan Ballard 2018-05-21 13:52:50 -07:00
parent f20fd9f966
commit edb3d69cfd
5 changed files with 107 additions and 46 deletions

View File

@ -1,13 +1,13 @@
package main package main
import ( import (
"os"
"time"
"log"
"github.com/dballard/markdown-bullet-journal/process"
"fmt" "fmt"
"github.com/dballard/markdown-bullet-journal/process"
"log"
"os"
"strconv" "strconv"
"strings" "strings"
"time"
) )
const template = `# Work const template = `# Work
@ -37,14 +37,14 @@ func (ph *processHandler) Writeln(line string) {
} }
// NOP // NOP
func (ph *processHandler) Eof() {} func (ph *processHandler) Eof() {}
func (ph *processHandler) NewFile() {} func (ph *processHandler) NewFile() {}
func (ph *processHandler) ProcessLine(line string, indentLevel int, stack []string, todo bool, done bool, repTask process.RepTask) { func (ph *processHandler) ProcessLine(line string, indentLevel int, headerStack []string, lineStack []string, todo bool, done bool, repTask process.RepTask) {
// TODO: handle [x] numXnum // TODO: handle [x] numXnum
if !done || repTask.Is { if !done || repTask.Is {
if repTask.Is { if repTask.Is {
ph.Writeln(strings.Repeat("\t", indentLevel) + "- [ ] 0x" + strconv.Itoa(repTask.B) + stack[len(stack)-1] ) ph.Writeln(strings.Repeat("\t", indentLevel) + "- [ ] 0x" + strconv.Itoa(repTask.B) + lineStack[len(lineStack)-1])
} else { } else {
ph.Writeln(line) ph.Writeln(line)
} }
@ -57,7 +57,7 @@ func main() {
fileName := time.Now().Format("2006-01-02") + ".md" fileName := time.Now().Format("2006-01-02") + ".md"
if _, err := os.Stat(fileName); os.IsNotExist(err) { if _, err := os.Stat(fileName); os.IsNotExist(err) {
ph.File, err = os.Create(fileName) ph.File, err = os.Create(fileName)
if err != nil { if err != nil {
log.Fatal("Cannot open: ", fileName, " > ", err) log.Fatal("Cannot open: ", fileName, " > ", err)
@ -73,7 +73,7 @@ func main() {
ph.File.WriteString(template) ph.File.WriteString(template)
} else { } else {
lastFile := files[len(files)-1] lastFile := files[len(files)-1]
fmt.Println ("Migrating " + lastFile + " to " + fileName) fmt.Println("Migrating " + lastFile + " to " + fileName)
process.ProcessFile(ph, lastFile) process.ProcessFile(ph, lastFile)
} }
} }

View File

@ -22,6 +22,20 @@
- [ ] not done - [ ] not done
- note - note
# Nested Header
## With Nothing
- note
- [ ] undone
## With something done
- more notes
- [ ] a partly done thing
- [ ] more to do
- [x] the one done thing
# Repetition # Repetition
- [x] 5x5 things - [x] 5x5 things

View File

@ -1,19 +1,23 @@
package main package main
import ( import (
"runtime"
"os"
"github.com/dballard/markdown-bullet-journal/process" "github.com/dballard/markdown-bullet-journal/process"
"log" "log"
"os"
"runtime"
"strconv" "strconv"
"strings" "strings"
) )
type header struct {
text string
printed bool
}
type processHandler struct { type processHandler struct {
File *os.File File *os.File
totalCount, doneCount int totalCount, doneCount int
header string headers []header
headerPrinted bool
} }
func (ph *processHandler) Writeln(line string) { func (ph *processHandler) Writeln(line string) {
@ -23,23 +27,36 @@ func (ph *processHandler) Writeln(line string) {
func (ph *processHandler) NewFile() { func (ph *processHandler) NewFile() {
ph.totalCount = 0 ph.totalCount = 0
ph.doneCount = 0 ph.doneCount = 0
ph.header = "" ph.headers = []header{}
ph.headerPrinted = false
} }
func (ph *processHandler) Eof() { func (ph *processHandler) Eof() {
ph.Writeln(strconv.Itoa(ph.doneCount) + " / " + strconv.Itoa(ph.totalCount)) ph.Writeln(strconv.Itoa(ph.doneCount) + " / " + strconv.Itoa(ph.totalCount))
} }
func (ph *processHandler) ProcessLine(line string, indentLevel int, stack []string, todo bool, done bool, repTask process.RepTask) { func (ph *processHandler) handleHeaderPrint() {
for i, header := range ph.headers {
if ! header.printed {
ph.Writeln("\t" + strings.Repeat("#", i+1) + " " + header.text)
ph.headers[i].printed = true
}
}
}
func (ph *processHandler) ProcessLine(line string, indentLevel int, headerStack []string, lineStack []string, todo bool, done bool, repTask process.RepTask) {
if strings.Trim(line, " \t\n\r") == "" { if strings.Trim(line, " \t\n\r") == "" {
return return
} }
if line[0] == '#' { if line[0] == '#' {
ph.header = line[2:] last := headerStack[len(headerStack)-1]
ph.headerPrinted = false; if len(headerStack) > len(ph.headers) {
return ph.headers = append(ph.headers, header{ last, false })
} else if len(headerStack) == len(ph.headers) {
ph.headers[len(ph.headers)-1] = header{last, false}
} else if len(headerStack) < len(ph.headers) {
ph.headers = ph.headers[: len(headerStack)]
ph.headers[len(ph.headers)-1] = header{last, false}
}
} }
// inc count of todo items (rep tasks shouldnt count towards outstanding todo, unless done) // inc count of todo items (rep tasks shouldnt count towards outstanding todo, unless done)
@ -48,18 +65,15 @@ func (ph *processHandler) ProcessLine(line string, indentLevel int, stack []stri
} }
if done { if done {
if !ph.headerPrinted { ph.handleHeaderPrint()
ph.Writeln("\t# " + ph.header)
ph.headerPrinted = true
}
ph.doneCount += 1 ph.doneCount += 1
repStr := "" repStr := ""
if repTask.Is { if repTask.Is {
repStr = strconv.Itoa( repTask.A * repTask.B) repStr = strconv.Itoa(repTask.A * repTask.B)
// inc todo count here since we did a thing, its done, and we dont want a higher done count than total // inc todo count here since we did a thing, its done, and we dont want a higher done count than total
ph.totalCount += 1 ph.totalCount += 1
} }
ph.Writeln("\t\t" + repStr + strings.Join(stack, " / ")) ph.Writeln("\t\t" + repStr + strings.Join(lineStack, " / "))
} }
} }

View File

@ -16,9 +16,12 @@ const EXPECTED = `
# Test Data # Test Data
nesting1 / nesting 2 / nesting 3 / nesting 4 / nesting 5 nesting1 / nesting 2 / nesting 3 / nesting 4 / nesting 5
not nested not nested
# Nested Header
## With something done
a partly done thing / the one done thing
# Repetition # Repetition
25 things 25 things
4 / 11 5 / 15
` `
func TestSummary(t *testing.T) { func TestSummary(t *testing.T) {
@ -54,6 +57,6 @@ func TestSummary(t *testing.T) {
line := strings.Count(string(result[:diffLoc]), "\n") line := strings.Count(string(result[:diffLoc]), "\n")
errorStr := string(result[int(math.Max(0, float64(diffLoc - 10))) : int(math.Min(float64(len(result)), float64(diffLoc + 10))) ]) errorStr := string(result[int(math.Max(0, float64(diffLoc - 10))) : int(math.Min(float64(len(result)), float64(diffLoc + 10))) ])
t.Errorf("Summary results do not match expected:\nfirst difference at line %v: '%v'\n%v<---->\n%v\n", line, errorStr, string(result), EXPECTED) t.Errorf("Summary results do not match expected:\nfirst difference at line %v\nexpected char: '%c'\nactual char: '%v'\nline: '%v'\n%v<---->\n%v\n", line, EXPECTED[diffLoc], string(result[diffLoc]), errorStr, string(result), EXPECTED)
} }
} }

View File

@ -1,23 +1,31 @@
package process package process
import ( import (
"os"
"log"
"bufio" "bufio"
"regexp"
"io/ioutil" "io/ioutil"
"log"
"os"
"regexp"
"strconv" "strconv"
"strings" "strings"
) )
var (
repTaskRegExp = regexp.MustCompile("^([0-9]*)[xX]([0-9]*)")
headerExp = regexp.MustCompile("^(#+) *(.+)")
)
type RepTask struct { type RepTask struct {
Is bool Is bool
A, B int A, B int
} }
type ProcessHandler interface { type Flags struct {
}
type ProcessHandler interface {
Writeln(line string) Writeln(line string)
ProcessLine(line string, indentLevel int, stack []string, todo bool, done bool, repTask RepTask) ProcessLine(line string, indentLevel int, headerStack []string, lineStack []string, todo bool, done bool, repTask RepTask)
Eof() Eof()
NewFile() NewFile()
} }
@ -40,6 +48,14 @@ func GetFiles() (filteredFiles []string) {
return return
} }
func max(x, y int) int {
if x >= y {
return x
} else {
return y
}
}
func ProcessFile(ph ProcessHandler, fileName string) { func ProcessFile(ph ProcessHandler, fileName string) {
file, err := os.Open(fileName) file, err := os.Open(fileName)
if err != nil { if err != nil {
@ -48,7 +64,9 @@ func ProcessFile(ph ProcessHandler, fileName string) {
defer file.Close() defer file.Close()
ph.NewFile() ph.NewFile()
stack := make([]string, 0) headerStack := make([]string, 1)
lineStack := make([]string, 0)
//flags := Flags{}
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
indentPattern := "" indentPattern := ""
@ -71,29 +89,42 @@ func ProcessFile(ph ProcessHandler, fileName string) {
} else { } else {
indentLevel = strings.Count(startSpaces.FindString(line), indentPattern) indentLevel = strings.Count(startSpaces.FindString(line), indentPattern)
} }
if headerExp.MatchString(line) {
matches := headerExp.FindStringSubmatch(line)
if len(matches[1]) > len(headerStack) {
headerStack = append(headerStack, matches[2])
} else if len(matches[1]) == len(headerStack) {
headerStack[len(headerStack)-1] = matches[2]
} else if len(matches[1]) < len(headerStack) {
headerStack = headerStack[:len(matches[1])]
headerStack[len(headerStack)-1] = matches[2]
}
}
todo := false todo := false
done := false done := false
var repTask RepTask var repTask RepTask
if indentLevel < len(stack)-1 { if indentLevel < len(lineStack)-1 {
stack = stack[: indentLevel+1] lineStack = lineStack[:indentLevel+1]
} }
if indentLevel == len(stack)-1 { if indentLevel == len(lineStack)-1 {
stack[len(stack)-1], todo, done, repTask = getText(line, indentLevel, indentPattern) lineStack[len(lineStack)-1], todo, done, repTask = getText(line, indentLevel, indentPattern)
} }
if indentLevel >= len(stack) { if indentLevel >= len(lineStack) {
row := "" row := ""
row, todo, done, repTask = getText(line, indentLevel, indentPattern) row, todo, done, repTask = getText(line, indentLevel, indentPattern)
stack = append(stack, row) lineStack = append(lineStack, row)
} }
ph.ProcessLine(line, indentLevel, stack, todo, done, repTask) ph.ProcessLine(line, indentLevel, headerStack, lineStack, todo, done, repTask)
} }
ph.Eof() ph.Eof()
} }
func getText(str string, indentLevel int, indentPattern string) (text string, todo bool, done bool, repTask RepTask) { func getText(str string, indentLevel int, indentPattern string) (text string, todo bool, done bool, repTask RepTask) {
//fmt.Printf("indentLevel: %v str: '%s'\n", indentLevel, str ) //fmt.Printf("indentLevel: %v str: '%s'\n", indentLevel, str )
if len(str) < (indentLevel*4 +2) { if len(str) < (indentLevel*4 + 2) {
return "", false, false, RepTask{false, 0, 0} return "", false, false, RepTask{false, 0, 0}
} }
str = strings.TrimLeft(str, strings.Repeat(indentPattern, indentLevel)) str = strings.TrimLeft(str, strings.Repeat(indentPattern, indentLevel))
@ -110,7 +141,6 @@ func getText(str string, indentLevel int, indentPattern string) (text string, to
text = text[4:] text = text[4:]
} }
repTaskRegExp := regexp.MustCompile("^([0-9]*)[xX]([0-9]*)")
if repTaskRegExp.MatchString(text) { if repTaskRegExp.MatchString(text) {
repTask.Is = true repTask.Is = true
matches := repTaskRegExp.FindStringSubmatch(text) matches := repTaskRegExp.FindStringSubmatch(text)
@ -121,4 +151,4 @@ func getText(str string, indentLevel int, indentPattern string) (text string, to
} }
} }
return return
} }