Skip to content

Commit 131576d

Browse files
committed
Add init command
1 parent b94b6d8 commit 131576d

File tree

10 files changed

+190
-20
lines changed

10 files changed

+190
-20
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ build = "build.rs"
1616
[dependencies]
1717
ansi_term = "0.11.0"
1818
anyhow = "1.0.31"
19-
casual = "0.1.1"
19+
casual = "0.1.2"
2020
fs2 = "0.4.3"
2121
git2 = "0.13.6"
2222
glob = "0.3.0"

src/cli.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use structopt::{
1010
use url::Url;
1111

1212
use crate::{
13-
config::{GistRepository, GitHubRepository, GitProtocol, GitReference, RawPlugin},
13+
config::{GistRepository, GitHubRepository, GitProtocol, GitReference, RawPlugin, Shell},
1414
context::Settings,
1515
edit::Plugin,
1616
log::{Output, Verbosity},
@@ -93,6 +93,14 @@ struct Add {
9393

9494
#[derive(Debug, PartialEq, StructOpt)]
9595
enum RawCommand {
96+
/// Initialize a new config file.
97+
#[structopt(help_message = HELP_MESSAGE)]
98+
Init {
99+
/// The type of shell, accepted values are: bash, zsh.
100+
#[structopt(long, value_name = "SHELL")]
101+
shell: Option<Shell>,
102+
},
103+
96104
/// Add a new plugin to the config file.
97105
#[structopt(help_message = HELP_MESSAGE)]
98106
Add(Box<Add>),
@@ -182,6 +190,8 @@ struct RawOpt {
182190
/// The resolved command.
183191
#[derive(Debug)]
184192
pub enum Command {
193+
/// Initialize a new config file.
194+
Init { shell: Option<Shell> },
185195
/// Add a new plugin to the config file.
186196
Add { name: String, plugin: Box<Plugin> },
187197
/// Open up the config file in the default editor.
@@ -310,6 +320,7 @@ impl Opt {
310320
};
311321

312322
let command = match command {
323+
RawCommand::Init { shell } => Command::Init { shell },
313324
RawCommand::Add(add) => {
314325
let (name, plugin) = Plugin::from_add(*add);
315326
Command::Add {
@@ -413,6 +424,7 @@ OPTIONS:
413424
SHELDON_DOWNLOAD_DIR=]
414425
415426
SUBCOMMANDS:
427+
init Initialize a new config file
416428
add Add a new plugin to the config file
417429
edit Open up the config file in the default editor
418430
remove Remove a plugin from the config file
@@ -507,6 +519,42 @@ For more information try --help",
507519
assert_eq!(err.info, None);
508520
}
509521

522+
#[test]
523+
fn raw_opt_init_help() {
524+
setup();
525+
let err = raw_opt_err(&["init", "--help"]);
526+
assert_eq!(
527+
err.message,
528+
format!(
529+
"\
530+
{name}-init {version}
531+
Initialize a new config file
532+
533+
USAGE:
534+
sheldon init [OPTIONS]
535+
536+
FLAGS:
537+
-h, --help Show this message and exit
538+
539+
OPTIONS:
540+
--shell <SHELL> The type of shell, accepted values are: bash, zsh",
541+
name = crate_name!(),
542+
version = crate_version!()
543+
)
544+
);
545+
assert_eq!(err.kind, structopt::clap::ErrorKind::HelpDisplayed);
546+
assert_eq!(err.info, None);
547+
}
548+
549+
#[test]
550+
fn raw_opt_init_with_invalid_shell() {
551+
setup();
552+
assert_eq!(
553+
raw_opt_err(&["init", "--shell", "ksh",]).kind,
554+
structopt::clap::ErrorKind::ValueValidation
555+
);
556+
}
557+
510558
#[test]
511559
fn raw_opt_add_help() {
512560
setup();

src/config.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ const GITHUB_HOST: &str = "github.com";
2828
// Configuration definitions
2929
/////////////////////////////////////////////////////////////////////////
3030

31+
/// The type of shell that we are using.
32+
#[derive(Debug, Clone, Copy, PartialEq)]
33+
pub enum Shell {
34+
Bash,
35+
Zsh,
36+
}
37+
3138
/// A wrapper around a template string.
3239
#[derive(Clone, Debug, PartialEq, Serialize)]
3340
pub struct Template {
@@ -194,6 +201,16 @@ pub struct Config {
194201
// Serialization implementations
195202
/////////////////////////////////////////////////////////////////////////
196203

204+
impl fmt::Display for Shell {
205+
/// Displays a `Shell`.
206+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207+
match self {
208+
Self::Bash => f.write_str("bash"),
209+
Self::Zsh => f.write_str("zsh"),
210+
}
211+
}
212+
}
213+
197214
impl fmt::Display for GitProtocol {
198215
/// Displays a `GitProtocol`.
199216
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -249,6 +266,33 @@ impl_serialize_as_str!(GitHubRepository);
249266
// Deserialization implementations
250267
/////////////////////////////////////////////////////////////////////////
251268

269+
impl Default for Shell {
270+
fn default() -> Self {
271+
Self::Zsh
272+
}
273+
}
274+
275+
#[derive(Debug)]
276+
pub struct ParseShellError;
277+
278+
impl fmt::Display for ParseShellError {
279+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280+
f.write_str("expected one of `bash` or `zsh`")
281+
}
282+
}
283+
284+
impl str::FromStr for Shell {
285+
type Err = ParseShellError;
286+
287+
fn from_str(s: &str) -> result::Result<Self, Self::Err> {
288+
match &*s.to_lowercase() {
289+
"bash" => Ok(Self::Bash),
290+
"zsh" => Ok(Self::Zsh),
291+
_ => Err(ParseShellError),
292+
}
293+
}
294+
}
295+
252296
/// A visitor to deserialize a `Template` from a string or a struct.
253297
struct TemplateVisitor;
254298

src/configs/bash.plugins.toml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# `sheldon` configuration file
2+
# ----------------------------
3+
#
4+
# You can modify this file directly or you can use one of the following
5+
# `sheldon` commands which are provided to assist in editing the config file:
6+
#
7+
# - `sheldon add` to add a new plugin to the config file
8+
# - `sheldon edit` to open up the config file in the default editor
9+
# - `sheldon remove` to remove a plugin from the config file
10+
#
11+
# See the documentation for more https://github.com/rossmacarthur/sheldon#readme
12+
13+
# This config field is overridden to use Bash relevant file matches.
14+
match = [
15+
"{{ name }}.plugin.bash",
16+
"{{ name }}.plugin.sh",
17+
"{{ name }}.bash",
18+
"{{ name }}.sh",
19+
"*.plugin.bash",
20+
"*.plugin.sh",
21+
"*.bash",
22+
"*.sh",
23+
]
24+
25+
[plugins]
26+
27+
# For example:
28+
#
29+
# [plugins.base16]
30+
# github = "chriskempson/base16-shell"
File renamed without changes.

src/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
44

55
use serde::{Deserialize, Serialize};
66

7-
use crate::{log::Output, util::PathExt};
7+
use crate::{config::Shell, log::Output, util::PathExt};
88

99
/// Settings to use over the entire program.
1010
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
@@ -34,13 +34,15 @@ pub struct Context<'a> {
3434
pub output: &'a Output,
3535
}
3636

37-
/// Contextual information to use while running edit tasks (add, remove).
37+
/// Contextual information to use while running edit tasks (init, add, remove).
3838
#[derive(Debug)]
3939
pub struct EditContext {
4040
/// Common data.
4141
pub settings: Settings,
4242
/// The output style.
4343
pub output: Output,
44+
/// The type of shell.
45+
pub shell: Option<Shell>,
4446
}
4547

4648
/// Contextual information to use while running the main tasks (lock and

src/edit.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{fmt, fs, path::Path};
44

55
use anyhow::{bail, Context as ResultExt, Result};
66

7-
use crate::config::RawPlugin;
7+
use crate::config::{RawPlugin, Shell};
88

99
/// An editable plugin.
1010
#[derive(Debug)]
@@ -25,19 +25,20 @@ impl From<RawPlugin> for Plugin {
2525
}
2626
}
2727

28-
impl Default for Config {
29-
fn default() -> Self {
30-
Self::from_str(include_str!("plugins.toml")).unwrap()
31-
}
32-
}
33-
3428
impl fmt::Display for Config {
3529
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3630
write!(f, "{}", self.doc)
3731
}
3832
}
3933

4034
impl Config {
35+
pub fn default(shell: Shell) -> Self {
36+
match shell {
37+
Shell::Bash => Self::from_str(include_str!("configs/bash.plugins.toml")).unwrap(),
38+
Shell::Zsh => Self::from_str(include_str!("configs/zsh.plugins.toml")).unwrap(),
39+
}
40+
}
41+
4142
/// Read a `Config` from the given string.
4243
pub fn from_str<S>(s: S) -> Result<Self>
4344
where

src/lib.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use anyhow::{bail, Context as ResultExt, Error, Result};
2929

3030
use crate::{
3131
cli::{Command, Opt},
32-
config::Config,
32+
config::{Config, Shell},
3333
context::{Context, EditContext, LockContext, SettingsExt},
3434
edit::Plugin,
3535
lock::LockedConfig,
@@ -51,18 +51,43 @@ impl Sheldon {
5151
)) {
5252
bail!("aborted initialization!");
5353
};
54+
55+
let shell = ctx.shell.unwrap_or_else(|| {
56+
casual::prompt("Are you using sheldon with Bash or Zsh? [default: zsh] ")
57+
.default(Shell::default())
58+
.get()
59+
});
60+
5461
if let Some(parent) = path.parent() {
5562
fs::create_dir_all(parent).with_context(s!(
5663
"failed to create directory `{}`",
5764
&ctx.replace_home(parent).display()
5865
))?;
5966
}
60-
Ok(edit::Config::default())
67+
Ok(edit::Config::default(shell))
6168
} else {
6269
Err(err)
6370
}
6471
}
6572

73+
// /// Initialize a new config file.
74+
fn init(ctx: &EditContext) -> Result<()> {
75+
let path = ctx.config_file();
76+
match path
77+
.metadata()
78+
.with_context(s!("failed to check `{}`", path.display()))
79+
{
80+
Ok(_) => {
81+
header!(ctx, "Checked", path);
82+
}
83+
Err(err) => {
84+
Self::init_config(ctx, path, err)?.to_path(path)?;
85+
header!(ctx, "Initialized", path);
86+
}
87+
}
88+
Ok(())
89+
}
90+
6691
/// Adds a new plugin to the config file.
6792
fn add(ctx: &EditContext, name: String, plugin: Plugin) -> Result<()> {
6893
let path = ctx.config_file();
@@ -207,16 +232,36 @@ impl Sheldon {
207232
let mut warnings = Vec::new();
208233

209234
match command {
235+
Command::Init { shell } => {
236+
let ctx = EditContext {
237+
settings,
238+
output,
239+
shell,
240+
};
241+
Self::init(&ctx)
242+
}
210243
Command::Add { name, plugin } => {
211-
let ctx = EditContext { settings, output };
244+
let ctx = EditContext {
245+
settings,
246+
output,
247+
shell: None,
248+
};
212249
Self::add(&ctx, name, *plugin)
213250
}
214251
Command::Edit => {
215-
let ctx = EditContext { settings, output };
252+
let ctx = EditContext {
253+
settings,
254+
output,
255+
shell: None,
256+
};
216257
Self::edit(&ctx)
217258
}
218259
Command::Remove { name } => {
219-
let ctx = EditContext { settings, output };
260+
let ctx = EditContext {
261+
settings,
262+
output,
263+
shell: None,
264+
};
220265
Self::remove(&ctx, name)
221266
}
222267
Command::Lock { reinstall } => {

src/lock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{
3131
const MAX_THREADS: u32 = 8;
3232

3333
lazy_static! {
34-
/// The default files to match on.
34+
/// The default files to match on (for Zsh)
3535
pub static ref DEFAULT_MATCHES: Vec<String> = vec_into![
3636
"{{ name }}.plugin.zsh",
3737
"{{ name }}.zsh",

0 commit comments

Comments
 (0)