markdown-bullet-journal/process/process.go

172 lines
4.0 KiB
Go

package process
import (
"bufio"
"io/ioutil"
"log"
"os"
"regexp"
"strconv"
"strings"
)
const (
Version = "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
A, B int
}
type Flags struct {
Todo bool
Done bool
Dropped bool
RepTask RepTask
Pomodoros int
}
type ProcessHandler interface {
Writeln(line string)
ProcessLine(line string, indentLevel int, indentString string, headerStack []string, lineStack []string, flags Flags)
Eof()
NewFile()
}
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
}
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 {
log.Fatal(err)
}
defer file.Close()
ph.NewFile()
headerStack := make([]string, 1)
lineStack := make([]string, 0)
//flags := Flags{}
scanner := bufio.NewScanner(file)
indentPattern := ""
indentLevel := 0
for scanner.Scan() {
line := scanner.Text()
// 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)
}
// number of times indent pattern repeats at front of line
if indentPattern == "" {
indentLevel = 0
} else {
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]
}
}
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, flags Flags) {
//fmt.Printf("indentLevel: %v str: '%s'\n", indentLevel, str )
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:]
if todoTaskExp.MatchString(text) {
flags.Todo = true
inner := string(todoTaskExp.FindSubmatch([]byte(text))[1])
if strings.ContainsAny(inner, "xX") {
flags.Done = true
}
if strings.Contains(inner, "-") {
flags.Dropped = true
}
flags.Pomodoros = strings.Count(inner, ".")
if len(text) > len(inner) + 3 {
text = text[len(inner)+3:]
}
if repTaskRegExp.MatchString(text) {
flags.RepTask.Is = true
matches := repTaskRegExp.FindStringSubmatch(text)
flags.RepTask.A, _ = strconv.Atoi(matches[1])
flags.RepTask.B, _ = strconv.Atoi(matches[2])
loc := repTaskRegExp.FindIndex([]byte(text))
text = text[loc[1]+1:]
}
}
return
}