Skip to content

Commit

Permalink
dev: multiple roots in same world
Browse files Browse the repository at this point in the history
  • Loading branch information
Myriad-Dreamin committed Jan 17, 2025
1 parent 7df84c1 commit 4c52d05
Show file tree
Hide file tree
Showing 15 changed files with 53 additions and 71 deletions.
33 changes: 12 additions & 21 deletions crates/tinymist-query/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ pub use doc_highlight::*;
pub mod link_expr;
pub use link_expr::*;
pub mod stats;
use reflexo_typst::vfs::{WorkspaceResolution, WorkspaceResolver};
use reflexo_typst::vfs::WorkspaceResolver;
pub use stats::*;
pub mod definition;
pub use definition::*;
pub mod signature;
pub use signature::*;
pub mod semantic_tokens;
pub use semantic_tokens::*;
use typst::syntax::{Source, VirtualPath};
use typst::syntax::Source;
use typst::World;
mod post_tyck;
mod tyck;
Expand All @@ -41,11 +41,11 @@ pub use global::*;

use ecow::eco_format;
use lsp_types::Url;
use reflexo_typst::{EntryReader, TypstFileId};
use reflexo_typst::TypstFileId;
use typst::diag::{FileError, FileResult};
use typst::foundations::{Func, Value};

use crate::{path_to_url, untitled_url};
use crate::path_res_to_url;

pub(crate) trait ToFunc {
fn to_func(&self) -> Option<Func>;
Expand Down Expand Up @@ -76,19 +76,13 @@ pub trait LspWorldExt {
impl LspWorldExt for tinymist_world::LspWorld {
fn file_id_by_path(&self, path: &Path) -> FileResult<TypstFileId> {
// todo: source in packages
let root = self.workspace_root().ok_or_else(|| {
let reason = eco_format!("workspace root not found");
FileError::Other(Some(reason))
})?;
let relative_path = path.strip_prefix(&root).map_err(|_| {
let reason = eco_format!("access denied, path: {path:?}, root: {root:?}");
FileError::Other(Some(reason))
})?;

Ok(WorkspaceResolver::workspace_file(
Some(&root),
VirtualPath::new(relative_path),
))
match self.id_for_path(path) {
Some(id) => Ok(id),
None => WorkspaceResolver::file_with_parent_root(path).ok_or_else(|| {
let reason = eco_format!("invalid path: {path:?}");
FileError::Other(Some(reason))
}),
}
}

fn source_by_path(&self, path: &Path) -> FileResult<Source> {
Expand All @@ -97,10 +91,7 @@ impl LspWorldExt for tinymist_world::LspWorld {
}

fn uri_for_id(&self, fid: TypstFileId) -> Result<Url, FileError> {
let res = match WorkspaceResolver::resolve(fid) {
Ok(WorkspaceResolution::Rootless) => untitled_url(fid.vpath().as_rooted_path()),
_ => path_to_url(&self.path_for_id(fid)?),
};
let res = path_res_to_url(self.path_for_id(fid)?);

log::info!("uri_for_id: {fid:?} -> {res:?}");
res.map_err(|err| FileError::Other(Some(eco_format!("convert to url: {err:?}"))))
Expand Down
7 changes: 3 additions & 4 deletions crates/tinymist-query/src/analysis/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use reflexo::debug_loc::DataSource;
use reflexo::hash::{hash128, FxDashMap};
use reflexo::ImmutPath;
use reflexo_typst::vfs::WorkspaceResolver;
use reflexo_typst::vfs::{PathResolution, WorkspaceResolver};
use reflexo_typst::{EntryReader, WorldDeps};
use rustc_hash::FxHashMap;
use tinymist_world::{LspWorld, DETACHED_ENTRY};
Expand Down Expand Up @@ -317,7 +316,7 @@ impl LocalContext {
self.caches
.completion_files
.get_or_init(|| {
if let Some(root) = self.world.workspace_root() {
if let Some(root) = self.world.entry_state().workspace_root() {
scan_workspace_files(&root, PathPreference::Special.ext_matcher(), |path| {
WorkspaceResolver::workspace_file(Some(&root), VirtualPath::new(path))
})
Expand Down Expand Up @@ -574,7 +573,7 @@ impl SharedContext {
}

/// Resolve the real path for a file id.
pub fn path_for_id(&self, id: TypstFileId) -> Result<ImmutPath, FileError> {
pub fn path_for_id(&self, id: TypstFileId) -> Result<PathResolution, FileError> {
self.world.path_for_id(id)
}

Expand Down
3 changes: 1 addition & 2 deletions crates/tinymist-query/src/analysis/link_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ impl LinkTarget {
LinkTarget::Url(url) => Some(url.as_ref().clone()),
LinkTarget::Path(id, path) => {
// Avoid creating new ids here.
let base = id.vpath().join(path.as_str());
let root = ctx.path_for_id(id.join("/")).ok()?;
crate::path_to_url(&base.resolve(&root)?).ok()
crate::path_res_to_url(root.join(path).ok()?).ok()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/tinymist-query/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ mod tests {
let mut results = vec![];
for s in rng.clone() {
let request = CompletionRequest {
path: ctx.path_for_id(id).unwrap().as_ref().to_owned(),
path: ctx.path_for_id(id).unwrap().as_path().to_owned(),
position: ctx.to_lsp_pos(s, &source),
explicit: false,
trigger_character,
Expand Down
24 changes: 9 additions & 15 deletions crates/tinymist-query/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use reflexo_typst::EntryReader;
use tinymist_world::LspWorld;
use typst::syntax::Span;

Expand Down Expand Up @@ -54,19 +53,10 @@ fn convert_diagnostic(
ctx: &LocalDiagContext,
typst_diagnostic: &TypstDiagnostic,
) -> anyhow::Result<(Url, Diagnostic)> {
let uri;
let lsp_range;
if let Some((id, span)) = diagnostic_span_id(typst_diagnostic) {
uri = ctx.uri_for_id(id)?;
let source = ctx.source(id)?;
lsp_range = diagnostic_range(&source, span, ctx.position_encoding);
} else {
let root = ctx
.workspace_root()
.ok_or_else(|| anyhow::anyhow!("no workspace root"))?;
uri = path_to_url(&root)?;
lsp_range = LspRange::default();
};
let (id, span) = diagnostic_span_id(ctx, typst_diagnostic);
let uri = ctx.uri_for_id(id)?;
let source = ctx.source(id)?;
let lsp_range = diagnostic_range(&source, span, ctx.position_encoding);

let lsp_severity = diagnostic_severity(typst_diagnostic.severity);

Expand Down Expand Up @@ -131,10 +121,14 @@ fn diagnostic_related_information(
Ok(tracepoints)
}

fn diagnostic_span_id(typst_diagnostic: &TypstDiagnostic) -> Option<(TypstFileId, Span)> {
fn diagnostic_span_id(
ctx: &LocalDiagContext,
typst_diagnostic: &TypstDiagnostic,
) -> (TypstFileId, Span) {
iter::once(typst_diagnostic.span)
.chain(typst_diagnostic.trace.iter().map(|trace| trace.span))
.find_map(|span| Some((span.id()?, span)))
.unwrap_or_else(|| (ctx.main(), Span::detached()))
}

fn diagnostic_range(
Expand Down
2 changes: 1 addition & 1 deletion crates/tinymist-query/src/document_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl DocumentMetricsWorker<'_> {
let column = source.byte_to_column(byte_index)?;

let filepath = self.ctx.path_for_id(file_id).ok()?;
let filepath_str = filepath.to_string_lossy().to_string();
let filepath_str = filepath.as_path().display().to_string();

Some((filepath_str, line as u32 + 1, column as u32 + 1))
}
Expand Down
9 changes: 9 additions & 0 deletions crates/tinymist-query/src/lsp_typst_boundary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::cmp::Ordering;

use reflexo::path::PathClean;
use reflexo_typst::vfs::PathResolution;
use typst::syntax::Source;

use crate::prelude::*;
Expand Down Expand Up @@ -65,6 +66,14 @@ pub fn path_to_url(path: &Path) -> anyhow::Result<Url> {
})
}

/// Convert a path resolution to a URL.
pub fn path_res_to_url(path: PathResolution) -> anyhow::Result<Url> {
match path {
PathResolution::Rootless(path) => untitled_url(path.as_rooted_path()),
PathResolution::Resolved(path) => path_to_url(&path),
}
}

/// Convert a URL to a path.
pub fn url_to_path(uri: Url) -> PathBuf {
if uri.scheme() == "file" {
Expand Down
3 changes: 2 additions & 1 deletion crates/tinymist-query/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ impl StatefulRequest for RenameRequest {
};

let def_fid = def.location(ctx.shared())?.0;
let old_path = ctx.path_for_id(def_fid).ok()?;
// todo: rename in untitled files
let old_path = ctx.path_for_id(def_fid).ok()?.to_err().ok()?;

let rename_loc = Path::new(ref_path_str.as_str());
let diff = pathdiff::diff_paths(Path::new(&new_path_str), rename_loc)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/tinymist-query/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub fn run_with_ctx<T>(
path: PathBuf,
f: &impl Fn(&mut LocalContext, PathBuf) -> T,
) -> T {
let root = verse.workspace_root().unwrap();
let root = verse.entry_state().workspace_root().unwrap();
let paths = verse
.shadow_paths()
.into_iter()
Expand Down
3 changes: 1 addition & 2 deletions crates/tinymist-query/src/workspace_label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ impl SemanticRequest for WorkspaceLabelRequest {
let Ok(source) = ctx.source_by_id(fid) else {
continue;
};
let Ok(path) = ctx.path_for_id(fid) else {
let Ok(uri) = ctx.uri_for_id(fid) else {
continue;
};
let uri = path_to_url(&path).unwrap();
let res = get_lexical_hierarchy(&source, LexicalScopeKind::Symbol).map(|hierarchy| {
filter_document_labels(&hierarchy, &source, &uri, ctx.position_encoding())
});
Expand Down
4 changes: 2 additions & 2 deletions crates/tinymist-world/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,8 +883,8 @@ impl<F: CompilerFeat + Send + Sync + 'static> SharedProjectState<F> {
// Notify the new file dependencies.
let mut deps = vec![];
world.iter_dependencies(&mut |dep| {
if let Ok(x) = world.file_path(dep) {
deps.push(x)
if let Ok(x) = world.file_path(dep).and_then(|e| e.to_err()) {
deps.push(x.into())
}
});
send(CompilerResponse::Notify(NotifyMessage::SyncDependency(
Expand Down
2 changes: 1 addition & 1 deletion crates/tinymist-world/src/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::LspWorld;

/// Make a new project lock updater.
pub fn update_lock(world: &LspWorld) -> Option<ProjectLockUpdater> {
let root = world.workspace_root()?;
let root = world.entry_state().workspace_root()?;
Some(ProjectLockUpdater {
root,
updates: vec![],
Expand Down
2 changes: 1 addition & 1 deletion crates/tinymist/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ impl LanguageState {

let entry: StrResult<EntryState> = Ok(()).and_then(|_| {
let toml_id = tinymist_query::package::get_manifest_id(&info)?;
let toml_path = world.path_for_id(toml_id)?;
let toml_path = world.path_for_id(toml_id)?.as_path().to_owned();
let pkg_root = toml_path.parent().ok_or_else(|| {
eco_format!("cannot get package root (parent of {toml_path:?})")
})?;
Expand Down
5 changes: 3 additions & 2 deletions crates/tinymist/src/tool/package/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,14 @@ fn scaffold_project(
}
}

let package_root = world.path_for_id(toml_id)?;
let package_root = world.path_for_id(toml_id)?.as_path().to_owned();
let package_root = package_root
.parent()
.ok_or_else(|| eco_format!("package root is not a directory (at {:?})", toml_id))?;

let template_dir = toml_id.join(tmpl_info.path.as_str());
let real_template_dir = world.path_for_id(template_dir)?;
// todo: template in memory
let real_template_dir = world.path_for_id(template_dir)?.to_err()?;
if !real_template_dir.exists() {
bail!(
"template directory does not exist (at {})",
Expand Down
23 changes: 6 additions & 17 deletions crates/tinymist/src/tool/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use hyper_util::server::graceful::GracefulShutdown;
use lsp_types::notification::Notification;
use reflexo_typst::debug_loc::SourceSpanOffset;
use reflexo_typst::vfs::notify::{FileChangeSet, MemoryEvent};
use reflexo_typst::{error::prelude::*, EntryReader, Error, TypstDocument};
use reflexo_typst::{error::prelude::*, Error, TypstDocument};
use serde::Serialize;
use serde_json::Value as JsonValue;
use sync_lsp::just_ok;
Expand All @@ -22,7 +22,7 @@ use tinymist_assets::TYPST_PREVIEW_HTML;
use tinymist_world::project::{CompileServerOpts, CompiledArtifact, ProjectCompileActor};
use tokio::sync::{mpsc, oneshot};
use typst::layout::{Frame, FrameItem, Point, Position};
use typst::syntax::{LinkedNode, Source, Span, SyntaxKind, VirtualPath};
use typst::syntax::{LinkedNode, Source, Span, SyntaxKind};
use typst::World;
pub use typst_preview::CompileStatus;
use typst_preview::{
Expand All @@ -31,7 +31,6 @@ use typst_preview::{
PreviewBuilder, PreviewMode, Previewer, WsMessage,
};
use typst_shim::syntax::LinkedNodeExt;
use vfs::WorkspaceResolver;

use crate::world::LspCompilerFeat;
use crate::*;
Expand Down Expand Up @@ -66,12 +65,8 @@ impl typst_preview::CompileView for PreviewCompileView {
let world = &self.snap.world;
let Location::Src(loc) = loc;

let filepath = Path::new(&loc.filepath);
let root = world.workspace_root()?;
let relative_path = filepath.strip_prefix(&root).ok()?;
let source_id = world.id_for_path(Path::new(&loc.filepath))?;

let source_id =
WorkspaceResolver::workspace_file(Some(&root), VirtualPath::new(relative_path));
let source = world.source(source_id).ok()?;
let cursor = source.line_column_to_byte(loc.pos.line, loc.pos.column)?;

Expand All @@ -90,23 +85,17 @@ impl typst_preview::CompileView for PreviewCompileView {
let world = &self.snap.world;
let Location::Src(src_loc) = loc;

let path = Path::new(&src_loc.filepath).to_owned();
let line = src_loc.pos.line;
let column = src_loc.pos.column;

let doc = self.snap.success_doc();
let Some(doc) = doc.as_deref() else {
return vec![];
};
let Some(root) = world.workspace_root() else {
return vec![];
};
let Some(relative_path) = path.strip_prefix(&root).ok() else {

let Some(source_id) = world.id_for_path(Path::new(&src_loc.filepath)) else {
return vec![];
};

let source_id =
WorkspaceResolver::workspace_file(Some(&root), VirtualPath::new(relative_path));
let Some(source) = world.source(source_id).ok() else {
return vec![];
};
Expand All @@ -129,7 +118,7 @@ impl typst_preview::CompileView for PreviewCompileView {
range.start += off;
}
}
let filepath = world.path_for_id(span.id()?).ok()?;
let filepath = world.path_for_id(span.id()?).ok()?.to_err().ok()?;
Some(DocToSrcJumpInfo {
filepath: filepath.to_string_lossy().to_string(),
start: resolve_off(&source, range.start),
Expand Down

0 comments on commit 4c52d05

Please sign in to comment.