fuzzyworld

template / commit

Added support for unique indexes.

ea896f4747706a1417867e44e7d26bb6e4be89a0 · Pavel Safronov · 2022-09-22 17:14:01 -0700 · parents 319b8b3fff54

Added support for unique indexes.
This is done by defining a special function, and checking if this function gets called.
Other changes:
- slight reformat
- slight cleanup
- added helpful VSCode tasks, like installing the app and removing its config
 .vscode/launch.json |  7 +++++
 .vscode/tasks.json  | 17 +++++++++++
 config.go           | 18 +++++------
 main.go             |  9 +++---
 new.go              | 88 ++++++++++++++++++++++++++++++++++-------------------
 utils.go            |  3 --
 6 files changed, 94 insertions(+), 48 deletions(-)

diff --git a/.vscode/launch.json b/.vscode/launch.json
index f9195f2..8ed2713 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -11,6 +11,13 @@
             "script": "rm ~/.template.yaml -ErrorAction SilentlyContinue",
             "cwd": "${workspaceFolder}"
         },
+        {
+            "name": "Install template",
+            "type": "PowerShell",
+            "request": "launch",
+            "script": "go install",
+            "cwd": "${workspaceFolder}"
+        },
         {
             "name": "Run: template",
             "type": "go",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..2e7bb7f
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "remove-template-yaml",
+            "type": "shell",
+            "command": "rm ~/.template.yaml -ErrorAction SilentlyContinue",
+            "options": {
+                "shell": {
+                    "executable": "powershell.exe"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/config.go b/config.go
index 962eccc..b1991e9 100644
--- a/config.go
+++ b/config.go
@@ -20,7 +20,6 @@ type Profile struct {
 	NamePatterns []string
 	PostScript   []string
 
-	// ReplacementStrings map[string][]string
 	// FileTemplatePath string
 }
 
@@ -36,10 +35,10 @@ func defaultConfig() Config {
 				Path:      "C:\\work\\daily-notes",
 				Type:      FileType,
 				NamePatterns: []string{
-					"{{.Year}}-{{.Month}}-{{.Day}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
-					"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
-					"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
-					"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
+					"{{$index := getUniqueIndex}}" +
+						"{{.Year}}-{{.Month}}-{{.Day}}" +
+						"{{if (gt $index 0)}}-{{$index}}{{end}}" +
+						".md",
 				},
 				PostScript: []string{
 					"code",
@@ -51,10 +50,11 @@ func defaultConfig() Config {
 				Path: "~/Dropbox/Blog",
 				Type: FileType,
 				NamePatterns: []string{
-					"{{.Year}}-{{.Month}}-{{.Day}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
-					"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
-					"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
-					"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.md",
+					"{{$index := getUniqueIndex}}" +
+						"{{.Year}}-{{.Month}}-{{.Day}}" +
+						"{{if (gt $index 0)}}-{{$index}}{{end}}" +
+						"{{if .ProjectName}}-{{.ProjectName}}{{end}}" +
+						".md",
 				},
 				PostScript: []string{
 					"code",
diff --git a/main.go b/main.go
index d1e87f6..a8ad254 100644
--- a/main.go
+++ b/main.go
@@ -10,7 +10,6 @@ import (
 
 func main() {
 	configFilePath := getFullPath("~/.template.yaml")
-	// defaultProfileName := "default"
 	var profileName string
 	var projectName string
 
@@ -20,12 +19,12 @@ func main() {
 		EnableBashCompletion: true,
 		Flags: []cli.Flag{
 			&cli.StringFlag{
-				Name:    "profile",
-				Aliases: []string{"p"},
-				Value:   "",
-				// Value:       defaultProfileName,
+				Name:        "profile",
+				Aliases:     []string{"p"},
+				Value:       "",
 				Usage:       "`PROFILE` to use for the template",
 				Destination: &profileName,
+				// Value:       defaultProfileName,
 				// Required:    true,
 				// EnvVars: []string{"TEMPLATE_PROFILE"},
 			},
diff --git a/new.go b/new.go
index 2812a37..4033292 100644
--- a/new.go
+++ b/new.go
@@ -83,7 +83,6 @@ func processProfile(profile Profile, name string) error {
 	if newName == "" {
 		return errors.New("Couldn't find a good new name")
 	} else {
-		fmt.Printf("newName: %v\n", newName)
 		if useDirs {
 			fmt.Printf("Creating directory: %v\n", fullPath)
 			err = os.Mkdir(fullPath, os.ModePerm)
@@ -104,10 +103,12 @@ func processProfile(profile Profile, name string) error {
 	if postScripts != nil && len(postScripts) > 0 {
 		allArgs := []string{"/C"}
 		allArgs = append(allArgs, postScripts...)
-		fmt.Printf("Executing post script: cmd %v \n", strings.Trim(fmt.Sprint(allArgs), "[]"))
+		debugProfileScript := fmt.Sprintf("cmd %v", strings.Trim(fmt.Sprint(allArgs), "[]"))
+		fmt.Printf("Executing post script: %v \n", debugProfileScript)
 		cmd := exec.Command("cmd", allArgs...)
 		if err := cmd.Run(); err != nil {
-			// return err
+			// post scripts tend to fail (TODO: investigate why), so for now we'll just log the error
+			fmt.Printf("Error executing post script '%v': %v\n", debugProfileScript, err)
 		}
 	}
 
@@ -117,6 +118,7 @@ func processProfile(profile Profile, name string) error {
 type NamePatternData struct {
 	Year, Month, Day, Hour, Minute, Second string
 	ProjectName                            string
+	Index                                  int
 }
 type PostScriptPatternData struct {
 	Name string
@@ -125,19 +127,16 @@ type PostScriptPatternData struct {
 
 func createNewName(name string, profile Profile, existingEntities []string) (string, error) {
 	now := time.Now()
-	patternInfos := createNamePatternData(now, name)
-	for _, patternInfo := range patternInfos {
-		newName, err := createNewNameForProfile(profile, patternInfo, existingEntities)
-		if err != nil {
-			return "", err
-		} else {
-			return newName, nil
-		}
+	patternInfo := createNamePatternData(now, name)
+	newName, err := createNewNameForProfile(profile, patternInfo, existingEntities)
+	if err != nil {
+		return "", err
+	} else {
+		return newName, nil
 	}
-	return "", errors.New("Couldn't find a new name")
 }
 
-func createNamePatternData(now time.Time, projectName string) []NamePatternData {
+func createNamePatternData(now time.Time, projectName string) NamePatternData {
 	patternInfo := NamePatternData{
 		Year:        now.Format("2006"),
 		Month:       now.Format("01"),
@@ -146,28 +145,59 @@ func createNamePatternData(now time.Time, projectName string) []NamePatternData
 		Minute:      now.Format("04"),
 		Second:      now.Format("05"),
 		ProjectName: projectName,
+		Index:       0,
 	}
 
-	return []NamePatternData{patternInfo}
+	return patternInfo
 }
 
 func createNewNameForProfile(profile Profile, patternData NamePatternData, existingEntities []string) (string, error) {
-	for _, namePattern := range profile.NamePatterns {
-		template, err := template.New("template-name").Parse(namePattern)
-		if err != nil {
-			return "", err
+	for index, namePattern := range profile.NamePatterns {
+
+		startingIndex := 0
+		invokeCount := 0
+		funcMap := template.FuncMap{
+			"getUniqueIndex": func() int {
+				invokeCount++
+				return startingIndex
+			},
 		}
+		template := template.New("template-name").Funcs(funcMap)
 
-		sb := new(strings.Builder)
-		err = template.Execute(sb, patternData)
-		if err != nil {
-			return "", err
-		}
+		for {
+
+			template, err := template.Parse(namePattern)
+			if err != nil {
+				return "", err
+			}
+
+			sb := new(strings.Builder)
+			err = template.Execute(sb, patternData)
+			if err != nil {
+				return "", err
+			}
+
+			newName := sb.String()
+			alreadyExists := slices.Contains(existingEntities, newName)
+			useIndex := invokeCount > 0
+			isLastPattern := index == len(profile.NamePatterns)-1
 
-		newName := sb.String()
-		alreadyExists := slices.Contains(existingEntities, newName)
-		if !alreadyExists {
-			return newName, nil
+			// if no conflict, use this name
+			if !alreadyExists {
+				return newName, nil
+			}
+			// if index is not being used (template did not invoke getUniqueIndex)
+			// then we're done
+			if !useIndex {
+				break
+			}
+
+			// if getUniqueIndex was used, but this isn't the last pattern, report an error
+			if useIndex && !isLastPattern {
+				return "", errors.New("Cannot use function getUniqueIndex in a pattern that is not the last pattern")
+			}
+
+			startingIndex++
 		}
 	}
 	return "", errors.New("Couldn't find a new name")
@@ -204,7 +234,3 @@ func createPostScriptArray(profile Profile, name string, path string) ([]string,
 
 	return array, nil
 }
-
-// func getNextEntry(name string, existingNames []string, profile Profile) string {
-// 	profile.
-// }
diff --git a/utils.go b/utils.go
index bbc6035..ceb6403 100644
--- a/utils.go
+++ b/utils.go
@@ -24,11 +24,8 @@ func getFullPath(path string) string {
 	dir := usr.HomeDir
 	var newPath string
 	if path == "~" {
-		// In case of "~", which won't be caught by the "else if"
 		newPath = dir
 	} else if strings.HasPrefix(path, "~/") {
-		// Use strings.HasPrefix so we don't match paths like
-		// "/something/~/something/"
 		newPath = filepath.Join(dir, path[2:])
 	} else {
 		newPath = path