From 36a37a41620e6385e07fe07c94503ebb330b20a5 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Mon, 26 Feb 2024 12:04:37 -0500 Subject: [PATCH] Fix deleted directory file handling in LSP mode --- src/aast_utils/lib.rs | 1 + src/file_scanner_analyzer/analyzer.rs | 15 +++++++ src/file_scanner_analyzer/file.rs | 31 ++++++++++++-- src/file_scanner_analyzer/lib.rs | 2 +- src/file_scanner_analyzer/wasm.rs | 1 + src/language_server/lib.rs | 61 ++++++++++++++++----------- 6 files changed, 82 insertions(+), 29 deletions(-) diff --git a/src/aast_utils/lib.rs b/src/aast_utils/lib.rs index 23a816db..3702a95e 100644 --- a/src/aast_utils/lib.rs +++ b/src/aast_utils/lib.rs @@ -19,6 +19,7 @@ mod naming_visitor; #[derive(Debug)] pub enum ParserError { + CannotReadFile, NotAHackFile, SyntaxError { message: String, pos: HPos }, } diff --git a/src/file_scanner_analyzer/analyzer.rs b/src/file_scanner_analyzer/analyzer.rs index 4fa41928..428d0007 100644 --- a/src/file_scanner_analyzer/analyzer.rs +++ b/src/file_scanner_analyzer/analyzer.rs @@ -234,6 +234,21 @@ fn analyze_file( }, &None, ), + ParserError::CannotReadFile => Issue::new( + IssueKind::InvalidHackFile, + "Cannot read file".to_string(), + HPos { + file_path, + start_offset: 0, + end_offset: 0, + start_line: 0, + end_line: 0, + start_column: 0, + end_column: 0, + insertion_start: None, + }, + &None, + ), ParserError::SyntaxError { message, pos } => { Issue::new(IssueKind::InvalidHackFile, message, pos, &None) } diff --git a/src/file_scanner_analyzer/file.rs b/src/file_scanner_analyzer/file.rs index fa44c840..9082455a 100644 --- a/src/file_scanner_analyzer/file.rs +++ b/src/file_scanner_analyzer/file.rs @@ -11,6 +11,7 @@ pub enum FileStatus { Unchanged(u64, u64), Added(u64, u64), Deleted, + DeletedDir, Modified(u64, u64), } @@ -35,10 +36,29 @@ impl VirtualFileSystem { config: &Config, files_to_analyze: &mut Vec, ) { + let deleted_folders = language_server_changes + .iter() + .filter(|(_, v)| matches!(v, FileStatus::DeletedDir)) + .into_iter() + .map(|(k, _)| k) + .collect::>(); + + let mut deleted_files = vec![]; + for file in self.file_hashes_and_times.keys() { let str_path = interner.lookup(&file.0).to_string(); - if !language_server_changes.contains_key(&str_path) { + let in_deleted_folder = deleted_folders + .iter() + .any(|f| str_path.starts_with(&(f.to_string() + "/"))); + + if in_deleted_folder { + deleted_files.push(*file); + } else if let Some(file_status) = language_server_changes.get(&str_path) { + if let FileStatus::Deleted = file_status { + deleted_files.push(*file); + } + } else { files_to_scan.push(str_path.clone()); if !str_path.starts_with("hsl_embedded") && !str_path.ends_with(".hhi") { @@ -53,6 +73,10 @@ impl VirtualFileSystem { } } + for deleted_file in deleted_files { + self.file_hashes_and_times.remove(&deleted_file); + } + for (file_path, status) in language_server_changes { let path = Path::new(&file_path); @@ -70,9 +94,8 @@ impl VirtualFileSystem { files_to_analyze, ); } - FileStatus::Deleted => { - let file_path = interner.intern(path.to_str().unwrap().to_string()); - self.file_hashes_and_times.remove(&FilePath(file_path)); + FileStatus::Deleted | FileStatus::DeletedDir => { + // handled above } } } diff --git a/src/file_scanner_analyzer/lib.rs b/src/file_scanner_analyzer/lib.rs index e2f821e5..f989a002 100644 --- a/src/file_scanner_analyzer/lib.rs +++ b/src/file_scanner_analyzer/lib.rs @@ -411,7 +411,7 @@ pub fn get_aast_for_path( } else { match fs::read_to_string(file_path_str) { Ok(str_file) => str_file, - Err(_) => return Err(ParserError::NotAHackFile), + Err(_) => return Err(ParserError::CannotReadFile), } }; diff --git a/src/file_scanner_analyzer/wasm.rs b/src/file_scanner_analyzer/wasm.rs index 2da0604f..0e120849 100644 --- a/src/file_scanner_analyzer/wasm.rs +++ b/src/file_scanner_analyzer/wasm.rs @@ -242,6 +242,7 @@ pub fn analyze_single_file( Ok(aast) => aast, Err(error) => match error { ParserError::NotAHackFile => return Err("Not a Hack file".to_string()), + ParserError::CannotReadFile => return Err("Cannot read file".to_string()), ParserError::SyntaxError { message, pos } => { analysis_result.emitted_issues.insert( file_path, diff --git a/src/language_server/lib.rs b/src/language_server/lib.rs index 1215c878..ced41bbd 100644 --- a/src/language_server/lib.rs +++ b/src/language_server/lib.rs @@ -72,8 +72,12 @@ impl LanguageServer for Backend { kind: None, }, FileSystemWatcher { - glob_pattern: GlobPattern::String("**/index.lock".to_string()), - kind: None, + glob_pattern: GlobPattern::String("**/.git/index.lock".to_string()), + kind: Some(WatchKind::Delete), + }, + FileSystemWatcher { + glob_pattern: GlobPattern::String("**/[!.]*/**/".to_string()), + kind: Some(WatchKind::Delete), }, ], }) @@ -100,33 +104,42 @@ impl LanguageServer for Backend { async fn did_change_watched_files(&mut self, params: DidChangeWatchedFilesParams) { let mut new_file_statuses = FxHashMap::default(); + // self.client + // .log_message( + // MessageType::INFO, + // format!("receiving changes {:?}", params.changes), + // ) + // .await; + for file_event in params.changes { //let uri = file_event.uri; let change_type = file_event.typ; let file_path = file_event.uri.path().to_string(); - match change_type { - FileChangeType::CREATED => { - new_file_statuses.insert(file_path, FileStatus::Added(0, 0)); - } - FileChangeType::CHANGED => { - new_file_statuses.insert(file_path, FileStatus::Modified(0, 0)); + if file_path.ends_with(".php") + || file_path.ends_with(".hack") + || file_path.ends_with(".hhi") + { + match change_type { + FileChangeType::CREATED => { + new_file_statuses.insert(file_path, FileStatus::Added(0, 0)); + } + FileChangeType::CHANGED => { + new_file_statuses.insert(file_path, FileStatus::Modified(0, 0)); + } + FileChangeType::DELETED => { + new_file_statuses.insert(file_path, FileStatus::Deleted); + } + _ => {} } - FileChangeType::DELETED => { - new_file_statuses.insert(file_path, FileStatus::Deleted); + } else if Path::new(&file_path).extension().is_none() { + if let FileChangeType::DELETED = change_type { + new_file_statuses.insert(file_path, FileStatus::DeletedDir); } - _ => {} } } - // self.client - // .log_message( - // MessageType::INFO, - // format!("adding changes {:?}", new_file_statuses), - // ) - // .await; - if let Some(ref mut existing_file_changes) = self.file_changes { existing_file_changes.extend(new_file_statuses); } else { @@ -138,12 +151,12 @@ impl LanguageServer for Backend { .log_message(MessageType::INFO, "Waiting a sec while git is doing stuff") .await; } else { - // self.client - // .log_message( - // MessageType::INFO, - // format!("analyzing changes {:?}", self.file_changes), - // ) - // .await; + self.client + .log_message( + MessageType::INFO, + format!("analyzing changes {:?}", self.file_changes), + ) + .await; self.do_analysis().await; self.file_changes = None; self.emit_issues().await;