Rename WorldState -> GlobalState

This commit is contained in:
Aleksey Kladov 2020-06-03 11:16:08 +02:00
parent 5100f77073
commit a87cd8ecc6
7 changed files with 291 additions and 273 deletions

View File

@ -4,7 +4,7 @@ use ra_cfg::CfgExpr;
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::{global_state::GlobalStateSnapshot, Result};
/// Abstract representation of Cargo target. /// Abstract representation of Cargo target.
/// ///
@ -89,7 +89,7 @@ impl CargoTargetSpec {
} }
pub(crate) fn for_file( pub(crate) fn for_file(
world: &WorldSnapshot, world: &GlobalStateSnapshot,
file_id: FileId, file_id: FileId,
) -> Result<Option<CargoTargetSpec>> { ) -> 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() {

View File

@ -3,7 +3,7 @@ use ra_db::{FileId, FilePosition, FileRange};
use ra_ide::{LineCol, LineIndex}; use ra_ide::{LineCol, LineIndex};
use ra_syntax::{TextRange, TextSize}; use ra_syntax::{TextRange, TextSize};
use crate::{world::WorldSnapshot, Result}; use crate::{global_state::GlobalStateSnapshot, Result};
pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 }; let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 };
@ -16,12 +16,12 @@ pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Tex
TextRange::new(start, end) TextRange::new(start, end)
} }
pub(crate) fn file_id(world: &WorldSnapshot, url: &lsp_types::Url) -> Result<FileId> { pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
world.uri_to_file_id(url) world.uri_to_file_id(url)
} }
pub(crate) fn file_position( pub(crate) fn file_position(
world: &WorldSnapshot, world: &GlobalStateSnapshot,
tdpp: lsp_types::TextDocumentPositionParams, tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> { ) -> Result<FilePosition> {
let file_id = file_id(world, &tdpp.text_document.uri)?; let file_id = file_id(world, &tdpp.text_document.uri)?;
@ -31,7 +31,7 @@ pub(crate) fn file_position(
} }
pub(crate) fn file_range( pub(crate) fn file_range(
world: &WorldSnapshot, world: &GlobalStateSnapshot,
text_document_identifier: lsp_types::TextDocumentIdentifier, text_document_identifier: lsp_types::TextDocumentIdentifier,
range: lsp_types::Range, range: lsp_types::Range,
) -> Result<FileRange> { ) -> Result<FileRange> {

View File

@ -50,13 +50,13 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) ->
}) })
} }
/// `WorldState` is the primary mutable state of the language server /// `GlobalState` is the primary mutable state of the language server
/// ///
/// The most interesting components are `vfs`, which stores a consistent /// The most interesting components are `vfs`, which stores a consistent
/// snapshot of the file systems, and `analysis_host`, which stores our /// snapshot of the file systems, and `analysis_host`, which stores our
/// incremental salsa database. /// incremental salsa database.
#[derive(Debug)] #[derive(Debug)]
pub struct WorldState { pub struct GlobalState {
pub config: Config, pub config: Config,
pub local_roots: Vec<PathBuf>, pub local_roots: Vec<PathBuf>,
pub workspaces: Arc<Vec<ProjectWorkspace>>, pub workspaces: Arc<Vec<ProjectWorkspace>>,
@ -70,7 +70,7 @@ pub struct WorldState {
} }
/// An immutable snapshot of the world's state at a point in time. /// An immutable snapshot of the world's state at a point in time.
pub struct WorldSnapshot { pub struct GlobalStateSnapshot {
pub config: Config, pub config: Config,
pub workspaces: Arc<Vec<ProjectWorkspace>>, pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis: Analysis, pub analysis: Analysis,
@ -79,14 +79,14 @@ pub struct WorldSnapshot {
vfs: Arc<RwLock<Vfs>>, vfs: Arc<RwLock<Vfs>>,
} }
impl WorldState { impl GlobalState {
pub fn new( pub fn new(
workspaces: Vec<ProjectWorkspace>, workspaces: Vec<ProjectWorkspace>,
lru_capacity: Option<usize>, lru_capacity: Option<usize>,
exclude_globs: &[Glob], exclude_globs: &[Glob],
watch: Watch, watch: Watch,
config: Config, config: Config,
) -> WorldState { ) -> GlobalState {
let mut change = AnalysisChange::new(); let mut change = AnalysisChange::new();
let extern_dirs: FxHashSet<_> = let extern_dirs: FxHashSet<_> =
@ -180,7 +180,7 @@ impl WorldState {
let mut analysis_host = AnalysisHost::new(lru_capacity); let mut analysis_host = AnalysisHost::new(lru_capacity);
analysis_host.apply_change(change); analysis_host.apply_change(change);
WorldState { GlobalState {
config, config,
local_roots, local_roots,
workspaces: Arc::new(workspaces), workspaces: Arc::new(workspaces),
@ -255,8 +255,8 @@ impl WorldState {
self.analysis_host.apply_change(change); self.analysis_host.apply_change(change);
} }
pub fn snapshot(&self) -> WorldSnapshot { pub fn snapshot(&self) -> GlobalStateSnapshot {
WorldSnapshot { GlobalStateSnapshot {
config: self.config.clone(), config: self.config.clone(),
workspaces: Arc::clone(&self.workspaces), workspaces: Arc::clone(&self.workspaces),
analysis: self.analysis_host.analysis(), analysis: self.analysis_host.analysis(),
@ -279,7 +279,7 @@ impl WorldState {
} }
} }
impl WorldSnapshot { impl GlobalStateSnapshot {
pub fn analysis(&self) -> &Analysis { pub fn analysis(&self) -> &Analysis {
&self.analysis &self.analysis
} }

View File

@ -26,7 +26,7 @@ mod main_loop;
mod markdown; mod markdown;
pub mod lsp_ext; pub mod lsp_ext;
pub mod config; pub mod config;
mod world; mod global_state;
mod diagnostics; mod diagnostics;
mod semantic_tokens; mod semantic_tokens;

View File

@ -38,12 +38,13 @@ use threadpool::ThreadPool;
use crate::{ use crate::{
config::{Config, FilesWatcher}, config::{Config, FilesWatcher},
diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask},
from_proto, lsp_ext, from_proto,
global_state::{GlobalState, GlobalStateSnapshot},
lsp_ext,
main_loop::{ main_loop::{
pending_requests::{PendingRequest, PendingRequests}, pending_requests::{PendingRequest, PendingRequests},
subscriptions::Subscriptions, subscriptions::Subscriptions,
}, },
world::{WorldSnapshot, WorldState},
Result, Result,
}; };
@ -92,7 +93,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
} }
let mut loop_state = LoopState::default(); let mut loop_state = LoopState::default();
let mut world_state = { let mut global_state = {
let workspaces = { let workspaces = {
// FIXME: support dynamic workspace loading. // FIXME: support dynamic workspace loading.
let project_roots: FxHashSet<_> = ws_roots let project_roots: FxHashSet<_> = ws_roots
@ -163,7 +164,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
connection.sender.send(request.into()).unwrap(); connection.sender.send(request.into()).unwrap();
} }
WorldState::new( GlobalState::new(
workspaces, workspaces,
config.lru_capacity, config.lru_capacity,
&globs, &globs,
@ -172,7 +173,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
) )
}; };
loop_state.roots_total = world_state.vfs.read().n_roots(); loop_state.roots_total = global_state.vfs.read().n_roots();
let pool = ThreadPool::default(); let pool = ThreadPool::default();
let (task_sender, task_receiver) = unbounded::<Task>(); let (task_sender, task_receiver) = unbounded::<Task>();
@ -190,12 +191,12 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
Err(RecvError) => return Err("client exited without shutdown".into()), Err(RecvError) => return Err("client exited without shutdown".into()),
}, },
recv(task_receiver) -> task => Event::Task(task.unwrap()), recv(task_receiver) -> task => Event::Task(task.unwrap()),
recv(world_state.task_receiver) -> task => match task { recv(global_state.task_receiver) -> task => match task {
Ok(task) => Event::Vfs(task), Ok(task) => Event::Vfs(task),
Err(RecvError) => return Err("vfs died".into()), Err(RecvError) => return Err("vfs died".into()),
}, },
recv(libdata_receiver) -> data => Event::Lib(data.unwrap()), recv(libdata_receiver) -> data => Event::Lib(data.unwrap()),
recv(world_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
Ok(task) => Event::CheckWatcher(task), Ok(task) => Event::CheckWatcher(task),
Err(RecvError) => return Err("check watcher died".into()), Err(RecvError) => return Err("check watcher died".into()),
} }
@ -210,16 +211,16 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
&task_sender, &task_sender,
&libdata_sender, &libdata_sender,
&connection, &connection,
&mut world_state, &mut global_state,
&mut loop_state, &mut loop_state,
event, event,
)?; )?;
} }
} }
world_state.analysis_host.request_cancellation(); global_state.analysis_host.request_cancellation();
log::info!("waiting for tasks to finish..."); log::info!("waiting for tasks to finish...");
task_receiver.into_iter().for_each(|task| { task_receiver.into_iter().for_each(|task| {
on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state)
}); });
libdata_receiver.into_iter().for_each(drop); libdata_receiver.into_iter().for_each(drop);
log::info!("...tasks have finished"); log::info!("...tasks have finished");
@ -228,7 +229,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
drop(pool); drop(pool);
log::info!("...threadpool has finished"); log::info!("...threadpool has finished");
let vfs = Arc::try_unwrap(world_state.vfs).expect("all snapshots should be dead"); let vfs = Arc::try_unwrap(global_state.vfs).expect("all snapshots should be dead");
drop(vfs); drop(vfs);
Ok(()) Ok(())
@ -319,7 +320,7 @@ fn loop_turn(
task_sender: &Sender<Task>, task_sender: &Sender<Task>,
libdata_sender: &Sender<LibraryData>, libdata_sender: &Sender<LibraryData>,
connection: &Connection, connection: &Connection,
world_state: &mut WorldState, global_state: &mut GlobalState,
loop_state: &mut LoopState, loop_state: &mut LoopState,
event: Event, event: Event,
) -> Result<()> { ) -> Result<()> {
@ -335,22 +336,22 @@ fn loop_turn(
match event { match event {
Event::Task(task) => { Event::Task(task) => {
on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); on_task(task, &connection.sender, &mut loop_state.pending_requests, global_state);
world_state.maybe_collect_garbage(); global_state.maybe_collect_garbage();
} }
Event::Vfs(task) => { Event::Vfs(task) => {
world_state.vfs.write().handle_task(task); global_state.vfs.write().handle_task(task);
} }
Event::Lib(lib) => { Event::Lib(lib) => {
world_state.add_lib(lib); global_state.add_lib(lib);
world_state.maybe_collect_garbage(); global_state.maybe_collect_garbage();
loop_state.in_flight_libraries -= 1; loop_state.in_flight_libraries -= 1;
loop_state.roots_scanned += 1; loop_state.roots_scanned += 1;
} }
Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
Event::Msg(msg) => match msg { Event::Msg(msg) => match msg {
Message::Request(req) => on_request( Message::Request(req) => on_request(
world_state, global_state,
&mut loop_state.pending_requests, &mut loop_state.pending_requests,
pool, pool,
task_sender, task_sender,
@ -359,7 +360,7 @@ fn loop_turn(
req, req,
)?, )?,
Message::Notification(not) => { Message::Notification(not) => {
on_notification(&connection.sender, world_state, loop_state, not)?; on_notification(&connection.sender, global_state, loop_state, not)?;
} }
Message::Response(resp) => { Message::Response(resp) => {
let removed = loop_state.pending_responses.remove(&resp.id); let removed = loop_state.pending_responses.remove(&resp.id);
@ -378,9 +379,9 @@ fn loop_turn(
} }
(None, Some(configs)) => { (None, Some(configs)) => {
if let Some(new_config) = configs.get(0) { if let Some(new_config) = configs.get(0) {
let mut config = world_state.config.clone(); let mut config = global_state.config.clone();
config.update(&new_config); config.update(&new_config);
world_state.update_configuration(config); global_state.update_configuration(config);
} }
} }
(None, None) => { (None, None) => {
@ -393,7 +394,7 @@ fn loop_turn(
}; };
let mut state_changed = false; let mut state_changed = false;
if let Some(changes) = world_state.process_changes(&mut loop_state.roots_scanned) { if let Some(changes) = global_state.process_changes(&mut loop_state.roots_scanned) {
state_changed = true; state_changed = true;
loop_state.pending_libraries.extend(changes); loop_state.pending_libraries.extend(changes);
} }
@ -415,7 +416,7 @@ fn loop_turn(
} }
let show_progress = let show_progress =
!loop_state.workspace_loaded && world_state.config.client_caps.work_done_progress; !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress;
if !loop_state.workspace_loaded if !loop_state.workspace_loaded
&& loop_state.roots_scanned == loop_state.roots_total && loop_state.roots_scanned == loop_state.roots_total
@ -424,7 +425,7 @@ fn loop_turn(
{ {
state_changed = true; state_changed = true;
loop_state.workspace_loaded = true; loop_state.workspace_loaded = true;
if let Some(flycheck) = &world_state.flycheck { if let Some(flycheck) = &global_state.flycheck {
flycheck.update(); flycheck.update();
} }
} }
@ -436,13 +437,13 @@ fn loop_turn(
if state_changed && loop_state.workspace_loaded { if state_changed && loop_state.workspace_loaded {
update_file_notifications_on_threadpool( update_file_notifications_on_threadpool(
pool, pool,
world_state.snapshot(), global_state.snapshot(),
task_sender.clone(), task_sender.clone(),
loop_state.subscriptions.subscriptions(), loop_state.subscriptions.subscriptions(),
); );
pool.execute({ pool.execute({
let subs = loop_state.subscriptions.subscriptions(); let subs = loop_state.subscriptions.subscriptions();
let snap = world_state.snapshot(); let snap = global_state.snapshot();
move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ())
}); });
} }
@ -466,7 +467,7 @@ fn on_task(
task: Task, task: Task,
msg_sender: &Sender<Message>, msg_sender: &Sender<Message>,
pending_requests: &mut PendingRequests, pending_requests: &mut PendingRequests,
state: &mut WorldState, state: &mut GlobalState,
) { ) {
match task { match task {
Task::Respond(response) => { Task::Respond(response) => {
@ -484,7 +485,7 @@ fn on_task(
} }
fn on_request( fn on_request(
world: &mut WorldState, global_state: &mut GlobalState,
pending_requests: &mut PendingRequests, pending_requests: &mut PendingRequests,
pool: &ThreadPool, pool: &ThreadPool,
task_sender: &Sender<Task>, task_sender: &Sender<Task>,
@ -495,7 +496,7 @@ fn on_request(
let mut pool_dispatcher = PoolDispatcher { let mut pool_dispatcher = PoolDispatcher {
req: Some(req), req: Some(req),
pool, pool,
world, global_state,
task_sender, task_sender,
msg_sender, msg_sender,
pending_requests, pending_requests,
@ -551,7 +552,7 @@ fn on_request(
fn on_notification( fn on_notification(
msg_sender: &Sender<Message>, msg_sender: &Sender<Message>,
state: &mut WorldState, state: &mut GlobalState,
loop_state: &mut LoopState, loop_state: &mut LoopState,
not: Notification, not: Notification,
) -> Result<()> { ) -> Result<()> {
@ -725,7 +726,7 @@ fn apply_document_changes(
fn on_check_task( fn on_check_task(
task: CheckTask, task: CheckTask,
world_state: &mut WorldState, global_state: &mut GlobalState,
task_sender: &Sender<Task>, task_sender: &Sender<Task>,
) -> Result<()> { ) -> Result<()> {
match task { match task {
@ -744,7 +745,7 @@ fn on_check_task(
.uri .uri
.to_file_path() .to_file_path()
.map_err(|()| format!("invalid uri: {}", diag.location.uri))?; .map_err(|()| format!("invalid uri: {}", diag.location.uri))?;
let file_id = match world_state.vfs.read().path2file(&path) { let file_id = match global_state.vfs.read().path2file(&path) {
Some(file) => FileId(file.0), Some(file) => FileId(file.0),
None => { None => {
log::error!( log::error!(
@ -764,7 +765,7 @@ fn on_check_task(
} }
CheckTask::Status(status) => { CheckTask::Status(status) => {
if world_state.config.client_caps.work_done_progress { if global_state.config.client_caps.work_done_progress {
let progress = match status { let progress = match status {
Status::Being => { Status::Being => {
lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
@ -803,7 +804,7 @@ fn on_check_task(
Ok(()) Ok(())
} }
fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state: &mut WorldState) { fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state: &mut GlobalState) {
let subscriptions = state.diagnostics.handle_task(task); let subscriptions = state.diagnostics.handle_task(task);
for file_id in subscriptions { for file_id in subscriptions {
@ -878,7 +879,7 @@ fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
struct PoolDispatcher<'a> { struct PoolDispatcher<'a> {
req: Option<Request>, req: Option<Request>,
pool: &'a ThreadPool, pool: &'a ThreadPool,
world: &'a mut WorldState, global_state: &'a mut GlobalState,
pending_requests: &'a mut PendingRequests, pending_requests: &'a mut PendingRequests,
msg_sender: &'a Sender<Message>, msg_sender: &'a Sender<Message>,
task_sender: &'a Sender<Task>, task_sender: &'a Sender<Task>,
@ -889,7 +890,7 @@ impl<'a> PoolDispatcher<'a> {
/// Dispatches the request onto the current thread /// Dispatches the request onto the current thread
fn on_sync<R>( fn on_sync<R>(
&mut self, &mut self,
f: fn(&mut WorldState, R::Params) -> Result<R::Result>, f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
) -> Result<&mut Self> ) -> Result<&mut Self>
where where
R: lsp_types::request::Request + 'static, R: lsp_types::request::Request + 'static,
@ -902,18 +903,21 @@ impl<'a> PoolDispatcher<'a> {
return Ok(self); return Ok(self);
} }
}; };
let world = panic::AssertUnwindSafe(&mut *self.world); let world = panic::AssertUnwindSafe(&mut *self.global_state);
let task = panic::catch_unwind(move || { let task = panic::catch_unwind(move || {
let result = f(world.0, params); let result = f(world.0, params);
result_to_task::<R>(id, result) result_to_task::<R>(id, result)
}) })
.map_err(|_| format!("sync task {:?} panicked", R::METHOD))?; .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?;
on_task(task, self.msg_sender, self.pending_requests, self.world); on_task(task, self.msg_sender, self.pending_requests, self.global_state);
Ok(self) Ok(self)
} }
/// Dispatches the request onto thread pool /// Dispatches the request onto thread pool
fn on<R>(&mut self, f: fn(WorldSnapshot, R::Params) -> Result<R::Result>) -> Result<&mut Self> fn on<R>(
&mut self,
f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
) -> Result<&mut Self>
where where
R: lsp_types::request::Request + 'static, R: lsp_types::request::Request + 'static,
R::Params: DeserializeOwned + Send + 'static, R::Params: DeserializeOwned + Send + 'static,
@ -927,7 +931,7 @@ impl<'a> PoolDispatcher<'a> {
}; };
self.pool.execute({ self.pool.execute({
let world = self.world.snapshot(); let world = self.global_state.snapshot();
let sender = self.task_sender.clone(); let sender = self.task_sender.clone();
move || { move || {
let result = f(world, params); let result = f(world, params);
@ -1011,7 +1015,7 @@ where
fn update_file_notifications_on_threadpool( fn update_file_notifications_on_threadpool(
pool: &ThreadPool, pool: &ThreadPool,
world: WorldSnapshot, world: GlobalStateSnapshot,
task_sender: Sender<Task>, task_sender: Sender<Task>,
subscriptions: Vec<FileId>, subscriptions: Vec<FileId>,
) { ) {

View File

@ -32,17 +32,16 @@ use crate::{
config::RustfmtConfig, config::RustfmtConfig,
diagnostics::DiagnosticTask, diagnostics::DiagnosticTask,
from_json, from_proto, from_json, from_proto,
global_state::GlobalStateSnapshot,
lsp_ext::{self, InlayHint, InlayHintsParams}, lsp_ext::{self, InlayHint, InlayHintsParams},
to_proto, to_proto, LspError, Result,
world::WorldSnapshot,
LspError, Result,
}; };
pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> { pub fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result<String> {
let _p = profile("handle_analyzer_status"); let _p = profile("handle_analyzer_status");
let mut buf = world.status(); let mut buf = snap.status();
format_to!(buf, "\n\nrequests:\n"); format_to!(buf, "\n\nrequests:\n");
let requests = world.latest_requests.read(); let requests = snap.latest_requests.read();
for (is_last, r) in requests.iter() { for (is_last, r) in requests.iter() {
let mark = if is_last { "*" } else { " " }; let mark = if is_last { "*" } else { " " };
format_to!(buf, "{}{:4} {:<36}{}ms\n", mark, r.id, r.method, r.duration.as_millis()); format_to!(buf, "{}{:4} {:<36}{}ms\n", mark, r.id, r.method, r.duration.as_millis());
@ -51,37 +50,37 @@ pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> {
} }
pub fn handle_syntax_tree( pub fn handle_syntax_tree(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::SyntaxTreeParams, params: lsp_ext::SyntaxTreeParams,
) -> Result<String> { ) -> Result<String> {
let _p = profile("handle_syntax_tree"); let _p = profile("handle_syntax_tree");
let id = from_proto::file_id(&world, &params.text_document.uri)?; let id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(id)?; let line_index = snap.analysis().file_line_index(id)?;
let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); let text_range = params.range.map(|r| from_proto::text_range(&line_index, r));
let res = world.analysis().syntax_tree(id, text_range)?; let res = snap.analysis().syntax_tree(id, text_range)?;
Ok(res) Ok(res)
} }
pub fn handle_expand_macro( pub fn handle_expand_macro(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::ExpandMacroParams, params: lsp_ext::ExpandMacroParams,
) -> Result<Option<lsp_ext::ExpandedMacro>> { ) -> Result<Option<lsp_ext::ExpandedMacro>> {
let _p = profile("handle_expand_macro"); let _p = profile("handle_expand_macro");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let offset = from_proto::offset(&line_index, params.position); let offset = from_proto::offset(&line_index, params.position);
let res = world.analysis().expand_macro(FilePosition { file_id, offset })?; let res = snap.analysis().expand_macro(FilePosition { file_id, offset })?;
Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion }))
} }
pub fn handle_selection_range( pub fn handle_selection_range(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::SelectionRangeParams, params: lsp_types::SelectionRangeParams,
) -> Result<Option<Vec<lsp_types::SelectionRange>>> { ) -> Result<Option<Vec<lsp_types::SelectionRange>>> {
let _p = profile("handle_selection_range"); let _p = profile("handle_selection_range");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let res: Result<Vec<lsp_types::SelectionRange>> = params let res: Result<Vec<lsp_types::SelectionRange>> = params
.positions .positions
.into_iter() .into_iter()
@ -93,7 +92,7 @@ pub fn handle_selection_range(
loop { loop {
ranges.push(range); ranges.push(range);
let frange = FileRange { file_id, range }; let frange = FileRange { file_id, range };
let next = world.analysis().extend_selection(frange)?; let next = snap.analysis().extend_selection(frange)?;
if next == range { if next == range {
break; break;
} else { } else {
@ -119,18 +118,18 @@ pub fn handle_selection_range(
} }
pub fn handle_matching_brace( pub fn handle_matching_brace(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::MatchingBraceParams, params: lsp_ext::MatchingBraceParams,
) -> Result<Vec<Position>> { ) -> Result<Vec<Position>> {
let _p = profile("handle_matching_brace"); let _p = profile("handle_matching_brace");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let res = params let res = params
.positions .positions
.into_iter() .into_iter()
.map(|position| { .map(|position| {
let offset = from_proto::offset(&line_index, position); let offset = from_proto::offset(&line_index, position);
let offset = match world.analysis().matching_brace(FilePosition { file_id, offset }) { let offset = match snap.analysis().matching_brace(FilePosition { file_id, offset }) {
Ok(Some(matching_brace_offset)) => matching_brace_offset, Ok(Some(matching_brace_offset)) => matching_brace_offset,
Err(_) | Ok(None) => offset, Err(_) | Ok(None) => offset,
}; };
@ -141,17 +140,17 @@ pub fn handle_matching_brace(
} }
pub fn handle_join_lines( pub fn handle_join_lines(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::JoinLinesParams, params: lsp_ext::JoinLinesParams,
) -> Result<Vec<lsp_types::TextEdit>> { ) -> Result<Vec<lsp_types::TextEdit>> {
let _p = profile("handle_join_lines"); let _p = profile("handle_join_lines");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let line_endings = world.file_line_endings(file_id); let line_endings = snap.file_line_endings(file_id);
let mut res = TextEdit::default(); let mut res = TextEdit::default();
for range in params.ranges { for range in params.ranges {
let range = from_proto::text_range(&line_index, range); let range = from_proto::text_range(&line_index, range);
let edit = world.analysis().join_lines(FileRange { file_id, range })?; let edit = snap.analysis().join_lines(FileRange { file_id, range })?;
match res.union(edit) { match res.union(edit) {
Ok(()) => (), Ok(()) => (),
Err(_edit) => { Err(_edit) => {
@ -164,37 +163,37 @@ pub fn handle_join_lines(
} }
pub fn handle_on_enter( pub fn handle_on_enter(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams, params: lsp_types::TextDocumentPositionParams,
) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> { ) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
let _p = profile("handle_on_enter"); let _p = profile("handle_on_enter");
let position = from_proto::file_position(&world, params)?; let position = from_proto::file_position(&snap, params)?;
let edit = match world.analysis().on_enter(position)? { let edit = match snap.analysis().on_enter(position)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let line_index = world.analysis().file_line_index(position.file_id)?; let line_index = snap.analysis().file_line_index(position.file_id)?;
let line_endings = world.file_line_endings(position.file_id); let line_endings = snap.file_line_endings(position.file_id);
let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit); let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit);
Ok(Some(edit)) Ok(Some(edit))
} }
// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
pub fn handle_on_type_formatting( pub fn handle_on_type_formatting(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::DocumentOnTypeFormattingParams, params: lsp_types::DocumentOnTypeFormattingParams,
) -> Result<Option<Vec<lsp_types::TextEdit>>> { ) -> Result<Option<Vec<lsp_types::TextEdit>>> {
let _p = profile("handle_on_type_formatting"); let _p = profile("handle_on_type_formatting");
let mut position = from_proto::file_position(&world, params.text_document_position)?; let mut position = from_proto::file_position(&snap, params.text_document_position)?;
let line_index = world.analysis().file_line_index(position.file_id)?; let line_index = snap.analysis().file_line_index(position.file_id)?;
let line_endings = world.file_line_endings(position.file_id); let line_endings = snap.file_line_endings(position.file_id);
// in `ra_ide`, the `on_type` invariant is that // in `ra_ide`, the `on_type` invariant is that
// `text.char_at(position) == typed_char`. // `text.char_at(position) == typed_char`.
position.offset -= TextSize::of('.'); position.offset -= TextSize::of('.');
let char_typed = params.ch.chars().next().unwrap_or('\0'); let char_typed = params.ch.chars().next().unwrap_or('\0');
assert!({ assert!({
let text = world.analysis().file_text(position.file_id)?; let text = snap.analysis().file_text(position.file_id)?;
text[usize::from(position.offset)..].starts_with(char_typed) text[usize::from(position.offset)..].starts_with(char_typed)
}); });
@ -206,7 +205,7 @@ pub fn handle_on_type_formatting(
return Ok(None); return Ok(None);
} }
let edit = world.analysis().on_char_typed(position, char_typed)?; let edit = snap.analysis().on_char_typed(position, char_typed)?;
let mut edit = match edit { let mut edit = match edit {
Some(it) => it, Some(it) => it,
None => return Ok(None), None => return Ok(None),
@ -220,16 +219,16 @@ pub fn handle_on_type_formatting(
} }
pub fn handle_document_symbol( pub fn handle_document_symbol(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::DocumentSymbolParams, params: lsp_types::DocumentSymbolParams,
) -> Result<Option<lsp_types::DocumentSymbolResponse>> { ) -> Result<Option<lsp_types::DocumentSymbolResponse>> {
let _p = profile("handle_document_symbol"); let _p = profile("handle_document_symbol");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new();
for symbol in world.analysis().file_structure(file_id)? { for symbol in snap.analysis().file_structure(file_id)? {
let doc_symbol = DocumentSymbol { let doc_symbol = DocumentSymbol {
name: symbol.label, name: symbol.label,
detail: symbol.detail, detail: symbol.detail,
@ -255,10 +254,10 @@ pub fn handle_document_symbol(
} }
} }
let res = if world.config.client_caps.hierarchical_symbols { let res = if snap.config.client_caps.hierarchical_symbols {
document_symbols.into() document_symbols.into()
} else { } else {
let url = to_proto::url(&world, file_id)?; let url = to_proto::url(&snap, file_id)?;
let mut symbol_information = Vec::<SymbolInformation>::new(); let mut symbol_information = Vec::<SymbolInformation>::new();
for symbol in document_symbols { for symbol in document_symbols {
flatten_document_symbol(&symbol, None, &url, &mut symbol_information); flatten_document_symbol(&symbol, None, &url, &mut symbol_information);
@ -288,7 +287,7 @@ pub fn handle_document_symbol(
} }
pub fn handle_workspace_symbol( pub fn handle_workspace_symbol(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::WorkspaceSymbolParams, params: lsp_types::WorkspaceSymbolParams,
) -> Result<Option<Vec<SymbolInformation>>> { ) -> Result<Option<Vec<SymbolInformation>>> {
let _p = profile("handle_workspace_symbol"); let _p = profile("handle_workspace_symbol");
@ -306,22 +305,22 @@ pub fn handle_workspace_symbol(
q.limit(128); q.limit(128);
q q
}; };
let mut res = exec_query(&world, query)?; let mut res = exec_query(&snap, query)?;
if res.is_empty() && !all_symbols { if res.is_empty() && !all_symbols {
let mut query = Query::new(params.query); let mut query = Query::new(params.query);
query.limit(128); query.limit(128);
res = exec_query(&world, query)?; res = exec_query(&snap, query)?;
} }
return Ok(Some(res)); return Ok(Some(res));
fn exec_query(world: &WorldSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
let mut res = Vec::new(); let mut res = Vec::new();
for nav in world.analysis().symbol_search(query)? { for nav in snap.analysis().symbol_search(query)? {
let info = SymbolInformation { let info = SymbolInformation {
name: nav.name().to_string(), name: nav.name().to_string(),
kind: to_proto::symbol_kind(nav.kind()), kind: to_proto::symbol_kind(nav.kind()),
location: to_proto::location(world, nav.file_range())?, location: to_proto::location(snap, nav.file_range())?,
container_name: nav.container_name().map(|v| v.to_string()), container_name: nav.container_name().map(|v| v.to_string()),
deprecated: None, deprecated: None,
}; };
@ -332,73 +331,73 @@ pub fn handle_workspace_symbol(
} }
pub fn handle_goto_definition( pub fn handle_goto_definition(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::GotoDefinitionParams, params: lsp_types::GotoDefinitionParams,
) -> Result<Option<lsp_types::GotoDefinitionResponse>> { ) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
let _p = profile("handle_goto_definition"); let _p = profile("handle_goto_definition");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match world.analysis().goto_definition(position)? { let nav_info = match snap.analysis().goto_definition(position)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let src = FileRange { file_id: position.file_id, range: nav_info.range }; let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_goto_implementation( pub fn handle_goto_implementation(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::request::GotoImplementationParams, params: lsp_types::request::GotoImplementationParams,
) -> Result<Option<lsp_types::request::GotoImplementationResponse>> { ) -> Result<Option<lsp_types::request::GotoImplementationResponse>> {
let _p = profile("handle_goto_implementation"); let _p = profile("handle_goto_implementation");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match world.analysis().goto_implementation(position)? { let nav_info = match snap.analysis().goto_implementation(position)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let src = FileRange { file_id: position.file_id, range: nav_info.range }; let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_goto_type_definition( pub fn handle_goto_type_definition(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::request::GotoTypeDefinitionParams, params: lsp_types::request::GotoTypeDefinitionParams,
) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> { ) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
let _p = profile("handle_goto_type_definition"); let _p = profile("handle_goto_type_definition");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match world.analysis().goto_type_definition(position)? { let nav_info = match snap.analysis().goto_type_definition(position)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let src = FileRange { file_id: position.file_id, range: nav_info.range }; let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_parent_module( pub fn handle_parent_module(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams, params: lsp_types::TextDocumentPositionParams,
) -> Result<Option<lsp_types::GotoDefinitionResponse>> { ) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
let _p = profile("handle_parent_module"); let _p = profile("handle_parent_module");
let position = from_proto::file_position(&world, params)?; let position = from_proto::file_position(&snap, params)?;
let navs = world.analysis().parent_module(position)?; let navs = snap.analysis().parent_module(position)?;
let res = to_proto::goto_definition_response(&world, None, navs)?; let res = to_proto::goto_definition_response(&snap, None, navs)?;
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_runnables( pub fn handle_runnables(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::RunnablesParams, params: lsp_ext::RunnablesParams,
) -> Result<Vec<lsp_ext::Runnable>> { ) -> Result<Vec<lsp_ext::Runnable>> {
let _p = profile("handle_runnables"); let _p = profile("handle_runnables");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let offset = params.position.map(|it| from_proto::offset(&line_index, it)); let offset = params.position.map(|it| from_proto::offset(&line_index, it));
let mut res = Vec::new(); let mut res = Vec::new();
let workspace_root = world.workspace_root_for(file_id); let workspace_root = snap.workspace_root_for(file_id);
let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
for runnable in world.analysis().runnables(file_id)? { for runnable in snap.analysis().runnables(file_id)? {
if let Some(offset) = offset { if let Some(offset) = offset {
if !runnable.nav.full_range().contains_inclusive(offset) { if !runnable.nav.full_range().contains_inclusive(offset) {
continue; continue;
@ -413,7 +412,7 @@ pub fn handle_runnables(
} }
} }
} }
res.push(to_proto::runnable(&world, file_id, runnable)?); res.push(to_proto::runnable(&snap, file_id, runnable)?);
} }
// Add `cargo check` and `cargo test` for the whole package // Add `cargo check` and `cargo test` for the whole package
@ -453,16 +452,16 @@ pub fn handle_runnables(
} }
pub fn handle_completion( pub fn handle_completion(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::CompletionParams, params: lsp_types::CompletionParams,
) -> Result<Option<lsp_types::CompletionResponse>> { ) -> Result<Option<lsp_types::CompletionResponse>> {
let _p = profile("handle_completion"); let _p = profile("handle_completion");
let position = from_proto::file_position(&world, params.text_document_position)?; let position = from_proto::file_position(&snap, params.text_document_position)?;
let completion_triggered_after_single_colon = { let completion_triggered_after_single_colon = {
let mut res = false; let mut res = false;
if let Some(ctx) = params.context { if let Some(ctx) = params.context {
if ctx.trigger_character.unwrap_or_default() == ":" { if ctx.trigger_character.unwrap_or_default() == ":" {
let source_file = world.analysis().parse(position.file_id)?; let source_file = snap.analysis().parse(position.file_id)?;
let syntax = source_file.syntax(); let syntax = source_file.syntax();
let text = syntax.text(); let text = syntax.text();
if let Some(next_char) = text.char_at(position.offset) { if let Some(next_char) = text.char_at(position.offset) {
@ -480,12 +479,12 @@ pub fn handle_completion(
return Ok(None); return Ok(None);
} }
let items = match world.analysis().completions(&world.config.completion, position)? { let items = match snap.analysis().completions(&snap.config.completion, position)? {
None => return Ok(None), None => return Ok(None),
Some(items) => items, Some(items) => items,
}; };
let line_index = world.analysis().file_line_index(position.file_id)?; let line_index = snap.analysis().file_line_index(position.file_id)?;
let line_endings = world.file_line_endings(position.file_id); let line_endings = snap.file_line_endings(position.file_id);
let items: Vec<CompletionItem> = items let items: Vec<CompletionItem> = items
.into_iter() .into_iter()
.map(|item| to_proto::completion_item(&line_index, line_endings, item)) .map(|item| to_proto::completion_item(&line_index, line_endings, item))
@ -495,15 +494,15 @@ pub fn handle_completion(
} }
pub fn handle_folding_range( pub fn handle_folding_range(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: FoldingRangeParams, params: FoldingRangeParams,
) -> Result<Option<Vec<FoldingRange>>> { ) -> Result<Option<Vec<FoldingRange>>> {
let _p = profile("handle_folding_range"); let _p = profile("handle_folding_range");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let folds = world.analysis().folding_ranges(file_id)?; let folds = snap.analysis().folding_ranges(file_id)?;
let text = world.analysis().file_text(file_id)?; let text = snap.analysis().file_text(file_id)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let line_folding_only = world.config.client_caps.line_folding_only; let line_folding_only = snap.config.client_caps.line_folding_only;
let res = folds let res = folds
.into_iter() .into_iter()
.map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it))
@ -512,16 +511,16 @@ pub fn handle_folding_range(
} }
pub fn handle_signature_help( pub fn handle_signature_help(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::SignatureHelpParams, params: lsp_types::SignatureHelpParams,
) -> Result<Option<lsp_types::SignatureHelp>> { ) -> Result<Option<lsp_types::SignatureHelp>> {
let _p = profile("handle_signature_help"); let _p = profile("handle_signature_help");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let call_info = match world.analysis().call_info(position)? { let call_info = match snap.analysis().call_info(position)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
let concise = !world.config.call_info_full; let concise = !snap.config.call_info_full;
let mut active_parameter = call_info.active_parameter.map(|it| it as i64); let mut active_parameter = call_info.active_parameter.map(|it| it as i64);
if concise && call_info.signature.has_self_param { if concise && call_info.signature.has_self_param {
active_parameter = active_parameter.map(|it| it.saturating_sub(1)); active_parameter = active_parameter.map(|it| it.saturating_sub(1));
@ -535,14 +534,17 @@ pub fn handle_signature_help(
})) }))
} }
pub fn handle_hover(world: WorldSnapshot, params: lsp_types::HoverParams) -> Result<Option<Hover>> { pub fn handle_hover(
snap: GlobalStateSnapshot,
params: lsp_types::HoverParams,
) -> Result<Option<Hover>> {
let _p = profile("handle_hover"); let _p = profile("handle_hover");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let info = match world.analysis().hover(position)? { let info = match snap.analysis().hover(position)? {
None => return Ok(None), None => return Ok(None),
Some(info) => info, Some(info) => info,
}; };
let line_index = world.analysis.file_line_index(position.file_id)?; let line_index = snap.analysis.file_line_index(position.file_id)?;
let range = to_proto::range(&line_index, info.range); let range = to_proto::range(&line_index, info.range);
let res = Hover { let res = Hover {
contents: HoverContents::Markup(MarkupContent { contents: HoverContents::Markup(MarkupContent {
@ -555,26 +557,29 @@ pub fn handle_hover(world: WorldSnapshot, params: lsp_types::HoverParams) -> Res
} }
pub fn handle_prepare_rename( pub fn handle_prepare_rename(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams, params: lsp_types::TextDocumentPositionParams,
) -> Result<Option<PrepareRenameResponse>> { ) -> Result<Option<PrepareRenameResponse>> {
let _p = profile("handle_prepare_rename"); let _p = profile("handle_prepare_rename");
let position = from_proto::file_position(&world, params)?; let position = from_proto::file_position(&snap, params)?;
let optional_change = world.analysis().rename(position, "dummy")?; let optional_change = snap.analysis().rename(position, "dummy")?;
let range = match optional_change { let range = match optional_change {
None => return Ok(None), None => return Ok(None),
Some(it) => it.range, Some(it) => it.range,
}; };
let line_index = world.analysis().file_line_index(position.file_id)?; let line_index = snap.analysis().file_line_index(position.file_id)?;
let range = to_proto::range(&line_index, range); let range = to_proto::range(&line_index, range);
Ok(Some(PrepareRenameResponse::Range(range))) Ok(Some(PrepareRenameResponse::Range(range)))
} }
pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> { pub fn handle_rename(
snap: GlobalStateSnapshot,
params: RenameParams,
) -> Result<Option<WorkspaceEdit>> {
let _p = profile("handle_rename"); let _p = profile("handle_rename");
let position = from_proto::file_position(&world, params.text_document_position)?; let position = from_proto::file_position(&snap, params.text_document_position)?;
if params.new_name.is_empty() { if params.new_name.is_empty() {
return Err(LspError::new( return Err(LspError::new(
@ -584,36 +589,36 @@ pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Optio
.into()); .into());
} }
let optional_change = world.analysis().rename(position, &*params.new_name)?; let optional_change = snap.analysis().rename(position, &*params.new_name)?;
let source_change = match optional_change { let source_change = match optional_change {
None => return Ok(None), None => return Ok(None),
Some(it) => it.info, Some(it) => it.info,
}; };
let workspace_edit = to_proto::workspace_edit(&world, source_change)?; let workspace_edit = to_proto::workspace_edit(&snap, source_change)?;
Ok(Some(workspace_edit)) Ok(Some(workspace_edit))
} }
pub fn handle_references( pub fn handle_references(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::ReferenceParams, params: lsp_types::ReferenceParams,
) -> Result<Option<Vec<Location>>> { ) -> Result<Option<Vec<Location>>> {
let _p = profile("handle_references"); let _p = profile("handle_references");
let position = from_proto::file_position(&world, params.text_document_position)?; let position = from_proto::file_position(&snap, params.text_document_position)?;
let refs = match world.analysis().find_all_refs(position, None)? { let refs = match snap.analysis().find_all_refs(position, None)? {
None => return Ok(None), None => return Ok(None),
Some(refs) => refs, Some(refs) => refs,
}; };
let locations = if params.context.include_declaration { let locations = if params.context.include_declaration {
refs.into_iter() refs.into_iter()
.filter_map(|reference| to_proto::location(&world, reference.file_range).ok()) .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok())
.collect() .collect()
} else { } else {
// Only iterate over the references if include_declaration was false // Only iterate over the references if include_declaration was false
refs.references() refs.references()
.iter() .iter()
.filter_map(|reference| to_proto::location(&world, reference.file_range).ok()) .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok())
.collect() .collect()
}; };
@ -621,24 +626,24 @@ pub fn handle_references(
} }
pub fn handle_formatting( pub fn handle_formatting(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: DocumentFormattingParams, params: DocumentFormattingParams,
) -> Result<Option<Vec<lsp_types::TextEdit>>> { ) -> Result<Option<Vec<lsp_types::TextEdit>>> {
let _p = profile("handle_formatting"); let _p = profile("handle_formatting");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let file = world.analysis().file_text(file_id)?; let file = snap.analysis().file_text(file_id)?;
let crate_ids = world.analysis().crate_for(file_id)?; let crate_ids = snap.analysis().crate_for(file_id)?;
let file_line_index = world.analysis().file_line_index(file_id)?; let file_line_index = snap.analysis().file_line_index(file_id)?;
let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str()));
let mut rustfmt = match &world.config.rustfmt { let mut rustfmt = match &snap.config.rustfmt {
RustfmtConfig::Rustfmt { extra_args } => { RustfmtConfig::Rustfmt { extra_args } => {
let mut cmd = process::Command::new("rustfmt"); let mut cmd = process::Command::new("rustfmt");
cmd.args(extra_args); cmd.args(extra_args);
if let Some(&crate_id) = crate_ids.first() { if let Some(&crate_id) = crate_ids.first() {
// Assume all crates are in the same edition // Assume all crates are in the same edition
let edition = world.analysis().crate_edition(crate_id)?; let edition = snap.analysis().crate_edition(crate_id)?;
cmd.arg("--edition"); cmd.arg("--edition");
cmd.arg(edition.to_string()); cmd.arg(edition.to_string());
} }
@ -697,23 +702,23 @@ pub fn handle_formatting(
} }
pub fn handle_code_action( pub fn handle_code_action(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::CodeActionParams, params: lsp_types::CodeActionParams,
) -> Result<Option<Vec<lsp_ext::CodeAction>>> { ) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
let _p = profile("handle_code_action"); let _p = profile("handle_code_action");
// We intentionally don't support command-based actions, as those either // We intentionally don't support command-based actions, as those either
// requires custom client-code anyway, or requires server-initiated edits. // requires custom client-code anyway, or requires server-initiated edits.
// Server initiated edits break causality, so we avoid those as well. // Server initiated edits break causality, so we avoid those as well.
if !world.config.client_caps.code_action_literals { if !snap.config.client_caps.code_action_literals {
return Ok(None); return Ok(None);
} }
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let range = from_proto::text_range(&line_index, params.range); let range = from_proto::text_range(&line_index, params.range);
let frange = FileRange { file_id, range }; let frange = FileRange { file_id, range };
let diagnostics = world.analysis().diagnostics(file_id)?; let diagnostics = snap.analysis().diagnostics(file_id)?;
let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
let fixes_from_diagnostics = diagnostics let fixes_from_diagnostics = diagnostics
@ -724,13 +729,13 @@ pub fn handle_code_action(
for fix in fixes_from_diagnostics { for fix in fixes_from_diagnostics {
let title = fix.label; let title = fix.label;
let edit = to_proto::snippet_workspace_edit(&world, fix.source_change)?; let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
let action = let action =
lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None };
res.push(action); res.push(action);
} }
for fix in world.check_fixes.get(&file_id).into_iter().flatten() { for fix in snap.check_fixes.get(&file_id).into_iter().flatten() {
let fix_range = from_proto::text_range(&line_index, fix.range); let fix_range = from_proto::text_range(&line_index, fix.range);
if fix_range.intersect(range).is_none() { if fix_range.intersect(range).is_none() {
continue; continue;
@ -738,31 +743,31 @@ pub fn handle_code_action(
res.push(fix.action.clone()); res.push(fix.action.clone());
} }
for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() { for assist in snap.analysis().assists(&snap.config.assist, frange)?.into_iter() {
res.push(to_proto::code_action(&world, assist)?.into()); res.push(to_proto::code_action(&snap, assist)?.into());
} }
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_code_lens( pub fn handle_code_lens(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::CodeLensParams, params: lsp_types::CodeLensParams,
) -> Result<Option<Vec<CodeLens>>> { ) -> Result<Option<Vec<CodeLens>>> {
let _p = profile("handle_code_lens"); let _p = profile("handle_code_lens");
let mut lenses: Vec<CodeLens> = Default::default(); let mut lenses: Vec<CodeLens> = Default::default();
if world.config.lens.none() { if snap.config.lens.none() {
// early return before any db query! // early return before any db query!
return Ok(Some(lenses)); return Ok(Some(lenses));
} }
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
if world.config.lens.runnable() { if snap.config.lens.runnable() {
// Gather runnables // Gather runnables
for runnable in world.analysis().runnables(file_id)? { for runnable in snap.analysis().runnables(file_id)? {
let (run_title, debugee) = match &runnable.kind { let (run_title, debugee) = match &runnable.kind {
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => {
("\u{fe0e} Run Test", true) ("\u{fe0e} Run Test", true)
@ -788,8 +793,8 @@ pub fn handle_code_lens(
}; };
let range = to_proto::range(&line_index, runnable.nav.range()); let range = to_proto::range(&line_index, runnable.nav.range());
let r = to_proto::runnable(&world, file_id, runnable)?; let r = to_proto::runnable(&snap, file_id, runnable)?;
if world.config.lens.run { if snap.config.lens.run {
let lens = CodeLens { let lens = CodeLens {
range, range,
command: Some(Command { command: Some(Command {
@ -802,7 +807,7 @@ pub fn handle_code_lens(
lenses.push(lens); lenses.push(lens);
} }
if debugee && world.config.lens.debug { if debugee && snap.config.lens.debug {
let debug_lens = CodeLens { let debug_lens = CodeLens {
range, range,
command: Some(Command { command: Some(Command {
@ -817,11 +822,10 @@ pub fn handle_code_lens(
} }
} }
if world.config.lens.impementations { if snap.config.lens.impementations {
// Handle impls // Handle impls
lenses.extend( lenses.extend(
world snap.analysis()
.analysis()
.file_structure(file_id)? .file_structure(file_id)?
.into_iter() .into_iter()
.filter(|it| match it.kind { .filter(|it| match it.kind {
@ -856,14 +860,17 @@ enum CodeLensResolveData {
Impls(lsp_types::request::GotoImplementationParams), Impls(lsp_types::request::GotoImplementationParams),
} }
pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { pub fn handle_code_lens_resolve(
snap: GlobalStateSnapshot,
code_lens: CodeLens,
) -> Result<CodeLens> {
let _p = profile("handle_code_lens_resolve"); let _p = profile("handle_code_lens_resolve");
let data = code_lens.data.unwrap(); let data = code_lens.data.unwrap();
let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?; let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?;
match resolve { match resolve {
Some(CodeLensResolveData::Impls(lens_params)) => { Some(CodeLensResolveData::Impls(lens_params)) => {
let locations: Vec<Location> = let locations: Vec<Location> =
match handle_goto_implementation(world, lens_params.clone())? { match handle_goto_implementation(snap, lens_params.clone())? {
Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) => vec![loc], Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) => vec![loc],
Some(lsp_types::GotoDefinitionResponse::Array(locs)) => locs, Some(lsp_types::GotoDefinitionResponse::Array(locs)) => locs,
Some(lsp_types::GotoDefinitionResponse::Link(links)) => links Some(lsp_types::GotoDefinitionResponse::Link(links)) => links
@ -902,14 +909,14 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re
} }
pub fn handle_document_highlight( pub fn handle_document_highlight(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_types::DocumentHighlightParams, params: lsp_types::DocumentHighlightParams,
) -> Result<Option<Vec<DocumentHighlight>>> { ) -> Result<Option<Vec<DocumentHighlight>>> {
let _p = profile("handle_document_highlight"); let _p = profile("handle_document_highlight");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let line_index = world.analysis().file_line_index(position.file_id)?; let line_index = snap.analysis().file_line_index(position.file_id)?;
let refs = match world let refs = match snap
.analysis() .analysis()
.find_all_refs(position, Some(SearchScope::single_file(position.file_id)))? .find_all_refs(position, Some(SearchScope::single_file(position.file_id)))?
{ {
@ -929,19 +936,19 @@ pub fn handle_document_highlight(
} }
pub fn handle_ssr( pub fn handle_ssr(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::SsrParams, params: lsp_ext::SsrParams,
) -> Result<lsp_types::WorkspaceEdit> { ) -> Result<lsp_types::WorkspaceEdit> {
let _p = profile("handle_ssr"); let _p = profile("handle_ssr");
let source_change = let source_change =
world.analysis().structural_search_replace(&params.query, params.parse_only)??; snap.analysis().structural_search_replace(&params.query, params.parse_only)??;
to_proto::workspace_edit(&world, source_change) to_proto::workspace_edit(&snap, source_change)
} }
pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { pub fn publish_diagnostics(snap: &GlobalStateSnapshot, file_id: FileId) -> Result<DiagnosticTask> {
let _p = profile("publish_diagnostics"); let _p = profile("publish_diagnostics");
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let diagnostics: Vec<Diagnostic> = world let diagnostics: Vec<Diagnostic> = snap
.analysis() .analysis()
.diagnostics(file_id)? .diagnostics(file_id)?
.into_iter() .into_iter()
@ -959,28 +966,28 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia
} }
pub fn handle_inlay_hints( pub fn handle_inlay_hints(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: InlayHintsParams, params: InlayHintsParams,
) -> Result<Vec<InlayHint>> { ) -> Result<Vec<InlayHint>> {
let _p = profile("handle_inlay_hints"); let _p = profile("handle_inlay_hints");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let analysis = world.analysis(); let analysis = snap.analysis();
let line_index = analysis.file_line_index(file_id)?; let line_index = analysis.file_line_index(file_id)?;
Ok(analysis Ok(analysis
.inlay_hints(file_id, &world.config.inlay_hints)? .inlay_hints(file_id, &snap.config.inlay_hints)?
.into_iter() .into_iter()
.map(|it| to_proto::inlay_int(&line_index, it)) .map(|it| to_proto::inlay_int(&line_index, it))
.collect()) .collect())
} }
pub fn handle_call_hierarchy_prepare( pub fn handle_call_hierarchy_prepare(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: CallHierarchyPrepareParams, params: CallHierarchyPrepareParams,
) -> Result<Option<Vec<CallHierarchyItem>>> { ) -> Result<Option<Vec<CallHierarchyItem>>> {
let _p = profile("handle_call_hierarchy_prepare"); let _p = profile("handle_call_hierarchy_prepare");
let position = from_proto::file_position(&world, params.text_document_position_params)?; let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match world.analysis().call_hierarchy(position)? { let nav_info = match snap.analysis().call_hierarchy(position)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
@ -989,24 +996,24 @@ pub fn handle_call_hierarchy_prepare(
let res = navs let res = navs
.into_iter() .into_iter()
.filter(|it| it.kind() == SyntaxKind::FN_DEF) .filter(|it| it.kind() == SyntaxKind::FN_DEF)
.map(|it| to_proto::call_hierarchy_item(&world, it)) .map(|it| to_proto::call_hierarchy_item(&snap, it))
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
Ok(Some(res)) Ok(Some(res))
} }
pub fn handle_call_hierarchy_incoming( pub fn handle_call_hierarchy_incoming(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: CallHierarchyIncomingCallsParams, params: CallHierarchyIncomingCallsParams,
) -> Result<Option<Vec<CallHierarchyIncomingCall>>> { ) -> Result<Option<Vec<CallHierarchyIncomingCall>>> {
let _p = profile("handle_call_hierarchy_incoming"); let _p = profile("handle_call_hierarchy_incoming");
let item = params.item; let item = params.item;
let doc = TextDocumentIdentifier::new(item.uri); let doc = TextDocumentIdentifier::new(item.uri);
let frange = from_proto::file_range(&world, doc, item.range)?; let frange = from_proto::file_range(&snap, doc, item.range)?;
let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
let call_items = match world.analysis().incoming_calls(fpos)? { let call_items = match snap.analysis().incoming_calls(fpos)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
@ -1015,8 +1022,8 @@ pub fn handle_call_hierarchy_incoming(
for call_item in call_items.into_iter() { for call_item in call_items.into_iter() {
let file_id = call_item.target.file_id(); let file_id = call_item.target.file_id();
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let item = to_proto::call_hierarchy_item(&world, call_item.target)?; let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
res.push(CallHierarchyIncomingCall { res.push(CallHierarchyIncomingCall {
from: item, from: item,
from_ranges: call_item from_ranges: call_item
@ -1031,17 +1038,17 @@ pub fn handle_call_hierarchy_incoming(
} }
pub fn handle_call_hierarchy_outgoing( pub fn handle_call_hierarchy_outgoing(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: CallHierarchyOutgoingCallsParams, params: CallHierarchyOutgoingCallsParams,
) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> { ) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> {
let _p = profile("handle_call_hierarchy_outgoing"); let _p = profile("handle_call_hierarchy_outgoing");
let item = params.item; let item = params.item;
let doc = TextDocumentIdentifier::new(item.uri); let doc = TextDocumentIdentifier::new(item.uri);
let frange = from_proto::file_range(&world, doc, item.range)?; let frange = from_proto::file_range(&snap, doc, item.range)?;
let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
let call_items = match world.analysis().outgoing_calls(fpos)? { let call_items = match snap.analysis().outgoing_calls(fpos)? {
None => return Ok(None), None => return Ok(None),
Some(it) => it, Some(it) => it,
}; };
@ -1050,8 +1057,8 @@ pub fn handle_call_hierarchy_outgoing(
for call_item in call_items.into_iter() { for call_item in call_items.into_iter() {
let file_id = call_item.target.file_id(); let file_id = call_item.target.file_id();
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let item = to_proto::call_hierarchy_item(&world, call_item.target)?; let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
res.push(CallHierarchyOutgoingCall { res.push(CallHierarchyOutgoingCall {
to: item, to: item,
from_ranges: call_item from_ranges: call_item
@ -1066,31 +1073,31 @@ pub fn handle_call_hierarchy_outgoing(
} }
pub fn handle_semantic_tokens( pub fn handle_semantic_tokens(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: SemanticTokensParams, params: SemanticTokensParams,
) -> Result<Option<SemanticTokensResult>> { ) -> Result<Option<SemanticTokensResult>> {
let _p = profile("handle_semantic_tokens"); let _p = profile("handle_semantic_tokens");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?; let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let text = world.analysis().file_text(file_id)?; let text = snap.analysis().file_text(file_id)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = snap.analysis().file_line_index(file_id)?;
let highlights = world.analysis().highlight(file_id)?; let highlights = snap.analysis().highlight(file_id)?;
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
Ok(Some(semantic_tokens.into())) Ok(Some(semantic_tokens.into()))
} }
pub fn handle_semantic_tokens_range( pub fn handle_semantic_tokens_range(
world: WorldSnapshot, snap: GlobalStateSnapshot,
params: SemanticTokensRangeParams, params: SemanticTokensRangeParams,
) -> Result<Option<SemanticTokensRangeResult>> { ) -> Result<Option<SemanticTokensRangeResult>> {
let _p = profile("handle_semantic_tokens_range"); let _p = profile("handle_semantic_tokens_range");
let frange = from_proto::file_range(&world, params.text_document, params.range)?; let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
let text = world.analysis().file_text(frange.file_id)?; let text = snap.analysis().file_text(frange.file_id)?;
let line_index = world.analysis().file_line_index(frange.file_id)?; let line_index = snap.analysis().file_line_index(frange.file_id)?;
let highlights = world.analysis().highlight_range(frange)?; let highlights = snap.analysis().highlight_range(frange)?;
let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
Ok(Some(semantic_tokens.into())) Ok(Some(semantic_tokens.into()))
} }

View File

@ -10,7 +10,8 @@ use ra_syntax::{SyntaxKind, TextRange, TextSize};
use ra_vfs::LineEndings; use ra_vfs::LineEndings;
use crate::{ use crate::{
cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, lsp_ext,
semantic_tokens, Result,
}; };
pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
@ -384,41 +385,44 @@ pub(crate) fn folding_range(
} }
} }
pub(crate) fn url(world: &WorldSnapshot, file_id: FileId) -> Result<lsp_types::Url> { pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> Result<lsp_types::Url> {
world.file_id_to_uri(file_id) snap.file_id_to_uri(file_id)
} }
pub(crate) fn versioned_text_document_identifier( pub(crate) fn versioned_text_document_identifier(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
file_id: FileId, file_id: FileId,
version: Option<i64>, version: Option<i64>,
) -> Result<lsp_types::VersionedTextDocumentIdentifier> { ) -> Result<lsp_types::VersionedTextDocumentIdentifier> {
let res = lsp_types::VersionedTextDocumentIdentifier { uri: url(world, file_id)?, version }; let res = lsp_types::VersionedTextDocumentIdentifier { uri: url(snap, file_id)?, version };
Ok(res) Ok(res)
} }
pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result<lsp_types::Location> { pub(crate) fn location(
let url = url(world, frange.file_id)?; snap: &GlobalStateSnapshot,
let line_index = world.analysis().file_line_index(frange.file_id)?; frange: FileRange,
) -> Result<lsp_types::Location> {
let url = url(snap, frange.file_id)?;
let line_index = snap.analysis().file_line_index(frange.file_id)?;
let range = range(&line_index, frange.range); let range = range(&line_index, frange.range);
let loc = lsp_types::Location::new(url, range); let loc = lsp_types::Location::new(url, range);
Ok(loc) Ok(loc)
} }
pub(crate) fn location_link( pub(crate) fn location_link(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
src: Option<FileRange>, src: Option<FileRange>,
target: NavigationTarget, target: NavigationTarget,
) -> Result<lsp_types::LocationLink> { ) -> Result<lsp_types::LocationLink> {
let origin_selection_range = match src { let origin_selection_range = match src {
Some(src) => { Some(src) => {
let line_index = world.analysis().file_line_index(src.file_id)?; let line_index = snap.analysis().file_line_index(src.file_id)?;
let range = range(&line_index, src.range); let range = range(&line_index, src.range);
Some(range) Some(range)
} }
None => None, None => None,
}; };
let (target_uri, target_range, target_selection_range) = location_info(world, target)?; let (target_uri, target_range, target_selection_range) = location_info(snap, target)?;
let res = lsp_types::LocationLink { let res = lsp_types::LocationLink {
origin_selection_range, origin_selection_range,
target_uri, target_uri,
@ -429,12 +433,12 @@ pub(crate) fn location_link(
} }
fn location_info( fn location_info(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
target: NavigationTarget, target: NavigationTarget,
) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> {
let line_index = world.analysis().file_line_index(target.file_id())?; let line_index = snap.analysis().file_line_index(target.file_id())?;
let target_uri = url(world, target.file_id())?; let target_uri = url(snap, target.file_id())?;
let target_range = range(&line_index, target.full_range()); let target_range = range(&line_index, target.full_range());
let target_selection_range = let target_selection_range =
target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range); target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range);
@ -442,14 +446,14 @@ fn location_info(
} }
pub(crate) fn goto_definition_response( pub(crate) fn goto_definition_response(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
src: Option<FileRange>, src: Option<FileRange>,
targets: Vec<NavigationTarget>, targets: Vec<NavigationTarget>,
) -> Result<lsp_types::GotoDefinitionResponse> { ) -> Result<lsp_types::GotoDefinitionResponse> {
if world.config.client_caps.location_link { if snap.config.client_caps.location_link {
let links = targets let links = targets
.into_iter() .into_iter()
.map(|nav| location_link(world, src, nav)) .map(|nav| location_link(snap, src, nav))
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
Ok(links.into()) Ok(links.into())
} else { } else {
@ -457,7 +461,7 @@ pub(crate) fn goto_definition_response(
.into_iter() .into_iter()
.map(|nav| { .map(|nav| {
location( location(
world, snap,
FileRange { FileRange {
file_id: nav.file_id(), file_id: nav.file_id(),
range: nav.focus_range().unwrap_or(nav.range()), range: nav.focus_range().unwrap_or(nav.range()),
@ -470,13 +474,13 @@ pub(crate) fn goto_definition_response(
} }
pub(crate) fn snippet_text_document_edit( pub(crate) fn snippet_text_document_edit(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
is_snippet: bool, is_snippet: bool,
source_file_edit: SourceFileEdit, source_file_edit: SourceFileEdit,
) -> Result<lsp_ext::SnippetTextDocumentEdit> { ) -> Result<lsp_ext::SnippetTextDocumentEdit> {
let text_document = versioned_text_document_identifier(world, source_file_edit.file_id, None)?; let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None)?;
let line_index = world.analysis().file_line_index(source_file_edit.file_id)?; let line_index = snap.analysis().file_line_index(source_file_edit.file_id)?;
let line_endings = world.file_line_endings(source_file_edit.file_id); let line_endings = snap.file_line_endings(source_file_edit.file_id);
let edits = source_file_edit let edits = source_file_edit
.edit .edit
.into_iter() .into_iter()
@ -486,17 +490,17 @@ pub(crate) fn snippet_text_document_edit(
} }
pub(crate) fn resource_op( pub(crate) fn resource_op(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
file_system_edit: FileSystemEdit, file_system_edit: FileSystemEdit,
) -> Result<lsp_types::ResourceOp> { ) -> Result<lsp_types::ResourceOp> {
let res = match file_system_edit { let res = match file_system_edit {
FileSystemEdit::CreateFile { source_root, path } => { FileSystemEdit::CreateFile { source_root, path } => {
let uri = world.path_to_uri(source_root, &path)?; let uri = snap.path_to_uri(source_root, &path)?;
lsp_types::ResourceOp::Create(lsp_types::CreateFile { uri, options: None }) lsp_types::ResourceOp::Create(lsp_types::CreateFile { uri, options: None })
} }
FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => { FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => {
let old_uri = world.file_id_to_uri(src)?; let old_uri = snap.file_id_to_uri(src)?;
let new_uri = world.path_to_uri(dst_source_root, &dst_path)?; let new_uri = snap.path_to_uri(dst_source_root, &dst_path)?;
lsp_types::ResourceOp::Rename(lsp_types::RenameFile { old_uri, new_uri, options: None }) lsp_types::ResourceOp::Rename(lsp_types::RenameFile { old_uri, new_uri, options: None })
} }
}; };
@ -504,16 +508,16 @@ pub(crate) fn resource_op(
} }
pub(crate) fn snippet_workspace_edit( pub(crate) fn snippet_workspace_edit(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
source_change: SourceChange, source_change: SourceChange,
) -> Result<lsp_ext::SnippetWorkspaceEdit> { ) -> Result<lsp_ext::SnippetWorkspaceEdit> {
let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
for op in source_change.file_system_edits { for op in source_change.file_system_edits {
let op = resource_op(&world, op)?; let op = resource_op(&snap, op)?;
document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op));
} }
for edit in source_change.source_file_edits { for edit in source_change.source_file_edits {
let edit = snippet_text_document_edit(&world, source_change.is_snippet, edit)?; let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?;
document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
} }
let workspace_edit = let workspace_edit =
@ -522,11 +526,11 @@ pub(crate) fn snippet_workspace_edit(
} }
pub(crate) fn workspace_edit( pub(crate) fn workspace_edit(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
source_change: SourceChange, source_change: SourceChange,
) -> Result<lsp_types::WorkspaceEdit> { ) -> Result<lsp_types::WorkspaceEdit> {
assert!(!source_change.is_snippet); assert!(!source_change.is_snippet);
snippet_workspace_edit(world, source_change).map(|it| it.into()) snippet_workspace_edit(snap, source_change).map(|it| it.into())
} }
impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
@ -565,13 +569,13 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
} }
pub fn call_hierarchy_item( pub fn call_hierarchy_item(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
target: NavigationTarget, target: NavigationTarget,
) -> Result<lsp_types::CallHierarchyItem> { ) -> Result<lsp_types::CallHierarchyItem> {
let name = target.name().to_string(); let name = target.name().to_string();
let detail = target.description().map(|it| it.to_string()); let detail = target.description().map(|it| it.to_string());
let kind = symbol_kind(target.kind()); let kind = symbol_kind(target.kind());
let (uri, range, selection_range) = location_info(world, target)?; let (uri, range, selection_range) = location_info(snap, target)?;
Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range })
} }
@ -619,23 +623,26 @@ fn main() <fold>{
} }
} }
pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_ext::CodeAction> { pub(crate) fn code_action(
snap: &GlobalStateSnapshot,
assist: Assist,
) -> Result<lsp_ext::CodeAction> {
let res = lsp_ext::CodeAction { let res = lsp_ext::CodeAction {
title: assist.label, title: assist.label,
group: if world.config.client_caps.code_action_group { assist.group_label } else { None }, group: if snap.config.client_caps.code_action_group { assist.group_label } else { None },
kind: Some(String::new()), kind: Some(String::new()),
edit: Some(snippet_workspace_edit(world, assist.source_change)?), edit: Some(snippet_workspace_edit(snap, assist.source_change)?),
command: None, command: None,
}; };
Ok(res) Ok(res)
} }
pub(crate) fn runnable( pub(crate) fn runnable(
world: &WorldSnapshot, snap: &GlobalStateSnapshot,
file_id: FileId, file_id: FileId,
runnable: Runnable, runnable: Runnable,
) -> Result<lsp_ext::Runnable> { ) -> Result<lsp_ext::Runnable> {
let spec = CargoTargetSpec::for_file(world, file_id)?; let spec = CargoTargetSpec::for_file(snap, file_id)?;
let target = spec.as_ref().map(|s| s.target.clone()); let target = spec.as_ref().map(|s| s.target.clone());
let (cargo_args, executable_args) = let (cargo_args, executable_args) =
CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?;
@ -648,14 +655,14 @@ pub(crate) fn runnable(
target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t))
} }
}; };
let location = location_link(world, None, runnable.nav)?; let location = location_link(snap, None, runnable.nav)?;
Ok(lsp_ext::Runnable { Ok(lsp_ext::Runnable {
label, label,
location: Some(location), location: Some(location),
kind: lsp_ext::RunnableKind::Cargo, kind: lsp_ext::RunnableKind::Cargo,
args: lsp_ext::CargoRunnable { args: lsp_ext::CargoRunnable {
workspace_root: world.workspace_root_for(file_id).map(|root| root.to_owned()), workspace_root: snap.workspace_root_for(file_id).map(|root| root.to_owned()),
cargo_args, cargo_args,
executable_args, executable_args,
}, },