Plugin repeated (#417)

* not repeated decl in file and help

* implemented heashmap for repeated

* sorted scope commands
This commit is contained in:
Fernando Herrera
2021-12-03 14:29:55 +00:00
committed by GitHub
parent a28d38b05f
commit f3c8d35eb7
11 changed files with 127 additions and 94 deletions

View File

@ -48,7 +48,7 @@ pub trait Command: Send + Sync + CommandClone {
self.name().contains(' ')
}
// Is a plugin command
// Is a plugin command (returns plugin's name if yes)
fn is_plugin(&self) -> Option<&PathBuf> {
None
}

View File

@ -11,6 +11,7 @@ use std::{
#[cfg(feature = "plugin")]
use std::path::PathBuf;
// Tells whether a decl etc. is visible or not
#[derive(Debug, Clone)]
struct Visibility {
@ -197,17 +198,14 @@ impl EngineState {
last.visibility.merge_with(first.visibility);
#[cfg(feature = "plugin")]
if !delta.plugin_decls.is_empty() {
for decl in delta.plugin_decls {
let name = decl.name().as_bytes().to_vec();
self.decls.push_back(decl);
let decl_id = self.decls.len() - 1;
if delta.plugins_changed {
let result = self.update_plugin_file();
last.decls.insert(name, decl_id);
last.visibility.use_decl_id(&decl_id);
if result.is_ok() {
delta.plugins_changed = false;
}
return self.update_plugin_file();
return result;
}
}
@ -230,7 +228,7 @@ impl EngineState {
let file_name = path.to_str().expect("path should be a str");
let line = serde_json::to_string_pretty(&decl.signature())
.map(|signature| format!("register {} {}\n", file_name, signature))
.map(|signature| format!("register {} {}\n\n", file_name, signature))
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
plugin_file
@ -250,6 +248,40 @@ impl EngineState {
}
}
#[cfg(feature = "plugin")]
pub fn update_plugin_file_1(&self) -> Result<(), ShellError> {
use std::io::Write;
// Updating the signatures plugin file with the added signatures
if let Some(plugin_path) = &self.plugin_signatures {
// Always creating the file which will erase previous signatures
let mut plugin_file = std::fs::File::create(plugin_path.as_path())
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
// Plugin definitions with parsed signature
for decl in self.plugin_decls() {
// A successful plugin registration already includes the plugin filename
// No need to check the None option
let path = decl.is_plugin().expect("plugin should have file name");
let file_name = path.to_str().expect("path should be a str");
let line = serde_json::to_string_pretty(&decl.signature())
.map(|signature| format!("register {} {}\n\n", file_name, signature))
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
plugin_file
.write_all(line.as_bytes())
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
}
Ok(())
} else {
Err(ShellError::PluginFailedToLoad(
"Plugin file not found".into(),
))
}
}
pub fn num_files(&self) -> usize {
self.files.len()
}
@ -311,8 +343,21 @@ impl EngineState {
None
}
#[cfg(feature = "plugin")]
pub fn plugin_decls(&self) -> impl Iterator<Item = &Box<dyn Command + 'static>> {
self.decls.iter().filter(|decl| decl.is_plugin().is_some())
let mut unique_plugin_decls = HashMap::new();
// Make sure there are no duplicate decls: Newer one overwrites the older one
for decl in self.decls.iter().filter(|d| d.is_plugin().is_some()) {
unique_plugin_decls.insert(decl.name(), decl);
}
let mut plugin_decls: Vec<(&str, &Box<dyn Command>)> =
unique_plugin_decls.into_iter().collect();
// Sort the plugins by name so we don't end up with a random plugin file each time
plugin_decls.sort_by(|a, b| a.0.cmp(b.0));
plugin_decls.into_iter().map(|(_, decl)| decl)
}
pub fn find_overlay(&self, name: &[u8]) -> Option<OverlayId> {
@ -423,6 +468,8 @@ impl EngineState {
}
output.sort_by(|a, b| a.0.name.cmp(&b.0.name));
output.dedup_by(|a, b| a.0.name.cmp(&b.0.name).is_eq());
output
}
@ -519,9 +566,7 @@ pub struct StateDelta {
overlays: Vec<Overlay>, // indexed by OverlayId
pub scope: Vec<ScopeFrame>,
#[cfg(feature = "plugin")]
pub plugin_signatures: Vec<(PathBuf, Option<Signature>)>,
#[cfg(feature = "plugin")]
plugin_decls: Vec<Box<dyn Command>>,
plugins_changed: bool, // marks whether plugin file should be updated
}
impl StateDelta {
@ -562,9 +607,7 @@ impl<'a> StateWorkingSet<'a> {
overlays: vec![],
scope: vec![ScopeFrame::new()],
#[cfg(feature = "plugin")]
plugin_signatures: vec![],
#[cfg(feature = "plugin")]
plugin_decls: vec![],
plugins_changed: false,
},
permanent_state,
}
@ -633,20 +676,8 @@ impl<'a> StateWorkingSet<'a> {
}
#[cfg(feature = "plugin")]
pub fn add_plugin_decls(&mut self, decls: Vec<Box<dyn Command>>) {
for decl in decls {
self.delta.plugin_decls.push(decl);
}
}
#[cfg(feature = "plugin")]
pub fn add_plugin_signature(&mut self, path: PathBuf, signature: Option<Signature>) {
self.delta.plugin_signatures.push((path, signature));
}
#[cfg(feature = "plugin")]
pub fn get_signatures(&self) -> impl Iterator<Item = &(PathBuf, Option<Signature>)> {
self.delta.plugin_signatures.iter()
pub fn mark_plugins_file_dirty(&mut self) {
self.delta.plugins_changed = true;
}
pub fn merge_predecl(&mut self, name: &[u8]) -> Option<DeclId> {