Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 58 additions & 8 deletions server/src/core/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct EntryPointMgr {
pub main_entry_point: Option<Rc<RefCell<EntryPoint>>>,
pub addons_entry_points: Vec<Rc<RefCell<EntryPoint>>>,
pub custom_entry_points: Vec<Rc<RefCell<EntryPoint>>>,
pub untitled_entry_points: Vec<Rc<RefCell<EntryPoint>>>,
}

impl EntryPointMgr {
Expand All @@ -25,8 +26,27 @@ impl EntryPointMgr {
main_entry_point: None,
addons_entry_points: vec![],
custom_entry_points: vec![],
untitled_entry_points: vec![],
}
}
/// Create a new entry for an untitled (in-memory) file.
/// Returns the file symbol for the untitled entry.
pub fn add_entry_to_untitled(session: &mut SessionInfo, path: String) -> Rc<RefCell<Symbol>> {
// For untitled files, we use a minimal tree: just the name as a single OYarn
let tree = vec![OYarn::from(path.clone())];
let entry = EntryPoint::new(
path.clone(),
tree,
EntryPointType::UNTITLED,
None,
None,
);
session.sync_odoo.entry_point_mgr.borrow_mut().untitled_entry_points.push(entry.clone());
// Create one file symbol under the root for the untitled file
let name: String = PathBuf::from(&path).with_extension("").components().last().unwrap().as_os_str().to_str().unwrap().to_string();
let file_sym = entry.borrow().root.borrow_mut().add_new_file(session, &name, &path);
file_sym.clone()
}

/**
* Create each required directory symbols for a given path.
Expand Down Expand Up @@ -193,6 +213,13 @@ impl EntryPointMgr {
true
}

pub fn create_new_untitled_entry_for_path(session: &mut SessionInfo, file_name: &String) -> bool {
let new_sym = EntryPointMgr::add_entry_to_untitled(session, file_name.clone());
new_sym.borrow_mut().as_file_mut().self_import = true;
SyncOdoo::add_to_rebuild_arch(session.sync_odoo, new_sym);
true
}

pub fn iter_for_import(&self, current_entry: &Rc<RefCell<EntryPoint>>) -> Box<dyn Iterator<Item = &Rc<RefCell<EntryPoint>>> + '_> {
let mut is_main = false;
for entry in self.iter_main() {
Expand All @@ -214,12 +241,12 @@ impl EntryPointMgr {
}

pub fn iter_all(&self) -> impl Iterator<Item = &Rc<RefCell<EntryPoint>>> {
self.addons_entry_points.iter().chain(
self.main_entry_point.iter()).chain(
self.builtins_entry_points.iter()).chain(
self.public_entry_points.iter()).chain(
self.custom_entry_points.iter()
)
self.addons_entry_points.iter()
.chain(self.main_entry_point.iter())
.chain(self.builtins_entry_points.iter())
.chain(self.public_entry_points.iter())
.chain(self.custom_entry_points.iter())
.chain(self.untitled_entry_points.iter())
}

//iter through all main entry points, sorted by tree length (from bigger to smaller)
Expand Down Expand Up @@ -256,6 +283,15 @@ impl EntryPointMgr {
self.clean_entries();
}

pub fn remove_untitled_entries_with_path(&mut self, path: &String) {
for entry in self.untitled_entry_points.iter() {
if &entry.borrow().path.clone() == path {
entry.borrow_mut().to_delete = true;
}
}
self.clean_entries();
}

pub fn check_custom_entry_to_delete_with_path(&mut self, path: &String) {
for entry in self.custom_entry_points.iter() {
if entry.borrow().path == *path {
Expand Down Expand Up @@ -292,7 +328,7 @@ impl EntryPointMgr {
entry_index += 1;
}
}
let mut entry_index = 0;
entry_index = 0;
while entry_index < self.custom_entry_points.len() {
let entry = self.custom_entry_points[entry_index].clone();
if entry.borrow().to_delete {
Expand All @@ -302,6 +338,16 @@ impl EntryPointMgr {
entry_index += 1;
}
}
entry_index = 0;
while entry_index < self.untitled_entry_points.len() {
let entry = self.untitled_entry_points[entry_index].clone();
if entry.borrow().to_delete {
info!("Dropping untitled entry point {}", entry.borrow().path);
self.untitled_entry_points.remove(entry_index);
} else {
entry_index += 1;
}
}
}

/// Transform the path of an addon to the odoo relative path.
Expand All @@ -323,7 +369,8 @@ pub enum EntryPointType {
BUILTIN,
PUBLIC,
ADDON,
CUSTOM
CUSTOM,
UNTITLED,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -359,6 +406,9 @@ impl EntryPoint {
}

pub fn is_valid_for(&self, path: &PathBuf) -> bool {
if self.typ == EntryPointType::UNTITLED {
return false;
}
path.starts_with(&self.path)
}

Expand Down
78 changes: 61 additions & 17 deletions server/src/core/file_mgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ropey::Rope;
use ruff_python_ast::{ModModule, PySourceType, Stmt};
use ruff_python_parser::{Parsed, Token, TokenKind};
use lsp_types::{Diagnostic, DiagnosticSeverity, MessageType, NumberOrString, Position, PublishDiagnosticsParams, Range, TextDocumentContentChangeEvent};
use tracing::{error, warn};
use tracing::{info, error, warn};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -104,9 +104,9 @@ impl FileInfo {
diagnostic_filters: Vec::new(),
}
}
pub fn update(&mut self, session: &mut SessionInfo, uri: &str, content: Option<&Vec<TextDocumentContentChangeEvent>>, version: Option<i32>, in_workspace: bool, force: bool) -> bool {
pub fn update(&mut self, session: &mut SessionInfo, path: &str, content: Option<&Vec<TextDocumentContentChangeEvent>>, version: Option<i32>, in_workspace: bool, force: bool, is_untitled: bool) -> bool {
// update the file info with the given information.
// uri: indicates the path of the file
// path: indicates the path of the file
// content: if content is given, it will be used to update the ast and text_rope, if not, the loading will be from the disk
// version: if the version is provided, the file_info wil be updated only if the new version is higher.
// -100 can be given as version number to indicates that the file has not been opened yet, and that we have to load it ourself
Expand Down Expand Up @@ -137,13 +137,16 @@ impl FileInfo {
for change in content.iter() {
self.apply_change(change);
}
} else if is_untitled {
session.log_message(MessageType::ERROR, format!("Attempt to update untitled file {}, without changes", path));
return false;
} else {
match fs::read_to_string(uri) {
match fs::read_to_string(path) {
Ok(content) => {
self.file_info_ast.borrow_mut().text_rope = Some(ropey::Rope::from(content.as_str()));
},
Err(e) => {
session.log_message(MessageType::ERROR, format!("Failed to read file {}, with error {}", uri, e));
session.log_message(MessageType::ERROR, format!("Failed to read file {}, with error {}", path, e));
return false;
},
};
Expand Down Expand Up @@ -441,6 +444,7 @@ impl FileInfo {
#[derive(Debug)]
pub struct FileMgr {
pub files: HashMap<String, Rc<RefCell<FileInfo>>>,
untitled_files: HashMap<String, Rc<RefCell<FileInfo>>>, // key: untitled URI or unique name
workspace_folders: HashMap<String, String>,
has_repeated_workspace_folders: bool,
}
Expand All @@ -450,6 +454,7 @@ impl FileMgr {
pub fn new() -> Self {
Self {
files: HashMap::new(),
untitled_files: HashMap::new(),
workspace_folders: HashMap::new(),
has_repeated_workspace_folders: false,
}
Expand All @@ -463,17 +468,30 @@ impl FileMgr {
}

pub fn get_file_info(&self, path: &String) -> Option<Rc<RefCell<FileInfo>>> {
self.files.get(path).cloned()
if Self::is_untitled(path) {
self.untitled_files.get(path).cloned()
} else {
self.files.get(path).cloned()
}
}

pub fn text_range_to_range(&self, session: &mut SessionInfo, path: &String, range: &TextRange) -> Range {
let file = self.files.get(path);
let file = if Self::is_untitled(path) {
self.untitled_files.get(path)
} else {
self.files.get(path)
};
if let Some(file) = file {
if file.borrow().file_info_ast.borrow().text_rope.is_none() {
file.borrow_mut().prepare_ast(session);
}
return file.borrow().text_range_to_range(range);
}
// For untitled, never try to read from disk
if Self::is_untitled(path) {
session.log_message(MessageType::ERROR, format!("Untitled file {} not found in memory", path));
return Range::default();
}
//file not in cache, let's load rope on the fly
match fs::read_to_string(path) {
Ok(content) => {
Expand All @@ -490,13 +508,22 @@ impl FileMgr {


pub fn std_range_to_range(&self, session: &mut SessionInfo, path: &String, range: &std::ops::Range<usize>) -> Range {
let file = self.files.get(path);
let file = if Self::is_untitled(path) {
self.untitled_files.get(path)
} else {
self.files.get(path)
};
if let Some(file) = file {
if file.borrow().file_info_ast.borrow().text_rope.is_none() {
file.borrow_mut().prepare_ast(session);
}
return file.borrow().std_range_to_range(range);
}
// For untitled, never try to read from disk
if Self::is_untitled(path) {
session.log_message(MessageType::ERROR, format!("Untitled file {} not found in memory", path));
return Range::default();
}
//file not in cache, let's load rope on the fly
match fs::read_to_string(path) {
Ok(content) => {
Expand All @@ -511,8 +538,20 @@ impl FileMgr {
Range::default()
}

/// Returns true if the path/uri is an untitled (in-memory) file.
/// by convention, untitled files start with "untitled:".
pub fn is_untitled(path: &str) -> bool {
path.starts_with("untitled:")
}

pub fn update_file_info(&mut self, session: &mut SessionInfo, uri: &str, content: Option<&Vec<TextDocumentContentChangeEvent>>, version: Option<i32>, force: bool) -> (bool, Rc<RefCell<FileInfo>>) {
let file_info = self.files.entry(uri.to_string()).or_insert_with(|| {
let is_untitled = Self::is_untitled(uri);
let entry = if is_untitled {
self.untitled_files.entry(uri.to_string())
} else {
self.files.entry(uri.to_string())
};
let file_info = entry.or_insert_with(|| {
let mut file_info = FileInfo::new(uri.to_string());
file_info.update_diagnostic_filters(session);
Rc::new(RefCell::new(file_info))
Expand All @@ -522,7 +561,7 @@ impl FileMgr {
let mut updated: bool = false;
if (version.is_some() && version.unwrap() != -100) || !file_info.borrow().opened || force {
let mut file_info_mut = (*return_info).borrow_mut();
updated = file_info_mut.update(session, uri, content, version, self.is_in_workspace(uri), force);
updated = file_info_mut.update(session, uri, content, version, self.is_in_workspace(uri), force, is_untitled);
drop(file_info_mut);
}
(updated, return_info)
Expand Down Expand Up @@ -612,13 +651,18 @@ impl FileMgr {
}

pub fn pathname2uri(s: &String) -> lsp_types::Uri {
let mut slash = "";
if cfg!(windows) {
slash = "/";
}
let pre_uri = match url::Url::parse(&format!("file://{}{}", slash, s)) {
Ok(pre_uri) => pre_uri,
Err(err) => panic!("unable to transform pathname to uri: {s}, {}", err)
let pre_uri = if s.starts_with("untitled:"){
s.clone()
} else {
let mut slash = "";
if cfg!(windows) {
slash = "/";
}
let pre_uri = match url::Url::parse(&format!("file://{}{}", slash, s)) {
Ok(pre_uri) => pre_uri,
Err(err) => panic!("unable to transform pathname to uri: {s}, {}", err)
};
pre_uri.to_string()
};
match lsp_types::Uri::from_str(pre_uri.as_str()) {
Ok(url) => url,
Expand Down
Loading