Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ notesmd-cli daily --vault "{vault-name}"

# Creates / opens daily note in your default editor
notesmd-cli daily --editor

# Adds content to daily note (appends if note already exists)
notesmd-cli daily --content "abcde"

# Adds content and opens in editor
notesmd-cli daily --content "abcde" --editor
```

### Search Note
Expand Down
4 changes: 4 additions & 0 deletions cmd/daily.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var DailyCmd = &cobra.Command{
uri := obsidian.Uri{}

err := actions.DailyNote(&vault, &uri, actions.DailyParams{
Content: dailyContent,
UseEditor: resolveUseEditor(cmd, &vault),
})
if err != nil {
Expand All @@ -26,8 +27,11 @@ var DailyCmd = &cobra.Command{
},
}

var dailyContent string

func init() {
DailyCmd.Flags().StringVarP(&vaultName, "vault", "v", "", "vault name (not required if default is set)")
DailyCmd.Flags().StringVarP(&dailyContent, "content", "c", "", "text to add to daily note (appends if note exists)")
DailyCmd.Flags().BoolP("editor", "e", false, "open in editor instead of Obsidian")
rootCmd.AddCommand(DailyCmd)
}
26 changes: 20 additions & 6 deletions pkg/actions/daily.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

type DailyParams struct {
Content string
UseEditor bool
}

Expand Down Expand Up @@ -48,17 +49,30 @@ func DailyNote(vault obsidian.VaultManager, uri obsidian.UriManager, params Dail
}

// Read template content if configured.
content := ""
templateContent := ""
if config.Template != "" {
templatePath := filepath.Join(vaultPath, obsidian.AddMdSuffix(config.Template))
if templateContent, readErr := os.ReadFile(templatePath); readErr == nil {
content = string(templateContent)
if data, readErr := os.ReadFile(templatePath); readErr == nil {
templateContent = string(data)
}
}

// WriteNoteFile leaves existing files unchanged (no append/overwrite).
if err := WriteNoteFile(notePath, content, false, false); err != nil {
return err
normalizedContent := NormalizeContent(params.Content)

_, statErr := os.Stat(notePath)
fileExists := statErr == nil

if fileExists && normalizedContent != "" {
// Append user content to existing daily note.
if err := WriteNoteFile(notePath, normalizedContent, true, false); err != nil {
return err
}
} else if !fileExists {
// Create new daily note with template + content.
newContent := templateContent + normalizedContent
if err := WriteNoteFile(notePath, newContent, false, false); err != nil {
return err
}
}

// Open the note.
Expand Down
80 changes: 80 additions & 0 deletions pkg/actions/daily_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,86 @@ func TestDailyNote(t *testing.T) {
assert.Equal(t, uri.ExecuteErr, err)
})

t.Run("Creates daily note with content", func(t *testing.T) {
tmpDir := t.TempDir()
vault := mocks.MockVaultOperator{Name: "myVault", PathValue: tmpDir}
uri := mocks.MockUriManager{}

err := actions.DailyNote(&vault, &uri, actions.DailyParams{
Content: "hello world",
})
assert.NoError(t, err)

data, _ := os.ReadFile(filepath.Join(tmpDir, today+".md"))
assert.Equal(t, "hello world", string(data))
})

t.Run("Creates daily note with template and content", func(t *testing.T) {
tmpDir := t.TempDir()
obsDir := filepath.Join(tmpDir, ".obsidian")
if err := os.MkdirAll(obsDir, 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(obsDir, "daily-notes.json"), []byte(`{
"template": "Templates/Daily"
}`), 0644); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Join(tmpDir, "Templates"), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "Templates", "Daily.md"), []byte("# Daily Note\n"), 0644); err != nil {
t.Fatal(err)
}

vault := mocks.MockVaultOperator{Name: "myVault", PathValue: tmpDir}
uri := mocks.MockUriManager{}

err := actions.DailyNote(&vault, &uri, actions.DailyParams{
Content: "- task 1",
})
assert.NoError(t, err)

data, _ := os.ReadFile(filepath.Join(tmpDir, today+".md"))
assert.Equal(t, "# Daily Note\n- task 1", string(data))
})

t.Run("Appends content to existing daily note", func(t *testing.T) {
tmpDir := t.TempDir()
notePath := filepath.Join(tmpDir, today+".md")
if err := os.WriteFile(notePath, []byte("existing content"), 0644); err != nil {
t.Fatal(err)
}

vault := mocks.MockVaultOperator{Name: "myVault", PathValue: tmpDir}
uri := mocks.MockUriManager{}

err := actions.DailyNote(&vault, &uri, actions.DailyParams{
Content: "\\nnew line",
})
assert.NoError(t, err)

data, _ := os.ReadFile(notePath)
assert.Equal(t, "existing content\nnew line", string(data))
})

t.Run("Does not modify existing daily note without content", func(t *testing.T) {
tmpDir := t.TempDir()
notePath := filepath.Join(tmpDir, today+".md")
if err := os.WriteFile(notePath, []byte("existing content"), 0644); err != nil {
t.Fatal(err)
}

vault := mocks.MockVaultOperator{Name: "myVault", PathValue: tmpDir}
uri := mocks.MockUriManager{}

err := actions.DailyNote(&vault, &uri, actions.DailyParams{})
assert.NoError(t, err)

data, _ := os.ReadFile(notePath)
assert.Equal(t, "existing content", string(data))
})

t.Run("Creates daily note with custom format", func(t *testing.T) {
tmpDir := t.TempDir()
obsDir := filepath.Join(tmpDir, ".obsidian")
Expand Down
Loading