实现 include 跳转
This commit is contained in:
parent
c8ae0f78a4
commit
6afe6a1077
@ -10,6 +10,9 @@ use tower_lsp::lsp_types::*;
|
||||
pub mod def_types;
|
||||
pub use def_types::*;
|
||||
|
||||
pub mod feature;
|
||||
pub use feature::*;
|
||||
|
||||
mod extract_defs;
|
||||
use extract_defs::*;
|
||||
|
||||
@ -27,9 +30,10 @@ impl LSPServer {
|
||||
let token: String = get_definition_token(&line_text, pos);
|
||||
|
||||
info!("definition token: {:?}", token);
|
||||
|
||||
|
||||
|
||||
let include_definition = goto_include_definition(&doc, &line_text, pos);
|
||||
if include_definition.is_some() {
|
||||
return include_definition;
|
||||
}
|
||||
|
||||
let scope_tree = self.srcs.scope_tree.read().ok()?;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::definition::def_types::*;
|
||||
use crate::definition::match_definitions;
|
||||
use log::info;
|
||||
use sv_parser::*;
|
||||
use tower_lsp::lsp_types::*;
|
||||
|
||||
|
@ -1,3 +1,62 @@
|
||||
pub fn goto_include_definition() {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use ropey::RopeSlice;
|
||||
use tower_lsp::lsp_types::{GotoDefinitionResponse, LocationLink, Position, Range, Url};
|
||||
|
||||
/// 跳转到定义
|
||||
pub fn goto_include_definition(uri: &Url, line: &RopeSlice, pos: Position) -> Option<GotoDefinitionResponse> {
|
||||
let line_text = line.as_str().unwrap_or("");
|
||||
if line_text.trim().starts_with("`include") {
|
||||
let character = pos.character as usize;
|
||||
let first_quote_idx = line_text.find("\"");
|
||||
let last_quote_idx = line_text.rfind("\"");
|
||||
|
||||
if first_quote_idx.is_none() || last_quote_idx.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let first_quote_idx = first_quote_idx.unwrap();
|
||||
let last_quote_idx = last_quote_idx.unwrap();
|
||||
if character >= first_quote_idx && character <= last_quote_idx {
|
||||
let mut path_string = &line_text[(first_quote_idx + 1) .. last_quote_idx];
|
||||
if path_string.starts_with("./") || path_string.starts_with(".\\") {
|
||||
path_string = &path_string[2 ..];
|
||||
}
|
||||
// 此处得到路径,根据是否为绝对路径进行判断
|
||||
let path = Path::new(path_string);
|
||||
let mut abs_path: PathBuf;
|
||||
if path.is_absolute() {
|
||||
abs_path = PathBuf::from(path);
|
||||
} else {
|
||||
let base = Path::new(uri.path()).parent()?;
|
||||
abs_path = base.join(path);
|
||||
}
|
||||
|
||||
if abs_path.exists() {
|
||||
let target_uri = match Url::from_file_path(abs_path.as_path()) {
|
||||
Ok(uri) => uri,
|
||||
Err(_) => return None
|
||||
};
|
||||
|
||||
let origin_selection_range = Range::new(
|
||||
Position { line: pos.line, character: first_quote_idx as u32 },
|
||||
Position { line: pos.line, character: last_quote_idx as u32 }
|
||||
);
|
||||
|
||||
let target_position = Position { line: 0, character: 0 };
|
||||
let target_range = Range::new(target_position, target_position);
|
||||
|
||||
let link = vec![LocationLink {
|
||||
target_uri,
|
||||
origin_selection_range: Some(origin_selection_range),
|
||||
target_range,
|
||||
target_selection_range: target_range
|
||||
}];
|
||||
let links = GotoDefinitionResponse::Link(link);
|
||||
return Some(links);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
use crate::core::sv_parser::make_fast_from_syntaxtree;
|
||||
use crate::custom_request::update_fast_to_client;
|
||||
use crate::definition::def_types::*;
|
||||
use crate::definition::get_scopes;
|
||||
use crate::diagnostics::{get_diagnostics, is_hidden};
|
||||
use crate::server::LSPServer;
|
||||
use futures::executor::block_on;
|
||||
#[allow(unused)]
|
||||
use log::info;
|
||||
use log::{debug, error};
|
||||
@ -18,9 +15,11 @@ use std::fs;
|
||||
use std::ops::Deref;
|
||||
use std::ops::Range as StdRange;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
||||
use std::thread;
|
||||
use sv_parser::*;
|
||||
use sv_parser::sv_parser_pp_range;
|
||||
use thread::JoinHandle;
|
||||
use tower_lsp::lsp_types::*;
|
||||
use walkdir::WalkDir;
|
||||
@ -34,6 +33,11 @@ macro_rules! unwrap_result {
|
||||
};
|
||||
}
|
||||
|
||||
struct CustomRange {
|
||||
pub begin: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
impl LSPServer {
|
||||
pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams {
|
||||
info!("[LSPServer] did open");
|
||||
@ -480,10 +484,13 @@ pub fn parse(
|
||||
|
||||
// 宏定义不存在的错误
|
||||
sv_parser::Error::DefineNotFound(not_found_macro_name) => {
|
||||
let range = sv_parser::sv_parser_pp_range::Range { begin: 0, end: 0 };
|
||||
let pathbuf = PathBuf::from_str(uri.as_str()).unwrap();
|
||||
let origin = Some((pathbuf, range));
|
||||
let com_define = Define {
|
||||
identifier: not_found_macro_name.to_string(),
|
||||
arguments: Vec::new(),
|
||||
text: Some(DefineText {text: "undefined".to_string(), origin: None})
|
||||
text: Some(DefineText {text: "undefined".to_string(), origin})
|
||||
};
|
||||
defines.insert(not_found_macro_name, Some(com_define));
|
||||
parse_iterations += 1;
|
||||
|
108
src/test/mod.rs
108
src/test/mod.rs
@ -4,6 +4,13 @@ const TESTFILES_DIR: &str = "testfiles";
|
||||
#[allow(unused)]
|
||||
const DIGTIAL_IDE_TEST: &str = "/home/dide/project/Digital-Test/Digital-IDE-test/user";
|
||||
|
||||
#[allow(unused)]
|
||||
const TEST_FILE: &str = "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/br_gh330.sv";
|
||||
|
||||
#[allow(unused)]
|
||||
const INCOMPLETE_EXAMPLE: &str = "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/incomplete-example";
|
||||
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! unwrap_result {
|
||||
($expr:expr) => {
|
||||
@ -61,6 +68,19 @@ mod test_fast {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_incomplete_example() {
|
||||
let path = Path::new(INCOMPLETE_EXAMPLE);
|
||||
if path.exists() && path.is_dir() {
|
||||
// 递归遍历文件夹
|
||||
if let Err(e) = traverse_directory(path) {
|
||||
eprintln!("Error: {}", e);
|
||||
}
|
||||
} else {
|
||||
eprintln!("Path does not exist or is not a directory");
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_directory(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if dir.is_dir() {
|
||||
for entry in fs::read_dir(dir)? {
|
||||
@ -89,7 +109,8 @@ mod test_fast {
|
||||
continue;
|
||||
}
|
||||
let file_path = path.to_str().unwrap();
|
||||
let _ = sv_parser(file_path);
|
||||
let result = sv_parser(file_path);
|
||||
assert!(result.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -101,17 +122,19 @@ mod test_fast {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_svparse {
|
||||
use std::{fs, path::PathBuf};
|
||||
use std::{fs, path::{Path, PathBuf}};
|
||||
|
||||
use ropey::Rope;
|
||||
use tower_lsp::lsp_types::Url;
|
||||
|
||||
use crate::sources::parse;
|
||||
|
||||
use super::{INCOMPLETE_EXAMPLE, TEST_FILE};
|
||||
|
||||
#[test]
|
||||
/// 测试单独的文件
|
||||
fn test_mycpu() {
|
||||
let includes: Vec<PathBuf> = Vec::new();
|
||||
let path = "/home/dide/project/Digital-Test/MipsDesign/src/MyCpu.v";
|
||||
let path = TEST_FILE;
|
||||
|
||||
let text = match fs::read_to_string(path) {
|
||||
Ok(text) => text,
|
||||
@ -122,14 +145,73 @@ mod test_svparse {
|
||||
let uri = Url::from_file_path(&path).unwrap();
|
||||
let result = parse(&doc, &uri, &None, &includes);
|
||||
match result {
|
||||
Some(syntax_tree) => {
|
||||
Some(_) => {
|
||||
println!("success");
|
||||
},
|
||||
None => {
|
||||
eprintln!("gen None");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 测试语法不完整的例子
|
||||
fn test_incomplete_example() {
|
||||
let path = Path::new(INCOMPLETE_EXAMPLE);
|
||||
if path.exists() && path.is_dir() {
|
||||
// 递归遍历文件夹
|
||||
if let Err(e) = traverse_directory(path) {
|
||||
eprintln!("Error: {}", e);
|
||||
}
|
||||
} else {
|
||||
eprintln!("Path does not exist or is not a directory");
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_directory(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if dir.is_dir() {
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_dir() {
|
||||
// 递归遍历子文件夹
|
||||
traverse_directory(&path)?;
|
||||
} else if path.is_file() {
|
||||
// 检查文件扩展名
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "v" || ext == "sv" {
|
||||
println!("Test file: {:?}", path);
|
||||
// TODO: Check Stack Overflow tests
|
||||
if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/comp1001.sv" {
|
||||
continue;
|
||||
}
|
||||
if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/comp1000.sv" {
|
||||
continue;
|
||||
}
|
||||
if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/ivtest/br_gh330.sv" {
|
||||
continue;
|
||||
}
|
||||
if path.to_str().unwrap() == "/home/dide/project/Digital-Test/Digital-IDE-test/user/src/svlog/tools/hdlconv/pri_encoder_using_assign.sv" {
|
||||
continue;
|
||||
}
|
||||
let file_path = path.to_str().unwrap();
|
||||
let text = match fs::read_to_string(file_path) {
|
||||
Ok(text) => text,
|
||||
Err(_) => continue
|
||||
};
|
||||
|
||||
let includes: Vec<PathBuf> = Vec::new();
|
||||
let doc = Rope::from_str(&text);
|
||||
let uri = Url::from_file_path(file_path).unwrap();
|
||||
let result = parse(&doc, &uri, &None, &includes);
|
||||
assert!(result.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,6 +273,19 @@ mod test_scope_tree {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_incomplete_example() {
|
||||
let path = Path::new(INCOMPLETE_EXAMPLE);
|
||||
if path.exists() && path.is_dir() {
|
||||
// 递归遍历文件夹
|
||||
if let Err(e) = traverse_directory(path) {
|
||||
eprintln!("Error: {}", e);
|
||||
}
|
||||
} else {
|
||||
eprintln!("Path does not exist or is not a directory");
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_directory(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if dir.is_dir() {
|
||||
for entry in fs::read_dir(dir)? {
|
||||
@ -219,7 +314,8 @@ mod test_scope_tree {
|
||||
continue;
|
||||
}
|
||||
let file_path = path.to_str().unwrap();
|
||||
let _ = get_scope_tree(file_path);
|
||||
let scope = get_scope_tree(file_path);
|
||||
assert!(scope.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user