fix(els): minor bugs

This commit is contained in:
Shunsuke Shibayama 2024-02-26 11:42:19 +09:00
parent f612340e80
commit 46610a1ae0
7 changed files with 55 additions and 18 deletions

View file

@ -588,7 +588,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
});
let Some(mod_ctx) = self.get_mod_ctx(&uri) else {
_log!(self, "module context not found: {uri}");
return Ok(None);
return Ok(Some(CompletionResponse::Array(result)));
};
for (name, vi) in contexts.into_iter().flat_map(|ctx| ctx.local_dir()) {
if comp_kind.should_be_method() && vi.vis.is_private() {

View file

@ -86,6 +86,7 @@ impl FileCache {
pub fn clear(&self) {
self.files.borrow_mut().clear();
self.editing.borrow_mut().clear();
}
fn load_once(&self, uri: &NormalizedUrl) -> ELSResult<()> {

View file

@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::time::Duration;
use erg_common::config::ErgConfig;
use erg_common::consts::PYTHON_MODE;
@ -748,7 +749,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
}
}
},
fn_name!(),
R::METHOD,
);
}
@ -873,9 +874,13 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
Some(MappedRwLockReadGuard::map(ent, |ent| &ent.module))
}
pub(crate) fn get_raw_mod_ctx(&self, uri: &NormalizedUrl) -> Option<&ModuleContext> {
pub(crate) fn get_raw_mod_ctx(
&self,
uri: &NormalizedUrl,
timeout: std::time::Duration,
) -> Option<&ModuleContext> {
let path = uri.to_file_path().ok()?;
self.shared.raw_ref_ctx(&path)
self.shared.raw_ref_ctx_with_timeout(&path, timeout)
}
/// TODO: Reuse cache.
@ -934,7 +939,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
pub(crate) fn get_local_ctx(&self, uri: &NormalizedUrl, pos: Position) -> Vec<&Context> {
let mut ctxs = vec![];
if let Some(mod_ctx) = self.get_raw_mod_ctx(uri) {
if let Some(mod_ctx) = self.get_raw_mod_ctx(uri, Duration::from_millis(100)) {
if let Some(visitor) = self.get_visitor(uri) {
// FIXME:
let mut ns = visitor.get_namespace(pos);
@ -972,6 +977,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
ctxs
}
/// the ctx of `uri` is not included
pub(crate) fn get_neighbor_ctxs(&self, uri: &NormalizedUrl) -> Vec<&Context> {
let mut ctxs = vec![];
if let Ok(dir) = uri
@ -982,8 +988,13 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
let Ok(neighbor) = neighbor else {
continue;
};
let uri = NormalizedUrl::from_file_path(neighbor.path()).unwrap();
if let Some(mod_ctx) = self.get_raw_mod_ctx(&uri) {
let neighbor_uri = NormalizedUrl::from_file_path(neighbor.path()).unwrap();
if &neighbor_uri == uri {
continue;
}
if let Some(mod_ctx) =
self.get_raw_mod_ctx(&neighbor_uri, Duration::from_millis(50))
{
ctxs.push(&mod_ctx.context);
}
}
@ -996,7 +1007,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
uri: &NormalizedUrl,
attr_marker_pos: Position,
) -> ELSResult<(Option<Type>, Vec<&Context>)> {
let Some(module) = self.get_raw_mod_ctx(uri) else {
let Some(module) = self.get_raw_mod_ctx(uri, Duration::from_millis(100)) else {
return Ok((None, vec![]));
};
let maybe_token = self.file_cache.get_receiver(uri, attr_marker_pos);

View file

@ -46,7 +46,7 @@ fn test_completion() -> Result<(), Box<dyn std::error::Error>> {
assert!(items.len() >= 40);
assert!(items.iter().any(|item| item.label == "abs"));
} else {
return Err(format!("not items: {resp:?}").into());
return Err(format!("{}: not items: {resp:?}", line!()).into());
}
client.notify_open(FILE_B)?;
client.notify_change(uri_b.clone().raw(), add_char(6, 20, "."))?;
@ -54,7 +54,7 @@ fn test_completion() -> Result<(), Box<dyn std::error::Error>> {
if let Some(CompletionResponse::Array(items)) = resp {
assert!(items.iter().any(|item| item.label == "a"));
} else {
return Err(format!("not items: {resp:?}").into());
return Err(format!("{}: not items: {resp:?}", line!()).into());
}
Ok(())
}
@ -142,7 +142,7 @@ fn test_completion_retrigger() -> Result<(), Box<dyn std::error::Error>> {
assert!(!items.is_empty());
assert!(items.iter().any(|item| item.label == "print!"));
} else {
return Err(format!("not items: {resp:?}").into());
return Err(format!("{}: not items: {resp:?}", line!()).into());
}
client.notify_change(uri.clone().raw(), add_char(3, 15, "t"))?;
let resp = client.request_completion(uri.raw(), 3, 15, "t")?;
@ -151,7 +151,7 @@ fn test_completion_retrigger() -> Result<(), Box<dyn std::error::Error>> {
assert!(items.iter().any(|item| item.label == "bit_count"));
assert!(items.iter().any(|item| item.label == "bit_length"));
} else {
return Err(format!("not items: {resp:?}").into());
return Err(format!("{}: not items: {resp:?}", line!()).into());
}
Ok(())
}
@ -170,7 +170,7 @@ fn test_tolerant_completion() -> Result<(), Box<dyn std::error::Error>> {
assert!(items.len() >= 40);
assert!(items.iter().any(|item| item.label == "capitalize"));
} else {
return Err(format!("not items: {resp:?}").into());
return Err(format!("{}: not items: {resp:?}", line!()).into());
}
client.notify_change(uri.clone().raw(), add_char(5, 14, "."))?;
let resp = client.request_completion(uri.clone().raw(), 5, 15, ".")?;
@ -178,7 +178,7 @@ fn test_tolerant_completion() -> Result<(), Box<dyn std::error::Error>> {
assert!(items.len() >= 40);
assert!(items.iter().any(|item| item.label == "abs"));
} else {
return Err(format!("not items: {resp:?}").into());
return Err(format!("{}: not items: {resp:?}", line!()).into());
}
client.notify_change(uri.clone().raw(), add_char(2, 9, "."))?;
let resp = client.request_completion(uri.raw(), 2, 10, ".")?;
@ -187,7 +187,7 @@ fn test_tolerant_completion() -> Result<(), Box<dyn std::error::Error>> {
assert!(items.iter().any(|item| item.label == "pi"));
Ok(())
} else {
Err(format!("not items: {resp:?}").into())
Err(format!("{}: not items: {resp:?}", line!()).into())
}
}

View file

@ -258,6 +258,14 @@ impl<T: ?Sized> Shared<T> {
self.data.try_write()
}
pub fn try_borrow_for(&self, timeout: Duration) -> Option<RwLockReadGuard<'_, T>> {
self.data.try_read_for(timeout)
}
pub fn try_borrow_mut_for(&self, timeout: Duration) -> Option<RwLockWriteGuard<'_, T>> {
self.data.try_write_for(timeout)
}
/// # Safety
/// don't call this except you need to handle cyclic references.
pub unsafe fn force_unlock_write(&self) {

View file

@ -289,6 +289,19 @@ impl SharedModuleCache {
ref_.get(path).map(|entry| &entry.module)
}
pub fn raw_ref_ctx_with_timeout<Q: Eq + Hash + ?Sized>(
&self,
path: &Q,
timeout: std::time::Duration,
) -> Option<&ModuleContext>
where
NormalizedPathBuf: Borrow<Q>,
{
let _ref = self.0.try_borrow_for(timeout)?;
let ref_ = unsafe { self.0.as_ptr().as_ref().unwrap() };
ref_.get(path).map(|entry| &entry.module)
}
// HACK: <builtins> is referenced very frequently and mutable references are not taken,
// so it can be take without lock.
pub fn raw_ref_builtins_ctx(&self) -> Option<&ModuleContext> {

View file

@ -142,11 +142,15 @@ impl SharedCompilerResource {
}
}
pub fn raw_ref_ctx(&self, path: &std::path::Path) -> Option<&ModuleContext> {
pub fn raw_ref_ctx_with_timeout(
&self,
path: &std::path::Path,
timeout: std::time::Duration,
) -> Option<&ModuleContext> {
if path.to_string_lossy().ends_with(".d.er") {
self.py_mod_cache.raw_ref_ctx(path)
self.py_mod_cache.raw_ref_ctx_with_timeout(path, timeout)
} else {
self.mod_cache.raw_ref_ctx(path)
self.mod_cache.raw_ref_ctx_with_timeout(path, timeout)
}
}