From 31b714f3da105be85a9810c8d30cc32e76496a67 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 28 Sep 2022 17:52:41 +0800 Subject: [PATCH] Use absolute VfsPath and remove file preloading We currently don't enable any workspace features. Reading file on demand can be more robust and memory efficient. Fixes #21 --- Cargo.lock | 87 ---------------------------------------- crates/ide/src/base.rs | 1 + crates/nil/Cargo.toml | 1 - crates/nil/src/lib.rs | 16 ++------ crates/nil/src/server.rs | 48 ++++------------------ crates/nil/src/vfs.rs | 24 +++++------ 6 files changed, 20 insertions(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58b9f77..ee825e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" -dependencies = [ - "memchr", -] - [[package]] name = "anyhow" version = "1.0.65" @@ -29,15 +20,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - [[package]] name = "builtin" version = "0.0.0" @@ -102,12 +84,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "form_urlencoded" version = "1.1.0" @@ -117,19 +93,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -172,24 +135,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils", - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - [[package]] name = "indexmap" version = "1.9.1" @@ -307,7 +252,6 @@ version = "0.0.0" dependencies = [ "crossbeam-channel", "ide", - "ignore", "indexmap", "log", "lsp-server", @@ -472,8 +416,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ - "aho-corasick", - "memchr", "regex-syntax", ] @@ -556,15 +498,6 @@ dependencies = [ "syn", ] -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -800,17 +733,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - [[package]] name = "winapi" version = "0.3.9" @@ -827,15 +749,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/crates/ide/src/base.rs b/crates/ide/src/base.rs index f03c0d5..ddae9a1 100644 --- a/crates/ide/src/base.rs +++ b/crates/ide/src/base.rs @@ -12,6 +12,7 @@ pub struct FileId(pub u32); pub struct SourceRootId(pub u32); /// An absolute path in format `(/.+)*` +/// Currently, it represent an absolute filesytem path. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct VfsPath(String); diff --git a/crates/nil/Cargo.toml b/crates/nil/Cargo.toml index 5cc6104..39f1737 100644 --- a/crates/nil/Cargo.toml +++ b/crates/nil/Cargo.toml @@ -8,7 +8,6 @@ rust-version = "1.62" [dependencies] crossbeam-channel = "0.5.6" ide = { path = "../ide" } -ignore = "0.4.18" indexmap = "1.9.1" log = "0.4.17" lsp-server = "0.6.0" diff --git a/crates/nil/src/lib.rs b/crates/nil/src/lib.rs index 4778a10..20f65c9 100644 --- a/crates/nil/src/lib.rs +++ b/crates/nil/src/lib.rs @@ -7,8 +7,7 @@ mod vfs; use lsp_server::{Connection, ErrorCode}; use lsp_types::InitializeParams; -use std::path::PathBuf; -use std::{env, fmt}; +use std::fmt; pub(crate) use server::{Server, StateSnapshot}; pub(crate) use vfs::{LineMap, Vfs}; @@ -36,18 +35,9 @@ pub fn main_loop(conn: Connection) -> Result<()> { tracing::info!("Init params: {}", init_params); let init_params = serde_json::from_value::(init_params)?; - let workspace_path = (|| -> Option { - if let Some(folders) = &init_params.workspace_folders { - return folders.get(0)?.uri.to_file_path().ok(); - } - if let Some(uri) = &init_params.root_uri { - return uri.to_file_path().ok(); - } - env::current_dir().ok() - })(); - let mut state = Server::new(conn.sender.clone(), workspace_path); - state.run(conn.receiver)?; + let mut server = Server::new(conn.sender.clone()); + server.run(conn.receiver, init_params)?; tracing::info!("Leaving main loop"); Ok(()) diff --git a/crates/nil/src/server.rs b/crates/nil/src/server.rs index 3137d14..9c9f32c 100644 --- a/crates/nil/src/server.rs +++ b/crates/nil/src/server.rs @@ -1,21 +1,20 @@ use crate::{convert, handler, Result, Vfs}; use crossbeam_channel::{Receiver, Sender}; -use ide::{Analysis, AnalysisHost, Cancelled, VfsPath}; +use ide::{Analysis, AnalysisHost, Cancelled}; use lsp_server::{ErrorCode, Message, Notification, ReqQueue, Request, RequestId, Response}; use lsp_types::notification::Notification as _; use lsp_types::{ notification as notif, request as req, ConfigurationItem, ConfigurationParams, Diagnostic, - MessageType, NumberOrString, PublishDiagnosticsParams, ShowMessageParams, Url, + InitializeParams, MessageType, NumberOrString, PublishDiagnosticsParams, ShowMessageParams, + Url, }; use serde::Deserialize; use std::cell::Cell; use std::collections::HashSet; use std::panic::UnwindSafe; -use std::path::PathBuf; use std::sync::{Arc, Once, RwLock}; -use std::{fs, panic, thread}; +use std::{panic, thread}; -const FILTER_FILE_EXTENTION: &str = "nix"; const CONFIG_KEY: &str = "nil"; #[derive(Debug, Clone, Default, Deserialize)] @@ -47,17 +46,10 @@ pub struct Server { task_tx: Sender, event_tx: Sender, event_rx: Receiver, - - // Immutable settings. - workspace_root: Option, } impl Server { - pub fn new(lsp_tx: Sender, workspace_root: Option) -> Self { - // Vfs root must be absolute. - let workspace_root = workspace_root.and_then(|root| root.canonicalize().ok()); - let vfs = Vfs::new(workspace_root.clone().unwrap_or_else(|| PathBuf::from("/"))); - + pub fn new(lsp_tx: Sender) -> Self { let (task_tx, task_rx) = crossbeam_channel::unbounded(); let (event_tx, event_rx) = crossbeam_channel::unbounded(); let worker_cnt = thread::available_parallelism().map_or(1, |n| n.get()); @@ -73,7 +65,7 @@ impl Server { Self { host: Default::default(), - vfs: Arc::new(RwLock::new(vfs)), + vfs: Arc::new(RwLock::new(Vfs::new())), opened_files: Default::default(), config: Arc::new(Config::default()), is_shutdown: false, @@ -83,8 +75,6 @@ impl Server { task_tx, event_tx, event_rx, - - workspace_root, } } @@ -96,31 +86,7 @@ impl Server { } } - pub fn run(&mut self, lsp_rx: Receiver) -> Result<()> { - if let Some(root) = &self.workspace_root { - let mut vfs = self.vfs.write().unwrap(); - for entry in ignore::WalkBuilder::new(root).follow_links(false).build() { - (|| -> Option<()> { - let entry = entry.ok()?; - if entry - .path() - .extension() - .map_or(true, |ext| ext != FILTER_FILE_EXTENTION) - { - return None; - } - - let relative_path = entry.path().strip_prefix(root).ok()?; - let vpath = VfsPath::from_path(relative_path)?; - let text = fs::read_to_string(entry.path()).ok().unwrap_or_default(); - vfs.set_path_content(vpath, text); - Some(()) - })(); - } - drop(vfs); - self.apply_vfs_change(); - } - + pub fn run(&mut self, lsp_rx: Receiver, _init_params: InitializeParams) -> Result<()> { loop { crossbeam_channel::select! { recv(lsp_rx) -> msg => { diff --git a/crates/nil/src/vfs.rs b/crates/nil/src/vfs.rs index 2dc6bf0..0725f1d 100644 --- a/crates/nil/src/vfs.rs +++ b/crates/nil/src/vfs.rs @@ -2,16 +2,16 @@ use crate::Result; use ide::{Change, FileId, FileSet, SourceRoot, VfsPath}; use lsp_types::Url; use std::collections::HashMap; -use std::path::PathBuf; use std::sync::Arc; use std::{fmt, mem}; use text_size::{TextRange, TextSize}; +/// Vfs stores file contents with line mapping, and a mapping between +/// filesystem paths and `FileId`s. +/// The query system is built on `FileId`'s. pub struct Vfs { // FIXME: Currently this list is append-only. files: Vec<(Arc, Arc)>, - /// The root directory, which must be absolute. - local_root: PathBuf, local_file_set: FileSet, root_changed: bool, change: Change, @@ -21,17 +21,16 @@ impl fmt::Debug for Vfs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Vfs") .field("file_cnt", &self.files.len()) - .field("local_root", &self.local_root) + .field("root_changed", &self.root_changed) + .field("change", &self.change) .finish_non_exhaustive() } } impl Vfs { - pub fn new(local_root: PathBuf) -> Self { - assert!(local_root.is_absolute()); + pub fn new() -> Self { Self { files: Vec::new(), - local_root, local_file_set: FileSet::default(), root_changed: false, change: Change::default(), @@ -42,10 +41,7 @@ impl Vfs { let path = uri .to_file_path() .map_err(|_| format!("Non-file URI: {}", uri))?; - let relative_path = path - .strip_prefix(&self.local_root) - .map_err(|_| format!("URI outside workspace: {}", uri))?; - Ok(VfsPath::from_path(relative_path).expect("URI is UTF-8")) + Ok(VfsPath::from_path(&path).expect("URI is UTF-8")) } pub fn set_uri_content(&mut self, uri: &Url, text: String) -> Result<()> { @@ -118,10 +114,8 @@ impl Vfs { } pub fn uri_for_file(&self, file: FileId) -> Url { - let vpath = self.local_file_set.path_for_file(file).as_str(); - assert!(!vpath.is_empty(), "Root is a directory"); - let path = self.local_root.join(vpath.strip_prefix('/').unwrap()); - Url::from_file_path(path).expect("Root is absolute") + let vpath = self.local_file_set.path_for_file(file); + Url::from_file_path(vpath.as_str()).expect("VfsPath is absolute") } pub fn take_change(&mut self) -> Change {