Skip to content

Commit

Permalink
Add repl
Browse files Browse the repository at this point in the history
Running repl from js side.
Add tests for repl behavior.
Handle ctrl-C and ctrl-D.
  • Loading branch information
hayd committed Oct 20, 2018
1 parent 172f7f5 commit 8594073
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 61 deletions.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ ts_sources = [
"js/read_link.ts",
"js/remove.ts",
"js/rename.ts",
"js/repl.ts",
"js/stat.ts",
"js/symlink.ts",
"js/text_encoding.ts",
Expand Down
5 changes: 0 additions & 5 deletions build_extra/rust/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ rust_crate("bitflags") {
source_root = "$registry_github/bitflags-1.0.4/src/lib.rs"
}





rust_crate("unicode_segmentation") {
source_root = "$registry_github/unicode-segmentation-1.2.1/src/lib.rs"
}
Expand All @@ -60,7 +56,6 @@ rust_crate("unicode_width") {
source_root = "$registry_github/unicode-width-0.1.5/src/lib.rs"
}


rust_crate("libc") {
source_root = "$registry_github/libc-0.2.43/src/lib.rs"
features = [ "use_std" ]
Expand Down
18 changes: 8 additions & 10 deletions js/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { libdeno } from "./libdeno";
import { args } from "./deno";
import { sendSync, handleAsyncMsgFromRust } from "./dispatch";
import { promiseErrorExaminer, promiseRejectHandler } from "./promise_util";
import { replLoop } from "./repl";
import { version } from "typescript";

function sendStart(): msg.StartRes {
Expand Down Expand Up @@ -77,23 +78,20 @@ export default function denoMain() {
}
log("args", args);
Object.freeze(args);
console.log('hahahaha')
const inputFn = args[0];
if (!inputFn) {
console.log("not exiting")
console.log("No input script specified.");
// os.exit(1);
}

// handle `--deps`
if (startResMsg.depsFlag()) {
if (inputFn && startResMsg.depsFlag()) {
for (const dep of compiler.getModuleDependencies(inputFn, `${cwd}/`)) {
console.log(dep);
}
os.exit(0);
}

compiler.recompile = startResMsg.recompileFlag();
compiler.run(inputFn, `${cwd}/`);
}

if (inputFn) {
compiler.run(inputFn, `${cwd}/`);
} else {
replLoop();
}
}
62 changes: 62 additions & 0 deletions js/repl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as msg from "gen/msg_generated";
import { flatbuffers } from "flatbuffers";
import { assert } from "./util";
import * as deno from "./deno";
import * as dispatch from "./dispatch";
import { exit } from "./os";
import { window } from "./globals";

// @internal
export async function readline(prompt: string): Promise<string> {
return res(await dispatch.sendAsync(...req(prompt)));
}

function req(
prompt: string
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = new flatbuffers.Builder();
const prompt_ = builder.createString(prompt);
msg.Repl.startRepl(builder);
msg.Repl.addPrompt(builder, prompt_);
const inner = msg.Repl.endRepl(builder);
return [builder, msg.Any.Repl, inner];
}

function res(baseRes: null | msg.Base): string {
assert(baseRes != null);
assert(msg.Any.ReplRes === baseRes!.innerType());
const inner = new msg.ReplRes();
assert(baseRes!.inner(inner) != null);
const line = inner.line();
assert(line !== null);
return line || "";
}

// @internal
export async function replLoop(): Promise<void> {
window.deno = deno; // FIXME use a new scope (rather than window).
let line = "";
while(true){
try {
line = await readline(">> ");
line = line.trim();
} catch(err) {
if (err.message === "EOF") { break; }
console.error(err);
exit(1);
}
if (!line) { continue; }
if (line === ".exit") { break; }
try {
const result = eval.call(window, line); // FIXME use a new scope.
console.log(result);
} catch (err) {
if (err instanceof Error) {
console.error(`${err.constructor.name}: ${err.message}`);
} else {
console.error("Thrown:", err);
}
}
}
}
1 change: 1 addition & 0 deletions js/unit_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// But it can also be run manually: ./out/debug/deno js/unit_tests.ts
import "./compiler_test.ts";
import "./console_test.ts";
import "./repl_test.ts";
import "./fetch_test.ts";
import "./os_test.ts";
import "./files_test.ts";
Expand Down
47 changes: 2 additions & 45 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
extern crate flatbuffers;
#[macro_use]
extern crate futures;
// extern crate rustyline;
extern crate hyper;
extern crate libc;
extern crate msg_rs as msg;
extern crate rustyline;
extern crate rand;
extern crate rustyline;
extern crate tempfile;
extern crate tokio;
extern crate tokio_executor;
Expand All @@ -24,10 +23,6 @@ extern crate hyper_rustls;
extern crate remove_dir_all;
extern crate ring;


use rustyline::error::ReadlineError;
use rustyline::Editor;

mod deno_dir;
mod errors;
mod flags;
Expand All @@ -36,6 +31,7 @@ mod http_util;
mod isolate;
mod libdeno;
pub mod ops;
mod repl;
mod resources;
mod tokio_util;
mod version;
Expand Down Expand Up @@ -88,44 +84,5 @@ fn main() {
std::process::exit(1);
});
isolate.event_loop();
if args2.len() == 1{
repl_loop(isolate)
}
});
}

#[allow(dead_code)]
fn repl_loop(isolate:Box<isolate::Isolate>) {
// `()` can be used when no completer is required
let mut rl = Editor::<()>::new();
if rl.load_history("history.txt").is_err() {
println!("No previous history.");
}
loop {
let readline = rl.readline(">> ");
match readline {
Ok(line) => {
rl.add_history_entry(line.as_ref());
isolate.execute("deno_main.js", &line)
.unwrap_or_else(|_err| {
// error!("{}", err);
println!("{}","error happened" )
});
// println!("Line: {}", line);
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
rl.save_history("history.txt").unwrap();
}
10 changes: 10 additions & 0 deletions src/msg.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ union Any {
Rename,
Readlink,
ReadlinkRes,
Repl,
ReplRes,
Symlink,
Stat,
StatRes,
Expand Down Expand Up @@ -251,6 +253,14 @@ table ReadlinkRes {
path: string;
}

table Repl {
prompt: string;
}

table ReplRes {
line: string;
}

table Symlink {
oldname: string;
newname: string;
Expand Down
36 changes: 36 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use isolate::Isolate;
use isolate::IsolateState;
use isolate::Op;
use msg;
use repl;
use resources;
use resources::Resource;
use tokio_util;
Expand Down Expand Up @@ -96,6 +97,7 @@ pub fn dispatch(
msg::Any::Read => op_read,
msg::Any::Remove => op_remove,
msg::Any::Rename => op_rename,
msg::Any::Repl => op_repl,
msg::Any::SetEnv => op_set_env,
msg::Any::Shutdown => op_shutdown,
msg::Any::Start => op_start,
Expand Down Expand Up @@ -1082,6 +1084,40 @@ fn op_read_link(
})
}

fn op_repl(
_state: Arc<IsolateState>,
base: &msg::Base,
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
let inner = base.inner_as_repl().unwrap();
let cmd_id = base.cmd_id();
let prompt = inner.prompt().unwrap().to_owned();

blocking!(base.sync(), || -> OpResult {
debug!("op_repl {}", prompt);
let line = repl::readline(&prompt)?;
let builder = &mut FlatBufferBuilder::new();
let line_off = builder.create_string(&line);
let inner = msg::ReplRes::create(
builder,
&msg::ReplResArgs {
line: Some(line_off),
..Default::default()
},
);
Ok(serialize_response(
cmd_id,
builder,
msg::BaseArgs {
inner: Some(inner.as_union_value()),
inner_type: msg::Any::ReplRes,
..Default::default()
},
))
})
}

fn op_truncate(
state: Arc<IsolateState>,
base: &msg::Base,
Expand Down
41 changes: 41 additions & 0 deletions src/repl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
extern crate rustyline;
use rustyline::Editor;
use rustyline::error::ReadlineError::Interrupted;

use std::error::Error;
use msg::ErrorKind;

use errors::DenoResult;
use errors::new as deno_error;
use std::process::exit;

const HISTORY_FILE: &str = "history.txt";

pub fn readline(prompt: &String) -> DenoResult<String> {
// TODO instantiate the editor once only (for the session).
let mut editor = start_repl();
editor
.readline(prompt)
.map(|line| {
editor.add_history_entry(line.as_ref());
// TODO We'd rather save the history only upon close,
// but atm we're instantiating a new editor each readline.
editor.save_history(HISTORY_FILE).unwrap();
line
})
.map_err(|err|
match err {
Interrupted => exit(1),
err => err
})
.map_err(|err| deno_error(ErrorKind::Other, err.description().to_string()))
}

fn start_repl() -> Editor<()> {
let mut editor = Editor::<()>::new();
if editor.load_history(HISTORY_FILE).is_err() {
eprintln!("No repl history found, creating new file: {}", HISTORY_FILE);
}
editor
}
2 changes: 1 addition & 1 deletion third_party
Submodule third_party updated 207 files
Loading

0 comments on commit 8594073

Please sign in to comment.