mirror of
https://github.com/tweag/nickel.git
synced 2024-10-04 23:27:15 +03:00
quick and dirty fix of lsp error when position is None (#773)
* try to manage items without position in the lsp * fix `linearisation::Completed::elem_at` and some code cleaning Co-authored-by: Yann Hamdaoui <yann.hamdaoui@gmail.com>
This commit is contained in:
parent
e66f8c62f2
commit
ce1afa2c10
@ -81,7 +81,7 @@ impl Building {
|
|||||||
let id = self.id_gen().get_and_advance();
|
let id = self.id_gen().get_and_advance();
|
||||||
self.push(LinearizationItem {
|
self.push(LinearizationItem {
|
||||||
id,
|
id,
|
||||||
pos: ident.pos.unwrap(),
|
pos: ident.pos,
|
||||||
// temporary, the actual type is resolved later and the item retyped
|
// temporary, the actual type is resolved later and the item retyped
|
||||||
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
||||||
kind: TermKind::RecordField {
|
kind: TermKind::RecordField {
|
||||||
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use codespan::ByteIndex;
|
use codespan::ByteIndex;
|
||||||
use nickel_lang::{
|
use nickel_lang::{
|
||||||
|
position::TermPos,
|
||||||
term::MetaValue,
|
term::MetaValue,
|
||||||
typecheck::linearization::{LinearizationState, Scope},
|
typecheck::linearization::{LinearizationState, Scope},
|
||||||
};
|
};
|
||||||
@ -80,21 +81,31 @@ impl Completed {
|
|||||||
) -> Option<&LinearizationItem<Resolved>> {
|
) -> Option<&LinearizationItem<Resolved>> {
|
||||||
let (file_id, start) = locator;
|
let (file_id, start) = locator;
|
||||||
let linearization = &self.linearization;
|
let linearization = &self.linearization;
|
||||||
let item = match linearization
|
let item = match linearization.binary_search_by(|item| {
|
||||||
.binary_search_by_key(locator, |item| (item.pos.src_id, item.pos.start))
|
item.pos
|
||||||
{
|
.as_opt_ref()
|
||||||
|
.map(|pos| (pos.src_id, pos.start).cmp(locator))
|
||||||
|
.unwrap_or(std::cmp::Ordering::Less)
|
||||||
|
}) {
|
||||||
// Found item(s) starting at `locator`
|
// Found item(s) starting at `locator`
|
||||||
// search for most precise element
|
// search for most precise element
|
||||||
Ok(index) => linearization[index..]
|
Ok(index) => linearization[index..]
|
||||||
.iter()
|
.iter()
|
||||||
.take_while(|item| (item.pos.src_id, item.pos.start) == *locator)
|
.take_while(|item| {
|
||||||
|
// Here because None is smaller than everything, if binary search succeeds,
|
||||||
|
// we can safely unwrap the position.
|
||||||
|
let pos = item.pos.unwrap();
|
||||||
|
(pos.src_id, pos.start) == *locator
|
||||||
|
})
|
||||||
.last(),
|
.last(),
|
||||||
// No perfect match found
|
// No perfect match found
|
||||||
// iterate back finding the first wrapping linearization item
|
// iterate back finding the first wrapping linearization item
|
||||||
Err(index) => linearization[..index].iter().rfind(|item| {
|
Err(index) => linearization[..index].iter().rfind(|item| {
|
||||||
let (istart, iend, ifile) = (item.pos.start, item.pos.end, item.pos.src_id);
|
item.pos
|
||||||
|
.as_opt_ref()
|
||||||
file_id == &ifile && start > &istart && start < &iend
|
.map(|pos| file_id == &pos.src_id && start > &pos.start && start < &pos.end)
|
||||||
|
// if the item found is None, we can not find a better one.
|
||||||
|
.unwrap_or(true)
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
item
|
item
|
||||||
|
@ -35,7 +35,7 @@ pub type Environment = nickel_lang::environment::Environment<Ident, usize>;
|
|||||||
pub struct LinearizationItem<S: ResolutionState> {
|
pub struct LinearizationItem<S: ResolutionState> {
|
||||||
//term_: Box<Term>,
|
//term_: Box<Term>,
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub pos: RawSpan,
|
pub pos: TermPos,
|
||||||
pub ty: S,
|
pub ty: S,
|
||||||
pub kind: TermKind,
|
pub kind: TermKind,
|
||||||
pub scope: Scope,
|
pub scope: Scope,
|
||||||
@ -171,7 +171,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
id: id_gen.get_and_advance(),
|
id: id_gen.get_and_advance(),
|
||||||
|
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
pos: ident.pos.clone().unwrap(),
|
pos: ident.pos.clone(),
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Structure,
|
kind: TermKind::Structure,
|
||||||
meta: self.meta.take(),
|
meta: self.meta.take(),
|
||||||
@ -187,7 +187,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
lin.push(LinearizationItem {
|
lin.push(LinearizationItem {
|
||||||
id,
|
id,
|
||||||
ty,
|
ty,
|
||||||
pos: ident.pos.unwrap(),
|
pos: ident.pos,
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Declaration(ident.to_owned(), Vec::new(), value_ptr),
|
kind: TermKind::Declaration(ident.to_owned(), Vec::new(), value_ptr),
|
||||||
meta: None,
|
meta: None,
|
||||||
@ -201,7 +201,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
id,
|
id,
|
||||||
// TODO: get type from pattern
|
// TODO: get type from pattern
|
||||||
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
||||||
pos: ident.pos.unwrap(),
|
pos: ident.pos,
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Declaration(
|
kind: TermKind::Declaration(
|
||||||
ident.to_owned(),
|
ident.to_owned(),
|
||||||
@ -230,7 +230,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
id: id_gen.get_and_advance(),
|
id: id_gen.get_and_advance(),
|
||||||
|
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
pos: ident.pos.clone().unwrap(),
|
pos: ident.pos.clone(),
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Structure,
|
kind: TermKind::Structure,
|
||||||
meta: self.meta.take(),
|
meta: self.meta.take(),
|
||||||
@ -244,7 +244,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
lin.push(LinearizationItem {
|
lin.push(LinearizationItem {
|
||||||
id: id_gen.get(),
|
id: id_gen.get(),
|
||||||
ty,
|
ty,
|
||||||
pos: ident.pos.unwrap(),
|
pos: ident.pos,
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Declaration(ident.to_owned(), Vec::new(), value_ptr),
|
kind: TermKind::Declaration(ident.to_owned(), Vec::new(), value_ptr),
|
||||||
meta: self.meta.take(),
|
meta: self.meta.take(),
|
||||||
@ -260,7 +260,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
|
|
||||||
lin.push(LinearizationItem {
|
lin.push(LinearizationItem {
|
||||||
id: root_id,
|
id: root_id,
|
||||||
pos: ident.pos.unwrap(),
|
pos: ident.pos,
|
||||||
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Usage(UsageState::from(self.env.get(ident))),
|
kind: TermKind::Usage(UsageState::from(self.env.get(ident))),
|
||||||
@ -278,7 +278,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
let id = id_gen.get_and_advance();
|
let id = id_gen.get_and_advance();
|
||||||
lin.push(LinearizationItem {
|
lin.push(LinearizationItem {
|
||||||
id,
|
id,
|
||||||
pos: accessor.pos.unwrap(),
|
pos: accessor.pos,
|
||||||
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
ty: TypeWrapper::Concrete(AbsType::Dyn()),
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Usage(UsageState::Deferred {
|
kind: TermKind::Usage(UsageState::Deferred {
|
||||||
@ -293,7 +293,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
Term::Record(fields, _) | Term::RecRecord(fields, ..) => {
|
Term::Record(fields, _) | Term::RecRecord(fields, ..) => {
|
||||||
lin.push(LinearizationItem {
|
lin.push(LinearizationItem {
|
||||||
id,
|
id,
|
||||||
pos: pos.unwrap(),
|
pos: pos,
|
||||||
ty,
|
ty,
|
||||||
kind: TermKind::Record(HashMap::new()),
|
kind: TermKind::Record(HashMap::new()),
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
@ -395,7 +395,7 @@ impl Linearizer for AnalysisHost {
|
|||||||
|
|
||||||
lin.push(LinearizationItem {
|
lin.push(LinearizationItem {
|
||||||
id,
|
id,
|
||||||
pos: pos.unwrap(),
|
pos: pos,
|
||||||
ty,
|
ty,
|
||||||
scope: self.scope.clone(),
|
scope: self.scope.clone(),
|
||||||
kind: TermKind::Structure,
|
kind: TermKind::Structure,
|
||||||
@ -437,7 +437,16 @@ impl Linearizer for AnalysisHost {
|
|||||||
scope,
|
scope,
|
||||||
} = lin.into_inner();
|
} = lin.into_inner();
|
||||||
|
|
||||||
linearization.sort_by_key(|item| (item.pos.src_id, item.pos.start));
|
linearization.sort_by(
|
||||||
|
|it1, it2| match (it1.pos.as_opt_ref(), it2.pos.as_opt_ref()) {
|
||||||
|
(None, None) => std::cmp::Ordering::Equal,
|
||||||
|
(None, _) => std::cmp::Ordering::Less,
|
||||||
|
(_, None) => std::cmp::Ordering::Greater,
|
||||||
|
(Some(pos1), Some(pos2)) => {
|
||||||
|
(pos1.src_id, pos1.start).cmp(&(pos2.src_id, pos2.start))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// create an index of id -> new position
|
// create an index of id -> new position
|
||||||
let mut id_mapping = HashMap::new();
|
let mut id_mapping = HashMap::new();
|
||||||
|
@ -5,7 +5,7 @@ use lsp_server::{RequestId, Response, ResponseError};
|
|||||||
use lsp_types::{
|
use lsp_types::{
|
||||||
GotoDefinitionParams, GotoDefinitionResponse, Location, Range, ReferenceParams, Url,
|
GotoDefinitionParams, GotoDefinitionResponse, Location, Range, ReferenceParams, Url,
|
||||||
};
|
};
|
||||||
use nickel_lang::position::RawSpan;
|
use nickel_lang::position::{RawSpan, TermPos};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -57,7 +57,7 @@ pub fn handle_to_definition(
|
|||||||
let location = match item.kind {
|
let location = match item.kind {
|
||||||
TermKind::Usage(UsageState::Resolved(usage_id)) => {
|
TermKind::Usage(UsageState::Resolved(usage_id)) => {
|
||||||
let definition = linearization.get_item(usage_id).unwrap();
|
let definition = linearization.get_item(usage_id).unwrap();
|
||||||
let location = match definition.pos {
|
let location = match definition.pos.unwrap() {
|
||||||
RawSpan {
|
RawSpan {
|
||||||
start: ByteIndex(start),
|
start: ByteIndex(start),
|
||||||
end: ByteIndex(end),
|
end: ByteIndex(end),
|
||||||
@ -117,30 +117,27 @@ pub fn handle_to_usages(
|
|||||||
|
|
||||||
debug!("found referencing item: {:?}", item);
|
debug!("found referencing item: {:?}", item);
|
||||||
|
|
||||||
let locations = match &item.kind {
|
let locations: Option<Vec<Location>> = match &item.kind {
|
||||||
TermKind::Declaration(_, usages, _) | TermKind::RecordField { usages, .. } => {
|
TermKind::Declaration(_, usages, _) | TermKind::RecordField { usages, .. } => Some(
|
||||||
let mut locations = Vec::new();
|
usages
|
||||||
|
.iter()
|
||||||
for reference_id in usages.iter() {
|
.filter_map(|reference_id| {
|
||||||
let reference = linearization.get_item(*reference_id).unwrap();
|
linearization
|
||||||
let location = match reference.pos {
|
.get_item(*reference_id)
|
||||||
RawSpan {
|
.unwrap()
|
||||||
start: ByteIndex(start),
|
.pos
|
||||||
end: ByteIndex(end),
|
.as_opt_ref()
|
||||||
src_id,
|
.map(|RawSpan { start, end, src_id }| Location {
|
||||||
} => Location {
|
uri: Url::parse(&server.cache.name(*src_id).to_string_lossy()).unwrap(),
|
||||||
uri: Url::parse(&server.cache.name(src_id).to_string_lossy()).unwrap(),
|
range: Range::from_codespan(
|
||||||
range: Range::from_codespan(
|
src_id,
|
||||||
&src_id,
|
&((*start).into()..(*end).into()),
|
||||||
&(start as usize..end as usize),
|
server.cache.files(),
|
||||||
server.cache.files(),
|
),
|
||||||
),
|
})
|
||||||
},
|
})
|
||||||
};
|
.collect(),
|
||||||
locations.push(location);
|
),
|
||||||
}
|
|
||||||
Some(locations)
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use codespan_lsp::position_to_byte_index;
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use lsp_server::{RequestId, Response, ResponseError};
|
use lsp_server::{RequestId, Response, ResponseError};
|
||||||
use lsp_types::{Hover, HoverContents, HoverParams, LanguageString, MarkedString, Range};
|
use lsp_types::{Hover, HoverContents, HoverParams, LanguageString, MarkedString, Range};
|
||||||
|
use nickel_lang::position::TermPos;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -54,9 +55,14 @@ pub fn handle(
|
|||||||
|
|
||||||
let (ty, meta) = linearization.resolve_item_type_meta(&item);
|
let (ty, meta) = linearization.resolve_item_type_meta(&item);
|
||||||
|
|
||||||
|
if item.pos == TermPos::None {
|
||||||
|
server.reply(Response::new_ok(id, Value::Null));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let pos = item.pos.unwrap();
|
||||||
let range = Range::from_codespan(
|
let range = Range::from_codespan(
|
||||||
&file_id,
|
&file_id,
|
||||||
&(item.pos.start.to_usize()..item.pos.end.to_usize()),
|
&(pos.start.to_usize()..pos.end.to_usize()),
|
||||||
server.cache.files(),
|
server.cache.files(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@ pub fn handle_document_symbols(
|
|||||||
.iter()
|
.iter()
|
||||||
.filter_map(|item| match &item.kind {
|
.filter_map(|item| match &item.kind {
|
||||||
TermKind::Declaration(name, _, _) => {
|
TermKind::Declaration(name, _, _) => {
|
||||||
let (file_id, span) = item.pos.to_range();
|
// TODO: can `unwrap` fail here?
|
||||||
|
let (file_id, span) = item.pos.unwrap().to_range();
|
||||||
|
|
||||||
let range =
|
let range =
|
||||||
codespan_lsp::byte_span_to_range(server.cache.files(), file_id, span)
|
codespan_lsp::byte_span_to_range(server.cache.files(), file_id, span)
|
||||||
|
Loading…
Reference in New Issue
Block a user