Skip to content

Commit 708bd9e

Browse files
committed
Apply templates per plugin not per file
The template now uses a for loop to loop over the files in the plugin. the `each` field is no longer supported in the config file.
1 parent fb28374 commit 708bd9e

65 files changed

Lines changed: 253 additions & 505 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ following.
627627

628628
```toml
629629
[templates]
630-
source = { value = 'source "{{ file }}"', each = true }
630+
source = '{% for file in files %}source "{{ file }}"\n{% endfor %}'
631631
PATH = 'export PATH="{{ dir }}:$PATH"'
632632
path = 'path=( "{{ dir }}" $path )'
633633
fpath = 'fpath=( "{{ dir }}" $fpath )'

docs/src/Configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ following.
236236

237237
```toml
238238
[templates]
239-
source = { value = 'source "{{ file }}"', each = true }
239+
source = '{% for file in files %}source "{{ file }}"\n{% endfor %}'
240240
PATH = 'export PATH="{{ dir }}:$PATH"'
241241
path = 'path=( "{{ dir }}" $path )'
242242
fpath = 'fpath=( "{{ dir }}" $fpath )'

docs/src/Examples.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Then add a template that calls `zsh-defer source` instead of just `source`.
2727

2828
```toml
2929
[templates]
30-
defer = { value = 'zsh-defer source "{{ file }}"', each = true }
30+
defer = '{% for file in files %}zsh-defer source "{{ file }}"\n{% endfor %}'
3131
```
3232

3333
Now any plugin that you want to defer you can apply the `defer` template. For

src/config/edit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ tag = '0.1.0'
230230
apply = ["PATH", "source"]
231231
232232
[templates]
233-
prompt = { value = 'ln -sf "{{ file }}" "{{ data_dir }}/functions/prompt_{{ name }}_setup"', each = true }
233+
prompt = '{% for file in files %}ln -sf "{{ file }}" "{{ data_dir }}/functions/prompt_{{ name }}_setup"{% endfor %}'
234234
235235
# yes this is the pure plugin
236236
[plugins.pure]
@@ -257,7 +257,7 @@ use = ["{{ name }}.zsh"]
257257
apply = ["PATH", "source"]
258258
259259
[templates]
260-
prompt = { value = 'ln -sf "{{ file }}" "{{ data_dir }}/functions/prompt_{{ name }}_setup"', each = true }
260+
prompt = '{% for file in files %}ln -sf "{{ file }}" "{{ data_dir }}/functions/prompt_{{ name }}_setup"{% endfor %}'
261261
262262
# yes this is the pure plugin
263263
[plugins.pure]

src/config/file.rs

Lines changed: 2 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
1414
use thiserror::Error;
1515
use url::Url;
1616

17-
use crate::config::{GitReference, Shell, Template};
17+
use crate::config::{GitReference, Shell};
1818

1919
/// The contents of the configuration file.
2020
#[derive(Debug, Default, Deserialize)]
@@ -28,7 +28,7 @@ pub struct RawConfig {
2828
/// The default list of template names to apply to each matched file.
2929
pub apply: Option<Vec<String>>,
3030
/// A map of name to template string.
31-
pub templates: IndexMap<String, Template>,
31+
pub templates: IndexMap<String, String>,
3232
/// A map of name to plugin.
3333
pub plugins: IndexMap<String, RawPlugin>,
3434
/// Any extra keys,
@@ -195,75 +195,6 @@ impl FromStr for Shell {
195195
}
196196
}
197197

198-
mod template {
199-
use super::*;
200-
201-
struct Visitor;
202-
203-
/// The same as a [`Template`]. It is used to prevent recursion when
204-
/// deserializing.
205-
#[derive(Deserialize)]
206-
struct TemplateAux {
207-
value: String,
208-
each: bool,
209-
}
210-
211-
impl From<TemplateAux> for Template {
212-
fn from(aux: TemplateAux) -> Self {
213-
let TemplateAux { value, each } = aux;
214-
Self { value, each }
215-
}
216-
}
217-
218-
impl From<&str> for Template {
219-
fn from(s: &str) -> Self {
220-
Self {
221-
value: s.to_string(),
222-
each: false,
223-
}
224-
}
225-
}
226-
227-
impl<'de> de::Visitor<'de> for Visitor {
228-
type Value = Template;
229-
230-
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231-
f.write_str("string or map")
232-
}
233-
234-
fn visit_str<E>(self, value: &str) -> result::Result<Self::Value, E>
235-
where
236-
E: de::Error,
237-
{
238-
Ok(From::from(value))
239-
}
240-
241-
fn visit_map<M>(self, visitor: M) -> result::Result<Self::Value, M::Error>
242-
where
243-
M: de::MapAccess<'de>,
244-
{
245-
let aux: TemplateAux =
246-
Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor))?;
247-
Ok(aux.into())
248-
}
249-
}
250-
251-
/// Manually implement `Deserialize` for a `Template`.
252-
///
253-
/// Unfortunately we can not use [the recommended method][string-or-struct],
254-
/// because we are storing `Template`s in a map.
255-
///
256-
/// [string-or-struct](https://serde.rs/string-or-struct.html)
257-
impl<'de> Deserialize<'de> for Template {
258-
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
259-
where
260-
D: Deserializer<'de>,
261-
{
262-
deserializer.deserialize_any(Visitor)
263-
}
264-
}
265-
}
266-
267198
/// Produced when we fail to parse a Git protocol.
268199
#[derive(Debug, Error)]
269200
#[error("expected one of `git`, `https`, or `ssh`, got `{}`", self.0)]
@@ -438,44 +369,6 @@ mod tests {
438369
)
439370
}
440371

441-
#[derive(Debug, Deserialize)]
442-
struct TemplateTest {
443-
t: Template,
444-
}
445-
446-
#[test]
447-
fn template_deserialize_as_str() {
448-
let test: TemplateTest = toml::from_str("t = 'test'").unwrap();
449-
assert_eq!(
450-
test.t,
451-
Template {
452-
value: "test".to_string(),
453-
each: false
454-
}
455-
);
456-
}
457-
458-
#[test]
459-
fn template_deserialize_as_map() {
460-
let test: TemplateTest = toml::from_str("t = { value = 'test', each = true }").unwrap();
461-
assert_eq!(
462-
test.t,
463-
Template {
464-
value: "test".to_string(),
465-
each: true
466-
}
467-
);
468-
}
469-
470-
#[test]
471-
fn template_deserialize_invalid() {
472-
let error = toml::from_str::<TemplateTest>("t = 0").unwrap_err();
473-
assert_eq!(
474-
error.to_string(),
475-
"invalid type: integer `0`, expected string or map for key `t` at line 1 column 5"
476-
);
477-
}
478-
479372
#[derive(Debug, Deserialize)]
480373
struct TestGitReference {
481374
#[serde(flatten)]

src/config/mod.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub struct Config {
3030
/// The default list of template names to apply to each matched file.
3131
pub apply: Option<Vec<String>>,
3232
/// A map of name to template string.
33-
pub templates: IndexMap<String, Template>,
33+
pub templates: IndexMap<String, String>,
3434
/// Each configured plugin.
3535
pub plugins: Vec<Plugin>,
3636
}
@@ -42,15 +42,6 @@ pub enum Shell {
4242
Zsh,
4343
}
4444

45-
/// A wrapper around a template string.
46-
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
47-
pub struct Template {
48-
/// The actual template string.
49-
pub value: String,
50-
/// Whether this template should be applied to each file.
51-
pub each: bool,
52-
}
53-
5445
/// A configured plugin.
5546
#[derive(Debug, PartialEq, Eq)]
5647
pub enum Plugin {

src/config/normalize.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use indexmap::IndexMap;
88
use url::Url;
99

1010
use crate::config::file::{GitProtocol, RawConfig, RawPlugin};
11-
use crate::config::{Config, ExternalPlugin, InlinePlugin, Plugin, Shell, Source, Template};
11+
use crate::config::{Config, ExternalPlugin, InlinePlugin, Plugin, Shell, Source};
1212
use crate::util::TEMPLATE_ENGINE;
1313

1414
/// The Gist domain host.
@@ -35,7 +35,7 @@ pub fn normalize(raw_config: RawConfig, warnings: &mut Vec<Error>) -> Result<Con
3535
// Check that the templates can be compiled.
3636
for (name, template) in &templates {
3737
TEMPLATE_ENGINE
38-
.compile(&template.value)
38+
.compile(template)
3939
.with_context(s!("failed to compile template `{}`", name))?;
4040
}
4141

@@ -70,7 +70,7 @@ fn normalize_plugin(
7070
raw_plugin: RawPlugin,
7171
name: String,
7272
shell: Shell,
73-
templates: &IndexMap<String, Template>,
73+
templates: &IndexMap<String, String>,
7474
warnings: &mut Vec<Error>,
7575
) -> Result<Plugin> {
7676
enum TempSource {
@@ -249,7 +249,7 @@ where
249249
fn validate_template_names(
250250
shell: Shell,
251251
apply: &Option<Vec<String>>,
252-
templates: &IndexMap<String, Template>,
252+
templates: &IndexMap<String, String>,
253253
) -> Result<()> {
254254
if let Some(apply) = apply {
255255
for name in apply {

src/lock/file.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use anyhow::{Context as ResultExt, Error, Result};
77
use indexmap::IndexMap;
88
use serde::{Deserialize, Serialize};
99

10-
use crate::config::{InlinePlugin, Template};
10+
use crate::config::InlinePlugin;
1111
use crate::context::Context;
1212

1313
/// A locked `Config`.
@@ -22,7 +22,7 @@ pub struct LockedConfig {
2222
///
2323
/// Note: this field must come last in the struct for it to serialize
2424
/// properly.
25-
pub templates: IndexMap<String, Template>,
25+
pub templates: IndexMap<String, String>,
2626
/// Any errors that occurred while generating this `LockedConfig`.
2727
#[serde(skip)]
2828
pub errors: Vec<Error>,

src/lock/mod.rs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use itertools::{Either, Itertools};
1212
use once_cell::sync::Lazy;
1313
use rayon::prelude::*;
1414

15-
use crate::config::{Config, MatchesProfile, Plugin, Shell, Template};
15+
use crate::config::{Config, MatchesProfile, Plugin, Shell};
1616
use crate::context::Context;
1717
pub use crate::lock::file::LockedConfig;
1818
use crate::lock::file::{LockedExternalPlugin, LockedPlugin};
@@ -86,8 +86,9 @@ pub fn config(ctx: &Context, config: Config) -> Result<LockedConfig> {
8686
.push((index, plugin));
8787
}
8888

89-
let matches = &matches.as_ref().unwrap_or_else(|| shell.default_matches());
90-
#[allow(clippy::redundant_closure)]
89+
let matches = matches
90+
.as_deref()
91+
.unwrap_or_else(|| shell.default_matches());
9192
let apply = apply.as_ref().unwrap_or_else(|| Shell::default_apply());
9293
let count = map.len();
9394
let mut errors = Vec::new();
@@ -117,9 +118,8 @@ pub fn config(ctx: &Context, config: Config) -> Result<LockedConfig> {
117118
let mut locked = Vec::with_capacity(plugins.len());
118119
for (index, plugin) in plugins {
119120
let name = plugin.name.clone();
120-
let plugin =
121-
plugin::lock(ctx, &templates, source.clone(), matches, apply, plugin)
122-
.with_context(s!("failed to install plugin `{}`", name));
121+
let plugin = plugin::lock(ctx, source.clone(), matches, apply, plugin)
122+
.with_context(s!("failed to install plugin `{}`", name));
123123
locked.push((index, plugin));
124124
}
125125
Ok(locked)
@@ -171,7 +171,7 @@ pub fn config(ctx: &Context, config: Config) -> Result<LockedConfig> {
171171

172172
impl Shell {
173173
/// The default files to match on for this shell.
174-
fn default_matches(&self) -> &Vec<String> {
174+
fn default_matches(&self) -> &[String] {
175175
static DEFAULT_MATCHES_BASH: Lazy<Vec<String>> = Lazy::new(|| {
176176
vec_into![
177177
"{{ name }}.plugin.bash",
@@ -203,19 +203,19 @@ impl Shell {
203203
}
204204

205205
/// The default templates for this shell.
206-
pub fn default_templates(&self) -> &IndexMap<String, Template> {
207-
static DEFAULT_TEMPLATES_BASH: Lazy<IndexMap<String, Template>> = Lazy::new(|| {
206+
pub fn default_templates(&self) -> &IndexMap<String, String> {
207+
static DEFAULT_TEMPLATES_BASH: Lazy<IndexMap<String, String>> = Lazy::new(|| {
208208
indexmap_into! {
209209
"PATH" => "export PATH=\"{{ dir }}:$PATH\"",
210-
"source" => Template::from("source \"{{ file }}\"").each(true)
210+
"source" => "{% for file in files %}source \"{{ file }}\"\n{% endfor %}"
211211
}
212212
});
213-
static DEFAULT_TEMPLATES_ZSH: Lazy<IndexMap<String, Template>> = Lazy::new(|| {
213+
static DEFAULT_TEMPLATES_ZSH: Lazy<IndexMap<String, String>> = Lazy::new(|| {
214214
indexmap_into! {
215215
"PATH" => "export PATH=\"{{ dir }}:$PATH\"",
216216
"path" => "path=( \"{{ dir }}\" $path )",
217217
"fpath" => "fpath=( \"{{ dir }}\" $fpath )",
218-
"source" => Template::from("source \"{{ file }}\"").each(true)
218+
"source" => "{% for file in files %}source \"{{ file }}\"\n{% endfor %}"
219219
}
220220
});
221221
match self {
@@ -231,14 +231,6 @@ impl Shell {
231231
}
232232
}
233233

234-
impl Template {
235-
/// Set whether this template should be applied to every file.
236-
fn each(mut self, each: bool) -> Self {
237-
self.each = each;
238-
self
239-
}
240-
}
241-
242234
impl LockedConfig {
243235
/// Verify that the `LockedConfig` is okay.
244236
pub fn verify(&self, ctx: &Context) -> bool {

0 commit comments

Comments
 (0)