64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
package ticket
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// taskCheckboxRe matches GFM/YouTrack-style task list items:
|
|
//
|
|
// - [ ] unchecked
|
|
// - [x] checked
|
|
// * [X] also accepted
|
|
var taskCheckboxRe = regexp.MustCompile(`^(\s*)([-*+])\s+\[([ xX])\](\s*)(.*)$`)
|
|
|
|
// Checkbox is one task-list item inside a Markdown description.
|
|
type Checkbox struct {
|
|
Line int // 0-based line index in the source
|
|
Checked bool
|
|
Text string // label after the checkbox marker
|
|
}
|
|
|
|
// ListCheckboxes returns all task-list items in markdown source order.
|
|
func ListCheckboxes(markdown string) []Checkbox {
|
|
if markdown == "" {
|
|
return nil
|
|
}
|
|
lines := strings.Split(markdown, "\n")
|
|
var out []Checkbox
|
|
for i, line := range lines {
|
|
m := taskCheckboxRe.FindStringSubmatch(line)
|
|
if m == nil {
|
|
continue
|
|
}
|
|
out = append(out, Checkbox{
|
|
Line: i,
|
|
Checked: m[3] == "x" || m[3] == "X",
|
|
Text: m[5],
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ToggleCheckbox flips the checked state of the checkbox at index
|
|
// (0-based among ListCheckboxes results) and returns the updated markdown.
|
|
func ToggleCheckbox(markdown string, index int) (string, error) {
|
|
boxes := ListCheckboxes(markdown)
|
|
if index < 0 || index >= len(boxes) {
|
|
return markdown, fmt.Errorf("checkbox %d: not found", index)
|
|
}
|
|
lines := strings.Split(markdown, "\n")
|
|
lineIdx := boxes[index].Line
|
|
m := taskCheckboxRe.FindStringSubmatch(lines[lineIdx])
|
|
if m == nil {
|
|
return markdown, fmt.Errorf("checkbox %d: line changed", index)
|
|
}
|
|
mark := " "
|
|
if !(m[3] == "x" || m[3] == "X") {
|
|
mark = "x"
|
|
}
|
|
lines[lineIdx] = m[1] + m[2] + " [" + mark + "]" + m[4] + m[5]
|
|
return strings.Join(lines, "\n"), nil
|
|
}
|