go-projecttxt/project.go

231 lines
5.8 KiB
Go
Raw Normal View History

2022-06-07 18:50:33 +00:00
package projecttxt
import (
"fmt"
"sort"
"strings"
)
type Project struct {
2023-08-23 16:22:19 +00:00
Id int `json:"id"` // Internal project id
Original string `json:"original"` // Original raw project text
Name string `json:"name"` // The name of the project
Directory string `json:"directory"` // The directory part of the project text
Notes string `json:"notes"` // The filename of the notes file, defaults to Directory+/+notes.md
Repo string `json:"repo"` // The directory to the git repository, defaults to Directory+/+Name
Contexts []string `json:"contexts"`
ProjectTags []string `json:"projectTags"`
AdditionalTags map[string]string `json:"additionalTags"`
2022-06-07 18:50:33 +00:00
}
// ParseProject parses the input text string into a Project struct
func ParseProject(text string) (*Project, error) {
var err error
project := Project{
AdditionalTags: make(map[string]string),
}
project.Original = strings.Trim(text, "\t\n\r ")
2022-07-21 13:44:10 +00:00
parts := getParts(project.Original)
//parts := strings.Fields(project.Original)
var pIdx int
for pIdx = range parts {
2023-09-14 15:01:09 +00:00
if partIsSpecial(parts[pIdx]) {
break
2022-07-21 13:44:10 +00:00
}
2023-09-14 15:01:09 +00:00
project.Name = project.Name + " " + parts[pIdx]
2022-06-07 18:50:33 +00:00
}
2022-07-21 13:44:10 +00:00
project.Name = strings.TrimSpace(project.Name)
parts = parts[pIdx:]
2022-12-08 17:40:53 +00:00
var notesAbs, repoAbs bool
project.Notes = "notes.md"
project.Repo = project.Name
2022-06-07 18:50:33 +00:00
for _, v := range parts {
switch v[0] {
2022-07-21 13:44:10 +00:00
case '^': // Project Directory
project.Directory = v[1:]
2022-12-08 17:40:53 +00:00
if strings.HasSuffix(project.Directory, "/") {
project.Directory = strings.TrimSuffix(project.Directory, "/")
}
case '~': // Project Repo
project.Repo = v[1:]
if strings.HasPrefix(project.Repo, "/") {
repoAbs = true
}
case '#':
project.Notes = v[1:]
if strings.HasPrefix(project.Notes, "/") {
notesAbs = true
}
2022-06-07 18:50:33 +00:00
case '@': // Contexts
project.Contexts = append(project.Contexts, v[1:])
case '+': // ProjectTags
project.ProjectTags = append(project.ProjectTags, v[1:])
default:
if strings.Contains(v, ":") {
// Additional Tags
tagPts := strings.Split(v, ":")
if tagPts[0] != "" && tagPts[1] != "" {
project.AdditionalTags[tagPts[0]] = tagPts[1]
}
}
}
}
2022-12-08 17:40:53 +00:00
if !notesAbs {
project.Notes = fmt.Sprintf("%s/%s", project.Directory, project.Notes)
}
if !repoAbs {
project.Repo = fmt.Sprintf("%s/%s", project.Directory, project.Repo)
}
2022-06-07 18:50:33 +00:00
return &project, err
}
2023-09-14 15:01:09 +00:00
func partIsSpecial(pt string) bool {
if len(pt) == 0 {
return false
}
switch pt[0] {
case '^', '~', '#', '@', '+':
return true
default:
return false
}
}
2022-07-21 13:44:10 +00:00
// getParts parses the text from text pulling out each part.
// By default it splits on spaces, the only exception is if we find a double-quote
func getParts(text string) []string {
var ret []string
var wrk string
quoteStart := -1
for i := range text {
if quoteStart >= 0 {
if text[i] == '"' {
quoteStart = -1
ret = append(ret, wrk)
} else {
wrk = wrk + string(text[i])
}
} else {
switch text[i] {
case '"':
quoteStart = i
case ' ':
if len(wrk) > 0 {
ret = append(ret, wrk)
}
wrk = ""
default:
wrk = wrk + string(text[i])
}
}
}
if len(wrk) > 0 {
ret = append(ret, wrk)
}
return ret
}
2022-06-07 18:50:33 +00:00
// String returns a complete project string in project.txt format.
//
// Contexts, ProjectTags, and Additional Tags are alphabetically sorted,
// and appended at the end in the following order:
// Contexts, ProjectTags, Tags
//
// For example:
// Project.txt ^/home/user/projects/projecttxt @personal +projectxt contact:"Frank Workman" "Address 1":"1234 Work Place"
func (project Project) String() string {
text := fmt.Sprintf("%s ", project.Name)
2022-10-26 17:05:38 +00:00
text += fmt.Sprintf("^%s ", project.Directory)
2023-09-12 15:43:41 +00:00
if project.Repo != "" {
text += fmt.Sprintf("~%s ", project.Repo)
}
if project.Notes != "" {
text += fmt.Sprintf("#%s ", project.Notes)
}
2022-06-07 18:50:33 +00:00
if len(project.Contexts) > 0 {
sort.Strings(project.Contexts)
for _, context := range project.Contexts {
text += fmt.Sprintf("@%s ", context)
}
}
if len(project.ProjectTags) > 0 {
sort.Strings(project.ProjectTags)
for _, pTag := range project.ProjectTags {
text += fmt.Sprintf("+%s ", pTag)
}
}
if len(project.AdditionalTags) > 0 {
keys := make([]string, 0, len(project.AdditionalTags))
for key := range project.AdditionalTags {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
text += fmt.Sprintf("%s:%s ", key, project.AdditionalTags[key])
}
}
return text
}
func (project *Project) HasContext(context string) bool {
for _, v := range project.Contexts {
if v == context {
return true
}
}
return false
}
2022-07-21 13:44:10 +00:00
func (project *Project) GetContextsString() string {
var text string
sort.Strings(project.Contexts)
for _, context := range project.Contexts {
text += fmt.Sprintf("%s ", context)
}
return text
}
2022-06-07 18:50:33 +00:00
func (project *Project) HasProjectTag(projectTag string) bool {
for _, v := range project.ProjectTags {
if v == projectTag {
return true
}
}
return false
}
2022-07-21 13:44:10 +00:00
func (project *Project) GetProjectsString() string {
var text string
sort.Strings(project.ProjectTags)
for _, pTag := range project.ProjectTags {
text += fmt.Sprintf("%s ", pTag)
}
return text
}
2022-06-07 18:50:33 +00:00
func (project *Project) SetTag(name, val string) {
project.AdditionalTags[name] = val
}
func (project *Project) HasTag(name string) bool {
_, ok := project.AdditionalTags[name]
return ok
}
func (project *Project) GetTag(name string) string {
return project.AdditionalTags[name]
}
2022-07-21 13:44:10 +00:00
func (project *Project) GetTagsString() string {
var text string
keys := make([]string, 0, len(project.AdditionalTags))
for key := range project.AdditionalTags {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
text += fmt.Sprintf("%s:%s ; ", key, project.AdditionalTags[key])
}
return text
}