Skip to content

Add Note search#44

Merged
mors119 merged 2 commits into
FrilLab:mainfrom
mors119:feature/note-search
Jun 3, 2026
Merged

Add Note search#44
mors119 merged 2 commits into
FrilLab:mainfrom
mors119:feature/note-search

Conversation

@mors119
Copy link
Copy Markdown
Collaborator

@mors119 mors119 commented Jun 3, 2026

Summary

Closes #20

Type of Change

  • feat
  • fix
  • docs
  • refactor
  • test
  • chore

Checklist

  • Code builds successfully
  • Tests pass
  • Documentation updated

Summary by CodeRabbit

  • New Features

    • Added search command to find notes by keyword matching with case-insensitive support
  • Documentation

    • Substantially rewrote README clarifying product positioning as a personal knowledge vault
    • Added comprehensive quick start section with CLI command examples
    • Expanded features, use cases, and multi-phase roadmap documentation
  • Chores

    • Updated CLI binary name to flvt
    • Updated pull request template with CI checklist

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements the keyword search feature for FrilVault notes with end-to-end changes: error handling for missing notes, case-insensitive search logic in the service, repository enumeration across the vault directory, CLI command definition, unified output formatting, command routing, API re-exports, comprehensive tests, and documentation updates clarifying the line-anchored note model.

Changes

Search Feature Implementation

Layer / File(s) Summary
Error handling for missing notes
crates/frilvault-core/src/error/errors.rs
FrilVaultError::NoteNotFound(Uuid) variant added to support explicit error reporting when notes are not found during delete/update operations.
Search service and note lifecycle updates
crates/frilvault-core/src/note/service.rs
search_notes() implements case-insensitive keyword matching across all notes. delete_note and update_note refactored to return NoteNotFound error instead of silently succeeding when the target note is missing.
Repository file enumeration
crates/frilvault-core/src/storage/yaml_repository.rs
list_all_note_files() recursively traverses the vault directory with private vault_root() helper to return all YAML note files, enabling bulk search across the vault.
Search command CLI definition
apps/frilvault-cli/src/cli/{mod.rs, search.rs}, apps/frilvault-cli/src/command/mod.rs
SearchCommand struct with keyword argument, pub mod search wiring, and Commands::Search enum variant for CLI argument parsing.
Unified output module
apps/frilvault-cli/src/output.rs
New output module with print_note() and print_note_count() functions to centralize note display logic, supporting both line and symbol anchor formatting.
List command refactoring
apps/frilvault-cli/src/command/list.rs
Delegates note display to shared output module instead of inline println! statements, improving consistency across commands.
Command execution and routing
apps/frilvault-cli/{Cargo.toml, src/main.rs, src/command/search.rs}
Implements command::search::execute() entrypoint, adds output module declaration, routes Commands::Search in main's dispatch, defines explicit flvt binary target, and adds search module to command hierarchy.
API re-exports and module visibility
crates/frilvault-core/src/{lib.rs, parser/mod.rs, workspace/path_resolver.rs}
Expands public re-exports with wildcard imports for error, parser, storage, and workspace modules; makes parser submodules private while keeping types accessible; adds workspace_root() getter to PathResolver.
Test coverage
crates/frilvault-core/src/tests/{mod.rs, note_service_test.rs, yaml_parser_test.rs, yaml_repository_test.rs}
Adds search_notes_finds_matching_notes test validating case-insensitive search across multiple notes, list_all_note_files_returns_all_note_files test validating repository enumeration, updates test module declarations and import formatting.
Documentation and template updates
README.md, .github/PULL_REQUEST_TEMPLATE.md
README repositioned as personal code vault, Quick Start with search command examples, reorganized Features around line anchors and search, added Storage Structure, Use Cases, and expanded Roadmap. PR template updated with required Rust CI checks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • FrilLab/frilvault#40: This PR builds on the existing CRUD CLI/service work by modifying NoteService delete/update flows and extending the CLI to route output via shared printing helpers before adding search on top.
  • FrilLab/frilvault#38: This PR extends the core storage/workspace foundation by modifying error handling (NoteNotFound variant) and adding list_all_note_files enumeration over the YAML repository used by the search feature.

Poem

🐇 A vault for notes, both line and thought,
Where keywords search what knowledge brought—
No symbols now, just anchored truth,
From early dev to tested proof,
FrilVault grows with every search! 📚

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Note search' directly and clearly describes the main change: implementation of a note search feature.
Linked Issues check ✅ Passed The PR implements the search functionality required by issue #20, adding a 'search' subcommand with keyword-based searching as specified.
Out of Scope Changes check ✅ Passed All changes are directly related to adding the note search feature. Documentation, CLI structure, core service methods, and tests align with the search feature scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
crates/frilvault-core/src/lib.rs (1)

8-12: 💤 Low value

Wildcard re-exports broaden the public API surface.

pub use module::* exposes every public item and risks name collisions or unintentionally stabilizing internals as part of the crate's public contract. Consider explicit re-exports of the types you intend to expose (e.g., Note, NoteAnchor, FrilVaultError, YamlNoteRepository, PathResolver, Workspace).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/frilvault-core/src/lib.rs` around lines 8 - 12, The wildcard
re-exports in lib.rs expose the entire modules; replace each `pub use ...::*`
with explicit re-exports of the public types you intend to stabilize (for
example export `Note`, `NoteAnchor` from note, `FrilVaultError` from error,
`YamlNoteRepository` from storage, `PathResolver` from parser, and `Workspace`
from workspace) so only those symbols become part of the crate API; update the
lines that currently read `pub use error::*`, `pub use note::*`, `pub use
parser::*`, `pub use storage::*`, `pub use workspace::*` to individual `pub use`
statements naming the specific types/functions/traits you want to expose.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/frilvault-cli/src/cli/mod.rs`:
- Line 16: The CLI name is inconsistent: the command attribute #[command(name =
"flvt", ...)] in src/cli/mod.rs and the [[bin]] name = "flvt" in Cargo.toml
differ from README examples that use "flv"; pick one canonical name and make
them consistent—either update README.md Quick Start examples to use "flvt"
(preferred if keeping current code) or change the binary and command attribute
to "flv" (edit Cargo.toml [[bin]] name and the #[command(name = "...")] value in
src/cli/mod.rs) so the documented command matches the actual binary.

In `@apps/frilvault-cli/src/output.rs`:
- Around line 32-36: The message in print_note_count always uses the plural
"notes"; change print_note_count to choose "note" when count == 1 and "notes"
otherwise (e.g., compute a suffix or full word based on count) and use that in
the println! call so it prints "Found 1 note" for a single result and "Found N
notes" for all other counts; keep the existing blank println! after the message.

In `@crates/frilvault-core/src/storage/yaml_repository.rs`:
- Around line 108-110: In collect_note_files, replace the hardcoded extension
check path.extension().and_then(|ext| ext.to_str()) != Some("yml") with a
comparison against the NOTE_FILE_EXTENSION constant (e.g. !=
Some(NOTE_FILE_EXTENSION) or compare ext.to_str() to NOTE_FILE_EXTENSION) so the
filter uses the same NOTE_FILE_EXTENSION as PathResolver::note_file_name; ensure
NOTE_FILE_EXTENSION is in scope or imported where collect_note_files is defined.

---

Nitpick comments:
In `@crates/frilvault-core/src/lib.rs`:
- Around line 8-12: The wildcard re-exports in lib.rs expose the entire modules;
replace each `pub use ...::*` with explicit re-exports of the public types you
intend to stabilize (for example export `Note`, `NoteAnchor` from note,
`FrilVaultError` from error, `YamlNoteRepository` from storage, `PathResolver`
from parser, and `Workspace` from workspace) so only those symbols become part
of the crate API; update the lines that currently read `pub use error::*`, `pub
use note::*`, `pub use parser::*`, `pub use storage::*`, `pub use workspace::*`
to individual `pub use` statements naming the specific types/functions/traits
you want to expose.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 591acc05-643e-4d02-979b-d955644ec6af

📥 Commits

Reviewing files that changed from the base of the PR and between b555844 and 19f95a4.

📒 Files selected for processing (20)
  • .github/PULL_REQUEST_TEMPLATE.md
  • README.md
  • apps/frilvault-cli/Cargo.toml
  • apps/frilvault-cli/src/cli/mod.rs
  • apps/frilvault-cli/src/cli/search.rs
  • apps/frilvault-cli/src/command/list.rs
  • apps/frilvault-cli/src/command/mod.rs
  • apps/frilvault-cli/src/command/search.rs
  • apps/frilvault-cli/src/main.rs
  • apps/frilvault-cli/src/output.rs
  • crates/frilvault-core/src/error/errors.rs
  • crates/frilvault-core/src/lib.rs
  • crates/frilvault-core/src/note/service.rs
  • crates/frilvault-core/src/parser/mod.rs
  • crates/frilvault-core/src/storage/yaml_repository.rs
  • crates/frilvault-core/src/tests/mod.rs
  • crates/frilvault-core/src/tests/note_service_test.rs
  • crates/frilvault-core/src/tests/yaml_parser_test.rs
  • crates/frilvault-core/src/tests/yaml_repository_test.rs
  • crates/frilvault-core/src/workspace/path_resolver.rs

version,
about = "Personal note vault for source code"
)]
#[command(name = "flvt", version, about = "Personal note vault for source code")]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the binary target name and any other references to flv/flvt
fd -t f Cargo.toml apps/frilvault-cli -x cat {}
echo "---- references ----"
rg -n -w 'flv|flvt' --glob '!**/target/**'

Repository: FrilLab/frilvault

Length of output: 734


🏁 Script executed:

#!/bin/bash
# Inspect CLI wiring to see whether there's any flv alias/wrapper.
set -euo pipefail
echo "---- apps/frilvault-cli/src/main.rs ----"
sed -n '1,200p' apps/frilvault-cli/src/main.rs
echo "---- apps/frilvault-cli/src/cli/mod.rs (around command derive) ----"
sed -n '1,120p' apps/frilvault-cli/src/cli/mod.rs
echo "---- any flv/flvt mentions in cli folder ----"
rg -n -S 'flv|flvt' apps/frilvault-cli/src

Repository: FrilLab/frilvault

Length of output: 1551


CLI name mismatch: binary/Clap uses flvt, README documents flv.

apps/frilvault-cli/Cargo.toml sets [[bin]] name = "flvt", and apps/frilvault-cli/src/cli/mod.rs uses #[command(name = "flvt", ...)], but README.md Quick Start examples invoke flv ...—so the documented commands won’t run as written. Align the canonical name by updating the README to flvt or changing the binary/command to flv.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/frilvault-cli/src/cli/mod.rs` at line 16, The CLI name is inconsistent:
the command attribute #[command(name = "flvt", ...)] in src/cli/mod.rs and the
[[bin]] name = "flvt" in Cargo.toml differ from README examples that use "flv";
pick one canonical name and make them consistent—either update README.md Quick
Start examples to use "flvt" (preferred if keeping current code) or change the
binary and command attribute to "flv" (edit Cargo.toml [[bin]] name and the
#[command(name = "...")] value in src/cli/mod.rs) so the documented command
matches the actual binary.

Comment on lines +32 to +36
pub fn print_note_count(count: usize) {
println!("Found {} notes", count);

println!();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Pluralization: "Found 1 notes" reads incorrectly for a single result.

The count message is always plural. Consider conditional pluralization.

✏️ Proposed fix
 pub fn print_note_count(count: usize) {
-    println!("Found {} notes", count);
+    println!("Found {} note{}", count, if count == 1 { "" } else { "s" });

     println!();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn print_note_count(count: usize) {
println!("Found {} notes", count);
println!();
}
pub fn print_note_count(count: usize) {
println!("Found {} note{}", count, if count == 1 { "" } else { "s" });
println!();
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/frilvault-cli/src/output.rs` around lines 32 - 36, The message in
print_note_count always uses the plural "notes"; change print_note_count to
choose "note" when count == 1 and "notes" otherwise (e.g., compute a suffix or
full word based on count) and use that in the println! call so it prints "Found
1 note" for a single result and "Found N notes" for all other counts; keep the
existing blank println! after the message.

Comment on lines +108 to +110
if path.extension().and_then(|ext| ext.to_str()) != Some("yml") {
continue;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP --type=rust 'NOTE_FILE_EXTENSION\s*[:=]'

Repository: FrilLab/frilvault

Length of output: 147


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="crates/frilvault-core/src/storage/yaml_repository.rs"
nl -ba "$FILE" | sed -n '80,140p'

Repository: FrilLab/frilvault

Length of output: 104


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="crates/frilvault-core/src/storage/yaml_repository.rs"

# Show relevant section with line numbers
awk 'NR>=80 && NR<=140 {printf "%d\t%s\n", NR, $0}' "$FILE"

echo "---- imports/const usage ----"
rg -n --fixed-string 'NOTE_FILE_EXTENSION' "$FILE" || true
rg -n --fixed-string 'Some("yml")' "$FILE" || true
rg -n --fixed-string '"yml"' "$FILE" || true

Repository: FrilLab/frilvault

Length of output: 2544


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="crates/frilvault-core/src/storage/yaml_repository.rs"

# Search within file
rg -n --fixed-strings 'NOTE_FILE_EXTENSION' "$FILE" || true
rg -n --fixed-strings '"yml"' "$FILE" || true

echo "---- top of file ----"
awk 'NR>=1 && NR<=80 {printf "%d\t%s\n", NR, $0}' "$FILE"

Repository: FrilLab/frilvault

Length of output: 2667


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate PathResolver::note_file_name implementation
rg -n "fn\s+note_file_name" crates/frilvault-core/src/workspace -S
rg -n "NOTE_FILE_EXTENSION" crates/frilvault-core/src/workspace -S || true

Repository: FrilLab/frilvault

Length of output: 429


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# show surrounding code for note_file_name if found
FILE=$(rg -l "fn\s+note_file_name" crates/frilvault-core/src/workspace -S | head -n 1 || true)
echo "NOTE_FILE_NAME_FILE=$FILE"
if [ -n "$FILE" ]; then
  awk 'NR>=1 && NR<=220 {print}' "$FILE" | sed -n '1,220p'
fi

Repository: FrilLab/frilvault

Length of output: 1495


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# tighter display: print around NOTE_FILE_EXTENSION usage in workspace
rg -n "NOTE_FILE_EXTENSION" crates/frilvault-core/src/workspace -S -n --context 3 || true

Repository: FrilLab/frilvault

Length of output: 1131


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find PathResolver::note_file_name and any NOTE_FILE_EXTENSION usage
rg -n "fn\s+note_file_name" crates/frilvault-core/src/workspace -S
rg -n "NOTE_FILE_EXTENSION" crates/frilvault-core/src/workspace -S || true

Repository: FrilLab/frilvault

Length of output: 429


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 2) Print the file content region around note_file_name (limit output)
FILE=$(rg -l "fn\s+note_file_name" crates/frilvault-core/src/workspace -S | head -n 1 || true)
echo "NOTE_FILE_NAME_FILE=$FILE"
if [ -n "$FILE" ]; then
  # print ~80 lines around the first match
  MATCH_LINE=$(rg -n "fn\s+note_file_name" "$FILE" -S | head -n 1 | cut -d: -f1)
  START=$((MATCH_LINE-40))
  END=$((MATCH_LINE+60))
  awk -v s="$START" -v e="$END" 'NR>=s && NR<=e {printf "%d\t%s\n", NR, $0}' "$FILE"
fi

Repository: FrilLab/frilvault

Length of output: 1624


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 3) Show exact NOTE_FILE_EXTENSION usage with nearby lines (if any) in workspace
rg -n "NOTE_FILE_EXTENSION" crates/frilvault-core/src/workspace -S --context 3 || true

Repository: FrilLab/frilvault

Length of output: 1131


Use NOTE_FILE_EXTENSION instead of hardcoding "yml" in collect_note_files.

crates/frilvault-core/src/storage/yaml_repository.rs (lines 108-110) filters by Some("yml"), while note paths are generated via PathResolver::note_file_name(..., NOTE_FILE_EXTENSION) (where NOTE_FILE_EXTENSION is exactly "yml"). This keeps enumeration consistent if the constant ever changes.

♻️ Proposed fix
-use crate::constants::VAULT_DIR_NAME;
+use crate::constants::{NOTE_FILE_EXTENSION, VAULT_DIR_NAME};
-            if path.extension().and_then(|ext| ext.to_str()) != Some("yml") {
+            if path.extension().and_then(|ext| ext.to_str()) != Some(NOTE_FILE_EXTENSION) {
                 continue;
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if path.extension().and_then(|ext| ext.to_str()) != Some("yml") {
continue;
}
if path.extension().and_then(|ext| ext.to_str()) != Some(NOTE_FILE_EXTENSION) {
continue;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/frilvault-core/src/storage/yaml_repository.rs` around lines 108 - 110,
In collect_note_files, replace the hardcoded extension check
path.extension().and_then(|ext| ext.to_str()) != Some("yml") with a comparison
against the NOTE_FILE_EXTENSION constant (e.g. != Some(NOTE_FILE_EXTENSION) or
compare ext.to_str() to NOTE_FILE_EXTENSION) so the filter uses the same
NOTE_FILE_EXTENSION as PathResolver::note_file_name; ensure NOTE_FILE_EXTENSION
is in scope or imported where collect_note_files is defined.

@mors119 mors119 merged commit 64626c4 into FrilLab:main Jun 3, 2026
3 checks passed
@mors119 mors119 deleted the feature/note-search branch June 3, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SEARCH] Search Notes By Keyword

1 participant