Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
Dan Ballard | ea5d34ec7b | |
Dan Ballard | b6b6cdcd93 | |
Dan Ballard | 42eb9019d4 | |
Dan Ballard | 82f90889df | |
Dan Ballard | e6adae8150 | |
Dan Ballard | 4941a346be | |
Dan Ballard | 4204f610a0 | |
Dan Ballard | 08624d672c | |
Dan Ballard | edb3d69cfd |
61
README.md
61
README.md
|
@ -2,9 +2,9 @@
|
|||
|
||||
![Markdown Bullet Journal Logo](https://github.com/dballard/markdown-bullet-journal/raw/master/Markdown-Bullet-Journal.png "Markdown Bullet Journal Logo")
|
||||
|
||||
Markdown Bullet Journal is a digital adaptation of [analog tech](http://bulletjournal.com/). For my personal productivity I found having a full markdown todo list file with daily migrations was the most optimal was to manage my time. I added in a utility to summarize my past work as the daily migrations made that hard to track.
|
||||
Markdown Bullet Journal is a digital adaptation of [analog tech](http://bulletjournal.com/). When using analog pen + paper, bullet journal migrations are expensive in space and time, however in digital form they are cheap. I found that for my personal productivity having a full markdown todo list file with daily migrations was the most optimal way to manage my time and a digital bullet journal enabled this. I added in a utility to summarize my past work as the daily migrations intentionally removed it. I have also extended this tool to my tastes adding in custom support for repetitive daily tasks and pomodoros.
|
||||
|
||||
These are a simple set of utilities that work for me. Nothing fancy
|
||||
These are a simple set of utilities that work for me. Nothing fancy.
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -15,7 +15,7 @@ Download:
|
|||
- [mdbj-migreate.exe](https://www.danballard.com/resources/mdbj/mdbj-summary.exe)
|
||||
- [mdbj-summary.exe](https://www.danballard.com/resources/mdbj/mdbj-migrate.exe)
|
||||
|
||||
And place them in a directory. Run `mdbj-migrate` to generate a template to work from and each day after to 'migrate'. Run `mdbj-summary` to generate summary.txt to review work done.
|
||||
And place them in a directory you want to use. Run `mdbj-migrate` to generate a template to work from in that directory and each day after to 'migrate' to create the new day's file in that directory. Run `mdbj-summary` to generate summary.txt in the same directory to review work done.
|
||||
|
||||
### Linux & Mac
|
||||
|
||||
|
@ -26,7 +26,7 @@ go install github.com/dballard/markdown-bullet-journal/tree/master/mdbj-migrate
|
|||
go install github.com/dballard/markdown-bullet-journal/tree/master/mdbj-summary
|
||||
```
|
||||
|
||||
Pick a directory you want to use and run `mdbj-migreate` to generate a template to work from. Run it on successive days to 'migrate'. Run `mdbj-summary` to print a summary of done work to the console.
|
||||
Pick a directory you want to use and run `mdbj-migreate` to generate a template to work from in that directory. Run `mdbj-migrate` on succesive days and it will find the last dated file in the directory and 'migrate' it. Run `mdbj-summary` in the directory to print a summary of all done work to the console.
|
||||
|
||||
### Recommendations
|
||||
|
||||
|
@ -36,7 +36,7 @@ My mdbj directoy is in a cloud backed up location so I can also slightly awkward
|
|||
|
||||
### mdbj-migrate
|
||||
|
||||
When run in a directory, takes the last dated .md file, copies it to a new file with today's date, and dropes all lines marked completed (with a '[x]').
|
||||
When run in a directory, takes the last dated .md file, copies it to a new file with today's date, and drops all lines marked completed (with a '[x]').
|
||||
|
||||
### mdbj-summary
|
||||
|
||||
|
@ -56,9 +56,9 @@ into
|
|||
|
||||
The basics of headers with '#'
|
||||
|
||||
Nested lists with '-' and indentation
|
||||
Nested lists with '-' for notes and indentation
|
||||
|
||||
Todo and done with '[ ]' and '[x]'
|
||||
Todo and done with '[ ]' for open todo item, '[x]' for done todo item, and '[-]' for dropped todo item
|
||||
|
||||
Obviously you can use other markdown features such as **bold**, *italics* and [Links](https://guides.github.com/features/mastering-markdown/) but none of these trigger any special treatment with regards to Markdown Bullet Journal.
|
||||
|
||||
|
@ -77,10 +77,53 @@ These are tasks you might want to do a subset of on any given day, and possibly
|
|||
- [x] 1x5 - minutes of meditation
|
||||
```
|
||||
|
||||
Will get output as:
|
||||
under `summary` will show as
|
||||
|
||||
```
|
||||
- 40 pushups
|
||||
- 5 minutes of meditation
|
||||
```
|
||||
|
||||
And then on migration the '4' and '1' will get reset to 0 and the tasks will not get dropped
|
||||
And then on `migrate` the '4' and '1' will get reset to 0 and the tasks will not get dropped
|
||||
|
||||
```
|
||||
- [ ] 0x10 - Pushups
|
||||
- [ ] 0x10 - Crunches
|
||||
- [ ] 0x10 - Lunges
|
||||
- [ ] 0x5 - minutes of meditation
|
||||
```
|
||||
|
||||
#### Pomodoro ####
|
||||
|
||||
If you want to track pomodoro sessions, simply add '.'s inside the square brackets of todo items. They will not be considered done until an 'x' is included and thus will migrate to clean items the next day. They will however count towards pomodoro summaries.
|
||||
|
||||
```
|
||||
- [..] Big Task
|
||||
- [x] Part A
|
||||
- [x] Part B
|
||||
- [x] Part C
|
||||
- [ ] Part D
|
||||
- [ ] Other Task
|
||||
- [..x] Thing 1
|
||||
- [ ] Thing 2
|
||||
```
|
||||
|
||||
will `migrate` to
|
||||
|
||||
```
|
||||
- [ ] Big Task
|
||||
- [ ] Part D
|
||||
- [ ] Other Task
|
||||
- [ ] Thing 2
|
||||
```
|
||||
|
||||
and `summary` will be
|
||||
|
||||
```
|
||||
Big Task / Part A
|
||||
Big Task / Part B
|
||||
Big Task / Part C
|
||||
Other Task / Thing 1
|
||||
4 / 8 - 4 Pomodoros
|
||||
```
|
||||
|
||||
|
|
|
@ -13,12 +13,16 @@
|
|||
- [ ] nesting 3
|
||||
- [ ] nesting 4
|
||||
- [x] nesting 5
|
||||
- [x] not nested
|
||||
- notes of done thing
|
||||
- notes of note done thing
|
||||
- [x] not nested with done notes
|
||||
-
|
||||
asdasd
|
||||
- tabbing
|
||||
- [x] tabs handled
|
||||
- [ ] tabs migrated
|
||||
- [x] tabs handled
|
||||
- [ ] tabs migrated
|
||||
- [-] dropping this task but it's not done
|
||||
- notes
|
||||
|
||||
# Nothing done
|
||||
|
||||
|
@ -32,3 +36,13 @@
|
|||
- [ ] Group
|
||||
- [ ] 0x3 nesting rep
|
||||
- [x] 2x6 done nested rep
|
||||
|
||||
# Pomodoros
|
||||
|
||||
- [ ] not done
|
||||
- [..] partly done
|
||||
- [X...] completed
|
||||
- [x] completed sub task
|
||||
- notes
|
||||
- more notes
|
||||
- [x] other done task
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
"log"
|
||||
"github.com/dballard/markdown-bullet-journal/process"
|
||||
"fmt"
|
||||
"github.com/dballard/markdown-bullet-journal/process"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const template = `# Work
|
||||
|
@ -30,6 +30,7 @@ const template = `# Work
|
|||
|
||||
type processHandler struct {
|
||||
File *os.File
|
||||
flagStack []process.Flags
|
||||
}
|
||||
|
||||
func (ph *processHandler) Writeln(line string) {
|
||||
|
@ -37,14 +38,35 @@ func (ph *processHandler) Writeln(line string) {
|
|||
}
|
||||
|
||||
// NOP
|
||||
func (ph *processHandler) Eof() {}
|
||||
func (ph *processHandler) NewFile() {}
|
||||
func (ph *processHandler) Eof() {}
|
||||
func (ph *processHandler) NewFile() {
|
||||
ph.flagStack = []process.Flags{}
|
||||
}
|
||||
|
||||
func (ph *processHandler) ProcessLine(line string, indentLevel int, stack []string, todo bool, done bool, repTask process.RepTask) {
|
||||
// TODO: handle [x] numXnum
|
||||
if !done || repTask.Is {
|
||||
if repTask.Is {
|
||||
ph.Writeln(strings.Repeat("\t", indentLevel) + "- [ ] 0x" + strconv.Itoa(repTask.B) + stack[len(stack)-1] )
|
||||
func (ph *processHandler) ProcessLine(line string, indentLevel int, indentString string, headerStack []string, lineStack []string, flags process.Flags) {
|
||||
if indentLevel+1 > len(ph.flagStack) {
|
||||
ph.flagStack = append(ph.flagStack, flags)
|
||||
} else {
|
||||
ph.flagStack[indentLevel] = flags
|
||||
}
|
||||
|
||||
print := true
|
||||
if !flags.RepTask.Is { // always print repTasks
|
||||
for i, iflags := range ph.flagStack {
|
||||
if i > indentLevel {
|
||||
break
|
||||
}
|
||||
if iflags.Done || iflags.Dropped {
|
||||
print = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if print {
|
||||
if flags.RepTask.Is {
|
||||
ph.Writeln(strings.Repeat(indentString, indentLevel) + "- [ ] 0x" + strconv.Itoa(flags.RepTask.B) + " " + lineStack[len(lineStack)-1])
|
||||
} else if flags.Todo {
|
||||
ph.Writeln(strings.Repeat(indentString, indentLevel) + "- [ ] " + lineStack[len(lineStack)-1])
|
||||
} else {
|
||||
ph.Writeln(line)
|
||||
}
|
||||
|
@ -52,12 +74,18 @@ func (ph *processHandler) ProcessLine(line string, indentLevel int, stack []stri
|
|||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
fmt.Println(os.Args)
|
||||
fmt.Println("Markdown Bullet Journal version: " + process.Version)
|
||||
return
|
||||
}
|
||||
|
||||
ph := new(processHandler)
|
||||
files := process.GetFiles()
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
log.Fatal("Cannot open: ", fileName, " > ", err)
|
||||
|
@ -73,7 +101,7 @@ func main() {
|
|||
ph.File.WriteString(template)
|
||||
} else {
|
||||
lastFile := files[len(files)-1]
|
||||
fmt.Println ("Migrating " + lastFile + " to " + fileName)
|
||||
fmt.Println("Migrating " + lastFile + " to " + fileName)
|
||||
process.ProcessFile(ph, lastFile)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ const EXPECTED = `# Work
|
|||
- [ ] nesting 2
|
||||
- [ ] nesting 3
|
||||
- [ ] nesting 4
|
||||
-
|
||||
asdasd
|
||||
- notes of note done thing
|
||||
- tabbing
|
||||
- [ ] tabs migrated
|
||||
- [ ] tabs migrated
|
||||
- notes
|
||||
|
||||
# Nothing done
|
||||
|
||||
|
@ -37,8 +37,13 @@ const EXPECTED = `# Work
|
|||
- [ ] 0x5 things
|
||||
- [ ] 0x2 other things
|
||||
- [ ] Group
|
||||
- [ ] 0x3 nesting rep
|
||||
- [ ] 0x6 done nested rep
|
||||
- [ ] 0x3 nesting rep
|
||||
- [ ] 0x6 done nested rep
|
||||
|
||||
# Pomodoros
|
||||
|
||||
- [ ] not done
|
||||
- [ ] partly done
|
||||
`
|
||||
|
||||
func TestMigrate(t *testing.T) {
|
||||
|
@ -71,7 +76,6 @@ func TestMigrate(t *testing.T) {
|
|||
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))) ])
|
||||
|
||||
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'\nACTUAL:\n%v<---->\nEXPECTED:\n%v\n", line, EXPECTED[diffLoc], string(result[diffLoc]), errorStr, string(result), EXPECTED)
|
||||
}
|
||||
}
|
|
@ -22,7 +22,29 @@
|
|||
- [ ] not done
|
||||
- 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
|
||||
|
||||
- [x] 5x5 things
|
||||
- [ ] 0x2 other things
|
||||
- [ ] 0x2 other things
|
||||
- category
|
||||
- [x] 2x10 nested rep
|
||||
|
||||
# Pomodoros
|
||||
|
||||
- [ ] not done
|
||||
- [..] partly done
|
||||
- [x...] completed
|
|
@ -1,19 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"os"
|
||||
"github.com/dballard/markdown-bullet-journal/process"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type header struct {
|
||||
text string
|
||||
printed bool
|
||||
}
|
||||
|
||||
type processHandler struct {
|
||||
File *os.File
|
||||
totalCount, doneCount int
|
||||
header string
|
||||
headerPrinted bool
|
||||
File *os.File
|
||||
totalCount, doneCount, pomodoroCount int
|
||||
headers []header
|
||||
}
|
||||
|
||||
func (ph *processHandler) Writeln(line string) {
|
||||
|
@ -23,47 +28,68 @@ func (ph *processHandler) Writeln(line string) {
|
|||
func (ph *processHandler) NewFile() {
|
||||
ph.totalCount = 0
|
||||
ph.doneCount = 0
|
||||
ph.header = ""
|
||||
ph.headerPrinted = false
|
||||
|
||||
ph.pomodoroCount = 0
|
||||
ph.headers = []header{}
|
||||
}
|
||||
|
||||
func (ph *processHandler) Eof() {
|
||||
ph.Writeln(strconv.Itoa(ph.doneCount) + " / " + strconv.Itoa(ph.totalCount))
|
||||
pomodoroStr := ""
|
||||
if ph.pomodoroCount > 0 {
|
||||
pomodoroStr = " - " + strconv.Itoa(ph.pomodoroCount) + " Pomodoros"
|
||||
}
|
||||
ph.Writeln(strconv.Itoa(ph.doneCount) + " / " + strconv.Itoa(ph.totalCount) + pomodoroStr)
|
||||
}
|
||||
|
||||
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, indentString string, headerStack []string, lineStack []string, flags process.Flags) {
|
||||
if strings.Trim(line, " \t\n\r") == "" {
|
||||
return
|
||||
}
|
||||
if line[0] == '#' {
|
||||
ph.header = line[2:]
|
||||
ph.headerPrinted = false;
|
||||
return
|
||||
last := headerStack[len(headerStack)-1]
|
||||
if len(headerStack) > len(ph.headers) {
|
||||
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)
|
||||
if todo && !repTask.Is {
|
||||
if flags.Todo && !flags.RepTask.Is {
|
||||
ph.totalCount += 1
|
||||
}
|
||||
|
||||
if done {
|
||||
if !ph.headerPrinted {
|
||||
ph.Writeln("\t# " + ph.header)
|
||||
ph.headerPrinted = true
|
||||
}
|
||||
if flags.Done {
|
||||
ph.handleHeaderPrint()
|
||||
ph.doneCount += 1
|
||||
repStr := ""
|
||||
if repTask.Is {
|
||||
repStr = strconv.Itoa( repTask.A * repTask.B)
|
||||
if flags.RepTask.Is {
|
||||
repStr = strconv.Itoa(flags.RepTask.A*flags.RepTask.B) + " "
|
||||
// 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.Writeln("\t\t" + repStr + strings.Join(stack, " / "))
|
||||
ph.Writeln("\t\t" + repStr + strings.Join(lineStack, " / "))
|
||||
}
|
||||
ph.pomodoroCount += flags.Pomodoros
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
fmt.Println("Markdown Bullet Journal version: " + process.Version)
|
||||
return
|
||||
}
|
||||
|
||||
ph := new(processHandler)
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
|
|
|
@ -16,9 +16,15 @@ const EXPECTED = `
|
|||
# Test Data
|
||||
nesting1 / nesting 2 / nesting 3 / nesting 4 / nesting 5
|
||||
not nested
|
||||
# Nested Header
|
||||
## With something done
|
||||
a partly done thing / the one done thing
|
||||
# Repetition
|
||||
25 things
|
||||
4 / 11
|
||||
20 category / nested rep
|
||||
# Pomodoros
|
||||
completed
|
||||
7 / 19 - 5 Pomodoros
|
||||
`
|
||||
|
||||
func TestSummary(t *testing.T) {
|
||||
|
@ -54,6 +60,6 @@ func TestSummary(t *testing.T) {
|
|||
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))) ])
|
||||
|
||||
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'\nACTUAL:\n%v<---->\nEXPECTED:\n%v\n", line, EXPECTED[diffLoc], string(result[diffLoc]), errorStr, string(result), EXPECTED)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +1,42 @@
|
|||
package process
|
||||
|
||||
import (
|
||||
"os"
|
||||
"log"
|
||||
"bufio"
|
||||
"regexp"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "1.1.1"
|
||||
)
|
||||
|
||||
var (
|
||||
todoTaskExp = regexp.MustCompile("^\\[([ \\.xX-]*)\\]")
|
||||
startSpaces = regexp.MustCompile("^[\t ]*")
|
||||
repTaskRegExp = regexp.MustCompile("^([0-9]*)[xX]([0-9]*)")
|
||||
headerExp = regexp.MustCompile("^(#+) *(.+)")
|
||||
)
|
||||
|
||||
type RepTask struct {
|
||||
Is bool
|
||||
Is bool
|
||||
A, B int
|
||||
}
|
||||
|
||||
type ProcessHandler interface {
|
||||
type Flags struct {
|
||||
Todo bool
|
||||
Done bool
|
||||
Dropped bool
|
||||
RepTask RepTask
|
||||
Pomodoros int
|
||||
}
|
||||
|
||||
type ProcessHandler interface {
|
||||
Writeln(line string)
|
||||
ProcessLine(line string, indentLevel int, stack []string, todo bool, done bool, repTask RepTask)
|
||||
ProcessLine(line string, indentLevel int, indentString string, headerStack []string, lineStack []string, flags Flags)
|
||||
Eof()
|
||||
NewFile()
|
||||
}
|
||||
|
@ -40,6 +59,14 @@ func GetFiles() (filteredFiles []string) {
|
|||
return
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x >= y {
|
||||
return x
|
||||
} else {
|
||||
return y
|
||||
}
|
||||
}
|
||||
|
||||
func ProcessFile(ph ProcessHandler, fileName string) {
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
|
@ -48,11 +75,12 @@ func ProcessFile(ph ProcessHandler, fileName string) {
|
|||
defer file.Close()
|
||||
ph.NewFile()
|
||||
|
||||
stack := make([]string, 0)
|
||||
headerStack := make([]string, 1)
|
||||
lineStack := make([]string, 0)
|
||||
//flags := Flags{}
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
indentPattern := ""
|
||||
startSpaces := regexp.MustCompile("^[\t ]*")
|
||||
indentLevel := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
@ -71,54 +99,73 @@ func ProcessFile(ph ProcessHandler, fileName string) {
|
|||
} else {
|
||||
indentLevel = strings.Count(startSpaces.FindString(line), indentPattern)
|
||||
}
|
||||
todo := false
|
||||
done := false
|
||||
var repTask RepTask
|
||||
if indentLevel < len(stack)-1 {
|
||||
stack = stack[: indentLevel+1]
|
||||
}
|
||||
if indentLevel == len(stack)-1 {
|
||||
stack[len(stack)-1], todo, done, repTask = getText(line, indentLevel, indentPattern)
|
||||
}
|
||||
if indentLevel >= len(stack) {
|
||||
row := ""
|
||||
row, todo, done, repTask = getText(line, indentLevel, indentPattern)
|
||||
stack = append(stack, row)
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
ph.ProcessLine(line, indentLevel, stack, todo, done, repTask)
|
||||
var flags Flags
|
||||
if indentLevel < len(lineStack)-1 {
|
||||
lineStack = lineStack[:indentLevel+1]
|
||||
}
|
||||
if indentLevel == len(lineStack)-1 {
|
||||
lineStack[len(lineStack)-1], flags = getText(line, indentLevel, indentPattern)
|
||||
}
|
||||
if indentLevel >= len(lineStack) {
|
||||
row := ""
|
||||
row, flags = getText(line, indentLevel, indentPattern)
|
||||
lineStack = append(lineStack, row)
|
||||
}
|
||||
|
||||
ph.ProcessLine(line, indentLevel, indentPattern, headerStack, lineStack, flags)
|
||||
}
|
||||
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, flags Flags) {
|
||||
//fmt.Printf("indentLevel: %v str: '%s'\n", indentLevel, str )
|
||||
if len(str) < (indentLevel*4 +2) {
|
||||
return "", false, false, RepTask{false, 0, 0}
|
||||
flags.Done = false
|
||||
flags.Dropped = false
|
||||
flags.Todo = false
|
||||
flags.RepTask.Is = false
|
||||
flags.Pomodoros = 0
|
||||
|
||||
if len(str) < (indentLevel*4 + 2) {
|
||||
return "", flags
|
||||
}
|
||||
str = strings.TrimLeft(str, strings.Repeat(indentPattern, indentLevel))
|
||||
text = str[2:]
|
||||
done = false
|
||||
todo = false
|
||||
repTask.Is = false
|
||||
if text[0] == '[' {
|
||||
todo = true
|
||||
if text[1] == 'x' || text[1] == 'X' {
|
||||
done = true
|
||||
|
||||
if todoTaskExp.MatchString(text) {
|
||||
flags.Todo = true
|
||||
inner := string(todoTaskExp.FindSubmatch([]byte(text))[1])
|
||||
if strings.ContainsAny(inner, "xX") {
|
||||
flags.Done = true
|
||||
}
|
||||
if len(text) > 4 {
|
||||
text = text[4:]
|
||||
if strings.Contains(inner, "-") {
|
||||
flags.Dropped = true
|
||||
}
|
||||
flags.Pomodoros = strings.Count(inner, ".")
|
||||
if len(text) > len(inner) + 3 {
|
||||
text = text[len(inner)+3:]
|
||||
}
|
||||
|
||||
repTaskRegExp := regexp.MustCompile("^([0-9]*)[xX]([0-9]*)")
|
||||
if repTaskRegExp.MatchString(text) {
|
||||
repTask.Is = true
|
||||
flags.RepTask.Is = true
|
||||
matches := repTaskRegExp.FindStringSubmatch(text)
|
||||
repTask.A, _ = strconv.Atoi(matches[1])
|
||||
repTask.B, _ = strconv.Atoi(matches[2])
|
||||
flags.RepTask.A, _ = strconv.Atoi(matches[1])
|
||||
flags.RepTask.B, _ = strconv.Atoi(matches[2])
|
||||
loc := repTaskRegExp.FindIndex([]byte(text))
|
||||
text = text[loc[1]:]
|
||||
text = text[loc[1]+1:]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue