Skip to content

Commit 8be2649

Browse files
authored
feat(doc): inline doc links (foundry-rs#6626)
* feat: infer hyperlinks * feat: inline doc links * rustfmt
1 parent aaf1273 commit 8be2649

File tree

8 files changed

+482
-57
lines changed

8 files changed

+482
-57
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/doc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ solang-parser.workspace = true
3131
thiserror = "1"
3232
toml.workspace = true
3333
tracing.workspace = true
34+
regex = "1.10.2"

crates/doc/src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub struct DocBuilder {
4242

4343
// TODO: consider using `tfio`
4444
impl DocBuilder {
45-
const SRC: &'static str = "src";
45+
pub(crate) const SRC: &'static str = "src";
4646
const SOL_EXT: &'static str = "sol";
4747
const README: &'static str = "README.md";
4848
const SUMMARY: &'static str = "SUMMARY.md";

crates/doc/src/document.rs

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
use crate::{ParseItem, PreprocessorId, PreprocessorOutput};
2-
use std::{collections::HashMap, path::PathBuf, sync::Mutex};
1+
use crate::{DocBuilder, ParseItem, PreprocessorId, PreprocessorOutput};
2+
use std::{
3+
collections::HashMap,
4+
path::{Path, PathBuf},
5+
slice::IterMut,
6+
sync::Mutex,
7+
};
38

49
/// The wrapper around the [ParseItem] containing additional
510
/// information the original item and extra context for outputting it.
@@ -62,6 +67,15 @@ impl Document {
6267
let context = self.context.lock().expect("failed to lock context");
6368
context.get(&id).cloned()
6469
}
70+
71+
fn try_relative_output_path(&self) -> Option<&Path> {
72+
self.target_path.strip_prefix(&self.out_target_dir).ok()?.strip_prefix(DocBuilder::SRC).ok()
73+
}
74+
75+
/// Returns the relative path of the document output.
76+
pub fn relative_output_path(&self) -> &Path {
77+
self.try_relative_output_path().unwrap_or(self.target_path.as_path())
78+
}
6579
}
6680

6781
/// The content of the document.
@@ -73,6 +87,100 @@ pub enum DocumentContent {
7387
OverloadedFunctions(Vec<ParseItem>),
7488
}
7589

90+
impl DocumentContent {
91+
pub(crate) fn len(&self) -> usize {
92+
match self {
93+
DocumentContent::Empty => 0,
94+
DocumentContent::Single(_) => 1,
95+
DocumentContent::Constants(items) => items.len(),
96+
DocumentContent::OverloadedFunctions(items) => items.len(),
97+
}
98+
}
99+
100+
pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut ParseItem> {
101+
match self {
102+
DocumentContent::Empty => None,
103+
DocumentContent::Single(item) => {
104+
if index == 0 {
105+
Some(item)
106+
} else {
107+
None
108+
}
109+
}
110+
DocumentContent::Constants(items) => items.get_mut(index),
111+
DocumentContent::OverloadedFunctions(items) => items.get_mut(index),
112+
}
113+
}
114+
115+
pub fn iter_items(&self) -> ParseItemIter<'_> {
116+
match self {
117+
DocumentContent::Empty => ParseItemIter { next: None, other: None },
118+
DocumentContent::Single(item) => ParseItemIter { next: Some(item), other: None },
119+
DocumentContent::Constants(items) => {
120+
ParseItemIter { next: None, other: Some(items.iter()) }
121+
}
122+
DocumentContent::OverloadedFunctions(items) => {
123+
ParseItemIter { next: None, other: Some(items.iter()) }
124+
}
125+
}
126+
}
127+
128+
pub fn iter_items_mut(&mut self) -> ParseItemIterMut<'_> {
129+
match self {
130+
DocumentContent::Empty => ParseItemIterMut { next: None, other: None },
131+
DocumentContent::Single(item) => ParseItemIterMut { next: Some(item), other: None },
132+
DocumentContent::Constants(items) => {
133+
ParseItemIterMut { next: None, other: Some(items.iter_mut()) }
134+
}
135+
DocumentContent::OverloadedFunctions(items) => {
136+
ParseItemIterMut { next: None, other: Some(items.iter_mut()) }
137+
}
138+
}
139+
}
140+
}
141+
142+
#[derive(Debug)]
143+
pub struct ParseItemIter<'a> {
144+
next: Option<&'a ParseItem>,
145+
other: Option<std::slice::Iter<'a, ParseItem>>,
146+
}
147+
148+
impl<'a> Iterator for ParseItemIter<'a> {
149+
type Item = &'a ParseItem;
150+
151+
fn next(&mut self) -> Option<Self::Item> {
152+
if let Some(next) = self.next.take() {
153+
return Some(next)
154+
}
155+
if let Some(other) = self.other.as_mut() {
156+
return other.next()
157+
}
158+
159+
None
160+
}
161+
}
162+
163+
#[derive(Debug)]
164+
pub struct ParseItemIterMut<'a> {
165+
next: Option<&'a mut ParseItem>,
166+
other: Option<IterMut<'a, ParseItem>>,
167+
}
168+
169+
impl<'a> Iterator for ParseItemIterMut<'a> {
170+
type Item = &'a mut ParseItem;
171+
172+
fn next(&mut self) -> Option<Self::Item> {
173+
if let Some(next) = self.next.take() {
174+
return Some(next)
175+
}
176+
if let Some(other) = self.other.as_mut() {
177+
return other.next()
178+
}
179+
180+
None
181+
}
182+
}
183+
76184
/// Read the preprocessor output variant from document context.
77185
/// Returns [None] if there is no output.
78186
macro_rules! read_context {

0 commit comments

Comments
 (0)