mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
logging
This commit is contained in:
parent
d7c5a6f308
commit
2e165ae82e
18 changed files with 233 additions and 115 deletions
|
@ -5,7 +5,7 @@ authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [ "tools", "cli", "libeditor", "libanalysis" ]
|
members = [ "tools", "cli", "libeditor", "libanalysis", "codeless/server" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
unicode-xid = "0.1.0"
|
unicode-xid = "0.1.0"
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
use tools::collect_tests;
|
use tools::collect_tests;
|
||||||
use libeditor::File;
|
use libeditor::{ast, syntax_tree, symbols};
|
||||||
|
|
||||||
type Result<T> = ::std::result::Result<T, failure::Error>;
|
type Result<T> = ::std::result::Result<T, failure::Error>;
|
||||||
|
|
||||||
|
@ -44,14 +44,14 @@ fn main() -> Result<()> {
|
||||||
let file = file()?;
|
let file = file()?;
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
if !matches.is_present("no-dump") {
|
if !matches.is_present("no-dump") {
|
||||||
println!("{}", file.syntax_tree());
|
println!("{}", syntax_tree(&file));
|
||||||
}
|
}
|
||||||
eprintln!("parsing: {:?}", elapsed);
|
eprintln!("parsing: {:?}", elapsed);
|
||||||
::std::mem::forget(file);
|
::std::mem::forget(file);
|
||||||
}
|
}
|
||||||
("symbols", _) => {
|
("symbols", _) => {
|
||||||
let file = file()?;
|
let file = file()?;
|
||||||
for s in file.symbols() {
|
for s in symbols(&file) {
|
||||||
println!("{:?}", s);
|
println!("{:?}", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,9 @@ fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file() -> Result<File> {
|
fn file() -> Result<ast::File> {
|
||||||
let text = read_stdin()?;
|
let text = read_stdin()?;
|
||||||
Ok(File::new(&text))
|
Ok(ast::File::parse(&text))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_stdin() -> Result<String> {
|
fn read_stdin() -> Result<String> {
|
||||||
|
@ -89,7 +89,7 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
|
||||||
None => bail!("No test found at line {} at {}", line, file.display()),
|
None => bail!("No test found at line {} at {}", line, file.display()),
|
||||||
Some((_start_line, test)) => test,
|
Some((_start_line, test)) => test,
|
||||||
};
|
};
|
||||||
let file = File::new(&test.text);
|
let file = ast::File::parse(&test.text);
|
||||||
let tree = file.syntax_tree();
|
let tree = syntax_tree(&file);
|
||||||
Ok((test.text, tree))
|
Ok((test.text, tree))
|
||||||
}
|
}
|
||||||
|
|
1
codeless/server/.gitignore
vendored
1
codeless/server/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
/target/*
|
|
|
@ -2,7 +2,6 @@
|
||||||
name = "m"
|
name = "m"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
||||||
[workspace]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
failure = "0.1.2"
|
failure = "0.1.2"
|
||||||
|
@ -12,5 +11,8 @@ serde = "1.0.71"
|
||||||
serde_derive = "1.0.71"
|
serde_derive = "1.0.71"
|
||||||
drop_bomb = "0.1.0"
|
drop_bomb = "0.1.0"
|
||||||
crossbeam-channel = "0.2.4"
|
crossbeam-channel = "0.2.4"
|
||||||
|
threadpool = "1.7.1"
|
||||||
|
flexi_logger = "0.9.0"
|
||||||
|
log = "0.4.3"
|
||||||
libeditor = { path = "../../libeditor" }
|
libeditor = { path = "../../libeditor" }
|
||||||
libanalysis = { path = "../../libanalysis" }
|
libanalysis = { path = "../../libanalysis" }
|
||||||
|
|
|
@ -24,8 +24,8 @@ impl<R: Request> Responder<R>
|
||||||
R::Params: DeserializeOwned,
|
R::Params: DeserializeOwned,
|
||||||
R::Result: Serialize,
|
R::Result: Serialize,
|
||||||
{
|
{
|
||||||
pub fn respond_with(self, io: &mut Io, f: impl FnOnce() -> Result<R::Result>) -> Result<()> {
|
pub fn response(self, io: &mut Io, resp: Result<R::Result>) -> Result<()> {
|
||||||
match f() {
|
match resp {
|
||||||
Ok(res) => self.result(io, res)?,
|
Ok(res) => self.result(io, res)?,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error(io)?;
|
self.error(io)?;
|
||||||
|
|
|
@ -49,16 +49,21 @@ impl MsgReceiver {
|
||||||
match self.chan.recv() {
|
match self.chan.recv() {
|
||||||
Some(msg) => Ok(msg),
|
Some(msg) => Ok(msg),
|
||||||
None => {
|
None => {
|
||||||
self.thread
|
self.cleanup()?;
|
||||||
.take()
|
unreachable!()
|
||||||
.ok_or_else(|| format_err!("MsgReceiver thread panicked"))?
|
|
||||||
.join()
|
|
||||||
.map_err(|_| format_err!("MsgReceiver thread panicked"))??;
|
|
||||||
bail!("client disconnected")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cleanup(&mut self) -> Result<()> {
|
||||||
|
self.thread
|
||||||
|
.take()
|
||||||
|
.ok_or_else(|| format_err!("MsgReceiver thread panicked"))?
|
||||||
|
.join()
|
||||||
|
.map_err(|_| format_err!("MsgReceiver thread panicked"))??;
|
||||||
|
bail!("client disconnected")
|
||||||
|
}
|
||||||
|
|
||||||
fn stop(self) -> Result<()> {
|
fn stop(self) -> Result<()> {
|
||||||
// Can't really self.thread.join() here, b/c it might be
|
// Can't really self.thread.join() here, b/c it might be
|
||||||
// blocking on read
|
// blocking on read
|
||||||
|
@ -68,7 +73,7 @@ impl MsgReceiver {
|
||||||
|
|
||||||
struct MsgSender {
|
struct MsgSender {
|
||||||
chan: Sender<RawMsg>,
|
chan: Sender<RawMsg>,
|
||||||
thread: Option<thread::JoinHandle<Result<()>>>,
|
thread: thread::JoinHandle<Result<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MsgSender {
|
impl MsgSender {
|
||||||
|
@ -76,28 +81,14 @@ impl MsgSender {
|
||||||
self.chan.send(msg)
|
self.chan.send(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(mut self) -> Result<()> {
|
fn stop(self) -> Result<()> {
|
||||||
if let Some(thread) = self.thread.take() {
|
drop(self.chan);
|
||||||
thread.join()
|
self.thread.join()
|
||||||
.map_err(|_| format_err!("MsgSender thread panicked"))??
|
.map_err(|_| format_err!("MsgSender thread panicked"))??;
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for MsgSender {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Some(thread) = self.thread.take() {
|
|
||||||
let res = thread.join();
|
|
||||||
if thread::panicking() {
|
|
||||||
drop(res)
|
|
||||||
} else {
|
|
||||||
res.unwrap().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Io {
|
pub struct Io {
|
||||||
receiver: MsgReceiver,
|
receiver: MsgReceiver,
|
||||||
sender: MsgSender,
|
sender: MsgSender,
|
||||||
|
@ -109,7 +100,7 @@ impl Io {
|
||||||
let (tx, rx) = bounded(16);
|
let (tx, rx) = bounded(16);
|
||||||
MsgSender {
|
MsgSender {
|
||||||
chan: tx,
|
chan: tx,
|
||||||
thread: Some(thread::spawn(move || {
|
thread: thread::spawn(move || {
|
||||||
let stdout = stdout();
|
let stdout = stdout();
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
for msg in rx {
|
for msg in rx {
|
||||||
|
@ -126,7 +117,7 @@ impl Io {
|
||||||
write_msg_text(&mut stdout, &text)?;
|
write_msg_text(&mut stdout, &text)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})),
|
}),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let receiver = {
|
let receiver = {
|
||||||
|
@ -155,6 +146,14 @@ impl Io {
|
||||||
self.receiver.recv()
|
self.receiver.recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn receiver(&mut self) -> &mut Receiver<RawMsg> {
|
||||||
|
&mut self.receiver.chan
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup_receiver(&mut self) -> Result<()> {
|
||||||
|
self.receiver.cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stop(self) -> Result<()> {
|
pub fn stop(self) -> Result<()> {
|
||||||
self.receiver.stop()?;
|
self.receiver.stop()?;
|
||||||
self.sender.stop()?;
|
self.sender.stop()?;
|
||||||
|
@ -190,10 +189,12 @@ fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> {
|
||||||
buf.resize(size, 0);
|
buf.resize(size, 0);
|
||||||
inp.read_exact(&mut buf)?;
|
inp.read_exact(&mut buf)?;
|
||||||
let buf = String::from_utf8(buf)?;
|
let buf = String::from_utf8(buf)?;
|
||||||
|
debug!("< {}", buf);
|
||||||
Ok(Some(buf))
|
Ok(Some(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> {
|
fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> {
|
||||||
|
debug!("> {}", msg);
|
||||||
write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
|
write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
|
||||||
out.write_all(msg.as_bytes())?;
|
out.write_all(msg.as_bytes())?;
|
||||||
out.flush()?;
|
out.flush()?;
|
||||||
|
|
|
@ -6,7 +6,12 @@ extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate languageserver_types;
|
extern crate languageserver_types;
|
||||||
extern crate drop_bomb;
|
extern crate drop_bomb;
|
||||||
|
#[macro_use]
|
||||||
extern crate crossbeam_channel;
|
extern crate crossbeam_channel;
|
||||||
|
extern crate threadpool;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
extern crate flexi_logger;
|
||||||
extern crate libeditor;
|
extern crate libeditor;
|
||||||
extern crate libanalysis;
|
extern crate libanalysis;
|
||||||
|
|
||||||
|
@ -16,16 +21,50 @@ mod req;
|
||||||
mod dispatch;
|
mod dispatch;
|
||||||
|
|
||||||
use languageserver_types::InitializeResult;
|
use languageserver_types::InitializeResult;
|
||||||
|
use threadpool::ThreadPool;
|
||||||
|
use crossbeam_channel::{bounded, Sender, Receiver};
|
||||||
|
use flexi_logger::Logger;
|
||||||
use libanalysis::WorldState;
|
use libanalysis::WorldState;
|
||||||
use self::io::{Io, RawMsg};
|
|
||||||
|
use ::{
|
||||||
|
io::{Io, RawMsg},
|
||||||
|
};
|
||||||
|
|
||||||
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
Logger::with_env_or_str("m=trace")
|
||||||
|
.log_to_file()
|
||||||
|
.directory("log")
|
||||||
|
.start()?;
|
||||||
|
info!("starting server");
|
||||||
|
match ::std::panic::catch_unwind(|| main_inner()) {
|
||||||
|
Ok(res) => {
|
||||||
|
info!("shutting down: {:?}", res);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
error!("server panicked");
|
||||||
|
bail!("server panicked")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_inner() -> Result<()> {
|
||||||
let mut io = Io::from_stdio();
|
let mut io = Io::from_stdio();
|
||||||
initialize(&mut io)?;
|
let res = initialize(&mut io);
|
||||||
io.stop()?;
|
info!("shutting down IO...");
|
||||||
Ok(())
|
let io_res = io.stop();
|
||||||
|
info!("... IO is down");
|
||||||
|
match (res, io_res) {
|
||||||
|
(Ok(()), Ok(())) => Ok(()),
|
||||||
|
(res, Ok(())) => res,
|
||||||
|
(Ok(()), io_res) => io_res,
|
||||||
|
(res, Err(io_err)) => {
|
||||||
|
error!("shutdown error: {:?}", io_err);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(io: &mut Io) -> Result<()> {
|
fn initialize(io: &mut Io) -> Result<()> {
|
||||||
|
@ -59,20 +98,69 @@ fn initialize(io: &mut Io) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Thunk = Box<for<'a> FnBox<&'a mut Io, Result<()>>>;
|
||||||
|
|
||||||
fn initialized(io: &mut Io) -> Result<()> {
|
fn initialized(io: &mut Io) -> Result<()> {
|
||||||
eprintln!("initialized");
|
let mut world = WorldState::new();
|
||||||
let world = WorldState::new();
|
let mut pool = ThreadPool::new(4);
|
||||||
|
let (sender, receiver) = bounded::<Thunk>(16);
|
||||||
|
let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone());
|
||||||
|
info!("waiting for background jobs to finish...");
|
||||||
|
receiver.for_each(drop);
|
||||||
|
info!("...background jobs have finished");
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_loop(
|
||||||
|
io: &mut Io,
|
||||||
|
world: &mut WorldState,
|
||||||
|
pool: &mut ThreadPool,
|
||||||
|
sender: Sender<Thunk>,
|
||||||
|
receiver: Receiver<Thunk>,
|
||||||
|
) -> Result<()> {
|
||||||
|
info!("server initialized, serving requests");
|
||||||
loop {
|
loop {
|
||||||
match io.recv()? {
|
enum Event {
|
||||||
|
Msg(RawMsg),
|
||||||
|
Thunk(Thunk),
|
||||||
|
ReceiverDead,
|
||||||
|
}
|
||||||
|
|
||||||
|
let event = select! {
|
||||||
|
recv(io.receiver(), msg) => match msg {
|
||||||
|
Some(msg) => Event::Msg(msg),
|
||||||
|
None => Event::ReceiverDead,
|
||||||
|
},
|
||||||
|
recv(receiver, thunk) => Event::Thunk(thunk.unwrap()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = match event {
|
||||||
|
Event::ReceiverDead => {
|
||||||
|
io.cleanup_receiver()?;
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
Event::Thunk(thunk) => {
|
||||||
|
thunk.call_box(io)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Event::Msg(msg) => msg,
|
||||||
|
};
|
||||||
|
|
||||||
|
match msg {
|
||||||
RawMsg::Request(req) => {
|
RawMsg::Request(req) => {
|
||||||
let world = world.snapshot();
|
|
||||||
if let Some((params, resp)) = dispatch::expect::<req::SyntaxTree>(io, req)? {
|
if let Some((params, resp)) = dispatch::expect::<req::SyntaxTree>(io, req)? {
|
||||||
resp.respond_with(io, || {
|
let world = world.snapshot();
|
||||||
let path = params.text_document.uri.to_file_path()
|
let sender = sender.clone();
|
||||||
.map_err(|()| format_err!("invalid path"))?;
|
pool.execute(move || {
|
||||||
let file = world.file_syntax(&path)?;
|
let res: Result<String> = (|| {
|
||||||
Ok(libeditor::syntax_tree(&file))
|
let path = params.text_document.uri.to_file_path()
|
||||||
})?
|
.map_err(|()| format_err!("invalid path"))?;
|
||||||
|
let file = world.file_syntax(&path)?;
|
||||||
|
Ok(libeditor::syntax_tree(&file))
|
||||||
|
})();
|
||||||
|
|
||||||
|
sender.send(Box::new(|io: &mut Io| resp.response(io, res)))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg => {
|
msg => {
|
||||||
|
@ -82,3 +170,13 @@ fn initialized(io: &mut Io) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trait FnBox<A, R>: Send {
|
||||||
|
fn call_box(self: Box<Self>, a: A) -> R;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, R, F: FnOnce(A) -> R + Send> FnBox<A, R> for F {
|
||||||
|
fn call_box(self: Box<F>, a: A) -> R {
|
||||||
|
(*self)(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"rustc_fingerprint":11898242945176772229,"outputs":{"15337506775154344876":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/matklad/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\nunix\n",""],"1617349019360157463":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/matklad/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\nunix\n",""],"1164083562126845933":["rustc 1.28.0 (9634041f0 2018-07-30)\nbinary: rustc\ncommit-hash: 9634041f0e8c0f3191d2867311276f19d0a42564\ncommit-date: 2018-07-30\nhost: x86_64-unknown-linux-gnu\nrelease: 1.28.0\nLLVM version: 6.0\n",""]}}
|
|
|
@ -1 +0,0 @@
|
||||||
/home/matklad/projects/libsyntax2/codeless/server/target/debug/libm.rmeta: /home/matklad/projects/libsyntax2/codeless/server/src/caps.rs /home/matklad/projects/libsyntax2/codeless/server/src/dispatch.rs /home/matklad/projects/libsyntax2/codeless/server/src/io.rs /home/matklad/projects/libsyntax2/codeless/server/src/main.rs /home/matklad/projects/libsyntax2/codeless/server/src/req.rs /home/matklad/projects/libsyntax2/libanalysis/src/lib.rs /home/matklad/projects/libsyntax2/libeditor/src/extend_selection.rs /home/matklad/projects/libsyntax2/libeditor/src/lib.rs /home/matklad/projects/libsyntax2/src/algo/mod.rs /home/matklad/projects/libsyntax2/src/algo/walk.rs /home/matklad/projects/libsyntax2/src/ast/generated.rs /home/matklad/projects/libsyntax2/src/ast/mod.rs /home/matklad/projects/libsyntax2/src/grammar/attributes.rs /home/matklad/projects/libsyntax2/src/grammar/expressions/atom.rs /home/matklad/projects/libsyntax2/src/grammar/expressions/mod.rs /home/matklad/projects/libsyntax2/src/grammar/items/consts.rs /home/matklad/projects/libsyntax2/src/grammar/items/mod.rs /home/matklad/projects/libsyntax2/src/grammar/items/structs.rs /home/matklad/projects/libsyntax2/src/grammar/items/traits.rs /home/matklad/projects/libsyntax2/src/grammar/items/use_item.rs /home/matklad/projects/libsyntax2/src/grammar/mod.rs /home/matklad/projects/libsyntax2/src/grammar/params.rs /home/matklad/projects/libsyntax2/src/grammar/paths.rs /home/matklad/projects/libsyntax2/src/grammar/patterns.rs /home/matklad/projects/libsyntax2/src/grammar/type_args.rs /home/matklad/projects/libsyntax2/src/grammar/type_params.rs /home/matklad/projects/libsyntax2/src/grammar/types.rs /home/matklad/projects/libsyntax2/src/lexer/classes.rs /home/matklad/projects/libsyntax2/src/lexer/comments.rs /home/matklad/projects/libsyntax2/src/lexer/mod.rs /home/matklad/projects/libsyntax2/src/lexer/numbers.rs /home/matklad/projects/libsyntax2/src/lexer/ptr.rs /home/matklad/projects/libsyntax2/src/lexer/strings.rs /home/matklad/projects/libsyntax2/src/lib.rs /home/matklad/projects/libsyntax2/src/parser_api.rs /home/matklad/projects/libsyntax2/src/parser_impl/event.rs /home/matklad/projects/libsyntax2/src/parser_impl/input.rs /home/matklad/projects/libsyntax2/src/parser_impl/mod.rs /home/matklad/projects/libsyntax2/src/smol_str.rs /home/matklad/projects/libsyntax2/src/syntax_kinds/generated.rs /home/matklad/projects/libsyntax2/src/syntax_kinds/mod.rs /home/matklad/projects/libsyntax2/src/utils.rs /home/matklad/projects/libsyntax2/src/yellow/builder.rs /home/matklad/projects/libsyntax2/src/yellow/green.rs /home/matklad/projects/libsyntax2/src/yellow/mod.rs /home/matklad/projects/libsyntax2/src/yellow/red.rs /home/matklad/projects/libsyntax2/src/yellow/syntax.rs
|
|
|
@ -43,10 +43,8 @@ export function deactivate(): Thenable<void> {
|
||||||
function startServer() {
|
function startServer() {
|
||||||
let run: Executable = {
|
let run: Executable = {
|
||||||
command: "cargo",
|
command: "cargo",
|
||||||
args: ["run"],
|
args: ["run", "--package", "m"],
|
||||||
options: {
|
options: { cwd: "." }
|
||||||
cwd: "./server"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let serverOptions: ServerOptions = {
|
let serverOptions: ServerOptions = {
|
||||||
run,
|
run,
|
||||||
|
|
|
@ -6,9 +6,8 @@ use libsyntax2::{
|
||||||
SyntaxNodeRef, AstNode,
|
SyntaxNodeRef, AstNode,
|
||||||
algo::walk,
|
algo::walk,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
ast,
|
|
||||||
};
|
};
|
||||||
pub use libsyntax2::{TextRange, TextUnit};
|
pub use libsyntax2::{TextRange, TextUnit, ast};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HighlightedRange {
|
pub struct HighlightedRange {
|
||||||
|
|
|
@ -3,7 +3,7 @@ extern crate itertools;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use libeditor::{File, TextRange};
|
use libeditor::{ast, highlight, runnables, extend_selection, TextRange};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extend_selection() {
|
fn test_extend_selection() {
|
||||||
|
@ -12,9 +12,9 @@ fn test_extend_selection() {
|
||||||
}
|
}
|
||||||
"#);
|
"#);
|
||||||
let range = TextRange::offset_len(18.into(), 0.into());
|
let range = TextRange::offset_len(18.into(), 0.into());
|
||||||
let range = file.extend_selection(range).unwrap();
|
let range = extend_selection(&file, range).unwrap();
|
||||||
assert_eq!(range, TextRange::from_to(17.into(), 18.into()));
|
assert_eq!(range, TextRange::from_to(17.into(), 18.into()));
|
||||||
let range = file.extend_selection(range).unwrap();
|
let range = extend_selection(&file, range).unwrap();
|
||||||
assert_eq!(range, TextRange::from_to(15.into(), 20.into()));
|
assert_eq!(range, TextRange::from_to(15.into(), 20.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ fn test_highlighting() {
|
||||||
fn main() {}
|
fn main() {}
|
||||||
println!("Hello, {}!", 92);
|
println!("Hello, {}!", 92);
|
||||||
"#);
|
"#);
|
||||||
let hls = file.highlight();
|
let hls = highlight(&file);
|
||||||
dbg_eq(
|
dbg_eq(
|
||||||
&hls,
|
&hls,
|
||||||
r#"[HighlightedRange { range: [1; 11), tag: "comment" },
|
r#"[HighlightedRange { range: [1; 11), tag: "comment" },
|
||||||
|
@ -49,7 +49,7 @@ fn test_foo() {}
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_foo() {}
|
fn test_foo() {}
|
||||||
"#);
|
"#);
|
||||||
let runnables = file.runnables();
|
let runnables = runnables(&file);
|
||||||
dbg_eq(
|
dbg_eq(
|
||||||
&runnables,
|
&runnables,
|
||||||
r#"[Runnable { range: [1; 13), kind: Bin },
|
r#"[Runnable { range: [1; 13), kind: Bin },
|
||||||
|
@ -58,8 +58,8 @@ fn test_foo() {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(text: &str) -> File {
|
fn file(text: &str) -> ast::File {
|
||||||
File::new(text)
|
ast::File::parse(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbg_eq(actual: &impl fmt::Debug, expected: &str) {
|
fn dbg_eq(actual: &impl fmt::Debug, expected: &str) {
|
||||||
|
|
|
@ -56,12 +56,6 @@ impl GreenNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assert_send_sync() {
|
|
||||||
fn f<T: Send + Sync>() {}
|
|
||||||
f::<GreenNode>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct GreenBranch {
|
pub(crate) struct GreenBranch {
|
||||||
text_len: TextUnit,
|
text_len: TextUnit,
|
||||||
|
|
|
@ -3,9 +3,60 @@ mod green;
|
||||||
mod red;
|
mod red;
|
||||||
mod syntax;
|
mod syntax;
|
||||||
|
|
||||||
pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxRoot, TreeRoot, SyntaxError};
|
use std::{
|
||||||
|
ops::Deref,
|
||||||
|
sync::Arc,
|
||||||
|
ptr,
|
||||||
|
};
|
||||||
|
pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError};
|
||||||
pub(crate) use self::{
|
pub(crate) use self::{
|
||||||
builder::GreenBuilder,
|
builder::GreenBuilder,
|
||||||
green::GreenNode,
|
green::GreenNode,
|
||||||
red::RedNode,
|
red::RedNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub trait TreeRoot: Deref<Target=SyntaxRoot> + Clone + Send + Sync {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SyntaxRoot {
|
||||||
|
red: RedNode,
|
||||||
|
pub(crate) errors: Vec<SyntaxError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeRoot for Arc<SyntaxRoot> {}
|
||||||
|
|
||||||
|
impl<'a> TreeRoot for &'a SyntaxRoot {}
|
||||||
|
|
||||||
|
impl SyntaxRoot {
|
||||||
|
pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
|
||||||
|
SyntaxRoot {
|
||||||
|
red: RedNode::new_root(green),
|
||||||
|
errors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub(crate) struct RedPtr(ptr::NonNull<RedNode>);
|
||||||
|
|
||||||
|
unsafe impl Send for RedPtr {}
|
||||||
|
|
||||||
|
unsafe impl Sync for RedPtr {}
|
||||||
|
|
||||||
|
impl RedPtr {
|
||||||
|
fn new(red: &RedNode) -> RedPtr {
|
||||||
|
RedPtr(red.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get<'a>(self, _root: &'a impl TreeRoot) -> &'a RedNode {
|
||||||
|
&*self.0.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_send_sync() {
|
||||||
|
fn f<T: Send + Sync>() {}
|
||||||
|
f::<GreenNode>();
|
||||||
|
f::<RedNode>();
|
||||||
|
f::<SyntaxNode>();
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use {yellow::GreenNode, TextUnit};
|
use {yellow::{GreenNode, RedPtr}, TextUnit};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct RedNode {
|
pub(crate) struct RedNode {
|
||||||
|
@ -12,7 +10,7 @@ pub(crate) struct RedNode {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ParentData {
|
struct ParentData {
|
||||||
parent: ptr::NonNull<RedNode>,
|
parent: RedPtr,
|
||||||
start_offset: TextUnit,
|
start_offset: TextUnit,
|
||||||
index_in_parent: usize,
|
index_in_parent: usize,
|
||||||
}
|
}
|
||||||
|
@ -24,7 +22,7 @@ impl RedNode {
|
||||||
|
|
||||||
fn new_child(
|
fn new_child(
|
||||||
green: GreenNode,
|
green: GreenNode,
|
||||||
parent: ptr::NonNull<RedNode>,
|
parent: RedPtr,
|
||||||
start_offset: TextUnit,
|
start_offset: TextUnit,
|
||||||
index_in_parent: usize,
|
index_in_parent: usize,
|
||||||
) -> RedNode {
|
) -> RedNode {
|
||||||
|
@ -64,12 +62,12 @@ impl RedNode {
|
||||||
self.green.children().len()
|
self.green.children().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_child(&self, idx: usize) -> Option<ptr::NonNull<RedNode>> {
|
pub(crate) fn get_child(&self, idx: usize) -> Option<RedPtr> {
|
||||||
if idx >= self.n_children() {
|
if idx >= self.n_children() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match &self.children.read()[idx] {
|
match &self.children.read()[idx] {
|
||||||
Some(child) => return Some(child.into()),
|
Some(child) => return Some(RedPtr::new(child)),
|
||||||
None => (),
|
None => (),
|
||||||
};
|
};
|
||||||
let green_children = self.green.children();
|
let green_children = self.green.children();
|
||||||
|
@ -79,15 +77,15 @@ impl RedNode {
|
||||||
.map(|x| x.text_len())
|
.map(|x| x.text_len())
|
||||||
.sum::<TextUnit>();
|
.sum::<TextUnit>();
|
||||||
let child =
|
let child =
|
||||||
RedNode::new_child(green_children[idx].clone(), self.into(), start_offset, idx);
|
RedNode::new_child(green_children[idx].clone(), RedPtr::new(self), start_offset, idx);
|
||||||
let mut children = self.children.write();
|
let mut children = self.children.write();
|
||||||
if children[idx].is_none() {
|
if children[idx].is_none() {
|
||||||
children[idx] = Some(child)
|
children[idx] = Some(child)
|
||||||
}
|
}
|
||||||
Some(children[idx].as_ref().unwrap().into())
|
Some(RedPtr::new(children[idx].as_ref().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parent(&self) -> Option<ptr::NonNull<RedNode>> {
|
pub(crate) fn parent(&self) -> Option<RedPtr> {
|
||||||
Some(self.parent.as_ref()?.parent)
|
Some(self.parent.as_ref()?.parent)
|
||||||
}
|
}
|
||||||
pub(crate) fn index_in_parent(&self) -> Option<usize> {
|
pub(crate) fn index_in_parent(&self) -> Option<usize> {
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
use std::{fmt, ops::Deref, ptr, sync::Arc};
|
use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
use {
|
use {
|
||||||
yellow::{GreenNode, RedNode},
|
yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr},
|
||||||
SyntaxKind::{self, *},
|
SyntaxKind::{self, *},
|
||||||
TextRange, TextUnit,
|
TextRange, TextUnit,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait TreeRoot: Deref<Target = SyntaxRoot> + Clone {}
|
|
||||||
|
|
||||||
impl TreeRoot for Arc<SyntaxRoot> {}
|
|
||||||
|
|
||||||
impl<'a> TreeRoot for &'a SyntaxRoot {}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SyntaxNode<R: TreeRoot = Arc<SyntaxRoot>> {
|
pub struct SyntaxNode<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||||
pub(crate) root: R,
|
pub(crate) root: R,
|
||||||
// Guaranteed to not dangle, because `root` holds a
|
// Guaranteed to not dangle, because `root` holds a
|
||||||
// strong reference to red's ancestor
|
// strong reference to red's ancestor
|
||||||
red: ptr::NonNull<RedNode>,
|
red: RedPtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {}
|
||||||
|
unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {}
|
||||||
|
|
||||||
impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
|
impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
|
||||||
fn eq(&self, other: &SyntaxNode<R1>) -> bool {
|
fn eq(&self, other: &SyntaxNode<R1>) -> bool {
|
||||||
self.red == other.red
|
self.red == other.red
|
||||||
|
@ -30,21 +28,6 @@ impl<R: TreeRoot> Eq for SyntaxNode<R> {}
|
||||||
|
|
||||||
pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>;
|
pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SyntaxRoot {
|
|
||||||
red: RedNode,
|
|
||||||
pub(crate) errors: Vec<SyntaxError>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntaxRoot {
|
|
||||||
pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
|
|
||||||
SyntaxRoot {
|
|
||||||
red: RedNode::new_root(green),
|
|
||||||
errors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
pub struct SyntaxError {
|
pub struct SyntaxError {
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
|
@ -54,11 +37,8 @@ pub struct SyntaxError {
|
||||||
impl SyntaxNode<Arc<SyntaxRoot>> {
|
impl SyntaxNode<Arc<SyntaxRoot>> {
|
||||||
pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
|
pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
|
||||||
let root = Arc::new(root);
|
let root = Arc::new(root);
|
||||||
let red_weak = ptr::NonNull::from(&root.red);
|
let red = RedPtr::new(&root.red);
|
||||||
SyntaxNode {
|
SyntaxNode { root, red }
|
||||||
root,
|
|
||||||
red: red_weak,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +46,7 @@ impl<R: TreeRoot> SyntaxNode<R> {
|
||||||
pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> {
|
pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> {
|
||||||
SyntaxNode {
|
SyntaxNode {
|
||||||
root: &*self.root,
|
root: &*self.root,
|
||||||
red: ptr::NonNull::clone(&self.red),
|
red: self.red,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +100,7 @@ impl<R: TreeRoot> SyntaxNode<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn red(&self) -> &RedNode {
|
fn red(&self) -> &RedNode {
|
||||||
unsafe { self.red.as_ref() }
|
unsafe { self.red.get(&self.root) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue