Struct tpnote_lib::context::Context
source · pub struct Context {
pub path: PathBuf,
pub dir_path: PathBuf,
pub root_path: PathBuf,
/* private fields */
}Expand description
Tiny wrapper around “Tera context” with some additional information.
Fields§
§path: PathBufFirst positional command line argument.
dir_path: PathBufThe directory (only) path corresponding to the first positional command line argument. The is our working directory and the directory where the note file is (will be) located.
root_path: PathBufContains the root directory of the current note. This is the first
directory, that upwards from dir_path, contains a file named
FILENAME_ROOT_PATH_MARKER. The root directory is used by Tp-Note’s viewer
as base directory
Implementations§
source§impl Context
impl Context
A thin wrapper around tera::Context storing some additional
information.
sourcepub fn from(path: &Path) -> Self
pub fn from(path: &Path) -> Self
Constructor: path is the first positional command line parameter
<path> (see man page). path must point to a directory or
a file.
A copy of path is stored in self.ct as key TMPL_VAR_PATH. It
directory path as key TMPL_VAR_DIR_PATH.
use std::path::Path;
use tpnote_lib::config::TMPL_VAR_DIR_PATH;
use tpnote_lib::config::TMPL_VAR_PATH;
use tpnote_lib::context::Context;
let mut context = Context::from(&Path::new("/path/to/mynote.md"));
assert_eq!(context.path, Path::new("/path/to/mynote.md"));
assert_eq!(context.dir_path, Path::new("/path/to/"));
assert_eq!(&context.get(TMPL_VAR_PATH).unwrap().to_string(),
r#""/path/to/mynote.md""#);
assert_eq!(&context.get(TMPL_VAR_DIR_PATH).unwrap().to_string(),
r#""/path/to""#);Furthermore, the constructor captures Tp-Note’s environment
and stores it as variables in a
context collection. The variables are needed later to populate
a context template and a filename template.
This function add the keys: TMPL_VAR_EXTENSION_DEFAULT, TMPL_VAR_USERNAME and TMPL_VAR_LANG.
use std::path::Path;
use tpnote_lib::context::Context;
use tpnote_lib::config::TMPL_VAR_EXTENSION_DEFAULT; // `extension_default`
use tpnote_lib::config::FILENAME_EXTENSION_DEFAULT; // usually `md`
let mut context = Context::from(&Path::new("/path/to/mynote.md"));
// For most platforms `context.get("extension_default")` is `md`
assert_eq!(&context.get(TMPL_VAR_EXTENSION_DEFAULT).unwrap().to_string(),
&format!("\"{FILENAME_EXTENSION_DEFAULT}\""));Examples found in repository?
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
pub fn synchronize_filename<T: Content>(path: &Path) -> Result<PathBuf, NoteError> {
// Collect input data for templates.
let context = Context::from(path);
let content = <T>::open(path).unwrap_or_default();
let n = synchronize::<T>(context, content)?;
Ok(n.rendered_filename)
}
#[inline]
/// Create a new note by inserting `Tp-Note`'s environment in a template.
/// If the note to be created exists already, append a so called `copy_counter`
/// to the filename and try to save it again. In case this does not succeed either,
/// increment the `copy_counter` until a free filename is found.
/// The returned path points to the (new) note file on disk.
/// Depending on the context, Tp-Note chooses one `TemplateKind` to operate
/// (c.f. `tpnote_lib::template::TemplateKind::from()`).
/// The `tk-filter` allows to overwrite this choice, e.g. you may set
/// `TemplateKind::None` under certain circumstances. This way the caller
/// can inject command line parameters like `--no-filename-sync`.
/// If `html_export = Some((dir, local_link_kind))`, the function renders
/// the note's content into HTML and saves the `.html` file in the
/// directory `dir`. This optional HTML rendition is performed just before
/// returning and does not affect any above described operation.
///
/// Returns the note's new or existing filename in `<Note>.rendered_filename`.
///
///
/// ## Example with `TemplateKind::FromClipboard`
///
/// ```rust
/// use tpnote_lib::content::Content;
/// use tpnote_lib::content::ContentString;
/// use tpnote_lib::workflow::create_new_note_or_synchronize_filename;
/// use std::env::temp_dir;
/// use std::path::PathBuf;
/// use std::fs;
///
/// // Prepare test.
/// let notedir = temp_dir();
///
/// let clipboard = ContentString::from("my clipboard\n".to_string());
/// let stdin = ContentString::from("my stdin\n".to_string());
/// // This is the condition to choose: `TemplateKind::FromClipboard`:
/// assert!(clipboard.header().is_empty() && stdin.header().is_empty());
/// assert!(!clipboard.body().is_empty() || !stdin.body().is_empty());
/// let template_kind_filer = |tk|tk;
///
/// // Start test.
/// // You can plug in your own type (must impl. `Content`).
/// let n = create_new_note_or_synchronize_filename::<ContentString, _>(
/// ¬edir, &clipboard, &stdin, template_kind_filer,
/// &None).unwrap();
/// // Check result.
/// assert!(n.as_os_str().to_str().unwrap()
/// .contains("my stdin-my clipboard--Note"));
/// assert!(n.is_file());
/// let raw_note = fs::read_to_string(n).unwrap();
///
/// #[cfg(not(target_family = "windows"))]
/// assert!(raw_note.starts_with(
/// "\u{feff}---\ntitle: \"my stdin\\nmy clipboard\\n\""));
/// #[cfg(target_family = "windows")]
/// assert!(raw_note.starts_with(
/// "\u{feff}---\r\ntitle: \"my stdin"));
/// ```
pub fn create_new_note_or_synchronize_filename<T, F>(
path: &Path,
clipboard: &T,
stdin: &T,
tk_filter: F,
html_export: &Option<(PathBuf, LocalLinkKind)>,
) -> Result<PathBuf, NoteError>
where
T: Content,
F: Fn(TemplateKind) -> TemplateKind,
{
// First, generate a new note (if it does not exist), then parse its front_matter
// and finally rename the file, if it is not in sync with its front matter.
// Collect input data for templates.
let mut context = Context::from(path);
context.insert_content(TMPL_VAR_CLIPBOARD, TMPL_VAR_CLIPBOARD_HEADER, clipboard)?;
context.insert_content(TMPL_VAR_STDIN, TMPL_VAR_STDIN_HEADER, stdin)?;
// `template_king` will tell us what to do.
let (template_kind, content) = TemplateKind::from::<T>(path, clipboard, stdin);
let template_kind = tk_filter(template_kind);
let n = match template_kind {
TemplateKind::New
| TemplateKind::FromClipboardYaml
| TemplateKind::FromClipboard
| TemplateKind::AnnotateFile => {
// CREATE A NEW NOTE WITH `TMPL_NEW_CONTENT` TEMPLATE
let mut n = Note::from_content_template(context, template_kind)?;
n.render_filename(template_kind)?;
// Check if the filename is not taken already
n.set_next_unused_rendered_filename()?;
n.save()?;
n
}
TemplateKind::FromTextFile => {
let mut n = Note::from_text_file(context, content.unwrap(), template_kind)?;
// Render filename.
n.render_filename(template_kind)?;
// Save new note.
let context_path = n.context.path.clone();
n.set_next_unused_rendered_filename_or(&context_path)?;
n.save_and_delete_from(&context_path)?;
n
}
TemplateKind::SyncFilename => synchronize(context, content.unwrap())?,
TemplateKind::None => Note::from_text_file(context, content.unwrap(), template_kind)?,
};
// Export HTML rendition, if wanted.
if let Some((dir, local_link_kind)) = html_export {
n.export_html(
&LIB_CFG.read().unwrap().tmpl_html.exporter,
dir,
*local_link_kind,
)?;
}
// If no new filename was rendered, return the old one.
let mut n = n;
if n.rendered_filename == PathBuf::new() {
n.rendered_filename = n.context.path.clone();
}
Ok(n.rendered_filename)
}sourcepub fn insert_content(
&mut self,
tmpl_var: &str,
tmpl_var_header: &str,
input: &impl Content
) -> Result<(), NoteError>
pub fn insert_content(
&mut self,
tmpl_var: &str,
tmpl_var_header: &str,
input: &impl Content
) -> Result<(), NoteError>
Inserts clipboard or stdin data into the context. The data may
contain some copied text with or without a YAML header.
The latter usually carries front matter variable.
These are added separately via insert_front_matter().
The input data below is registered with the key name given
by tmpl_var. Typical names are "clipboard" or "stdin".
If the below input contains a valid YAML header, it will
be registered in the context with the key name given by
tmpl_var_header. This string is typically one of
clipboard_header or std_header.
The raw data that will be inserted into the context.
use std::path::Path;
use tpnote_lib::context::Context;
use tpnote_lib::content::Content;
use tpnote_lib::content::ContentString;
let mut context = Context::from(&Path::new("/path/to/mynote.md"));
context.insert_content("clipboard", "clipboard_header",
&ContentString::from(String::from("Data from clipboard.")));
assert_eq!(&context.get("clipboard").unwrap().to_string(),
"\"Data from clipboard.\"");
context.insert_content("stdin", "stdin_header",
&ContentString::from("---\ntitle: \"My Stdin.\"\n---\nbody".to_string()));
assert_eq!(&context.get("stdin").unwrap().to_string(),
r#""body""#);
assert_eq!(&context.get("stdin_header").unwrap().to_string(),
r#""title: \"My Stdin.\"""#);
// "fm_title" is dynamically generated from the header variable "title".
assert_eq!(&context.get("fm_title").unwrap().to_string(),
r#""My Stdin.""#);Examples found in repository?
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
pub fn create_new_note_or_synchronize_filename<T, F>(
path: &Path,
clipboard: &T,
stdin: &T,
tk_filter: F,
html_export: &Option<(PathBuf, LocalLinkKind)>,
) -> Result<PathBuf, NoteError>
where
T: Content,
F: Fn(TemplateKind) -> TemplateKind,
{
// First, generate a new note (if it does not exist), then parse its front_matter
// and finally rename the file, if it is not in sync with its front matter.
// Collect input data for templates.
let mut context = Context::from(path);
context.insert_content(TMPL_VAR_CLIPBOARD, TMPL_VAR_CLIPBOARD_HEADER, clipboard)?;
context.insert_content(TMPL_VAR_STDIN, TMPL_VAR_STDIN_HEADER, stdin)?;
// `template_king` will tell us what to do.
let (template_kind, content) = TemplateKind::from::<T>(path, clipboard, stdin);
let template_kind = tk_filter(template_kind);
let n = match template_kind {
TemplateKind::New
| TemplateKind::FromClipboardYaml
| TemplateKind::FromClipboard
| TemplateKind::AnnotateFile => {
// CREATE A NEW NOTE WITH `TMPL_NEW_CONTENT` TEMPLATE
let mut n = Note::from_content_template(context, template_kind)?;
n.render_filename(template_kind)?;
// Check if the filename is not taken already
n.set_next_unused_rendered_filename()?;
n.save()?;
n
}
TemplateKind::FromTextFile => {
let mut n = Note::from_text_file(context, content.unwrap(), template_kind)?;
// Render filename.
n.render_filename(template_kind)?;
// Save new note.
let context_path = n.context.path.clone();
n.set_next_unused_rendered_filename_or(&context_path)?;
n.save_and_delete_from(&context_path)?;
n
}
TemplateKind::SyncFilename => synchronize(context, content.unwrap())?,
TemplateKind::None => Note::from_text_file(context, content.unwrap(), template_kind)?,
};
// Export HTML rendition, if wanted.
if let Some((dir, local_link_kind)) = html_export {
n.export_html(
&LIB_CFG.read().unwrap().tmpl_html.exporter,
dir,
*local_link_kind,
)?;
}
// If no new filename was rendered, return the old one.
let mut n = n;
if n.rendered_filename == PathBuf::new() {
n.rendered_filename = n.context.path.clone();
}
Ok(n.rendered_filename)
}Methods from Deref<Target = Context>§
sourcepub fn insert<T, S>(&mut self, key: S, val: &T)where
T: Serialize + ?Sized,
S: Into<String>,
pub fn insert<T, S>(&mut self, key: S, val: &T)where
T: Serialize + ?Sized,
S: Into<String>,
Converts the val parameter to Value and insert it into the context.
Panics if the serialization fails.
let mut context = tera::Context::new();
context.insert("number_users", &42);sourcepub fn try_insert<T, S>(&mut self, key: S, val: &T) -> Result<(), Error>where
T: Serialize + ?Sized,
S: Into<String>,
pub fn try_insert<T, S>(&mut self, key: S, val: &T) -> Result<(), Error>where
T: Serialize + ?Sized,
S: Into<String>,
Converts the val parameter to Value and insert it into the context.
Returns an error if the serialization fails.
let mut context = Context::new();
// user is an instance of a struct implementing `Serialize`
if let Err(_) = context.try_insert("number_users", &user) {
// Serialization failed
}sourcepub fn extend(&mut self, source: Context)
pub fn extend(&mut self, source: Context)
Appends the data of the source parameter to self, overwriting existing keys.
The source context will be dropped.
let mut target = Context::new();
target.insert("a", &1);
target.insert("b", &2);
let mut source = Context::new();
source.insert("b", &3);
source.insert("d", &4);
target.extend(source);sourcepub fn remove(&mut self, index: &str) -> Option<Value>
pub fn remove(&mut self, index: &str) -> Option<Value>
Remove a key from the context, returning the value at the key if the key was previously inserted into the context.
sourcepub fn contains_key(&self, index: &str) -> bool
pub fn contains_key(&self, index: &str) -> bool
Checks if a value exists at a specific index.