Skip to content

Commit

Permalink
Support --json-(object|null|false)-value options
Browse files Browse the repository at this point in the history
  • Loading branch information
blahgeek committed Jan 6, 2024
1 parent 4714ca3 commit 187d190
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 21 deletions.
16 changes: 11 additions & 5 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use log::{warn, info};
use anyhow::Result;
use serde_json as json;

use crate::{rpcio, bytecode};
use crate::{rpcio, bytecode::{self, BytecodeOptions}};
use crate::lsp_message::{LspRequest, LspResponse, LspResponseError};

fn process_channel_to_writer(channel_sub: mpsc::Receiver<String>,
Expand Down Expand Up @@ -63,15 +63,16 @@ fn process_client_reader(reader: impl std::io::Read,
}

fn process_server_reader(reader: impl std::io::Read,
channel_pub: mpsc::Sender<String>) -> Result<()> {
channel_pub: mpsc::Sender<String>,
bytecode_options: BytecodeOptions) -> Result<()> {
let mut bufreader = std::io::BufReader::new(reader);
loop {
let msg = rpcio::rpc_read(&mut bufreader)?;
if msg.is_empty() {
break
}
let json_val = json::from_str(&msg)?;
match bytecode::generate_bytecode_repl(&json_val, bytecode::BytecodeOptions::default()) {
match bytecode::generate_bytecode_repl(&json_val, bytecode_options.clone()) {
Ok(bytecode_str) => {
channel_pub.send(bytecode_str)?;
},
Expand All @@ -84,9 +85,14 @@ fn process_server_reader(reader: impl std::io::Read,
Ok(())
}

pub struct AppOptions {
pub bytecode_options: bytecode::BytecodeOptions,
}

pub fn run_app_forever(client_reader: impl std::io::Read + Send + 'static,
client_writer: impl std::io::Write + Send + 'static,
mut server_cmd: std::process::Command) -> Result<std::process::ExitStatus> {
mut server_cmd: std::process::Command,
options: AppOptions) -> Result<std::process::ExitStatus> {
info!("Running server {:?}", server_cmd);
let mut proc = server_cmd
.stdin(std::process::Stdio::piped())
Expand Down Expand Up @@ -117,7 +123,7 @@ pub fn run_app_forever(client_reader: impl std::io::Read + Send + 'static,
let proc_stdout = proc.stdout.take().unwrap();
std::thread::spawn(move || {
info!("Started server->client read thread");
process_server_reader(proc_stdout, s2c_channel_pub).unwrap();
process_server_reader(proc_stdout, s2c_channel_pub, options.bytecode_options).unwrap();
info!("Finished server->client read thread");
});
}
Expand Down
32 changes: 25 additions & 7 deletions src/bytecode.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::BTreeMap;
use std::str::FromStr;

use anyhow::{Result, bail};
use serde_json as json;
Expand All @@ -17,6 +18,22 @@ pub enum LispObject {
Vector(Vec<LispObject>),
}

impl FromStr for LispObject {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self> {
if s == "nil" {
Ok(Self::Nil)
} else if s == "t" {
Ok(Self::T)
} else if s.starts_with(":") {
Ok(Self::Symbol(s[1..].to_string()))
} else {
bail!("Supported LispObject: {}", s)
}
}
}

impl LispObject {
fn to_repl(&self) -> String {
match self {
Expand Down Expand Up @@ -139,26 +156,27 @@ impl Op {
}
}

#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum ObjectType {
Plist,
Hashtable,
Alist,
}

#[derive(Clone)]
pub struct BytecodeOptions {
pub object_type: ObjectType,
// TODO: array_type
pub null_object: LispObject,
pub false_object: LispObject,
pub null_value: LispObject,
pub false_value: LispObject,
}

impl Default for BytecodeOptions {
fn default() -> Self {
Self {
object_type: ObjectType::Plist,
null_object: LispObject::Nil,
false_object: LispObject::Nil,
null_value: LispObject::Nil,
false_value: LispObject::Nil,
}
}
}
Expand Down Expand Up @@ -270,10 +288,10 @@ impl BytecodeCompiler {
fn compile_value(&mut self, value: &json::Value) {
match value {
&json::Value::Null => {
self.compile_constant_op(self.options.null_object.clone());
self.compile_constant_op(self.options.null_value.clone());
},
&json::Value::Bool(false) => {
self.compile_constant_op(self.options.false_object.clone());
self.compile_constant_op(self.options.false_value.clone());
},
&json::Value::Bool(true) => {
self.compile_constant_op(LispObject::T);
Expand Down
41 changes: 33 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,30 @@ use anyhow::{Result, bail};
use clap::Parser;

use emacs_lsp_booster::app;
use emacs_lsp_booster::bytecode;


#[derive(Parser, Default)]
#[derive(Parser)]
#[command(long_about = None, about = None,
arg_required_else_help = true, after_help = "For backward compatibility, `emacs-lsp-booster <SERVER_CMD>...` (without any options) is also supported\n" )]
arg_required_else_help = true, after_help = "For backward compatibility, `emacs-lsp-booster <SERVER_CMD>...` (without any options) is also supported" )]
struct Cli {
#[command(flatten)]
verbose: clap_verbosity_flag::Verbosity,

#[arg(last = true)]
server_cmd: Vec<String>,

#[arg(long, default_value = "plist",
help = "Lisp type used to represent a JSON object. Plist is the most performant one.\nMust match what lsp client expects.\n")]
json_object_type: bytecode::ObjectType,

#[arg(long, default_value = "nil",
help = "Which lisp value is used to represent a JSON null value. Support :SYMBOL or nil.\nMust match what lsp client expects.\n")]
json_null_value: bytecode::LispObject,

#[arg(long, default_value = "nil",
help = "Which lisp value is used to represent a JSON false value. Support :SYMBOL or nil.\nMust match what lsp client expects.\n")]
json_false_value: bytecode::LispObject,
}

fn parse_args<T, S>(args: T) -> Cli
Expand All @@ -21,10 +34,9 @@ where T: IntoIterator<Item=S>,
let args = args.into_iter().map(|x| x.into()).collect::<Vec<String>>();
// backward compatible. support `emacs-lsp-booster server_cmd args...` directly
if args.len() > 1 && !args[1].starts_with('-') && !args.contains(&"--".into()) {
Cli {
server_cmd: args[1..].to_vec(),
..Default::default()
}
let mut fake_args = vec![args[0].clone(), "--".into()];
fake_args.extend_from_slice(&args[1..]);
Cli::parse_from(fake_args)
} else {
Cli::parse_from(args)
}
Expand All @@ -48,7 +60,13 @@ fn main() -> Result<()> {
let mut cmd = std::process::Command::new(&cli.server_cmd[0]);
cmd.args(&cli.server_cmd[1..]);

let exit_status = app::run_app_forever(std::io::stdin(), std::io::stdout(), cmd)?;
let exit_status = app::run_app_forever(std::io::stdin(), std::io::stdout(), cmd, app::AppOptions {
bytecode_options: bytecode::BytecodeOptions {
object_type: cli.json_object_type,
null_value: cli.json_null_value,
false_value: cli.json_false_value,
},
})?;
std::process::exit(exit_status.code().unwrap_or(1))
}

Expand All @@ -60,7 +78,14 @@ fn test_parse_args() {
let cli = parse_args(vec!["emacs-lsp-booster", "--", "server_cmd", "arg1"]);
assert_eq!(cli.server_cmd, vec!["server_cmd", "arg1"]);

let cli = parse_args(vec!["emacs-lsp-booster", "-v", "--", "server_cmd", "arg1"]);
let cli = parse_args(vec!["emacs-lsp-booster", "-v",
"--json-object-type", "hashtable",
"--json-null-value", ":null",
"--json-false-value", ":json-false",
"--", "server_cmd", "arg1"]);
assert_eq!(cli.verbose.log_level_filter(), log::LevelFilter::Warn);
assert_eq!(cli.server_cmd, vec!["server_cmd", "arg1"]);
assert_eq!(cli.json_object_type, bytecode::ObjectType::Hashtable);
assert_eq!(cli.json_null_value, bytecode::LispObject::Symbol("null".into()));
assert_eq!(cli.json_false_value, bytecode::LispObject::Symbol("json-false".into()));
}
4 changes: 3 additions & 1 deletion tests/app_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ fn test_app_with_echo_server() -> Result<()> {
let mut cmd = std::process::Command::new("timeout");
cmd.args(&["1", "cat"]);

let exit_status = app::run_app_forever(input_pair_out, output_file, cmd)?;
let exit_status = app::run_app_forever(input_pair_out, output_file, cmd, app::AppOptions {
bytecode_options: Default::default(),
})?;
assert!(!exit_status.success()); // timeout kill

let output = std::fs::read_to_string(tmpdir.path().join("output.txt"))?;
Expand Down

0 comments on commit 187d190

Please sign in to comment.