mirror of
https://github.com/oxalica/nil.git
synced 2025-12-23 09:19:49 +00:00
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
This commit is contained in:
parent
ec7d3490f2
commit
31b714f3da
6 changed files with 20 additions and 157 deletions
87
Cargo.lock
generated
87
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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::<InitializeParams>(init_params)?;
|
||||
let workspace_path = (|| -> Option<PathBuf> {
|
||||
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(())
|
||||
|
|
|
|||
|
|
@ -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<Task>,
|
||||
event_tx: Sender<Event>,
|
||||
event_rx: Receiver<Event>,
|
||||
|
||||
// Immutable settings.
|
||||
workspace_root: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new(lsp_tx: Sender<Message>, workspace_root: Option<PathBuf>) -> 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<Message>) -> 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<Message>) -> 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<Message>, _init_params: InitializeParams) -> Result<()> {
|
||||
loop {
|
||||
crossbeam_channel::select! {
|
||||
recv(lsp_rx) -> msg => {
|
||||
|
|
|
|||
|
|
@ -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<str>, Arc<LineMap>)>,
|
||||
/// 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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue