use crate::config::CFG;
use crate::error::NoteError;
use crate::error::WorkflowError;
use crate::file_editor::launch_editor;
use crate::filename;
use crate::filename::MarkupLanguage;
use crate::note::Note;
use crate::note::TMPL_VAR_FM_;
use crate::note::TMPL_VAR_FM_FILENAME_SYNC;
use crate::note::TMPL_VAR_FM_NO_FILENAME_SYNC;
use crate::settings::ARGS;
use crate::settings::CLIPBOARD;
use crate::settings::LAUNCH_EDITOR;
use crate::settings::LAUNCH_VIEWER;
use crate::settings::STDIN;
#[cfg(feature = "viewer")]
use crate::viewer::launch_viewer_thread;
use std::env;
use std::fs;
#[cfg(not(target_family = "windows"))]
use std::matches;
use std::path::Path;
use std::path::PathBuf;
#[cfg(feature = "viewer")]
use std::thread;
#[cfg(feature = "viewer")]
use std::time::Duration;
use tera::Value;
fn synchronize_filename(path: &Path) -> Result<PathBuf, WorkflowError> {
let mut n = Note::from_existing_note(path)?;
let no_filename_sync = match (
n.context.get(TMPL_VAR_FM_FILENAME_SYNC),
n.context.get(TMPL_VAR_FM_NO_FILENAME_SYNC),
) {
(None, None) => false,
(None, Some(Value::Bool(nsync))) => *nsync,
(None, Some(_)) => true,
(Some(Value::Bool(sync)), None) => !*sync,
_ => false,
};
if no_filename_sync {
log::trace!(
"Filename synchronisation disabled with the front matter field: `{}: {}`",
TMPL_VAR_FM_FILENAME_SYNC.trim_start_matches(TMPL_VAR_FM_),
!no_filename_sync
);
}
if ARGS.no_filename_sync {
log::trace!("Filename synchronisation disabled with the flag: `--no-filename-sync`",);
}
if CFG.arg_default.no_filename_sync {
log::trace!(
"Filename synchronisation disabled with the configuration file \
variable: `[arg_default] no_filename_sync = true`",
);
}
let new_file_path =
if !no_filename_sync && !CFG.arg_default.no_filename_sync && !ARGS.no_filename_sync {
log::trace!("Applying template `[tmpl] sync_filename`.");
let new_file_path = n.render_filename(&CFG.tmpl.sync_filename).map_err(|e| {
WorkflowError::Template {
tmpl_name: "[tmpl] sync_filename".to_string(),
source: e,
}
})?;
if !filename::exclude_copy_counter_eq(path, &new_file_path) {
let new_file_path = filename::find_unused(new_file_path)?;
fs::rename(&path, &new_file_path)?;
log::trace!("File renamed to {:?}", new_file_path);
new_file_path
} else {
path.to_path_buf()
}
} else {
path.to_path_buf()
};
if let Some(dir) = &ARGS.export {
n.render_and_write_content(&new_file_path, &CFG.exporter.rendition_tmpl, dir)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[exporter] rendition_tmpl".to_string(),
source: e,
})?;
}
Ok(new_file_path)
}
#[inline]
fn create_new_note_or_synchronize_filename(path: &Path) -> Result<PathBuf, WorkflowError> {
if path.is_dir() {
if ARGS.export.is_some() {
return Err(WorkflowError::ExportNeedsNoteFile);
};
let (n, new_file_path) = if STDIN.is_empty() && CLIPBOARD.is_empty() {
log::trace!("Applying templates `[tmpl] new_content` and `[tmpl] new_filename`.");
let n = Note::from_content_template(path, &CFG.tmpl.new_content).map_err(|e| {
WorkflowError::Template {
tmpl_name: "[tmpl] new_content".to_string(),
source: e,
}
})?;
let new_file_path =
n.render_filename(&CFG.tmpl.new_filename)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[tmpl] new_filename".to_string(),
source: e,
})?;
(n, new_file_path)
} else if !STDIN.borrow_dependent().header.is_empty()
|| !CLIPBOARD.borrow_dependent().header.is_empty()
{
log::trace!("Applying templates: `[tmpl] from_clipboard_yaml_content`, `[tmpl] from_clipboard_yaml_filename`");
let n = Note::from_content_template(path, &CFG.tmpl.from_clipboard_yaml_content)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[tmpl] from_clipboard_yaml_content".to_string(),
source: e,
})?;
let new_file_path = n
.render_filename(&CFG.tmpl.from_clipboard_yaml_filename)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[tmpl] from_clipboard_yaml_filename".to_string(),
source: e,
})?;
(n, new_file_path)
} else {
log::trace!(
"Applying templates: `[tmpl] from_clipboard_content`, `[tmpl] from_clipboard_filename`"
);
let n = Note::from_content_template(path, &CFG.tmpl.from_clipboard_content).map_err(
|e| WorkflowError::Template {
tmpl_name: "[tmpl] from_clipboard_content".to_string(),
source: e,
},
)?;
let new_file_path = n
.render_filename(&CFG.tmpl.from_clipboard_filename)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[tmpl] from_clipboard_filename".to_string(),
source: e,
})?;
(n, new_file_path)
};
let new_file_path = filename::find_unused(new_file_path)?;
n.content.write_to_disk(&new_file_path)?;
Ok(new_file_path)
} else {
let extension_is_known = !matches!(
MarkupLanguage::from(
path.extension()
.unwrap_or_default()
.to_str()
.unwrap_or_default()
),
MarkupLanguage::None
);
if extension_is_known {
match (
synchronize_filename(path),
(ARGS.add_header || CFG.arg_default.add_header)
&& !CFG.arg_default.no_filename_sync
&& !ARGS.no_filename_sync,
) {
(Ok(path), _) => Ok(path),
(
Err(WorkflowError::Note {
source: NoteError::MissingFrontMatter { .. },
}),
true,
) => {
log::trace!(
"Applying template: `[tmpl] from_text_file_content`, `[tmpl] from_text_file_filename`"
);
let n = Note::from_text_file(path, &CFG.tmpl.from_text_file_content)?;
let new_file_path = n
.render_filename(&CFG.tmpl.from_text_file_filename)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[tmpl] from_text_file_filename".to_string(),
source: e,
})?;
n.content.write_to_disk(&*new_file_path)?;
if path != new_file_path {
log::trace!("Deleting file: {:?}", path);
fs::remove_file(path)?;
}
Ok(new_file_path)
}
(Err(e), _) => Err(e),
}
} else {
if ARGS.export.is_some() {
return Err(WorkflowError::ExportNeedsNoteFile);
};
log::trace!(
"Applying templates `[tmpl] annotate_file_content` and `[tmpl] annotate_file_filename`."
);
let n = Note::from_content_template(path, &CFG.tmpl.annotate_file_content).map_err(
|e| WorkflowError::Template {
tmpl_name: "[tmpl] annotate_file_content".to_string(),
source: e,
},
)?;
let new_file_path = n
.render_filename(&CFG.tmpl.annotate_file_filename)
.map_err(|e| WorkflowError::Template {
tmpl_name: "[tmpl] annotate_file_filename".to_string(),
source: e,
})?;
let new_file_path = filename::find_unused(new_file_path)?;
n.content.write_to_disk(&new_file_path)?;
Ok(new_file_path)
}
}
}
#[inline]
pub fn run() -> Result<PathBuf, WorkflowError> {
let mut path = if let Some(p) = &ARGS.path {
p.canonicalize()?
} else {
env::current_dir()?
};
let launch_viewer;
match create_new_note_or_synchronize_filename(&path) {
Ok(p) => {
path = p;
#[cfg(feature = "viewer")]
{
launch_viewer = *LAUNCH_VIEWER;
}
}
Err(WorkflowError::Note { source: e }) => {
if (matches!(e, NoteError::InvalidFrontMatterYaml { .. })
|| matches!(e, NoteError::MissingFrontMatter { .. })
|| matches!(e, NoteError::MissingFrontMatterField { .. })
|| matches!(e, NoteError::CompulsoryFrontMatterFieldIsEmpty { .. })
|| matches!(e, NoteError::SortTagVarInvalidChar { .. })
|| matches!(e, NoteError::FileExtNotRegistered { .. }))
&& !ARGS.batch
&& ARGS.export.is_none()
{
let missing_header = matches!(e, NoteError::MissingFrontMatter { .. })
|| matches!(e, NoteError::MissingFrontMatterField { .. });
launch_viewer = *LAUNCH_VIEWER
&& !(missing_header
&& CFG.viewer.missing_header_disables
&& !CFG.arg_default.add_header
&& !ARGS.add_header
&& !ARGS.view);
if launch_viewer || missing_header {
log::warn!("{}", e,);
} else {
log::error!("{}", e,);
};
} else {
return Err(WorkflowError::Note { source: e });
}
}
Err(e) => return Err(e),
};
#[cfg(feature = "viewer")]
let viewer_join_handle = if launch_viewer {
Some(launch_viewer_thread(&path))
} else {
None
};
if *LAUNCH_EDITOR {
#[cfg(feature = "viewer")]
if viewer_join_handle.is_some() && CFG.viewer.startup_delay < 0 {
thread::sleep(Duration::from_millis(CFG.viewer.startup_delay.abs() as u64));
};
launch_editor(&path)?;
};
if *LAUNCH_EDITOR {
match synchronize_filename(&path) {
Ok(p) => path = p,
Err(e) => {
let missing_header = matches!(
e,
WorkflowError::Note {
source: NoteError::MissingFrontMatter { .. }
}
) || matches!(
e,
WorkflowError::Note {
source: NoteError::MissingFrontMatterField { .. }
}
);
if missing_header {
log::warn!("{}", e);
} else {
return Err(e);
}
}
};
} else {
#[cfg(feature = "viewer")]
if let Some(jh) = viewer_join_handle {
let _ = jh.join();
};
};
Ok(path)
}