Skip to content

Commit c1d0c3e

Browse files
committed
support optional arguments in ?play
1 parent e4524cf commit c1d0c3e

File tree

2 files changed

+116
-18
lines changed

2 files changed

+116
-18
lines changed

src/main.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,29 @@ fn app() -> Result<()> {
112112

113113
if config.eval {
114114
// rust playground
115-
cmds.add("?play ```\ncode```", playground::run);
116-
cmds.add("?play code...", playground::help);
115+
cmds.add(
116+
"?play mode={} edition={} channel={} ```\ncode```",
117+
playground::run,
118+
);
119+
cmds.add("?play code...", playground::err);
120+
cmds.help(
121+
"?play",
122+
"Compile and run rust code in a playground",
123+
|args| playground::help(args, "play"),
124+
);
117125

118-
cmds.add("?eval ```\ncode```", playground::eval);
119-
cmds.add("?eval `code`", playground::eval);
120-
cmds.add("?eval code...", playground::eval_help);
126+
cmds.add(
127+
"?eval mode={} edition={} channel={} ```\ncode```",
128+
playground::eval,
129+
);
130+
cmds.add(
131+
"?eval mode={} edition={} channel={} `code`",
132+
playground::eval,
133+
);
134+
cmds.add("?eval code...", playground::eval_err);
135+
cmds.help("?eval", "Evaluate a single rust expression", |args| {
136+
playground::help(args, "eval")
137+
});
121138
}
122139

123140
// Slow mode.

src/playground.rs

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@ use crate::{
88
use reqwest::header;
99
use serde::{Deserialize, Serialize};
1010
use std::collections::HashMap;
11+
use std::str::FromStr;
1112

1213
#[derive(Debug, Serialize)]
13-
struct PlaygroundCode {
14+
struct PlaygroundCode<'a> {
1415
channel: Channel,
1516
edition: Edition,
16-
code: String,
17+
code: &'a str,
1718
#[serde(rename = "crateType")]
1819
crate_type: CrateType,
1920
mode: Mode,
2021
tests: bool,
2122
}
2223

23-
impl PlaygroundCode {
24-
fn new(code: String) -> Self {
24+
impl<'a> PlaygroundCode<'a> {
25+
fn new(code: &'a str) -> Self {
2526
PlaygroundCode {
2627
channel: Channel::Nightly,
2728
edition: Edition::E2018,
@@ -64,6 +65,19 @@ enum Channel {
6465
Nightly,
6566
}
6667

68+
impl FromStr for Channel {
69+
type Err = Box<dyn std::error::Error>;
70+
71+
fn from_str(s: &str) -> Result<Self> {
72+
match s {
73+
"stable" => Ok(Channel::Stable),
74+
"beta" => Ok(Channel::Beta),
75+
"nightly" => Ok(Channel::Nightly),
76+
_ => Err(format!("invalid release channel `{}`", s).into()),
77+
}
78+
}
79+
}
80+
6781
#[derive(Debug, Serialize)]
6882
enum Edition {
6983
#[serde(rename = "2015")]
@@ -72,6 +86,18 @@ enum Edition {
7286
E2018,
7387
}
7488

89+
impl FromStr for Edition {
90+
type Err = Box<dyn std::error::Error>;
91+
92+
fn from_str(s: &str) -> Result<Self> {
93+
match s {
94+
"2015" => Ok(Edition::E2015),
95+
"2018" => Ok(Edition::E2018),
96+
_ => Err(format!("invalid edition `{}`", s).into()),
97+
}
98+
}
99+
}
100+
75101
#[derive(Debug, Serialize)]
76102
enum CrateType {
77103
#[serde(rename = "bin")]
@@ -87,6 +113,18 @@ enum Mode {
87113
Release,
88114
}
89115

116+
impl FromStr for Mode {
117+
type Err = Box<dyn std::error::Error>;
118+
119+
fn from_str(s: &str) -> Result<Self> {
120+
match s {
121+
"debug" => Ok(Mode::Debug),
122+
"release" => Ok(Mode::Release),
123+
_ => Err(format!("invalid compilation mode `{}`", s).into()),
124+
}
125+
}
126+
}
127+
90128
#[derive(Debug, Deserialize)]
91129
struct PlayResult {
92130
success: bool,
@@ -95,8 +133,32 @@ struct PlayResult {
95133
}
96134

97135
fn run_code(args: &Args, code: &str) -> Result<String> {
98-
info!("sending request to playground.");
99-
let request = PlaygroundCode::new(code.to_string());
136+
let mut errors = String::new();
137+
138+
let channel = args.params.get("channel").unwrap_or_else(|| &"nightly");
139+
let mode = args.params.get("mode").unwrap_or_else(|| &"debug");
140+
let edition = args.params.get("edition").unwrap_or_else(|| &"2018");
141+
142+
let mut request = PlaygroundCode::new(code);
143+
144+
match Channel::from_str(channel) {
145+
Ok(c) => request.channel = c,
146+
Err(e) => errors += &format!("{}\n", e),
147+
}
148+
149+
match Mode::from_str(mode) {
150+
Ok(m) => request.mode = m,
151+
Err(e) => errors += &format!("{}\n", e),
152+
}
153+
154+
match Edition::from_str(edition) {
155+
Ok(e) => request.edition = e,
156+
Err(e) => errors += &format!("{}\n", e),
157+
}
158+
159+
if !code.contains("fn main") {
160+
request.crate_type = CrateType::Library;
161+
}
100162

101163
let resp = args
102164
.http
@@ -112,13 +174,16 @@ fn run_code(args: &Args, code: &str) -> Result<String> {
112174
result.stderr
113175
};
114176

115-
Ok(if result.len() > 1994 {
177+
Ok(if result.len() + errors.len() > 1994 {
116178
format!(
117-
"Output too large. Playground link: {}",
179+
"{}Output too large. Playground link: {}",
180+
errors,
118181
get_playground_link(args, code, &request)?
119182
)
183+
} else if result.len() == 0 {
184+
format!("{}compilation succeded.", errors)
120185
} else {
121-
format!("```{}```", result)
186+
format!("{}```{}```", errors, result)
122187
})
123188
}
124189

@@ -134,11 +199,11 @@ fn get_playground_link(args: &Args, code: &str, request: &PlaygroundCode) -> Res
134199
.send()?;
135200

136201
let resp: HashMap<String, String> = resp.json()?;
137-
debug!("gist response: {:?}", resp);
202+
info!("gist response: {:?}", resp);
138203

139204
resp.get("id")
140205
.map(|id| request.url_from_gist(id))
141-
.ok_or("no gist found".into())
206+
.ok_or_else(|| "no gist found".into())
142207
}
143208

144209
pub fn run(args: Args) -> Result<()> {
@@ -152,7 +217,23 @@ pub fn run(args: Args) -> Result<()> {
152217
Ok(())
153218
}
154219

155-
pub fn help(args: Args) -> Result<()> {
220+
pub fn help(args: Args, name: &str) -> Result<()> {
221+
let message = format!(
222+
"Compile and run rust code. All code is executed on https://play.rust-lang.org.
223+
```?{} mode={{}} channel={{}} edition={{}} ``\u{200B}`code``\u{200B}` ```
224+
Optional arguments:
225+
\tmode: debug, release (default: debug)
226+
\tchannel: stable, beta, nightly (default: nightly)
227+
\tedition: 2015, 2018 (default: 2018)
228+
",
229+
name
230+
);
231+
232+
api::send_reply(&args, &message)?;
233+
Ok(())
234+
}
235+
236+
pub fn err(args: Args) -> Result<()> {
156237
let message = "Missing code block. Please use the following markdown:
157238
\\`\\`\\`rust
158239
code here
@@ -183,7 +264,7 @@ pub fn eval(args: Args) -> Result<()> {
183264
Ok(())
184265
}
185266

186-
pub fn eval_help(args: Args) -> Result<()> {
267+
pub fn eval_err(args: Args) -> Result<()> {
187268
let message = "Missing code block. Please use the following markdown:
188269
\\`code here\\`
189270
or

0 commit comments

Comments
 (0)