4724: Rename WorldState -> GlobalState r=matklad a=matklad



bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-06-03 09:20:30 +00:00 committed by GitHub
commit 992e1256d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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_project_model::{self, ProjectWorkspace, TargetKind};
use crate::{world::WorldSnapshot, Result};
use crate::{global_state::GlobalStateSnapshot, Result};
/// Abstract representation of Cargo target.
///
@ -89,7 +89,7 @@ impl CargoTargetSpec {
}
pub(crate) fn for_file(
world: &WorldSnapshot,
world: &GlobalStateSnapshot,
file_id: FileId,
) -> Result<Option<CargoTargetSpec>> {
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_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 {
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)
}
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)
}
pub(crate) fn file_position(
world: &WorldSnapshot,
world: &GlobalStateSnapshot,
tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> {
let file_id = file_id(world, &tdpp.text_document.uri)?;
@ -31,7 +31,7 @@ pub(crate) fn file_position(
}
pub(crate) fn file_range(
world: &WorldSnapshot,
world: &GlobalStateSnapshot,
text_document_identifier: lsp_types::TextDocumentIdentifier,
range: lsp_types::Range,
) -> 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
/// snapshot of the file systems, and `analysis_host`, which stores our
/// incremental salsa database.
#[derive(Debug)]
pub struct WorldState {
pub struct GlobalState {
pub config: Config,
pub local_roots: Vec<PathBuf>,
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.
pub struct WorldSnapshot {
pub struct GlobalStateSnapshot {
pub config: Config,
pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis: Analysis,
@ -79,14 +79,14 @@ pub struct WorldSnapshot {
vfs: Arc<RwLock<Vfs>>,
}
impl WorldState {
impl GlobalState {
pub fn new(
workspaces: Vec<ProjectWorkspace>,
lru_capacity: Option<usize>,
exclude_globs: &[Glob],
watch: Watch,
config: Config,
) -> WorldState {
) -> GlobalState {
let mut change = AnalysisChange::new();
let extern_dirs: FxHashSet<_> =
@ -180,7 +180,7 @@ impl WorldState {
let mut analysis_host = AnalysisHost::new(lru_capacity);
analysis_host.apply_change(change);
WorldState {
GlobalState {
config,
local_roots,
workspaces: Arc::new(workspaces),
@ -255,8 +255,8 @@ impl WorldState {
self.analysis_host.apply_change(change);
}
pub fn snapshot(&self) -> WorldSnapshot {
WorldSnapshot {
pub fn snapshot(&self) -> GlobalStateSnapshot {
GlobalStateSnapshot {
config: self.config.clone(),
workspaces: Arc::clone(&self.workspaces),
analysis: self.analysis_host.analysis(),
@ -279,7 +279,7 @@ impl WorldState {
}
}
impl WorldSnapshot {
impl GlobalStateSnapshot {
pub fn analysis(&self) -> &Analysis {
&self.analysis
}

View File

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

View File

@ -38,12 +38,13 @@ use threadpool::ThreadPool;
use crate::{
config::{Config, FilesWatcher},
diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask},
from_proto, lsp_ext,
from_proto,
global_state::{GlobalState, GlobalStateSnapshot},
lsp_ext,
main_loop::{
pending_requests::{PendingRequest, PendingRequests},
subscriptions::Subscriptions,
},
world::{WorldSnapshot, WorldState},
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 world_state = {
let mut global_state = {
let workspaces = {
// FIXME: support dynamic workspace loading.
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();
}
WorldState::new(
GlobalState::new(
workspaces,
config.lru_capacity,
&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 (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()),
},
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),
Err(RecvError) => return Err("vfs died".into()),
},
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),
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,
&libdata_sender,
&connection,
&mut world_state,
&mut global_state,
&mut loop_state,
event,
)?;
}
}
world_state.analysis_host.request_cancellation();
global_state.analysis_host.request_cancellation();
log::info!("waiting for tasks to finish...");
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);
log::info!("...tasks have finished");
@ -228,7 +229,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
drop(pool);
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);
Ok(())
@ -319,7 +320,7 @@ fn loop_turn(
task_sender: &Sender<Task>,
libdata_sender: &Sender<LibraryData>,
connection: &Connection,
world_state: &mut WorldState,
global_state: &mut GlobalState,
loop_state: &mut LoopState,
event: Event,
) -> Result<()> {
@ -335,22 +336,22 @@ fn loop_turn(
match event {
Event::Task(task) => {
on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state);
world_state.maybe_collect_garbage();
on_task(task, &connection.sender, &mut loop_state.pending_requests, global_state);
global_state.maybe_collect_garbage();
}
Event::Vfs(task) => {
world_state.vfs.write().handle_task(task);
global_state.vfs.write().handle_task(task);
}
Event::Lib(lib) => {
world_state.add_lib(lib);
world_state.maybe_collect_garbage();
global_state.add_lib(lib);
global_state.maybe_collect_garbage();
loop_state.in_flight_libraries -= 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 {
Message::Request(req) => on_request(
world_state,
global_state,
&mut loop_state.pending_requests,
pool,
task_sender,
@ -359,7 +360,7 @@ fn loop_turn(
req,
)?,
Message::Notification(not) => {
on_notification(&connection.sender, world_state, loop_state, not)?;
on_notification(&connection.sender, global_state, loop_state, not)?;
}
Message::Response(resp) => {
let removed = loop_state.pending_responses.remove(&resp.id);
@ -378,9 +379,9 @@ fn loop_turn(
}
(None, Some(configs)) => {
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);
world_state.update_configuration(config);
global_state.update_configuration(config);
}
}
(None, None) => {
@ -393,7 +394,7 @@ fn loop_turn(
};
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;
loop_state.pending_libraries.extend(changes);
}
@ -415,7 +416,7 @@ fn loop_turn(
}
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
&& loop_state.roots_scanned == loop_state.roots_total
@ -424,7 +425,7 @@ fn loop_turn(
{
state_changed = true;
loop_state.workspace_loaded = true;
if let Some(flycheck) = &world_state.flycheck {
if let Some(flycheck) = &global_state.flycheck {
flycheck.update();
}
}
@ -436,13 +437,13 @@ fn loop_turn(
if state_changed && loop_state.workspace_loaded {
update_file_notifications_on_threadpool(
pool,
world_state.snapshot(),
global_state.snapshot(),
task_sender.clone(),
loop_state.subscriptions.subscriptions(),
);
pool.execute({
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| ())
});
}
@ -466,7 +467,7 @@ fn on_task(
task: Task,
msg_sender: &Sender<Message>,
pending_requests: &mut PendingRequests,
state: &mut WorldState,
state: &mut GlobalState,
) {
match task {
Task::Respond(response) => {
@ -484,7 +485,7 @@ fn on_task(
}
fn on_request(
world: &mut WorldState,
global_state: &mut GlobalState,
pending_requests: &mut PendingRequests,
pool: &ThreadPool,
task_sender: &Sender<Task>,
@ -495,7 +496,7 @@ fn on_request(
let mut pool_dispatcher = PoolDispatcher {
req: Some(req),
pool,
world,
global_state,
task_sender,
msg_sender,
pending_requests,
@ -551,7 +552,7 @@ fn on_request(
fn on_notification(
msg_sender: &Sender<Message>,
state: &mut WorldState,
state: &mut GlobalState,
loop_state: &mut LoopState,
not: Notification,
) -> Result<()> {
@ -725,7 +726,7 @@ fn apply_document_changes(
fn on_check_task(
task: CheckTask,
world_state: &mut WorldState,
global_state: &mut GlobalState,
task_sender: &Sender<Task>,
) -> Result<()> {
match task {
@ -744,7 +745,7 @@ fn on_check_task(
.uri
.to_file_path()
.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),
None => {
log::error!(
@ -764,7 +765,7 @@ fn on_check_task(
}
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 {
Status::Being => {
lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
@ -803,7 +804,7 @@ fn on_check_task(
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);
for file_id in subscriptions {
@ -878,7 +879,7 @@ fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
struct PoolDispatcher<'a> {
req: Option<Request>,
pool: &'a ThreadPool,
world: &'a mut WorldState,
global_state: &'a mut GlobalState,
pending_requests: &'a mut PendingRequests,
msg_sender: &'a Sender<Message>,
task_sender: &'a Sender<Task>,
@ -889,7 +890,7 @@ impl<'a> PoolDispatcher<'a> {
/// Dispatches the request onto the current thread
fn on_sync<R>(
&mut self,
f: fn(&mut WorldState, R::Params) -> Result<R::Result>,
f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
) -> Result<&mut Self>
where
R: lsp_types::request::Request + 'static,
@ -902,18 +903,21 @@ impl<'a> PoolDispatcher<'a> {
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 result = f(world.0, params);
result_to_task::<R>(id, result)
})
.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)
}
/// 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
R: lsp_types::request::Request + 'static,
R::Params: DeserializeOwned + Send + 'static,
@ -927,7 +931,7 @@ impl<'a> PoolDispatcher<'a> {
};
self.pool.execute({
let world = self.world.snapshot();
let world = self.global_state.snapshot();
let sender = self.task_sender.clone();
move || {
let result = f(world, params);
@ -1011,7 +1015,7 @@ where
fn update_file_notifications_on_threadpool(
pool: &ThreadPool,
world: WorldSnapshot,
world: GlobalStateSnapshot,
task_sender: Sender<Task>,
subscriptions: Vec<FileId>,
) {

View File

@ -32,17 +32,16 @@ use crate::{
config::RustfmtConfig,
diagnostics::DiagnosticTask,
from_json, from_proto,
global_state::GlobalStateSnapshot,
lsp_ext::{self, InlayHint, InlayHintsParams},
to_proto,
world::WorldSnapshot,
LspError, Result,
to_proto, 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 mut buf = world.status();
let mut buf = snap.status();
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() {
let mark = if is_last { "*" } else { " " };
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(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_ext::SyntaxTreeParams,
) -> Result<String> {
let _p = profile("handle_syntax_tree");
let id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(id)?;
let id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(id)?;
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)
}
pub fn handle_expand_macro(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_ext::ExpandMacroParams,
) -> Result<Option<lsp_ext::ExpandedMacro>> {
let _p = profile("handle_expand_macro");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
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 }))
}
pub fn handle_selection_range(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::SelectionRangeParams,
) -> Result<Option<Vec<lsp_types::SelectionRange>>> {
let _p = profile("handle_selection_range");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let res: Result<Vec<lsp_types::SelectionRange>> = params
.positions
.into_iter()
@ -93,7 +92,7 @@ pub fn handle_selection_range(
loop {
ranges.push(range);
let frange = FileRange { file_id, range };
let next = world.analysis().extend_selection(frange)?;
let next = snap.analysis().extend_selection(frange)?;
if next == range {
break;
} else {
@ -119,18 +118,18 @@ pub fn handle_selection_range(
}
pub fn handle_matching_brace(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_ext::MatchingBraceParams,
) -> Result<Vec<Position>> {
let _p = profile("handle_matching_brace");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let res = params
.positions
.into_iter()
.map(|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,
Err(_) | Ok(None) => offset,
};
@ -141,17 +140,17 @@ pub fn handle_matching_brace(
}
pub fn handle_join_lines(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_ext::JoinLinesParams,
) -> Result<Vec<lsp_types::TextEdit>> {
let _p = profile("handle_join_lines");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let line_endings = world.file_line_endings(file_id);
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let line_endings = snap.file_line_endings(file_id);
let mut res = TextEdit::default();
for range in params.ranges {
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) {
Ok(()) => (),
Err(_edit) => {
@ -164,37 +163,37 @@ pub fn handle_join_lines(
}
pub fn handle_on_enter(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams,
) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
let _p = profile("handle_on_enter");
let position = from_proto::file_position(&world, params)?;
let edit = match world.analysis().on_enter(position)? {
let position = from_proto::file_position(&snap, params)?;
let edit = match snap.analysis().on_enter(position)? {
None => return Ok(None),
Some(it) => it,
};
let line_index = world.analysis().file_line_index(position.file_id)?;
let line_endings = world.file_line_endings(position.file_id);
let line_index = snap.analysis().file_line_index(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);
Ok(Some(edit))
}
// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
pub fn handle_on_type_formatting(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::DocumentOnTypeFormattingParams,
) -> Result<Option<Vec<lsp_types::TextEdit>>> {
let _p = profile("handle_on_type_formatting");
let mut position = from_proto::file_position(&world, params.text_document_position)?;
let line_index = world.analysis().file_line_index(position.file_id)?;
let line_endings = world.file_line_endings(position.file_id);
let mut position = from_proto::file_position(&snap, params.text_document_position)?;
let line_index = snap.analysis().file_line_index(position.file_id)?;
let line_endings = snap.file_line_endings(position.file_id);
// in `ra_ide`, the `on_type` invariant is that
// `text.char_at(position) == typed_char`.
position.offset -= TextSize::of('.');
let char_typed = params.ch.chars().next().unwrap_or('\0');
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)
});
@ -206,7 +205,7 @@ pub fn handle_on_type_formatting(
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 {
Some(it) => it,
None => return Ok(None),
@ -220,16 +219,16 @@ pub fn handle_on_type_formatting(
}
pub fn handle_document_symbol(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::DocumentSymbolParams,
) -> Result<Option<lsp_types::DocumentSymbolResponse>> {
let _p = profile("handle_document_symbol");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
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 {
name: symbol.label,
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()
} else {
let url = to_proto::url(&world, file_id)?;
let url = to_proto::url(&snap, file_id)?;
let mut symbol_information = Vec::<SymbolInformation>::new();
for symbol in document_symbols {
flatten_document_symbol(&symbol, None, &url, &mut symbol_information);
@ -288,7 +287,7 @@ pub fn handle_document_symbol(
}
pub fn handle_workspace_symbol(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::WorkspaceSymbolParams,
) -> Result<Option<Vec<SymbolInformation>>> {
let _p = profile("handle_workspace_symbol");
@ -306,22 +305,22 @@ pub fn handle_workspace_symbol(
q.limit(128);
q
};
let mut res = exec_query(&world, query)?;
let mut res = exec_query(&snap, query)?;
if res.is_empty() && !all_symbols {
let mut query = Query::new(params.query);
query.limit(128);
res = exec_query(&world, query)?;
res = exec_query(&snap, query)?;
}
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();
for nav in world.analysis().symbol_search(query)? {
for nav in snap.analysis().symbol_search(query)? {
let info = SymbolInformation {
name: nav.name().to_string(),
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()),
deprecated: None,
};
@ -332,73 +331,73 @@ pub fn handle_workspace_symbol(
}
pub fn handle_goto_definition(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::GotoDefinitionParams,
) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
let _p = profile("handle_goto_definition");
let position = from_proto::file_position(&world, params.text_document_position_params)?;
let nav_info = match world.analysis().goto_definition(position)? {
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match snap.analysis().goto_definition(position)? {
None => return Ok(None),
Some(it) => it,
};
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))
}
pub fn handle_goto_implementation(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::request::GotoImplementationParams,
) -> Result<Option<lsp_types::request::GotoImplementationResponse>> {
let _p = profile("handle_goto_implementation");
let position = from_proto::file_position(&world, params.text_document_position_params)?;
let nav_info = match world.analysis().goto_implementation(position)? {
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match snap.analysis().goto_implementation(position)? {
None => return Ok(None),
Some(it) => it,
};
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))
}
pub fn handle_goto_type_definition(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::request::GotoTypeDefinitionParams,
) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
let _p = profile("handle_goto_type_definition");
let position = from_proto::file_position(&world, params.text_document_position_params)?;
let nav_info = match world.analysis().goto_type_definition(position)? {
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let nav_info = match snap.analysis().goto_type_definition(position)? {
None => return Ok(None),
Some(it) => it,
};
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))
}
pub fn handle_parent_module(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams,
) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
let _p = profile("handle_parent_module");
let position = from_proto::file_position(&world, params)?;
let navs = world.analysis().parent_module(position)?;
let res = to_proto::goto_definition_response(&world, None, navs)?;
let position = from_proto::file_position(&snap, params)?;
let navs = snap.analysis().parent_module(position)?;
let res = to_proto::goto_definition_response(&snap, None, navs)?;
Ok(Some(res))
}
pub fn handle_runnables(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_ext::RunnablesParams,
) -> Result<Vec<lsp_ext::Runnable>> {
let _p = profile("handle_runnables");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let offset = params.position.map(|it| from_proto::offset(&line_index, it));
let mut res = Vec::new();
let workspace_root = world.workspace_root_for(file_id);
let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?;
for runnable in world.analysis().runnables(file_id)? {
let workspace_root = snap.workspace_root_for(file_id);
let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
for runnable in snap.analysis().runnables(file_id)? {
if let Some(offset) = offset {
if !runnable.nav.full_range().contains_inclusive(offset) {
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
@ -453,16 +452,16 @@ pub fn handle_runnables(
}
pub fn handle_completion(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::CompletionParams,
) -> Result<Option<lsp_types::CompletionResponse>> {
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 mut res = false;
if let Some(ctx) = params.context {
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 text = syntax.text();
if let Some(next_char) = text.char_at(position.offset) {
@ -480,12 +479,12 @@ pub fn handle_completion(
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),
Some(items) => items,
};
let line_index = world.analysis().file_line_index(position.file_id)?;
let line_endings = world.file_line_endings(position.file_id);
let line_index = snap.analysis().file_line_index(position.file_id)?;
let line_endings = snap.file_line_endings(position.file_id);
let items: Vec<CompletionItem> = items
.into_iter()
.map(|item| to_proto::completion_item(&line_index, line_endings, item))
@ -495,15 +494,15 @@ pub fn handle_completion(
}
pub fn handle_folding_range(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: FoldingRangeParams,
) -> Result<Option<Vec<FoldingRange>>> {
let _p = profile("handle_folding_range");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let folds = world.analysis().folding_ranges(file_id)?;
let text = world.analysis().file_text(file_id)?;
let line_index = world.analysis().file_line_index(file_id)?;
let line_folding_only = world.config.client_caps.line_folding_only;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let folds = snap.analysis().folding_ranges(file_id)?;
let text = snap.analysis().file_text(file_id)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let line_folding_only = snap.config.client_caps.line_folding_only;
let res = folds
.into_iter()
.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(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::SignatureHelpParams,
) -> Result<Option<lsp_types::SignatureHelp>> {
let _p = profile("handle_signature_help");
let position = from_proto::file_position(&world, params.text_document_position_params)?;
let call_info = match world.analysis().call_info(position)? {
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let call_info = match snap.analysis().call_info(position)? {
None => return Ok(None),
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);
if concise && call_info.signature.has_self_param {
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 position = from_proto::file_position(&world, params.text_document_position_params)?;
let info = match world.analysis().hover(position)? {
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let info = match snap.analysis().hover(position)? {
None => return Ok(None),
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 res = Hover {
contents: HoverContents::Markup(MarkupContent {
@ -555,26 +557,29 @@ pub fn handle_hover(world: WorldSnapshot, params: lsp_types::HoverParams) -> Res
}
pub fn handle_prepare_rename(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::TextDocumentPositionParams,
) -> Result<Option<PrepareRenameResponse>> {
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 {
None => return Ok(None),
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);
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 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() {
return Err(LspError::new(
@ -584,36 +589,36 @@ pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Optio
.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 {
None => return Ok(None),
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))
}
pub fn handle_references(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::ReferenceParams,
) -> Result<Option<Vec<Location>>> {
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),
Some(refs) => refs,
};
let locations = if params.context.include_declaration {
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()
} else {
// Only iterate over the references if include_declaration was false
refs.references()
.iter()
.filter_map(|reference| to_proto::location(&world, reference.file_range).ok())
.filter_map(|reference| to_proto::location(&snap, reference.file_range).ok())
.collect()
};
@ -621,24 +626,24 @@ pub fn handle_references(
}
pub fn handle_formatting(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: DocumentFormattingParams,
) -> Result<Option<Vec<lsp_types::TextEdit>>> {
let _p = profile("handle_formatting");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let file = world.analysis().file_text(file_id)?;
let crate_ids = world.analysis().crate_for(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let file = snap.analysis().file_text(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 mut rustfmt = match &world.config.rustfmt {
let mut rustfmt = match &snap.config.rustfmt {
RustfmtConfig::Rustfmt { extra_args } => {
let mut cmd = process::Command::new("rustfmt");
cmd.args(extra_args);
if let Some(&crate_id) = crate_ids.first() {
// 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.to_string());
}
@ -697,23 +702,23 @@ pub fn handle_formatting(
}
pub fn handle_code_action(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::CodeActionParams,
) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
let _p = profile("handle_code_action");
// We intentionally don't support command-based actions, as those either
// requires custom client-code anyway, or requires server-initiated edits.
// 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);
}
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let range = from_proto::text_range(&line_index, params.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 fixes_from_diagnostics = diagnostics
@ -724,13 +729,13 @@ pub fn handle_code_action(
for fix in fixes_from_diagnostics {
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 =
lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None };
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);
if fix_range.intersect(range).is_none() {
continue;
@ -738,31 +743,31 @@ pub fn handle_code_action(
res.push(fix.action.clone());
}
for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() {
res.push(to_proto::code_action(&world, assist)?.into());
for assist in snap.analysis().assists(&snap.config.assist, frange)?.into_iter() {
res.push(to_proto::code_action(&snap, assist)?.into());
}
Ok(Some(res))
}
pub fn handle_code_lens(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::CodeLensParams,
) -> Result<Option<Vec<CodeLens>>> {
let _p = profile("handle_code_lens");
let mut lenses: Vec<CodeLens> = Default::default();
if world.config.lens.none() {
if snap.config.lens.none() {
// early return before any db query!
return Ok(Some(lenses));
}
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let line_index = world.analysis().file_line_index(file_id)?;
let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
if world.config.lens.runnable() {
if snap.config.lens.runnable() {
// 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 {
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => {
("\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 r = to_proto::runnable(&world, file_id, runnable)?;
if world.config.lens.run {
let r = to_proto::runnable(&snap, file_id, runnable)?;
if snap.config.lens.run {
let lens = CodeLens {
range,
command: Some(Command {
@ -802,7 +807,7 @@ pub fn handle_code_lens(
lenses.push(lens);
}
if debugee && world.config.lens.debug {
if debugee && snap.config.lens.debug {
let debug_lens = CodeLens {
range,
command: Some(Command {
@ -817,11 +822,10 @@ pub fn handle_code_lens(
}
}
if world.config.lens.impementations {
if snap.config.lens.impementations {
// Handle impls
lenses.extend(
world
.analysis()
snap.analysis()
.file_structure(file_id)?
.into_iter()
.filter(|it| match it.kind {
@ -856,14 +860,17 @@ enum CodeLensResolveData {
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 data = code_lens.data.unwrap();
let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?;
match resolve {
Some(CodeLensResolveData::Impls(lens_params)) => {
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::Array(locs)) => locs,
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(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_types::DocumentHighlightParams,
) -> Result<Option<Vec<DocumentHighlight>>> {
let _p = profile("handle_document_highlight");
let position = from_proto::file_position(&world, params.text_document_position_params)?;
let line_index = world.analysis().file_line_index(position.file_id)?;
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let line_index = snap.analysis().file_line_index(position.file_id)?;
let refs = match world
let refs = match snap
.analysis()
.find_all_refs(position, Some(SearchScope::single_file(position.file_id)))?
{
@ -929,19 +936,19 @@ pub fn handle_document_highlight(
}
pub fn handle_ssr(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: lsp_ext::SsrParams,
) -> Result<lsp_types::WorkspaceEdit> {
let _p = profile("handle_ssr");
let source_change =
world.analysis().structural_search_replace(&params.query, params.parse_only)??;
to_proto::workspace_edit(&world, source_change)
snap.analysis().structural_search_replace(&params.query, params.parse_only)??;
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 line_index = world.analysis().file_line_index(file_id)?;
let diagnostics: Vec<Diagnostic> = world
let line_index = snap.analysis().file_line_index(file_id)?;
let diagnostics: Vec<Diagnostic> = snap
.analysis()
.diagnostics(file_id)?
.into_iter()
@ -959,28 +966,28 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia
}
pub fn handle_inlay_hints(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: InlayHintsParams,
) -> Result<Vec<InlayHint>> {
let _p = profile("handle_inlay_hints");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let analysis = world.analysis();
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let analysis = snap.analysis();
let line_index = analysis.file_line_index(file_id)?;
Ok(analysis
.inlay_hints(file_id, &world.config.inlay_hints)?
.inlay_hints(file_id, &snap.config.inlay_hints)?
.into_iter()
.map(|it| to_proto::inlay_int(&line_index, it))
.collect())
}
pub fn handle_call_hierarchy_prepare(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: CallHierarchyPrepareParams,
) -> Result<Option<Vec<CallHierarchyItem>>> {
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),
Some(it) => it,
};
@ -989,24 +996,24 @@ pub fn handle_call_hierarchy_prepare(
let res = navs
.into_iter()
.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<_>>>()?;
Ok(Some(res))
}
pub fn handle_call_hierarchy_incoming(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: CallHierarchyIncomingCallsParams,
) -> Result<Option<Vec<CallHierarchyIncomingCall>>> {
let _p = profile("handle_call_hierarchy_incoming");
let item = params.item;
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 call_items = match world.analysis().incoming_calls(fpos)? {
let call_items = match snap.analysis().incoming_calls(fpos)? {
None => return Ok(None),
Some(it) => it,
};
@ -1015,8 +1022,8 @@ pub fn handle_call_hierarchy_incoming(
for call_item in call_items.into_iter() {
let file_id = call_item.target.file_id();
let line_index = world.analysis().file_line_index(file_id)?;
let item = to_proto::call_hierarchy_item(&world, call_item.target)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
res.push(CallHierarchyIncomingCall {
from: item,
from_ranges: call_item
@ -1031,17 +1038,17 @@ pub fn handle_call_hierarchy_incoming(
}
pub fn handle_call_hierarchy_outgoing(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: CallHierarchyOutgoingCallsParams,
) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> {
let _p = profile("handle_call_hierarchy_outgoing");
let item = params.item;
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 call_items = match world.analysis().outgoing_calls(fpos)? {
let call_items = match snap.analysis().outgoing_calls(fpos)? {
None => return Ok(None),
Some(it) => it,
};
@ -1050,8 +1057,8 @@ pub fn handle_call_hierarchy_outgoing(
for call_item in call_items.into_iter() {
let file_id = call_item.target.file_id();
let line_index = world.analysis().file_line_index(file_id)?;
let item = to_proto::call_hierarchy_item(&world, call_item.target)?;
let line_index = snap.analysis().file_line_index(file_id)?;
let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
res.push(CallHierarchyOutgoingCall {
to: item,
from_ranges: call_item
@ -1066,31 +1073,31 @@ pub fn handle_call_hierarchy_outgoing(
}
pub fn handle_semantic_tokens(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: SemanticTokensParams,
) -> Result<Option<SemanticTokensResult>> {
let _p = profile("handle_semantic_tokens");
let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
let text = world.analysis().file_text(file_id)?;
let line_index = world.analysis().file_line_index(file_id)?;
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let text = snap.analysis().file_text(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);
Ok(Some(semantic_tokens.into()))
}
pub fn handle_semantic_tokens_range(
world: WorldSnapshot,
snap: GlobalStateSnapshot,
params: SemanticTokensRangeParams,
) -> Result<Option<SemanticTokensRangeResult>> {
let _p = profile("handle_semantic_tokens_range");
let frange = from_proto::file_range(&world, params.text_document, params.range)?;
let text = world.analysis().file_text(frange.file_id)?;
let line_index = world.analysis().file_line_index(frange.file_id)?;
let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
let text = snap.analysis().file_text(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);
Ok(Some(semantic_tokens.into()))
}

View File

@ -10,7 +10,8 @@ use ra_syntax::{SyntaxKind, TextRange, TextSize};
use ra_vfs::LineEndings;
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 {
@ -384,41 +385,44 @@ pub(crate) fn folding_range(
}
}
pub(crate) fn url(world: &WorldSnapshot, file_id: FileId) -> Result<lsp_types::Url> {
world.file_id_to_uri(file_id)
pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> Result<lsp_types::Url> {
snap.file_id_to_uri(file_id)
}
pub(crate) fn versioned_text_document_identifier(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
file_id: FileId,
version: Option<i64>,
) -> 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)
}
pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result<lsp_types::Location> {
let url = url(world, frange.file_id)?;
let line_index = world.analysis().file_line_index(frange.file_id)?;
pub(crate) fn location(
snap: &GlobalStateSnapshot,
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 loc = lsp_types::Location::new(url, range);
Ok(loc)
}
pub(crate) fn location_link(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
src: Option<FileRange>,
target: NavigationTarget,
) -> Result<lsp_types::LocationLink> {
let origin_selection_range = match 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);
Some(range)
}
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 {
origin_selection_range,
target_uri,
@ -429,12 +433,12 @@ pub(crate) fn location_link(
}
fn location_info(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
target: NavigationTarget,
) -> 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_selection_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(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
src: Option<FileRange>,
targets: Vec<NavigationTarget>,
) -> Result<lsp_types::GotoDefinitionResponse> {
if world.config.client_caps.location_link {
if snap.config.client_caps.location_link {
let links = targets
.into_iter()
.map(|nav| location_link(world, src, nav))
.map(|nav| location_link(snap, src, nav))
.collect::<Result<Vec<_>>>()?;
Ok(links.into())
} else {
@ -457,7 +461,7 @@ pub(crate) fn goto_definition_response(
.into_iter()
.map(|nav| {
location(
world,
snap,
FileRange {
file_id: nav.file_id(),
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(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
is_snippet: bool,
source_file_edit: SourceFileEdit,
) -> Result<lsp_ext::SnippetTextDocumentEdit> {
let text_document = versioned_text_document_identifier(world, source_file_edit.file_id, None)?;
let line_index = world.analysis().file_line_index(source_file_edit.file_id)?;
let line_endings = world.file_line_endings(source_file_edit.file_id);
let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None)?;
let line_index = snap.analysis().file_line_index(source_file_edit.file_id)?;
let line_endings = snap.file_line_endings(source_file_edit.file_id);
let edits = source_file_edit
.edit
.into_iter()
@ -486,17 +490,17 @@ pub(crate) fn snippet_text_document_edit(
}
pub(crate) fn resource_op(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
file_system_edit: FileSystemEdit,
) -> Result<lsp_types::ResourceOp> {
let res = match file_system_edit {
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 })
}
FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => {
let old_uri = world.file_id_to_uri(src)?;
let new_uri = world.path_to_uri(dst_source_root, &dst_path)?;
let old_uri = snap.file_id_to_uri(src)?;
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 })
}
};
@ -504,16 +508,16 @@ pub(crate) fn resource_op(
}
pub(crate) fn snippet_workspace_edit(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
source_change: SourceChange,
) -> Result<lsp_ext::SnippetWorkspaceEdit> {
let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
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));
}
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));
}
let workspace_edit =
@ -522,11 +526,11 @@ pub(crate) fn snippet_workspace_edit(
}
pub(crate) fn workspace_edit(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
source_change: SourceChange,
) -> Result<lsp_types::WorkspaceEdit> {
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 {
@ -565,13 +569,13 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
}
pub fn call_hierarchy_item(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
target: NavigationTarget,
) -> Result<lsp_types::CallHierarchyItem> {
let name = target.name().to_string();
let detail = target.description().map(|it| it.to_string());
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 })
}
@ -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 {
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()),
edit: Some(snippet_workspace_edit(world, assist.source_change)?),
edit: Some(snippet_workspace_edit(snap, assist.source_change)?),
command: None,
};
Ok(res)
}
pub(crate) fn runnable(
world: &WorldSnapshot,
snap: &GlobalStateSnapshot,
file_id: FileId,
runnable: 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 (cargo_args, executable_args) =
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))
}
};
let location = location_link(world, None, runnable.nav)?;
let location = location_link(snap, None, runnable.nav)?;
Ok(lsp_ext::Runnable {
label,
location: Some(location),
kind: lsp_ext::RunnableKind::Cargo,
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,
executable_args,
},