From 3a17944a660686df543b420d2fa07b252cbd093a Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Sat, 19 Sep 2020 17:59:33 -0700 Subject: [PATCH] Add document links for #include lines --- src/dreammaker/annotation.rs | 1 + src/dreammaker/preprocessor.rs | 23 +++++++++++++++++++---- src/langserver/main.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/dreammaker/annotation.rs b/src/dreammaker/annotation.rs index 445d122f..9db83c29 100644 --- a/src/dreammaker/annotation.rs +++ b/src/dreammaker/annotation.rs @@ -30,6 +30,7 @@ pub enum Annotation { // a macro is called here, which is defined at this location MacroDefinition(String), MacroUse(String, Location), + Include(std::path::PathBuf), // error annotations, mostly for autocompletion ScopedMissingIdent(Vec), // when a . is followed by a non-ident diff --git a/src/dreammaker/preprocessor.rs b/src/dreammaker/preprocessor.rs index 410bd55a..614ef00a 100644 --- a/src/dreammaker/preprocessor.rs +++ b/src/dreammaker/preprocessor.rs @@ -741,9 +741,10 @@ impl<'ctx> Preprocessor<'ctx> { // include searches relevant paths for files "include" if disabled => {} "include" => { - expect_token!((path) = Token::String(path)); + expect_token!((path_str) = Token::String(path_str)); + let include_loc = _last_expected_loc; expect_token!(() = Token::Punct(Punctuation::Newline)); - let path = PathBuf::from(path.replace("\\", "/")); + let path = PathBuf::from(path_str.replace("\\", "/")); for candidate in vec![ // 1. relative to file in which `#include` appears. @@ -762,7 +763,7 @@ impl<'ctx> Preprocessor<'ctx> { DMS, DM, } - match match candidate.extension().and_then(|s| s.to_str()) { + let file_type = match candidate.extension().and_then(|s| s.to_str()) { Some("dmm") => FileType::DMM, Some("dmf") => FileType::DMF, Some("dms") => FileType::DMS, @@ -779,7 +780,19 @@ impl<'ctx> Preprocessor<'ctx> { self.context.register_error(DMError::new(self.last_input_loc, "filename has no extension")); return Ok(()); } - } { + }; + + if let Some(annotations) = self.annotations.as_mut() { + let mut full_path = candidate.clone(); + if full_path.is_relative() { + full_path = std::env::current_dir().expect("couldn't get current dir").join(&full_path); + } + annotations.insert( + include_loc .. include_loc.add_columns(2 + path_str.len() as u16), + Annotation::Include(full_path)); + } + + match file_type { FileType::DMM => self.maps.push(candidate), FileType::DMF => self.skins.push(candidate), FileType::DMS => self.scripts.push(candidate), @@ -794,8 +807,10 @@ impl<'ctx> Preprocessor<'ctx> { Err(e) => self.context.register_error(e), }, } + return Ok(()); } + self.context.register_error(DMError::new(self.last_input_loc, format!("failed to find #include {:?}", path))); return Ok(()); } diff --git a/src/langserver/main.rs b/src/langserver/main.rs index a3a3d0e7..fd71a8a7 100644 --- a/src/langserver/main.rs +++ b/src/langserver/main.rs @@ -1083,6 +1083,10 @@ handle_method_call! { retrigger_characters: None, work_done_progress_options: Default::default(), }), + document_link_provider: Some(DocumentLinkOptions { + resolve_provider: None, + work_done_progress_options: Default::default(), + }), color_provider: Some(ColorProviderCapability::Simple(true)), .. Default::default() }, @@ -1850,6 +1854,30 @@ handle_method_call! { ] } + on DocumentLinkRequest(&mut self, params) { + let (_, _, annotations) = self.get_annotations(¶ms.text_document.uri)?; + if annotations.is_empty() { + None + } else { + let mut results = Vec::new(); + for (span, annotation) in annotations.iter() { + match annotation { + Annotation::Include(pathbuf) => { + results.push(DocumentLink { + range: span_to_range(span.start..span.end.add_columns(1)), + target: Some(path_to_url(pathbuf.clone())?), + tooltip: None, + data: None, + }); + } + _ => {} + } + } + + Some(results) + } + } + // ------------------------------------------------------------------------ // debugger entry point on StartDebugger(&mut self, params) {