adding nested header support (mostly in summary); gofmt
This commit is contained in:
parent
f20fd9f966
commit
edb3d69cfd
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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, " / "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue