pub trait Content: AsRef<str> + Debug + Eq + PartialEq + Default {
    fn from_string(input: String) -> Self;

    fn open(path: &Path) -> Result<Self, Error>
    where
        Self: Sized
, { ... } fn from_string_with_cr(input: String) -> Self { ... } fn header(&self) -> &str { ... } fn body(&self) -> &str { ... } fn save_as(&self, new_file_path: &Path) -> Result<(), Error> { ... } fn as_str(&self) -> &str { ... } fn is_empty(&self) -> bool { ... } fn split(content: &str) -> (&str, &str) { ... } }
Expand description

Provides cheap access to the header with header(), the body with body(), and the whole raw text with as_str().

use tpnote_lib::content::Content;
use tpnote_lib::content::ContentString;
let input = "---\ntitle: \"My note\"\n---\nMy body";
let c = ContentString::from_string(String::from(input));

assert_eq!(c.header(), r#"title: "My note""#);
assert_eq!(c.body(), r#"My body"#);
assert_eq!(c.as_str(), input);

// A test without front matter leads to an empty header:
let c = ContentString::from_string(String::from("No header"));

assert_eq!(c.header(), "");
assert_eq!(c.body(), "No header");
assert_eq!(c.as_str(), "No header");

The Content trait allows to plug in you own storage back end ContentString does not suit you.

use tpnote_lib::content::Content;
use std::string::String;

#[derive(Debug, Eq, PartialEq, Default)]
struct MyString(String);
impl Content for MyString {
    fn from_string(input: String) -> Self {
        MyString(input)    
    }
}

impl AsRef<str> for MyString {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

let input = "---\ntitle: \"My note\"\n---\nMy body";
let s = MyString::from_string(input.to_string());

assert_eq!(s.header(), r#"title: "My note""#);
assert_eq!(s.body(), r#"My body"#);
assert_eq!(s.as_str(), input);

Required Methods

Constructor that parses a Tp-Note document. A valid document is UTF-8 encoded and starts with an optional BOM (byte order mark) followed by ---. When the start marker --- does not follow directly the BOM, it must be prepended by an empty line. In this case all text before is ignored: BOM + ignored text + empty line + ---.

use tpnote_lib::content::Content;
use tpnote_lib::content::ContentString;
let input = "---\ntitle: \"My note\"\n---\nMy body";
let c = ContentString::from_string(input.to_string());

assert_eq!(c.header(), r#"title: "My note""#);
assert_eq!(c.body(), "My body");

// A test without front matter leads to an empty header:
let c = ContentString::from_string("No header".to_string());

assert_eq!(c.header(), "");
assert_eq!(c.body(), "No header");

Provided Methods

Reads the file at path and stores the content Content. Possible \r\n are replaced by \n. This trait has a default implementation, the empty content.

use tpnote_lib::content::Content;
use tpnote_lib::content::ContentString;
use std::env::temp_dir;

// Prepare test.
let raw = "---\ntitle: \"My note\"\n---\nMy body";
let notefile = temp_dir().join("20221030-hello -- world.md");
let _ = std::fs::write(&notefile, raw.as_bytes());

// Start test.
let c = ContentString::open(&notefile).unwrap();

assert_eq!(c.header(), r#"title: "My note""#);
assert_eq!(c.body(), "My body");

Constructor that reads a structured document with a YAML header and body. All \r\n are converted to \n if there are any. If not, no memory allocation occurs and the buffer remains untouched.

use tpnote_lib::content::Content;
use tpnote_lib::content::ContentString;
let c = ContentString::from_string_with_cr(String::from(
    "---\r\ntitle: \"My note\"\r\n---\r\nMy\nbody\r\n"));

assert_eq!(c.header(), r#"title: "My note""#);
assert_eq!(c.body(), "My\nbody\n");

// A test without front matter leads to an empty header:
let c = ContentString::from_string(String::from("No header"));

assert_eq!(c.borrow_dependent().header, "");
assert_eq!(c.borrow_dependent().body, r#"No header"#);

Provides cheap access to the header between --- and ---. The default implementation is very expensive. Overwrite this.

Provides cheap access to the body after the second ---. The default implementation is very expensive. Overwrite this.

Writes the note to disk with new_file_path as filename. If new_file_path contains missing directories, they will be created on the fly.

use std::path::Path;
use std::env::temp_dir;
use std::fs;
use tpnote_lib::content::Content;
use tpnote_lib::content::ContentString;
let c = ContentString::from_string(
     String::from("prelude\n\n---\ntitle: \"My note\"\n---\nMy body"));
let outfile = temp_dir().join("mynote.md");
#[cfg(not(target_family = "windows"))]
let expected = "\u{feff}---\ntitle: \"My note\"\n---\nMy body\n";
#[cfg(target_family = "windows")]
let expected = "\u{feff}---\r\ntitle: \"My note\"\r\n---\r\nMy body\r\n";

c.save_as(&outfile).unwrap();
let result = fs::read_to_string(&outfile).unwrap();

assert_eq!(result, expected);
fs::remove_file(&outfile);

Accesses the whole content with all ---. Contract: The content does not contain any \r\n. If your content contains \r\n use the from_string_with_cr() constructor.

True if the header and body is empty.

Helper function that splits the content into header and body. The header, if present, is trimmed (trim()), the body is kept as it is. Any BOM (byte order mark) at the beginning is ignored.

  1. Ignore \u{feff} if present
  2. Ignore ---\n or ignore all bytes until\n\n---\n,
  3. followed by header bytes,
  4. optionally followed by \n,
  5. followed by \n---\n or \n...\n,
  6. optionally followed by some \t and/or some ,
  7. optionally followed by \n. The remaining bytes are the “body”.

Alternatively, a YAML metadata block may occur anywhere in the document, but if it is not at the beginning, it must be preceded by a blank line:

  1. skip all text (BEFORE_HEADER_MAX_IGNORED_CHARS) until you find "\n\n---"
  2. followed by header bytes,
  3. same as above …

Implementors