加入 codedoc 部分
This commit is contained in:
parent
3d91cd1ee3
commit
10fbbd8843
2
src/codedoc/mod.rs
Normal file
2
src/codedoc/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod vlog;
|
||||||
|
pub mod vhdl;
|
137
src/codedoc/vhdl.rs
Normal file
137
src/codedoc/vhdl.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ropey::Rope;
|
||||||
|
use sv_parser::{RefNode, SyntaxTree};
|
||||||
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
|
use crate::core::sv_parser::{get_identifier, get_position};
|
||||||
|
|
||||||
|
struct CommentSymbol {
|
||||||
|
comment_string: String,
|
||||||
|
start_pos: crate::core::hdlparam::Position,
|
||||||
|
end_pos: crate::core::hdlparam::Position
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_comments_from_ast(doc: &Rope, syntax_tree: &SyntaxTree) {
|
||||||
|
// 创造一个收容 comment 的栈,对连续的注释进行合并
|
||||||
|
let mut comments = Vec::<CommentSymbol>::new();
|
||||||
|
|
||||||
|
for node in syntax_tree {
|
||||||
|
match node {
|
||||||
|
RefNode::Comment(x) => {
|
||||||
|
let locate = x.nodes.0;
|
||||||
|
let comment_string = syntax_tree.get_str(&locate).unwrap();
|
||||||
|
let start_pos = get_position(doc, locate, 0);
|
||||||
|
let end_pos = get_position(doc, locate, locate.len);
|
||||||
|
|
||||||
|
println!("{:?}", comment_string);
|
||||||
|
println!("start {:?}", start_pos);
|
||||||
|
println!("end {:?}", end_pos);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if let Some(mut last_comment) = comments.last_mut() {
|
||||||
|
// 判断是否需要合并
|
||||||
|
let last_end_line = last_comment.end_pos.line;
|
||||||
|
let current_start_line = start_pos.line;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则,直接加入
|
||||||
|
comments.push(CommentSymbol {
|
||||||
|
comment_string: comment_string.to_string(),
|
||||||
|
start_pos, end_pos
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 解析第一行 tag
|
||||||
|
/// /* @meta
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
///
|
||||||
|
/// /* @module
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
///
|
||||||
|
/// /* @wavedrom xxx
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
///
|
||||||
|
/// 或者压根儿没有
|
||||||
|
/// /*
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
fn parse_first_line_tag(comment: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 解析不同的注释块
|
||||||
|
fn codedoc_parse_pipeline(comment: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_c_style_comment(comment: &str) -> Result<Value, String> {
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
let mut revision_vec = Vec::new();
|
||||||
|
let mut in_revision = false;
|
||||||
|
|
||||||
|
for line in comment.lines() {
|
||||||
|
let line = line.trim();
|
||||||
|
if line.is_empty() || line.starts_with("/*") || line.starts_with("*/") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.starts_with("*") {
|
||||||
|
let line = line[1..].trim();
|
||||||
|
if line.starts_with("@meta") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((key, value)) = line.split_once(':') {
|
||||||
|
let key = key.trim();
|
||||||
|
let value = value.trim();
|
||||||
|
|
||||||
|
match key {
|
||||||
|
"Tool Versions" => {
|
||||||
|
let tools: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
|
||||||
|
result.insert(key.to_string(), json!(tools));
|
||||||
|
}
|
||||||
|
"Revision" => {
|
||||||
|
in_revision = true;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if in_revision {
|
||||||
|
if value.matches('&').count() == 2 {
|
||||||
|
let parts: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
|
||||||
|
let revision = json!({
|
||||||
|
"date": parts[0],
|
||||||
|
"version": parts[1],
|
||||||
|
"revision": parts[2]
|
||||||
|
});
|
||||||
|
revision_vec.push(revision);
|
||||||
|
} else {
|
||||||
|
in_revision = false;
|
||||||
|
result.insert(key.to_string(), json!(revision_vec));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.insert(key.to_string(), json!(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Copyright field
|
||||||
|
if let Some(copyright) = result.get_mut("Copyright") {
|
||||||
|
let copyright_str = copyright.as_str().unwrap_or("");
|
||||||
|
*copyright = json!(format!("Copyright(c) {}", copyright_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(json!(result))
|
||||||
|
}
|
180
src/codedoc/vlog.rs
Normal file
180
src/codedoc/vlog.rs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ropey::Rope;
|
||||||
|
use sv_parser::{RefNode, SyntaxTree};
|
||||||
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
|
use crate::core::sv_parser::{get_identifier, get_position};
|
||||||
|
|
||||||
|
struct CommentSymbol {
|
||||||
|
comment_string: String,
|
||||||
|
start_pos: crate::core::hdlparam::Position,
|
||||||
|
end_pos: crate::core::hdlparam::Position
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_comments_from_ast(doc: &Rope, syntax_tree: &SyntaxTree) {
|
||||||
|
|
||||||
|
let comments = make_comment_list(doc, syntax_tree);
|
||||||
|
|
||||||
|
for comment in &comments {
|
||||||
|
if let Some(comment_meta) = get_meta_info(comment) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 处理为普通注释
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 创造一个收容 comment 的栈,对连续的注释进行合并
|
||||||
|
fn make_comment_list(doc: &Rope, syntax_tree: &SyntaxTree) -> Vec<CommentSymbol> {
|
||||||
|
let mut comments = Vec::<CommentSymbol>::new();
|
||||||
|
|
||||||
|
for node in syntax_tree {
|
||||||
|
match node {
|
||||||
|
RefNode::Comment(x) => {
|
||||||
|
let locate = x.nodes.0;
|
||||||
|
let comment_string = syntax_tree.get_str(&locate).unwrap();
|
||||||
|
let start_pos = get_position(doc, locate, 0);
|
||||||
|
let end_pos = get_position(doc, locate, locate.len);
|
||||||
|
|
||||||
|
println!("{:?}", comment_string);
|
||||||
|
println!("start {:?}", start_pos);
|
||||||
|
println!("end {:?}", end_pos);
|
||||||
|
|
||||||
|
if let Some(last_comment) = comments.last_mut() {
|
||||||
|
// 判断是否需要合并
|
||||||
|
// vlog 只合并单行注释
|
||||||
|
let last_end_line = last_comment.end_pos.line;
|
||||||
|
let current_start_line = start_pos.line;
|
||||||
|
|
||||||
|
if current_start_line - last_end_line <= 1
|
||||||
|
&& last_comment.comment_string.starts_with("//")
|
||||||
|
&& comment_string.starts_with("//") {
|
||||||
|
last_comment.comment_string += comment_string;
|
||||||
|
last_comment.end_pos = end_pos;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则,直接加入
|
||||||
|
comments.push(CommentSymbol {
|
||||||
|
comment_string: comment_string.to_string(),
|
||||||
|
start_pos, end_pos
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comments
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CommentMeta<'a> {
|
||||||
|
comment_type: &'a str,
|
||||||
|
argruments: Vec::<&'a str>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 解析第一行 tag
|
||||||
|
/// /* @meta
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
///
|
||||||
|
/// /* @module
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
///
|
||||||
|
/// /* @wavedrom xxx
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
///
|
||||||
|
/// 或者压根儿没有
|
||||||
|
/// /*
|
||||||
|
/// *
|
||||||
|
/// */
|
||||||
|
fn get_meta_info(comment: &str) -> Option<CommentMeta> {
|
||||||
|
let first_line = comment.lines().next().unwrap_or("").trim();
|
||||||
|
// 注释开头都是 // 或者 /* ,都是两个字符
|
||||||
|
let comment_meta = &first_line[2..];
|
||||||
|
if comment_meta.trim().starts_with("@") {
|
||||||
|
let arguments: Vec<&str> = comment_meta.split_whitespace().collect();
|
||||||
|
if arguments.len() > 0 {
|
||||||
|
let comment_type = arguments[0];
|
||||||
|
let arguments = &arguments[1..];
|
||||||
|
Some(CommentMeta {
|
||||||
|
comment_type,
|
||||||
|
argruments: arguments.to_vec()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 解析不同的注释块
|
||||||
|
fn codedoc_parse_pipeline(comment: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_c_style_comment(comment: &str) -> Result<Value, String> {
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
let mut revision_vec = Vec::new();
|
||||||
|
let mut in_revision = false;
|
||||||
|
|
||||||
|
for line in comment.lines() {
|
||||||
|
let line = line.trim();
|
||||||
|
if line.is_empty() || line.starts_with("/*") || line.starts_with("*/") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.starts_with("*") {
|
||||||
|
let line = line[1..].trim();
|
||||||
|
if line.starts_with("@meta") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((key, value)) = line.split_once(':') {
|
||||||
|
let key = key.trim();
|
||||||
|
let value = value.trim();
|
||||||
|
|
||||||
|
match key {
|
||||||
|
"Tool Versions" => {
|
||||||
|
let tools: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
|
||||||
|
result.insert(key.to_string(), json!(tools));
|
||||||
|
}
|
||||||
|
"Revision" => {
|
||||||
|
in_revision = true;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if in_revision {
|
||||||
|
if value.matches('&').count() == 2 {
|
||||||
|
let parts: Vec<&str> = value.split('&').map(|s| s.trim()).collect();
|
||||||
|
let revision = json!({
|
||||||
|
"date": parts[0],
|
||||||
|
"version": parts[1],
|
||||||
|
"revision": parts[2]
|
||||||
|
});
|
||||||
|
revision_vec.push(revision);
|
||||||
|
} else {
|
||||||
|
in_revision = false;
|
||||||
|
result.insert(key.to_string(), json!(revision_vec));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.insert(key.to_string(), json!(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Copyright field
|
||||||
|
if let Some(copyright) = result.get_mut("Copyright") {
|
||||||
|
let copyright_str = copyright.as_str().unwrap_or("");
|
||||||
|
*copyright = json!(format!("Copyright(c) {}", copyright_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(json!(result))
|
||||||
|
}
|
16
src/execute_command/codedoc.rs
Normal file
16
src/execute_command/codedoc.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
use serde_json::Value;
|
||||||
|
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||||
|
|
||||||
|
use crate::{diagnostics::provide_diagnostics, server::Backend, utils::{from_uri_to_escape_path_string, open_doc_as_rope}};
|
||||||
|
|
||||||
|
// /// 前端请求,发布诊断结果,仅在初始化和修改配置时触发
|
||||||
|
// /// 参数为 [file_path: string]
|
||||||
|
// pub async fn publish_diagnostics(
|
||||||
|
// backend: &Backend,
|
||||||
|
// arguments: Vec<Value>
|
||||||
|
// ) -> tower_lsp::jsonrpc::Result<Option<Value>> {
|
||||||
|
|
||||||
|
// }
|
@ -4,6 +4,9 @@ use tower_lsp::lsp_types::*;
|
|||||||
use crate::server::Backend;
|
use crate::server::Backend;
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
|
|
||||||
|
pub use codedoc::*;
|
||||||
|
mod codedoc;
|
||||||
|
|
||||||
pub async fn execute_command(
|
pub async fn execute_command(
|
||||||
backend: &Backend,
|
backend: &Backend,
|
||||||
params: ExecuteCommandParams
|
params: ExecuteCommandParams
|
||||||
@ -17,6 +20,8 @@ pub async fn execute_command(
|
|||||||
diagnostics::clear_diagnostics(backend, params.arguments).await
|
diagnostics::clear_diagnostics(backend, params.arguments).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,9 @@ pub mod diagnostics;
|
|||||||
// 格式化
|
// 格式化
|
||||||
pub mod format;
|
pub mod format;
|
||||||
|
|
||||||
|
// 格式化
|
||||||
|
pub mod codedoc;
|
||||||
|
|
||||||
// 基础工具
|
// 基础工具
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ mod document_highlight;
|
|||||||
mod inlay_hint;
|
mod inlay_hint;
|
||||||
mod code_lens;
|
mod code_lens;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod codedoc;
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
mod format;
|
mod format;
|
||||||
mod server;
|
mod server;
|
||||||
|
@ -702,7 +702,7 @@ pub fn sv_parser_pipeline(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let escape_path_string = from_uri_to_escape_path_string(uri).unwrap();
|
let escape_path_string = from_uri_to_escape_path_string(uri).unwrap();
|
||||||
let escape_path = PathBuf::from_str(&escape_path_string).unwrap();
|
// let escape_path = PathBuf::from_str(&escape_path_string).unwrap();
|
||||||
|
|
||||||
let ast = recovery_sv_parse_with_retry(
|
let ast = recovery_sv_parse_with_retry(
|
||||||
doc,
|
doc,
|
||||||
|
@ -487,3 +487,36 @@ mod test_file {
|
|||||||
assert!(!is_character_ordered_match("suprt", "super"));
|
assert!(!is_character_ordered_match("suprt", "super"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_code_doc {
|
||||||
|
use std::{env, fs, path::PathBuf};
|
||||||
|
|
||||||
|
use ropey::Rope;
|
||||||
|
use tower_lsp::lsp_types::Url;
|
||||||
|
|
||||||
|
use crate::sources::recovery_sv_parse_with_retry;
|
||||||
|
use crate::codedoc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dev_code_doc() {
|
||||||
|
match env::current_dir() {
|
||||||
|
Ok(path) => println!("当前工作目录: {}", path.display()),
|
||||||
|
Err(e) => println!("获取当前工作目录失败: {}", e),
|
||||||
|
}
|
||||||
|
let path = PathBuf::from("E:/Project/Digital-IDE/digital-lsp-server/test/vlog/codedoc.v");
|
||||||
|
let includes: Vec<PathBuf> = Vec::new();
|
||||||
|
|
||||||
|
let text = match fs::read_to_string(&path) {
|
||||||
|
Ok(text) => text,
|
||||||
|
Err(_) => return
|
||||||
|
};
|
||||||
|
|
||||||
|
let doc = Rope::from_str(&text);
|
||||||
|
let uri = Url::from_file_path(&path).unwrap();
|
||||||
|
let result = recovery_sv_parse_with_retry(&doc, &uri, &None, &includes);
|
||||||
|
if let Some((syntax_tree, _)) = result {
|
||||||
|
codedoc::vlog::get_comments_from_ast(&doc, &syntax_tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
test/vlog/codedoc.v
Normal file
57
test/vlog/codedoc.v
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/* @meta
|
||||||
|
* Create Date : 2/6/2025 14:58
|
||||||
|
* Author : nitcloud
|
||||||
|
* Target Device : [Target FPGA and ASIC Device]
|
||||||
|
* Tool Versions : vivado 18.3 & DC 2016
|
||||||
|
* Revision Historyc :
|
||||||
|
* Revision :
|
||||||
|
* 04/12 0.01 - File Created
|
||||||
|
* Description :
|
||||||
|
* Company : ncai Technology .Inc
|
||||||
|
* Copyright : 1999, ncai Technology Inc, All right reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* @module
|
||||||
|
* Netlist : level-1
|
||||||
|
* FSMView : on
|
||||||
|
* Overview: 4-stage pipelined accumulator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 这是一些简单的文字,可以随意渲染
|
||||||
|
* :::info
|
||||||
|
* 请注意版权问题
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* 使用 C 语言如此进行简单的编译
|
||||||
|
* ```c
|
||||||
|
* int main() {
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @wavedrom accuml this is accuml wavedrom
|
||||||
|
{signal: [
|
||||||
|
{name: 'clock', wave: '10101010101010101'},
|
||||||
|
{name: 'reset', wave: '10...............'},
|
||||||
|
{name: 'clr', wave: '01.0.............'},
|
||||||
|
{name: 'idata', wave: 'x3...............', data: ['5']},
|
||||||
|
{name: 'odata', wave: 'x........5.5.5.5.', data: ['5','10','25','30']},
|
||||||
|
]}
|
||||||
|
*/
|
||||||
|
|
||||||
|
module adder(
|
||||||
|
// 这是一个简单的注释
|
||||||
|
// 这是它们的第二行注释
|
||||||
|
input a,
|
||||||
|
input b,
|
||||||
|
|
||||||
|
// 这是输出信号
|
||||||
|
output c,
|
||||||
|
);
|
||||||
|
// 具体的代码实现
|
||||||
|
meta_add u_meta_add(a, b, c);
|
||||||
|
endmodule
|
Loading…
x
Reference in New Issue
Block a user