3214: Fully document ra_lsp_server r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-02-18 11:26:10 +00:00 committed by GitHub
commit 2768476e49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 109 additions and 86 deletions

View file

@ -3,10 +3,15 @@ edition = "2018"
name = "ra_lsp_server" name = "ra_lsp_server"
version = "0.1.0" version = "0.1.0"
authors = ["rust-analyzer developers"] authors = ["rust-analyzer developers"]
autobins = false
[lib] [lib]
doctest = false doctest = false
[[bin]]
name = "ra_lsp_server"
path = "./src/bin/main.rs"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
crossbeam-channel = "0.4" crossbeam-channel = "0.4"

View file

@ -1,4 +1,6 @@
//! `ra_lsp_server` binary //! Driver for rust-analyzer.
//!
//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
mod args; mod args;
use lsp_server::Connection; use lsp_server::Connection;

View file

@ -1,69 +1,74 @@
//! FIXME: write short doc here //! See `CargoTargetSpec`
use ra_ide::{FileId, RunnableKind, TestId}; use ra_ide::{FileId, RunnableKind, TestId};
use ra_project_model::{self, ProjectWorkspace, TargetKind}; use ra_project_model::{self, ProjectWorkspace, TargetKind};
use crate::{world::WorldSnapshot, Result}; use crate::{world::WorldSnapshot, Result};
pub(crate) fn runnable_args( /// Abstract representation of Cargo target.
world: &WorldSnapshot, ///
file_id: FileId, /// We use it to cook up the set of cli args we need to pass to Cargo to
kind: &RunnableKind, /// build/test/run the target.
) -> Result<Vec<String>> { pub(crate) struct CargoTargetSpec {
let spec = CargoTargetSpec::for_file(world, file_id)?; pub(crate) package: String,
let mut res = Vec::new(); pub(crate) target: String,
match kind { pub(crate) target_kind: TargetKind,
RunnableKind::Test { test_id } => {
res.push("test".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
res.push("--".to_string());
res.push(test_id.to_string());
if let TestId::Path(_) = test_id {
res.push("--exact".to_string());
}
res.push("--nocapture".to_string());
}
RunnableKind::TestMod { path } => {
res.push("test".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
res.push("--".to_string());
res.push(path.to_string());
res.push("--nocapture".to_string());
}
RunnableKind::Bench { test_id } => {
res.push("bench".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
res.push("--".to_string());
res.push(test_id.to_string());
if let TestId::Path(_) = test_id {
res.push("--exact".to_string());
}
res.push("--nocapture".to_string());
}
RunnableKind::Bin => {
res.push("run".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
}
}
Ok(res)
}
pub struct CargoTargetSpec {
pub package: String,
pub target: String,
pub target_kind: TargetKind,
} }
impl CargoTargetSpec { impl CargoTargetSpec {
pub fn for_file(world: &WorldSnapshot, file_id: FileId) -> Result<Option<CargoTargetSpec>> { pub(crate) fn runnable_args(
spec: Option<CargoTargetSpec>,
kind: &RunnableKind,
) -> Result<Vec<String>> {
let mut res = Vec::new();
match kind {
RunnableKind::Test { test_id } => {
res.push("test".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
res.push("--".to_string());
res.push(test_id.to_string());
if let TestId::Path(_) = test_id {
res.push("--exact".to_string());
}
res.push("--nocapture".to_string());
}
RunnableKind::TestMod { path } => {
res.push("test".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
res.push("--".to_string());
res.push(path.to_string());
res.push("--nocapture".to_string());
}
RunnableKind::Bench { test_id } => {
res.push("bench".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
res.push("--".to_string());
res.push(test_id.to_string());
if let TestId::Path(_) = test_id {
res.push("--exact".to_string());
}
res.push("--nocapture".to_string());
}
RunnableKind::Bin => {
res.push("run".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
}
}
}
Ok(res)
}
pub(crate) fn for_file(
world: &WorldSnapshot,
file_id: FileId,
) -> Result<Option<CargoTargetSpec>> {
let &crate_id = match world.analysis().crate_for(file_id)?.first() { let &crate_id = match world.analysis().crate_for(file_id)?.first() {
Some(crate_id) => crate_id, Some(crate_id) => crate_id,
None => return Ok(None), None => return Ok(None),
@ -84,7 +89,7 @@ impl CargoTargetSpec {
Ok(res) Ok(res)
} }
pub fn push_to(self, buf: &mut Vec<String>) { pub(crate) fn push_to(self, buf: &mut Vec<String>) {
buf.push("--package".to_string()); buf.push("--package".to_string());
buf.push(self.package); buf.push(self.package);
match self.target_kind { match self.target_kind {

View file

@ -1,4 +1,4 @@
//! FIXME: write short doc here //! Various batch processing tasks, intended primarily for debugging.
mod load_cargo; mod load_cargo;
mod analysis_stats; mod analysis_stats;

View file

@ -1,4 +1,4 @@
//! FIXME: write short doc here //! Benchmark operations like highlighting or goto definition.
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},

View file

@ -1,4 +1,5 @@
//! FIXME: write short doc here //! Fully type-check project and print various stats, like the number of type
//! errors.
use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};

View file

@ -1,18 +1,18 @@
//! FIXME: write short doc here //! Loads a Cargo project into a static instance of analysis, without support
//! for incorporating changes.
use std::{collections::HashSet, path::Path}; use std::path::Path;
use anyhow::Result;
use crossbeam_channel::{unbounded, Receiver}; use crossbeam_channel::{unbounded, Receiver};
use ra_db::{CrateGraph, FileId, SourceRootId}; use ra_db::{CrateGraph, FileId, SourceRootId};
use ra_ide::{AnalysisChange, AnalysisHost, FeatureFlags}; use ra_ide::{AnalysisChange, AnalysisHost, FeatureFlags};
use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace};
use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
use rustc_hash::FxHashMap; use rustc_hash::{FxHashMap, FxHashSet};
use crate::vfs_glob::RustPackageFilterBuilder; use crate::vfs_glob::RustPackageFilterBuilder;
use anyhow::Result;
fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId {
FileId(f.0) FileId(f.0)
} }
@ -20,7 +20,9 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
SourceRootId(r.0) SourceRootId(r.0)
} }
pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { pub(crate) fn load_cargo(
root: &Path,
) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
let root = std::env::current_dir()?.join(root); let root = std::env::current_dir()?.join(root);
let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?; let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?;
let project_roots = ws.to_roots(); let project_roots = ws.to_roots();
@ -74,7 +76,7 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
Ok((host, source_roots)) Ok((host, source_roots))
} }
pub fn load( pub(crate) fn load(
source_roots: &FxHashMap<SourceRootId, PackageRoot>, source_roots: &FxHashMap<SourceRootId, PackageRoot>,
crate_graph: CrateGraph, crate_graph: CrateGraph,
vfs: &mut Vfs, vfs: &mut Vfs,
@ -86,7 +88,7 @@ pub fn load(
analysis_change.set_crate_graph(crate_graph); analysis_change.set_crate_graph(crate_graph);
// wait until Vfs has loaded all roots // wait until Vfs has loaded all roots
let mut roots_loaded = HashSet::new(); let mut roots_loaded = FxHashSet::default();
for task in receiver { for task in receiver {
vfs.handle_task(task); vfs.handle_task(task);
let mut done = false; let mut done = false;

View file

@ -1,4 +1,5 @@
//! Convenience module responsible for translating between rust-analyzer's types and LSP types. //! Convenience module responsible for translating between rust-analyzer's types
//! and LSP types.
use lsp_types::{ use lsp_types::{
self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation, self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation,

View file

@ -1,7 +1,9 @@
//! Book keeping for keeping diagnostics easily in sync with the client. //! Book keeping for keeping diagnostics easily in sync with the client.
use std::{collections::HashMap, sync::Arc};
use lsp_types::{CodeActionOrCommand, Diagnostic, Range}; use lsp_types::{CodeActionOrCommand, Diagnostic, Range};
use ra_ide::FileId; use ra_ide::FileId;
use std::{collections::HashMap, sync::Arc};
pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>;

View file

@ -1,10 +1,13 @@
//! Implementation of the LSP for rust-analyzer. //! Implementation of the LSP for rust-analyzer.
//! //!
//! This crate takes Rust-specific analysis results from ra_ide and //! This crate takes Rust-specific analysis results from ra_ide and translates
//! translates into LSP types. //! into LSP types.
//! //!
//! It also is the root of all state. `world` module defines the bulk of the //! It also is the root of all state. `world` module defines the bulk of the
//! state, and `main_loop` module defines the rules for modifying it. //! state, and `main_loop` module defines the rules for modifying it.
//!
//! The `cli` submodule implements some batch-processing analysis, primarily as
//! a debugging aid.
#![recursion_limit = "512"] #![recursion_limit = "512"]
pub mod cli; pub mod cli;

View file

@ -1,5 +1,5 @@
//! The main loop of `ra_lsp_server` responsible for dispatching LSP requests/replies and //! The main loop of `ra_lsp_server` responsible for dispatching LSP
//! notifications back to the client. //! requests/replies and notifications back to the client.
mod handlers; mod handlers;
mod subscriptions; mod subscriptions;

View file

@ -1,5 +1,6 @@
//! This module is responsible for implementing handlers for Lanuage Server Protocol. //! This module is responsible for implementing handlers for Language Server
//! The majority of requests are fulfilled by calling into the `ra_ide` crate. //! Protocol. The majority of requests are fulfilled by calling into the
//! `ra_ide` crate.
use std::{ use std::{
collections::hash_map::Entry, collections::hash_map::Entry,
@ -29,7 +30,7 @@ use serde::{Deserialize, Serialize};
use serde_json::to_value; use serde_json::to_value;
use crate::{ use crate::{
cargo_target_spec::{runnable_args, CargoTargetSpec}, cargo_target_spec::CargoTargetSpec,
conv::{ conv::{
to_call_hierarchy_item, to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, to_call_hierarchy_item, to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith,
TryConvWithToVec, TryConvWithToVec,
@ -921,7 +922,8 @@ fn to_lsp_runnable(
file_id: FileId, file_id: FileId,
runnable: Runnable, runnable: Runnable,
) -> Result<req::Runnable> { ) -> Result<req::Runnable> {
let args = runnable_args(world, file_id, &runnable.kind)?; let spec = CargoTargetSpec::for_file(world, file_id)?;
let args = CargoTargetSpec::runnable_args(spec, &runnable.kind)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = world.analysis().file_line_index(file_id)?;
let label = match &runnable.kind { let label = match &runnable.kind {
RunnableKind::Test { test_id } => format!("test {}", test_id), RunnableKind::Test { test_id } => format!("test {}", test_id),

View file

@ -1,4 +1,4 @@
//! Datastructures that keep track of inflight requests. //! Data structures that keep track of inflight requests.
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};

View file

@ -1,4 +1,5 @@
//! Keeps track of file subscriptions. //! Keeps track of file subscriptions -- the set of currently opened files for
//! which we want to publish diagnostics, syntax highlighting, etc.
use ra_ide::FileId; use ra_ide::FileId;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;

View file

@ -1,4 +1,4 @@
//! `ra_vfs_glob` crate implements exclusion rules for vfs. //! Exclusion rules for vfs.
//! //!
//! By default, we include only `.rs` files, and skip some know offenders like //! By default, we include only `.rs` files, and skip some know offenders like
//! `/target` or `/node_modules` altogether. //! `/target` or `/node_modules` altogether.

View file

@ -1,5 +1,5 @@
//! The context or environment in which the language server functions. //! The context or environment in which the language server functions. In our
//! In our server implementation this is know as the `WorldState`. //! server implementation this is know as the `WorldState`.
//! //!
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.

View file

@ -77,7 +77,6 @@ fn no_docs_comments() {
"ra_hir", "ra_hir",
"ra_hir_expand", "ra_hir_expand",
"ra_ide", "ra_ide",
"ra_lsp_server",
"ra_mbe", "ra_mbe",
"ra_parser", "ra_parser",
"ra_prof", "ra_prof",