mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 12:14:43 +00:00
fix(els): file operation bugs
This commit is contained in:
parent
863f1f2fdb
commit
6c665157bc
6 changed files with 73 additions and 70 deletions
|
@ -59,7 +59,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
character: range.end.character + 1,
|
||||
},
|
||||
};
|
||||
let code = util::get_ranged_code_from_uri(&uri, next)?;
|
||||
let code = self.file_cache.get_ranged(&uri, next)?;
|
||||
match code.as_ref().map(|s| &s[..]) {
|
||||
None => {
|
||||
// \n
|
||||
|
|
|
@ -18,7 +18,7 @@ use erg_compiler::erg_parser::token::{Token, TokenStream};
|
|||
use crate::server::ELSResult;
|
||||
use crate::util::{self, NormalizedUrl};
|
||||
|
||||
pub fn _get_code_from_uri(uri: &Url) -> ELSResult<String> {
|
||||
fn _get_code_from_uri(uri: &Url) -> ELSResult<String> {
|
||||
let path = uri
|
||||
.to_file_path()
|
||||
.or_else(|_| util::denormalize(uri.clone()).to_file_path())
|
||||
|
@ -152,6 +152,43 @@ impl FileCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_line(&self, uri: &NormalizedUrl, line: u32) -> Option<&str> {
|
||||
self.get(uri).ok().and_then(|ent| ent.get_line(line))
|
||||
}
|
||||
|
||||
pub(crate) fn get_ranged(
|
||||
&self,
|
||||
uri: &NormalizedUrl,
|
||||
range: Range,
|
||||
) -> ELSResult<Option<String>> {
|
||||
let file = self.get(uri)?;
|
||||
let mut code = String::new();
|
||||
for (i, line) in file.code.lines().enumerate() {
|
||||
if i >= range.start.line as usize && i <= range.end.line as usize {
|
||||
if i == range.start.line as usize && i == range.end.line as usize {
|
||||
if line.len() < range.end.character as usize {
|
||||
return Ok(None);
|
||||
}
|
||||
code.push_str(
|
||||
&line[range.start.character as usize..range.end.character as usize],
|
||||
);
|
||||
} else if i == range.start.line as usize {
|
||||
code.push_str(&line[range.start.character as usize..]);
|
||||
code.push('\n');
|
||||
} else if i == range.end.line as usize {
|
||||
if line.len() < range.end.character as usize {
|
||||
return Ok(None);
|
||||
}
|
||||
code.push_str(&line[..range.end.character as usize]);
|
||||
} else {
|
||||
code.push_str(line);
|
||||
code.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(code))
|
||||
}
|
||||
|
||||
pub(crate) fn update(&self, uri: &NormalizedUrl, code: String, ver: Option<i32>) {
|
||||
let entry = unsafe { self.files.as_ref() }.get(uri);
|
||||
if let Some(entry) = entry {
|
||||
|
|
|
@ -5,6 +5,7 @@ use erg_compiler::hir::*;
|
|||
use erg_compiler::varinfo::VarInfo;
|
||||
use lsp_types::Position;
|
||||
|
||||
use crate::file_cache::FileCache;
|
||||
use crate::util::{self, NormalizedUrl};
|
||||
|
||||
/// This struct provides:
|
||||
|
@ -13,16 +14,18 @@ use crate::util::{self, NormalizedUrl};
|
|||
/// * cursor(`Token`) -> `VarInfo` mapping (`get_info`)
|
||||
pub struct HIRVisitor<'a> {
|
||||
hir: &'a HIR,
|
||||
file_cache: &'a FileCache,
|
||||
uri: NormalizedUrl,
|
||||
strict_cmp: bool,
|
||||
}
|
||||
|
||||
impl<'a> HIRVisitor<'a> {
|
||||
pub fn new(hir: &'a HIR, uri: NormalizedUrl, strict_cmp: bool) -> Self {
|
||||
pub fn new(hir: &'a HIR, file_cache: &'a FileCache, uri: NormalizedUrl) -> Self {
|
||||
Self {
|
||||
hir,
|
||||
file_cache,
|
||||
uri,
|
||||
strict_cmp,
|
||||
strict_cmp: !cfg!(feature = "py_compat"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,10 +49,16 @@ impl<'a> HIRVisitor<'a> {
|
|||
|
||||
fn is_new_final_line(&self, chunk: &Expr, pos: Position) -> bool {
|
||||
let ln_end = chunk.ln_end().unwrap_or(0);
|
||||
let line = util::get_line_from_uri(&self.uri, ln_end).unwrap();
|
||||
let line = self
|
||||
.file_cache
|
||||
.get_line(&self.uri, ln_end)
|
||||
.unwrap_or_default();
|
||||
let indent_len = line.len() - line.trim_start_matches(' ').len();
|
||||
let cond = ln_end == pos.line && pos.character as usize == indent_len + 1;
|
||||
matches!(chunk, Expr::Call(_) | Expr::Lambda(_) | Expr::Def(_) | Expr::ClassDef(_) if cond)
|
||||
cond && matches!(
|
||||
chunk,
|
||||
Expr::Call(_) | Expr::Lambda(_) | Expr::Def(_) | Expr::ClassDef(_)
|
||||
)
|
||||
}
|
||||
|
||||
fn get_expr_ns(&self, cur_ns: Vec<Str>, chunk: &Expr, pos: Position) -> Option<Vec<Str>> {
|
||||
|
|
|
@ -129,7 +129,12 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
};
|
||||
// display the definition line
|
||||
if vi.kind.is_defined() {
|
||||
code_block += util::get_line_from_path(file_path, line)?.trim_start();
|
||||
let uri = NormalizedUrl::try_from(file_path.as_path())?;
|
||||
code_block += self
|
||||
.file_cache
|
||||
.get_line(&uri, line)
|
||||
.unwrap_or_default()
|
||||
.trim_start();
|
||||
match code_block.chars().last() {
|
||||
Some('=' | '>') => {
|
||||
code_block += " ...";
|
||||
|
|
|
@ -541,7 +541,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
.get(uri)?
|
||||
.object
|
||||
.as_ref()
|
||||
.map(|hir| HIRVisitor::new(hir, uri.clone(), !cfg!(feature = "py_compat")))
|
||||
.map(|hir| HIRVisitor::new(hir, &self.file_cache, uri.clone()))
|
||||
}
|
||||
|
||||
pub(crate) fn get_local_ctx(&self, uri: &NormalizedUrl, pos: Position) -> Vec<&Context> {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Read};
|
||||
use std::path::Path;
|
||||
use std::fs::{metadata, Metadata};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use erg_common::normalize_path;
|
||||
use erg_common::traits::{DequeStream, Locational};
|
||||
|
@ -10,7 +9,6 @@ use erg_compiler::erg_parser::token::{Token, TokenStream};
|
|||
|
||||
use lsp_types::{Position, Range, Url};
|
||||
|
||||
use crate::file_cache::_get_code_from_uri;
|
||||
use crate::server::ELSResult;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -60,13 +58,13 @@ impl NormalizedUrl {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn loc_to_range(loc: erg_common::error::Location) -> Option<Range> {
|
||||
pub(crate) fn loc_to_range(loc: erg_common::error::Location) -> Option<Range> {
|
||||
let start = Position::new(loc.ln_begin()?.saturating_sub(1), loc.col_begin()?);
|
||||
let end = Position::new(loc.ln_end()?.saturating_sub(1), loc.col_end()?);
|
||||
Some(Range::new(start, end))
|
||||
}
|
||||
|
||||
pub fn loc_to_pos(loc: erg_common::error::Location) -> Option<Position> {
|
||||
pub(crate) fn loc_to_pos(loc: erg_common::error::Location) -> Option<Position> {
|
||||
// FIXME: should `Position::new(loc.ln_begin()? - 1, loc.col_begin()?)`
|
||||
// but completion doesn't work (because the newline will be included)
|
||||
let start = Position::new(loc.ln_begin()?.saturating_sub(1), loc.col_begin()? + 1);
|
||||
|
@ -82,7 +80,7 @@ pub fn _pos_to_loc(pos: Position) -> erg_common::error::Location {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn pos_in_loc<L: Locational>(loc: &L, pos: Position) -> bool {
|
||||
pub(crate) fn pos_in_loc<L: Locational>(loc: &L, pos: Position) -> bool {
|
||||
let ln_begin = loc.ln_begin().unwrap_or(0);
|
||||
let ln_end = loc.ln_end().unwrap_or(0);
|
||||
let in_lines = (ln_begin..=ln_end).contains(&(pos.line + 1));
|
||||
|
@ -94,7 +92,7 @@ pub fn pos_in_loc<L: Locational>(loc: &L, pos: Position) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn pos_to_byte_index(src: &str, pos: Position) -> usize {
|
||||
pub(crate) fn pos_to_byte_index(src: &str, pos: Position) -> usize {
|
||||
if src.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
|
@ -115,7 +113,10 @@ pub fn pos_to_byte_index(src: &str, pos: Position) -> usize {
|
|||
src.char_indices().last().unwrap().0 + 1
|
||||
}
|
||||
|
||||
pub fn get_token_from_stream(stream: &TokenStream, pos: Position) -> ELSResult<Option<Token>> {
|
||||
pub(crate) fn get_token_from_stream(
|
||||
stream: &TokenStream,
|
||||
pos: Position,
|
||||
) -> ELSResult<Option<Token>> {
|
||||
for token in stream.iter() {
|
||||
if pos_in_loc(token, pos) {
|
||||
return Ok(Some(token.clone()));
|
||||
|
@ -124,67 +125,18 @@ pub fn get_token_from_stream(stream: &TokenStream, pos: Position) -> ELSResult<O
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn get_ranged_code_from_uri(uri: &Url, range: Range) -> ELSResult<Option<String>> {
|
||||
pub(crate) fn get_metadata_from_uri(uri: &Url) -> ELSResult<Metadata> {
|
||||
let path = uri.to_file_path().unwrap();
|
||||
let file = File::open(path)?;
|
||||
let reader = BufReader::new(file);
|
||||
let mut code = String::new();
|
||||
for (i, line) in reader.lines().enumerate() {
|
||||
if i >= range.start.line as usize && i <= range.end.line as usize {
|
||||
let line = line?;
|
||||
if i == range.start.line as usize && i == range.end.line as usize {
|
||||
if line.len() < range.end.character as usize {
|
||||
return Ok(None);
|
||||
}
|
||||
code.push_str(&line[range.start.character as usize..range.end.character as usize]);
|
||||
} else if i == range.start.line as usize {
|
||||
code.push_str(&line[range.start.character as usize..]);
|
||||
code.push('\n');
|
||||
} else if i == range.end.line as usize {
|
||||
if line.len() < range.end.character as usize {
|
||||
return Ok(None);
|
||||
}
|
||||
code.push_str(&line[..range.end.character as usize]);
|
||||
} else {
|
||||
code.push_str(&line);
|
||||
code.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(code))
|
||||
Ok(metadata(path)?)
|
||||
}
|
||||
|
||||
pub fn get_line_from_uri(uri: &Url, line: u32) -> ELSResult<String> {
|
||||
let code = _get_code_from_uri(uri)?;
|
||||
let line = code
|
||||
.lines()
|
||||
.nth(line.saturating_sub(1) as usize)
|
||||
.unwrap_or("");
|
||||
Ok(line.to_string())
|
||||
}
|
||||
|
||||
pub fn get_metadata_from_uri(uri: &Url) -> ELSResult<std::fs::Metadata> {
|
||||
let path = uri.to_file_path().unwrap();
|
||||
Ok(std::fs::metadata(path)?)
|
||||
}
|
||||
|
||||
pub fn get_line_from_path(path: &Path, line: u32) -> ELSResult<String> {
|
||||
let mut code = String::new();
|
||||
File::open(path)?.read_to_string(&mut code)?;
|
||||
let line = code
|
||||
.lines()
|
||||
.nth(line.saturating_sub(1) as usize)
|
||||
.unwrap_or("");
|
||||
Ok(line.to_string())
|
||||
}
|
||||
|
||||
pub fn uri_to_path(uri: &NormalizedUrl) -> std::path::PathBuf {
|
||||
pub(crate) fn uri_to_path(uri: &NormalizedUrl) -> PathBuf {
|
||||
normalize_path(
|
||||
uri.to_file_path()
|
||||
.unwrap_or_else(|_| denormalize(uri.clone().raw()).to_file_path().unwrap()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn denormalize(uri: Url) -> Url {
|
||||
pub(crate) fn denormalize(uri: Url) -> Url {
|
||||
Url::parse(&uri.as_str().replace("c:", "file:///c%3A")).unwrap()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue