2018-05-07 15:14:59 +00:00
|
|
|
package process
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"io/ioutil"
|
2018-05-21 20:52:50 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"regexp"
|
2018-05-08 17:07:20 +00:00
|
|
|
"strconv"
|
2018-05-13 17:07:54 +00:00
|
|
|
"strings"
|
2018-05-07 15:14:59 +00:00
|
|
|
)
|
|
|
|
|
2018-05-29 17:28:52 +00:00
|
|
|
const (
|
2018-05-30 16:57:46 +00:00
|
|
|
Version = "1.1.1"
|
2018-05-29 17:28:52 +00:00
|
|
|
)
|
|
|
|
|
2018-05-21 20:52:50 +00:00
|
|
|
var (
|
2018-05-30 16:57:24 +00:00
|
|
|
todoTaskExp = regexp.MustCompile("^\\[([ \\.xX-]*)\\]")
|
2018-05-29 16:41:30 +00:00
|
|
|
startSpaces = regexp.MustCompile("^[\t ]*")
|
2018-05-21 20:52:50 +00:00
|
|
|
repTaskRegExp = regexp.MustCompile("^([0-9]*)[xX]([0-9]*)")
|
|
|
|
headerExp = regexp.MustCompile("^(#+) *(.+)")
|
|
|
|
)
|
|
|
|
|
2018-05-08 17:07:20 +00:00
|
|
|
type RepTask struct {
|
2018-05-21 20:52:50 +00:00
|
|
|
Is bool
|
2018-05-08 17:07:20 +00:00
|
|
|
A, B int
|
|
|
|
}
|
|
|
|
|
2018-05-21 20:52:50 +00:00
|
|
|
type Flags struct {
|
2018-05-21 21:02:22 +00:00
|
|
|
Todo bool
|
|
|
|
Done bool
|
2018-05-30 16:57:24 +00:00
|
|
|
Dropped bool
|
2018-05-21 21:02:22 +00:00
|
|
|
RepTask RepTask
|
2018-05-29 16:41:30 +00:00
|
|
|
Pomodoros int
|
2018-05-21 20:52:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ProcessHandler interface {
|
2018-05-07 15:14:59 +00:00
|
|
|
Writeln(line string)
|
2018-05-30 16:57:24 +00:00
|
|
|
ProcessLine(line string, indentLevel int, indentString string, headerStack []string, lineStack []string, flags Flags)
|
2018-05-07 15:58:42 +00:00
|
|
|
Eof()
|
|
|
|
NewFile()
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetFiles() (filteredFiles []string) {
|
|
|
|
// open current directory
|
|
|
|
files, err := ioutil.ReadDir("./")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
filteredFiles = []string{}
|
|
|
|
|
|
|
|
// process files of '2*.md'
|
|
|
|
for _, file := range files {
|
|
|
|
if file.Name()[0] == '2' && file.Name()[len(file.Name())-3:] == ".md" {
|
|
|
|
filteredFiles = append(filteredFiles, file.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-21 20:52:50 +00:00
|
|
|
func max(x, y int) int {
|
|
|
|
if x >= y {
|
|
|
|
return x
|
|
|
|
} else {
|
|
|
|
return y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-07 15:14:59 +00:00
|
|
|
func ProcessFile(ph ProcessHandler, fileName string) {
|
|
|
|
file, err := os.Open(fileName)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer file.Close()
|
2018-05-07 15:58:42 +00:00
|
|
|
ph.NewFile()
|
2018-05-07 15:14:59 +00:00
|
|
|
|
2018-05-21 20:52:50 +00:00
|
|
|
headerStack := make([]string, 1)
|
|
|
|
lineStack := make([]string, 0)
|
|
|
|
//flags := Flags{}
|
2018-05-07 15:14:59 +00:00
|
|
|
|
|
|
|
scanner := bufio.NewScanner(file)
|
2018-05-13 17:07:54 +00:00
|
|
|
indentPattern := ""
|
|
|
|
indentLevel := 0
|
2018-05-07 15:14:59 +00:00
|
|
|
for scanner.Scan() {
|
2018-05-07 15:58:42 +00:00
|
|
|
line := scanner.Text()
|
2018-05-13 17:07:54 +00:00
|
|
|
// if current line has no spaces at front, reset indent pattern
|
|
|
|
if len(line) == 0 || (line[0] != ' ' && line[0] != '\t') {
|
|
|
|
indentPattern = ""
|
|
|
|
}
|
|
|
|
// if no indent pattern and opening of line is space, set indent pattern
|
|
|
|
if indentPattern == "" && len(line) > 0 && (line[0] != ' ' || line[0] != '\t') {
|
|
|
|
indentPattern = startSpaces.FindString(line)
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
|
|
|
|
2018-05-13 17:07:54 +00:00
|
|
|
// number of times indent pattern repeats at front of line
|
|
|
|
if indentPattern == "" {
|
|
|
|
indentLevel = 0
|
|
|
|
} else {
|
|
|
|
indentLevel = strings.Count(startSpaces.FindString(line), indentPattern)
|
|
|
|
}
|
2018-05-21 20:52:50 +00:00
|
|
|
|
|
|
|
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]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:02:22 +00:00
|
|
|
var flags Flags
|
2018-05-21 20:52:50 +00:00
|
|
|
if indentLevel < len(lineStack)-1 {
|
|
|
|
lineStack = lineStack[:indentLevel+1]
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
2018-05-21 20:52:50 +00:00
|
|
|
if indentLevel == len(lineStack)-1 {
|
2018-05-21 21:02:22 +00:00
|
|
|
lineStack[len(lineStack)-1], flags = getText(line, indentLevel, indentPattern)
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
2018-05-21 20:52:50 +00:00
|
|
|
if indentLevel >= len(lineStack) {
|
2018-05-07 15:58:42 +00:00
|
|
|
row := ""
|
2018-05-21 21:02:22 +00:00
|
|
|
row, flags = getText(line, indentLevel, indentPattern)
|
2018-05-21 20:52:50 +00:00
|
|
|
lineStack = append(lineStack, row)
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
|
|
|
|
2018-05-30 16:57:24 +00:00
|
|
|
ph.ProcessLine(line, indentLevel, indentPattern, headerStack, lineStack, flags)
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
2018-05-07 15:58:42 +00:00
|
|
|
ph.Eof()
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
|
|
|
|
2018-05-21 21:02:22 +00:00
|
|
|
func getText(str string, indentLevel int, indentPattern string) (text string, flags Flags) {
|
2018-05-07 15:14:59 +00:00
|
|
|
//fmt.Printf("indentLevel: %v str: '%s'\n", indentLevel, str )
|
2018-05-29 16:41:30 +00:00
|
|
|
flags.Done = false
|
2018-05-30 16:57:24 +00:00
|
|
|
flags.Dropped = false
|
2018-05-29 16:41:30 +00:00
|
|
|
flags.Todo = false
|
|
|
|
flags.RepTask.Is = false
|
|
|
|
flags.Pomodoros = 0
|
|
|
|
|
2018-05-21 20:52:50 +00:00
|
|
|
if len(str) < (indentLevel*4 + 2) {
|
2018-05-29 16:41:30 +00:00
|
|
|
return "", flags
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
2018-05-13 17:07:54 +00:00
|
|
|
str = strings.TrimLeft(str, strings.Repeat(indentPattern, indentLevel))
|
|
|
|
text = str[2:]
|
2018-05-29 16:41:30 +00:00
|
|
|
|
|
|
|
if todoTaskExp.MatchString(text) {
|
2018-05-21 21:02:22 +00:00
|
|
|
flags.Todo = true
|
2018-05-29 16:41:30 +00:00
|
|
|
inner := string(todoTaskExp.FindSubmatch([]byte(text))[1])
|
|
|
|
if strings.ContainsAny(inner, "xX") {
|
2018-05-21 21:02:22 +00:00
|
|
|
flags.Done = true
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
2018-05-30 16:57:24 +00:00
|
|
|
if strings.Contains(inner, "-") {
|
|
|
|
flags.Dropped = true
|
|
|
|
}
|
2018-05-29 16:41:30 +00:00
|
|
|
flags.Pomodoros = strings.Count(inner, ".")
|
|
|
|
if len(text) > len(inner) + 3 {
|
|
|
|
text = text[len(inner)+3:]
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
2018-05-08 17:07:20 +00:00
|
|
|
|
|
|
|
if repTaskRegExp.MatchString(text) {
|
2018-05-21 21:02:22 +00:00
|
|
|
flags.RepTask.Is = true
|
2018-05-08 17:07:20 +00:00
|
|
|
matches := repTaskRegExp.FindStringSubmatch(text)
|
2018-05-21 21:02:22 +00:00
|
|
|
flags.RepTask.A, _ = strconv.Atoi(matches[1])
|
|
|
|
flags.RepTask.B, _ = strconv.Atoi(matches[2])
|
2018-05-08 17:07:20 +00:00
|
|
|
loc := repTaskRegExp.FindIndex([]byte(text))
|
2018-05-21 21:13:21 +00:00
|
|
|
text = text[loc[1]+1:]
|
2018-05-08 17:07:20 +00:00
|
|
|
}
|
2018-05-07 15:14:59 +00:00
|
|
|
}
|
|
|
|
return
|
2018-05-21 20:52:50 +00:00
|
|
|
}
|