Skip to content

Commit cd16347

Browse files
committed
Initial code commit
1 parent 5db6283 commit cd16347

11 files changed

+509
-6
lines changed

LICENSE

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
MIT License
1+
The MIT License (MIT)
22

3-
Copyright (c) 2025 Sean Ottey
3+
Copyright © 2025 sottey
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99
copies of the Software, and to permit persons to whom the Software is
1010
furnished to do so, subject to the following conditions:
1111

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
1414

1515
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# goteplan
22
Unofficial Noteplan Command Line Utility
3+
4+
This is an unofficial app to manage NotePlan notes from the command line. It should be able to compile for any operating system supporting the Go language.

cmd/create.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Copyright © 2025 sottey
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"bufio"
26+
"fmt"
27+
"os"
28+
"path/filepath"
29+
30+
"github.com/spf13/cobra"
31+
)
32+
33+
var createCmd = &cobra.Command{
34+
Use: "create <filename>",
35+
Short: "Create a new note",
36+
Args: cobra.MinimumNArgs(1),
37+
Example: "goteplan create Notes/Home/mynote.md",
38+
Run: func(cmd *cobra.Command, args []string) {
39+
filename := args[0]
40+
path := filepath.Join(BaseDir, filename)
41+
fmt.Println("Enter your note content. Press Ctrl+D when done:")
42+
scanner := bufio.NewScanner(os.Stdin)
43+
var content string
44+
for scanner.Scan() {
45+
content += scanner.Text() + "\n"
46+
}
47+
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
48+
fmt.Println("Error creating file:", err)
49+
}
50+
fmt.Println("Note saved:", filename)
51+
},
52+
}
53+
54+
func init() {
55+
rootCmd.AddCommand(createCmd)
56+
}

cmd/edit.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
Copyright © 2025 sottey
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"fmt"
26+
"os"
27+
"os/exec"
28+
"path/filepath"
29+
30+
"github.com/spf13/cobra"
31+
)
32+
33+
var editCmd = &cobra.Command{
34+
Use: "edit <filename>",
35+
Short: "Edit specified file",
36+
Args: cobra.MinimumNArgs(1),
37+
Example: "goteplan edit Notes/Home/mynote.md",
38+
Run: func(cmd *cobra.Command, args []string) {
39+
filename := args[0]
40+
path := filepath.Join(BaseDir, filename)
41+
editor := "nano" // Change to your preferred editor
42+
editCmd := exec.Command(editor, path)
43+
editCmd.Stdin = os.Stdin
44+
editCmd.Stdout = os.Stdout
45+
editCmd.Stderr = os.Stderr
46+
err := editCmd.Run()
47+
if err != nil {
48+
fmt.Println("Error opening editor:", err)
49+
}
50+
},
51+
}
52+
53+
func init() {
54+
rootCmd.AddCommand(editCmd)
55+
}

cmd/list.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Copyright © 2025 sottey
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"fmt"
26+
"os"
27+
"path/filepath"
28+
"strings"
29+
30+
"github.com/spf13/cobra"
31+
)
32+
33+
var listCmd = &cobra.Command{
34+
Use: "list",
35+
Short: "List all notes",
36+
Example: "goteplan list",
37+
Run: func(cmd *cobra.Command, args []string) {
38+
fmt.Printf("BaseDir: %v\n", BaseDir)
39+
err := filepath.Walk(BaseDir, func(path string, info os.FileInfo, err error) error {
40+
if err != nil {
41+
return err
42+
}
43+
if strings.HasSuffix(info.Name(), ".md") {
44+
fmt.Println(strings.TrimPrefix(path, BaseDir+"/"))
45+
}
46+
return nil
47+
})
48+
if err != nil {
49+
fmt.Println("Error listing notes:", err)
50+
}
51+
},
52+
}
53+
54+
func init() {
55+
rootCmd.AddCommand(listCmd)
56+
}

cmd/root.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
Copyright © 2025 sottey
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"fmt"
26+
"os"
27+
"path/filepath"
28+
"strings"
29+
30+
"github.com/spf13/cobra"
31+
"github.com/spf13/viper"
32+
)
33+
34+
var BaseDir string
35+
36+
var rootCmd = &cobra.Command{
37+
Use: "goteplan",
38+
Short: "A CLI for NotePlan notes management",
39+
}
40+
41+
func Execute() {
42+
err := rootCmd.Execute()
43+
if err != nil {
44+
os.Exit(1)
45+
}
46+
}
47+
48+
func init() {
49+
dataPath, _ := expandPath("~/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application Support/co.noteplan.NotePlan-setapp")
50+
configPath, _ := expandPath("~/")
51+
rootCmd.PersistentFlags().StringVarP(&BaseDir, "basedir", "b", "", "Root location of the NotePlan data")
52+
viper.BindPFlag("basedir", rootCmd.PersistentFlags().Lookup("basedir"))
53+
54+
viper.SetConfigName(".goteplan")
55+
viper.SetConfigType("json")
56+
viper.AddConfigPath(configPath)
57+
if err := viper.ReadInConfig(); err != nil {
58+
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
59+
fmt.Println("Config file not found. Creating...")
60+
viper.SetDefault("basedir", dataPath)
61+
if errTwo := viper.SafeWriteConfig(); errTwo != nil {
62+
fmt.Printf("Error creating config file: '%v'\n", errTwo)
63+
}
64+
} else {
65+
fmt.Printf("Error opening config file: %v\n", err)
66+
return
67+
}
68+
}
69+
70+
BaseDir = viper.GetString("basedir")
71+
}
72+
73+
func expandPath(path string) (string, error) {
74+
if strings.HasPrefix(path, "~") {
75+
homeDir, err := os.UserHomeDir()
76+
if err != nil {
77+
return "", err
78+
}
79+
return filepath.Join(homeDir, path[1:]), nil
80+
}
81+
return filepath.Abs(path)
82+
}

cmd/search.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
Copyright © 2025 sottey
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"fmt"
26+
"os"
27+
"path/filepath"
28+
"strings"
29+
30+
"github.com/spf13/cobra"
31+
)
32+
33+
var searchCmd = &cobra.Command{
34+
Use: "search <query>",
35+
Short: "Search for notes with the specified string (NOTE: This IS case sensitive)",
36+
Args: cobra.MinimumNArgs(1),
37+
Example: "goteplan search QueryString",
38+
Run: func(cmd *cobra.Command, args []string) {
39+
query := args[0]
40+
41+
err := filepath.Walk(BaseDir, func(path string, info os.FileInfo, err error) error {
42+
if err != nil {
43+
return err
44+
}
45+
if strings.HasSuffix(info.Name(), ".md") {
46+
content, err := os.ReadFile(path)
47+
if err != nil {
48+
return nil
49+
}
50+
if strings.Contains(string(content), query) {
51+
fmt.Println("Match found in:", strings.TrimPrefix(path, BaseDir+"/"))
52+
}
53+
}
54+
return nil
55+
})
56+
if err != nil {
57+
fmt.Println("Error searching notes:", err)
58+
}
59+
},
60+
}
61+
62+
func init() {
63+
rootCmd.AddCommand(searchCmd)
64+
}

0 commit comments

Comments
 (0)