emdbed/io.go

96 lines
1.7 KiB
Go

package emdbed
import (
"fmt"
"regexp"
"strconv"
"strings"
)
var endline = regexp.MustCompile(`(?m)$`)
type emdbed struct {
name string
contents string
language string
start string
end string
}
func (e emdbed) line(line int, end bool) (int, error) {
if line == 1 && !end {
return 0, nil
}
indexes := endline.FindAllStringIndex(e.contents, -1)
if len(indexes) < line {
return 0, fmt.Errorf("file %q has no line %d", e.name, line)
}
dec := 1
if !end {
dec++
}
var inc int
if !end {
inc++
}
return indexes[line-dec][0] + inc, nil
}
func (e emdbed) regex(pattern string, end bool) (int, error) {
re, err := regexp.Compile(pattern)
if err != nil {
return 0, err
}
match := re.FindStringIndex(e.contents)
if match == nil {
return 0, fmt.Errorf("file %q has no match for pattern %q", e.name, pattern)
}
var inc int
if end {
inc++
}
return match[0] + inc, nil
}
func (e emdbed) selector(selector string, end bool) (int, error) {
switch {
case strings.HasPrefix(selector, "L"):
line, err := strconv.Atoi(selector[1:])
if err != nil {
return 0, err
}
return e.line(line, end)
case strings.HasPrefix(selector, "/"):
pattern := strings.Trim(selector, "/")
return e.regex(pattern, end)
default:
return 0, fmt.Errorf("unknown selector %q", selector)
}
}
func (e emdbed) Start() (int, error) {
if e.start == "" {
return 0, nil
}
return e.selector(e.start, false)
}
func (e emdbed) End() (int, error) {
if e.end == "" {
return len(e.contents), nil
}
return e.selector(e.end, true)
}
func (e emdbed) Selection() (string, error) {
start, err := e.Start()
if err != nil {
return "", err
}
end, err := e.End()
if err != nil {
return "", err
}
return e.contents[start:end], nil
}