Browse Source

Merge pull request #106 from Keats/init-ux

Improve gutenberg init
index-subcmd
Vincent Prouillet GitHub 7 years ago
parent
commit
45d366dee3
12 changed files with 109 additions and 18 deletions
  1. +2
    -0
      CHANGELOG.md
  2. +1
    -0
      Cargo.lock
  3. +3
    -0
      Cargo.toml
  4. +5
    -5
      components/config/src/lib.rs
  5. +0
    -0
      components/templates/src/builtins/index.html
  6. +0
    -0
      components/templates/src/builtins/page.html
  7. +0
    -0
      components/templates/src/builtins/section.html
  8. +6
    -0
      components/templates/src/lib.rs
  9. +1
    -1
      src/cli.rs
  10. +35
    -11
      src/cmd/init.rs
  11. +3
    -1
      src/main.rs
  12. +53
    -0
      src/prompt.rs

+ 2
- 0
CHANGELOG.md View File

@@ -4,6 +4,8 @@


- Add `redirect_to` to section front matter to redirect when landing on section - Add `redirect_to` to section front matter to redirect when landing on section
root page root page
- Make `title` in config optional
- Improved `gutenberg init` UX and users first experience


## 0.1.1 (2017-07-16) ## 0.1.1 (2017-07-16)




+ 1
- 0
Cargo.lock View File

@@ -400,6 +400,7 @@ dependencies = [
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"utils 0.1.0", "utils 0.1.0",
"ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]


+ 3
- 0
Cargo.toml View File

@@ -22,6 +22,9 @@ chrono = "0.4"
toml = "0.4" toml = "0.4"
term-painter = "0.2" term-painter = "0.2"


# Used in init to ensure the url given as base_url is a valid one
url = "1.5"

# Below is for the serve cmd # Below is for the serve cmd
staticfile = "0.4" staticfile = "0.4"
iron = "0.5" iron = "0.5"


+ 5
- 5
components/config/src/lib.rs View File

@@ -18,11 +18,11 @@ use rendering::highlighting::THEME_SET;


#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Config { pub struct Config {
/// Title of the site
pub title: String,
/// Base URL of the site
/// Base URL of the site, the only required config argument
pub base_url: String, pub base_url: String,


/// Title of the site. Defaults to None
pub title: Option<String>,
/// Whether to highlight all code blocks found in markdown files. Defaults to false /// Whether to highlight all code blocks found in markdown files. Defaults to false
pub highlight_code: Option<bool>, pub highlight_code: Option<bool>,
/// Which themes to use for code highlighting. See Readme for supported themes /// Which themes to use for code highlighting. See Readme for supported themes
@@ -123,7 +123,7 @@ impl Config {
impl Default for Config { impl Default for Config {
fn default() -> Config { fn default() -> Config {
Config { Config {
title: "".to_string(),
title: Some("".to_string()),
base_url: "http://a-website.com/".to_string(), base_url: "http://a-website.com/".to_string(),
highlight_code: Some(true), highlight_code: Some(true),
highlight_theme: Some("base16-ocean-dark".to_string()), highlight_theme: Some("base16-ocean-dark".to_string()),
@@ -167,7 +167,7 @@ base_url = "https://replace-this-with-your-url.com"
"#; "#;


let config = Config::parse(config).unwrap(); let config = Config::parse(config).unwrap();
assert_eq!(config.title, "My site".to_string());
assert_eq!(config.title.unwrap(), "My site".to_string());
} }


#[test] #[test]


+ 0
- 0
components/templates/src/builtins/index.html View File


+ 0
- 0
components/templates/src/builtins/page.html View File


+ 0
- 0
components/templates/src/builtins/section.html View File


+ 6
- 0
components/templates/src/lib.rs View File

@@ -20,6 +20,12 @@ lazy_static! {
pub static ref GUTENBERG_TERA: Tera = { pub static ref GUTENBERG_TERA: Tera = {
let mut tera = Tera::default(); let mut tera = Tera::default();
tera.add_raw_templates(vec![ tera.add_raw_templates(vec![
// adding default built-ins templates for index/page/section so
// users don't get an error when they run gutenberg after init
("index.html", include_str!("builtins/index.html")),
("page.html", include_str!("builtins/page.html")),
("section.html", include_str!("builtins/section.html")),

("rss.xml", include_str!("builtins/rss.xml")), ("rss.xml", include_str!("builtins/rss.xml")),
("sitemap.xml", include_str!("builtins/sitemap.xml")), ("sitemap.xml", include_str!("builtins/sitemap.xml")),
("robots.txt", include_str!("builtins/robots.txt")), ("robots.txt", include_str!("builtins/robots.txt")),


+ 1
- 1
src/cli.rs View File

@@ -10,7 +10,7 @@ pub fn build_cli() -> App<'static, 'static> {
(@arg config: -c --config +takes_value "Path to a config file other than config.toml") (@arg config: -c --config +takes_value "Path to a config file other than config.toml")
(@subcommand init => (@subcommand init =>
(about: "Create a new Gutenberg project") (about: "Create a new Gutenberg project")
(@arg name: +required "Name of the project. Will create a directory with that name in the current directory")
(@arg name: +required "Name of the project. Will create a new directory with that name in the current directory")
) )
(@subcommand build => (@subcommand build =>
(about: "Builds the site") (about: "Builds the site")


+ 35
- 11
src/cmd/init.rs View File

@@ -1,14 +1,23 @@
use std::fs::create_dir;
use std::fs::{create_dir, canonicalize};
use std::path::Path; use std::path::Path;


use errors::Result; use errors::Result;
use utils::fs::create_file; use utils::fs::create_file;


use prompt::{ask_bool, ask_url};
use console;



const CONFIG: &'static str = r#" const CONFIG: &'static str = r#"
title = "My site"
# replace the url below with yours
base_url = "https://example.com"
# The URL the site will be built for
base_url = "%BASE_URL%"

# Whether to automatically compile all Sass files in the sass directory
compile_sass = %COMPILE_SASS%

# Whether to do syntax highlighting
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Gutenberg
highlight_code = %HIGHLIGHT%


[extra] [extra]
# Put all your custom variables here # Put all your custom variables here
@@ -17,23 +26,38 @@ base_url = "https://example.com"


pub fn create_new_project(name: &str) -> Result<()> { pub fn create_new_project(name: &str) -> Result<()> {
let path = Path::new(name); let path = Path::new(name);

// Better error message than the rust default // Better error message than the rust default
if path.exists() && path.is_dir() { if path.exists() && path.is_dir() {
bail!("Folder `{}` already exists", path.to_string_lossy().to_string()); bail!("Folder `{}` already exists", path.to_string_lossy().to_string());
} }


// main folder
create_dir(path)?; create_dir(path)?;
create_file(&path.join("config.toml"), CONFIG.trim_left())?;
console::info("Welcome to Gutenberg!");


// content folder
create_dir(path.join("content"))?;
let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;


// layouts folder
create_dir(path.join("templates"))?;
let config = CONFIG
.trim_left()
.replace("%BASE_URL%", &base_url)
.replace("%COMPILE_SASS%", &format!("{}", compile_sass))
.replace("%HIGHLIGHT%", &format!("{}", highlight));

create_file(&path.join("config.toml"), &config)?;


create_dir(path.join("content"))?;
create_dir(path.join("templates"))?;
create_dir(path.join("static"))?; create_dir(path.join("static"))?;
if compile_sass {
create_dir(path.join("sass"))?;
}


println!();
console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
println!();
console::info("Get started by using the built-in server: `gutenberg serve`");
println!("There is no built-in theme so you will see a white page.");
println!("Visit https://github.com/Keats/gutenberg for the full documentation.");
Ok(()) Ok(())
} }

+ 3
- 1
src/main.rs View File

@@ -6,6 +6,7 @@ extern crate staticfile;
extern crate iron; extern crate iron;
extern crate mount; extern crate mount;
extern crate notify; extern crate notify;
extern crate url;
extern crate ws; extern crate ws;


extern crate site; extern crate site;
@@ -21,6 +22,7 @@ mod cmd;
mod console; mod console;
mod rebuild; mod rebuild;
mod cli; mod cli;
mod prompt;




fn main() { fn main() {
@@ -31,7 +33,7 @@ fn main() {
match matches.subcommand() { match matches.subcommand() {
("init", Some(matches)) => { ("init", Some(matches)) => {
match cmd::create_new_project(matches.value_of("name").unwrap()) { match cmd::create_new_project(matches.value_of("name").unwrap()) {
Ok(()) => console::success("Project created"),
Ok(()) => (),
Err(e) => { Err(e) => {
console::unravel_errors("Failed to create the project", &e); console::unravel_errors("Failed to create the project", &e);
::std::process::exit(1); ::std::process::exit(1);


+ 53
- 0
src/prompt.rs View File

@@ -0,0 +1,53 @@
use std::io::{self, Write, BufRead};

use url::Url;

use errors::Result;

/// Wait for user input and return what they typed
fn read_line() -> Result<String> {
let stdin = io::stdin();
let stdin = stdin.lock();
let mut lines = stdin.lines();
lines
.next()
.and_then(|l| l.ok())
.ok_or("unable to read from stdin for confirmation".into())
}

/// Ask a yes/no question to the user
pub fn ask_bool(question: &str, default: bool) -> Result<bool> {
print!("{} {}: ", question, if default { "[Y/n]" } else { "[y/N]" });
let _ = io::stdout().flush();
let input = read_line()?;

match &*input {
"y" | "Y" | "yes" | "YES" | "true" => Ok(true),
"n" | "N" | "no" | "NO" | "false" => Ok(false),
"" => Ok(default),
_ => {
println!("Invalid choice: '{}'", input);
ask_bool(question, default)
},
}
}

/// Ask a question to the user where they can write a URL
pub fn ask_url(question: &str, default: &str) -> Result<String> {
print!("{} ({}): ", question, default);
let _ = io::stdout().flush();
let input = read_line()?;

match &*input {
"" => Ok(default.to_string()),
_ => {
match Url::parse(&input) {
Ok(_) => Ok(input),
Err(_) => {
println!("Invalid URL: '{}'", input);
ask_url(question, default)
}
}
},
}
}

Loading…
Cancel
Save